Patchwork [objc] maintenance, make Obj{C,C++} LTO-friendly.

login
register
mail settings
Submitter IainS
Date July 2, 2010, 7:19 p.m.
Message ID <076D2894-5E9C-4021-92A1-1987D2B7E04A@sandoe-acoustics.co.uk>
Download mbox | patch
Permalink /patch/57754/
State New
Headers show

Comments

IainS - July 2, 2010, 7:19 p.m.
This patch is intended to maintain the 'status-quo' in the presence of  
LTO.

In fact, it is a general step forward in that I have identified the  
reason that 'blanket' application of DECL_PRESERVE_P was required and  
got rid of that.

There are places that I intended to round things out a bit more before  
posting - but we are going to have major patch collisions with  
Nathan's work and with resources being so limited, it seems better to  
move forward in smaller steps - rather than spend all the time  
counteracting bit-rot.

It's best viewed as general maintenance - with the side-effect that  
LTO now works - so there's one fewer barriers to enabling that by  
default on Darwin.

This has been tested on:
powerpc*-apple-darwin{8,9} i686-apple-darwin9, x86_64-apple- 
darwin10,  ?86*-unknown-linux-gnu, cris-elf (sim), s390x (compile  
only), mipsisa64-elf(sim), armel-linux-eabi(compile-only).

OK for trunk?
Iain

objc/ChangeLog:
	
	PR objc/44140
	* objc-act.c: build_objc_string_decl() remove declaration.
	(finish_var_decl):  Remove forcing of var output and  
indiscriminate ,marking as "Used".
	(init_objc_symtab): Use integer_zero_node. Use  
short_integer_type_node for the counts.
	(generate_objc_symtab_decl): Remove call to  
forward_declare_categories().  Attatch the
	correct section designation to the symtab.
	(init_module_descriptor): Make the filename "N/A" instead of "".  Use  
integer_zero_node
	instead of building each time. DECL_PRESERVE_P this item.
	(diagnose_missing_method): New.
	(build_next_selector_translation_table): New.
	(build_gnu_selector_translation_table): New.
	(add_objc_string): Incorporate the code from build_objc_string_decl.
	(build_objc_string_decl): Remove.
	(objc_declare_alias): Use integer_zero_node.
	(generate_category): Pass in the current class/category entry.
	Ensure that we finish the variables we originally started, and keep  
them so that they are
	emitted.  (generate_shared_structures): Pass in the current class/ 
category entry. Ensure
	that we finish the variables we originally started so that they are  
output.
	(finish_objc): Reorder code so that we finish variables before  
referencing them.  Save the
	global data before calling meta-daat creation routines, and pass the  
current reference to the
	two main routines. (generate_classref_translation_entry):  
DECL_PRESERVE_P this item
	it is needed by the runtime.  (handle_class_ref): Use finish_var()  
mark items as
	DECL_PRESERVE_P where they are needed by the runtime.
	(handle_impent): Use finish_var() mark items as  DECL_PRESERVE_P  
where they are
	needed by the runtime. (generate_objc_image_info): Use  
integer_zero_node, attatch the
	correct section info.  DECL_PRESERVE_P, this is needed by the runtime.

testsuite/Changelog:

	PR objc/44140

	objc.dg/lto: New.
	objc.dg/lto/trivial-1_0.m: New.
	objc.dg/lto/lto.exp: New.
	obj-c++.dg/lto: New.
	obj-c++.dg/lto/trivial-1_0.mm: New.
	obj-c++.dg/lto/lto.exp: New.
Mike Stump - July 3, 2010, 5:48 p.m.
On Jul 2, 2010, at 12:19 PM, IainS wrote:
> In fact, it is a general step forward in that I have identified the reason that 'blanket' application of DECL_PRESERVE_P was required and got rid of that.

If you get it wrong, things just disappear from the file...  I didn't audit it to make sure all your assumptions are correct.  So, first, is there any data that should not be preserved that uses finish_var_decl?  I didn't think there was?  If not, I'd rather keep finish_var_decl as is.


-  expr = add_objc_string (get_identifier (""), class_names);
+  expr = add_objc_string (get_identifier ("N/A"), class_names);

Please leave this as "".  I don't see a good reason to change it.


   UOBJC_SYMBOLS_decl = start_var_decl (objc_symtab_template, "_OBJC_SYMBOLS");
+  TREE_CONSTANT (UOBJC_SYMBOLS_decl) = 1;
+  if (flag_next_runtime)
+    {
+      tree sect = my_build_string (16, "__OBJC,__symbols");
+      DECL_SECTION_NAME (UOBJC_SYMBOLS_decl) = sect;
+    }

?  This is overly darwin specific, and yet, this file isn't a darwin file.  This shouldn't be necessary, as machopic_select_section should already select the right section based upon the name:

      else if (!strncmp (name, "_OBJC_SYMBOLS", 13))
        return darwin_sections[objc_symbols_section];

?

Likewise with:

+  if (flag_next_runtime)
+    {
+      tree sect = my_build_string (44, 
+      				"__OBJC,__image_info,regular,no_dead_strip");
+      DECL_SECTION_NAME (decl) = sect;
+    }

?


-  /* Mark the decl to avoid "defined but not used" warning.  */
-  TREE_USED (var) = 1;

You didn't explain why one can get rid of this.  I think it is still applicable?


+	  /* Entries of this form are used for references to methods.
+	  The runtime re-writes these one start-up but the FE can't see 
+	  that and optimizes it away unless we force it.  */

Wording, these one start-up...
IainS - July 3, 2010, 6:07 p.m.
On 3 Jul 2010, at 18:48, Mike Stump wrote:

> On Jul 2, 2010, at 12:19 PM, IainS wrote:
>> In fact, it is a general step forward in that I have identified the  
>> reason that 'blanket' application of DECL_PRESERVE_P was required  
>> and got rid of that.
>
> If you get it wrong, things just disappear from the file...  I  
> didn't audit it to make sure all your assumptions are correct.  So,  
> first, is there any data that should not be preserved that uses  
> finish_var_decl?  I didn't think there was?  If not, I'd rather keep  
> finish_var_decl as is.

lto will not work with finish_var_decl as it is.
  see PR 43038 (although, as I see it this is not a problem to ObjC -  
since the version I posted produces the requisite connectivity and  
meta-data).

The only reason that we needed a "blanket" DECL_PRESERVE_P was that  
the variables we started were never finished - and thus were  
disconnected from the root data structures (Symtab &c).

> -  expr = add_objc_string (get_identifier (""), class_names);
> +  expr = add_objc_string (get_identifier ("N/A"), class_names);

the NULL string causes the Symtab to jump between sections when other  
data are all zero.
But that can be cured with explicit section decls.

> Please leave this as "".  I don't see a good reason to change it.

well .. one thing or the other ... (I have no colors to nail to a mast  
here).

>   UOBJC_SYMBOLS_decl = start_var_decl (objc_symtab_template,  
> "_OBJC_SYMBOLS");
> +  TREE_CONSTANT (UOBJC_SYMBOLS_decl) = 1;
> +  if (flag_next_runtime)
> +    {
> +      tree sect = my_build_string (16, "__OBJC,__symbols");
> +      DECL_SECTION_NAME (UOBJC_SYMBOLS_decl) = sect;
> +    }
>
> ?  This is overly darwin specific, and yet, this file isn't a darwin  
> file.  This shouldn't be necessary, as machopic_select_section  
> should already select the right section based upon the name:

NeXT is darwin-specific - we should not need objc-specific stuff in  
the backend to try and guess the section based on the variable names.

It is my intention to separate the runtimes - so that we can hookize  
the interface to make it easier to add ABI V2.
I don't see it as any more Darwin-specific than NeXT is itself  
(although, of course, there's nothing to stop someone porting the  
NeXCT runtime to linux, for example). However, in the latter event I  
suspect they'd have to port the use of these sections too - since my  
understanding is that the runtime uses them.

> -  /* Mark the decl to avoid "defined but not used" warning.  */
> -  TREE_USED (var) = 1;
>
> You didn't explain why one can get rid of this.  I think it is still  
> applicable?

well, we don't get the warning - because the decls that we *are* using  
are now output - and are linked back to the root meta-data that are  
DECL_PRESERVE_P'd

thanks for the review,
I guess one more pass needed :-)
Iain.
IainS - July 3, 2010, 8:06 p.m.
On 3 Jul 2010, at 19:07, IainS wrote:
>>  UOBJC_SYMBOLS_decl = start_var_decl (objc_symtab_template,  
>> "_OBJC_SYMBOLS");
>> +  TREE_CONSTANT (UOBJC_SYMBOLS_decl) = 1;
>> +  if (flag_next_runtime)
>> +    {
>> +      tree sect = my_build_string (16, "__OBJC,__symbols");
>> +      DECL_SECTION_NAME (UOBJC_SYMBOLS_decl) = sect;
>> +    }
>>
>> ?  This is overly darwin specific, and yet, this file isn't a  
>> darwin file.  This shouldn't be necessary, as  
>> machopic_select_section should already select the right section  
>> based upon the name:
>
> NeXT is darwin-specific - we should not need objc-specific stuff in  
> the backend to try and guess the section based on the variable names.

Maybe that's not wholly achievable, some output is clearly dependent  
on what the FE requires...

so (a) attaching the section names in the meta-data generator (FE  
takes responsibility).
(b) attaching an attribute that allows the backend to do the same (at  
least variable names don't need to be parsed)..
(c) keeping with the choice of section based on var names (we know  
this mostly*** works).

... attaching an attribute ("objc_class_ref/objc_class_def")  is also  
an intention for the two cases where we have ASM_xxx in the FE
  so that varasm can output the appropriate thing (depending on what  
the assembler supports) and the FE doesn't need to do something  
different depending on what target macros are defined.

and, of course, the section ID strings  should be #define'd ..

cheers,
Iain

*** it fails in the case that varasm intercepts all-zero items an  
sticks them in lcomm or comm before the darwin section chooser gets a  
look-in.
... all-zero meta-data is possibly only found in test-suites, so  
perhaps this is not an issue (except of tidiness).
Mike Stump - July 9, 2010, 5:59 a.m.
On Jul 2, 2010, at 12:19 PM, IainS wrote:
> This patch is intended to maintain the 'status-quo' in the presence of LTO.

> OK for trunk?

[ after more thought and some more offline email... ]

Ok with the:

+	  /* Entries of this form are used for references to methods.
+	  The runtime re-writes these one start-up but the FE can't see 
+	  that and optimizes it away unless we force it.  */

Wording, these one start-up...

fixed.  As for the raw darwin section names in objc/*.c, I'd pre-approve moving that bit of the code behind a target hook or macro, what ever is in style this week.  I'm not sure what style I like.  Maybe just a TARGET_OBJC_CHOOSE_SECTION(decl); type of interface.

Thanks for all your help.

Patch

Index: gcc/objc/objc-act.c
===================================================================
--- gcc/objc/objc-act.c	(revision 161726)
+++ gcc/objc/objc-act.c	(working copy)
@@ -214,7 +214,6 @@  enum string_section
 };
 
 static tree add_objc_string (tree, enum string_section);
-static tree build_objc_string_decl (enum string_section);
 static void build_selector_table_decl (void);
 
 /* Protocol additions.  */
@@ -1525,14 +1524,6 @@  static void
 finish_var_decl (tree var, tree initializer)
 {
   finish_decl (var, input_location, initializer, NULL_TREE, NULL_TREE);
-  /* Ensure that the variable actually gets output.  */
-  mark_decl_referenced (var);
-  /* Mark the decl to avoid "defined but not used" warning.  */
-  TREE_USED (var) = 1;
-  DECL_READ_P (var) = 1;
-  /* We reserve the right for the runtime to use/modify these variables
-     in ways that are opaque to us.  */
-  DECL_PRESERVE_P (var) = 1;
 }
 
 /* Find the decl for the constant string class reference.  This is only
@@ -2183,7 +2174,7 @@  init_def_list (tree type)
 	expr = build_unary_op (input_location,
 			       ADDR_EXPR, static_instances_decl, 0);
       else
-	expr = build_int_cst (NULL_TREE, 0);
+	expr = integer_zero_node;
 
       CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr);
     }
@@ -2206,7 +2197,9 @@  init_objc_symtab (tree type)
   /* refs = { ..., _OBJC_SELECTOR_TABLE, ... } */
 
   if (flag_next_runtime || ! sel_ref_chain)
-    CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0));
+    CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, convert (
+					build_pointer_type (objc_selector_type),
+							integer_zero_node));
   else
     {
       tree expr = build_unary_op (input_location, ADDR_EXPR,
@@ -2219,11 +2212,13 @@  init_objc_symtab (tree type)
 
   /* cls_def_cnt = { ..., 5, ... } */
 
-  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, imp_count));
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, 
+			  build_int_cst (short_integer_type_node, imp_count));
 
   /* cat_def_cnt = { ..., 5, ... } */
 
-  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, cat_count));
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, 
+			  build_int_cst (short_integer_type_node, cat_count));
 
   /* cls_def = { ..., { &Foo, &Bar, ...}, ... } */
 
@@ -2284,12 +2279,15 @@  forward_declare_categories (void)
 static void
 generate_objc_symtab_decl (void)
 {
-  /* forward declare categories */
-  if (cat_count)
-    forward_declare_categories ();
-
+ 
   build_objc_symtab_template ();
   UOBJC_SYMBOLS_decl = start_var_decl (objc_symtab_template, "_OBJC_SYMBOLS");
+  TREE_CONSTANT (UOBJC_SYMBOLS_decl) = 1;
+  if (flag_next_runtime)
+    {
+      tree sect = my_build_string (16, "__OBJC,__symbols");
+      DECL_SECTION_NAME (UOBJC_SYMBOLS_decl) = sect;
+    }
   finish_var_decl (UOBJC_SYMBOLS_decl,
 		   init_objc_symtab (TREE_TYPE (UOBJC_SYMBOLS_decl)));
 }
@@ -2314,7 +2312,7 @@  init_module_descriptor (tree type)
   /* Don't provide any file name for security reasons. */
   /* name = { ..., "", ... } */
 
-  expr = add_objc_string (get_identifier (""), class_names);
+  expr = add_objc_string (get_identifier ("N/A"), class_names);
   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr);
 
   /* symtab = { ..., _OBJC_SYMBOLS, ... } */
@@ -2323,7 +2321,7 @@  init_module_descriptor (tree type)
     expr = build_unary_op (input_location,
 			   ADDR_EXPR, UOBJC_SYMBOLS_decl, 0);
   else
-    expr = build_int_cst (NULL_TREE, 0);
+    expr = integer_zero_node;
   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr);
 
   return objc_build_constructor (type, v);
@@ -2368,6 +2366,9 @@  build_module_descriptor (void)
 
   /* Create an instance of "_objc_module".  */
   UOBJC_MODULES_decl = start_var_decl (objc_module_template, "_OBJC_MODULES");
+  /* This is the root of the metadata for defined classes and categories, it
+     is referenced by the runtime and, therefore, needed.  */
+  DECL_PRESERVE_P (UOBJC_MODULES_decl) = 1;
   finish_var_decl (UOBJC_MODULES_decl,
 		   init_module_descriptor (TREE_TYPE (UOBJC_MODULES_decl)));
 
@@ -2491,7 +2492,7 @@  generate_static_references (void)
   VEC(constructor_elt,gc) *decls = NULL;
 
   if (flag_next_runtime)
-    abort ();
+    gcc_unreachable ();
 
   for (cl_chain = objc_static_instances, num_class = 0;
        cl_chain; cl_chain = TREE_CHAIN (cl_chain), num_class++)
@@ -2575,12 +2576,65 @@  build_selector (tree ident)
 		  add_objc_string (ident, meth_var_names));
 }
 
+/* Used only by build_*_selector_translation_table (). */
 static void
-build_selector_translation_table (void)
+diagnose_missing_method (tree meth, location_t here)
 {
+  tree method_chain;
+  bool found = false;
+  for (method_chain = meth_var_names_chain;
+       method_chain;
+       method_chain = TREE_CHAIN (method_chain))
+    {
+      if (TREE_VALUE (method_chain) == meth)
+	{
+	  found = true;
+	  break;
+	}
+     }
+
+  if (!found)
+    warning_at (here, 0, "creating selector for nonexistent method %qE",
+			meth);
+}
+
+static void
+build_next_selector_translation_table (void)
+{
   tree chain;
-  int offset = 0;
-  tree decl = NULL_TREE;
+  for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
+    {
+      tree expr;
+      tree decl = TREE_PURPOSE (chain);
+      if (warn_selector && objc_implementation_context)
+      	{
+	  location_t loc;
+      	  if (decl) 
+      	    loc = DECL_SOURCE_LOCATION (decl);
+      	  else
+      	    loc = input_location;
+	  diagnose_missing_method (TREE_VALUE (chain), loc);
+	}
+
+      expr = build_selector (TREE_VALUE (chain));
+
+      if (decl)
+	{
+	  /* Entries of this form are used for references to methods.
+	  The runtime re-writes these one start-up but the FE can't see 
+	  that and optimizes it away unless we force it.  */
+	  DECL_PRESERVE_P (decl) = 1;
+	  finish_var_decl (decl, expr);
+	}
+    }
+}
+
+static void
+build_gnu_selector_translation_table (void)
+{
+  tree chain;
+/*  int offset = 0;
+  tree decl = NULL_TREE;*/
   VEC(constructor_elt,gc) *inits = NULL;
 
   for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
@@ -2588,42 +2642,13 @@  static void
       tree expr;
 
       if (warn_selector && objc_implementation_context)
-      {
-        tree method_chain;
-        bool found = false;
-        for (method_chain = meth_var_names_chain;
-             method_chain;
-             method_chain = TREE_CHAIN (method_chain))
-          {
-            if (TREE_VALUE (method_chain) == TREE_VALUE (chain))
-              {
-                found = true;
-                break;
-              }
-          }
-        if (!found)
-	  {
-	    location_t loc;
-	    if (flag_next_runtime && TREE_PURPOSE (chain))
-	      loc = DECL_SOURCE_LOCATION (TREE_PURPOSE (chain));
-	    else
-	      loc = input_location;
-	    warning_at (loc, 0, "creating selector for nonexistent method %qE",
-			TREE_VALUE (chain));
-	  }
-      }
+	diagnose_missing_method (TREE_VALUE (chain), input_location);
 
       expr = build_selector (TREE_VALUE (chain));
-      /* add one for the '\0' character */
-      offset += IDENTIFIER_LENGTH (TREE_VALUE (chain)) + 1;
+      /* add one for the '\0' character 
+      offset += IDENTIFIER_LENGTH (TREE_VALUE (chain)) + 1;*/
 
-      if (flag_next_runtime)
 	{
-	  decl = TREE_PURPOSE (chain);
-	  finish_var_decl (decl, expr);
-	}
-      else
-	{
 	  if (flag_typed_selectors)
 	    {
 	      VEC(constructor_elt,gc) *v = NULL;
@@ -2635,9 +2660,8 @@  static void
 
 	  CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr);
 	}
-    }
+    } /* each element in the chain */
 
-  if (! flag_next_runtime)
     {
       /* Cause the selector table (previously forward-declared)
 	 to be actually output.	 */
@@ -2646,12 +2670,12 @@  static void
       if (flag_typed_selectors)
 	{
 	  VEC(constructor_elt,gc) *v = NULL;
-	  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0));
-	  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0));
+	  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node);
+	  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node);
 	  expr = objc_build_constructor (objc_selector_template, v);
 	}
       else
-	expr = build_int_cst (NULL_TREE, 0);
+	expr = integer_zero_node;
 
       CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr);
       expr = objc_build_constructor (TREE_TYPE (UOBJC_SELECTOR_TABLE_decl),
@@ -2855,19 +2879,34 @@  objc_get_class_reference (tree ident)
 /* For each string section we have a chain which maps identifier nodes
    to decls for the strings.  */
 
+static GTY(()) int class_names_idx;
+static GTY(()) int meth_var_names_idx;
+static GTY(()) int meth_var_types_idx;
+
 static tree
 add_objc_string (tree ident, enum string_section section)
 {
-  tree *chain, decl, type, string_expr;
-
+  tree *chain, decl, type, string_expr, namefromsect;
+  char buf[256];
+  
+  buf[0] = 0;
   if (section == class_names)
-    chain = &class_names_chain;
+    {
+      chain = &class_names_chain;
+      sprintf (buf, "_OBJC_CLASS_NAME_%d", class_names_idx++);
+    }
   else if (section == meth_var_names)
-    chain = &meth_var_names_chain;
+    {
+      chain = &meth_var_names_chain;
+      sprintf (buf, "_OBJC_METH_VAR_NAME_%d", meth_var_names_idx++);
+    }
   else if (section == meth_var_types)
-    chain = &meth_var_types_chain;
+    {
+      chain = &meth_var_types_chain;
+      sprintf (buf, "_OBJC_METH_VAR_TYPE_%d", meth_var_types_idx++);
+    }
   else
-    abort ();
+    gcc_unreachable ();
 
   while (*chain)
     {
@@ -2879,14 +2918,15 @@  add_objc_string (tree ident, enum string_section s
       chain = &TREE_CHAIN (*chain);
     }
 
-  decl = build_objc_string_decl (section);
+  namefromsect = get_identifier (buf);
 
   type = build_array_type
 	 (char_type_node,
 	  build_index_type
 	  (build_int_cst (NULL_TREE,
 			  IDENTIFIER_LENGTH (ident))));
-  decl = start_var_decl (type, IDENTIFIER_POINTER (DECL_NAME (decl)));
+  decl = start_var_decl (type, IDENTIFIER_POINTER (namefromsect));
+  TREE_CONSTANT (decl) = 1;
   string_expr = my_build_string (IDENTIFIER_LENGTH (ident) + 1,
 				 IDENTIFIER_POINTER (ident));
   finish_var_decl (decl, string_expr);
@@ -2897,44 +2937,6 @@  add_objc_string (tree ident, enum string_section s
 						    ADDR_EXPR, decl, 1));
 }
 
-static GTY(()) int class_names_idx;
-static GTY(()) int meth_var_names_idx;
-static GTY(()) int meth_var_types_idx;
-
-static tree
-build_objc_string_decl (enum string_section section)
-{
-  tree decl, ident;
-  char buf[256];
-
-  if (section == class_names)
-    sprintf (buf, "_OBJC_CLASS_NAME_%d", class_names_idx++);
-  else if (section == meth_var_names)
-    sprintf (buf, "_OBJC_METH_VAR_NAME_%d", meth_var_names_idx++);
-  else if (section == meth_var_types)
-    sprintf (buf, "_OBJC_METH_VAR_TYPE_%d", meth_var_types_idx++);
-
-  ident = get_identifier (buf);
-
-  decl = build_decl (input_location,
-		     VAR_DECL, ident, build_array_type (char_type_node, 0));
-  DECL_EXTERNAL (decl) = 1;
-  TREE_PUBLIC (decl) = 0;
-  TREE_USED (decl) = 1;
-  TREE_CONSTANT (decl) = 1;
-  DECL_CONTEXT (decl) = 0;
-  DECL_ARTIFICIAL (decl) = 1;
-#ifdef OBJCPLUS
-  DECL_THIS_STATIC (decl) = 1; /* squash redeclaration errors */
-#endif
-
-  make_decl_rtl (decl);
-  pushdecl_top_level (decl);
-
-  return decl;
-}
-
-
 void
 objc_declare_alias (tree alias_ident, tree class_ident)
 {
@@ -5418,7 +5420,7 @@  generate_dispatch_table (tree type, const char *na
   decl = start_var_decl (type, synth_id_with_class_suffix
 			       (name, objc_implementation_context));
 
-  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0));
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node);
   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, size));
   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, list);
 
@@ -5744,12 +5746,16 @@  lookup_category (tree klass, tree cat_name)
 /* static struct objc_category _OBJC_CATEGORY_<name> = { ... };  */
 
 static void
-generate_category (tree cat)
+generate_category (struct imp_entry *impent)
 {
-  tree decl;
   tree initlist, cat_name_expr, class_name_expr;
   tree protocol_decl, category;
+  tree cat = impent->imp_context;
 
+  implementation_template = impent->imp_template;
+  UOBJC_CLASS_decl = impent->class_decl;
+  UOBJC_METACLASS_decl = impent->meta_decl;
+
   add_class_reference (CLASS_NAME (cat));
   cat_name_expr = add_objc_string (CLASS_SUPER_NAME (cat), class_names);
 
@@ -5766,30 +5772,32 @@  static void
   else
     protocol_decl = 0;
 
-  decl = start_var_decl (objc_category_template,
-			 synth_id_with_class_suffix
-			 ("_OBJC_CATEGORY", objc_implementation_context));
-
-  initlist = build_category_initializer (TREE_TYPE (decl),
+  initlist = build_category_initializer (TREE_TYPE (UOBJC_CLASS_decl),
 					 cat_name_expr, class_name_expr,
 					 UOBJC_INSTANCE_METHODS_decl,
 					 UOBJC_CLASS_METHODS_decl,
 					 protocol_decl);
-
-  finish_var_decl (decl, initlist);
+  /* Finish and initialize the forward decl.  */
+  finish_var_decl (UOBJC_CLASS_decl, initlist);
 }
 
 /* static struct objc_class _OBJC_METACLASS_Foo={ ... };
    static struct objc_class _OBJC_CLASS_Foo={ ... };  */
 
 static void
-generate_shared_structures (int cls_flags)
+generate_shared_structures (struct imp_entry *impent)
 {
-  tree decl;
   tree name_expr, super_expr, root_expr;
-  tree my_root_id = NULL_TREE, my_super_id = NULL_TREE;
+  tree my_root_id, my_super_id;
   tree cast_type, initlist, protocol_decl;
-
+  int cls_flags;
+  
+  objc_implementation_context = impent->imp_context;
+  implementation_template = impent->imp_template;
+  UOBJC_CLASS_decl = impent->class_decl;
+  UOBJC_METACLASS_decl = impent->meta_decl;
+  cls_flags = impent->has_cxx_cdtors ? CLS_HAS_CXX_STRUCTORS : 0 ;
+  
   my_super_id = CLASS_SUPER_NAME (implementation_template);
   if (my_super_id)
     {
@@ -5820,13 +5828,12 @@  static void
 
   /* Install class `isa' and `super' pointers at runtime.  */
   if (my_super_id)
-    {
-      super_expr = add_objc_string (my_super_id, class_names);
-      super_expr = build_c_cast (input_location,
+    super_expr = add_objc_string (my_super_id, class_names);
+  else
+    super_expr = integer_zero_node;
+    
+  super_expr = build_c_cast (input_location,
 				 cast_type, super_expr); /* cast! */
-    }
-  else
-    super_expr = build_int_cst (NULL_TREE, 0);
 
   root_expr = add_objc_string (my_root_id, class_names);
   root_expr = build_c_cast (input_location, cast_type, root_expr); /* cast! */
@@ -5842,13 +5849,9 @@  static void
 
   /* static struct objc_class _OBJC_METACLASS_Foo = { ... }; */
 
-  decl = start_var_decl (objc_class_template,
-			 IDENTIFIER_POINTER
-			 (DECL_NAME (UOBJC_METACLASS_decl)));
-
   initlist
     = build_shared_structure_initializer
-      (TREE_TYPE (decl),
+      (TREE_TYPE (UOBJC_METACLASS_decl),
        root_expr, super_expr, name_expr,
        convert (integer_type_node, TYPE_SIZE_UNIT (objc_class_template)),
        2 /*CLS_META*/,
@@ -5856,17 +5859,13 @@  static void
        UOBJC_CLASS_VARIABLES_decl,
        protocol_decl);
 
-  finish_var_decl (decl, initlist);
+  finish_var_decl (UOBJC_METACLASS_decl, initlist);
 
   /* static struct objc_class _OBJC_CLASS_Foo={ ... }; */
 
-  decl = start_var_decl (objc_class_template,
-			 IDENTIFIER_POINTER
-			 (DECL_NAME (UOBJC_CLASS_decl)));
-
   initlist
     = build_shared_structure_initializer
-      (TREE_TYPE (decl),
+      (TREE_TYPE (UOBJC_CLASS_decl),
        build_unary_op (input_location, ADDR_EXPR, UOBJC_METACLASS_decl, 0),
        super_expr, name_expr,
        convert (integer_type_node,
@@ -5877,7 +5876,7 @@  static void
        UOBJC_INSTANCE_VARIABLES_decl,
        protocol_decl);
 
-  finish_var_decl (decl, initlist);
+  finish_var_decl (UOBJC_CLASS_decl, initlist);
 }
 
 
@@ -9262,15 +9261,17 @@  finish_objc (void)
   if (objc_static_instances)
     generate_static_references ();
 
-  if (imp_list || class_names_chain
-      || meth_var_names_chain || meth_var_types_chain || sel_ref_chain)
-    generate_objc_symtab_decl ();
+  /* forward declare categories */
+  if (cat_count)
+    forward_declare_categories ();
 
   for (impent = imp_list; impent; impent = impent->next)
     {
       objc_implementation_context = impent->imp_context;
       implementation_template = impent->imp_template;
 
+      /* FIXME: This needs reworking to be more obvious.  */
+
       UOBJC_CLASS_decl = impent->class_decl;
       UOBJC_METACLASS_decl = impent->meta_decl;
 
@@ -9288,28 +9289,35 @@  finish_objc (void)
 	  /* all of the following reference the string pool...  */
 	  generate_ivar_lists ();
 	  generate_dispatch_tables ();
-	  generate_shared_structures (impent->has_cxx_cdtors
-				      ? CLS_HAS_CXX_STRUCTORS
-				      : 0);
+	  generate_shared_structures (impent);
 	}
       else
 	{
 	  generate_dispatch_tables ();
-	  generate_category (objc_implementation_context);
+	  generate_category (impent);
 	}
+
+      impent->class_decl = UOBJC_CLASS_decl;
+      impent->meta_decl = UOBJC_METACLASS_decl;
     }
 
   /* If we are using an array of selectors, we must always
      finish up the array decl even if no selectors were used.  */
-  if (! flag_next_runtime || sel_ref_chain)
-    build_selector_translation_table ();
+  if (flag_next_runtime)
+    build_next_selector_translation_table ();
+  else
+    build_gnu_selector_translation_table ();
 
   if (protocol_chain)
     generate_protocols ();
 
-  if ((flag_replace_objc_classes && imp_list) || flag_objc_gc)
+  if (flag_next_runtime)
     generate_objc_image_info ();
 
+  if (imp_list || class_names_chain
+      || meth_var_names_chain || meth_var_types_chain || sel_ref_chain)
+    generate_objc_symtab_decl ();
+
   /* Arrange for ObjC data structures to be initialized at run time.  */
   if (objc_implementation_context || class_names_chain || objc_static_instances
       || meth_var_names_chain || meth_var_types_chain || sel_ref_chain)
@@ -9368,8 +9376,9 @@  generate_classref_translation_entry (tree chain)
   expr = add_objc_string (TREE_VALUE (chain), class_names);
   expr = convert (type, expr); /* cast! */
 
-  /* The decl that is the one that we
-     forward declared in build_class_reference.  */
+  /* This is a class reference.  It is re-written by the runtime,
+     but will be optimized away unless we force it.  */
+  DECL_PRESERVE_P (decl) = 1;
   finish_var_decl (decl, expr);
   return;
 }
@@ -9395,12 +9404,11 @@  handle_class_ref (tree chain)
 
   /* Make a decl for this name, so we can use its address in a tree.  */
   decl = build_decl (input_location,
-		     VAR_DECL, get_identifier (string), char_type_node);
+		     VAR_DECL, get_identifier (string), TREE_TYPE (integer_zero_node));
   DECL_EXTERNAL (decl) = 1;
   TREE_PUBLIC (decl) = 1;
-
   pushdecl (decl);
-  rest_of_decl_compilation (decl, 0, 0);
+  finish_var_decl (decl, 0);
 
   /* Make a decl for the address.  */
   sprintf (string, "%sobjc_class_ref_%s",
@@ -9408,15 +9416,17 @@  handle_class_ref (tree chain)
   exp = build1 (ADDR_EXPR, string_type_node, decl);
   decl = build_decl (input_location,
 		     VAR_DECL, get_identifier (string), string_type_node);
-  DECL_INITIAL (decl) = exp;
   TREE_STATIC (decl) = 1;
   TREE_USED (decl) = 1;
   DECL_READ_P (decl) = 1;
-  /* Force the output of the decl as this forces the reference of the class.  */
-  mark_decl_referenced (decl);
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_INITIAL (decl) = error_mark_node;
+ 
+  /* We must force the reference.  */
+  DECL_PRESERVE_P (decl) = 1;
 
   pushdecl (decl);
-  rest_of_decl_compilation (decl, 0, 0);
+  finish_var_decl (decl, exp);
 }
 
 static void
@@ -9467,17 +9477,21 @@  handle_impent (struct imp_entry *impent)
     {
       tree decl, init;
 
-      init = build_int_cst (c_common_type_for_size (BITS_PER_WORD, 1), 0);
+      init = integer_zero_node;
       decl = build_decl (input_location,
 			 VAR_DECL, get_identifier (string), TREE_TYPE (init));
       TREE_PUBLIC (decl) = 1;
       TREE_READONLY (decl) = 1;
       TREE_USED (decl) = 1;
       TREE_CONSTANT (decl) = 1;
-      DECL_CONTEXT (decl) = 0;
+      DECL_CONTEXT (decl) = NULL_TREE;
       DECL_ARTIFICIAL (decl) = 1;
-      DECL_INITIAL (decl) = init;
-      assemble_variable (decl, 1, 0, 0);
+      TREE_STATIC (decl) = 1;
+      DECL_INITIAL (decl) = error_mark_node; /* A real initializer is coming... */
+      /* We must force the reference.  */
+      DECL_PRESERVE_P (decl) = 1;
+
+      finish_var_decl(decl, init) ;
     }
 }
 
@@ -9501,9 +9515,16 @@  generate_objc_image_info (void)
 			  build_index_type (build_int_cst (NULL_TREE, 2 - 1))),
 			 "_OBJC_IMAGE_INFO");
 
-  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0));
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node);
   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, flags));
 
+  if (flag_next_runtime)
+    {
+      tree sect = my_build_string (44, 
+      				"__OBJC,__image_info,regular,no_dead_strip");
+      DECL_SECTION_NAME (decl) = sect;
+    }
+  DECL_PRESERVE_P (decl) = 1;
   finish_var_decl (decl, objc_build_constructor (TREE_TYPE (decl), v));
 }
 
Index: gcc/testsuite/objc.dg/lto/trivial-1_0.m
===================================================================
--- gcc/testsuite/objc.dg/lto/trivial-1_0.m	(revision 0)
+++ gcc/testsuite/objc.dg/lto/trivial-1_0.m	(revision 0)
@@ -0,0 +1,37 @@ 
+/* { dg-lto-do run } */
+/* { dg-skip-if "" { "*-*-darwin*" && lp64 } { "*" } { "" } } */
+extern int printf (char *,...) ;
+
+typedef struct objc_class *Class;
+
+struct objc_class {
+    Class isa;
+    /* other stuff... */
+}  ;
+
+@interface myRootObject {
+@public
+     Class isa;
+}
++initialize;
++(Class)class;
+
+@end
+
+@implementation myRootObject
++initialize {
+     return self;
+}
+
++(Class)class {
+     return (Class)self;
+}
+
+@end
+
+int main(void)
+{
+  [myRootObject class];
+  printf("trivial OK\n");
+  return 0;
+}
Index: gcc/testsuite/objc.dg/lto/lto.exp
===================================================================
--- gcc/testsuite/objc.dg/lto/lto.exp	(revision 0)
+++ gcc/testsuite/objc.dg/lto/lto.exp	(revision 0)
@@ -0,0 +1,84 @@ 
+# Copyright (C) 2010 Free Software Foundation, Inc.
+
+# This program 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+#
+# Based on gcc/testsuite/gcc.dg/lto/lto.exp.
+
+# Test link-time optimization across multiple files.
+#
+# Programs are broken into multiple files.  Each one is compiled
+# separately with LTO information.  The final executable is generated
+# by collecting all the generated object files using regular LTO or WHOPR.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+# Load procedures from common libraries. 
+load_lib standard.exp
+load_lib objc-dg.exp
+
+# Load the language-independent compabibility support procedures.
+load_lib lto.exp
+
+# If LTO has not been enabled, bail.
+if { ![check_effective_target_lto] } {
+    return
+}
+
+global LTO_OPTIONS
+
+set LTO_OPTIONS [list	\
+  {-O0 -fwhopr -fgnu-runtime}	\
+  {-O2 -fwhopr -fgnu-runtime}	\
+  {-O0 -flto -fgnu-runtime} 	\
+  {-O2 -flto -fgnu-runtime}	\
+]
+
+objc_init
+lto_init no-mathlib
+
+# Define an identifier for use with this suite to avoid name conflicts
+# with other lto tests running at the same time.
+set sid "objc_lto"
+set tests [lsort [glob -nocomplain $srcdir/$subdir/*_0.m]]
+
+# Main loop.
+foreach src $tests {
+    # If we're only testing specific files and this isn't one of them, skip it.
+    if ![runtest_file_p $runtests $src] then {
+	continue
+    }
+    lto-execute $src $sid
+}
+
+# darwin targets can also run code with the NeXT runtime.
+if [istarget "*-*-darwin*" ] {
+set LTO_OPTIONS [list	\
+  {-O0 -fwhopr -fnext-runtime}	\
+  {-O2 -fwhopr -fnext-runtime}	\
+  {-O0 -flto -fnext-runtime} 	\
+  {-O2 -flto -fnext-runtime}	\
+]
+  foreach src $tests {
+    # If we're only testing specific files and this isn't one of them, skip it.
+    if ![runtest_file_p $runtests $src] then {
+	continue
+    }
+    lto-execute $src $sid
+  }
+}
+
+lto_finish
Index: gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm	(revision 0)
@@ -0,0 +1,43 @@ 
+/* { dg-lto-do run } */
+/* { dg-skip-if "Needs OBJC2 ABI" { "*-*-darwin*" && lp64 } { "*" } { "" } } */
+extern "C" {
+extern int printf (char *,...) ;
+extern void abort (void) ;
+} 
+
+typedef struct objc_class *Class;
+
+struct objc_class {
+    Class isa;
+    /* other stuff... */
+}  ;
+
+@interface myRootObject {
+@public
+     Class isa; 
+}
++initialize;
++(Class)class;
+
+@end
+
+@implementation myRootObject
++initialize {
+     return self;
+}
+
++(Class)class {
+     return (Class)self;
+}
+
+@end
+
+int main(void)
+{
+  Class cl = [myRootObject class];
+  if (cl != (Class)0) {
+    printf((char *)"trivial OK\n");
+    return 0;
+  }
+  abort () ;
+}
Index: gcc/testsuite/obj-c++.dg/lto/lto.exp
===================================================================
--- gcc/testsuite/obj-c++.dg/lto/lto.exp	(revision 0)
+++ gcc/testsuite/obj-c++.dg/lto/lto.exp	(revision 0)
@@ -0,0 +1,84 @@ 
+# Copyright (C) 2010 Free Software Foundation, Inc.
+
+# This program 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+#
+# Based on gcc/testsuite/gcc.dg/lto/lto.exp.
+
+# Test link-time optimization across multiple files.
+#
+# Programs are broken into multiple files.  Each one is compiled
+# separately with LTO information.  The final executable is generated
+# by collecting all the generated object files using regular LTO or WHOPR.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+# Load procedures from common libraries. 
+load_lib standard.exp
+load_lib obj-c++-dg.exp
+
+# Load the language-independent compabibility support procedures.
+load_lib lto.exp
+
+# If LTO has not been enabled, bail.
+if { ![check_effective_target_lto] } {
+    return
+}
+
+global LTO_OPTIONS
+
+set LTO_OPTIONS [list	\
+  {-O0 -fwhopr -fgnu-runtime}	\
+  {-O2 -fwhopr -fgnu-runtime}	\
+  {-O0 -flto -fgnu-runtime} 	\
+  {-O2 -flto -fgnu-runtime}	\
+]
+
+obj-c++_init
+lto_init no-mathlib
+
+# Define an identifier for use with this suite to avoid name conflicts
+# with other lto tests running at the same time.
+set sid "obj_cpp_lto"
+set tests [lsort [glob -nocomplain $srcdir/$subdir/*_0.mm]]
+
+# Main loop.
+foreach src $tests {
+    # If we're only testing specific files and this isn't one of them, skip it.
+    if ![runtest_file_p $runtests $src] then {
+	continue
+    }
+    lto-execute $src $sid
+}
+
+# darwin targets can also run code with the NeXT runtime.
+if [istarget "*-*-darwin*" ] {
+set LTO_OPTIONS [list	\
+  {-O0 -fwhopr -fnext-runtime}	\
+  {-O2 -fwhopr -fnext-runtime}	\
+  {-O0 -flto -fnext-runtime} 	\
+  {-O2 -flto -fnext-runtime}	\
+]
+  foreach src $tests {
+    # If we're only testing specific files and this isn't one of them, skip it.
+    if ![runtest_file_p $runtests $src] then {
+	continue
+    }
+    lto-execute $src $sid
+  }
+}
+
+lto_finish