On Wed, Jun 29, 2011 at 7:47 PM, Iain Sandoe
<[email protected]> wrote:
> The bug arises because of the use, by the ObjC FE, of two old target macros
> that emit efficient representations of class definitions and references.
>
> This 'works fine' (however wrong it might be conceptually), until LTO is
> engaged, whereupon the definitions vanish without trace (since no
> corresponding real variable is ever created).
>
> ---
>
> The patch creates appropriate variables in the FE and tags them as ObjC
> meta-data (in the same manner as is done for other objc meta-data).
>
> We then intercept them in varasm.c with a hook that allows the target to
> declare that it has completely handled the output of a variable - allowing
> us to handle them in the required special manner.
>
> FAOD, It is necessary to preserve this mechanism for emitting the
> definitions and references to permit linkage with existing system libraries.
>
> ----
>
> If the patch is acceptable, then I would expect to follow up with a patch to
> remove ASM_DECLARE_CLASS_REFERENCE and ASM_DECLARE_UNRESOLVED_REFERENCE from
> the tree - since this is their only use.
>
> ----
>
> bootstrapped on i686-linux, i686-darwin9, x86_64-darwin10, (checked to do
> the Right Thing on darwin).
>
> Mike has already given this a 'seems reasonable' in the PR thread, however,
> I need an approver for the varasm.c and target hook changes.
>
> OK for trunk & 4.6?
Where does the target handle output of the variable? If it is in the hook
then that hook is misnamed - it should then probably be called
assemble_variable. Not sure if this is the most reasonable piece of
assemble_variable to split out to a hook though.
I'm not sure we want to backport this though (there isn't even a bugreport
about it?).
Thanks,
Richard.
> Iain
>
> ===
>
> gcc/
>
> * target.def (handled_assemble_variable_p): New hook.
> * varasm.c (assemble_variable): Allow target to handle variable
> output
> in some special manner.
> * doc/tm.texi: Regenerate.
> * config/darwin.c (darwin_objc1_section): Handle class defs/refs.
> (darwin_handled_assemble_variable_p): New.
> * config/darwin-protos.h (darwin_handled_assemble_variable_p): New.
> * config/darwin.h (TARGET_ASM_HANDLED_ASSEMBLE_VARIABLE_P): New.
>
> gcc/objc/
>
> *objc-next-runtime-abi-01.c (handle_next_class_ref): Don't emit lazy
> refs. for
> cases where the class is local. Declare a real, meta-data item
> tagged as
> a class reference.
> (handle_next_impent): Declare a real, meta-data item tagged as a
> class def.
>
> ===
>
> Index: gcc/target.def
> ===================================================================
> --- gcc/target.def (revision 175628)
> +++ gcc/target.def (working copy)
> @@ -449,6 +449,13 @@ DEFHOOK
> bool, (FILE *file, rtx x),
> default_asm_output_addr_const_extra)
>
> +DEFHOOK
> +(handled_assemble_variable_p,
> + "Returns @code{true} iff the target has handled the assembly of the\
> + variable @var{var_decl}",
> + bool, (tree var_decl),
> + hook_bool_tree_false)
> +
> /* ??? The TARGET_PRINT_OPERAND* hooks are part of the asm_out struct,
> even though that is not reflected in the macro name to override their
> initializers. */
> Index: gcc/objc/objc-next-runtime-abi-01.c
> ===================================================================
> --- gcc/objc/objc-next-runtime-abi-01.c (revision 175628)
> +++ gcc/objc/objc-next-runtime-abi-01.c (working copy)
> @@ -2267,27 +2267,51 @@ generate_objc_symtab_decl (void)
> init_objc_symtab (TREE_TYPE (UOBJC_SYMBOLS_decl)));
> }
>
> -
> static void
> handle_next_class_ref (tree chain)
> {
> + tree decl, exp;
> + struct imp_entry *impent;
> const char *name = IDENTIFIER_POINTER (TREE_VALUE (chain));
> char *string = (char *) alloca (strlen (name) + 30);
>
> + for (impent = imp_list; impent; impent = impent->next)
> + if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE
> + && IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))
> + == IDENTIFIER_POINTER (TREE_VALUE (chain)))
> + return; /* we declare this, no need for a lazy ref. */
> +
> sprintf (string, ".objc_class_name_%s", name);
>
> -#ifdef ASM_DECLARE_UNRESOLVED_REFERENCE
> - ASM_DECLARE_UNRESOLVED_REFERENCE (asm_out_file, string);
> -#else
> - return ; /* NULL build for targets other than Darwin. */
> -#endif
> + decl = build_decl (UNKNOWN_LOCATION,
> + VAR_DECL, get_identifier (string), char_type_node);
> + TREE_PUBLIC (decl) = 1;
> + DECL_EXTERNAL (decl) = 1;
> + DECL_CONTEXT (decl) = NULL_TREE;
> + finish_var_decl (decl, NULL);
> +
> + /* We build a variable to signal the reference. This will be intercepted
> + and output as a lazy reference. */
> + sprintf (string, "_OBJC_class_ref_%s", name);
> + exp = build1 (ADDR_EXPR, string_type_node, decl);
> + decl = build_decl (input_location,
> + VAR_DECL, get_identifier (string), string_type_node);
> + TREE_STATIC (decl) = 1;
> + DECL_ARTIFICIAL (decl) = 1;
> + DECL_INITIAL (decl) = error_mark_node;
> +
> + /* We must force the reference. */
> + DECL_PRESERVE_P (decl) = 1;
> + OBJCMETA (decl, objc_meta, get_identifier ("V1_CREF"));
> + DECL_CONTEXT (decl) = NULL_TREE;
> + finish_var_decl (decl, exp);
> }
>
> static void
> handle_next_impent (struct imp_entry *impent)
> {
> char buf[BUFSIZE];
> -
> + tree decl;
> switch (TREE_CODE (impent->imp_context))
> {
> case CLASS_IMPLEMENTATION_TYPE:
> @@ -2303,11 +2327,16 @@ handle_next_impent (struct imp_entry *impent)
> return;
> }
>
> -#ifdef ASM_DECLARE_CLASS_REFERENCE
> - ASM_DECLARE_CLASS_REFERENCE (asm_out_file, buf);
> -#else
> - return ; /* NULL build for targets other than Darwin. */
> -#endif
> + /* We build a variable to signal that this TU contains this class
> metadata. */
> + decl = build_decl (UNKNOWN_LOCATION,
> + VAR_DECL, get_identifier (buf), char_type_node);
> + TREE_PUBLIC (decl) = 1;
> + DECL_CONTEXT (decl) = NULL_TREE;
> + OBJCMETA (decl, objc_meta, get_identifier ("V1_CDEF"));
> + TREE_STATIC (decl) = 1;
> + DECL_ARTIFICIAL (decl) = 1;
> + DECL_INITIAL (decl) = error_mark_node;
> + finish_var_decl (decl, NULL);
> }
>
> static void
> Index: gcc/varasm.c
> ===================================================================
> --- gcc/varasm.c (revision 175628)
> +++ gcc/varasm.c (working copy)
> @@ -2009,6 +2009,10 @@ assemble_variable (tree decl, int top_level ATTRIB
> align_variable (decl, dont_output_data);
> set_mem_align (decl_rtl, DECL_ALIGN (decl));
>
> + /* Allow the target to handle the variable output in some special manner.
> */
> + if (targetm.asm_out.handled_assemble_variable_p (decl))
> + return;
> +
> if (TREE_PUBLIC (decl))
> maybe_assemble_visibility (decl);
>
> Index: gcc/config/darwin-protos.h
> ===================================================================
> --- gcc/config/darwin-protos.h (revision 175628)
> +++ gcc/config/darwin-protos.h (working copy)
> @@ -106,6 +106,7 @@ extern void darwin_asm_output_aligned_decl_local (
> extern void darwin_asm_output_aligned_decl_common (FILE *, tree, const char
> *,
> unsigned HOST_WIDE_INT,
> unsigned int);
> +extern bool darwin_handled_assemble_variable_p (tree);
>
> extern bool darwin_binds_local_p (const_tree);
> extern void darwin_cpp_builtins (struct cpp_reader *);
> Index: gcc/config/darwin.c
> ===================================================================
> --- gcc/config/darwin.c (revision 175628)
> +++ gcc/config/darwin.c (working copy)
> @@ -1439,6 +1439,11 @@ darwin_objc1_section (tree decl ATTRIBUTE_UNUSED,
> else if (!strncmp (p, "V2_CSTR", 7))
> return darwin_sections[objc_constant_string_object_section];
>
> + else if (!strncmp (p, "V1_CREF", 7))
> + return darwin_sections[objc_cls_refs_section];
> + else if (!strncmp (p, "V1_CDEF", 7))
> + return data_section;
> +
> return base;
> }
>
> @@ -2594,6 +2599,53 @@ darwin_assemble_visibility (tree decl, int vis)
> "not supported in this configuration; ignored");
> }
>
> +/* For certain Objective-C metadata we handle the assembly of the variables
> + here (it must be here, rather than in darwin-c.c, to cater for LTO).
> When
> + we reference a class we emit a lazy ref, when we have class metadata
> + (local to a specific object), we emit a tag so that linkage will be
> + satisfied for the class. */
> +
> +bool
> +darwin_handled_assemble_variable_p (tree decl)
> +{
> + tree meta;
> + if (DECL_ATTRIBUTES (decl)
> + && (meta = lookup_attribute ("OBJC1META", DECL_ATTRIBUTES (decl))))
> + {
> + const char *name;
> + rtx decl_rtl, symbol;
> +
> + if (TREE_VALUE (meta) == get_identifier ("V1_CREF"))
> + {
> + tree exp = DECL_INITIAL (decl);
> + gcc_assert (exp
> + && exp != error_mark_node
> + && TREE_CODE (exp) == ADDR_EXPR);
> + exp = TREE_OPERAND (exp, 0);
> + decl_rtl = DECL_RTL (exp);
> + symbol = XEXP (decl_rtl, 0);
> + name = XSTR (symbol, 0);
> + targetm.asm_out.globalize_decl_name (asm_out_file, exp);
> + fputs ("\t.lazy_reference\t",asm_out_file);
> + assemble_name (asm_out_file, name);
> + fputs ("\n",asm_out_file);
> + return true;
> + }
> + else if (TREE_VALUE (meta) == get_identifier ("V1_CDEF"))
> + {
> + decl_rtl = DECL_RTL (decl);
> + symbol = XEXP (decl_rtl, 0);
> + name = XSTR (symbol, 0);
> + targetm.asm_out.globalize_decl_name (asm_out_file, decl);
> + fputs ("\t",asm_out_file);
> + assemble_name (asm_out_file, name);
> + fputs (" = 0\n",asm_out_file);
> + return true;
> + }
> + }
> + return false;
> +}
> +
> /* VEC Used by darwin_asm_dwarf_section.
> Maybe a hash tab would be better here - but the intention is that this is
> a very short list (fewer than 16 items) and each entry should (ideally,
> Index: gcc/config/darwin.h
> ===================================================================
> --- gcc/config/darwin.h (revision 175628)
> +++ gcc/config/darwin.h (working copy)
> @@ -678,6 +678,9 @@ extern GTY(()) section * darwin_sections[NUM_DARWI
> #undef TARGET_ASM_SELECT_SECTION
> #define TARGET_ASM_SELECT_SECTION machopic_select_section
>
> +#undef TARGET_ASM_HANDLED_ASSEMBLE_VARIABLE_P
> +#define TARGET_ASM_HANDLED_ASSEMBLE_VARIABLE_P
> darwin_handled_assemble_variable_p
> +
> #undef TARGET_ASM_FUNCTION_SECTION
> #define TARGET_ASM_FUNCTION_SECTION darwin_function_section
>
>
>
>