diff options
author | Iain Sandoe <iains@gcc.gnu.org> | 2011-02-18 00:07:38 +0000 |
---|---|---|
committer | Nicola Pero <nicola@gcc.gnu.org> | 2011-02-18 00:07:38 +0000 |
commit | d764a8e6bdae09aecb7a8378def9d900f84ce53e (patch) | |
tree | c0b6f091c931f0a65e3fb59fbd9fff3f5ba9bde9 | |
parent | 0a8134cacea8b18b0e241cc492546cbb69ae598a (diff) | |
download | gcc-d764a8e6bdae09aecb7a8378def9d900f84ce53e.zip gcc-d764a8e6bdae09aecb7a8378def9d900f84ce53e.tar.gz gcc-d764a8e6bdae09aecb7a8378def9d900f84ce53e.tar.bz2 |
Added support for the 64-bit Apple Objective-C runtime
From-SVN: r170260
70 files changed, 12197 insertions, 4765 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8382f50..7fecfea 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2011-02-17 Iain Sandoe <iains@gcc.gnu.org> + + * config/darwin-c.c (darwin_cpp_builtins): Define __OBJC2__ for + objc_abi == 2. + * config/darwin.c (output_objc_section_asm_op): Added support for + ABI v1 and v2. + (is_objc_metadata): New. + (darwin_objc2_section): New. + (darwin_objc1_section): New. + (machopic_select_section): Added support for ABI v1 and v2. + (darwin_emit_objc_zeroed): New. + (darwin_output_aligned_bss): Detect objc metadata and treat it + appropriately. + (darwin_asm_output_aligned_decl_common): Same. + (darwin_asm_output_aligned_decl_local): Same. + * config/darwin-sections.def: Updated for ABI v1 and v2. + * config/darwin.h (SUBTARGET_C_COMMON_OVERRIDE_OPTIONS): When + compiling Objective-C code for the NeXT runtime, default to using + ABI version 0 for 32-bit, and version 2 for 64-bit. + 2011-02-17 Joseph Myers <joseph@codesourcery.com> * common.opt (optimize_fast): New Variable. diff --git a/gcc/config/darwin-c.c b/gcc/config/darwin-c.c index c246f70..0c713ba 100644 --- a/gcc/config/darwin-c.c +++ b/gcc/config/darwin-c.c @@ -629,6 +629,9 @@ darwin_cpp_builtins (cpp_reader *pfile) builtin_define ("__strong="); builtin_define ("__weak="); } + + if (flag_objc_abi == 2) + builtin_define ("__OBJC2__"); } /* Handle C family front-end options. */ diff --git a/gcc/config/darwin-sections.def b/gcc/config/darwin-sections.def index 62d1d8d..61b6f69 100644 --- a/gcc/config/darwin-sections.def +++ b/gcc/config/darwin-sections.def @@ -94,7 +94,7 @@ DEF_SECTION (mod_term_section, 0, ".mod_term_func", 0) DEF_SECTION (constructor_section, 0, ".constructor", 0) DEF_SECTION (destructor_section, 0, ".destructor", 0) -/* Objective-C (V1) sections. */ +/* Objective-C ABI=0 (Original version) sections. */ DEF_SECTION (objc_class_section, 0, ".objc_class", 1) DEF_SECTION (objc_meta_class_section, 0, ".objc_meta_class", 1) DEF_SECTION (objc_category_section, 0, ".objc_category", 1) @@ -112,7 +112,7 @@ DEF_SECTION (objc_module_info_section, 0, ".objc_module_info", 1) DEF_SECTION (objc_protocol_section, 0, ".objc_protocol", 1) DEF_SECTION (objc_string_object_section, 0, ".objc_string_object", 1) DEF_SECTION (objc_constant_string_object_section, 0, - ".section __OBJC, __cstring_object, regular, no_dead_strip", 1) + ".section __OBJC, __cstring_object, regular, no_dead_strip", 0) /* Fix-and-Continue image marker. */ DEF_SECTION (objc_image_info_section, 0, @@ -156,3 +156,40 @@ DEF_SECTION (darwin_exception_section, SECTION_NO_ANCHOR, DEF_SECTION (darwin_eh_frame_section, SECTION_NO_ANCHOR, ".section " EH_FRAME_SECTION_NAME ",__eh_frame" EH_FRAME_SECTION_ATTR, 0) + +/* Sections for ObjC ABI=1 (ObjC 'V1' extensions) */ +DEF_SECTION (objc1_class_ext_section, 0, + ".section __OBJC, __class_ext, regular, no_dead_strip", 1) +DEF_SECTION (objc1_prop_list_section, 0, + ".section __OBJC, __property, regular, no_dead_strip", 1) +DEF_SECTION (objc1_protocol_ext_section, 0, + ".section __OBJC, __protocol_ext, regular, no_dead_strip", 1) + +/* Sections for ObjC ABI=2 (m64). */ +DEF_SECTION (objc2_message_refs_section, 0, + ".section __DATA, __objc_msgrefs, regular, no_dead_strip", 1) +DEF_SECTION (objc2_classdefs_section, 0, ".section __DATA, __objc_data", 1) +DEF_SECTION (objc2_metadata_section, 0, ".section __DATA, __objc_const", 1) + +DEF_SECTION (objc2_classrefs_section, 0, + ".section __DATA, __objc_classrefs, regular, no_dead_strip", 1) +DEF_SECTION (objc2_classlist_section, 0, + ".section __DATA, __objc_classlist, regular, no_dead_strip", 1) +DEF_SECTION (objc2_categorylist_section, 0, + ".section __DATA, __objc_catlist, regular, no_dead_strip", 1) +DEF_SECTION (objc2_selector_refs_section, 0, + ".section __DATA, __objc_selrefs, literal_pointers, no_dead_strip", 1) +DEF_SECTION (objc2_nonlazy_class_section, 0, + ".section __DATA, __objc_nlclslist, regular, no_dead_strip", 1) +DEF_SECTION (objc2_nonlazy_category_section, 0, + ".section __DATA, __objc_nlcatlist, regular, no_dead_strip", 1) +DEF_SECTION (objc2_protocollist_section, 0, + ".section __DATA, __objc_protolist, regular, no_dead_strip", 1) +DEF_SECTION (objc2_protocolrefs_section, 0, + ".section __DATA, __objc_protorefs, regular, no_dead_strip", 1) +DEF_SECTION (objc2_super_classrefs_section, 0, + ".section __DATA, __objc_superrefs, regular, no_dead_strip", 1) +DEF_SECTION (objc2_image_info_section, 0, + ".section __DATA, __objc_imageinfo, regular, no_dead_strip", 1) +DEF_SECTION (objc2_constant_string_object_section, 0, + ".section __DATA, __objc_stringobj, regular, no_dead_strip", 1) diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c index c31aeed..2969f10 100644 --- a/gcc/config/darwin.c +++ b/gcc/config/darwin.c @@ -148,13 +148,48 @@ output_objc_section_asm_op (const void *directive) objc_class_vars_section, objc_instance_vars_section, objc_module_info_section, - objc_symbols_section + objc_symbols_section, }; + /* ABI=1 */ + static const enum darwin_section_enum tomarkv1[] = + { + objc1_protocol_ext_section, + objc1_class_ext_section, + objc1_prop_list_section + } ; + /* ABI=2 */ + static const enum darwin_section_enum tomarkv2[] = + { + objc2_message_refs_section, + objc2_classdefs_section, + objc2_metadata_section, + objc2_classrefs_section, + objc2_classlist_section, + objc2_categorylist_section, + objc2_selector_refs_section, + objc2_nonlazy_class_section, + objc2_nonlazy_category_section, + objc2_protocollist_section, + objc2_protocolrefs_section, + objc2_super_classrefs_section, + objc2_image_info_section, + objc2_constant_string_object_section + } ; size_t i; been_here = true; - for (i = 0; i < ARRAY_SIZE (tomark); i++) - switch_to_section (darwin_sections[tomark[i]]); + if (flag_objc_abi < 2) + { + for (i = 0; i < ARRAY_SIZE (tomark); i++) + switch_to_section (darwin_sections[tomark[i]]); + if (flag_objc_abi == 1) + for (i = 0; i < ARRAY_SIZE (tomarkv1); i++) + switch_to_section (darwin_sections[tomarkv1[i]]); + } + else + for (i = 0; i < ARRAY_SIZE (tomarkv2); i++) + switch_to_section (darwin_sections[tomarkv2[i]]); + /* Make sure we don't get varasm.c out of sync with us. */ switch_to_section (saved_in_section); } output_section_asm_op (directive); @@ -277,7 +312,6 @@ indirect_data (rtx sym_ref) return ! lprefix; } - static int machopic_data_defined_p (rtx sym_ref) { @@ -1233,6 +1267,177 @@ machopic_reloc_rw_mask (void) return MACHOPIC_INDIRECT ? 3 : 0; } +/* We have to deal with ObjC/C++ metadata section placement in the common + code, since it will also be called from LTO. + + Return metadata attributes, if present (searching for ABI=2 first) + Return NULL_TREE if no such attributes are found. */ + +static tree +is_objc_metadata (tree decl) +{ + if (DECL_P (decl) + && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == CONST_DECL) + && DECL_ATTRIBUTES (decl)) + { + tree meta = lookup_attribute ("OBJC2META", DECL_ATTRIBUTES (decl)); + if (meta) + return meta; + meta = lookup_attribute ("OBJC1META", DECL_ATTRIBUTES (decl)); + if (meta) + return meta; + } + return NULL_TREE; +} + +/* Return the section required for Objective C ABI 2 metadata. */ +static section * +darwin_objc2_section (tree decl ATTRIBUTE_UNUSED, tree meta, section * base) +{ + const char *p; + tree ident = TREE_VALUE (meta); + gcc_assert (TREE_CODE (ident) == IDENTIFIER_NODE); + p = IDENTIFIER_POINTER (ident); + + /* If we are in LTO, then we don't know the state of flag_next_runtime + or flag_objc_abi when the code was generated. We set these from the + meta-data - which is needed to deal with const string constructors. */ + + flag_next_runtime = 1; + flag_objc_abi = 2; + + if (base == data_section) + base = darwin_sections[objc2_metadata_section]; + + /* Most of the OBJC2 META-data end up in the base section, so check it + first. */ + if (!strncmp (p, "V2_BASE", 7)) + return base; + else if (!strncmp (p, "V2_STRG", 7)) + return darwin_sections[cstring_section]; + + else if (!strncmp (p, "G2_META", 7) || !strncmp (p, "G2_CLAS", 7)) + return darwin_sections[objc2_classdefs_section]; + else if (!strncmp (p, "V2_MREF", 7)) + return darwin_sections[objc2_message_refs_section]; + else if (!strncmp (p, "V2_CLRF", 7)) + return darwin_sections[objc2_classrefs_section]; + else if (!strncmp (p, "V2_SURF", 7)) + return darwin_sections[objc2_super_classrefs_section]; + else if (!strncmp (p, "V2_NLCL", 7)) + return darwin_sections[objc2_nonlazy_class_section]; + else if (!strncmp (p, "V2_CLAB", 7)) + return darwin_sections[objc2_classlist_section]; + else if (!strncmp (p, "V2_SRFS", 7)) + return darwin_sections[objc2_selector_refs_section]; + else if (!strncmp (p, "V2_NLCA", 7)) + return darwin_sections[objc2_nonlazy_category_section]; + else if (!strncmp (p, "V2_CALA", 7)) + return darwin_sections[objc2_categorylist_section]; + + else if (!strncmp (p, "V2_PLST", 7)) + return darwin_sections[objc2_protocollist_section]; + else if (!strncmp (p, "V2_PRFS", 7)) + return darwin_sections[objc2_protocolrefs_section]; + + else if (!strncmp (p, "V2_INFO", 7)) + return darwin_sections[objc2_image_info_section]; + + else if (!strncmp (p, "V2_EHTY", 7)) + return darwin_sections[data_coal_section]; + + else if (!strncmp (p, "V2_CSTR", 7)) + return darwin_sections[objc2_constant_string_object_section]; + + /* Not recognized, default. */ + return base; +} + +/* Return the section required for Objective C ABI 0/1 metadata. */ +static section * +darwin_objc1_section (tree decl ATTRIBUTE_UNUSED, tree meta, section * base) +{ + const char *p; + tree ident = TREE_VALUE (meta); + gcc_assert (TREE_CODE (ident) == IDENTIFIER_NODE); + p = IDENTIFIER_POINTER (ident); + + /* If we are in LTO, then we don't know the state of flag_next_runtime + or flag_objc_abi when the code was generated. We set these from the + meta-data - which is needed to deal with const string constructors. */ + flag_next_runtime = 1; + if (!global_options_set.x_flag_objc_abi) + flag_objc_abi = 1; + + /* String sections first, cos there are lots of strings. */ + if (!strncmp (p, "V1_STRG", 7)) + return darwin_sections[cstring_section]; + else if (!strncmp (p, "V1_CLSN", 7)) + return darwin_sections[objc_class_names_section]; + else if (!strncmp (p, "V1_METN", 7)) + return darwin_sections[objc_meth_var_names_section]; + else if (!strncmp (p, "V1_METT", 7)) + return darwin_sections[objc_meth_var_types_section]; + + else if (!strncmp (p, "V1_CLAS", 7)) + return darwin_sections[objc_class_section]; + else if (!strncmp (p, "V1_META", 7)) + return darwin_sections[objc_meta_class_section]; + else if (!strncmp (p, "V1_CATG", 7)) + return darwin_sections[objc_category_section]; + else if (!strncmp (p, "V1_PROT", 7)) + return darwin_sections[objc_protocol_section]; + + else if (!strncmp (p, "V1_CLCV", 7)) + return darwin_sections[objc_class_vars_section]; + else if (!strncmp (p, "V1_CLIV", 7)) + return darwin_sections[objc_instance_vars_section]; + + else if (!strncmp (p, "V1_CLCM", 7)) + return darwin_sections[objc_cls_meth_section]; + else if (!strncmp (p, "V1_CLIM", 7)) + return darwin_sections[objc_inst_meth_section]; + else if (!strncmp (p, "V1_CACM", 7)) + return darwin_sections[objc_cat_cls_meth_section]; + else if (!strncmp (p, "V1_CAIM", 7)) + return darwin_sections[objc_cat_inst_meth_section]; + else if (!strncmp (p, "V1_PNSM", 7)) + return darwin_sections[objc_cat_inst_meth_section]; + else if (!strncmp (p, "V1_PCLM", 7)) + return darwin_sections[objc_cat_cls_meth_section]; + + else if (!strncmp (p, "V1_CLPR", 7)) + return darwin_sections[objc_cat_cls_meth_section]; + else if (!strncmp (p, "V1_CAPR", 7)) + return darwin_sections[objc_category_section]; /* ??? CHECK me. */ + + else if (!strncmp (p, "V1_PRFS", 7)) + return darwin_sections[objc_cat_cls_meth_section]; + else if (!strncmp (p, "V1_CLRF", 7)) + return darwin_sections[objc_cls_refs_section]; + else if (!strncmp (p, "V1_SRFS", 7)) + return darwin_sections[objc_selector_refs_section]; + + else if (!strncmp (p, "V1_MODU", 7)) + return darwin_sections[objc_module_info_section]; + else if (!strncmp (p, "V1_SYMT", 7)) + return darwin_sections[objc_symbols_section]; + else if (!strncmp (p, "V1_INFO", 7)) + return darwin_sections[objc_image_info_section]; + + else if (!strncmp (p, "V1_PLST", 7)) + return darwin_sections[objc1_prop_list_section]; + else if (!strncmp (p, "V1_PEXT", 7)) + return darwin_sections[objc1_protocol_ext_section]; + else if (!strncmp (p, "V1_CEXT", 7)) + return darwin_sections[objc1_class_ext_section]; + + else if (!strncmp (p, "V2_CSTR", 7)) + return darwin_sections[objc_constant_string_object_section]; + + return base; +} + section * machopic_select_section (tree decl, int reloc, @@ -1331,7 +1536,25 @@ machopic_select_section (tree decl, gcc_unreachable (); } - /* Darwin weird special cases. */ + /* Darwin weird special cases. + a) OBJC Meta-data. */ + if (DECL_P (decl) + && (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == CONST_DECL) + && DECL_ATTRIBUTES (decl)) + { + tree meta = lookup_attribute ("OBJC2META", DECL_ATTRIBUTES (decl)); + if (meta) + return darwin_objc2_section (decl, meta, base_section); + meta = lookup_attribute ("OBJC1META", DECL_ATTRIBUTES (decl)); + if (meta) + return darwin_objc1_section (decl, meta, base_section); + meta = lookup_attribute ("OBJC1METG", DECL_ATTRIBUTES (decl)); + if (meta) + return base_section; /* GNU runtime is happy with it all in one pot. */ + } + + /* b) Constant string objects. */ if (TREE_CODE (decl) == CONSTRUCTOR && TREE_TYPE (decl) && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE @@ -1341,29 +1564,53 @@ machopic_select_section (tree decl, if (TREE_CODE (name) == TYPE_DECL) name = DECL_NAME (name); + /* FIXME: This is unsatisfactory for LTO, since it relies on other + metadata determining the source FE. */ if (!strcmp (IDENTIFIER_POINTER (name), "__builtin_ObjCString")) - { - if (flag_next_runtime) - return darwin_sections[objc_constant_string_object_section]; - else - return darwin_sections[objc_string_object_section]; - } + { + if (flag_next_runtime) + { + if (flag_objc_abi == 2) + return darwin_sections[objc2_constant_string_object_section]; + else + return darwin_sections[objc_constant_string_object_section]; + } + else + return darwin_sections[objc_string_object_section]; + } else if (!strcmp (IDENTIFIER_POINTER (name), "__builtin_CFString")) return darwin_sections[cfstring_constant_object_section]; else - return base_section; + return base_section; } + /* c) legacy meta-data selection. */ else if (TREE_CODE (decl) == VAR_DECL && DECL_NAME (decl) && TREE_CODE (DECL_NAME (decl)) == IDENTIFIER_NODE && IDENTIFIER_POINTER (DECL_NAME (decl)) + && flag_next_runtime && !strncmp (IDENTIFIER_POINTER (DECL_NAME (decl)), "_OBJC_", 6)) { const char *name = IDENTIFIER_POINTER (DECL_NAME (decl)); - + static bool warned_objc_46 = false; /* We shall assert that zero-sized objects are an error in ObjC meta-data. */ gcc_assert (tree_low_cst (DECL_SIZE_UNIT (decl), 1) != 0); + + /* ??? This mechanism for determining the metadata section is + broken when LTO is in use, since the frontend that generated + the data is not identified. We will keep the capability for + the short term - in case any non-Objective-C programs are using + it to place data in specified sections. */ + if (!warned_objc_46) + { + location_t loc = DECL_SOURCE_LOCATION (decl); + warning_at (loc, 0, "the use of _OBJC_-prefixed variable names" + " to select meta-data sections is deprecated at 4.6" + " and will be removed in 4.7"); + warned_objc_46 = true; + } + if (!strncmp (name, "_OBJC_CLASS_METHODS_", 20)) return darwin_sections[objc_cls_meth_section]; else if (!strncmp (name, "_OBJC_INSTANCE_METHODS_", 23)) @@ -1911,6 +2158,30 @@ darwin_emit_weak_or_comdat (FILE *fp, tree decl, const char *name, assemble_zeros (size); } +/* Emit a chunk of data for ObjC meta-data that got placed in BSS erroneously. */ +static void +darwin_emit_objc_zeroed (FILE *fp, tree decl, const char *name, + unsigned HOST_WIDE_INT size, + unsigned int align, tree meta) +{ + section *ocs = data_section; + + if (TREE_PURPOSE (meta) == get_identifier("OBJC2META")) + ocs = darwin_objc2_section (decl, meta, ocs); + else + ocs = darwin_objc1_section (decl, meta, ocs); + + switch_to_section (ocs); + + /* We shall declare that zero-sized meta-data are not valid (yet). */ + gcc_assert (size); + fprintf (fp, "\t.align\t%d\n", floor_log2 (align / BITS_PER_UNIT)); + + /* ... and we let it deal with outputting one byte of zero for them too. */ + darwin_asm_declare_object_name (fp, name, decl); + assemble_zeros (size); +} + /* This routine emits 'local' storage: When Section Anchors are off this routine emits .zerofill commands in @@ -2042,6 +2313,7 @@ darwin_output_aligned_bss (FILE *fp, tree decl, const char *name, { unsigned int l2align; bool one, pub, weak; + tree meta; pub = TREE_PUBLIC (decl); one = DECL_ONE_ONLY (decl); @@ -2058,6 +2330,14 @@ fprintf (fp, "# albss: %s (%lld,%d) ro %d cst %d stat %d com %d" pub, weak, one, (unsigned long)DECL_INITIAL (decl)); #endif + /* ObjC metadata can get put in BSS because varasm.c decides it's BSS + before the target has a chance to comment. */ + if ((meta = is_objc_metadata (decl))) + { + darwin_emit_objc_zeroed (fp, decl, name, size, DECL_ALIGN (decl), meta); + return; + } + /* Check that any initializer is valid. */ gcc_assert ((DECL_INITIAL (decl) == NULL) || (DECL_INITIAL (decl) == error_mark_node) @@ -2152,6 +2432,8 @@ darwin_asm_output_aligned_decl_common (FILE *fp, tree decl, const char *name, { unsigned int l2align; bool one, weak; + tree meta; + /* No corresponding var. */ if (decl==NULL) { @@ -2176,6 +2458,14 @@ fprintf (fp, "# adcom: %s (%lld,%d) ro %d cst %d stat %d com %d pub %d" TREE_PUBLIC (decl), weak, one, (unsigned long)DECL_INITIAL (decl)); #endif + /* ObjC metadata can get put in BSS because varasm.c decides it's BSS + before the target has a chance to comment. */ + if ((meta = is_objc_metadata (decl))) + { + darwin_emit_objc_zeroed (fp, decl, name, size, DECL_ALIGN (decl), meta); + return; + } + /* We shouldn't be messing with this if the decl has a section name. */ gcc_assert (DECL_SECTION_NAME (decl) == NULL); @@ -2222,6 +2512,7 @@ darwin_asm_output_aligned_decl_local (FILE *fp, tree decl, const char *name, { unsigned long l2align; bool one, weak; + tree meta; one = DECL_ONE_ONLY (decl); weak = (DECL_P (decl) @@ -2237,6 +2528,14 @@ fprintf (fp, "# adloc: %s (%lld,%d) ro %d cst %d stat %d one %d pub %d" weak , (unsigned long)DECL_INITIAL (decl)); #endif + /* ObjC metadata can get put in BSS because varasm.c decides it's BSS + before the target has a chance to comment. */ + if ((meta = is_objc_metadata (decl))) + { + darwin_emit_objc_zeroed (fp, decl, name, size, DECL_ALIGN (decl), meta); + return; + } + /* We shouldn't be messing with this if the decl has a section name. */ gcc_assert (DECL_SECTION_NAME (decl) == NULL); diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h index 778ff1e..0526d85 100644 --- a/gcc/config/darwin.h +++ b/gcc/config/darwin.h @@ -140,6 +140,16 @@ extern GTY(()) int darwin_ms_struct; } while (0) #define SUBTARGET_C_COMMON_OVERRIDE_OPTIONS do { \ + /* Unless set, force ABI=2 for NeXT and m64, 0 otherwise. */ \ + if (!global_options_set.x_flag_objc_abi) \ + global_options.x_flag_objc_abi \ + = (flag_next_runtime && TARGET_64BIT) ? 2 : 0; \ + /* Objective-C family ABI 2 is only valid for next/m64 at present. */ \ + if (global_options_set.x_flag_objc_abi && flag_next_runtime) \ + if (TARGET_64BIT && global_options.x_flag_objc_abi < 2) \ + error_at (UNKNOWN_LOCATION, "%<-fobjc-abi-version%> >= 2 is only" \ + " supported on %<-m64%> targets for" \ + " %<-fnext-runtime%>"); \ /* Sort out ObjC exceptions: If the runtime is NeXT we default to \ sjlj for m32 only. */ \ if (!global_options_set.x_flag_objc_sjlj_exceptions) \ @@ -599,7 +609,7 @@ int darwin_label_is_anonymous_local_objc_name (const char *name); } \ else if (xname[0] == '+' || xname[0] == '-') \ fprintf (FILE, "\"%s\"", xname); \ - else if (darwin_label_is_anonymous_local_objc_name (xname)) \ + else if (darwin_label_is_anonymous_local_objc_name (xname)) \ fprintf (FILE, "L%s", xname); \ else if (!strncmp (xname, ".objc_class_name_", 17)) \ fprintf (FILE, "%s", xname); \ diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 7b42439..926352e 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,106 @@ +2011-02-17 Iain Sandoe <iains@gcc.gnu.org> + + * config-lang.in (gtfiles): Updated. + * Make-lang.in (START_HDRS): New. + (OBJC_OBJS): Added new object files. + (objc/objc-act.o): Updated prerequisites. + (objc/objc-lang.o): Updated prerequisites. + (objc/objc-runtime-shared-support.o): New. + (objc/objc-gnu-runtime-abi-01.o): New. + (objc/objc-next-runtime-abi-01.o): New. + (objc/objc-next-runtime-abi-02.o): New. + * objc-runtime-hooks.h: New. + * objc-runtime-shared-support.h: New. + * objc-runtime-shared-support.c: New. + * objc-gnu-runtime-abi-01.c: New. + * objc-next-metadata-tags.h: New. + * objc-next-runtime-abi-01.c: New. + * objc-next-runtime-abi-02.c: New. + * objc-lang.c: Include c-lang.h. + (LANG_HOOKS_EH_PERSONALITY): Removed. + * objc-act.h: Moved many declarations and code from objc-act.c + into objc-act.h to make them available outside objc-act.c. + (objc_eh_runtime_type): Removed. + (objc_eh_personality): Removed. + (CLASS_HAS_EXCEPTION_ATTR): New. + (OCTI_SUPER_SUPERFIELD_ID): New. + (OCTI_V1_PROP_LIST_TEMPL): New. + (OCTI_V1_PROP_NAME_ATTR_CHAIN): New. + (super_superclassfield_id): New. + (objc_prop_list_ptr): New. + (prop_names_attr_chain): New. + * objc-act.c: Include new runtime headers. Moved many #defines + and declarations into objc-act.h and + objc-runtime-shared-support.h. Made some corresponding functions + non-static, and moved some others into + objc-runtime-shared-support.c. Moved metadata generation code + into the new runtime hook files. + (ivar_offset_hash_list): New. + (objc_init): Call generate_struct_value_by_array() before doing + any runtime initialization. Create the appropriate runtime hook + structures. + (init_objc): Removed. Code moved directly into objc_init. + (finish_objc): Removed. Code moved directly into + objc_write_global_declarations. + (objc_write_global_declarations): Do the warn_selector checks + before emitting metadata. Use a runtime hook to emit the + metadata. Do not emit the metadata or do -gen-decls processing if + -fsyntax-only or we are producing a PCH. + (build_objc_exception_stuff): Renamed to + build_common_objc_exception_stuff. Remove TREE_NOTHROW flag from + objc_exception_throw_decl. + (synth_module_prologue): Call runtime initialize hook instead of + building runtime declarations here. Use the + default_constant_string_class_name runtime hook to set the + constant string class name. + (objc_build_string_object): Call the setup_const_string_class_decl + runtime hook instead of setup_string_decl. Call the + build_const_string_constructor runtime hook instead of building + the string object here. + (get_objc_string_decl): Added prop_names_attr case. Removed + gcc_unreachable() at the end. + (objc_begin_catch_clause): Distinguish between @catch (...) and + @catch (id x). Call the begin_catch runtime hook instead of + building the CATCH_EXPR here. + (objc_finish_catch_clause): Call the finish_catch runtime hook + instead of adding the catch here. + (objc_finish_try_stmt): Call the finish_try_stmt runtime hook + instead of doing it here. + (objc_build_throw_stmt): Bail out early for error_mark_node. Call + the build_exc_ptr runtime hook instead of objc_build_exc_ptr. + Call the build_throw_stmt runtime hook instead of building the + throw call here. + (objc_generate_cxx_cdtors): Set has_cxx_cdtors for the GNU runtime + as well. + (get_arg_type_list): Call the get_arg_type_list_base runtime hook + instead of building the list of arguments here. + (receiver_is_class_object): Call the receiver_is_class_object + runtime hook instead of doing the check here. Call the + tag_getclass runtime hook instead of using TAG_GETCLASS. + (objc_finish_message_expr): Call the build_objc_method_call + runtime hook. + (objc_build_protocol_expr): Call the get_protocol_reference + runtime hook. + (objc_build_selector_expr): Call the build_selector_reference + runtime hook. + (build_ivar_reference): Call the build_ivar_reference runtime + hook. + (hash_init): Set up ivar_offset_hash_list. + (start_class): Recognize the objc_exception attribute and store + it. + (continue_class): Use the class_decl and metaclass_decl runtime + hooks. + (build_objc_property_accessor_helpers): Renamed to + build_common_objc_property_accessor_helpers. Do not build + objc_copyStruct_decl, objc_getPropertyStruct_decl and + objc_setPropertyStruct_decl. + (objc_synthesize_getter): Check what struct setter/getter helper + is available instead of checking the type of runtime. + (get_super_receiver): Use the super_superclassfield_ident runtime + hook. Added assert. Use the get_class_super_ref and + get_category_super_ref runtime hooks. + (objc_v2_encode_prop_attr): New. + 2011-01-17 Nicola Pero <nicola.pero@meta-innovation.com> PR objc/47314 diff --git a/gcc/objc/Make-lang.in b/gcc/objc/Make-lang.in index c479769..6f48aba 100644 --- a/gcc/objc/Make-lang.in +++ b/gcc/objc/Make-lang.in @@ -1,6 +1,6 @@ # Top level -*- makefile -*- fragment for GNU Objective-C # Copyright (C) 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2007, -# 2008, 2009, 2010 Free Software Foundation, Inc. +# 2008, 2009, 2010, 2011 Free Software Foundation, Inc. #This file is part of GCC. @@ -43,11 +43,18 @@ objc: cc1obj$(exeext) # Tell GNU make to ignore these if they exist. .PHONY: objc +START_HDRS = $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(C_TREE_H) \ + c-lang.h langhooks.h c-family/c-objc.h objc/objc-act.h + # Use maximal warnings for this front end. objc-warn = $(STRICT_WARN) # Language-specific object files for Objective C. -OBJC_OBJS = objc/objc-lang.o objc/objc-act.o +OBJC_OBJS = objc/objc-lang.o objc/objc-act.o \ + objc/objc-runtime-shared-support.o \ + objc/objc-gnu-runtime-abi-01.o \ + objc/objc-next-runtime-abi-01.o \ + objc/objc-next-runtime-abi-02.o \ objc_OBJS = $(OBJC_OBJS) cc1obj-checksum.o @@ -66,17 +73,32 @@ cc1obj$(exeext): $(OBJC_OBJS) $(C_AND_OBJC_OBJS) cc1obj-checksum.o $(BACKEND) $( # Objective C language specific files. -objc/objc-lang.o : objc/objc-lang.c \ - $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(C_TREE_H) \ - $(GGC_H) langhooks.h $(LANGHOOKS_DEF_H) $(C_COMMON_H) gtype-objc.h \ - c-objc-common.h c-family/c-objc.h objc/objc-act.h - -objc/objc-act.o : objc/objc-act.c \ - $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(TARGET_H) $(C_TREE_H) $(DIAGNOSTIC_CORE_H) toplev.h $(FLAGS_H) \ - objc/objc-act.h input.h $(FUNCTION_H) output.h debug.h langhooks.h \ - $(LANGHOOKS_DEF_H) $(HASHTAB_H) $(C_PRAGMA_H) gt-objc-objc-act.h \ - $(GIMPLE_H) c-lang.h c-family/c-objc.h +objc/objc-lang.o : objc/objc-lang.c $(START_HDRS) \ + $(GGC_H) $(LANGHOOKS_DEF_H) $(C_COMMON_H) gtype-objc.h \ + c-objc-common.h + +objc/objc-runtime-shared-support.o : objc/objc-runtime-shared-support.c \ + $(START_HDRS) objc/objc-runtime-shared-support.h $(OBSTACK_H) \ + objc/objc-next-metadata-tags.h gt-objc-objc-runtime-shared-support.h + +objc/objc-gnu-runtime-abi-01.o: objc/objc-gnu-runtime-abi-01.c $(START_HDRS) \ + objc/objc-runtime-hooks.h $(GGC_H) \ + objc/objc-runtime-shared-support.h gt-objc-objc-gnu-runtime-abi-01.h toplev.h + +objc/objc-next-runtime-abi-01.o: objc/objc-next-runtime-abi-01.c $(START_HDRS) \ + $(GGC_H) objc/objc-runtime-hooks.h \ + objc/objc-next-metadata-tags.h gt-objc-objc-next-runtime-abi-01.h output.h \ + objc/objc-runtime-shared-support.h $(TARGET_H) + +objc/objc-next-runtime-abi-02.o: objc/objc-next-runtime-abi-02.c $(START_HDRS) \ + $(GGC_H) objc/objc-runtime-hooks.h \ + objc/objc-next-metadata-tags.h gt-objc-objc-next-runtime-abi-02.h $(TARGET_H) \ + objc/objc-runtime-shared-support.h $(OBSTACK_H) + +objc/objc-act.o : objc/objc-act.c $(START_HDRS) $(GGC_H) \ + $(DIAGNOSTIC_CORE_H) toplev.h $(FLAGS_H) input.h $(FUNCTION_H) output.h debug.h \ + $(LANGHOOKS_DEF_H) $(HASHTAB_H) $(C_PRAGMA_H) gt-objc-objc-act.h $(OBSTACK_H) \ + $(GIMPLE_H) objc/objc-runtime-shared-support.h objc/objc-runtime-hooks.h objc.srcextra: diff --git a/gcc/objc/config-lang.in b/gcc/objc/config-lang.in index 9ae6d6c..db5c5a5 100644 --- a/gcc/objc/config-lang.in +++ b/gcc/objc/config-lang.in @@ -1,6 +1,6 @@ # Top level configure fragment for GNU Objective-C -# Copyright (C) 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2010 -# Free Software Foundation, Inc. +# Copyright (C) 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2010, +# 2011 Free Software Foundation, Inc. #This file is part of GCC. @@ -33,4 +33,4 @@ target_libs=target-libobjc # Most of the object files for cc1obj actually come from C. lang_requires="c" -gtfiles="\$(srcdir)/objc/objc-act.h \$(srcdir)/c-parser.c \$(srcdir)/c-tree.h \$(srcdir)/c-decl.c \$(srcdir)/c-objc-common.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/objc/objc-act.c" +gtfiles="\$(srcdir)/objc/objc-act.h \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-runtime-shared-support.c \$(srcdir)/objc/objc-gnu-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-02.c \$(srcdir)/c-parser.c \$(srcdir)/c-tree.h \$(srcdir)/c-decl.c \$(srcdir)/c-lang.h \$(srcdir)/c-objc-common.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c" diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 33d39b2..d73f2c0 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -1,6 +1,6 @@ /* Implement classes and message passing for Objective C. Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, - 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Steve Naroff. @@ -53,15 +53,17 @@ along with GCC; see the file COPYING3. If not see #include "tree-iterator.h" #include "hashtab.h" #include "langhooks-def.h" - +/* Different initialization, code gen and meta data generation for each + runtime. */ +#include "objc-runtime-hooks.h" +/* Routines used mainly by the runtimes. */ +#include "objc-runtime-shared-support.h" /* For default_tree_printer (). */ #include "tree-pretty-print.h" /* For enum gimplify_status */ #include "gimple.h" -#define OBJC_VOID_AT_END void_list_node - static unsigned int should_call_super_dealloc = 0; /* When building Objective-C++, we are not linking against the C front-end @@ -102,53 +104,30 @@ static unsigned int should_call_super_dealloc = 0; #ifndef OBJC_FORWARDING_MIN_OFFSET #define OBJC_FORWARDING_MIN_OFFSET 0 #endif - + /* Set up for use of obstacks. */ #include "obstack.h" /* This obstack is used to accumulate the encoding of a data type. */ -static struct obstack util_obstack; +struct obstack util_obstack; /* This points to the beginning of obstack contents, so we can free the whole contents. */ char *util_firstobj; -/* The version identifies which language generation and runtime - the module (file) was compiled for, and is recorded in the - module descriptor. */ - -#define OBJC_VERSION (flag_next_runtime ? 6 : 8) -#define PROTOCOL_VERSION 2 - -/* (Decide if these can ever be validly changed.) */ -#define OBJC_ENCODE_INLINE_DEFS 0 -#define OBJC_ENCODE_DONT_INLINE_DEFS 1 - /*** Private Interface (procedures) ***/ -/* Used by compile_file. */ - -static void init_objc (void); -static void finish_objc (void); +/* Init stuff. */ +static void synth_module_prologue (void); /* Code generation. */ -static tree objc_build_constructor (tree, VEC(constructor_elt,gc) *); -static tree build_objc_method_call (location_t, int, tree, tree, tree, tree); -static tree get_proto_encoding (tree); -static tree lookup_interface (tree); -static tree objc_add_static_instance (tree, tree); - static tree start_class (enum tree_code, tree, tree, tree, tree); static tree continue_class (tree); static void finish_class (tree); static void start_method_def (tree); -#ifdef OBJCPLUS -static void objc_start_function (tree, tree, tree, tree); -#else -static void objc_start_function (tree, tree, tree, struct c_arg_info *); -#endif + static tree start_protocol (enum tree_code, tree, tree, tree); static tree build_method_decl (enum tree_code, tree, tree, tree, bool); static tree objc_add_method (tree, tree, int, bool); @@ -156,9 +135,6 @@ static tree add_instance_variable (tree, objc_ivar_visibility_kind, tree); static tree build_ivar_reference (tree); static tree is_ivar (tree, tree); -static void build_objc_exception_stuff (void); -static void build_next_objc_exception_stuff (void); - /* We only need the following for ObjC; ObjC++ will use C++'s definition of DERIVED_FROM_P. */ #ifndef OBJCPLUS @@ -175,18 +151,11 @@ static int match_proto_with_proto (tree, tree, int); static tree lookup_property (tree, tree); static tree lookup_property_in_list (tree, tree); static tree lookup_property_in_protocol_list (tree, tree); -static void build_objc_property_accessor_helpers (void); +static void build_common_objc_property_accessor_helpers (void); static void objc_xref_basetypes (tree, tree); -static void build_class_template (void); -static void build_selector_template (void); -static void build_category_template (void); -static void build_super_template (void); -static tree build_protocol_initializer (tree, tree, tree, tree, tree); static tree get_class_ivars (tree, bool); -static tree generate_protocol_list (tree); -static void build_protocol_reference (tree); static void build_fast_enumeration_state_template (void); @@ -197,9 +166,9 @@ static void objc_generate_cxx_cdtors (void); /* objc attribute */ static void objc_decl_method_attributes (tree*, tree, int); static tree build_keyword_selector (tree); -static const char *synth_id_with_class_suffix (const char *, tree); /* Hash tables to manage the global pool of method prototypes. */ +static void hash_init (void); hash *nst_method_hash_list = 0; hash *cls_method_hash_list = 0; @@ -209,6 +178,8 @@ hash *cls_method_hash_list = 0; hash *cls_name_hash_list = 0; hash *als_name_hash_list = 0; +hash *ivar_offset_hash_list = 0; + static void hash_class_name_enter (hash *, tree, tree); static hash hash_class_name_lookup (hash *, tree); @@ -220,16 +191,6 @@ static tree add_class (tree, tree); static void add_category (tree, tree); static inline tree lookup_category (tree, tree); -enum string_section -{ - class_names, /* class, category, protocol, module names */ - meth_var_names, /* method and variable names */ - meth_var_types /* method and variable type descriptors */ -}; - -static tree add_objc_string (tree, enum string_section); -static void build_selector_table_decl (void); - /* Protocols. */ static tree lookup_protocol (tree, bool, bool); @@ -239,7 +200,6 @@ static tree lookup_and_install_protocols (tree, bool); static void encode_type_qualifiers (tree); static void encode_type (tree, int, int); -static void encode_field_decl (tree, int, int); #ifdef OBJCPLUS static void really_start_method (tree, tree); @@ -247,14 +207,7 @@ static void really_start_method (tree, tree); static void really_start_method (tree, struct c_arg_info *); #endif static int comp_proto_with_proto (tree, tree, int); -static tree get_arg_type_list (tree, int, int); static tree objc_decay_parm_type (tree); -static void objc_push_parm (tree); -#ifdef OBJCPLUS -static tree objc_get_parm_info (int); -#else -static struct c_arg_info *objc_get_parm_info (int); -#endif /* Utilities for debugging and error diagnostics. */ @@ -265,113 +218,13 @@ static char *gen_declaration (tree); /* Everything else. */ -static tree create_field_decl (tree, const char *); -static void add_class_reference (tree); -static void build_protocol_template (void); -static tree encode_method_prototype (tree); -static void generate_classref_translation_entry (tree); -static void handle_class_ref (tree); -static void generate_struct_by_value_array (void) - ATTRIBUTE_NORETURN; +static void generate_struct_by_value_array (void) ATTRIBUTE_NORETURN; + static void mark_referenced_methods (void); -static void generate_objc_image_info (void); static bool objc_type_valid_for_messaging (tree type, bool allow_classes); +static tree check_duplicates (hash, int, int); /*** Private Interface (data) ***/ - -/* Reserved tag definitions. */ - -#define OBJECT_TYPEDEF_NAME "id" -#define CLASS_TYPEDEF_NAME "Class" - -#define TAG_OBJECT "objc_object" -#define TAG_CLASS "objc_class" -#define TAG_SUPER "objc_super" -#define TAG_SELECTOR "objc_selector" - -#define UTAG_CLASS "_objc_class" -#define UTAG_IVAR "_objc_ivar" -#define UTAG_IVAR_LIST "_objc_ivar_list" -#define UTAG_METHOD "_objc_method" -#define UTAG_METHOD_LIST "_objc_method_list" -#define UTAG_CATEGORY "_objc_category" -#define UTAG_MODULE "_objc_module" -#define UTAG_SYMTAB "_objc_symtab" -#define UTAG_SUPER "_objc_super" -#define UTAG_SELECTOR "_objc_selector" - -#define UTAG_PROTOCOL "_objc_protocol" -#define UTAG_METHOD_PROTOTYPE "_objc_method_prototype" -#define UTAG_METHOD_PROTOTYPE_LIST "_objc__method_prototype_list" - -/* Note that the string object global name is only needed for the - NeXT runtime. */ -#define STRING_OBJECT_GLOBAL_FORMAT "_%sClassReference" - -#define PROTOCOL_OBJECT_CLASS_NAME "Protocol" - -#define TAG_ENUMERATION_MUTATION "objc_enumerationMutation" -#define TAG_FAST_ENUMERATION_STATE "__objcFastEnumerationState" - -static const char *TAG_GETCLASS; -static const char *TAG_GETMETACLASS; -static const char *TAG_MSGSEND; -static const char *TAG_MSGSENDSUPER; -/* The NeXT Objective-C messenger may have two extra entry points, for use - when returning a structure. */ -static const char *TAG_MSGSEND_STRET; -static const char *TAG_MSGSENDSUPER_STRET; -static const char *default_constant_string_class_name; - -/* Runtime metadata flags. */ -#define CLS_FACTORY 0x0001L -#define CLS_META 0x0002L -#define CLS_HAS_CXX_STRUCTORS 0x2000L - -#define OBJC_MODIFIER_STATIC 0x00000001 -#define OBJC_MODIFIER_FINAL 0x00000002 -#define OBJC_MODIFIER_PUBLIC 0x00000004 -#define OBJC_MODIFIER_PRIVATE 0x00000008 -#define OBJC_MODIFIER_PROTECTED 0x00000010 -#define OBJC_MODIFIER_NATIVE 0x00000020 -#define OBJC_MODIFIER_SYNCHRONIZED 0x00000040 -#define OBJC_MODIFIER_ABSTRACT 0x00000080 -#define OBJC_MODIFIER_VOLATILE 0x00000100 -#define OBJC_MODIFIER_TRANSIENT 0x00000200 -#define OBJC_MODIFIER_NONE_SPECIFIED 0x80000000 - -/* NeXT-specific tags. */ - -#define TAG_MSGSEND_NONNIL "objc_msgSendNonNil" -#define TAG_MSGSEND_NONNIL_STRET "objc_msgSendNonNil_stret" -#define TAG_EXCEPTIONEXTRACT "objc_exception_extract" -#define TAG_EXCEPTIONTRYENTER "objc_exception_try_enter" -#define TAG_EXCEPTIONTRYEXIT "objc_exception_try_exit" -#define TAG_EXCEPTIONMATCH "objc_exception_match" -#define TAG_EXCEPTIONTHROW "objc_exception_throw" -#define TAG_SYNCENTER "objc_sync_enter" -#define TAG_SYNCEXIT "objc_sync_exit" -#define TAG_SETJMP "_setjmp" -#define UTAG_EXCDATA "_objc_exception_data" - -#define TAG_ASSIGNIVAR "objc_assign_ivar" -#define TAG_ASSIGNGLOBAL "objc_assign_global" -#define TAG_ASSIGNSTRONGCAST "objc_assign_strongCast" - -/* Branch entry points. All that matters here are the addresses; - functions with these names do not really exist in libobjc. */ - -#define TAG_MSGSEND_FAST "objc_msgSend_Fast" -#define TAG_ASSIGNIVAR_FAST "objc_assign_ivar_Fast" - -#define TAG_CXX_CONSTRUCT ".cxx_construct" -#define TAG_CXX_DESTRUCT ".cxx_destruct" - -/* GNU-specific tags. */ - -#define TAG_EXECCLASS "__objc_exec_class" -#define TAG_GNUINIT "__objc_gnu_init" - /* Flags for lookup_method_static(). */ /* Look for class methods. */ @@ -385,8 +238,6 @@ static const char *default_constant_string_class_name; /* The OCTI_... enumeration itself is in objc/objc-act.h. */ tree objc_global_trees[OCTI_MAX]; -static void handle_impent (struct imp_entry *); - struct imp_entry *imp_list = 0; int imp_count = 0; /* `@implementation' */ int cat_count = 0; /* `@category' */ @@ -408,17 +259,12 @@ static int objc_collecting_ivars = 0; @interface, or in a class extension. */ static bool objc_in_class_extension = false; -#define BUFSIZE 1024 - static char *errbuf; /* Buffer for error diagnostics */ /* An array of all the local variables in the current function that need to be marked as volatile. */ VEC(tree,gc) *local_variables_to_volatilize = NULL; - -static int flag_typed_selectors; - /* Store all constructed constant strings in a hash table so that they get uniqued properly. */ @@ -439,59 +285,16 @@ FILE *gen_declaration_file; Type descriptors for instance variables contain more information than methods (for static typing and embedded structures). */ -static int generating_instance_variables = 0; - -/* For building an objc struct. These may not be used when this file - is compiled as part of obj-c++. */ - -static bool objc_building_struct; -static struct c_struct_parse_info *objc_struct_info ATTRIBUTE_UNUSED; - -/* Start building a struct for objc. */ - -static tree -objc_start_struct (tree name) -{ - gcc_assert (!objc_building_struct); - objc_building_struct = true; - return start_struct (input_location, RECORD_TYPE, name, &objc_struct_info); -} - -/* Finish building a struct for objc. */ - -static tree -objc_finish_struct (tree type, tree fieldlist) -{ - gcc_assert (objc_building_struct); - objc_building_struct = false; - return finish_struct (input_location, type, fieldlist, NULL_TREE, - objc_struct_info); -} - -static tree -build_sized_array_type (tree base_type, int size) -{ - tree index_type = build_index_type (build_int_cst (NULL_TREE, size - 1)); - return build_array_type (base_type, index_type); -} - -static tree -add_field_decl (tree type, const char *name, tree **chain) -{ - tree field = create_field_decl (type, name); - - if (*chain != NULL) - **chain = field; - *chain = &DECL_CHAIN (field); +int generating_instance_variables = 0; - return field; -} +/* Hooks for stuff that differs between runtimes. */ +objc_runtime_hooks runtime; /* Create a temporary variable of type 'type'. If 'name' is set, uses the specified name, else use no name. Returns the declaration of the type. The 'name' is mostly useful for debugging. */ -static tree +tree objc_create_temporary_var (tree type, const char *name) { tree decl; @@ -527,7 +330,8 @@ generate_struct_by_value_array (void) int aggregate_in_mem[32]; int found = 0; - /* Presumably no platform passes 32 byte structures in a register. */ + /* ??? as an example, m64/ppc/Darwin can pass up to 8*long+13*double in regs. + Presumably no platform passes 32 byte structures in a register. */ for (i = 1; i < 32; i++) { char buffer[5]; @@ -567,6 +371,7 @@ generate_struct_by_value_array (void) bool objc_init (void) { + bool ok; #ifdef OBJCPLUS if (cxx_init () == false) #else @@ -574,54 +379,30 @@ objc_init (void) #endif return false; - /* If gen_declaration desired, open the output file. */ - if (flag_gen_declaration) - { - register char * const dumpname = concat (dump_base_name, ".decl", NULL); - gen_declaration_file = fopen (dumpname, "w"); - if (gen_declaration_file == 0) - fatal_error ("can%'t open %s: %m", dumpname); - free (dumpname); - } + if (print_struct_values && !flag_compare_debug) + /* This routine does not require any ObjC set-up and never returns. */ + generate_struct_by_value_array (); - if (flag_next_runtime) - { - TAG_GETCLASS = "objc_getClass"; - TAG_GETMETACLASS = "objc_getMetaClass"; - TAG_MSGSEND = "objc_msgSend"; - TAG_MSGSENDSUPER = "objc_msgSendSuper"; - TAG_MSGSEND_STRET = "objc_msgSend_stret"; - TAG_MSGSENDSUPER_STRET = "objc_msgSendSuper_stret"; - default_constant_string_class_name = "NSConstantString"; - } - else - { - TAG_GETCLASS = "objc_get_class"; - TAG_GETMETACLASS = "objc_get_meta_class"; - TAG_MSGSEND = "objc_msg_lookup"; - TAG_MSGSENDSUPER = "objc_msg_lookup_super"; - /* GNU runtime does not provide special functions to support - structure-returning methods. */ - default_constant_string_class_name = "NXConstantString"; - flag_typed_selectors = 1; - /* GNU runtime does not need the compiler to change code - in order to do GC. */ - if (flag_objc_gc) - { - warning_at (0, 0, "%<-fobjc-gc%> is ignored for %<-fgnu-runtime%>"); - flag_objc_gc=0; - } - } + /* Set up stuff used by FE parser and all runtimes. */ + errbuf = XNEWVEC (char, 1024 * 10); + hash_init (); + gcc_obstack_init (&util_obstack); + util_firstobj = (char *) obstack_finish (&util_obstack); - init_objc (); + /* ... and then check flags and set-up for the selected runtime ... */ + if (flag_next_runtime && flag_objc_abi >= 2) + ok = objc_next_runtime_abi_02_init (&runtime); + else if (flag_next_runtime) + ok = objc_next_runtime_abi_01_init (&runtime); + else + ok = objc_gnu_runtime_abi_01_init (&runtime); - if (print_struct_values && !flag_compare_debug) - generate_struct_by_value_array (); + /* If that part of the setup failed - bail out immediately. */ + if (!ok) + return false; -#ifndef OBJCPLUS - if (flag_objc_exceptions && !flag_objc_sjlj_exceptions) - using_eh_for_cleanups (); -#endif + /* Generate general types and push runtime-specific decls to file scope. */ + synth_module_prologue (); return true; } @@ -633,13 +414,58 @@ objc_write_global_declarations (void) { mark_referenced_methods (); - /* Finalize Objective-C runtime data. */ - finish_objc (); + /* A missing @end might not be detected by the parser. */ + if (objc_implementation_context) + { + warning (0, "%<@end%> missing in implementation context"); + finish_class (objc_implementation_context); + objc_ivar_chain = NULL_TREE; + objc_implementation_context = NULL_TREE; + } + + if (warn_selector) + { + int slot; + hash hsh; - if (gen_declaration_file) - fclose (gen_declaration_file); + /* Run through the selector hash tables and print a warning for any + selector which has multiple methods. */ + + for (slot = 0; slot < SIZEHASHTABLE; slot++) + { + for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next) + check_duplicates (hsh, 0, 1); + for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next) + check_duplicates (hsh, 0, 0); + } + } + + /* TODO: consider an early exit here if either errorcount or sorrycount + is non-zero. Not only is it wasting time to generate the metadata, + it needlessly imposes need to re-check for things that are already + determined to be errors. */ + + /* Finalize Objective-C runtime data. No need to generate tables + and code if only checking syntax, or if generating a PCH file. */ + if (!flag_syntax_only && !pch_file) + { + /* If gen_declaration desired, open the output file. */ + if (flag_gen_declaration) + { + char * const dumpname = concat (dump_base_name, ".decl", NULL); + gen_declaration_file = fopen (dumpname, "w"); + if (gen_declaration_file == 0) + fatal_error ("can%'t open %s: %m", dumpname); + free (dumpname); + } + /* Compute and emit the meta-data tables for this runtime. */ + (*runtime.generate_metadata) (); + /* ... and then close any declaration file we opened. */ + if (gen_declaration_file) + fclose (gen_declaration_file); + } } - + /* Return the first occurrence of a method declaration corresponding to sel_name in rproto_list. Search rproto_list recursively. If is_class is 0, search for instance methods, otherwise for class @@ -2200,20 +2026,6 @@ objc_add_instance_variable (tree decl) decl); } -/* Return true if TYPE is 'id'. */ - -static bool -objc_is_object_id (tree type) -{ - return OBJC_TYPE_NAME (type) == objc_object_id; -} - -static bool -objc_is_class_id (tree type) -{ - return OBJC_TYPE_NAME (type) == objc_class_id; -} - /* Construct a C struct with same name as KLASS, a base struct with tag SUPER_NAME (if any), and FIELDS indicated. */ @@ -2761,7 +2573,7 @@ objc_derived_from_p (tree parent, tree child) } #endif -static tree +tree objc_build_component_ref (tree datum, tree component) { /* If COMPONENT is NULL, the caller is referring to the anonymous @@ -2999,63 +2811,34 @@ lookup_and_install_protocols (tree protocols, bool definition_required) return return_value; } -/* Create a declaration for field NAME of a given TYPE. */ - -static tree -create_field_decl (tree type, const char *name) -{ - return build_decl (input_location, - FIELD_DECL, get_identifier (name), type); -} - -/* Create a global, static declaration for variable NAME of a given TYPE. The - finish_var_decl() routine will need to be called on it afterwards. */ - -static tree -start_var_decl (tree type, const char *name) -{ - tree var = build_decl (input_location, - VAR_DECL, get_identifier (name), type); - - TREE_STATIC (var) = 1; - DECL_INITIAL (var) = error_mark_node; /* A real initializer is coming... */ - DECL_IGNORED_P (var) = 1; - DECL_ARTIFICIAL (var) = 1; - DECL_CONTEXT (var) = NULL_TREE; -#ifdef OBJCPLUS - DECL_THIS_STATIC (var) = 1; /* squash redeclaration errors */ -#endif - - return var; -} - -/* Finish off the variable declaration created by start_var_decl(). */ - static void -finish_var_decl (tree var, tree initializer) +build_common_objc_exception_stuff (void) { - finish_decl (var, input_location, initializer, NULL_TREE, NULL_TREE); -} + tree noreturn_list, nothrow_list, temp_type; -/* Find the decl for the constant string class reference. This is only - used for the NeXT runtime. */ + noreturn_list = tree_cons (get_identifier ("noreturn"), NULL, NULL); + nothrow_list = tree_cons (get_identifier ("nothrow"), NULL, NULL); -static tree -setup_string_decl (void) -{ - char *name; - size_t length; + /* void objc_exception_throw(id) __attribute__((noreturn)); */ + /* void objc_sync_enter(id); */ + /* void objc_sync_exit(id); */ + temp_type = build_function_type_list (void_type_node, + objc_object_type, + NULL_TREE); + objc_exception_throw_decl + = add_builtin_function (TAG_EXCEPTIONTHROW, temp_type, 0, NOT_BUILT_IN, NULL, + noreturn_list); + /* Make sure that objc_exception_throw (id) claims that it may throw an + exception. */ + TREE_NOTHROW (objc_exception_throw_decl) = 0; - /* %s in format will provide room for terminating null */ - length = strlen (STRING_OBJECT_GLOBAL_FORMAT) - + strlen (constant_string_class_name); - name = XNEWVEC (char, length); - sprintf (name, STRING_OBJECT_GLOBAL_FORMAT, - constant_string_class_name); - constant_string_global_id = get_identifier (name); - string_class_decl = lookup_name (constant_string_global_id); + objc_sync_enter_decl + = add_builtin_function (TAG_SYNCENTER, temp_type, 0, NOT_BUILT_IN, + NULL, nothrow_list); - return string_class_decl; + objc_sync_exit_decl + = add_builtin_function (TAG_SYNCEXIT, temp_type, 0, NOT_BUILT_IN, + NULL, nothrow_list); } /* Purpose: "play" parser, creating/installing representations @@ -3100,12 +2883,12 @@ synth_module_prologue (void) objc_class_name = get_identifier (CLASS_TYPEDEF_NAME); /* Declare the 'id' and 'Class' typedefs. */ - type = lang_hooks.decls.pushdecl (build_decl (input_location, TYPE_DECL, objc_object_name, objc_object_type)); TREE_NO_WARNING (type) = 1; + type = lang_hooks.decls.pushdecl (build_decl (input_location, TYPE_DECL, objc_class_name, @@ -3113,29 +2896,11 @@ synth_module_prologue (void) TREE_NO_WARNING (type) = 1; /* Forward-declare '@interface Protocol'. */ - type = get_identifier (PROTOCOL_OBJECT_CLASS_NAME); objc_declare_class (tree_cons (NULL_TREE, type, NULL_TREE)); - objc_protocol_type = build_pointer_type (xref_tag (RECORD_TYPE, - type)); - - /* Declare type of selector-objects that represent an operation name. */ - - if (flag_next_runtime) - /* `struct objc_selector *' */ - objc_selector_type - = build_pointer_type (xref_tag (RECORD_TYPE, - get_identifier (TAG_SELECTOR))); - else - /* `const struct objc_selector *' */ - objc_selector_type - = build_pointer_type - (build_qualified_type (xref_tag (RECORD_TYPE, - get_identifier (TAG_SELECTOR)), - TYPE_QUAL_CONST)); + objc_protocol_type = build_pointer_type (xref_tag (RECORD_TYPE, type)); /* Declare receiver type used for dispatching messages to 'super'. */ - /* `struct objc_super *' */ objc_super_type = build_pointer_type (xref_tag (RECORD_TYPE, get_identifier (TAG_SUPER))); @@ -3151,162 +2916,18 @@ synth_module_prologue (void) (xref_tag (RECORD_TYPE, get_identifier (UTAG_IVAR_LIST))); - /* TREE_NOTHROW is cleared for the message-sending functions, - because the function that gets called can throw in Obj-C++, or - could itself call something that can throw even in Obj-C. */ - - if (flag_next_runtime) - { - /* NB: In order to call one of the ..._stret (struct-returning) - functions, the function *MUST* first be cast to a signature that - corresponds to the actual ObjC method being invoked. This is - what is done by the build_objc_method_call() routine below. */ - - /* id objc_msgSend (id, SEL, ...); */ - /* id objc_msgSendNonNil (id, SEL, ...); */ - /* id objc_msgSend_stret (id, SEL, ...); */ - /* id objc_msgSendNonNil_stret (id, SEL, ...); */ - type - = build_varargs_function_type_list (objc_object_type, - objc_object_type, - objc_selector_type, - NULL_TREE); - umsg_decl = add_builtin_function (TAG_MSGSEND, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - umsg_nonnil_decl = add_builtin_function (TAG_MSGSEND_NONNIL, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - umsg_stret_decl = add_builtin_function (TAG_MSGSEND_STRET, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - umsg_nonnil_stret_decl = add_builtin_function (TAG_MSGSEND_NONNIL_STRET, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - - /* These can throw, because the function that gets called can throw - in Obj-C++, or could itself call something that can throw even - in Obj-C. */ - TREE_NOTHROW (umsg_decl) = 0; - TREE_NOTHROW (umsg_nonnil_decl) = 0; - TREE_NOTHROW (umsg_stret_decl) = 0; - TREE_NOTHROW (umsg_nonnil_stret_decl) = 0; - - /* id objc_msgSend_Fast (id, SEL, ...) - __attribute__ ((hard_coded_address (OFFS_MSGSEND_FAST))); */ -#ifdef OFFS_MSGSEND_FAST - umsg_fast_decl = add_builtin_function (TAG_MSGSEND_FAST, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - TREE_NOTHROW (umsg_fast_decl) = 0; - DECL_ATTRIBUTES (umsg_fast_decl) - = tree_cons (get_identifier ("hard_coded_address"), - build_int_cst (NULL_TREE, OFFS_MSGSEND_FAST), - NULL_TREE); -#else - /* No direct dispatch available. */ - umsg_fast_decl = umsg_decl; -#endif - - /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */ - /* id objc_msgSendSuper_stret (struct objc_super *, SEL, ...); */ - type - = build_varargs_function_type_list (objc_object_type, - objc_super_type, - objc_selector_type, - NULL_TREE); - umsg_super_decl = add_builtin_function (TAG_MSGSENDSUPER, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - umsg_super_stret_decl = add_builtin_function (TAG_MSGSENDSUPER_STRET, - type, 0, NOT_BUILT_IN, 0, - NULL_TREE); - TREE_NOTHROW (umsg_super_decl) = 0; - TREE_NOTHROW (umsg_super_stret_decl) = 0; - } - else - { - /* GNU runtime messenger entry points. */ - - /* typedef id (*IMP)(id, SEL, ...); */ - tree ftype = - build_varargs_function_type_list (objc_object_type, - objc_object_type, - objc_selector_type, - NULL_TREE); - tree IMP_type = build_pointer_type (ftype); - - /* IMP objc_msg_lookup (id, SEL); */ - type = build_function_type_list (IMP_type, - objc_object_type, - objc_selector_type, - NULL_TREE); - umsg_decl = add_builtin_function (TAG_MSGSEND, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - TREE_NOTHROW (umsg_decl) = 0; - - /* IMP objc_msg_lookup_super (struct objc_super *, SEL); */ - type - = build_function_type_list (IMP_type, - objc_super_type, - objc_selector_type, - NULL_TREE); - umsg_super_decl = add_builtin_function (TAG_MSGSENDSUPER, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - TREE_NOTHROW (umsg_super_decl) = 0; - - /* The following GNU runtime entry point is called to initialize - each module: - - __objc_exec_class (void *); */ - type - = build_function_type_list (void_type_node, - ptr_type_node, - NULL_TREE); - execclass_decl = add_builtin_function (TAG_EXECCLASS, - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - } - - /* id objc_getClass (const char *); */ - - type = build_function_type_list (objc_object_type, - const_string_type_node, - NULL_TREE); - - objc_get_class_decl - = add_builtin_function (TAG_GETCLASS, type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - - /* id objc_getMetaClass (const char *); */ + build_common_objc_exception_stuff (); - objc_get_meta_class_decl - = add_builtin_function (TAG_GETMETACLASS, type, 0, NOT_BUILT_IN, NULL, NULL_TREE); - - build_class_template (); - build_super_template (); - build_protocol_template (); - build_category_template (); - build_objc_exception_stuff (); + /* Set-up runtime-specific templates, message and exception stuff. */ + (*runtime.initialize) (); /* Declare objc_getProperty, object_setProperty and other property accessor helpers. */ - build_objc_property_accessor_helpers (); - - if (flag_next_runtime) - build_next_objc_exception_stuff (); - - /* static SEL _OBJC_SELECTOR_TABLE[]; */ - - if (! flag_next_runtime) - build_selector_table_decl (); + build_common_objc_property_accessor_helpers (); /* Forward declare constant_string_id and constant_string_type. */ if (!constant_string_class_name) - constant_string_class_name = default_constant_string_class_name; - + constant_string_class_name = runtime.default_constant_string_class_name; constant_string_id = get_identifier (constant_string_class_name); objc_declare_class (tree_cons (NULL_TREE, constant_string_id, NULL_TREE)); @@ -3333,6 +2954,8 @@ synth_module_prologue (void) debug_hooks = save_hooks; } +/* --- const strings --- */ + /* Ensure that the ivar list for NSConstantString/NXConstantString (or whatever was specified via `-fconstant-string-class') contains fields at least as large as the following three, so that @@ -3397,7 +3020,7 @@ objc_build_internal_const_str_type (void) /* Custom build_string which sets TREE_TYPE! */ -static tree +tree my_build_string (int len, const char *str) { return fix_string_type (build_string (len, str)); @@ -3406,7 +3029,7 @@ my_build_string (int len, const char *str) /* Build a string with contents STR and length LEN and convert it to a pointer. */ -static tree +tree my_build_string_pointer (int len, const char *str) { tree string = my_build_string (len, str); @@ -3452,7 +3075,7 @@ objc_build_string_object (tree string) { tree constant_string_class; int length; - tree fields, addr; + tree addr; struct string_descriptor *desc, key; void **loc; @@ -3465,7 +3088,8 @@ objc_build_string_object (tree string) literal. On Darwin (Mac OS X), for example, we may wish to obtain a constant CFString reference instead. At present, this is only supported for the NeXT runtime. */ - if (flag_next_runtime && targetcm.objc_construct_string_object) + if (flag_next_runtime + && targetcm.objc_construct_string_object) { tree constructor = (*targetcm.objc_construct_string_object) (string); if (constructor) @@ -3489,11 +3113,10 @@ objc_build_string_object (tree string) else if (!check_string_class_template ()) error ("interface %qE does not have valid constant string layout", constant_string_id); - /* For the NeXT runtime, we can generate a literal reference - to the string class, don't need to run a constructor. */ - else if (flag_next_runtime && !setup_string_decl ()) - error ("cannot find reference tag for class %qE", - constant_string_id); + /* If the runtime can generate a literal reference to the string class, + don't need to run a constructor. */ + else if (!(*runtime.setup_const_string_class_decl)()) + error ("cannot find reference tag for class %qE", constant_string_id); else { string_layout_checked = 1; /* Success! */ @@ -3511,40 +3134,10 @@ objc_build_string_object (tree string) if (!desc) { - tree var, constructor; - VEC(constructor_elt,gc) *v = NULL; *loc = desc = ggc_alloc_string_descriptor (); desc->literal = string; - - /* GNU: (NXConstantString *) & ((__builtin_ObjCString) { NULL, string, length }) */ - /* NeXT: (NSConstantString *) & ((__builtin_ObjCString) { isa, string, length }) */ - fields = TYPE_FIELDS (internal_const_str_type); - CONSTRUCTOR_APPEND_ELT (v, fields, - flag_next_runtime - ? build_unary_op (input_location, - ADDR_EXPR, string_class_decl, 0) - : build_int_cst (NULL_TREE, 0)); - fields = DECL_CHAIN (fields); - CONSTRUCTOR_APPEND_ELT (v, fields, - build_unary_op (input_location, - ADDR_EXPR, string, 1)); - fields = DECL_CHAIN (fields); - CONSTRUCTOR_APPEND_ELT (v, fields, build_int_cst (NULL_TREE, length)); - constructor = objc_build_constructor (internal_const_str_type, v); - - if (!flag_next_runtime) - constructor - = objc_add_static_instance (constructor, constant_string_type); - else - { - var = build_decl (input_location, - CONST_DECL, NULL, TREE_TYPE (constructor)); - DECL_INITIAL (var) = constructor; - TREE_STATIC (var) = 1; - pushdecl_top_level (var); - constructor = var; - } - desc->constructor = constructor; + desc->constructor = + (*runtime.build_const_string_constructor) (input_location, string, length); } addr = convert (build_pointer_type (constant_string_type), @@ -3554,51 +3147,10 @@ objc_build_string_object (tree string) return addr; } -/* Declare a static instance of CLASS_DECL initialized by CONSTRUCTOR. */ - -static GTY(()) int num_static_inst; - -static tree -objc_add_static_instance (tree constructor, tree class_decl) -{ - tree *chain, decl; - char buf[256]; - - /* Find the list of static instances for the CLASS_DECL. Create one if - not found. */ - for (chain = &objc_static_instances; - *chain && TREE_VALUE (*chain) != class_decl; - chain = &TREE_CHAIN (*chain)); - if (!*chain) - { - *chain = tree_cons (NULL_TREE, class_decl, NULL_TREE); - add_objc_string (OBJC_TYPE_NAME (class_decl), class_names); - } - - sprintf (buf, "_OBJC_INSTANCE_%d", num_static_inst++); - decl = build_decl (input_location, - VAR_DECL, get_identifier (buf), class_decl); - TREE_STATIC (decl) = 1; - DECL_ARTIFICIAL (decl) = 1; - TREE_USED (decl) = 1; - DECL_INITIAL (decl) = constructor; - - /* We may be writing something else just now. - Postpone till end of input. */ - DECL_DEFER_OUTPUT (decl) = 1; - pushdecl_top_level (decl); - rest_of_decl_compilation (decl, 1, 0); - - /* Add the DECL to the head of this CLASS' list. */ - TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, decl, TREE_PURPOSE (*chain)); - - return decl; -} - /* Build a static constant CONSTRUCTOR with type TYPE and elements ELTS. */ -static tree +tree objc_build_constructor (tree type, VEC(constructor_elt,gc) *elts) { tree constructor = build_constructor (type, elts); @@ -3616,360 +3168,10 @@ objc_build_constructor (tree type, VEC(constructor_elt,gc) *elts) return constructor; } - -/* Take care of defining and initializing _OBJC_SYMBOLS. */ - -/* Predefine the following data type: - - struct _objc_symtab - { - long sel_ref_cnt; - SEL *refs; - short cls_def_cnt; - short cat_def_cnt; - void *defs[cls_def_cnt + cat_def_cnt]; - }; */ - -static void -build_objc_symtab_template (void) -{ - tree fields, *chain = NULL; - - objc_symtab_template = objc_start_struct (get_identifier (UTAG_SYMTAB)); - - /* long sel_ref_cnt; */ - fields = add_field_decl (long_integer_type_node, "sel_ref_cnt", &chain); - - /* SEL *refs; */ - add_field_decl (build_pointer_type (objc_selector_type), "refs", &chain); - - /* short cls_def_cnt; */ - add_field_decl (short_integer_type_node, "cls_def_cnt", &chain); - - /* short cat_def_cnt; */ - add_field_decl (short_integer_type_node, "cat_def_cnt", &chain); - - if (imp_count || cat_count || !flag_next_runtime) - { - /* void *defs[imp_count + cat_count (+ 1)]; */ - /* NB: The index is one less than the size of the array. */ - int index = imp_count + cat_count + (flag_next_runtime ? -1: 0); - tree array_type = build_sized_array_type (ptr_type_node, index + 1); - add_field_decl (array_type, "defs", &chain); - } - - objc_finish_struct (objc_symtab_template, fields); -} - -/* Create the initial value for the `defs' field of _objc_symtab. - This is a CONSTRUCTOR. */ - -static tree -init_def_list (tree type) -{ - tree expr; - struct imp_entry *impent; - VEC(constructor_elt,gc) *v = NULL; - - if (imp_count) - for (impent = imp_list; impent; impent = impent->next) - { - if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) - { - expr = build_unary_op (input_location, - ADDR_EXPR, impent->class_decl, 0); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); - } - } - - if (cat_count) - for (impent = imp_list; impent; impent = impent->next) - { - if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE) - { - expr = build_unary_op (input_location, - ADDR_EXPR, impent->class_decl, 0); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); - } - } - - if (!flag_next_runtime) - { - /* statics = { ..., _OBJC_STATIC_INSTANCES, ... } */ - if (static_instances_decl) - expr = build_unary_op (input_location, - ADDR_EXPR, static_instances_decl, 0); - else - expr = integer_zero_node; - - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); - } - - return objc_build_constructor (type, v); -} - -/* Construct the initial value for all of _objc_symtab. */ - -static tree -init_objc_symtab (tree type) -{ - VEC(constructor_elt,gc) *v = NULL; - - /* sel_ref_cnt = { ..., 5, ... } */ - - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, - build_int_cst (long_integer_type_node, 0)); - - /* refs = { ..., _OBJC_SELECTOR_TABLE, ... } */ - - if (flag_next_runtime || ! sel_ref_chain) - 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, - UOBJC_SELECTOR_TABLE_decl, 1); - - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, - convert (build_pointer_type (objc_selector_type), - expr)); - } - - /* cls_def_cnt = { ..., 5, ... } */ - - 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 (short_integer_type_node, cat_count)); - - /* cls_def = { ..., { &Foo, &Bar, ...}, ... } */ - - if (imp_count || cat_count || !flag_next_runtime) - { - - tree field = TYPE_FIELDS (type); - field = DECL_CHAIN (DECL_CHAIN (DECL_CHAIN (DECL_CHAIN (field)))); - - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init_def_list (TREE_TYPE (field))); - } - - return objc_build_constructor (type, v); -} - -/* Generate forward declarations for metadata such as - 'OBJC_CLASS_...'. */ - -static tree -build_metadata_decl (const char *name, tree type) -{ - tree decl; - - /* struct TYPE NAME_<name>; */ - decl = start_var_decl (type, synth_id_with_class_suffix - (name, - objc_implementation_context)); - - return decl; -} - -/* Push forward-declarations of all the categories so that - init_def_list can use them in a CONSTRUCTOR. */ - -static void -forward_declare_categories (void) -{ - struct imp_entry *impent; - tree sav = objc_implementation_context; - - for (impent = imp_list; impent; impent = impent->next) - { - if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE) - { - /* Set an invisible arg to synth_id_with_class_suffix. */ - objc_implementation_context = impent->imp_context; - /* extern struct objc_category _OBJC_CATEGORY_<name>; */ - impent->class_decl = build_metadata_decl ("_OBJC_CATEGORY", - objc_category_template); - } - } - objc_implementation_context = sav; -} - -/* Create the declaration of _OBJC_SYMBOLS, with type `struct _objc_symtab' - and initialized appropriately. */ - -static void -generate_objc_symtab_decl (void) -{ - - build_objc_symtab_template (); - UOBJC_SYMBOLS_decl = start_var_decl (objc_symtab_template, "_OBJC_SYMBOLS"); - finish_var_decl (UOBJC_SYMBOLS_decl, - init_objc_symtab (TREE_TYPE (UOBJC_SYMBOLS_decl))); -} - -static tree -init_module_descriptor (tree type) -{ - tree expr; - VEC(constructor_elt,gc) *v = NULL; - - /* version = { 1, ... } */ - - expr = build_int_cst (long_integer_type_node, OBJC_VERSION); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); - - /* size = { ..., sizeof (struct _objc_module), ... } */ - - expr = convert (long_integer_type_node, - size_in_bytes (objc_module_template)); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); - - /* Don't provide any file name for security reasons. */ - /* name = { ..., "", ... } */ - - expr = add_objc_string (get_identifier (""), class_names); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); - - /* symtab = { ..., _OBJC_SYMBOLS, ... } */ - - if (UOBJC_SYMBOLS_decl) - expr = build_unary_op (input_location, - ADDR_EXPR, UOBJC_SYMBOLS_decl, 0); - else - expr = null_pointer_node; - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); - - return objc_build_constructor (type, v); -} - -/* Write out the data structures to describe Objective C classes defined. - - struct _objc_module { ... } _OBJC_MODULE = { ... }; */ - -static void -build_module_descriptor (void) -{ - tree decls, *chain = NULL; - -#ifdef OBJCPLUS - push_lang_context (lang_name_c); /* extern "C" */ -#endif - - objc_module_template = objc_start_struct (get_identifier (UTAG_MODULE)); - - /* long version; */ - decls = add_field_decl (long_integer_type_node, "version", &chain); - - /* long size; */ - add_field_decl (long_integer_type_node, "size", &chain); - - /* char *name; */ - add_field_decl (string_type_node, "name", &chain); - - /* struct _objc_symtab *symtab; */ - add_field_decl (build_pointer_type (xref_tag (RECORD_TYPE, - get_identifier (UTAG_SYMTAB))), - "symtab", &chain); - - objc_finish_struct (objc_module_template, decls); - - /* 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))); - -#ifdef OBJCPLUS - pop_lang_context (); -#endif -} - -/* The GNU runtime requires us to provide a static initializer function - for each module: - - static void __objc_gnu_init (void) { - __objc_exec_class (&L_OBJC_MODULES); - } */ - -static void -build_module_initializer_routine (void) -{ - tree body; - -#ifdef OBJCPLUS - push_lang_context (lang_name_c); /* extern "C" */ -#endif - - objc_push_parm (build_decl (input_location, - PARM_DECL, NULL_TREE, void_type_node)); -#ifdef OBJCPLUS - objc_start_function (get_identifier (TAG_GNUINIT), - build_function_type_list (void_type_node, NULL_TREE), - NULL_TREE, NULL_TREE); -#else - objc_start_function (get_identifier (TAG_GNUINIT), - build_function_type_list (void_type_node, NULL_TREE), - NULL_TREE, objc_get_parm_info (0)); -#endif - body = c_begin_compound_stmt (true); - add_stmt (build_function_call - (input_location, - execclass_decl, - build_tree_list - (NULL_TREE, - build_unary_op (input_location, ADDR_EXPR, - UOBJC_MODULES_decl, 0)))); - add_stmt (c_end_compound_stmt (input_location, body, true)); - - TREE_PUBLIC (current_function_decl) = 0; - -#ifndef OBJCPLUS - /* For Objective-C++, we will need to call __objc_gnu_init - from objc_generate_static_init_call() below. */ - DECL_STATIC_CONSTRUCTOR (current_function_decl) = 1; -#endif - - GNU_INIT_decl = current_function_decl; - finish_function (); - -#ifdef OBJCPLUS - pop_lang_context (); -#endif -} - -#ifdef OBJCPLUS -/* Return 1 if the __objc_gnu_init function has been synthesized and needs - to be called by the module initializer routine. */ - -int -objc_static_init_needed_p (void) -{ - return (GNU_INIT_decl != NULL_TREE); -} - -/* Generate a call to the __objc_gnu_init initializer function. */ - -tree -objc_generate_static_init_call (tree ctors ATTRIBUTE_UNUSED) -{ - add_stmt (build_stmt (input_location, EXPR_STMT, - build_function_call (input_location, - GNU_INIT_decl, NULL_TREE))); - - return ctors; -} -#endif /* OBJCPLUS */ /* Return the DECL of the string IDENT in the SECTION. */ -static tree +tree get_objc_string_decl (tree ident, enum string_section section) { tree chain; @@ -3985,6 +3187,9 @@ get_objc_string_decl (tree ident, enum string_section section) case meth_var_types: chain = meth_var_types_chain; break; + case prop_names_attr: + chain = prop_names_attr_chain; + break; default: gcc_unreachable (); } @@ -3993,314 +3198,14 @@ get_objc_string_decl (tree ident, enum string_section section) if (TREE_VALUE (chain) == ident) return (TREE_PURPOSE (chain)); - gcc_unreachable (); + /* We didn't find the entry. */ return NULL_TREE; } -/* Output references to all statically allocated objects. Return the DECL - for the array built. */ - -static void -generate_static_references (void) -{ - tree expr = NULL_TREE; - tree class_name, klass, decl; - tree cl_chain, in_chain, type - = build_array_type (build_pointer_type (void_type_node), NULL_TREE); - int num_inst, num_class; - char buf[256]; - VEC(constructor_elt,gc) *decls = NULL; - - if (flag_next_runtime) - gcc_unreachable (); - - for (cl_chain = objc_static_instances, num_class = 0; - cl_chain; cl_chain = TREE_CHAIN (cl_chain), num_class++) - { - VEC(constructor_elt,gc) *v = NULL; - - for (num_inst = 0, in_chain = TREE_PURPOSE (cl_chain); - in_chain; num_inst++, in_chain = TREE_CHAIN (in_chain)); - - sprintf (buf, "_OBJC_STATIC_INSTANCES_%d", num_class); - decl = start_var_decl (type, buf); - - /* Output {class_name, ...}. */ - klass = TREE_VALUE (cl_chain); - class_name = get_objc_string_decl (OBJC_TYPE_NAME (klass), class_names); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, - build_unary_op (input_location, - ADDR_EXPR, class_name, 1)); - - /* Output {..., instance, ...}. */ - for (in_chain = TREE_PURPOSE (cl_chain); - in_chain; in_chain = TREE_CHAIN (in_chain)) - { - expr = build_unary_op (input_location, - ADDR_EXPR, TREE_VALUE (in_chain), 1); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); - } - - /* Output {..., NULL}. */ - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); - - expr = objc_build_constructor (TREE_TYPE (decl), v); - finish_var_decl (decl, expr); - CONSTRUCTOR_APPEND_ELT (decls, NULL_TREE, - build_unary_op (input_location, - ADDR_EXPR, decl, 1)); - } - - CONSTRUCTOR_APPEND_ELT (decls, NULL_TREE, build_int_cst (NULL_TREE, 0)); - expr = objc_build_constructor (type, decls); - static_instances_decl = start_var_decl (type, "_OBJC_STATIC_INSTANCES"); - finish_var_decl (static_instances_decl, expr); -} - -static GTY(()) int selector_reference_idx; - -static tree -build_selector_reference_decl (void) -{ - tree decl; - char buf[256]; - - sprintf (buf, "_OBJC_SELECTOR_REFERENCES_%d", selector_reference_idx++); - decl = start_var_decl (objc_selector_type, buf); - - return decl; -} - -static void -build_selector_table_decl (void) -{ - tree temp; - - if (flag_typed_selectors) - { - build_selector_template (); - temp = build_array_type (objc_selector_template, NULL_TREE); - } - else - temp = build_array_type (objc_selector_type, NULL_TREE); - - UOBJC_SELECTOR_TABLE_decl = start_var_decl (temp, "_OBJC_SELECTOR_TABLE"); -} - -/* Just a handy wrapper for add_objc_string. */ - -static tree -build_selector (tree ident) -{ - return convert (objc_selector_type, - add_objc_string (ident, meth_var_names)); -} - -/* Used only by build_*_selector_translation_table (). */ -static 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; - 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 on start-up, but the compiler 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)) - { - tree expr; - - if (warn_selector && objc_implementation_context) - 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;*/ - - { - if (flag_typed_selectors) - { - VEC(constructor_elt,gc) *v = NULL; - tree encoding = get_proto_encoding (TREE_PURPOSE (chain)); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, encoding); - expr = objc_build_constructor (objc_selector_template, v); - } - - CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); - } - } /* each element in the chain */ - - { - /* Cause the selector table (previously forward-declared) - to be actually output. */ - tree expr; - - if (flag_typed_selectors) - { - VEC(constructor_elt,gc) *v = NULL; - 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 = integer_zero_node; - - CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); - expr = objc_build_constructor (TREE_TYPE (UOBJC_SELECTOR_TABLE_decl), - inits); - finish_var_decl (UOBJC_SELECTOR_TABLE_decl, expr); - } -} - -static tree -get_proto_encoding (tree proto) -{ - tree encoding; - if (proto) - { - if (! METHOD_ENCODING (proto)) - { - encoding = encode_method_prototype (proto); - METHOD_ENCODING (proto) = encoding; - } - else - encoding = METHOD_ENCODING (proto); - - return add_objc_string (encoding, meth_var_types); - } - else - return build_int_cst (NULL_TREE, 0); -} - -/* sel_ref_chain is a list whose "value" fields will be instances of - identifier_node that represent the selector. LOC is the location of - the @selector. */ - -static tree -build_typed_selector_reference (location_t loc, tree ident, tree prototype) -{ - tree *chain = &sel_ref_chain; - tree expr; - int index = 0; - - while (*chain) - { - if (TREE_PURPOSE (*chain) == prototype && TREE_VALUE (*chain) == ident) - goto return_at_index; - - index++; - chain = &TREE_CHAIN (*chain); - } - - *chain = tree_cons (prototype, ident, NULL_TREE); - - return_at_index: - expr = build_unary_op (loc, ADDR_EXPR, - build_array_ref (loc, UOBJC_SELECTOR_TABLE_decl, - build_int_cst (NULL_TREE, index)), - 1); - return convert (objc_selector_type, expr); -} - -static tree -build_selector_reference (location_t loc, tree ident) -{ - tree *chain = &sel_ref_chain; - tree expr; - int index = 0; - - while (*chain) - { - if (TREE_VALUE (*chain) == ident) - return (flag_next_runtime - ? TREE_PURPOSE (*chain) - : build_array_ref (loc, UOBJC_SELECTOR_TABLE_decl, - build_int_cst (NULL_TREE, index))); - - index++; - chain = &TREE_CHAIN (*chain); - } - - expr = (flag_next_runtime ? build_selector_reference_decl (): NULL_TREE); - - *chain = tree_cons (expr, ident, NULL_TREE); - - return (flag_next_runtime - ? expr - : build_array_ref (loc, UOBJC_SELECTOR_TABLE_decl, - build_int_cst (NULL_TREE, index))); -} - -static GTY(()) int class_reference_idx; - -static tree -build_class_reference_decl (void) -{ - tree decl; - char buf[256]; - - sprintf (buf, "_OBJC_CLASS_REFERENCES_%d", class_reference_idx++); - decl = start_var_decl (objc_class_type, buf); - - return decl; -} - /* Create a class reference, but don't create a variable to reference it. */ -static void +void add_class_reference (tree ident) { tree chain; @@ -4361,93 +3266,7 @@ objc_get_class_reference (tree ident) return error_mark_node; } - if (flag_next_runtime && !flag_zero_link) - { - tree *chain; - tree decl; - - for (chain = &cls_ref_chain; *chain; chain = &TREE_CHAIN (*chain)) - if (TREE_VALUE (*chain) == ident) - { - if (! TREE_PURPOSE (*chain)) - TREE_PURPOSE (*chain) = build_class_reference_decl (); - - return TREE_PURPOSE (*chain); - } - - decl = build_class_reference_decl (); - *chain = tree_cons (decl, ident, NULL_TREE); - return decl; - } - else - { - tree params; - - add_class_reference (ident); - - params = build_tree_list (NULL_TREE, - my_build_string_pointer - (IDENTIFIER_LENGTH (ident) + 1, - IDENTIFIER_POINTER (ident))); - - assemble_external (objc_get_class_decl); - return build_function_call (input_location, objc_get_class_decl, params); - } -} - -/* 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; - char buf[256]; - - buf[0] = 0; - switch (section) - { - case class_names: - chain = &class_names_chain; - sprintf (buf, "_OBJC_CLASS_NAME_%d", class_names_idx++); - break; - case meth_var_names: - chain = &meth_var_names_chain; - sprintf (buf, "_OBJC_METH_VAR_NAME_%d", meth_var_names_idx++); - break; - case meth_var_types: - chain = &meth_var_types_chain; - sprintf (buf, "_OBJC_METH_VAR_TYPE_%d", meth_var_types_idx++); - break; - default: - gcc_unreachable (); - } - - while (*chain) - { - if (TREE_VALUE (*chain) == ident) - return convert (string_type_node, - build_unary_op (input_location, - ADDR_EXPR, TREE_PURPOSE (*chain), 1)); - - chain = &TREE_CHAIN (*chain); - } - - type = build_sized_array_type (char_type_node, IDENTIFIER_LENGTH (ident) + 1); - decl = start_var_decl (type, buf); - string_expr = my_build_string (IDENTIFIER_LENGTH (ident) + 1, - IDENTIFIER_POINTER (ident)); - TREE_CONSTANT (decl) = 1; - finish_var_decl (decl, string_expr); - - *chain = tree_cons (decl, ident, NULL_TREE); - - return convert (string_type_node, build_unary_op (input_location, - ADDR_EXPR, decl, 1)); + return (*runtime.get_class_reference) (ident); } void @@ -4505,9 +3324,9 @@ objc_declare_class (tree ident_list) if (record) { if (TREE_CODE (record) == TYPE_DECL) - type = DECL_ORIGINAL_TYPE (record) ? - DECL_ORIGINAL_TYPE (record) : - TREE_TYPE (record); + type = DECL_ORIGINAL_TYPE (record) + ? DECL_ORIGINAL_TYPE (record) + : TREE_TYPE (record); if (!TYPE_HAS_OBJC_INFO (type) || !TYPE_OBJC_INTERFACE (type)) @@ -4909,7 +3728,7 @@ eq_interface (const void *p1, const void *p2) return d->id == p2; } -static tree +tree lookup_interface (tree ident) { #ifdef OBJCPLUS @@ -4997,76 +3816,6 @@ get_class_ivars (tree interface, bool inherited) return ivar_chain; } - -/* Exception handling constructs. We begin by having the parser do most - of the work and passing us blocks. What we do next depends on whether - we're doing "native" exception handling or legacy Darwin setjmp exceptions. - We abstract all of this in a handful of appropriately named routines. */ - -/* Stack of open try blocks. */ - -struct objc_try_context -{ - struct objc_try_context *outer; - - /* Statements (or statement lists) as processed by the parser. */ - tree try_body; - tree finally_body; - - /* Some file position locations. */ - location_t try_locus; - location_t end_try_locus; - location_t end_catch_locus; - location_t finally_locus; - location_t end_finally_locus; - - /* A STATEMENT_LIST of CATCH_EXPRs, appropriate for sticking into op1 - of a TRY_CATCH_EXPR. Even when doing Darwin setjmp. */ - tree catch_list; - - /* The CATCH_EXPR of an open @catch clause. */ - tree current_catch; - - /* The VAR_DECL holding the Darwin equivalent of __builtin_eh_pointer. */ - tree caught_decl; - tree stack_decl; - tree rethrow_decl; -}; - -static struct objc_try_context *cur_try_context; - -static GTY(()) tree objc_eh_personality_decl; - -/* This hook, called via lang_eh_runtime_type, generates a runtime object - that represents TYPE. For Objective-C, this is just the class name. */ -/* ??? Isn't there a class object or some such? Is it easy to get? */ - -#ifndef OBJCPLUS -tree -objc_eh_runtime_type (tree type) -{ - /* Use 'ErrorMarkNode' as class name when error_mark_node is found - to prevent an ICE. Note that we know that the compiler will - terminate with an error and this 'ErrorMarkNode' class name will - never be actually used. */ - if (type == error_mark_node) - return add_objc_string (get_identifier ("ErrorMarkNode"), class_names); - else - return add_objc_string (OBJC_TYPE_NAME (TREE_TYPE (type)), class_names); -} - -tree -objc_eh_personality (void) -{ - if (!flag_objc_sjlj_exceptions && !objc_eh_personality_decl) - objc_eh_personality_decl = build_personality_function - (flag_next_runtime - ? "objc" - : "gnu_objc"); - return objc_eh_personality_decl; -} -#endif - void objc_maybe_warn_exceptions (location_t loc) { @@ -5089,293 +3838,7 @@ objc_maybe_warn_exceptions (location_t loc) } } -/* Build __builtin_eh_pointer, or the moral equivalent. In the case - of Darwin, we'll arrange for it to be initialized (and associated - with a binding) later. */ - -static tree -objc_build_exc_ptr (void) -{ - if (flag_objc_sjlj_exceptions) - { - tree var = cur_try_context->caught_decl; - if (!var) - { - var = objc_create_temporary_var (objc_object_type, NULL); - cur_try_context->caught_decl = var; - } - return var; - } - else - { - tree t; - t = built_in_decls[BUILT_IN_EH_POINTER]; - t = build_call_expr (t, 1, integer_zero_node); - return fold_convert (objc_object_type, t); - } -} - -/* Build "objc_exception_try_exit(&_stack)". */ - -static tree -next_sjlj_build_try_exit (void) -{ - tree t; - t = build_fold_addr_expr_loc (input_location, cur_try_context->stack_decl); - t = tree_cons (NULL, t, NULL); - t = build_function_call (input_location, - objc_exception_try_exit_decl, t); - return t; -} - -/* Build - objc_exception_try_enter (&_stack); - if (_setjmp(&_stack.buf)) - ; - else - ; - Return the COND_EXPR. Note that the THEN and ELSE fields are left - empty, ready for the caller to fill them in. */ - -static tree -next_sjlj_build_enter_and_setjmp (void) -{ - tree t, enter, sj, cond; - - t = build_fold_addr_expr_loc (input_location, cur_try_context->stack_decl); - t = tree_cons (NULL, t, NULL); - enter = build_function_call (input_location, - objc_exception_try_enter_decl, t); - - t = objc_build_component_ref (cur_try_context->stack_decl, - get_identifier ("buf")); - t = build_fold_addr_expr_loc (input_location, t); -#ifdef OBJCPLUS - /* Convert _setjmp argument to type that is expected. */ - if (prototype_p (TREE_TYPE (objc_setjmp_decl))) - t = convert (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl))), t); - else - t = convert (ptr_type_node, t); -#else - t = convert (ptr_type_node, t); -#endif - t = tree_cons (NULL, t, NULL); - sj = build_function_call (input_location, - objc_setjmp_decl, t); - - cond = build2 (COMPOUND_EXPR, TREE_TYPE (sj), enter, sj); - cond = c_common_truthvalue_conversion (input_location, cond); - - return build3 (COND_EXPR, void_type_node, cond, NULL, NULL); -} - -/* Build: - - DECL = objc_exception_extract(&_stack); */ - -static tree -next_sjlj_build_exc_extract (tree decl) -{ - tree t; - - t = build_fold_addr_expr_loc (input_location, cur_try_context->stack_decl); - t = tree_cons (NULL, t, NULL); - t = build_function_call (input_location, - objc_exception_extract_decl, t); - t = convert (TREE_TYPE (decl), t); - t = build2 (MODIFY_EXPR, void_type_node, decl, t); - - return t; -} - -/* Build - if (objc_exception_match(obj_get_class(TYPE), _caught) - BODY - else if (...) - ... - else - { - _rethrow = _caught; - objc_exception_try_exit(&_stack); - } - from the sequence of CATCH_EXPRs in the current try context. */ - -static tree -next_sjlj_build_catch_list (void) -{ - tree_stmt_iterator i = tsi_start (cur_try_context->catch_list); - tree catch_seq, t; - tree *last = &catch_seq; - bool saw_id = false; - - for (; !tsi_end_p (i); tsi_next (&i)) - { - tree stmt = tsi_stmt (i); - tree type = CATCH_TYPES (stmt); - tree body = CATCH_BODY (stmt); - - if (type == NULL) - { - *last = body; - saw_id = true; - break; - } - else - { - tree args, cond; - - if (type == error_mark_node) - cond = error_mark_node; - else - { - args = tree_cons (NULL, cur_try_context->caught_decl, NULL); - t = objc_get_class_reference (OBJC_TYPE_NAME (TREE_TYPE (type))); - args = tree_cons (NULL, t, args); - t = build_function_call (input_location, - objc_exception_match_decl, args); - cond = c_common_truthvalue_conversion (input_location, t); - } - t = build3 (COND_EXPR, void_type_node, cond, body, NULL); - SET_EXPR_LOCATION (t, EXPR_LOCATION (stmt)); - - *last = t; - last = &COND_EXPR_ELSE (t); - } - } - - if (!saw_id) - { - t = build2 (MODIFY_EXPR, void_type_node, cur_try_context->rethrow_decl, - cur_try_context->caught_decl); - SET_EXPR_LOCATION (t, cur_try_context->end_catch_locus); - append_to_statement_list (t, last); - - t = next_sjlj_build_try_exit (); - SET_EXPR_LOCATION (t, cur_try_context->end_catch_locus); - append_to_statement_list (t, last); - } - - return catch_seq; -} - -/* Build a complete @try-@catch-@finally block for legacy Darwin setjmp - exception handling. We aim to build: - - { - struct _objc_exception_data _stack; - id _rethrow = 0; - try - { - objc_exception_try_enter (&_stack); - if (_setjmp(&_stack.buf)) - { - id _caught = objc_exception_extract(&_stack); - objc_exception_try_enter (&_stack); - if (_setjmp(&_stack.buf)) - _rethrow = objc_exception_extract(&_stack); - else - CATCH-LIST - } - else - TRY-BLOCK - } - finally - { - if (!_rethrow) - objc_exception_try_exit(&_stack); - FINALLY-BLOCK - if (_rethrow) - objc_exception_throw(_rethrow); - } - } - - If CATCH-LIST is empty, we can omit all of the block containing - "_caught" except for the setting of _rethrow. Note the use of - a real TRY_FINALLY_EXPR here, which is not involved in EH per-se, - but handles goto and other exits from the block. */ - -static tree -next_sjlj_build_try_catch_finally (void) -{ - tree rethrow_decl, stack_decl, t; - tree catch_seq, try_fin, bind; - - /* Create the declarations involved. */ - t = xref_tag (RECORD_TYPE, get_identifier (UTAG_EXCDATA)); - stack_decl = objc_create_temporary_var (t, NULL); - cur_try_context->stack_decl = stack_decl; - - rethrow_decl = objc_create_temporary_var (objc_object_type, NULL); - cur_try_context->rethrow_decl = rethrow_decl; - TREE_CHAIN (rethrow_decl) = stack_decl; - - /* Build the outermost variable binding level. */ - bind = build3 (BIND_EXPR, void_type_node, rethrow_decl, NULL, NULL); - SET_EXPR_LOCATION (bind, cur_try_context->try_locus); - TREE_SIDE_EFFECTS (bind) = 1; - - /* Initialize rethrow_decl. */ - t = build2 (MODIFY_EXPR, void_type_node, rethrow_decl, - convert (objc_object_type, null_pointer_node)); - SET_EXPR_LOCATION (t, cur_try_context->try_locus); - append_to_statement_list (t, &BIND_EXPR_BODY (bind)); - - /* Build the outermost TRY_FINALLY_EXPR. */ - try_fin = build2 (TRY_FINALLY_EXPR, void_type_node, NULL, NULL); - SET_EXPR_LOCATION (try_fin, cur_try_context->try_locus); - TREE_SIDE_EFFECTS (try_fin) = 1; - append_to_statement_list (try_fin, &BIND_EXPR_BODY (bind)); - - /* Create the complete catch sequence. */ - if (cur_try_context->catch_list) - { - tree caught_decl = objc_build_exc_ptr (); - catch_seq = build_stmt (input_location, BIND_EXPR, caught_decl, NULL, NULL); - TREE_SIDE_EFFECTS (catch_seq) = 1; - - t = next_sjlj_build_exc_extract (caught_decl); - append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq)); - - t = next_sjlj_build_enter_and_setjmp (); - COND_EXPR_THEN (t) = next_sjlj_build_exc_extract (rethrow_decl); - COND_EXPR_ELSE (t) = next_sjlj_build_catch_list (); - append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq)); - } - else - catch_seq = next_sjlj_build_exc_extract (rethrow_decl); - SET_EXPR_LOCATION (catch_seq, cur_try_context->end_try_locus); - - /* Build the main register-and-try if statement. */ - t = next_sjlj_build_enter_and_setjmp (); - SET_EXPR_LOCATION (t, cur_try_context->try_locus); - COND_EXPR_THEN (t) = catch_seq; - COND_EXPR_ELSE (t) = cur_try_context->try_body; - TREE_OPERAND (try_fin, 0) = t; - - /* Build the complete FINALLY statement list. */ - t = next_sjlj_build_try_exit (); - t = build_stmt (input_location, COND_EXPR, - c_common_truthvalue_conversion - (input_location, rethrow_decl), - NULL, t); - SET_EXPR_LOCATION (t, cur_try_context->finally_locus); - append_to_statement_list (t, &TREE_OPERAND (try_fin, 1)); - - append_to_statement_list (cur_try_context->finally_body, - &TREE_OPERAND (try_fin, 1)); - - t = tree_cons (NULL, rethrow_decl, NULL); - t = build_function_call (input_location, - objc_exception_throw_decl, t); - t = build_stmt (input_location, COND_EXPR, - c_common_truthvalue_conversion (input_location, - rethrow_decl), - t, NULL); - SET_EXPR_LOCATION (t, cur_try_context->end_finally_locus); - append_to_statement_list (t, &TREE_OPERAND (try_fin, 1)); - - return bind; -} +static struct objc_try_context *cur_try_context; /* Called just after parsing the @try and its associated BODY. We now must prepare for the tricky bits -- handling the catches and finally. */ @@ -5407,6 +3870,7 @@ void objc_begin_catch_clause (tree decl) { tree compound, type, t; + bool ellipsis = false; /* Begin a new scope that the entire catch clause will live in. */ compound = c_begin_compound_stmt (true); @@ -5422,6 +3886,9 @@ objc_begin_catch_clause (tree decl) type 'id' and use it. */ decl = objc_create_temporary_var (objc_object_type, "__objc_generic_catch_var"); DECL_SOURCE_LOCATION (decl) = input_location; + /* ... but allow the runtime to differentiate between ellipsis and the + case of @catch (id xyz). */ + ellipsis = true; } else { @@ -5441,13 +3908,13 @@ objc_begin_catch_clause (tree decl) type = TREE_TYPE (decl); } - /* Verify that the type of the catch is valid. It must be a pointer - to an Objective-C class, or "id" (which is catch-all). */ - if (type == error_mark_node) - { - ;/* Just keep going. */ - } - else if (!objc_type_valid_for_messaging (type, false)) + /* Verify that the type of the catch is valid. It must be a pointer + to an Objective-C class, or "id" (which is catch-all). */ + if (type == error_mark_node) + { + ;/* Just keep going. */ + } + else if (!objc_type_valid_for_messaging (type, false)) { error ("@catch parameter is not a known Objective-C class type"); type = error_mark_node; @@ -5458,8 +3925,10 @@ objc_begin_catch_clause (tree decl) error ("@catch parameter can not be protocol-qualified"); type = error_mark_node; } - else if (objc_is_object_id (TREE_TYPE (type))) - type = NULL; + else if (POINTER_TYPE_P (type) && objc_is_object_id (TREE_TYPE (type))) + /* @catch (id xyz) or @catch (...) but we note this for runtimes that + identify 'id'. */ + ; else { /* If 'type' was built using typedefs, we need to get rid of @@ -5508,15 +3977,7 @@ objc_begin_catch_clause (tree decl) } } - /* Record the data for the catch in the try context so that we can - finalize it later. */ - t = build_stmt (input_location, CATCH_EXPR, type, compound); - cur_try_context->current_catch = t; - - /* Initialize the decl from the EXC_PTR_EXPR we get from the runtime. */ - t = objc_build_exc_ptr (); - t = convert (TREE_TYPE (decl), t); - t = build2 (MODIFY_EXPR, void_type_node, decl, t); + t = (*runtime.begin_catch) (&cur_try_context, type, decl, compound, ellipsis); add_stmt (t); } @@ -5531,7 +3992,8 @@ objc_finish_catch_clause (void) cur_try_context->end_catch_locus = input_location; CATCH_BODY (c) = c_end_compound_stmt (input_location, CATCH_BODY (c), 1); - append_to_statement_list (c, &cur_try_context->catch_list); + + (*runtime.finish_catch) (&cur_try_context, c); } /* Called after parsing a @finally clause and its associated BODY. @@ -5556,34 +4018,7 @@ objc_finish_try_stmt (void) if (c->catch_list == NULL && c->finally_body == NULL) error ("%<@try%> without %<@catch%> or %<@finally%>"); - /* If we're doing Darwin setjmp exceptions, build the big nasty. */ - if (flag_objc_sjlj_exceptions) - { - bool save = in_late_binary_op; - in_late_binary_op = true; - if (!cur_try_context->finally_body) - { - cur_try_context->finally_locus = input_location; - cur_try_context->end_finally_locus = input_location; - } - stmt = next_sjlj_build_try_catch_finally (); - in_late_binary_op = save; - } - else - { - /* Otherwise, nest the CATCH inside a FINALLY. */ - stmt = c->try_body; - if (c->catch_list) - { - stmt = build_stmt (input_location, TRY_CATCH_EXPR, stmt, c->catch_list); - SET_EXPR_LOCATION (stmt, cur_try_context->try_locus); - } - if (c->finally_body) - { - stmt = build_stmt (input_location, TRY_FINALLY_EXPR, stmt, c->finally_body); - SET_EXPR_LOCATION (stmt, cur_try_context->try_locus); - } - } + stmt = (*runtime.finish_try_stmt) (&cur_try_context); add_stmt (stmt); cur_try_context = c->outer; @@ -5594,10 +4029,14 @@ objc_finish_try_stmt (void) tree objc_build_throw_stmt (location_t loc, tree throw_expr) { - tree args; + bool rethrown = false; objc_maybe_warn_exceptions (loc); + /* Don't waste time trying to build something if we're already dead. */ + if (throw_expr == error_mark_node) + return error_mark_node; + if (throw_expr == NULL) { /* If we're not inside a @catch block, there is no "current @@ -5611,9 +4050,10 @@ objc_build_throw_stmt (location_t loc, tree throw_expr) /* Otherwise the object is still sitting in the EXC_PTR_EXPR value that we get from the runtime. */ - throw_expr = objc_build_exc_ptr (); + throw_expr = (*runtime.build_exc_ptr) (&cur_try_context); + rethrown = true; } - else if (throw_expr != error_mark_node) + else { if (!objc_type_valid_for_messaging (TREE_TYPE (throw_expr), true)) { @@ -5622,11 +4062,7 @@ objc_build_throw_stmt (location_t loc, tree throw_expr) } } - /* A throw is just a call to the runtime throw function with the - object as a parameter. */ - args = tree_cons (NULL, throw_expr, NULL); - return add_stmt (build_function_call (loc, - objc_exception_throw_decl, args)); + return (*runtime.build_throw_stmt) (loc, throw_expr, rethrown); } tree @@ -5685,143 +4121,6 @@ objc_build_synchronized (location_t start_locus, tree object_expr, tree body) } } - -/* Predefine the following data type: - - struct _objc_exception_data - { - int buf[OBJC_JBLEN]; - void *pointers[4]; - }; */ - -/* The following yuckiness should prevent users from having to #include - <setjmp.h> in their code... */ - -/* Define to a harmless positive value so the below code doesn't die. */ -#ifndef OBJC_JBLEN -#define OBJC_JBLEN 18 -#endif - -static void -build_next_objc_exception_stuff (void) -{ - tree decls, temp_type, *chain = NULL; - - objc_exception_data_template - = objc_start_struct (get_identifier (UTAG_EXCDATA)); - - /* int buf[OBJC_JBLEN]; */ - - temp_type = build_sized_array_type (integer_type_node, OBJC_JBLEN); - decls = add_field_decl (temp_type, "buf", &chain); - - /* void *pointers[4]; */ - - temp_type = build_sized_array_type (ptr_type_node, 4); - add_field_decl (temp_type, "pointers", &chain); - - objc_finish_struct (objc_exception_data_template, decls); - - /* int _setjmp(...); */ - /* If the user includes <setjmp.h>, this shall be superseded by - 'int _setjmp(jmp_buf);' */ - temp_type = build_varargs_function_type_list (integer_type_node, NULL_TREE); - objc_setjmp_decl - = add_builtin_function (TAG_SETJMP, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); - - /* id objc_exception_extract(struct _objc_exception_data *); */ - temp_type - = build_function_type_list (objc_object_type, - build_pointer_type (objc_exception_data_template), - NULL_TREE); - objc_exception_extract_decl - = add_builtin_function (TAG_EXCEPTIONEXTRACT, temp_type, 0, NOT_BUILT_IN, NULL, - NULL_TREE); - /* void objc_exception_try_enter(struct _objc_exception_data *); */ - /* void objc_exception_try_exit(struct _objc_exception_data *); */ - temp_type - = build_function_type_list (void_type_node, - build_pointer_type (objc_exception_data_template), - NULL_TREE); - objc_exception_try_enter_decl - = add_builtin_function (TAG_EXCEPTIONTRYENTER, temp_type, 0, NOT_BUILT_IN, NULL, - NULL_TREE); - objc_exception_try_exit_decl - = add_builtin_function (TAG_EXCEPTIONTRYEXIT, temp_type, 0, NOT_BUILT_IN, NULL, - NULL_TREE); - - /* int objc_exception_match(id, id); */ - temp_type - = build_function_type_list (integer_type_node, - objc_object_type, objc_object_type, NULL_TREE); - objc_exception_match_decl - = add_builtin_function (TAG_EXCEPTIONMATCH, temp_type, 0, NOT_BUILT_IN, NULL, - NULL_TREE); - - /* id objc_assign_ivar (id, id, unsigned int); */ - /* id objc_assign_ivar_Fast (id, id, unsigned int) - __attribute__ ((hard_coded_address (OFFS_ASSIGNIVAR_FAST))); */ - temp_type - = build_function_type_list (objc_object_type, - objc_object_type, - objc_object_type, - unsigned_type_node, - NULL_TREE); - objc_assign_ivar_decl - = add_builtin_function (TAG_ASSIGNIVAR, temp_type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); -#ifdef OFFS_ASSIGNIVAR_FAST - objc_assign_ivar_fast_decl - = add_builtin_function (TAG_ASSIGNIVAR_FAST, temp_type, 0, - NOT_BUILT_IN, NULL, NULL_TREE); - DECL_ATTRIBUTES (objc_assign_ivar_fast_decl) - = tree_cons (get_identifier ("hard_coded_address"), - build_int_cst (NULL_TREE, OFFS_ASSIGNIVAR_FAST), - NULL_TREE); -#else - /* Default to slower ivar method. */ - objc_assign_ivar_fast_decl = objc_assign_ivar_decl; -#endif - - /* id objc_assign_global (id, id *); */ - /* id objc_assign_strongCast (id, id *); */ - temp_type = build_function_type_list (objc_object_type, - objc_object_type, - build_pointer_type (objc_object_type), - NULL_TREE); - objc_assign_global_decl - = add_builtin_function (TAG_ASSIGNGLOBAL, temp_type, 0, NOT_BUILT_IN, NULL, - NULL_TREE); - objc_assign_strong_cast_decl - = add_builtin_function (TAG_ASSIGNSTRONGCAST, temp_type, 0, NOT_BUILT_IN, NULL, - NULL_TREE); -} - -static void -build_objc_exception_stuff (void) -{ - tree noreturn_list, nothrow_list, temp_type; - - noreturn_list = tree_cons (get_identifier ("noreturn"), NULL, NULL); - nothrow_list = tree_cons (get_identifier ("nothrow"), NULL, NULL); - - /* void objc_exception_throw(id) __attribute__((noreturn)); */ - /* void objc_sync_enter(id); */ - /* void objc_sync_exit(id); */ - temp_type = build_function_type_list (void_type_node, - objc_object_type, - NULL_TREE); - objc_exception_throw_decl - = add_builtin_function (TAG_EXCEPTIONTHROW, temp_type, 0, NOT_BUILT_IN, NULL, - noreturn_list); - objc_sync_enter_decl - = add_builtin_function (TAG_SYNCENTER, temp_type, 0, NOT_BUILT_IN, - NULL, nothrow_list); - objc_sync_exit_decl - = add_builtin_function (TAG_SYNCEXIT, temp_type, 0, NOT_BUILT_IN, - NULL, nothrow_list); -} - /* Construct a C struct corresponding to ObjC class CLASS, with the same name as the class: @@ -5847,120 +4146,13 @@ build_private_template (tree klass) /* Copy the attributes from the class to the type. */ if (TREE_DEPRECATED (klass)) TREE_DEPRECATED (record) = 1; - } -} - -/* Begin code generation for protocols... */ - -/* struct _objc_protocol { - struct _objc_class *isa; - char *protocol_name; - struct _objc_protocol **protocol_list; - struct _objc__method_prototype_list *instance_methods; - struct _objc__method_prototype_list *class_methods; - }; */ - -static void -build_protocol_template (void) -{ - tree ptype, decls, *chain = NULL; - - objc_protocol_template = objc_start_struct (get_identifier (UTAG_PROTOCOL)); - - /* struct _objc_class *isa; */ - ptype = build_pointer_type (xref_tag (RECORD_TYPE, - get_identifier (UTAG_CLASS))); - decls = add_field_decl (ptype, "isa", &chain); - /* char *protocol_name; */ - add_field_decl (string_type_node, "protocol_name", &chain); - - /* struct _objc_protocol **protocol_list; */ - ptype = build_pointer_type (build_pointer_type (objc_protocol_template)); - add_field_decl (ptype, "protocol_list", &chain); - - /* struct _objc__method_prototype_list *instance_methods; */ - add_field_decl (objc_method_proto_list_ptr, "instance_methods", &chain); - - /* struct _objc__method_prototype_list *class_methods; */ - add_field_decl (objc_method_proto_list_ptr, "class_methods", &chain); - - objc_finish_struct (objc_protocol_template, decls); -} - -static tree -build_descriptor_table_initializer (tree type, tree entries) -{ - VEC(constructor_elt,gc) *inits = NULL; - - do - { - VEC(constructor_elt,gc) *elts = NULL; - - CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, - build_selector (METHOD_SEL_NAME (entries))); - CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, - add_objc_string (METHOD_ENCODING (entries), - meth_var_types)); - - CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, - objc_build_constructor (type, elts)); - - entries = DECL_CHAIN (entries); + if (CLASS_HAS_EXCEPTION_ATTR (klass)) + CLASS_HAS_EXCEPTION_ATTR (record) = 1; } - while (entries); - - return objc_build_constructor (build_array_type (type, 0), inits); -} - -/* struct objc_method_prototype_list { - int count; - struct objc_method_prototype { - SEL name; - char *types; - } list[1]; - }; */ - -static tree -build_method_prototype_list_template (tree list_type, int size) -{ - tree objc_ivar_list_record; - tree array_type, decls, *chain = NULL; - - /* Generate an unnamed struct definition. */ - - objc_ivar_list_record = objc_start_struct (NULL_TREE); - - /* int method_count; */ - decls = add_field_decl (integer_type_node, "method_count", &chain); - - /* struct objc_method method_list[]; */ - array_type = build_sized_array_type (list_type, size); - add_field_decl (array_type, "method_list", &chain); - - objc_finish_struct (objc_ivar_list_record, decls); - - return objc_ivar_list_record; } -static tree -build_method_prototype_template (void) -{ - tree proto_record; - tree decls, *chain = NULL; - - proto_record = objc_start_struct (get_identifier (UTAG_METHOD_PROTOTYPE)); - - /* SEL _cmd; */ - decls = add_field_decl (objc_selector_type, "_cmd", &chain); - - /* char *method_types; */ - add_field_decl (string_type_node, "method_types", &chain); - - objc_finish_struct (proto_record, decls); - - return proto_record; -} +/* Begin code generation for protocols... */ static tree objc_method_parm_type (tree type) @@ -5992,7 +4184,8 @@ objc_encoded_type_size (tree type) The format is described in gcc/doc/objc.texi, section 'Method signatures'. */ -static tree + +tree encode_method_prototype (tree method_decl) { tree parms; @@ -6063,96 +4256,6 @@ encode_method_prototype (tree method_decl) return result; } -static tree -generate_descriptor_table (tree type, const char *name, int size, tree list, - tree proto) -{ - tree decl; - VEC(constructor_elt,gc) *v = NULL; - - decl = start_var_decl (type, synth_id_with_class_suffix (name, proto)); - - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, size)); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, list); - - finish_var_decl (decl, objc_build_constructor (type, v)); - - return decl; -} - -static void -generate_method_descriptors (tree protocol) -{ - tree initlist, chain, method_list_template; - int size; - - if (!objc_method_prototype_template) - objc_method_prototype_template = build_method_prototype_template (); - - chain = PROTOCOL_CLS_METHODS (protocol); - if (chain) - { - size = list_length (chain); - - method_list_template - = build_method_prototype_list_template (objc_method_prototype_template, - size); - - initlist - = build_descriptor_table_initializer (objc_method_prototype_template, - chain); - - UOBJC_CLASS_METHODS_decl - = generate_descriptor_table (method_list_template, - "_OBJC_PROTOCOL_CLASS_METHODS", - size, initlist, protocol); - } - else - UOBJC_CLASS_METHODS_decl = 0; - - chain = PROTOCOL_NST_METHODS (protocol); - if (chain) - { - size = list_length (chain); - - method_list_template - = build_method_prototype_list_template (objc_method_prototype_template, - size); - initlist - = build_descriptor_table_initializer (objc_method_prototype_template, - chain); - - UOBJC_INSTANCE_METHODS_decl - = generate_descriptor_table (method_list_template, - "_OBJC_PROTOCOL_INSTANCE_METHODS", - size, initlist, protocol); - } - else - UOBJC_INSTANCE_METHODS_decl = 0; -} - -static void -generate_protocol_references (tree plist) -{ - tree lproto; - - /* Forward declare protocols referenced. */ - for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) - { - tree proto = TREE_VALUE (lproto); - - if (TREE_CODE (proto) == PROTOCOL_INTERFACE_TYPE - && PROTOCOL_NAME (proto)) - { - if (! PROTOCOL_FORWARD_DECL (proto)) - build_protocol_reference (proto); - - if (PROTOCOL_LIST (proto)) - generate_protocol_references (PROTOCOL_LIST (proto)); - } - } -} - /* Generate either '- .cxx_construct' or '- .cxx_destruct' for the current class. */ #ifdef OBJCPLUS @@ -6282,346 +4385,11 @@ objc_generate_cxx_cdtors (void) /* The 'imp_list' variable points at an imp_entry record for the current @implementation. Record the existence of '- .cxx_construct' and/or '- .cxx_destruct' methods therein; it will be included in the - metadata for the class. */ - if (flag_next_runtime) - imp_list->has_cxx_cdtors = (need_ctor || need_dtor); + metadata for the class if the runtime needs it. */ + imp_list->has_cxx_cdtors = (need_ctor || need_dtor); } #endif -/* For each protocol which was referenced either from a @protocol() - expression, or because a class/category implements it (then a - pointer to the protocol is stored in the struct describing the - class/category), we create a statically allocated instance of the - Protocol class. The code is written in such a way as to generate - as few Protocol objects as possible; we generate a unique Protocol - instance for each protocol, and we don't generate a Protocol - instance if the protocol is never referenced (either from a - @protocol() or from a class/category implementation). These - statically allocated objects can be referred to via the static - (that is, private to this module) symbols _OBJC_PROTOCOL_n. - - The statically allocated Protocol objects that we generate here - need to be fixed up at runtime in order to be used: the 'isa' - pointer of the objects need to be set up to point to the 'Protocol' - class, as known at runtime. - - The NeXT runtime fixes up all protocols at program startup time, - before main() is entered. It uses a low-level trick to look up all - those symbols, then loops on them and fixes them up. - - The GNU runtime as well fixes up all protocols before user code - from the module is executed; it requires pointers to those symbols - to be put in the objc_symtab (which is then passed as argument to - the function __objc_exec_class() which the compiler sets up to be - executed automatically when the module is loaded); setup of those - Protocol objects happen in two ways in the GNU runtime: all - Protocol objects referred to by a class or category implementation - are fixed up when the class/category is loaded; all Protocol - objects referred to by a @protocol() expression are added by the - compiler to the list of statically allocated instances to fixup - (the same list holding the statically allocated constant string - objects). Because, as explained above, the compiler generates as - few Protocol objects as possible, some Protocol object might end up - being referenced multiple times when compiled with the GNU runtime, - and end up being fixed up multiple times at runtime initialization. - But that doesn't hurt, it's just a little inefficient. */ - -static void -generate_protocols (void) -{ - tree p, encoding; - tree decl; - tree initlist, protocol_name_expr, refs_decl, refs_expr; - - /* If a protocol was directly referenced, pull in indirect references. */ - for (p = protocol_chain; p; p = TREE_CHAIN (p)) - if (PROTOCOL_FORWARD_DECL (p) && PROTOCOL_LIST (p)) - generate_protocol_references (PROTOCOL_LIST (p)); - - for (p = protocol_chain; p; p = TREE_CHAIN (p)) - { - tree nst_methods = PROTOCOL_NST_METHODS (p); - tree cls_methods = PROTOCOL_CLS_METHODS (p); - - /* If protocol wasn't referenced, don't generate any code. */ - decl = PROTOCOL_FORWARD_DECL (p); - - if (!decl) - continue; - - /* Make sure we link in the Protocol class. */ - add_class_reference (get_identifier (PROTOCOL_OBJECT_CLASS_NAME)); - - while (nst_methods) - { - if (! METHOD_ENCODING (nst_methods)) - { - encoding = encode_method_prototype (nst_methods); - METHOD_ENCODING (nst_methods) = encoding; - } - nst_methods = DECL_CHAIN (nst_methods); - } - - while (cls_methods) - { - if (! METHOD_ENCODING (cls_methods)) - { - encoding = encode_method_prototype (cls_methods); - METHOD_ENCODING (cls_methods) = encoding; - } - - cls_methods = DECL_CHAIN (cls_methods); - } - generate_method_descriptors (p); - - if (PROTOCOL_LIST (p)) - refs_decl = generate_protocol_list (p); - else - refs_decl = 0; - - /* static struct objc_protocol _OBJC_PROTOCOL_<mumble>; */ - protocol_name_expr = add_objc_string (PROTOCOL_NAME (p), class_names); - - if (refs_decl) - refs_expr = convert (build_pointer_type (build_pointer_type - (objc_protocol_template)), - build_unary_op (input_location, - ADDR_EXPR, refs_decl, 0)); - else - refs_expr = build_int_cst (NULL_TREE, 0); - - /* UOBJC_INSTANCE_METHODS_decl/UOBJC_CLASS_METHODS_decl are set - by generate_method_descriptors, which is called above. */ - initlist = build_protocol_initializer (TREE_TYPE (decl), - protocol_name_expr, refs_expr, - UOBJC_INSTANCE_METHODS_decl, - UOBJC_CLASS_METHODS_decl); - finish_var_decl (decl, initlist); - } -} - -static tree -build_protocol_initializer (tree type, tree protocol_name, - tree protocol_list, tree instance_methods, - tree class_methods) -{ - tree expr; - tree cast_type = build_pointer_type - (xref_tag (RECORD_TYPE, - get_identifier (UTAG_CLASS))); - VEC(constructor_elt,gc) *inits = NULL; - - /* Filling the "isa" in with one allows the runtime system to - detect that the version change...should remove before final release. */ - - expr = build_int_cst (cast_type, PROTOCOL_VERSION); - CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); - CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, protocol_name); - CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, protocol_list); - - if (!instance_methods) - CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, build_int_cst (NULL_TREE, 0)); - else - { - expr = convert (objc_method_proto_list_ptr, - build_unary_op (input_location, - ADDR_EXPR, instance_methods, 0)); - CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); - } - - if (!class_methods) - CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, build_int_cst (NULL_TREE, 0)); - else - { - expr = convert (objc_method_proto_list_ptr, - build_unary_op (input_location, - ADDR_EXPR, class_methods, 0)); - CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); - } - - return objc_build_constructor (type, inits); -} - -/* struct _objc_category { - char *category_name; - char *class_name; - struct _objc_method_list *instance_methods; - struct _objc_method_list *class_methods; - struct _objc_protocol_list *protocols; - }; */ - -static void -build_category_template (void) -{ - tree ptype, decls, *chain = NULL; - - objc_category_template = objc_start_struct (get_identifier (UTAG_CATEGORY)); - - /* char *category_name; */ - decls = add_field_decl (string_type_node, "category_name", &chain); - - /* char *class_name; */ - add_field_decl (string_type_node, "class_name", &chain); - - /* struct _objc_method_list *instance_methods; */ - add_field_decl (objc_method_list_ptr, "instance_methods", &chain); - - /* struct _objc_method_list *class_methods; */ - add_field_decl (objc_method_list_ptr, "class_methods", &chain); - - /* struct _objc_protocol **protocol_list; */ - ptype = build_pointer_type (build_pointer_type (objc_protocol_template)); - add_field_decl (ptype, "protocol_list", &chain); - - objc_finish_struct (objc_category_template, decls); -} - -/* struct _objc_selector { - SEL sel_id; - char *sel_type; - }; */ - -static void -build_selector_template (void) -{ - tree decls, *chain = NULL; - - objc_selector_template = objc_start_struct (get_identifier (UTAG_SELECTOR)); - - /* SEL sel_id; */ - decls = add_field_decl (objc_selector_type, "sel_id", &chain); - - /* char *sel_type; */ - add_field_decl (string_type_node, "sel_type", &chain); - - objc_finish_struct (objc_selector_template, decls); -} - -/* struct _objc_class { - struct _objc_class *isa; - struct _objc_class *super_class; - char *name; - long version; - long info; - long instance_size; - struct _objc_ivar_list *ivars; - struct _objc_method_list *methods; - #ifdef __NEXT_RUNTIME__ - struct objc_cache *cache; - #else - struct sarray *dtable; - struct _objc_class *subclass_list; - struct _objc_class *sibling_class; - #endif - struct _objc_protocol_list *protocols; - #ifdef __NEXT_RUNTIME__ - void *sel_id; - #endif - void *gc_object_type; - }; */ - -/* NB: The 'sel_id' and 'gc_object_type' fields are not being used by - the NeXT/Apple runtime; still, the compiler must generate them to - maintain backward binary compatibility (and to allow for future - expansion). */ - -static void -build_class_template (void) -{ - tree ptype, decls, *chain = NULL; - - objc_class_template = objc_start_struct (get_identifier (UTAG_CLASS)); - - /* struct _objc_class *isa; */ - decls = add_field_decl (build_pointer_type (objc_class_template), - "isa", &chain); - - /* struct _objc_class *super_class; */ - add_field_decl (build_pointer_type (objc_class_template), - "super_class", &chain); - - /* char *name; */ - add_field_decl (string_type_node, "name", &chain); - - /* long version; */ - add_field_decl (long_integer_type_node, "version", &chain); - - /* long info; */ - add_field_decl (long_integer_type_node, "info", &chain); - - /* long instance_size; */ - add_field_decl (long_integer_type_node, "instance_size", &chain); - - /* struct _objc_ivar_list *ivars; */ - add_field_decl (objc_ivar_list_ptr,"ivars", &chain); - - /* struct _objc_method_list *methods; */ - add_field_decl (objc_method_list_ptr, "methods", &chain); - - if (flag_next_runtime) - { - /* struct objc_cache *cache; */ - ptype = build_pointer_type (xref_tag (RECORD_TYPE, - get_identifier ("objc_cache"))); - add_field_decl (ptype, "cache", &chain); - } - else - { - /* struct sarray *dtable; */ - ptype = build_pointer_type(xref_tag (RECORD_TYPE, - get_identifier ("sarray"))); - add_field_decl (ptype, "dtable", &chain); - - /* struct objc_class *subclass_list; */ - ptype = build_pointer_type (objc_class_template); - add_field_decl (ptype, "subclass_list", &chain); - - /* struct objc_class *sibling_class; */ - ptype = build_pointer_type (objc_class_template); - add_field_decl (ptype, "sibling_class", &chain); - } - - /* struct _objc_protocol **protocol_list; */ - ptype = build_pointer_type (build_pointer_type - (xref_tag (RECORD_TYPE, - get_identifier (UTAG_PROTOCOL)))); - add_field_decl (ptype, "protocol_list", &chain); - - if (flag_next_runtime) - { - /* void *sel_id; */ - add_field_decl (build_pointer_type (void_type_node), "sel_id", &chain); - } - - /* void *gc_object_type; */ - add_field_decl (build_pointer_type (void_type_node), - "gc_object_type", &chain); - - objc_finish_struct (objc_class_template, decls); -} - -/* Generate appropriate forward declarations for an implementation. */ - -static void -synth_forward_declarations (void) -{ - tree an_id; - - /* static struct objc_class _OBJC_CLASS_<my_name>; */ - UOBJC_CLASS_decl = build_metadata_decl ("_OBJC_CLASS", - objc_class_template); - - /* static struct objc_class _OBJC_METACLASS_<my_name>; */ - UOBJC_METACLASS_decl = build_metadata_decl ("_OBJC_METACLASS", - objc_class_template); - - /* Pre-build the following entities - for speed/convenience. */ - - an_id = get_identifier ("super_class"); - ucls_super_ref = objc_build_component_ref (UOBJC_CLASS_decl, an_id); - uucls_super_ref = objc_build_component_ref (UOBJC_METACLASS_decl, an_id); -} - static void error_with_ivar (const char *message, tree decl) { @@ -6685,322 +4453,6 @@ check_ivars (tree inter, tree imp) } } -/* Set 'objc_super_template' to the data type node for 'struct _objc_super'. - This needs to be done just once per compilation. */ - -/* struct _objc_super { - struct _objc_object *self; - struct _objc_class *super_class; - }; */ - -static void -build_super_template (void) -{ - tree decls, *chain = NULL; - - objc_super_template = objc_start_struct (get_identifier (UTAG_SUPER)); - - /* struct _objc_object *self; */ - decls = add_field_decl (objc_object_type, "self", &chain); - - /* struct _objc_class *super_class; */ - add_field_decl (build_pointer_type (objc_class_template), - "super_class", &chain); - - objc_finish_struct (objc_super_template, decls); -} - -/* struct _objc_ivar { - char *ivar_name; - char *ivar_type; - int ivar_offset; - }; */ - -static tree -build_ivar_template (void) -{ - tree objc_ivar_id, objc_ivar_record; - tree decls, *chain = NULL; - - objc_ivar_id = get_identifier (UTAG_IVAR); - objc_ivar_record = objc_start_struct (objc_ivar_id); - - /* char *ivar_name; */ - decls = add_field_decl (string_type_node, "ivar_name", &chain); - - /* char *ivar_type; */ - add_field_decl (string_type_node, "ivar_type", &chain); - - /* int ivar_offset; */ - add_field_decl (integer_type_node, "ivar_offset", &chain); - - objc_finish_struct (objc_ivar_record, decls); - - return objc_ivar_record; -} - -/* struct { - int ivar_count; - struct objc_ivar ivar_list[ivar_count]; - }; */ - -static tree -build_ivar_list_template (tree list_type, int size) -{ - tree objc_ivar_list_record; - tree array_type, decls, *chain = NULL; - - objc_ivar_list_record = objc_start_struct (NULL_TREE); - - /* int ivar_count; */ - decls = add_field_decl (integer_type_node, "ivar_count", &chain); - - /* struct objc_ivar ivar_list[]; */ - array_type = build_sized_array_type (list_type, size); - add_field_decl (array_type, "ivar_list", &chain); - - objc_finish_struct (objc_ivar_list_record, decls); - - return objc_ivar_list_record; -} - -/* struct { - struct _objc__method_prototype_list *method_next; - int method_count; - struct objc_method method_list[method_count]; - }; */ - -static tree -build_method_list_template (tree list_type, int size) -{ - tree objc_ivar_list_record; - tree array_type, decls, *chain = NULL; - - objc_ivar_list_record = objc_start_struct (NULL_TREE); - - /* struct _objc__method_prototype_list *method_next; */ - decls = add_field_decl (objc_method_proto_list_ptr, "method_next", &chain); - - /* int method_count; */ - add_field_decl (integer_type_node, "method_count", &chain); - - /* struct objc_method method_list[]; */ - array_type = build_sized_array_type (list_type, size); - add_field_decl (array_type, "method_list", &chain); - - objc_finish_struct (objc_ivar_list_record, decls); - - return objc_ivar_list_record; -} - -static tree -build_ivar_list_initializer (tree type, tree field_decl) -{ - VEC(constructor_elt,gc) *inits = NULL; - - do - { - VEC(constructor_elt,gc) *ivar = NULL; - tree id; - - /* Set name. */ - if (DECL_NAME (field_decl)) - CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, - add_objc_string (DECL_NAME (field_decl), - meth_var_names)); - else - /* Unnamed bit-field ivar (yuck). */ - CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, build_int_cst (NULL_TREE, 0)); - - /* Set type. */ - encode_field_decl (field_decl, - obstack_object_size (&util_obstack), - OBJC_ENCODE_DONT_INLINE_DEFS); - - /* Null terminate string. */ - obstack_1grow (&util_obstack, 0); - id = add_objc_string (get_identifier (XOBFINISH (&util_obstack, char *)), - meth_var_types); - CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, id); - obstack_free (&util_obstack, util_firstobj); - - /* Set offset. */ - CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, byte_position (field_decl)); - CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, - objc_build_constructor (type, ivar)); - do - field_decl = DECL_CHAIN (field_decl); - while (field_decl && TREE_CODE (field_decl) != FIELD_DECL); - } - while (field_decl); - - return objc_build_constructor (build_array_type (type, 0), inits); -} - -static tree -generate_ivars_list (tree type, const char *name, int size, tree list) -{ - tree decl; - VEC(constructor_elt,gc) *inits = NULL; - - decl = start_var_decl (type, synth_id_with_class_suffix - (name, objc_implementation_context)); - - CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, build_int_cst (NULL_TREE, size)); - CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, list); - - finish_var_decl (decl, - objc_build_constructor (TREE_TYPE (decl), inits)); - - return decl; -} - -/* Count only the fields occurring in T. */ - -static int -ivar_list_length (tree t) -{ - int count = 0; - - for (; t; t = DECL_CHAIN (t)) - if (TREE_CODE (t) == FIELD_DECL) - ++count; - - return count; -} - -static void -generate_ivar_lists (void) -{ - tree initlist, ivar_list_template, chain; - int size; - - generating_instance_variables = 1; - - if (!objc_ivar_template) - objc_ivar_template = build_ivar_template (); - - /* Only generate class variables for the root of the inheritance - hierarchy since these will be the same for every class. */ - - if (CLASS_SUPER_NAME (implementation_template) == NULL_TREE - && (chain = TYPE_FIELDS (objc_class_template))) - { - size = ivar_list_length (chain); - - ivar_list_template = build_ivar_list_template (objc_ivar_template, size); - initlist = build_ivar_list_initializer (objc_ivar_template, chain); - - UOBJC_CLASS_VARIABLES_decl - = generate_ivars_list (ivar_list_template, "_OBJC_CLASS_VARIABLES", - size, initlist); - } - else - UOBJC_CLASS_VARIABLES_decl = 0; - - chain = CLASS_IVARS (implementation_template); - if (chain) - { - size = ivar_list_length (chain); - ivar_list_template = build_ivar_list_template (objc_ivar_template, size); - initlist = build_ivar_list_initializer (objc_ivar_template, chain); - - UOBJC_INSTANCE_VARIABLES_decl - = generate_ivars_list (ivar_list_template, "_OBJC_INSTANCE_VARIABLES", - size, initlist); - } - else - UOBJC_INSTANCE_VARIABLES_decl = 0; - - generating_instance_variables = 0; -} - -static tree -build_dispatch_table_initializer (tree type, tree entries) -{ - VEC(constructor_elt,gc) *inits = NULL; - - do - { - VEC(constructor_elt,gc) *elems = NULL; - tree expr; - - CONSTRUCTOR_APPEND_ELT (elems, NULL_TREE, - build_selector (METHOD_SEL_NAME (entries))); - - /* Generate the method encoding if we don't have one already. */ - if (! METHOD_ENCODING (entries)) - METHOD_ENCODING (entries) = - encode_method_prototype (entries); - - CONSTRUCTOR_APPEND_ELT (elems, NULL_TREE, - add_objc_string (METHOD_ENCODING (entries), - meth_var_types)); - - expr = convert (ptr_type_node, - build_unary_op (input_location, ADDR_EXPR, - METHOD_DEFINITION (entries), 1)); - CONSTRUCTOR_APPEND_ELT (elems, NULL_TREE, expr); - - CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, - objc_build_constructor (type, elems)); - - entries = DECL_CHAIN (entries); - } - while (entries); - - return objc_build_constructor (build_array_type (type, 0), inits); -} - -/* To accomplish method prototyping without generating all kinds of - inane warnings, the definition of the dispatch table entries were - changed from: - - struct objc_method { SEL _cmd; ...; id (*_imp)(); }; - to: - struct objc_method { SEL _cmd; ...; void *_imp; }; */ - -static tree -build_method_template (void) -{ - tree _SLT_record; - tree decls, *chain = NULL; - - _SLT_record = objc_start_struct (get_identifier (UTAG_METHOD)); - - /* SEL _cmd; */ - decls = add_field_decl (objc_selector_type, "_cmd", &chain); - - /* char *method_types; */ - add_field_decl (string_type_node, "method_types", &chain); - - /* void *_imp; */ - add_field_decl (build_pointer_type (void_type_node), "_imp", &chain); - - objc_finish_struct (_SLT_record, decls); - - return _SLT_record; -} - - -static tree -generate_dispatch_table (tree type, const char *name, int size, tree list) -{ - tree decl; - VEC(constructor_elt,gc) *v = NULL; - - decl = start_var_decl (type, synth_id_with_class_suffix - (name, objc_implementation_context)); - - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (integer_type_node, size)); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, list); - - finish_var_decl (decl, - objc_build_constructor (TREE_TYPE (decl), v)); - - return decl; -} static void mark_referenced_methods (void) @@ -7026,477 +4478,6 @@ mark_referenced_methods (void) } } -static void -generate_dispatch_tables (void) -{ - tree initlist, chain, method_list_template; - int size; - - if (!objc_method_template) - objc_method_template = build_method_template (); - - chain = CLASS_CLS_METHODS (objc_implementation_context); - if (chain) - { - size = list_length (chain); - - method_list_template - = build_method_list_template (objc_method_template, size); - initlist - = build_dispatch_table_initializer (objc_method_template, chain); - - UOBJC_CLASS_METHODS_decl - = generate_dispatch_table (method_list_template, - ((TREE_CODE (objc_implementation_context) - == CLASS_IMPLEMENTATION_TYPE) - ? "_OBJC_CLASS_METHODS" - : "_OBJC_CATEGORY_CLASS_METHODS"), - size, initlist); - } - else - UOBJC_CLASS_METHODS_decl = 0; - - chain = CLASS_NST_METHODS (objc_implementation_context); - if (chain) - { - size = list_length (chain); - - method_list_template - = build_method_list_template (objc_method_template, size); - initlist - = build_dispatch_table_initializer (objc_method_template, chain); - - if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) - UOBJC_INSTANCE_METHODS_decl - = generate_dispatch_table (method_list_template, - "_OBJC_INSTANCE_METHODS", - size, initlist); - else - /* We have a category. */ - UOBJC_INSTANCE_METHODS_decl - = generate_dispatch_table (method_list_template, - "_OBJC_CATEGORY_INSTANCE_METHODS", - size, initlist); - } - else - UOBJC_INSTANCE_METHODS_decl = 0; -} - -static tree -generate_protocol_list (tree i_or_p) -{ - tree array_type, ptype, refs_decl, lproto, e, plist; - int size = 0; - const char *ref_name; - VEC(constructor_elt,gc) *v = NULL; - - switch (TREE_CODE (i_or_p)) - { - case CLASS_INTERFACE_TYPE: - case CATEGORY_INTERFACE_TYPE: - plist = CLASS_PROTOCOL_LIST (i_or_p); - break; - case PROTOCOL_INTERFACE_TYPE: - plist = PROTOCOL_LIST (i_or_p); - break; - default: - gcc_unreachable (); - } - - /* Compute size. */ - for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) - if (TREE_CODE (TREE_VALUE (lproto)) == PROTOCOL_INTERFACE_TYPE - && PROTOCOL_FORWARD_DECL (TREE_VALUE (lproto))) - size++; - - /* Build initializer. */ - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); - e = build_int_cst (build_pointer_type (objc_protocol_template), size); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, e); - - for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) - { - tree pval = TREE_VALUE (lproto); - - if (TREE_CODE (pval) == PROTOCOL_INTERFACE_TYPE - && PROTOCOL_FORWARD_DECL (pval)) - { - e = build_unary_op (input_location, ADDR_EXPR, - PROTOCOL_FORWARD_DECL (pval), 0); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, e); - } - } - - /* static struct objc_protocol *refs[n]; */ - - switch (TREE_CODE (i_or_p)) - { - case PROTOCOL_INTERFACE_TYPE: - ref_name = synth_id_with_class_suffix ("_OBJC_PROTOCOL_REFS", i_or_p); - break; - case CLASS_INTERFACE_TYPE: - ref_name = synth_id_with_class_suffix ("_OBJC_CLASS_PROTOCOLS", i_or_p); - break; - case CATEGORY_INTERFACE_TYPE: - ref_name = synth_id_with_class_suffix ("_OBJC_CATEGORY_PROTOCOLS", i_or_p); - break; - default: - gcc_unreachable (); - } - - ptype = build_pointer_type (objc_protocol_template); - array_type = build_sized_array_type (ptype, size + 3); - refs_decl = start_var_decl (array_type, ref_name); - - finish_var_decl (refs_decl, - objc_build_constructor (TREE_TYPE (refs_decl), v)); - - return refs_decl; -} - -static tree -build_category_initializer (tree type, tree cat_name, tree class_name, - tree instance_methods, tree class_methods, - tree protocol_list) -{ - tree expr; - VEC(constructor_elt,gc) *v = NULL; - - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, cat_name); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, class_name); - - if (!instance_methods) - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); - else - { - expr = convert (objc_method_list_ptr, - build_unary_op (input_location, ADDR_EXPR, - instance_methods, 0)); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); - } - if (!class_methods) - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); - else - { - expr = convert (objc_method_list_ptr, - build_unary_op (input_location, ADDR_EXPR, - class_methods, 0)); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); - } - - /* protocol_list = */ - if (!protocol_list) - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); - else - { - expr = convert (build_pointer_type - (build_pointer_type - (objc_protocol_template)), - build_unary_op (input_location, ADDR_EXPR, - protocol_list, 0)); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); - } - - return objc_build_constructor (type, v); -} - -/* struct _objc_class { - struct objc_class *isa; - struct objc_class *super_class; - char *name; - long version; - long info; - long instance_size; - struct objc_ivar_list *ivars; - struct objc_method_list *methods; - if (flag_next_runtime) - struct objc_cache *cache; - else { - struct sarray *dtable; - struct objc_class *subclass_list; - struct objc_class *sibling_class; - } - struct objc_protocol_list *protocols; - if (flag_next_runtime) - void *sel_id; - void *gc_object_type; - }; */ - -static tree -build_shared_structure_initializer (tree type, tree isa, tree super, - tree name, tree size, int status, - tree dispatch_table, tree ivar_list, - tree protocol_list) -{ - tree expr; - VEC(constructor_elt,gc) *v = NULL; - - /* isa = */ - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, isa); - - /* super_class = */ - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, super); - - /* name = */ - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, default_conversion (name)); - - /* version = */ - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, - build_int_cst (long_integer_type_node, 0)); - - /* info = */ - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, - build_int_cst (long_integer_type_node, status)); - - /* instance_size = */ - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, - convert (long_integer_type_node, size)); - - /* objc_ivar_list = */ - if (!ivar_list) - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); - else - { - expr = convert (objc_ivar_list_ptr, - build_unary_op (input_location, ADDR_EXPR, - ivar_list, 0)); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); - } - - /* objc_method_list = */ - if (!dispatch_table) - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); - else - { - expr = convert (objc_method_list_ptr, - build_unary_op (input_location, ADDR_EXPR, - dispatch_table, 0)); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); - } - - if (flag_next_runtime) - /* method_cache = */ - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); - else - { - /* dtable = */ - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); - - /* subclass_list = */ - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); - - /* sibling_class = */ - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); - } - - /* protocol_list = */ - if (! protocol_list) - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); - else - { - expr = convert (build_pointer_type - (build_pointer_type - (objc_protocol_template)), - build_unary_op (input_location, ADDR_EXPR, - protocol_list, 0)); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); - } - - if (flag_next_runtime) - /* sel_id = NULL */ - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); - - /* gc_object_type = NULL */ - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); - - return objc_build_constructor (type, v); -} - -/* Retrieve category interface CAT_NAME (if any) associated with CLASS. */ - -static inline tree -lookup_category (tree klass, tree cat_name) -{ - tree category = CLASS_CATEGORY_LIST (klass); - - while (category && CLASS_SUPER_NAME (category) != cat_name) - category = CLASS_CATEGORY_LIST (category); - return category; -} - -/* static struct objc_category _OBJC_CATEGORY_<name> = { ... }; */ - -static void -generate_category (struct imp_entry *impent) -{ - 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); - - class_name_expr = add_objc_string (CLASS_NAME (cat), class_names); - - category = lookup_category (implementation_template, - CLASS_SUPER_NAME (cat)); - - if (category && CLASS_PROTOCOL_LIST (category)) - { - generate_protocol_references (CLASS_PROTOCOL_LIST (category)); - protocol_decl = generate_protocol_list (category); - } - else - protocol_decl = 0; - - 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 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 (struct imp_entry *impent) -{ - tree name_expr, super_expr, root_expr; - 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) - { - add_class_reference (my_super_id); - - /* Compute "my_root_id" - this is required for code generation. - the "isa" for all meta class structures points to the root of - the inheritance hierarchy (e.g. "__Object")... */ - my_root_id = my_super_id; - do - { - tree my_root_int = lookup_interface (my_root_id); - - if (my_root_int && CLASS_SUPER_NAME (my_root_int)) - my_root_id = CLASS_SUPER_NAME (my_root_int); - else - break; - } - while (1); - } - else - /* No super class. */ - my_root_id = CLASS_NAME (implementation_template); - - cast_type = build_pointer_type (objc_class_template); - name_expr = add_objc_string (CLASS_NAME (implementation_template), - class_names); - - /* Install class `isa' and `super' pointers at runtime. */ - if (my_super_id) - 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! */ - - root_expr = add_objc_string (my_root_id, class_names); - root_expr = build_c_cast (input_location, cast_type, root_expr); /* cast! */ - - if (CLASS_PROTOCOL_LIST (implementation_template)) - { - generate_protocol_references - (CLASS_PROTOCOL_LIST (implementation_template)); - protocol_decl = generate_protocol_list (implementation_template); - } - else - protocol_decl = 0; - - /* static struct objc_class _OBJC_METACLASS_Foo = { ... }; */ - - initlist - = build_shared_structure_initializer - (TREE_TYPE (UOBJC_METACLASS_decl), - root_expr, super_expr, name_expr, - convert (integer_type_node, TYPE_SIZE_UNIT (objc_class_template)), - 2 /*CLS_META*/, - UOBJC_CLASS_METHODS_decl, - UOBJC_CLASS_VARIABLES_decl, - protocol_decl); - - finish_var_decl (UOBJC_METACLASS_decl, initlist); - - /* static struct objc_class _OBJC_CLASS_Foo={ ... }; */ - - initlist - = build_shared_structure_initializer - (TREE_TYPE (UOBJC_CLASS_decl), - build_unary_op (input_location, ADDR_EXPR, UOBJC_METACLASS_decl, 0), - super_expr, name_expr, - convert (integer_type_node, - TYPE_SIZE_UNIT (CLASS_STATIC_TEMPLATE - (implementation_template))), - 1 /*CLS_FACTORY*/ | cls_flags, - UOBJC_INSTANCE_METHODS_decl, - UOBJC_INSTANCE_VARIABLES_decl, - protocol_decl); - - finish_var_decl (UOBJC_CLASS_decl, initlist); -} - - -static const char * -synth_id_with_class_suffix (const char *preamble, tree ctxt) -{ - static char string[BUFSIZE]; - - switch (TREE_CODE (ctxt)) - { - case CLASS_IMPLEMENTATION_TYPE: - case CLASS_INTERFACE_TYPE: - sprintf (string, "%s_%s", preamble, - IDENTIFIER_POINTER (CLASS_NAME (ctxt))); - break; - case CATEGORY_IMPLEMENTATION_TYPE: - case CATEGORY_INTERFACE_TYPE: - { - /* We have a category. */ - const char *const class_name - = IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context)); - const char *const class_super_name - = IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context)); - sprintf (string, "%s_%s_%s", preamble, class_name, class_super_name); - break; - } - case PROTOCOL_INTERFACE_TYPE: - { - const char *protocol_name = IDENTIFIER_POINTER (PROTOCOL_NAME (ctxt)); - sprintf (string, "%s_%s", preamble, protocol_name); - break; - } - default: - gcc_unreachable (); - } - - return string; -} - /* If type is empty or only type qualifiers are present, add default type of id (otherwise grokdeclarator will default to int). */ static inline tree @@ -7666,9 +4647,6 @@ build_method_decl (enum tree_code code, tree ret_type, tree selector, return method_decl; } -#define METHOD_DEF 0 -#define METHOD_REF 1 - /* This routine processes objective-c method attributes. */ static void @@ -7803,21 +4781,13 @@ objc_method_decl (enum tree_code opcode) the method call are done together. If METH is null, user-defined arguments (i.e., beyond self and _cmd) shall be represented by `...'. */ -static tree +tree get_arg_type_list (tree meth, int context, int superflag) { tree arglist, akey; - /* Receiver type. */ - if (flag_next_runtime && superflag) - arglist = build_tree_list (NULL_TREE, objc_super_type); - else if (context == METHOD_DEF && TREE_CODE (meth) == INSTANCE_METHOD_DECL) - arglist = build_tree_list (NULL_TREE, objc_instance_type); - else - arglist = build_tree_list (NULL_TREE, objc_object_type); - - /* Selector type - will eventually change to `int'. */ - chainon (arglist, build_tree_list (NULL_TREE, objc_selector_type)); + /* Receiver & _cmd types are runtime-dependent. */ + arglist = (*runtime.get_arg_type_list_base) (meth, context, superflag); /* No actual method prototype given -- assume that remaining arguments are `...'. */ @@ -7934,7 +4904,7 @@ check_duplicates (hash hsh, int methods, int is_class) static tree receiver_is_class_object (tree receiver, int self, int super) { - tree chain, exp, arg; + tree exp, arg; /* The receiver is 'self' or 'super' in the context of a class method. */ if (objc_method_context @@ -7944,16 +4914,10 @@ receiver_is_class_object (tree receiver, int self, int super) ? CLASS_SUPER_NAME (implementation_template) : CLASS_NAME (implementation_template)); - if (flag_next_runtime) - { - /* The receiver is a variable created by - build_class_reference_decl. */ - if (TREE_CODE (receiver) == VAR_DECL && IS_CLASS (TREE_TYPE (receiver))) - /* Look up the identifier. */ - for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain)) - if (TREE_PURPOSE (chain) == receiver) - return TREE_VALUE (chain); - } + /* The runtime might encapsulate things its own way. */ + exp = (*runtime.receiver_is_class_object) (receiver); + if (exp) + return exp; /* The receiver is a function call that returns an id. Check if it is a call to objc_getClass, if so, pick up the class name. */ @@ -7966,7 +4930,7 @@ receiver_is_class_object (tree receiver, int self, int super) prototypes for objc_get_class(). Thankfully, they seem to share the same function type. */ && TREE_TYPE (exp) == TREE_TYPE (objc_get_class_decl) - && !strcmp (IDENTIFIER_POINTER (DECL_NAME (exp)), TAG_GETCLASS) + && !strcmp (IDENTIFIER_POINTER (DECL_NAME (exp)), runtime.tag_getclass) /* We have a call to objc_get_class/objc_getClass! */ && (arg = CALL_EXPR_ARG (receiver, 0))) { @@ -7979,7 +4943,7 @@ receiver_is_class_object (tree receiver, int self, int super) } return 0; } - + /* If we are currently building a message expr, this holds the identifier of the selector of the message. This is used when printing warnings about argument mismatches. */ @@ -8108,7 +5072,7 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params, tree *deprecated_method_prototype) { tree method_prototype = NULL_TREE, rprotos = NULL_TREE, rtype; - tree selector, retval, class_tree; + tree retval, class_tree; int self, super, have_cast; /* We have used the receiver, so mark it as read. */ @@ -8321,7 +5285,7 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params, In practice this makes sense since casting an object to 'id' is often used precisely to turn off warnings associated with the object being of a particular class. */ - if (TREE_DEPRECATED (method_prototype) && rtype != NULL_TREE) + if (TREE_DEPRECATED (method_prototype) && rtype != NULL_TREE) { if (deprecated_method_prototype) *deprecated_method_prototype = method_prototype; @@ -8330,213 +5294,42 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params, } } - /* Save the selector name for printing error messages. */ current_objc_message_selector = sel_name; - /* Build the parameters list for looking up the method. - These are the object itself and the selector. */ - - if (flag_typed_selectors) - selector = build_typed_selector_reference (input_location, - sel_name, method_prototype); - else - selector = build_selector_reference (input_location, sel_name); - - retval = build_objc_method_call (input_location, super, method_prototype, - receiver, - selector, method_params); + /* Build the method call. + TODO: Get the location from somewhere that will work for delayed + expansion. */ + + retval = (*runtime.build_objc_method_call) (input_location, method_prototype, + receiver, rtype, sel_name, + method_params, super); current_objc_message_selector = 0; return retval; } -/* Build a tree expression to send OBJECT the operation SELECTOR, - looking up the method on object LOOKUP_OBJECT (often same as OBJECT), - assuming the method has prototype METHOD_PROTOTYPE. - (That is an INSTANCE_METHOD_DECL or CLASS_METHOD_DECL.) - LOC is the location of the expression to build. - Use METHOD_PARAMS as list of args to pass to the method. - If SUPER_FLAG is nonzero, we look up the superclass's method. */ - -static tree -build_objc_method_call (location_t loc, int super_flag, tree method_prototype, - tree lookup_object, tree selector, - tree method_params) -{ - tree sender = (super_flag ? umsg_super_decl : - (!flag_next_runtime || flag_nil_receivers - ? (flag_objc_direct_dispatch - ? umsg_fast_decl - : umsg_decl) - : umsg_nonnil_decl)); - tree rcv_p = (super_flag ? objc_super_type : objc_object_type); - VEC(tree, gc) *parms = NULL; - unsigned nparm = (method_params ? list_length (method_params) : 0); - - /* If a prototype for the method to be called exists, then cast - the sender's return type and arguments to match that of the method. - Otherwise, leave sender as is. */ - tree ret_type - = (method_prototype - ? TREE_VALUE (TREE_TYPE (method_prototype)) - : objc_object_type); - - tree method_param_types = - get_arg_type_list (method_prototype, METHOD_REF, super_flag); - tree ftype = build_function_type (ret_type, method_param_types); - tree sender_cast; - tree method, t; - - if (method_prototype && METHOD_TYPE_ATTRIBUTES (method_prototype)) - ftype = build_type_attribute_variant (ftype, - METHOD_TYPE_ATTRIBUTES - (method_prototype)); - - sender_cast = build_pointer_type (ftype); - - lookup_object = build_c_cast (loc, rcv_p, lookup_object); - - /* Use SAVE_EXPR to avoid evaluating the receiver twice. */ - lookup_object = save_expr (lookup_object); - - /* Param list + 2 slots for object and selector. */ - parms = VEC_alloc (tree, gc, nparm + 2); - - if (flag_next_runtime) - { - /* If we are returning a struct in memory, and the address - of that memory location is passed as a hidden first - argument, then change which messenger entry point this - expr will call. NB: Note that sender_cast remains - unchanged (it already has a struct return type). */ - if (!targetm.calls.struct_value_rtx (0, 0) - && (TREE_CODE (ret_type) == RECORD_TYPE - || TREE_CODE (ret_type) == UNION_TYPE) - && targetm.calls.return_in_memory (ret_type, 0)) - sender = (super_flag ? umsg_super_stret_decl : - flag_nil_receivers ? umsg_stret_decl : umsg_nonnil_stret_decl); - - method = build_fold_addr_expr_loc (input_location, sender); - /* Pass the object to the method. */ - VEC_quick_push (tree, parms, lookup_object); - } - else - { - /* This is the portable (GNU) way. */ - /* First, call the lookup function to get a pointer to the method, - then cast the pointer, then call it with the method arguments. */ - VEC(tree, gc) *tv = VEC_alloc (tree, gc, 2); - VEC_quick_push (tree, tv, lookup_object); - VEC_quick_push (tree, tv, selector); - method = build_function_call_vec (loc, sender, tv, NULL); - VEC_free (tree, gc, tv); - - /* Pass the appropriate object to the method. */ - VEC_quick_push (tree, parms, (super_flag ? self_decl : lookup_object)); - } - /* Pass the selector to the method. */ - VEC_quick_push (tree, parms, selector); - /* Now append the remainder of the parms. */ - if (nparm) - for (; method_params; method_params = TREE_CHAIN (method_params)) - VEC_quick_push (tree, parms, TREE_VALUE (method_params)); - - /* Build an obj_type_ref, with the correct cast for the method call. */ - t = build3 (OBJ_TYPE_REF, sender_cast, method, - lookup_object, size_zero_node); - t = build_function_call_vec (loc, t, parms, NULL);\ - VEC_free (tree, gc, parms); - return t; -} - -static void -build_protocol_reference (tree p) -{ - tree decl; - const char *proto_name; - - /* static struct _objc_protocol _OBJC_PROTOCOL_<mumble>; */ - - proto_name = synth_id_with_class_suffix ("_OBJC_PROTOCOL", p); - decl = start_var_decl (objc_protocol_template, proto_name); - - PROTOCOL_FORWARD_DECL (p) = decl; -} +/* This routine creates a static variable used to implement @protocol(MyProtocol) + expression. This variable will be initialized to global protocol_t meta-data + pointer. */ /* This function is called by the parser when (and only when) a @protocol() expression is found, in order to compile it. */ tree objc_build_protocol_expr (tree protoname) { - tree expr; tree p = lookup_protocol (protoname, /* warn if deprecated */ true, /* definition_required */ false); if (!p) { - error ("cannot find protocol declaration for %qE", - protoname); + error ("cannot find protocol declaration for %qE", protoname); return error_mark_node; } - if (!PROTOCOL_FORWARD_DECL (p)) - build_protocol_reference (p); - - expr = build_unary_op (input_location, - ADDR_EXPR, PROTOCOL_FORWARD_DECL (p), 0); - - /* ??? Ideally we'd build the reference with objc_protocol_type directly, - if we have it, rather than converting it here. */ - expr = convert (objc_protocol_type, expr); - - /* The @protocol() expression is being compiled into a pointer to a - statically allocated instance of the Protocol class. To become - usable at runtime, the 'isa' pointer of the instance need to be - fixed up at runtime by the runtime library, to point to the - actual 'Protocol' class. */ - - /* For the GNU runtime, put the static Protocol instance in the list - of statically allocated instances, so that we make sure that its - 'isa' pointer is fixed up at runtime by the GNU runtime library - to point to the Protocol class (at runtime, when loading the - module, the GNU runtime library loops on the statically allocated - instances (as found in the defs field in objc_symtab) and fixups - all the 'isa' pointers of those objects). */ - if (! flag_next_runtime) - { - /* This type is a struct containing the fields of a Protocol - object. (Cfr. objc_protocol_type instead is the type of a pointer - to such a struct). */ - tree protocol_struct_type = xref_tag - (RECORD_TYPE, get_identifier (PROTOCOL_OBJECT_CLASS_NAME)); - tree *chain; - - /* Look for the list of Protocol statically allocated instances - to fixup at runtime. Create a new list to hold Protocol - statically allocated instances, if the list is not found. At - present there is only another list, holding NSConstantString - static instances to be fixed up at runtime. */ - for (chain = &objc_static_instances; - *chain && TREE_VALUE (*chain) != protocol_struct_type; - chain = &TREE_CHAIN (*chain)); - if (!*chain) - { - *chain = tree_cons (NULL_TREE, protocol_struct_type, NULL_TREE); - add_objc_string (OBJC_TYPE_NAME (protocol_struct_type), - class_names); - } - - /* Add this statically allocated instance to the Protocol list. */ - TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, - PROTOCOL_FORWARD_DECL (p), - TREE_PURPOSE (*chain)); - } - - - return expr; + return (*runtime.get_protocol_reference) (input_location, p); } /* This function is called by the parser when a @selector() expression @@ -8587,11 +5380,9 @@ objc_build_selector_expr (location_t loc, tree selnamelist) } } - - if (flag_typed_selectors) - return build_typed_selector_reference (loc, selname, 0); - else - return build_selector_reference (loc, selname); + /* The runtimes do this differently, most particularly, GNU has typed + selectors, whilst NeXT does not. */ + return (*runtime.build_selector_reference) (loc, selname, NULL_TREE); } /* This is used to implement @encode(). See gcc/doc/objc.texi, @@ -8616,6 +5407,7 @@ objc_build_encode_expr (tree type) static tree build_ivar_reference (tree id) { + tree base; if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL) { /* Historically, a class method that produced objects (factory @@ -8632,11 +5424,10 @@ build_ivar_reference (tree id) self_decl = convert (objc_instance_type, self_decl); /* cast */ } - return objc_build_component_ref (build_indirect_ref (input_location, - self_decl, RO_ARROW), - id); + base = build_indirect_ref (input_location, self_decl, RO_ARROW); + return (*runtime.build_ivar_reference) (input_location, base, id); } - + /* Compute a hash value for a given method SEL_NAME. */ static size_t @@ -8660,6 +5451,8 @@ hash_init (void) cls_name_hash_list = ggc_alloc_cleared_vec_hash (SIZEHASHTABLE); als_name_hash_list = ggc_alloc_cleared_vec_hash (SIZEHASHTABLE); + ivar_offset_hash_list = ggc_alloc_cleared_vec_hash (SIZEHASHTABLE); + /* Initialize the hash table used to hold the constant string objects. */ string_htab = htab_create_ggc (31, string_hash, string_eq, NULL); @@ -9200,16 +5993,6 @@ add_instance_variable (tree klass, objc_ivar_visibility_kind visibility, return klass; } - - -static tree -is_ivar (tree decl_chain, tree ident) -{ - for ( ; decl_chain; decl_chain = DECL_CHAIN (decl_chain)) - if (DECL_NAME (decl_chain) == ident) - return decl_chain; - return NULL_TREE; -} /* True if the ivar is private and we are not in its implementation. */ @@ -9763,9 +6546,6 @@ start_class (enum tree_code code, tree class_name, tree super_name, CLASS_PROTOCOL_LIST (klass) = lookup_and_install_protocols (protocol_list, /* definition_required */ true); - /* Determine if 'deprecated', the only attribute we recognize - for classes, was used. Ignore all other attributes for now, - but store them in the klass. */ if (attributes) { tree attribute; @@ -9773,9 +6553,14 @@ start_class (enum tree_code code, tree class_name, tree super_name, { tree name = TREE_PURPOSE (attribute); + /* We handle the 'deprecated' and (undocumented) 'objc_exception' + attributes. */ if (is_attribute_p ("deprecated", name)) TREE_DEPRECATED (klass) = 1; + else if (is_attribute_p ("objc_exception", name)) + CLASS_HAS_EXCEPTION_ATTR (klass) = 1; else + /* Warn about and ignore all others for now, but store them. */ warning (OPT_Wattributes, "%qE attribute directive ignored", name); } TYPE_ATTRIBUTES (klass) = attributes; @@ -9874,25 +6659,32 @@ continue_class (tree klass) #ifdef OBJCPLUS push_lang_context (lang_name_c); #endif - build_private_template (implementation_template); - uprivate_record = CLASS_STATIC_TEMPLATE (implementation_template); - objc_instance_type = build_pointer_type (uprivate_record); - - imp_entry = ggc_alloc_imp_entry (); + build_private_template (implementation_template); + uprivate_record = CLASS_STATIC_TEMPLATE (implementation_template); + objc_instance_type = build_pointer_type (uprivate_record); - imp_entry->next = imp_list; - imp_entry->imp_context = klass; - imp_entry->imp_template = implementation_template; + imp_entry = ggc_alloc_imp_entry (); - synth_forward_declarations (); - imp_entry->class_decl = UOBJC_CLASS_decl; - imp_entry->meta_decl = UOBJC_METACLASS_decl; + imp_entry->next = imp_list; + imp_entry->imp_context = klass; + imp_entry->imp_template = implementation_template; + ucls_super_ref = uucls_super_ref = NULL; + if (TREE_CODE (klass) == CLASS_IMPLEMENTATION_TYPE) + { + imp_entry->class_decl = (*runtime.class_decl) (klass); + imp_entry->meta_decl = (*runtime.metaclass_decl) (klass); + } + else + { + imp_entry->class_decl = (*runtime.category_decl) (klass); + imp_entry->meta_decl = NULL; + } imp_entry->has_cxx_cdtors = 0; - /* Append to front and increment count. */ - imp_list = imp_entry; - if (TREE_CODE (klass) == CLASS_IMPLEMENTATION_TYPE) - imp_count++; + /* Append to front and increment count. */ + imp_list = imp_entry; + if (TREE_CODE (klass) == CLASS_IMPLEMENTATION_TYPE) + imp_count++; else cat_count++; #ifdef OBJCPLUS @@ -9936,9 +6728,12 @@ objc_build_property_setter_name (tree ident) /* This routine prepares the declarations of the property accessor helper functions (objc_getProperty(), etc) that are used when - @synthesize is used. */ + @synthesize is used. + + runtime-specific routines are built in the respective runtime + initialize functions. */ static void -build_objc_property_accessor_helpers (void) +build_common_objc_property_accessor_helpers (void) { tree type; @@ -9974,52 +6769,6 @@ build_objc_property_accessor_helpers (void) type, 0, NOT_BUILT_IN, NULL, NULL_TREE); TREE_NOTHROW (objc_setProperty_decl) = 0; - - /* This is the type of all of the following functions - (objc_copyStruct(), objc_getPropertyStruct() and - objc_setPropertyStruct()). */ - type = build_function_type_list (void_type_node, - ptr_type_node, - const_ptr_type_node, - ptrdiff_type_node, - boolean_type_node, - boolean_type_node, - NULL_TREE); - - if (flag_next_runtime) - { - /* Declare the following function: - void - objc_copyStruct (void *destination, const void *source, - ptrdiff_t size, BOOL is_atomic, BOOL has_strong); */ - objc_copyStruct_decl = add_builtin_function ("objc_copyStruct", - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - TREE_NOTHROW (objc_copyStruct_decl) = 0; - objc_getPropertyStruct_decl = NULL_TREE; - objc_setPropertyStruct_decl = NULL_TREE; - } - else - { - objc_copyStruct_decl = NULL_TREE; - - /* Declare the following function: - void - objc_getPropertyStruct (void *destination, const void *source, - ptrdiff_t size, BOOL is_atomic, BOOL has_strong); */ - objc_getPropertyStruct_decl = add_builtin_function ("objc_getPropertyStruct", - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - TREE_NOTHROW (objc_getPropertyStruct_decl) = 0; - /* Declare the following function: - void - objc_setPropertyStruct (void *destination, const void *source, - ptrdiff_t size, BOOL is_atomic, BOOL has_strong); */ - objc_setPropertyStruct_decl = add_builtin_function ("objc_setPropertyStruct", - type, 0, NOT_BUILT_IN, - NULL, NULL_TREE); - TREE_NOTHROW (objc_setPropertyStruct_decl) = 0; - } } /* This looks up an ivar in a class (including superclasses). */ @@ -10169,7 +6918,7 @@ objc_synthesize_getter (tree klass, tree class_methods ATTRIBUTE_UNUSED, tree pr else is_atomic = boolean_true_node; - if (flag_next_runtime) + if (objc_copyStruct_decl) function_decl = objc_copyStruct_decl; else function_decl = objc_getPropertyStruct_decl; @@ -10369,7 +7118,7 @@ objc_synthesize_setter (tree klass, tree class_methods ATTRIBUTE_UNUSED, tree pr else is_atomic = boolean_true_node; - if (flag_next_runtime) + if (objc_copyStruct_decl) function_decl = objc_copyStruct_decl; else function_decl = objc_setPropertyStruct_decl; @@ -10756,6 +7505,10 @@ objc_gen_property_data (tree klass, tree class_methods) /* @dynamic property - nothing to check or synthesize. */ if (PROPERTY_DYNAMIC (x)) continue; + /* Add any property that is declared in the interface, but undeclared in the + implementation to thie implementation. These are the 'dynamic' properties. + + objc_v2_merge_dynamic_property ();*/ /* @synthesize property - need to synthesize the accessors. */ if (PROPERTY_IVAR_NAME (x)) @@ -10781,7 +7534,7 @@ finish_class (tree klass) { case CLASS_IMPLEMENTATION_TYPE: { - /* All code generation is done in finish_objc. */ + /* All metadata generation is done in runtime.generate_metadata(). */ /* Generate what needed for property; setters, getters, etc. */ objc_gen_property_data (implementation_template, implementation_template); @@ -11018,6 +7771,7 @@ objc_declare_protocols (tree names, tree attributes) add_protocol (protocol); PROTOCOL_DEFINED (protocol) = 0; PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE; +/* PROTOCOL_V2_FORWARD_DECL (protocol) = NULL_TREE;*/ if (attributes) { @@ -11070,6 +7824,7 @@ start_protocol (enum tree_code code, tree name, tree list, tree attributes) add_protocol (protocol); PROTOCOL_DEFINED (protocol) = 1; PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE; +/* PROTOCOL_V2_FORWARD_DECL (protocol) = NULL_TREE;*/ check_protocol_recursively (protocol, list); } @@ -11096,666 +7851,6 @@ start_protocol (enum tree_code code, tree name, tree list, tree attributes) return protocol; } - -/* "Encode" a data type into a string, which grows in util_obstack. - - The format is described in gcc/doc/objc.texi, section 'Type - encoding'. - - Most of the encode_xxx functions have a 'type' argument, which is - the type to encode, and an integer 'curtype' argument, which is the - index in the encoding string of the beginning of the encoding of - the current type, and allows you to find what characters have - already been written for the current type (they are the ones in the - current encoding string starting from 'curtype'). - - For example, if we are encoding a method which returns 'int' and - takes a 'char **' argument, then when we get to the point of - encoding the 'char **' argument, the encoded string already - contains 'i12@0:4' (assuming a pointer size of 4 bytes). So, - 'curtype' will be set to 7 when starting to encode 'char **'. - During the whole of the encoding of 'char **', 'curtype' will be - fixed at 7, so the routine encoding the second pointer can find out - that it's actually encoding a pointer to a pointer by looking - backwards at what has already been encoded for the current type, - and seeing there is a "^" (meaning a pointer) in there. -*/ - - -/* Encode type qualifiers encodes one of the "PQ" Objective-C - keywords, ie 'in', 'out', 'inout', 'bycopy', 'byref', 'oneway'. - 'const', instead, is encoded directly as part of the type. - */ - -static void -encode_type_qualifiers (tree declspecs) -{ - tree spec; - - for (spec = declspecs; spec; spec = TREE_CHAIN (spec)) - { - /* FIXME: Shouldn't we use token->keyword here ? */ - if (ridpointers[(int) RID_IN] == TREE_VALUE (spec)) - obstack_1grow (&util_obstack, 'n'); - else if (ridpointers[(int) RID_INOUT] == TREE_VALUE (spec)) - obstack_1grow (&util_obstack, 'N'); - else if (ridpointers[(int) RID_OUT] == TREE_VALUE (spec)) - obstack_1grow (&util_obstack, 'o'); - else if (ridpointers[(int) RID_BYCOPY] == TREE_VALUE (spec)) - obstack_1grow (&util_obstack, 'O'); - else if (ridpointers[(int) RID_BYREF] == TREE_VALUE (spec)) - obstack_1grow (&util_obstack, 'R'); - else if (ridpointers[(int) RID_ONEWAY] == TREE_VALUE (spec)) - obstack_1grow (&util_obstack, 'V'); - else - gcc_unreachable (); - } -} - -/* Determine if a pointee is marked read-only. Only used by the NeXT - runtime to be compatible with gcc-3.3. */ - -static bool -pointee_is_readonly (tree pointee) -{ - while (POINTER_TYPE_P (pointee)) - pointee = TREE_TYPE (pointee); - - return TYPE_READONLY (pointee); -} - -/* Encode a pointer type. */ - -static void -encode_pointer (tree type, int curtype, int format) -{ - tree pointer_to = TREE_TYPE (type); - - if (flag_next_runtime) - { - /* This code is used to be compatible with gcc-3.3. */ - /* For historical/compatibility reasons, the read-only qualifier - of the pointee gets emitted _before_ the '^'. The read-only - qualifier of the pointer itself gets ignored, _unless_ we are - looking at a typedef! Also, do not emit the 'r' for anything - but the outermost type! */ - if (!generating_instance_variables - && (obstack_object_size (&util_obstack) - curtype <= 1) - && (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL - ? TYPE_READONLY (type) - : pointee_is_readonly (pointer_to))) - obstack_1grow (&util_obstack, 'r'); - } - - if (TREE_CODE (pointer_to) == RECORD_TYPE) - { - if (OBJC_TYPE_NAME (pointer_to) - && TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE) - { - const char *name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (pointer_to)); - - if (strcmp (name, TAG_OBJECT) == 0) /* '@' */ - { - obstack_1grow (&util_obstack, '@'); - return; - } - else if (TYPE_HAS_OBJC_INFO (pointer_to) - && TYPE_OBJC_INTERFACE (pointer_to)) - { - if (generating_instance_variables) - { - obstack_1grow (&util_obstack, '@'); - obstack_1grow (&util_obstack, '"'); - obstack_grow (&util_obstack, name, strlen (name)); - obstack_1grow (&util_obstack, '"'); - return; - } - else - { - obstack_1grow (&util_obstack, '@'); - return; - } - } - else if (strcmp (name, TAG_CLASS) == 0) /* '#' */ - { - obstack_1grow (&util_obstack, '#'); - return; - } - else if (strcmp (name, TAG_SELECTOR) == 0) /* ':' */ - { - obstack_1grow (&util_obstack, ':'); - return; - } - } - } - else if (TREE_CODE (pointer_to) == INTEGER_TYPE - && TYPE_MODE (pointer_to) == QImode) - { - tree pname = TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE - ? OBJC_TYPE_NAME (pointer_to) - : DECL_NAME (OBJC_TYPE_NAME (pointer_to)); - - /* (BOOL *) are an exception and are encoded as ^c, while all - other pointers to char are encoded as *. */ - if (strcmp (IDENTIFIER_POINTER (pname), "BOOL")) - { - if (!flag_next_runtime) - { - /* The NeXT runtime adds the 'r' before getting here. */ - - /* It appears that "r*" means "const char *" rather than - "char *const". "char *const" is encoded as "*", - which is identical to "char *", so the "const" is - unfortunately lost. */ - if (TYPE_READONLY (pointer_to)) - obstack_1grow (&util_obstack, 'r'); - } - - obstack_1grow (&util_obstack, '*'); - return; - } - } - - /* We have a normal pointer type that does not get special treatment. */ - obstack_1grow (&util_obstack, '^'); - encode_type (pointer_to, curtype, format); -} - -static void -encode_array (tree type, int curtype, int format) -{ - tree an_int_cst = TYPE_SIZE (type); - tree array_of = TREE_TYPE (type); - char buffer[40]; - - if (an_int_cst == NULL) - { - /* We are trying to encode an incomplete array. An incomplete - array is forbidden as part of an instance variable. */ - if (generating_instance_variables) - { - /* TODO: Detect this error earlier. */ - error ("instance variable has unknown size"); - return; - } - - /* So the only case in which an incomplete array could occur is - if we are encoding the arguments or return value of a method. - In that case, an incomplete array argument or return value - (eg, -(void)display: (char[])string) is treated like a - pointer because that is how the compiler does the function - call. A special, more complicated case, is when the - incomplete array is the last member of a struct (eg, if we - are encoding "struct { unsigned long int a;double b[];}"), - which is again part of a method argument/return value. In - that case, we really need to communicate to the runtime that - there is an incomplete array (not a pointer!) there. So, we - detect that special case and encode it as a zero-length - array. - - Try to detect that we are part of a struct. We do this by - searching for '=' in the type encoding for the current type. - NB: This hack assumes that you can't use '=' as part of a C - identifier. - */ - { - char *enc = obstack_base (&util_obstack) + curtype; - if (memchr (enc, '=', - obstack_object_size (&util_obstack) - curtype) == NULL) - { - /* We are not inside a struct. Encode the array as a - pointer. */ - encode_pointer (type, curtype, format); - return; - } - } - - /* Else, we are in a struct, and we encode it as a zero-length - array. */ - sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)0); - } - else if (TREE_INT_CST_LOW (TYPE_SIZE (array_of)) == 0) - sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)0); - else - sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, - TREE_INT_CST_LOW (an_int_cst) - / TREE_INT_CST_LOW (TYPE_SIZE (array_of))); - - obstack_grow (&util_obstack, buffer, strlen (buffer)); - encode_type (array_of, curtype, format); - obstack_1grow (&util_obstack, ']'); - return; -} - -/* Encode a vector. The vector type is a GCC extension to C. */ -static void -encode_vector (tree type, int curtype, int format) -{ - tree vector_of = TREE_TYPE (type); - char buffer[40]; - - /* Vectors are like simple fixed-size arrays. */ - - /* Output ![xx,yy,<code>] where xx is the vector_size, yy is the - alignment of the vector, and <code> is the base type. Eg, int - __attribute__ ((vector_size (16))) gets encoded as ![16,32,i] - assuming that the alignment is 32 bytes. We include size and - alignment in bytes so that the runtime does not have to have any - knowledge of the actual types. - */ - sprintf (buffer, "![" HOST_WIDE_INT_PRINT_DEC ",%d", - /* We want to compute the equivalent of sizeof (<vector>). - Code inspired by c_sizeof_or_alignof_type. */ - ((TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type)) - / (TYPE_PRECISION (char_type_node) / BITS_PER_UNIT))), - /* We want to compute the equivalent of __alignof__ - (<vector>). Code inspired by - c_sizeof_or_alignof_type. */ - TYPE_ALIGN_UNIT (type)); - obstack_grow (&util_obstack, buffer, strlen (buffer)); - encode_type (vector_of, curtype, format); - obstack_1grow (&util_obstack, ']'); - return; -} - -static void -encode_aggregate_fields (tree type, bool pointed_to, int curtype, int format) -{ - tree field = TYPE_FIELDS (type); - - for (; field; field = DECL_CHAIN (field)) - { -#ifdef OBJCPLUS - /* C++ static members, and things that are not field at all, - should not appear in the encoding. */ - if (TREE_CODE (field) != FIELD_DECL || TREE_STATIC (field)) - continue; -#endif - - /* Recursively encode fields of embedded base classes. */ - if (DECL_ARTIFICIAL (field) && !DECL_NAME (field) - && TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE) - { - encode_aggregate_fields (TREE_TYPE (field), - pointed_to, curtype, format); - continue; - } - - if (generating_instance_variables && !pointed_to) - { - tree fname = DECL_NAME (field); - - obstack_1grow (&util_obstack, '"'); - - if (fname && TREE_CODE (fname) == IDENTIFIER_NODE) - obstack_grow (&util_obstack, - IDENTIFIER_POINTER (fname), - strlen (IDENTIFIER_POINTER (fname))); - - obstack_1grow (&util_obstack, '"'); - } - - encode_field_decl (field, curtype, format); - } -} - -static void -encode_aggregate_within (tree type, int curtype, int format, int left, - int right) -{ - tree name; - /* NB: aggregates that are pointed to have slightly different encoding - rules in that you never encode the names of instance variables. */ - int ob_size = obstack_object_size (&util_obstack); - bool inline_contents = false; - bool pointed_to = false; - - if (flag_next_runtime) - { - if (ob_size > 0 && *(obstack_next_free (&util_obstack) - 1) == '^') - pointed_to = true; - - if ((format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables) - && (!pointed_to || ob_size - curtype == 1 - || (ob_size - curtype == 2 - && *(obstack_next_free (&util_obstack) - 2) == 'r'))) - inline_contents = true; - } - else - { - /* c0 and c1 are the last two characters in the encoding of the - current type; if the last two characters were '^' or '^r', - then we are encoding an aggregate that is "pointed to". The - comment above applies: in that case we should avoid encoding - the names of instance variables. - */ - char c1 = ob_size > 1 ? *(obstack_next_free (&util_obstack) - 2) : 0; - char c0 = ob_size > 0 ? *(obstack_next_free (&util_obstack) - 1) : 0; - - if (c0 == '^' || (c1 == '^' && c0 == 'r')) - pointed_to = true; - - if (format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables) - { - if (!pointed_to) - inline_contents = true; - else - { - /* Note that the check (ob_size - curtype < 2) prevents - infinite recursion when encoding a structure which is - a linked list (eg, struct node { struct node *next; - }). Each time we follow a pointer, we add one - character to ob_size, and curtype is fixed, so after - at most two pointers we stop inlining contents and - break the loop. - - The other case where we don't inline is "^r", which - is a pointer to a constant struct. - */ - if ((ob_size - curtype <= 2) && !(c0 == 'r')) - inline_contents = true; - } - } - } - - /* Traverse struct aliases; it is important to get the - original struct and its tag name (if any). */ - type = TYPE_MAIN_VARIANT (type); - name = OBJC_TYPE_NAME (type); - /* Open parenth/bracket. */ - obstack_1grow (&util_obstack, left); - - /* Encode the struct/union tag name, or '?' if a tag was - not provided. Typedef aliases do not qualify. */ -#ifdef OBJCPLUS - /* For compatibility with the NeXT runtime, ObjC++ encodes template - args as a composite struct tag name. */ - if (name && TREE_CODE (name) == IDENTIFIER_NODE - /* Did this struct have a tag? */ - && !TYPE_WAS_ANONYMOUS (type)) - obstack_grow (&util_obstack, - decl_as_string (type, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME), - strlen (decl_as_string (type, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME))); -#else - if (name && TREE_CODE (name) == IDENTIFIER_NODE) - obstack_grow (&util_obstack, - IDENTIFIER_POINTER (name), - strlen (IDENTIFIER_POINTER (name))); -#endif - else - obstack_1grow (&util_obstack, '?'); - - /* Encode the types (and possibly names) of the inner fields, - if required. */ - if (inline_contents) - { - obstack_1grow (&util_obstack, '='); - encode_aggregate_fields (type, pointed_to, curtype, format); - } - /* Close parenth/bracket. */ - obstack_1grow (&util_obstack, right); -} - -/* Encode a bitfield NeXT-style (i.e., without a bit offset or the underlying - field type. */ - -static void -encode_next_bitfield (int width) -{ - char buffer[40]; - sprintf (buffer, "b%d", width); - obstack_grow (&util_obstack, buffer, strlen (buffer)); -} - - -/* Encodes 'type', ignoring type qualifiers (which you should encode - beforehand if needed) with the exception of 'const', which is - encoded by encode_type. See above for the explanation of - 'curtype'. 'format' can be OBJC_ENCODE_INLINE_DEFS or - OBJC_ENCODE_DONT_INLINE_DEFS. -*/ -static void -encode_type (tree type, int curtype, int format) -{ - enum tree_code code = TREE_CODE (type); - - /* Ignore type qualifiers other than 'const' when encoding a - type. */ - - if (type == error_mark_node) - return; - - if (!flag_next_runtime) - { - if (TYPE_READONLY (type)) - obstack_1grow (&util_obstack, 'r'); - } - - switch (code) - { - case ENUMERAL_TYPE: - if (flag_next_runtime) - { - /* Kludge for backwards-compatibility with gcc-3.3: enums - are always encoded as 'i' no matter what type they - actually are (!). */ - obstack_1grow (&util_obstack, 'i'); - break; - } - /* Else, they are encoded exactly like the integer type that is - used by the compiler to store them. */ - case INTEGER_TYPE: - { - char c; - switch (GET_MODE_BITSIZE (TYPE_MODE (type))) - { - case 8: c = TYPE_UNSIGNED (type) ? 'C' : 'c'; break; - case 16: c = TYPE_UNSIGNED (type) ? 'S' : 's'; break; - case 32: - { - tree int_type = type; - if (flag_next_runtime) - { - /* Another legacy kludge for compatiblity with - gcc-3.3: 32-bit longs are encoded as 'l' or 'L', - but not always. For typedefs, we need to use 'i' - or 'I' instead if encoding a struct field, or a - pointer! */ - int_type = ((!generating_instance_variables - && (obstack_object_size (&util_obstack) - == (unsigned) curtype)) - ? TYPE_MAIN_VARIANT (type) - : type); - } - if (int_type == long_unsigned_type_node - || int_type == long_integer_type_node) - c = TYPE_UNSIGNED (type) ? 'L' : 'l'; - else - c = TYPE_UNSIGNED (type) ? 'I' : 'i'; - } - break; - case 64: c = TYPE_UNSIGNED (type) ? 'Q' : 'q'; break; - case 128: c = TYPE_UNSIGNED (type) ? 'T' : 't'; break; - default: gcc_unreachable (); - } - obstack_1grow (&util_obstack, c); - break; - } - case REAL_TYPE: - { - char c; - /* Floating point types. */ - switch (GET_MODE_BITSIZE (TYPE_MODE (type))) - { - case 32: c = 'f'; break; - case 64: c = 'd'; break; - case 96: - case 128: c = 'D'; break; - default: gcc_unreachable (); - } - obstack_1grow (&util_obstack, c); - break; - } - case VOID_TYPE: - obstack_1grow (&util_obstack, 'v'); - break; - - case BOOLEAN_TYPE: - obstack_1grow (&util_obstack, 'B'); - break; - - case ARRAY_TYPE: - encode_array (type, curtype, format); - break; - - case POINTER_TYPE: -#ifdef OBJCPLUS - case REFERENCE_TYPE: -#endif - encode_pointer (type, curtype, format); - break; - - case RECORD_TYPE: - encode_aggregate_within (type, curtype, format, '{', '}'); - break; - - case UNION_TYPE: - encode_aggregate_within (type, curtype, format, '(', ')'); - break; - - case FUNCTION_TYPE: /* '?' means an unknown type. */ - obstack_1grow (&util_obstack, '?'); - break; - - case COMPLEX_TYPE: - /* A complex is encoded as 'j' followed by the inner type (eg, - "_Complex int" is encoded as 'ji'). */ - obstack_1grow (&util_obstack, 'j'); - encode_type (TREE_TYPE (type), curtype, format); - break; - - case VECTOR_TYPE: - encode_vector (type, curtype, format); - break; - - default: - warning (0, "unknown type %s found during Objective-C encoding", - gen_type_name (type)); - obstack_1grow (&util_obstack, '?'); - break; - } - - if (flag_next_runtime) - { - /* Super-kludge. Some ObjC qualifier and type combinations need - to be rearranged for compatibility with gcc-3.3. */ - if (code == POINTER_TYPE && obstack_object_size (&util_obstack) >= 3) - { - char *enc = obstack_base (&util_obstack) + curtype; - - /* Rewrite "in const" from "nr" to "rn". */ - if (curtype >= 1 && !strncmp (enc - 1, "nr", 2)) - strncpy (enc - 1, "rn", 2); - } - } -} - -static void -encode_gnu_bitfield (int position, tree type, int size) -{ - enum tree_code code = TREE_CODE (type); - char buffer[40]; - char charType = '?'; - - /* This code is only executed for the GNU runtime, so we can ignore - the NeXT runtime kludge of always encoding enums as 'i' no matter - what integers they actually are. */ - if (code == INTEGER_TYPE || code == ENUMERAL_TYPE) - { - if (integer_zerop (TYPE_MIN_VALUE (type))) - /* Unsigned integer types. */ - { - switch (TYPE_MODE (type)) - { - case QImode: - charType = 'C'; break; - case HImode: - charType = 'S'; break; - case SImode: - { - if (type == long_unsigned_type_node) - charType = 'L'; - else - charType = 'I'; - break; - } - case DImode: - charType = 'Q'; break; - default: - gcc_unreachable (); - } - } - else - /* Signed integer types. */ - { - switch (TYPE_MODE (type)) - { - case QImode: - charType = 'c'; break; - case HImode: - charType = 's'; break; - case SImode: - { - if (type == long_integer_type_node) - charType = 'l'; - else - charType = 'i'; - break; - } - case DImode: - charType = 'q'; break; - default: - gcc_unreachable (); - } - } - } - else - { - /* Do not do any encoding, produce an error and keep going. */ - error ("trying to encode non-integer type as a bitfield"); - return; - } - - sprintf (buffer, "b%d%c%d", position, charType, size); - obstack_grow (&util_obstack, buffer, strlen (buffer)); -} - -static void -encode_field_decl (tree field_decl, int curtype, int format) -{ -#ifdef OBJCPLUS - /* C++ static members, and things that are not fields at all, - should not appear in the encoding. */ - if (TREE_CODE (field_decl) != FIELD_DECL || TREE_STATIC (field_decl)) - return; -#endif - - /* Generate the bitfield typing information, if needed. Note the difference - between GNU and NeXT runtimes. */ - if (DECL_BIT_FIELD_TYPE (field_decl)) - { - int size = tree_low_cst (DECL_SIZE (field_decl), 1); - - if (flag_next_runtime) - encode_next_bitfield (size); - else - encode_gnu_bitfield (int_bit_position (field_decl), - DECL_BIT_FIELD_TYPE (field_decl), size); - } - else - encode_type (TREE_TYPE (field_decl), curtype, format); -} - /* Decay array and function parameters into pointers. */ static tree @@ -11774,7 +7869,7 @@ static GTY(()) tree objc_parmlist = NULL_TREE; /* Append PARM to a list of formal parameters of a method, making a necessary array-to-pointer adjustment along the way. */ -static void +void objc_push_parm (tree parm) { tree type; @@ -11809,19 +7904,18 @@ objc_push_parm (tree parm) objc_push_parm(). */ #ifdef OBJCPLUS -static tree +tree objc_get_parm_info (int have_ellipsis ATTRIBUTE_UNUSED) -#else -static struct c_arg_info * -objc_get_parm_info (int have_ellipsis) -#endif { -#ifdef OBJCPLUS tree parm_info = objc_parmlist; objc_parmlist = NULL_TREE; return parm_info; +} #else +struct c_arg_info * +objc_get_parm_info (int have_ellipsis) +{ tree parm_info = objc_parmlist; struct c_arg_info *arg_info; /* The C front-end requires an elaborate song and dance at @@ -11841,8 +7935,8 @@ objc_get_parm_info (int have_ellipsis) pop_scope (); objc_parmlist = NULL_TREE; return arg_info; -#endif } +#endif /* Synthesize the formal parameters 'id self' and 'SEL _cmd' needed for ObjC method definitions. In the case of instance methods, we can be more @@ -12043,6 +8137,39 @@ match_proto_with_proto (tree proto1, tree proto2, int strict) return (!type1 && !type2); } +/* This routine returns true if TYPE is a valid objc object type, + suitable for messaging; false otherwise. If 'accept_class' is + 'true', then a Class object is considered valid for messaging and + 'true' is returned if 'type' refers to a Class. If 'accept_class' + is 'false', then a Class object is not considered valid for + messaging and 'false' is returned in that case. */ + +static bool +objc_type_valid_for_messaging (tree type, bool accept_classes) +{ + if (!POINTER_TYPE_P (type)) + return false; + + /* Remove the pointer indirection; don't remove more than one + otherwise we'd consider "NSObject **" a valid type for messaging, + which it isn't. */ + type = TREE_TYPE (type); + + if (TREE_CODE (type) != RECORD_TYPE) + return false; + + if (objc_is_object_id (type)) + return true; + + if (objc_is_class_id (type)) + return accept_classes; + + if (TYPE_HAS_OBJC_INFO (type)) + return true; + + return false; +} + /* Fold an OBJ_TYPE_REF expression for ObjC method dispatches, where this occurs. ObjC method dispatches are _not_ like C++ virtual member function dispatches, and we account for the difference here. */ @@ -12070,7 +8197,7 @@ objc_fold_obj_type_ref (tree ref ATTRIBUTE_UNUSED, #endif } -static void +void objc_start_function (tree name, tree type, tree attrs, #ifdef OBJCPLUS tree params @@ -12255,8 +8382,8 @@ get_super_receiver (void) { if (objc_method_context) { - tree super_expr, super_expr_list; - + tree super_expr, super_expr_list, class_expr; + bool inst_meth; if (!UOBJC_SUPER_decl) { UOBJC_SUPER_decl = build_decl (input_location, @@ -12279,80 +8406,42 @@ get_super_receiver (void) super_expr_list = super_expr; /* Set class to begin searching. */ - super_expr = objc_build_component_ref (UOBJC_SUPER_decl, - get_identifier ("super_class")); + /* Get the ident for the superclass class field & build a ref to it. + ??? maybe we should just name the field the same for all runtimes. */ + super_expr = (*runtime.super_superclassfield_ident) (); + super_expr = objc_build_component_ref (UOBJC_SUPER_decl, super_expr); - if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) - { - /* [_cls, __cls]Super are "pre-built" in - synth_forward_declarations. */ - - super_expr = build_modify_expr (input_location, super_expr, - NULL_TREE, NOP_EXPR, - input_location, - ((TREE_CODE (objc_method_context) - == INSTANCE_METHOD_DECL) - ? ucls_super_ref - : uucls_super_ref), - NULL_TREE); - } + gcc_assert (imp_list->imp_context == objc_implementation_context + && imp_list->imp_template == implementation_template); + inst_meth = (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL); + if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) + class_expr = (*runtime.get_class_super_ref) (input_location, + imp_list, inst_meth); else /* We have a category. */ { - tree super_name = CLASS_SUPER_NAME (implementation_template); + tree super_name = CLASS_SUPER_NAME (imp_list->imp_template); tree super_class; - /* Barf if super used in a category of Object. */ + /* Barf if super used in a category of a root object. */ if (!super_name) { error ("no super class declared in interface for %qE", - CLASS_NAME (implementation_template)); + CLASS_NAME (imp_list->imp_template)); return error_mark_node; } - if (flag_next_runtime && !flag_zero_link) - { - super_class = objc_get_class_reference (super_name); - if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL) - /* If we are in a class method, we must retrieve the - _metaclass_ for the current class, pointed at by - the class's "isa" pointer. The following assumes that - "isa" is the first ivar in a class (which it must be). */ - super_class - = build_indirect_ref - (input_location, - build_c_cast (input_location, - build_pointer_type (objc_class_type), - super_class), RO_UNARY_STAR); - } - else - { - add_class_reference (super_name); - super_class = (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL - ? objc_get_class_decl : objc_get_meta_class_decl); - assemble_external (super_class); - super_class - = build_function_call - (input_location, - super_class, - build_tree_list - (NULL_TREE, - my_build_string_pointer - (IDENTIFIER_LENGTH (super_name) + 1, - IDENTIFIER_POINTER (super_name)))); - } - - super_expr - = build_modify_expr (input_location, super_expr, NULL_TREE, - NOP_EXPR, - input_location, - build_c_cast (input_location, - TREE_TYPE (super_expr), - super_class), - NULL_TREE); + super_class = (*runtime.get_category_super_ref) (input_location, + imp_list, inst_meth); + class_expr = build_c_cast (input_location, + TREE_TYPE (super_expr), super_class); } + super_expr = build_modify_expr (input_location, super_expr, NULL_TREE, + NOP_EXPR, + input_location, class_expr, NULL_TREE); + super_expr_list = build_compound_expr (input_location, super_expr_list, super_expr); @@ -12581,7 +8670,7 @@ gen_method_decl (tree method) supplied file FP. Used to implement the -gen-decls option (which prints out an @interface declaration of all classes compiled in this run); potentially useful for debugging the compiler too. */ -static void +void dump_interface (FILE *fp, tree chain) { /* FIXME: A heap overflow here whenever a method (or ivar) @@ -12856,313 +8945,6 @@ objc_printable_name (tree decl, int v) return IDENTIFIER_POINTER (DECL_NAME (decl)); } -static void -init_objc (void) -{ - gcc_obstack_init (&util_obstack); - util_firstobj = (char *) obstack_finish (&util_obstack); - - errbuf = XNEWVEC (char, 1024 * 10); - hash_init (); - synth_module_prologue (); -} - -static void -finish_objc (void) -{ - struct imp_entry *impent; - tree chain; - /* The internally generated initializers appear to have missing braces. - Don't warn about this. */ - int save_warn_missing_braces = warn_missing_braces; - warn_missing_braces = 0; - - /* A missing @end may not be detected by the parser. */ - if (objc_implementation_context) - { - warning (0, "%<@end%> missing in implementation context"); - finish_class (objc_implementation_context); - objc_ivar_chain = NULL_TREE; - objc_implementation_context = NULL_TREE; - } - - /* Process the static instances here because initialization of objc_symtab - depends on them. */ - if (objc_static_instances) - generate_static_references (); - - /* 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; - - /* Dump the @interface of each class as we compile it, if the - -gen-decls option is in use. TODO: Dump the classes in the - order they were found, rather than in reverse order as we - are doing now. */ - if (flag_gen_declaration) - { - dump_interface (gen_declaration_file, objc_implementation_context); - } - - if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) - { - /* all of the following reference the string pool... */ - generate_ivar_lists (); - generate_dispatch_tables (); - generate_shared_structures (impent); - } - else - { - generate_dispatch_tables (); - 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) - build_next_selector_translation_table (); - else - build_gnu_selector_translation_table (); - - if (protocol_chain) - generate_protocols (); - - 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) - { - build_module_descriptor (); - - if (!flag_next_runtime) - build_module_initializer_routine (); - } - - /* Dump the class references. This forces the appropriate classes - to be linked into the executable image, preserving unix archive - semantics. This can be removed when we move to a more dynamically - linked environment. */ - - for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain)) - { - handle_class_ref (chain); - if (TREE_PURPOSE (chain)) - generate_classref_translation_entry (chain); - } - - for (impent = imp_list; impent; impent = impent->next) - handle_impent (impent); - - if (warn_selector) - { - int slot; - hash hsh; - - /* Run through the selector hash tables and print a warning for any - selector which has multiple methods. */ - - for (slot = 0; slot < SIZEHASHTABLE; slot++) - { - for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next) - check_duplicates (hsh, 0, 1); - for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next) - check_duplicates (hsh, 0, 0); - } - } - - warn_missing_braces = save_warn_missing_braces; -} - -/* Subroutines of finish_objc. */ - -static void -generate_classref_translation_entry (tree chain) -{ - tree expr, decl, type; - - decl = TREE_PURPOSE (chain); - type = TREE_TYPE (decl); - - expr = add_objc_string (TREE_VALUE (chain), class_names); - expr = convert (type, expr); /* cast! */ - - /* 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; -} - -static void -handle_class_ref (tree chain) -{ - const char *name = IDENTIFIER_POINTER (TREE_VALUE (chain)); - char *string = (char *) alloca (strlen (name) + 30); - tree decl; - tree exp; - - sprintf (string, "%sobjc_class_name_%s", - (flag_next_runtime ? "." : "__"), name); - -#ifdef ASM_DECLARE_UNRESOLVED_REFERENCE - if (flag_next_runtime) - { - ASM_DECLARE_UNRESOLVED_REFERENCE (asm_out_file, string); - return; - } -#endif - - /* 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), TREE_TYPE (integer_zero_node)); - DECL_EXTERNAL (decl) = 1; - TREE_PUBLIC (decl) = 1; - pushdecl (decl); - finish_var_decl (decl, 0); - - /* Make a decl for the address. */ - sprintf (string, "%sobjc_class_ref_%s", - (flag_next_runtime ? "." : "__"), 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; - TREE_USED (decl) = 1; - DECL_READ_P (decl) = 1; - DECL_ARTIFICIAL (decl) = 1; - DECL_INITIAL (decl) = error_mark_node; - - /* We must force the reference. */ - DECL_PRESERVE_P (decl) = 1; - - pushdecl (decl); - finish_var_decl (decl, exp); -} - -static void -handle_impent (struct imp_entry *impent) -{ - char *string; - - objc_implementation_context = impent->imp_context; - implementation_template = impent->imp_template; - - switch (TREE_CODE (impent->imp_context)) - { - case CLASS_IMPLEMENTATION_TYPE: - { - const char *const class_name = - IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)); - - string = (char *) alloca (strlen (class_name) + 30); - - sprintf (string, "%sobjc_class_name_%s", - (flag_next_runtime ? "." : "__"), class_name); - break; - } - case CATEGORY_IMPLEMENTATION_TYPE: - { - const char *const class_name = - IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)); - const char *const class_super_name = - IDENTIFIER_POINTER (CLASS_SUPER_NAME (impent->imp_context)); - - string = (char *) alloca (strlen (class_name) - + strlen (class_super_name) + 30); - - /* Do the same for categories. Even though no references to - these symbols are generated automatically by the compiler, - it gives you a handle to pull them into an archive by - hand. */ - sprintf (string, "*%sobjc_category_name_%s_%s", - (flag_next_runtime ? "." : "__"), class_name, class_super_name); - break; - } - default: - return; - } - -#ifdef ASM_DECLARE_CLASS_REFERENCE - if (flag_next_runtime) - { - ASM_DECLARE_CLASS_REFERENCE (asm_out_file, string); - return; - } - else -#endif - { - tree decl, init; - - 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) = NULL_TREE; - DECL_ARTIFICIAL (decl) = 1; - 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) ; - } -} - -/* The Fix-and-Continue functionality available in Mac OS X 10.3 and - later requires that ObjC translation units participating in F&C be - specially marked. The following routine accomplishes this. */ - -/* static int _OBJC_IMAGE_INFO[2] = { 0, 1 }; */ - -static void -generate_objc_image_info (void) -{ - tree decl; - int flags - = ((flag_replace_objc_classes && imp_count ? 1 : 0) - | (flag_objc_gc ? 2 : 0)); - VEC(constructor_elt,gc) *v = NULL; - tree array_type; - - if (!flags) - return; /* No need for an image_info entry. */ - - array_type = build_sized_array_type (integer_type_node, 2); - - decl = start_var_decl (array_type, "_OBJC_IMAGE_INFO"); - - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (integer_type_node, flags)); - /* If we need this (determined above) it is because the runtime wants to - refer to it in a manner hidden from the compiler. So we must force the - output. */ - DECL_PRESERVE_P (decl) = 1; - finish_var_decl (decl, objc_build_constructor (TREE_TYPE (decl), v)); -} - /* Routine is called to issue diagnostic when reference to a private ivar is made and no other variable with same name is found in current scope. */ @@ -13347,39 +9129,7 @@ objc_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) #endif } -/* This routine returns true if TYPE is a valid objc object type, - suitable for messaging; false otherwise. If 'accept_class' is - 'true', then a Class object is considered valid for messaging and - 'true' is returned if 'type' refers to a Class. If 'accept_class' - is 'false', then a Class object is not considered valid for - messaging and 'false' is returned in that case. */ - -static bool -objc_type_valid_for_messaging (tree type, bool accept_classes) -{ - if (!POINTER_TYPE_P (type)) - return false; - - /* Remove the pointer indirection; don't remove more than one - otherwise we'd consider "NSObject **" a valid type for messaging, - which it isn't. */ - type = TREE_TYPE (type); - - if (TREE_CODE (type) != RECORD_TYPE) - return false; - - if (objc_is_object_id (type)) - return true; - - if (objc_is_class_id (type)) - return accept_classes; - - if (TYPE_HAS_OBJC_INFO (type)) - return true; - - return false; -} - +/* --- FAST ENUMERATION --- */ /* Begin code generation for fast enumeration (foreach) ... */ /* Defines @@ -13923,6 +9673,7 @@ objc_finish_foreach_loop (location_t location, tree object_expression, tree coll /* Done by c-parser.c */ } +/* --- SUPPORT FOR FORMAT ARG CHECKING --- */ /* Return true if we have an NxString object pointer. */ bool @@ -13947,4 +9698,722 @@ objc_check_format_arg (tree ARG_UNUSED (format_arg), { } +/* --- Encode --- */ +/* "Encode" a data type into a string, which grows in util_obstack. + + The format is described in gcc/doc/objc.texi, section 'Type + encoding'. + + Most of the encode_xxx functions have a 'type' argument, which is + the type to encode, and an integer 'curtype' argument, which is the + index in the encoding string of the beginning of the encoding of + the current type, and allows you to find what characters have + already been written for the current type (they are the ones in the + current encoding string starting from 'curtype'). + + For example, if we are encoding a method which returns 'int' and + takes a 'char **' argument, then when we get to the point of + encoding the 'char **' argument, the encoded string already + contains 'i12@0:4' (assuming a pointer size of 4 bytes). So, + 'curtype' will be set to 7 when starting to encode 'char **'. + During the whole of the encoding of 'char **', 'curtype' will be + fixed at 7, so the routine encoding the second pointer can find out + that it's actually encoding a pointer to a pointer by looking + backwards at what has already been encoded for the current type, + and seeing there is a "^" (meaning a pointer) in there. +*/ + + +/* Encode type qualifiers encodes one of the "PQ" Objective-C + keywords, ie 'in', 'out', 'inout', 'bycopy', 'byref', 'oneway'. + 'const', instead, is encoded directly as part of the type. + */ + +static void +encode_type_qualifiers (tree declspecs) +{ + tree spec; + + for (spec = declspecs; spec; spec = TREE_CHAIN (spec)) + { + /* FIXME: Shouldn't we use token->keyword here ? */ + if (ridpointers[(int) RID_IN] == TREE_VALUE (spec)) + obstack_1grow (&util_obstack, 'n'); + else if (ridpointers[(int) RID_INOUT] == TREE_VALUE (spec)) + obstack_1grow (&util_obstack, 'N'); + else if (ridpointers[(int) RID_OUT] == TREE_VALUE (spec)) + obstack_1grow (&util_obstack, 'o'); + else if (ridpointers[(int) RID_BYCOPY] == TREE_VALUE (spec)) + obstack_1grow (&util_obstack, 'O'); + else if (ridpointers[(int) RID_BYREF] == TREE_VALUE (spec)) + obstack_1grow (&util_obstack, 'R'); + else if (ridpointers[(int) RID_ONEWAY] == TREE_VALUE (spec)) + obstack_1grow (&util_obstack, 'V'); + else + gcc_unreachable (); + } +} + +/* Determine if a pointee is marked read-only. Only used by the NeXT + runtime to be compatible with gcc-3.3. */ + +static bool +pointee_is_readonly (tree pointee) +{ + while (POINTER_TYPE_P (pointee)) + pointee = TREE_TYPE (pointee); + + return TYPE_READONLY (pointee); +} + +/* Encode a pointer type. */ + +static void +encode_pointer (tree type, int curtype, int format) +{ + tree pointer_to = TREE_TYPE (type); + + if (flag_next_runtime) + { + /* This code is used to be compatible with gcc-3.3. */ + /* For historical/compatibility reasons, the read-only qualifier + of the pointee gets emitted _before_ the '^'. The read-only + qualifier of the pointer itself gets ignored, _unless_ we are + looking at a typedef! Also, do not emit the 'r' for anything + but the outermost type! */ + if (!generating_instance_variables + && (obstack_object_size (&util_obstack) - curtype <= 1) + && (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + ? TYPE_READONLY (type) + : pointee_is_readonly (pointer_to))) + obstack_1grow (&util_obstack, 'r'); + } + + if (TREE_CODE (pointer_to) == RECORD_TYPE) + { + if (OBJC_TYPE_NAME (pointer_to) + && TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE) + { + const char *name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (pointer_to)); + + if (strcmp (name, TAG_OBJECT) == 0) /* '@' */ + { + obstack_1grow (&util_obstack, '@'); + return; + } + else if (TYPE_HAS_OBJC_INFO (pointer_to) + && TYPE_OBJC_INTERFACE (pointer_to)) + { + if (generating_instance_variables) + { + obstack_1grow (&util_obstack, '@'); + obstack_1grow (&util_obstack, '"'); + obstack_grow (&util_obstack, name, strlen (name)); + obstack_1grow (&util_obstack, '"'); + return; + } + else + { + obstack_1grow (&util_obstack, '@'); + return; + } + } + else if (strcmp (name, TAG_CLASS) == 0) /* '#' */ + { + obstack_1grow (&util_obstack, '#'); + return; + } + else if (strcmp (name, TAG_SELECTOR) == 0) /* ':' */ + { + obstack_1grow (&util_obstack, ':'); + return; + } + } + } + else if (TREE_CODE (pointer_to) == INTEGER_TYPE + && TYPE_MODE (pointer_to) == QImode) + { + tree pname = TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE + ? OBJC_TYPE_NAME (pointer_to) + : DECL_NAME (OBJC_TYPE_NAME (pointer_to)); + + /* (BOOL *) are an exception and are encoded as ^c, while all + other pointers to char are encoded as *. */ + if (strcmp (IDENTIFIER_POINTER (pname), "BOOL")) + { + if (!flag_next_runtime) + { + /* The NeXT runtime adds the 'r' before getting here. */ + + /* It appears that "r*" means "const char *" rather than + "char *const". "char *const" is encoded as "*", + which is identical to "char *", so the "const" is + unfortunately lost. */ + if (TYPE_READONLY (pointer_to)) + obstack_1grow (&util_obstack, 'r'); + } + + obstack_1grow (&util_obstack, '*'); + return; + } + } + + /* We have a normal pointer type that does not get special treatment. */ + obstack_1grow (&util_obstack, '^'); + encode_type (pointer_to, curtype, format); +} + +static void +encode_array (tree type, int curtype, int format) +{ + tree an_int_cst = TYPE_SIZE (type); + tree array_of = TREE_TYPE (type); + char buffer[40]; + + if (an_int_cst == NULL) + { + /* We are trying to encode an incomplete array. An incomplete + array is forbidden as part of an instance variable. */ + if (generating_instance_variables) + { + /* TODO: Detect this error earlier. */ + error ("instance variable has unknown size"); + return; + } + + /* So the only case in which an incomplete array could occur is + if we are encoding the arguments or return value of a method. + In that case, an incomplete array argument or return value + (eg, -(void)display: (char[])string) is treated like a + pointer because that is how the compiler does the function + call. A special, more complicated case, is when the + incomplete array is the last member of a struct (eg, if we + are encoding "struct { unsigned long int a;double b[];}"), + which is again part of a method argument/return value. In + that case, we really need to communicate to the runtime that + there is an incomplete array (not a pointer!) there. So, we + detect that special case and encode it as a zero-length + array. + + Try to detect that we are part of a struct. We do this by + searching for '=' in the type encoding for the current type. + NB: This hack assumes that you can't use '=' as part of a C + identifier. + */ + { + char *enc = obstack_base (&util_obstack) + curtype; + if (memchr (enc, '=', + obstack_object_size (&util_obstack) - curtype) == NULL) + { + /* We are not inside a struct. Encode the array as a + pointer. */ + encode_pointer (type, curtype, format); + return; + } + } + + /* Else, we are in a struct, and we encode it as a zero-length + array. */ + sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)0); + } + else if (TREE_INT_CST_LOW (TYPE_SIZE (array_of)) == 0) + sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)0); + else + sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, + TREE_INT_CST_LOW (an_int_cst) + / TREE_INT_CST_LOW (TYPE_SIZE (array_of))); + + obstack_grow (&util_obstack, buffer, strlen (buffer)); + encode_type (array_of, curtype, format); + obstack_1grow (&util_obstack, ']'); + return; +} + +/* Encode a vector. The vector type is a GCC extension to C. */ +static void +encode_vector (tree type, int curtype, int format) +{ + tree vector_of = TREE_TYPE (type); + char buffer[40]; + + /* Vectors are like simple fixed-size arrays. */ + + /* Output ![xx,yy,<code>] where xx is the vector_size, yy is the + alignment of the vector, and <code> is the base type. Eg, int + __attribute__ ((vector_size (16))) gets encoded as ![16,32,i] + assuming that the alignment is 32 bytes. We include size and + alignment in bytes so that the runtime does not have to have any + knowledge of the actual types. + */ + sprintf (buffer, "![" HOST_WIDE_INT_PRINT_DEC ",%d", + /* We want to compute the equivalent of sizeof (<vector>). + Code inspired by c_sizeof_or_alignof_type. */ + ((TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type)) + / (TYPE_PRECISION (char_type_node) / BITS_PER_UNIT))), + /* We want to compute the equivalent of __alignof__ + (<vector>). Code inspired by + c_sizeof_or_alignof_type. */ + TYPE_ALIGN_UNIT (type)); + obstack_grow (&util_obstack, buffer, strlen (buffer)); + encode_type (vector_of, curtype, format); + obstack_1grow (&util_obstack, ']'); + return; +} + +static void +encode_aggregate_fields (tree type, bool pointed_to, int curtype, int format) +{ + tree field = TYPE_FIELDS (type); + + for (; field; field = DECL_CHAIN (field)) + { +#ifdef OBJCPLUS + /* C++ static members, and things that are not field at all, + should not appear in the encoding. */ + if (TREE_CODE (field) != FIELD_DECL || TREE_STATIC (field)) + continue; +#endif + + /* Recursively encode fields of embedded base classes. */ + if (DECL_ARTIFICIAL (field) && !DECL_NAME (field) + && TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE) + { + encode_aggregate_fields (TREE_TYPE (field), + pointed_to, curtype, format); + continue; + } + + if (generating_instance_variables && !pointed_to) + { + tree fname = DECL_NAME (field); + + obstack_1grow (&util_obstack, '"'); + + if (fname && TREE_CODE (fname) == IDENTIFIER_NODE) + obstack_grow (&util_obstack, + IDENTIFIER_POINTER (fname), + strlen (IDENTIFIER_POINTER (fname))); + + obstack_1grow (&util_obstack, '"'); + } + + encode_field_decl (field, curtype, format); + } +} + +static void +encode_aggregate_within (tree type, int curtype, int format, int left, + int right) +{ + tree name; + /* NB: aggregates that are pointed to have slightly different encoding + rules in that you never encode the names of instance variables. */ + int ob_size = obstack_object_size (&util_obstack); + bool inline_contents = false; + bool pointed_to = false; + + if (flag_next_runtime) + { + if (ob_size > 0 && *(obstack_next_free (&util_obstack) - 1) == '^') + pointed_to = true; + + if ((format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables) + && (!pointed_to || ob_size - curtype == 1 + || (ob_size - curtype == 2 + && *(obstack_next_free (&util_obstack) - 2) == 'r'))) + inline_contents = true; + } + else + { + /* c0 and c1 are the last two characters in the encoding of the + current type; if the last two characters were '^' or '^r', + then we are encoding an aggregate that is "pointed to". The + comment above applies: in that case we should avoid encoding + the names of instance variables. + */ + char c1 = ob_size > 1 ? *(obstack_next_free (&util_obstack) - 2) : 0; + char c0 = ob_size > 0 ? *(obstack_next_free (&util_obstack) - 1) : 0; + + if (c0 == '^' || (c1 == '^' && c0 == 'r')) + pointed_to = true; + + if (format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables) + { + if (!pointed_to) + inline_contents = true; + else + { + /* Note that the check (ob_size - curtype < 2) prevents + infinite recursion when encoding a structure which is + a linked list (eg, struct node { struct node *next; + }). Each time we follow a pointer, we add one + character to ob_size, and curtype is fixed, so after + at most two pointers we stop inlining contents and + break the loop. + + The other case where we don't inline is "^r", which + is a pointer to a constant struct. + */ + if ((ob_size - curtype <= 2) && !(c0 == 'r')) + inline_contents = true; + } + } + } + + /* Traverse struct aliases; it is important to get the + original struct and its tag name (if any). */ + type = TYPE_MAIN_VARIANT (type); + name = OBJC_TYPE_NAME (type); + /* Open parenth/bracket. */ + obstack_1grow (&util_obstack, left); + + /* Encode the struct/union tag name, or '?' if a tag was + not provided. Typedef aliases do not qualify. */ +#ifdef OBJCPLUS + /* For compatibility with the NeXT runtime, ObjC++ encodes template + args as a composite struct tag name. */ + if (name && TREE_CODE (name) == IDENTIFIER_NODE + /* Did this struct have a tag? */ + && !TYPE_WAS_ANONYMOUS (type)) + obstack_grow (&util_obstack, + decl_as_string (type, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME), + strlen (decl_as_string (type, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME))); +#else + if (name && TREE_CODE (name) == IDENTIFIER_NODE) + obstack_grow (&util_obstack, + IDENTIFIER_POINTER (name), + strlen (IDENTIFIER_POINTER (name))); +#endif + else + obstack_1grow (&util_obstack, '?'); + + /* Encode the types (and possibly names) of the inner fields, + if required. */ + if (inline_contents) + { + obstack_1grow (&util_obstack, '='); + encode_aggregate_fields (type, pointed_to, curtype, format); + } + /* Close parenth/bracket. */ + obstack_1grow (&util_obstack, right); +} + +/* Encode a bitfield NeXT-style (i.e., without a bit offset or the underlying + field type. */ + +static void +encode_next_bitfield (int width) +{ + char buffer[40]; + sprintf (buffer, "b%d", width); + obstack_grow (&util_obstack, buffer, strlen (buffer)); +} + +/* Encodes 'type', ignoring type qualifiers (which you should encode + beforehand if needed) with the exception of 'const', which is + encoded by encode_type. See above for the explanation of + 'curtype'. 'format' can be OBJC_ENCODE_INLINE_DEFS or + OBJC_ENCODE_DONT_INLINE_DEFS. +*/ +static void +encode_type (tree type, int curtype, int format) +{ + enum tree_code code = TREE_CODE (type); + + /* Ignore type qualifiers other than 'const' when encoding a + type. */ + + if (type == error_mark_node) + return; + + if (!flag_next_runtime) + { + if (TYPE_READONLY (type)) + obstack_1grow (&util_obstack, 'r'); + } + + switch (code) + { + case ENUMERAL_TYPE: + if (flag_next_runtime) + { + /* Kludge for backwards-compatibility with gcc-3.3: enums + are always encoded as 'i' no matter what type they + actually are (!). */ + obstack_1grow (&util_obstack, 'i'); + break; + } + /* Else, they are encoded exactly like the integer type that is + used by the compiler to store them. */ + case INTEGER_TYPE: + { + char c; + switch (GET_MODE_BITSIZE (TYPE_MODE (type))) + { + case 8: c = TYPE_UNSIGNED (type) ? 'C' : 'c'; break; + case 16: c = TYPE_UNSIGNED (type) ? 'S' : 's'; break; + case 32: + { + tree int_type = type; + if (flag_next_runtime) + { + /* Another legacy kludge for compatiblity with + gcc-3.3: 32-bit longs are encoded as 'l' or 'L', + but not always. For typedefs, we need to use 'i' + or 'I' instead if encoding a struct field, or a + pointer! */ + int_type = ((!generating_instance_variables + && (obstack_object_size (&util_obstack) + == (unsigned) curtype)) + ? TYPE_MAIN_VARIANT (type) + : type); + } + if (int_type == long_unsigned_type_node + || int_type == long_integer_type_node) + c = TYPE_UNSIGNED (type) ? 'L' : 'l'; + else + c = TYPE_UNSIGNED (type) ? 'I' : 'i'; + } + break; + case 64: c = TYPE_UNSIGNED (type) ? 'Q' : 'q'; break; + case 128: c = TYPE_UNSIGNED (type) ? 'T' : 't'; break; + default: gcc_unreachable (); + } + obstack_1grow (&util_obstack, c); + break; + } + case REAL_TYPE: + { + char c; + /* Floating point types. */ + switch (GET_MODE_BITSIZE (TYPE_MODE (type))) + { + case 32: c = 'f'; break; + case 64: c = 'd'; break; + case 96: + case 128: c = 'D'; break; + default: gcc_unreachable (); + } + obstack_1grow (&util_obstack, c); + break; + } + case VOID_TYPE: + obstack_1grow (&util_obstack, 'v'); + break; + + case BOOLEAN_TYPE: + obstack_1grow (&util_obstack, 'B'); + break; + + case ARRAY_TYPE: + encode_array (type, curtype, format); + break; + + case POINTER_TYPE: +#ifdef OBJCPLUS + case REFERENCE_TYPE: +#endif + encode_pointer (type, curtype, format); + break; + + case RECORD_TYPE: + encode_aggregate_within (type, curtype, format, '{', '}'); + break; + + case UNION_TYPE: + encode_aggregate_within (type, curtype, format, '(', ')'); + break; + + case FUNCTION_TYPE: /* '?' means an unknown type. */ + obstack_1grow (&util_obstack, '?'); + break; + + case COMPLEX_TYPE: + /* A complex is encoded as 'j' followed by the inner type (eg, + "_Complex int" is encoded as 'ji'). */ + obstack_1grow (&util_obstack, 'j'); + encode_type (TREE_TYPE (type), curtype, format); + break; + + case VECTOR_TYPE: + encode_vector (type, curtype, format); + break; + + default: + warning (0, "unknown type %s found during Objective-C encoding", + gen_type_name (type)); + obstack_1grow (&util_obstack, '?'); + break; + } + + if (flag_next_runtime) + { + /* Super-kludge. Some ObjC qualifier and type combinations need + to be rearranged for compatibility with gcc-3.3. */ + if (code == POINTER_TYPE && obstack_object_size (&util_obstack) >= 3) + { + char *enc = obstack_base (&util_obstack) + curtype; + + /* Rewrite "in const" from "nr" to "rn". */ + if (curtype >= 1 && !strncmp (enc - 1, "nr", 2)) + strncpy (enc - 1, "rn", 2); + } + } +} + +static void +encode_gnu_bitfield (int position, tree type, int size) +{ + enum tree_code code = TREE_CODE (type); + char buffer[40]; + char charType = '?'; + + /* This code is only executed for the GNU runtime, so we can ignore + the NeXT runtime kludge of always encoding enums as 'i' no matter + what integers they actually are. */ + if (code == INTEGER_TYPE || code == ENUMERAL_TYPE) + { + if (integer_zerop (TYPE_MIN_VALUE (type))) + /* Unsigned integer types. */ + { + switch (TYPE_MODE (type)) + { + case QImode: + charType = 'C'; break; + case HImode: + charType = 'S'; break; + case SImode: + { + if (type == long_unsigned_type_node) + charType = 'L'; + else + charType = 'I'; + break; + } + case DImode: + charType = 'Q'; break; + default: + gcc_unreachable (); + } + } + else + /* Signed integer types. */ + { + switch (TYPE_MODE (type)) + { + case QImode: + charType = 'c'; break; + case HImode: + charType = 's'; break; + case SImode: + { + if (type == long_integer_type_node) + charType = 'l'; + else + charType = 'i'; + break; + } + case DImode: + charType = 'q'; break; + default: + gcc_unreachable (); + } + } + } + else + { + /* Do not do any encoding, produce an error and keep going. */ + error ("trying to encode non-integer type as a bitfield"); + return; + } + + sprintf (buffer, "b%d%c%d", position, charType, size); + obstack_grow (&util_obstack, buffer, strlen (buffer)); +} + +void +encode_field_decl (tree field_decl, int curtype, int format) +{ +#ifdef OBJCPLUS + /* C++ static members, and things that are not fields at all, + should not appear in the encoding. */ + if (TREE_CODE (field_decl) != FIELD_DECL || TREE_STATIC (field_decl)) + return; +#endif + + /* Generate the bitfield typing information, if needed. Note the difference + between GNU and NeXT runtimes. */ + if (DECL_BIT_FIELD_TYPE (field_decl)) + { + int size = tree_low_cst (DECL_SIZE (field_decl), 1); + + if (flag_next_runtime) + encode_next_bitfield (size); + else + encode_gnu_bitfield (int_bit_position (field_decl), + DECL_BIT_FIELD_TYPE (field_decl), size); + } + else + encode_type (TREE_TYPE (field_decl), curtype, format); +} + +/* This routine encodes the attribute of the input PROPERTY according to following + formula: + +Property attributes are stored as a comma-delimited C string. The simple attributes +readonly and copies are encoded as single characters. The parametrized attributes, +getter=name, setter=name, and ivar=name, are encoded as single characters, followed +by an identifier. Property types are also encoded as a parametrized attribute. The +characters used to encode these attributes are defined by the following enumeration: + +enum PropertyAttributes { + kPropertyReadOnly = 'r', // property is read-only. + kPropertyCopies = 'c', // property is a copy of the value last assigned + kPropertyGetter = 'g', // followed by getter selector name + kPropertySetter = 's', // followed by setter selector name + kPropertyInstanceVariable = 'i' // followed by instance variable name + kPropertyType = 't' // followed by old-style type encoding. +}; + +*/ + +tree +objc_v2_encode_prop_attr (tree property) +{ + const char *string; + tree type = TREE_TYPE (property); + obstack_1grow (&util_obstack, 't'); + encode_type (type, obstack_object_size (&util_obstack), + OBJC_ENCODE_INLINE_DEFS); + if (PROPERTY_READONLY (property)) + obstack_grow (&util_obstack, ",r", 2); + + if (PROPERTY_ASSIGN_SEMANTICS (property) == OBJC_PROPERTY_COPY) + obstack_grow (&util_obstack, ",c", 2); + + if (PROPERTY_GETTER_NAME (property)) + { + obstack_grow (&util_obstack, ",g", 2); + string = IDENTIFIER_POINTER (PROPERTY_GETTER_NAME (property)); + obstack_grow (&util_obstack, string, strlen (string)); + } + if (PROPERTY_SETTER_NAME (property)) + { + obstack_grow (&util_obstack, ",s", 2); + string = IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (property)); + obstack_grow (&util_obstack, string, strlen (string)); + } + if (PROPERTY_IVAR_NAME (property)) + { + obstack_grow (&util_obstack, ",i", 2); + string = IDENTIFIER_POINTER (PROPERTY_IVAR_NAME (property)); + obstack_grow (&util_obstack, string, strlen (string)); + } + + obstack_1grow (&util_obstack, 0); /* null terminate string */ + string = XOBFINISH (&util_obstack, char *); + obstack_free (&util_obstack, util_firstobj); + return get_identifier (string); +} + #include "gt-objc-objc-act.h" diff --git a/gcc/objc/objc-act.h b/gcc/objc/objc-act.h index b7d8403..f45b4ea 100644 --- a/gcc/objc/objc-act.h +++ b/gcc/objc/objc-act.h @@ -1,6 +1,6 @@ /* Declarations for objc-act.c. Copyright (C) 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, - 2010 Free Software Foundation, Inc. + 2010, 2011 Free Software Foundation, Inc. This file is part of GCC. @@ -28,8 +28,6 @@ bool objc_init (void); const char *objc_printable_name (tree, int); tree objc_fold_obj_type_ref (tree, tree); int objc_gimplify_expr (tree *, gimple_seq *, gimple_seq *); -tree objc_eh_runtime_type (tree); -tree objc_eh_personality (void); /* NB: The remaining public functions are prototyped in c-common.h, for the benefit of stub-objc.c and objc-act.c. */ @@ -167,6 +165,8 @@ typedef enum objc_property_assign_semantics { #define CLASS_PROTOCOL_LIST(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 4) #define TOTAL_CLASS_RAW_IVARS(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 5) +#define CLASS_HAS_EXCEPTION_ATTR(CLASS) ((CLASS)->type.lang_flag_0) + #define PROTOCOL_NAME(CLASS) ((CLASS)->type.name) #define PROTOCOL_LIST(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 0) #define PROTOCOL_NST_METHODS(CLASS) ((CLASS)->type.minval) @@ -176,7 +176,6 @@ typedef enum objc_property_assign_semantics { #define PROTOCOL_OPTIONAL_CLS_METHODS(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 2) #define PROTOCOL_OPTIONAL_NST_METHODS(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 3) - /* For CATEGORY_INTERFACE_TYPE, CLASS_INTERFACE_TYPE or PROTOCOL_INTERFACE_TYPE */ #define CLASS_PROPERTY_DECL(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 6) /* For CLASS_IMPLEMENTATION_TYPE or CATEGORY_IMPLEMENTATION_TYPE. */ @@ -215,6 +214,7 @@ typedef enum objc_property_assign_semantics { = make_tree_vec (OBJC_INFO_SLOT_ELTS); \ } \ while (0) + #define DUP_TYPE_OBJC_INFO(DST, SRC) \ do \ { \ @@ -244,20 +244,21 @@ struct GTY(()) hashed_attribute { attr next; tree value; }; + struct GTY(()) hashed_entry { attr list; hash next; tree key; }; +#define SIZEHASHTABLE 257 + extern GTY ((length ("SIZEHASHTABLE"))) hash *nst_method_hash_list; extern GTY ((length ("SIZEHASHTABLE"))) hash *cls_method_hash_list; extern GTY ((length ("SIZEHASHTABLE"))) hash *cls_name_hash_list; extern GTY ((length ("SIZEHASHTABLE"))) hash *als_name_hash_list; -#define SIZEHASHTABLE 257 - /* An array of all the local variables in the current function that need to be marked as volatile. */ extern GTY(()) VEC(tree,gc) *local_variables_to_volatilize; @@ -268,8 +269,8 @@ struct GTY(()) imp_entry { struct imp_entry *next; tree imp_context; tree imp_template; - tree class_decl; /* _OBJC_CLASS_<my_name>; */ - tree meta_decl; /* _OBJC_METACLASS_<my_name>; */ + tree class_decl; /* _OBJC[_v2]_CLASS/CATEGORY_<my_name>; */ + tree meta_decl; /* _OBJC[_v2]_METACLASS_<my_name>; */ BOOL_BITFIELD has_cxx_cdtors : 1; }; @@ -361,6 +362,7 @@ enum objc_tree_index OCTI_STRING_CLASS_DECL, OCTI_INTERNAL_CNST_STR_TYPE, OCTI_SUPER_DECL, + OCTI_SUPER_SUPERFIELD_ID, OCTI_UMSG_NONNIL_DECL, OCTI_UMSG_NONNIL_STRET_DECL, OCTI_STORAGE_CLS, @@ -394,6 +396,10 @@ enum objc_tree_index OCTI_GET_PROPERTY_STRUCT_DECL, OCTI_SET_PROPERTY_STRUCT_DECL, + /* "V1" stuff. */ + OCTI_V1_PROP_LIST_TEMPL, + OCTI_V1_PROP_NAME_ATTR_CHAIN, + OCTI_MAX }; @@ -433,14 +439,17 @@ extern GTY(()) tree objc_global_trees[OCTI_MAX]; (TREE_CODE (TYPE) == POINTER_TYPE \ && (TYPE_MAIN_VARIANT (TREE_TYPE (TYPE)) \ == TREE_TYPE (objc_object_type))) + #define IS_CLASS(TYPE) \ (TREE_CODE (TYPE) == POINTER_TYPE \ && (TYPE_MAIN_VARIANT (TREE_TYPE (TYPE)) \ == TREE_TYPE (objc_class_type))) + #define IS_PROTOCOL_QUALIFIED_UNTYPED(TYPE) \ ((IS_ID (TYPE) || IS_CLASS (TYPE)) \ && TYPE_HAS_OBJC_INFO (TREE_TYPE (TYPE)) \ && TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (TYPE))) + #define IS_SUPER(TYPE) \ (TREE_CODE (TYPE) == POINTER_TYPE \ && TREE_TYPE (TYPE) == objc_super_template) @@ -549,13 +558,19 @@ extern GTY(()) tree objc_global_trees[OCTI_MAX]; #define objc_class_id objc_global_trees[OCTI_CLS_ID] #define objc_object_name objc_global_trees[OCTI_ID_NAME] #define objc_class_name objc_global_trees[OCTI_CLASS_NAME] + +/* Constant string classes. */ #define constant_string_id objc_global_trees[OCTI_CNST_STR_ID] #define constant_string_type objc_global_trees[OCTI_CNST_STR_TYPE] #define constant_string_global_id \ objc_global_trees[OCTI_CNST_STR_GLOB_ID] #define string_class_decl objc_global_trees[OCTI_STRING_CLASS_DECL] #define internal_const_str_type objc_global_trees[OCTI_INTERNAL_CNST_STR_TYPE] + #define UOBJC_SUPER_decl objc_global_trees[OCTI_SUPER_DECL] +#define super_superclassfield_id \ + objc_global_trees[OCTI_SUPER_SUPERFIELD_ID] + #define objc_fast_enumeration_state_template \ objc_global_trees[OCTI_FAST_ENUM_STATE_TEMP] #define objc_enumeration_mutation_decl \ @@ -563,11 +578,168 @@ extern GTY(()) tree objc_global_trees[OCTI_MAX]; /* Declarations of functions used when synthesizing property accessors. */ -#define objc_getProperty_decl objc_global_trees[OCTI_GET_PROPERTY_DECL] -#define objc_setProperty_decl objc_global_trees[OCTI_SET_PROPERTY_DECL] -#define objc_copyStruct_decl objc_global_trees[OCTI_COPY_STRUCT_DECL] -#define objc_getPropertyStruct_decl objc_global_trees[OCTI_GET_PROPERTY_STRUCT_DECL] -#define objc_setPropertyStruct_decl objc_global_trees[OCTI_SET_PROPERTY_STRUCT_DECL] +#define objc_getProperty_decl objc_global_trees[OCTI_GET_PROPERTY_DECL] +#define objc_setProperty_decl objc_global_trees[OCTI_SET_PROPERTY_DECL] +#define objc_copyStruct_decl objc_global_trees[OCTI_COPY_STRUCT_DECL] +#define objc_getPropertyStruct_decl \ + objc_global_trees[OCTI_GET_PROPERTY_STRUCT_DECL] +#define objc_setPropertyStruct_decl \ + objc_global_trees[OCTI_SET_PROPERTY_STRUCT_DECL] + +/* V1 stuff. */ +#define objc_prop_list_ptr objc_global_trees[OCTI_V1_PROP_LIST_TEMPL] +#define prop_names_attr_chain objc_global_trees[OCTI_V1_PROP_NAME_ATTR_CHAIN] + +/* Reserved tag definitions. */ + +#define OBJECT_TYPEDEF_NAME "id" +#define CLASS_TYPEDEF_NAME "Class" + +#define TAG_OBJECT "objc_object" +#define TAG_CLASS "objc_class" +#define TAG_SUPER "objc_super" +#define TAG_SELECTOR "objc_selector" + +#define UTAG_CLASS "_objc_class" +#define UTAG_IVAR "_objc_ivar" +#define UTAG_IVAR_LIST "_objc_ivar_list" +#define UTAG_METHOD "_objc_method" +#define UTAG_METHOD_LIST "_objc_method_list" +#define UTAG_CATEGORY "_objc_category" +#define UTAG_MODULE "_objc_module" +#define UTAG_SYMTAB "_objc_symtab" +#define UTAG_SUPER "_objc_super" +#define UTAG_SELECTOR "_objc_selector" + +#define UTAG_PROTOCOL "_objc_protocol" +#define UTAG_METHOD_PROTOTYPE "_objc_method_prototype" +#define UTAG_METHOD_PROTOTYPE_LIST "_objc__method_prototype_list" + +#define PROTOCOL_OBJECT_CLASS_NAME "Protocol" + +#define TAG_EXCEPTIONTHROW "objc_exception_throw" +#define TAG_SYNCENTER "objc_sync_enter" +#define TAG_SYNCEXIT "objc_sync_exit" + +/* Really should be NeXT private. */ +#define UTAG_EXCDATA "_objc_exception_data" + +#define TAG_CXX_CONSTRUCT ".cxx_construct" +#define TAG_CXX_DESTRUCT ".cxx_destruct" + +#define TAG_ENUMERATION_MUTATION "objc_enumerationMutation" +#define TAG_FAST_ENUMERATION_STATE "__objcFastEnumerationState" + +typedef enum string_section +{ + class_names, /* class, category, protocol, module names */ + meth_var_names, /* method and variable names */ + meth_var_types, /* method and variable type descriptors */ + prop_names_attr /* property names and their attributes. */ +} string_section; + +#define METHOD_DEF 0 +#define METHOD_REF 1 + +/* (Decide if these can ever be validly changed.) */ +#define OBJC_ENCODE_INLINE_DEFS 0 +#define OBJC_ENCODE_DONT_INLINE_DEFS 1 + +#define BUFSIZE 1024 +#define CLS_FACTORY 0x0001L +#define CLS_META 0x0002L + +/* Runtime metadata flags - ??? apparently unused. */ + +#define OBJC_MODIFIER_STATIC 0x00000001 +#define OBJC_MODIFIER_FINAL 0x00000002 +#define OBJC_MODIFIER_PUBLIC 0x00000004 +#define OBJC_MODIFIER_PRIVATE 0x00000008 +#define OBJC_MODIFIER_PROTECTED 0x00000010 +#define OBJC_MODIFIER_NATIVE 0x00000020 +#define OBJC_MODIFIER_SYNCHRONIZED 0x00000040 +#define OBJC_MODIFIER_ABSTRACT 0x00000080 +#define OBJC_MODIFIER_VOLATILE 0x00000100 +#define OBJC_MODIFIER_TRANSIENT 0x00000200 +#define OBJC_MODIFIER_NONE_SPECIFIED 0x80000000 + +#define OBJC_VOID_AT_END void_list_node + +/* Exception handling constructs. We begin by having the parser do most + of the work and passing us blocks. + This allows us to handle different exceptions implementations. */ + +/* Stack of open try blocks. */ + +struct objc_try_context +{ + struct objc_try_context *outer; + + /* Statements (or statement lists) as processed by the parser. */ + tree try_body; + tree finally_body; + + /* Some file position locations. */ + location_t try_locus; + location_t end_try_locus; + location_t end_catch_locus; + location_t finally_locus; + location_t end_finally_locus; + + /* A STATEMENT_LIST of CATCH_EXPRs, appropriate for sticking into op1 + of a TRY_CATCH_EXPR. Even when doing Darwin setjmp. */ + tree catch_list; + + /* The CATCH_EXPR of an open @catch clause. */ + tree current_catch; + + /* The VAR_DECL holding __builtin_eh_pointer (or equivalent). */ + tree caught_decl; + tree stack_decl; + tree rethrow_decl; +}; + +/* A small number of routines used by the FE parser and the runtime code + generators. Put here as inlines for efficiency in non-lto builds rather + than making them externs. */ + +extern tree objc_create_temporary_var (tree, const char *); + +#define objc_is_object_id(TYPE) (OBJC_TYPE_NAME (TYPE) == objc_object_id) +#define objc_is_class_id(TYPE) (OBJC_TYPE_NAME (TYPE) == objc_class_id) + +/* Retrieve category interface CAT_NAME (if any) associated with CLASS. */ +static inline tree +lookup_category (tree klass, tree cat_name) +{ + tree category = CLASS_CATEGORY_LIST (klass); + + while (category && CLASS_SUPER_NAME (category) != cat_name) + category = CLASS_CATEGORY_LIST (category); + return category; +} + +/* Count only the fields occurring in T. */ +static inline int +ivar_list_length (tree t) +{ + int count = 0; + + for (; t; t = DECL_CHAIN (t)) + if (TREE_CODE (t) == FIELD_DECL) + ++count; + + return count; +} + +static inline tree +is_ivar (tree decl_chain, tree ident) +{ + for ( ; decl_chain; decl_chain = DECL_CHAIN (decl_chain)) + if (DECL_NAME (decl_chain) == ident) + return decl_chain; + return NULL_TREE; +} #endif /* GCC_OBJC_ACT_H */ diff --git a/gcc/objc/objc-gnu-runtime-abi-01.c b/gcc/objc/objc-gnu-runtime-abi-01.c new file mode 100644 index 0000000..a13f015 --- /dev/null +++ b/gcc/objc/objc-gnu-runtime-abi-01.c @@ -0,0 +1,2265 @@ +/* GNU Runtime (ABI-0/1) private. + Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by Iain Sandoe (split from objc-act.c) + +This file is part of GCC. + +GCC 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, or (at your option) +any later version. + +GCC 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/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" + +#ifdef OBJCPLUS +#include "cp-tree.h" +#else +#include "c-tree.h" +#include "c-lang.h" +#endif + +#include "langhooks.h" +#include "c-family/c-objc.h" +#include "objc-act.h" + +/* When building Objective-C++, we are not linking against the C front-end + and so need to replicate the C tree-construction functions in some way. */ +#ifdef OBJCPLUS +#define OBJCP_REMAP_FUNCTIONS +#include "objcp-decl.h" +#endif /* OBJCPLUS */ + +#include "toplev.h" +#include "ggc.h" +#include "tree-iterator.h" + +#include "objc-runtime-hooks.h" +#include "objc-runtime-shared-support.h" + +/* GNU runtime private definitions. */ +#define DEF_CONSTANT_STRING_CLASS_NAME "NXConstantString" + +#define TAG_GETCLASS "objc_get_class" +#define TAG_GETMETACLASS "objc_get_meta_class" + +#define TAG_MSGSEND "objc_msg_lookup" +#define TAG_MSGSENDSUPER "objc_msg_lookup_super" + +/* GNU-specific tags. */ + +#define TAG_EXECCLASS "__objc_exec_class" +#define TAG_GNUINIT "__objc_gnu_init" + +/* The version identifies which language generation and runtime + the module (file) was compiled for, and is recorded in the + module descriptor. */ +#define OBJC_VERSION 8 + +#define PROTOCOL_VERSION 2 + +/* This macro provides a method of removing ambiguity between runtimes + when LTO is in use on targets supporting multiple runtimes. + + For example, at present, any target that includes an implementation of + the NeXT runtime needs to place Objective-C meta-data into specific + named sections. This should _not_ be done for the GNU runtime, and the + folowing macro is used to attach Objective-C private attributes that may + be used to identify the runtime for which the meta-data are intended. */ + +#define OBJCMETA(DECL,VERS,KIND) \ + if (VERS) \ + DECL_ATTRIBUTES (DECL) = build_tree_list ((VERS), (KIND)); + +#ifndef TARGET_64BIT +#define TARGET_64BIT 0 +#endif + +static void gnu_runtime_01_initialize (void); + +static void build_selector_template (void); + +static tree gnu_runtime_abi_01_super_superclassfield_id (void); + +static tree gnu_runtime_abi_01_class_decl (tree); +static tree gnu_runtime_abi_01_metaclass_decl (tree); +static tree gnu_runtime_abi_01_category_decl (tree); +static tree gnu_runtime_abi_01_protocol_decl (tree); +static tree gnu_runtime_abi_01_string_decl (tree, const char *, string_section); + +static tree gnu_runtime_abi_01_get_class_reference (tree); +static tree gnu_runtime_abi_01_build_typed_selector_reference (location_t, tree, + tree); +static tree gnu_runtime_abi_01_get_protocol_reference (location_t, tree); +static tree gnu_runtime_abi_01_build_ivar_ref (location_t, tree, tree); +static tree gnu_runtime_abi_01_get_class_super_ref (location_t, struct imp_entry *, bool); +static tree gnu_runtime_abi_01_get_category_super_ref (location_t, struct imp_entry *, bool); + +static tree gnu_runtime_abi_01_receiver_is_class_object (tree); +static tree gnu_runtime_abi_01_get_arg_type_list_base (tree, int, int); +static tree gnu_runtime_abi_01_build_objc_method_call (location_t, tree, tree, + tree, tree, tree, int); + +static bool gnu_runtime_abi_01_setup_const_string_class_decl (void); +static tree gnu_runtime_abi_01_build_const_string_constructor (location_t, tree,int); + +static void objc_generate_v1_gnu_metadata (void); + +static tree objc_eh_runtime_type (tree type); +static tree objc_eh_personality (void); +static tree objc_build_exc_ptr (struct objc_try_context **); +static tree build_throw_stmt (location_t, tree, bool); +static tree begin_catch (struct objc_try_context **, tree, tree, tree, bool); +static void finish_catch (struct objc_try_context **, tree); +static tree finish_try_stmt (struct objc_try_context **); + +bool +objc_gnu_runtime_abi_01_init (objc_runtime_hooks *rthooks) +{ + /* GNU runtime does not need the compiler to change code in order to do GC. */ + if (flag_objc_gc) + { + warning_at (0, 0, "%<-fobjc-gc%> is ignored for %<-fgnu-runtime%>"); + flag_objc_gc = 0; + } + + /* Although I guess we could, we don't currently support SJLJ exceptions for the + GNU runtime. */ + if (flag_objc_sjlj_exceptions) + { + inform (UNKNOWN_LOCATION, "%<-fobjc-sjlj-exceptions%> is ignored for %<-fgnu-runtime%>"); + flag_objc_sjlj_exceptions = 0; + } + + rthooks->initialize = gnu_runtime_01_initialize; + rthooks->default_constant_string_class_name = DEF_CONSTANT_STRING_CLASS_NAME; + rthooks->tag_getclass = TAG_GETCLASS; + rthooks->super_superclassfield_ident = gnu_runtime_abi_01_super_superclassfield_id; + + rthooks->class_decl = gnu_runtime_abi_01_class_decl; + rthooks->metaclass_decl = gnu_runtime_abi_01_metaclass_decl; + rthooks->category_decl = gnu_runtime_abi_01_category_decl; + rthooks->protocol_decl = gnu_runtime_abi_01_protocol_decl; + rthooks->string_decl = gnu_runtime_abi_01_string_decl; + + rthooks->get_class_reference = gnu_runtime_abi_01_get_class_reference; + rthooks->build_selector_reference = gnu_runtime_abi_01_build_typed_selector_reference; + rthooks->get_protocol_reference = gnu_runtime_abi_01_get_protocol_reference; + rthooks->build_ivar_reference = gnu_runtime_abi_01_build_ivar_ref; + rthooks->get_class_super_ref = gnu_runtime_abi_01_get_class_super_ref; + rthooks->get_category_super_ref = gnu_runtime_abi_01_get_category_super_ref; + + rthooks->receiver_is_class_object = gnu_runtime_abi_01_receiver_is_class_object; + rthooks->get_arg_type_list_base = gnu_runtime_abi_01_get_arg_type_list_base; + rthooks->build_objc_method_call = gnu_runtime_abi_01_build_objc_method_call; + + rthooks->setup_const_string_class_decl = + gnu_runtime_abi_01_setup_const_string_class_decl; + rthooks->build_const_string_constructor = + gnu_runtime_abi_01_build_const_string_constructor; + + rthooks->build_throw_stmt = build_throw_stmt; + rthooks->build_exc_ptr = objc_build_exc_ptr; + rthooks->begin_catch = begin_catch; + rthooks->finish_catch = finish_catch; + rthooks->finish_try_stmt = finish_try_stmt; + + rthooks->generate_metadata = objc_generate_v1_gnu_metadata; + return true; +} + +static void build_selector_table_decl (void); +static void build_class_template (void); +static void build_category_template (void); +static void build_protocol_template (void); + +static GTY(()) tree objc_meta; +static GTY(()) tree meta_base; + +static void gnu_runtime_01_initialize (void) +{ + tree type, ftype, IMP_type; + + /* We do not need to mark GNU ObjC metadata for different sections, + however, we do need to make sure that it is not mistaken for NeXT + metadata. */ + objc_meta = get_identifier ("OBJC1METG"); + meta_base = get_identifier ("NONE"); + + /* Declare type of selector-objects that represent an operation name. */ + /* `const struct objc_selector *' */ + type = xref_tag (RECORD_TYPE, get_identifier (TAG_SELECTOR)); + type = build_qualified_type (type, TYPE_QUAL_CONST); + objc_selector_type = build_pointer_type (type); + + /* typedef id (*IMP)(id, SEL, ...); */ + ftype = build_varargs_function_type_list (objc_object_type, + objc_object_type, + objc_selector_type, + NULL_TREE); + + IMP_type = build_pointer_type (ftype); + + build_class_template (); + build_super_template (); + build_protocol_template (); + build_category_template (); + + /* GNU runtime messenger entry points. */ + /* TREE_NOTHROW is cleared for the message-sending functions, + because the function that gets called can throw in Obj-C++, or + could itself call something that can throw even in Obj-C. */ + + /* IMP objc_msg_lookup (id, SEL); */ + type = build_function_type_list (IMP_type, + objc_object_type, + objc_selector_type, + NULL_TREE); + + umsg_decl = add_builtin_function (TAG_MSGSEND, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (umsg_decl) = 0; + + /* IMP objc_msg_lookup_super (struct objc_super *, SEL); */ + type = build_function_type_list (IMP_type, + objc_super_type, + objc_selector_type, + NULL_TREE); + + umsg_super_decl = add_builtin_function (TAG_MSGSENDSUPER, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (umsg_super_decl) = 0; + + /* The following GNU runtime entry point is called to initialize + each module: + + __objc_exec_class (void *); */ + type = build_function_type_list (void_type_node, + ptr_type_node, + NULL_TREE); + + execclass_decl = add_builtin_function (TAG_EXECCLASS, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + type = build_function_type_list (objc_object_type, + const_string_type_node, + NULL_TREE); + + /* id objc_getClass (const char *); */ + objc_get_class_decl + = add_builtin_function (TAG_GETCLASS, type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + /* id objc_getMetaClass (const char *); */ + objc_get_meta_class_decl = add_builtin_function (TAG_GETMETACLASS, type, + 0, NOT_BUILT_IN, NULL, + NULL_TREE); + + /* static SEL _OBJC_SELECTOR_TABLE[]; */ + build_selector_table_decl (); + + /* Stuff for properties. + The codegen relies on this being NULL for GNU. */ + objc_copyStruct_decl = NULL_TREE; + + /* This is the type of all of the following functions + bjc_getPropertyStruct() and objc_setPropertyStruct(). */ + type = build_function_type_list (void_type_node, + ptr_type_node, + const_ptr_type_node, + ptrdiff_type_node, + boolean_type_node, + boolean_type_node, + NULL_TREE); + + /* Declare the following function: + void + objc_getPropertyStruct (void *destination, const void *source, + ptrdiff_t size, BOOL is_atomic, BOOL has_strong); */ + objc_getPropertyStruct_decl = add_builtin_function ("objc_getPropertyStruct", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (objc_getPropertyStruct_decl) = 0; + /* Declare the following function: + void + objc_setPropertyStruct (void *destination, const void *source, + ptrdiff_t size, BOOL is_atomic, BOOL has_strong); */ + objc_setPropertyStruct_decl = add_builtin_function ("objc_setPropertyStruct", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (objc_setPropertyStruct_decl) = 0; + + using_eh_for_cleanups (); + lang_hooks.eh_runtime_type = objc_eh_runtime_type; + lang_hooks.eh_personality = objc_eh_personality; +} + +/* --- templates --- */ +/* struct _objc_selector { + SEL sel_id; + char *sel_type; + }; */ + +static void +build_selector_template (void) +{ + tree decls, *chain = NULL; + + objc_selector_template = objc_start_struct (get_identifier (UTAG_SELECTOR)); + + /* SEL sel_id; */ + decls = add_field_decl (objc_selector_type, "sel_id", &chain); + + /* char *sel_type; */ + add_field_decl (string_type_node, "sel_type", &chain); + + objc_finish_struct (objc_selector_template, decls); +} + +/* struct _objc_class { + struct _objc_class *isa; + struct _objc_class *super_class; + char *name; + long version; + long info; + long instance_size; + struct _objc_ivar_list *ivars; + struct _objc_method_list *methods; + struct sarray *dtable; + struct _objc_class *subclass_list; + struct _objc_class *sibling_class; + struct _objc_protocol_list *protocols; + void *gc_object_type; + }; */ + +static void +build_class_template (void) +{ + tree ptype, decls, *chain = NULL; + + objc_class_template = objc_start_struct (get_identifier (UTAG_CLASS)); + + /* struct _objc_class *isa; */ + decls = add_field_decl (build_pointer_type (objc_class_template), + "isa", &chain); + + /* struct _objc_class *super_class; */ + add_field_decl (build_pointer_type (objc_class_template), + "super_class", &chain); + + /* char *name; */ + add_field_decl (string_type_node, "name", &chain); + + /* long version; */ + add_field_decl (long_integer_type_node, "version", &chain); + + /* long info; */ + add_field_decl (long_integer_type_node, "info", &chain); + + /* long instance_size; */ + add_field_decl (long_integer_type_node, "instance_size", &chain); + + /* struct _objc_ivar_list *ivars; */ + add_field_decl (objc_ivar_list_ptr,"ivars", &chain); + + /* struct _objc_method_list *methods; */ + add_field_decl (objc_method_list_ptr, "methods", &chain); + + /* struct sarray *dtable; */ + ptype = build_pointer_type(xref_tag (RECORD_TYPE, + get_identifier ("sarray"))); + add_field_decl (ptype, "dtable", &chain); + + /* struct objc_class *subclass_list; */ + ptype = build_pointer_type (objc_class_template); + add_field_decl (ptype, "subclass_list", &chain); + + /* struct objc_class *sibling_class; */ + ptype = build_pointer_type (objc_class_template); + add_field_decl (ptype, "sibling_class", &chain); + + /* struct _objc_protocol **protocol_list; */ + ptype = build_pointer_type (build_pointer_type + (xref_tag (RECORD_TYPE, + get_identifier (UTAG_PROTOCOL)))); + add_field_decl (ptype, "protocol_list", &chain); + + /* void *gc_object_type; */ + add_field_decl (build_pointer_type (void_type_node), + "gc_object_type", &chain); + + objc_finish_struct (objc_class_template, decls); +} + +/* struct _objc_category { + char *category_name; + char *class_name; + struct _objc_method_list *instance_methods; + struct _objc_method_list *class_methods; + struct _objc_protocol_list *protocols; + }; */ + +static void +build_category_template (void) +{ + tree ptype, decls, *chain = NULL; + + objc_category_template = objc_start_struct (get_identifier (UTAG_CATEGORY)); + + /* char *category_name; */ + decls = add_field_decl (string_type_node, "category_name", &chain); + + /* char *class_name; */ + add_field_decl (string_type_node, "class_name", &chain); + + /* struct _objc_method_list *instance_methods; */ + add_field_decl (objc_method_list_ptr, "instance_methods", &chain); + + /* struct _objc_method_list *class_methods; */ + add_field_decl (objc_method_list_ptr, "class_methods", &chain); + + /* struct _objc_protocol **protocol_list; */ + ptype = build_pointer_type (build_pointer_type (objc_protocol_template)); + add_field_decl (ptype, "protocol_list", &chain); + + objc_finish_struct (objc_category_template, decls); +} + +/* struct _objc_protocol { + struct _objc_class *isa; + char *protocol_name; + struct _objc_protocol **protocol_list; + struct _objc__method_prototype_list *instance_methods; + struct _objc__method_prototype_list *class_methods; + }; */ + +static void +build_protocol_template (void) +{ + tree ptype, decls, *chain = NULL; + + objc_protocol_template = objc_start_struct (get_identifier (UTAG_PROTOCOL)); + + /* struct _objc_class *isa; */ + ptype = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (UTAG_CLASS))); + decls = add_field_decl (ptype, "isa", &chain); + + /* char *protocol_name; */ + add_field_decl (string_type_node, "protocol_name", &chain); + + /* struct _objc_protocol **protocol_list; */ + ptype = build_pointer_type (build_pointer_type (objc_protocol_template)); + add_field_decl (ptype, "protocol_list", &chain); + + /* struct _objc__method_prototype_list *instance_methods; */ + add_field_decl (objc_method_proto_list_ptr, "instance_methods", &chain); + + /* struct _objc__method_prototype_list *class_methods; */ + add_field_decl (objc_method_proto_list_ptr, "class_methods", &chain); + + objc_finish_struct (objc_protocol_template, decls); +} + +/* --- names, decls + identifers --- */ + +static void +build_selector_table_decl (void) +{ + tree temp; + + build_selector_template (); + temp = build_array_type (objc_selector_template, NULL_TREE); + + UOBJC_SELECTOR_TABLE_decl = start_var_decl (temp, "_OBJC_SELECTOR_TABLE"); + OBJCMETA (UOBJC_SELECTOR_TABLE_decl, objc_meta, meta_base); +} + + +static tree +gnu_runtime_abi_01_super_superclassfield_id (void) +{ + if (!super_superclassfield_id) + super_superclassfield_id = get_identifier ("super_class"); + return super_superclassfield_id; +} + + +static tree +gnu_runtime_abi_01_class_decl (tree klass) +{ + tree decl; + char buf[BUFSIZE]; + snprintf (buf, BUFSIZE, "_OBJC_Class_%s", + IDENTIFIER_POINTER (CLASS_NAME (klass))); + decl = start_var_decl (objc_class_template, buf); + OBJCMETA (decl, objc_meta, meta_base); + return decl; +} + +static tree +gnu_runtime_abi_01_metaclass_decl (tree klass) +{ + tree decl; + char buf[BUFSIZE]; + snprintf (buf, BUFSIZE, "_OBJC_MetaClass_%s", + IDENTIFIER_POINTER (CLASS_NAME (klass))); + decl = start_var_decl (objc_class_template, buf); + OBJCMETA (decl, objc_meta, meta_base); + return decl; +} + +static tree +gnu_runtime_abi_01_category_decl (tree klass) +{ + tree decl; + char buf[BUFSIZE]; + snprintf (buf, BUFSIZE, "_OBJC_Category_%s_on_%s", + IDENTIFIER_POINTER (CLASS_SUPER_NAME (klass)), + IDENTIFIER_POINTER (CLASS_NAME (klass))); + decl = start_var_decl (objc_category_template, buf); + OBJCMETA (decl, objc_meta, meta_base); + return decl; +} + +static tree +gnu_runtime_abi_01_protocol_decl (tree p) +{ + tree decl; + char buf[BUFSIZE]; + + /* static struct _objc_protocol _OBJC_Protocol_<mumble>; */ + snprintf (buf, BUFSIZE, "_OBJC_Protocol_%s", + IDENTIFIER_POINTER (PROTOCOL_NAME (p))); + decl = start_var_decl (objc_protocol_template, buf); + OBJCMETA (decl, objc_meta, meta_base); + return decl; +} + +static tree +gnu_runtime_abi_01_string_decl (tree type, const char *name, + string_section where ATTRIBUTE_UNUSED) +{ + tree decl = start_var_decl (type, name); + OBJCMETA (decl, objc_meta, meta_base); + return decl; +} + +/* --- entry --- */ + +static tree +gnu_runtime_abi_01_get_class_reference (tree ident) +{ + tree params; + + add_class_reference (ident); + + params = build_tree_list (NULL_TREE, my_build_string_pointer + (IDENTIFIER_LENGTH (ident) + 1, + IDENTIFIER_POINTER (ident))); + +/* assemble_external (objc_get_class_decl);*/ + return build_function_call (input_location, objc_get_class_decl, params); +} + +/* Used by get_arg_type_list. + Return the types for receiver & _cmd at the start of a method argument list. + context is either METHOD_DEF or METHOD_REF, saying whether we are trying + to define a method or call one. superflag says this is for a send to super. + meth may be NULL, in the case that there is no prototype. */ + +static tree +gnu_runtime_abi_01_get_arg_type_list_base (tree meth, int context, + int superflag ATTRIBUTE_UNUSED) +{ + tree arglist; + + /* Receiver type. */ + if (context == METHOD_DEF && TREE_CODE (meth) == INSTANCE_METHOD_DECL) + arglist = build_tree_list (NULL_TREE, objc_instance_type); + else + arglist = build_tree_list (NULL_TREE, objc_object_type); + + /* Selector type - will eventually change to `int'. */ + chainon (arglist, build_tree_list (NULL_TREE, objc_selector_type)); + return arglist; +} + +/* Unused for GNU runtime. */ +static tree +gnu_runtime_abi_01_receiver_is_class_object (tree a ATTRIBUTE_UNUSED) +{ + return NULL_TREE; +} + +/* sel_ref_chain is a list whose "value" fields will be instances of + identifier_node that represent the selector. LOC is the location of + the @selector. */ + +static tree +gnu_runtime_abi_01_build_typed_selector_reference (location_t loc, tree ident, + tree prototype) +{ + tree *chain = &sel_ref_chain; + tree expr; + int index = 0; + + while (*chain) + { + /* When we do a lookup for @selector () we have no idea of the + prototype - so match the first we find. */ + if (TREE_VALUE (*chain) == ident + && (!prototype || TREE_PURPOSE (*chain) == prototype)) + goto return_at_index; + + index++; + chain = &TREE_CHAIN (*chain); + } + + *chain = tree_cons (prototype, ident, NULL_TREE); + + /* TODO: Use a vec and keep this in it to (a) avoid re-creating and + (b) provide better diagnostics for the first time an undefined + selector is used. */ + return_at_index: + expr = build_unary_op (loc, ADDR_EXPR, + build_array_ref (loc, UOBJC_SELECTOR_TABLE_decl, + build_int_cst (NULL_TREE, index)), + 1); + return convert (objc_selector_type, expr); +} + +/* Build a tree expression to send OBJECT the operation SELECTOR, + looking up the method on object LOOKUP_OBJECT (often same as OBJECT), + assuming the method has prototype METHOD_PROTOTYPE. + (That is an INSTANCE_METHOD_DECL or CLASS_METHOD_DECL.) + LOC is the location of the expression to build. + Use METHOD_PARAMS as list of args to pass to the method. + If SUPER_FLAG is nonzero, we look up the superclass's method. */ + +static tree +build_objc_method_call (location_t loc, int super_flag, tree method_prototype, + tree lookup_object, tree selector, + tree method_params) +{ + tree sender = (super_flag ? umsg_super_decl + : (flag_objc_direct_dispatch ? umsg_fast_decl + : umsg_decl)); + tree rcv_p = (super_flag ? objc_super_type : objc_object_type); + VEC(tree, gc) *parms; + VEC(tree, gc) *tv; + unsigned nparm = (method_params ? list_length (method_params) : 0); + + /* If a prototype for the method to be called exists, then cast + the sender's return type and arguments to match that of the method. + Otherwise, leave sender as is. */ + tree ret_type + = (method_prototype + ? TREE_VALUE (TREE_TYPE (method_prototype)) + : objc_object_type); + + tree method_param_types = + get_arg_type_list (method_prototype, METHOD_REF, super_flag); + tree ftype = build_function_type (ret_type, method_param_types); + tree sender_cast; + tree method, t; + + if (method_prototype && METHOD_TYPE_ATTRIBUTES (method_prototype)) + ftype = build_type_attribute_variant (ftype, + METHOD_TYPE_ATTRIBUTES + (method_prototype)); + + sender_cast = build_pointer_type (ftype); + + lookup_object = build_c_cast (loc, rcv_p, lookup_object); + + /* Use SAVE_EXPR to avoid evaluating the receiver twice. */ + lookup_object = save_expr (lookup_object); + + /* Param list + 2 slots for object and selector. */ + parms = VEC_alloc (tree, gc, nparm + 2); + tv = VEC_alloc (tree, gc, 2); + + /* First, call the lookup function to get a pointer to the method, + then cast the pointer, then call it with the method arguments. */ + VEC_quick_push (tree, tv, lookup_object); + VEC_quick_push (tree, tv, selector); + method = build_function_call_vec (loc, sender, tv, NULL); + VEC_free (tree, gc, tv); + + /* Pass the appropriate object to the method. */ + VEC_quick_push (tree, parms, (super_flag ? self_decl : lookup_object)); + + /* Pass the selector to the method. */ + VEC_quick_push (tree, parms, selector); + /* Now append the remainder of the parms. */ + if (nparm) + for (; method_params; method_params = TREE_CHAIN (method_params)) + VEC_quick_push (tree, parms, TREE_VALUE (method_params)); + + /* Build an obj_type_ref, with the correct cast for the method call. */ + t = build3 (OBJ_TYPE_REF, sender_cast, method, lookup_object, size_zero_node); + t = build_function_call_vec (loc, t, parms, NULL); + VEC_free (tree, gc, parms); + return t; +} + +static tree +gnu_runtime_abi_01_build_objc_method_call (location_t loc, + tree method_prototype, + tree receiver, + tree rtype ATTRIBUTE_UNUSED, + tree sel_name, + tree method_params, + int super ATTRIBUTE_UNUSED) +{ + tree selector = + gnu_runtime_abi_01_build_typed_selector_reference (loc, + sel_name, + method_prototype); + + return build_objc_method_call (loc, super, method_prototype, receiver, + selector, method_params); +} + +static tree +gnu_runtime_abi_01_get_protocol_reference (location_t loc, tree p) +{ + tree expr, protocol_struct_type, *chain; + if (!PROTOCOL_FORWARD_DECL (p)) + PROTOCOL_FORWARD_DECL (p) = gnu_runtime_abi_01_protocol_decl (p); + + expr = build_unary_op (loc, ADDR_EXPR, PROTOCOL_FORWARD_DECL (p), 0); + + /* ??? Ideally we'd build the reference with objc_protocol_type directly, + if we have it, rather than converting it here. */ + expr = convert (objc_protocol_type, expr); + + /* The @protocol() expression is being compiled into a pointer to a + statically allocated instance of the Protocol class. To become + usable at runtime, the 'isa' pointer of the instance need to be + fixed up at runtime by the runtime library, to point to the + actual 'Protocol' class. */ + + /* For the GNU runtime, put the static Protocol instance in the list + of statically allocated instances, so that we make sure that its + 'isa' pointer is fixed up at runtime by the GNU runtime library + to point to the Protocol class (at runtime, when loading the + module, the GNU runtime library loops on the statically allocated + instances (as found in the defs field in objc_symtab) and fixups + all the 'isa' pointers of those objects). */ + + /* This type is a struct containing the fields of a Protocol + object. (Cfr. objc_protocol_type instead is the type of a pointer + to such a struct). */ + protocol_struct_type = xref_tag (RECORD_TYPE, + get_identifier (PROTOCOL_OBJECT_CLASS_NAME)); + + /* Look for the list of Protocol statically allocated instances + to fixup at runtime. Create a new list to hold Protocol + statically allocated instances, if the list is not found. At + present there is only another list, holding NSConstantString + static instances to be fixed up at runtime. */ + + for (chain = &objc_static_instances; + *chain && TREE_VALUE (*chain) != protocol_struct_type; + chain = &TREE_CHAIN (*chain)); + + if (!*chain) + { + *chain = tree_cons (NULL_TREE, protocol_struct_type, NULL_TREE); + add_objc_string (OBJC_TYPE_NAME (protocol_struct_type), + class_names); + } + + /* Add this statically allocated instance to the Protocol list. */ + TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, + PROTOCOL_FORWARD_DECL (p), + TREE_PURPOSE (*chain)); + return expr; +} + +/* For ABI 0/1 and IVAR is just a fixed offset in the class struct. */ + +static tree +gnu_runtime_abi_01_build_ivar_ref (location_t loc ATTRIBUTE_UNUSED, + tree base, tree id) +{ + return objc_build_component_ref (base, id); +} + +/* We build super class references as we need them (but keep them once + built for the sake of efficiency). */ + +static tree +gnu_runtime_abi_01_get_class_super_ref (location_t loc ATTRIBUTE_UNUSED, + struct imp_entry *imp, bool inst_meth) +{ + if (inst_meth) + { + if (!ucls_super_ref) + ucls_super_ref = + objc_build_component_ref (imp->class_decl, + get_identifier ("super_class")); + return ucls_super_ref; + } + else + { + if (!uucls_super_ref) + uucls_super_ref = + objc_build_component_ref (imp->meta_decl, + get_identifier ("super_class")); + return uucls_super_ref; + } +} + +static tree +gnu_runtime_abi_01_get_category_super_ref (location_t loc ATTRIBUTE_UNUSED, + struct imp_entry *imp, bool inst_meth) +{ + tree super_name = CLASS_SUPER_NAME (imp->imp_template); + tree super_class; + + add_class_reference (super_name); + super_class = (inst_meth ? objc_get_class_decl : objc_get_meta_class_decl); +/* assemble_external (super_class);*/ + super_name = my_build_string_pointer (IDENTIFIER_LENGTH (super_name) + 1, + IDENTIFIER_POINTER (super_name)); + /* super_class = get_{meta_}class("CLASS_SUPER_NAME"); */ + return build_function_call (input_location, + super_class, + build_tree_list (NULL_TREE, super_name)); +} + +static bool +gnu_runtime_abi_01_setup_const_string_class_decl (void) +{ + /* Do nothing, and create no error. */ + return true; +} + +/* Declare a static instance of CLASS_DECL initialized by CONSTRUCTOR. */ + +static GTY(()) int num_static_inst; + +static tree +objc_add_static_instance (tree constructor, tree class_decl) +{ + tree *chain, decl; + char buf[BUFSIZE]; + + /* Find the list of static instances for the CLASS_DECL. Create one if + not found. */ + for (chain = &objc_static_instances; + *chain && TREE_VALUE (*chain) != class_decl; + chain = &TREE_CHAIN (*chain)); + if (!*chain) + { + *chain = tree_cons (NULL_TREE, class_decl, NULL_TREE); + add_objc_string (OBJC_TYPE_NAME (class_decl), class_names); + } + + snprintf (buf, BUFSIZE, "_OBJC_INSTANCE_%d", num_static_inst++); + decl = build_decl (input_location, + VAR_DECL, get_identifier (buf), class_decl); + TREE_STATIC (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + TREE_USED (decl) = 1; + DECL_INITIAL (decl) = constructor; + DECL_CONTEXT (decl) = NULL; + OBJCMETA (decl, objc_meta, meta_base); + + /* We may be writing something else just now. + Postpone till end of input. */ + DECL_DEFER_OUTPUT (decl) = 1; + pushdecl_top_level (decl); + rest_of_decl_compilation (decl, 1, 0); + + /* Add the DECL to the head of this CLASS' list. */ + TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, decl, TREE_PURPOSE (*chain)); + + return decl; +} + +static tree +gnu_runtime_abi_01_build_const_string_constructor (location_t loc, tree string, + int length) +{ + tree constructor, fields; + VEC(constructor_elt,gc) *v = NULL; + + /* GNU: (NXConstantString *) & ((__builtin_ObjCString) { NULL, string, length }) */ + fields = TYPE_FIELDS (internal_const_str_type); + CONSTRUCTOR_APPEND_ELT (v, fields, build_int_cst (NULL_TREE, 0)); + + fields = DECL_CHAIN (fields); + CONSTRUCTOR_APPEND_ELT (v, fields, build_unary_op (loc, + ADDR_EXPR, string, 1)); + + fields = DECL_CHAIN (fields); + CONSTRUCTOR_APPEND_ELT (v, fields, build_int_cst (NULL_TREE, length)); + constructor = objc_build_constructor (internal_const_str_type, v); + + constructor = objc_add_static_instance (constructor, constant_string_type); + return constructor; +} + +/* --- metadata - module initializer --- */ + +/* The GNU runtime requires us to provide a static initializer function + for each module: + + static void __objc_gnu_init (void) { + __objc_exec_class (&L_OBJC_MODULES); + } */ + + +static void +build_module_initializer_routine (void) +{ + tree body; + +#ifdef OBJCPLUS + push_lang_context (lang_name_c); /* extern "C" */ +#endif + + objc_push_parm (build_decl (input_location, + PARM_DECL, NULL_TREE, void_type_node)); +#ifdef OBJCPLUS + objc_start_function (get_identifier (TAG_GNUINIT), + build_function_type_list (void_type_node, NULL_TREE), + NULL_TREE, NULL_TREE); +#else + objc_start_function (get_identifier (TAG_GNUINIT), + build_function_type_list (void_type_node, NULL_TREE), + NULL_TREE, objc_get_parm_info (0)); +#endif + body = c_begin_compound_stmt (true); + add_stmt (build_function_call + (input_location, + execclass_decl, + build_tree_list + (NULL_TREE, + build_unary_op (input_location, ADDR_EXPR, + UOBJC_MODULES_decl, 0)))); + add_stmt (c_end_compound_stmt (input_location, body, true)); + + TREE_PUBLIC (current_function_decl) = 0; + +#ifndef OBJCPLUS + /* For Objective-C++, we will need to call __objc_gnu_init + from objc_generate_static_init_call() below. */ + DECL_STATIC_CONSTRUCTOR (current_function_decl) = 1; +#endif + + GNU_INIT_decl = current_function_decl; + finish_function (); + +#ifdef OBJCPLUS + pop_lang_context (); +#endif +} + +#ifdef OBJCPLUS +/* Return 1 if the __objc_gnu_init function has been synthesized and needs + to be called by the module initializer routine. */ + +int +objc_static_init_needed_p (void) +{ + return (GNU_INIT_decl != NULL_TREE); +} + +/* Generate a call to the __objc_gnu_init initializer function. */ + +tree +objc_generate_static_init_call (tree ctors ATTRIBUTE_UNUSED) +{ + add_stmt (build_stmt (input_location, EXPR_STMT, + build_function_call (input_location, + GNU_INIT_decl, NULL_TREE))); + + return ctors; +} +#endif /* OBJCPLUS */ + +/* --- Output GNU Meta-data --- */ + +static void +generate_classref_translation_entry (tree chain) +{ + tree expr, decl, type; + + decl = TREE_PURPOSE (chain); + type = TREE_TYPE (decl); + + expr = add_objc_string (TREE_VALUE (chain), class_names); + expr = convert (type, expr); /* cast! */ + + /* 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; + OBJCMETA (decl, objc_meta, meta_base); + finish_var_decl (decl, expr); + return; +} + + +static void +handle_impent (struct imp_entry *impent) +{ + char *string; + +/* objc_implementation_context = impent->imp_context; + implementation_template = impent->imp_template;*/ + + switch (TREE_CODE (impent->imp_context)) + { + case CLASS_IMPLEMENTATION_TYPE: + { + const char *const class_name = + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)); + + string = (char *) alloca (strlen (class_name) + 30); + + sprintf (string, "__objc_class_name_%s", class_name); + break; + } + case CATEGORY_IMPLEMENTATION_TYPE: + { + const char *const class_name = + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)); + const char *const class_super_name = + IDENTIFIER_POINTER (CLASS_SUPER_NAME (impent->imp_context)); + + string = (char *) alloca (strlen (class_name) + + strlen (class_super_name) + 30); + + /* Do the same for categories. Even though no references to + these symbols are generated automatically by the compiler, + it gives you a handle to pull them into an archive by + hand. */ + sprintf (string, "*__objc_category_name_%s_%s", class_name, class_super_name); + break; + } + default: + return; + } + + { + tree decl, init; + + 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) = NULL_TREE; + DECL_ARTIFICIAL (decl) = 1; + 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) ; + } +} + +tree +build_protocol_initializer (tree type, tree protocol_name, tree protocol_list, + tree inst_methods, tree class_methods) +{ + tree expr, ttyp; + location_t loc; + VEC(constructor_elt,gc) *inits = NULL; + + /* TODO: pass the loc in or find it from args. */ + loc = input_location; + ttyp = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (UTAG_CLASS))); + /* Filling the "isa" in with a version allows the runtime system to + detect this ... */ + expr = build_int_cst (ttyp, PROTOCOL_VERSION); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, protocol_name); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, protocol_list); + + ttyp = objc_method_proto_list_ptr; + if (inst_methods) + expr = convert (ttyp, build_unary_op (loc, ADDR_EXPR, inst_methods, 0)); + else + expr = convert (ttyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + + if (class_methods) + expr = convert (ttyp, build_unary_op (loc, ADDR_EXPR, class_methods, 0)); + else + expr = convert (ttyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + + return objc_build_constructor (type, inits); +} + +static tree +generate_protocol_list (tree i_or_p, tree klass_ctxt) +{ + tree array_type, ptype, refs_decl, lproto, e, plist; + VEC(constructor_elt,gc) *v = NULL; + char buf[BUFSIZE]; + int size = 0; + + switch (TREE_CODE (i_or_p)) + { + case CLASS_INTERFACE_TYPE: + case CATEGORY_INTERFACE_TYPE: + plist = CLASS_PROTOCOL_LIST (i_or_p); + break; + case PROTOCOL_INTERFACE_TYPE: + plist = PROTOCOL_LIST (i_or_p); + break; + default: + gcc_unreachable (); + } + + /* Compute size. */ + for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) + if (TREE_CODE (TREE_VALUE (lproto)) == PROTOCOL_INTERFACE_TYPE + && PROTOCOL_FORWARD_DECL (TREE_VALUE (lproto))) + size++; + + /* Build initializer. */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); + e = build_int_cst (build_pointer_type (objc_protocol_template), size); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, e); + + for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) + { + tree pval = TREE_VALUE (lproto); + + if (TREE_CODE (pval) == PROTOCOL_INTERFACE_TYPE + && PROTOCOL_FORWARD_DECL (pval)) + { + tree fwref = PROTOCOL_FORWARD_DECL (pval); + location_t loc = DECL_SOURCE_LOCATION (fwref) ; + e = build_unary_op (loc, ADDR_EXPR, fwref, 0); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, e); + } + } + + /* static struct objc_protocol *refs[n]; */ + + switch (TREE_CODE (i_or_p)) + { + case PROTOCOL_INTERFACE_TYPE: + snprintf (buf, BUFSIZE, "_OBJC_ProtocolRefs_%s", + IDENTIFIER_POINTER (PROTOCOL_NAME (i_or_p))); + break; + case CLASS_INTERFACE_TYPE: + snprintf (buf, BUFSIZE, "_OBJC_ClassProtocols_%s", + IDENTIFIER_POINTER (CLASS_NAME (i_or_p))); + break; + case CATEGORY_INTERFACE_TYPE: + snprintf (buf, BUFSIZE, "_OBJC_CategoryProtocols_%s_%s", + IDENTIFIER_POINTER (CLASS_NAME (klass_ctxt)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (klass_ctxt))); + break; + default: + gcc_unreachable (); + } + + ptype = build_pointer_type (objc_protocol_template); + array_type = build_sized_array_type (ptype, size + 3); + refs_decl = start_var_decl (array_type, buf); + OBJCMETA (refs_decl, objc_meta, meta_base); + finish_var_decl (refs_decl, + objc_build_constructor (TREE_TYPE (refs_decl), v)); + + return refs_decl; +} + +static tree +generate_v1_meth_descriptor_table (tree chain, tree protocol, const char *prefix) +{ + tree method_list_template, initlist, decl; + int size; + VEC(constructor_elt,gc) *v = NULL; + char buf[BUFSIZE]; + + if (!chain || !prefix) + return NULL_TREE; + + if (!objc_method_prototype_template) + objc_method_prototype_template = build_method_prototype_template (); + + size = list_length (chain); + method_list_template = + build_method_prototype_list_template (objc_method_prototype_template, + size); + snprintf (buf, BUFSIZE, "%s_%s", prefix, + IDENTIFIER_POINTER (PROTOCOL_NAME (protocol))); + + decl = start_var_decl (method_list_template, buf); + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, size)); + initlist = + build_descriptor_table_initializer (objc_method_prototype_template, + chain); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, initlist); + OBJCMETA (decl, objc_meta, meta_base); + finish_var_decl (decl, objc_build_constructor (method_list_template, v)); + return decl; +} + +/* For each protocol which was referenced either from a @protocol() + expression, or because a class/category implements it (then a + pointer to the protocol is stored in the struct describing the + class/category), we create a statically allocated instance of the + Protocol class. The code is written in such a way as to generate + as few Protocol objects as possible; we generate a unique Protocol + instance for each protocol, and we don't generate a Protocol + instance if the protocol is never referenced (either from a + @protocol() or from a class/category implementation). These + statically allocated objects can be referred to via the static + (that is, private to this module) symbols _OBJC_PROTOCOL_n. + + The statically allocated Protocol objects that we generate here + need to be fixed up at runtime in order to be used: the 'isa' + pointer of the objects need to be set up to point to the 'Protocol' + class, as known at runtime. + + The GNU runtime fixes up all protocols before user code from the module + is executed; it requires pointers to those symbols + to be put in the objc_symtab (which is then passed as argument to + the function __objc_exec_class() which the compiler sets up to be + executed automatically when the module is loaded); setup of those + Protocol objects happen in two ways in the GNU runtime: all + Protocol objects referred to by a class or category implementation + are fixed up when the class/category is loaded; all Protocol + objects referred to by a @protocol() expression are added by the + compiler to the list of statically allocated instances to fixup + (the same list holding the statically allocated constant string + objects). Because, as explained above, the compiler generates as + few Protocol objects as possible, some Protocol object might end up + being referenced multiple times when compiled with the GNU runtime, + and end up being fixed up multiple times at runtime initialization. + But that doesn't hurt, it's just a little inefficient. */ + +static void +generate_protocols (void) +{ + tree p, encoding; + tree decl; + tree initlist, protocol_name_expr, refs_decl, refs_expr; + + /* If a protocol was directly referenced, pull in indirect references. */ + for (p = protocol_chain; p; p = TREE_CHAIN (p)) + if (PROTOCOL_FORWARD_DECL (p) && PROTOCOL_LIST (p)) + generate_protocol_references (PROTOCOL_LIST (p)); + + for (p = protocol_chain; p; p = TREE_CHAIN (p)) + { + tree nst_methods = PROTOCOL_NST_METHODS (p); + tree cls_methods = PROTOCOL_CLS_METHODS (p); + + /* If protocol wasn't referenced, don't generate any code. */ + decl = PROTOCOL_FORWARD_DECL (p); + + if (!decl) + continue; + + /* Make sure we link in the Protocol class. */ + add_class_reference (get_identifier (PROTOCOL_OBJECT_CLASS_NAME)); + + while (nst_methods) + { + if (! METHOD_ENCODING (nst_methods)) + { + encoding = encode_method_prototype (nst_methods); + METHOD_ENCODING (nst_methods) = encoding; + } + nst_methods = DECL_CHAIN (nst_methods); + } + + UOBJC_INSTANCE_METHODS_decl = + generate_v1_meth_descriptor_table (PROTOCOL_NST_METHODS (p), p, + "_OBJC_PROTOCOL_INSTANCE_METHODS"); + + while (cls_methods) + { + if (! METHOD_ENCODING (cls_methods)) + { + encoding = encode_method_prototype (cls_methods); + METHOD_ENCODING (cls_methods) = encoding; + } + + cls_methods = DECL_CHAIN (cls_methods); + } + + UOBJC_CLASS_METHODS_decl = + generate_v1_meth_descriptor_table (PROTOCOL_CLS_METHODS (p), p, + "_OBJC_PROTOCOL_CLASS_METHODS"); +/* generate_method_descriptors (p);*/ + + if (PROTOCOL_LIST (p)) + refs_decl = generate_protocol_list (p, NULL_TREE); + else + refs_decl = 0; + + /* static struct objc_protocol _OBJC_PROTOCOL_<mumble>; */ + protocol_name_expr = add_objc_string (PROTOCOL_NAME (p), class_names); + + if (refs_decl) + refs_expr = convert (build_pointer_type (build_pointer_type + (objc_protocol_template)), + build_unary_op (input_location, + ADDR_EXPR, refs_decl, 0)); + else + refs_expr = build_int_cst (NULL_TREE, 0); + + /* UOBJC_INSTANCE_METHODS_decl/UOBJC_CLASS_METHODS_decl are set + by generate_method_descriptors, which is called above. */ + initlist = build_protocol_initializer (TREE_TYPE (decl), + protocol_name_expr, refs_expr, + UOBJC_INSTANCE_METHODS_decl, + UOBJC_CLASS_METHODS_decl); + finish_var_decl (decl, initlist); + } +} + +static tree +generate_dispatch_table (tree chain, const char *name) +{ + tree decl, method_list_template, initlist; + VEC(constructor_elt,gc) *v = NULL; + int size = list_length (chain); + + if (!objc_method_template) + objc_method_template = build_method_template (); + + method_list_template = build_method_list_template (objc_method_template, + size); + initlist = build_dispatch_table_initializer (objc_method_template, chain); + + decl = start_var_decl (method_list_template, name); + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (integer_type_node, size)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, initlist); + + OBJCMETA (decl, objc_meta, meta_base); + finish_var_decl (decl, + objc_build_constructor (TREE_TYPE (decl), v)); + + return decl; +} + +/* Init a category. */ +static tree +build_category_initializer (tree type, tree cat_name, tree class_name, + tree inst_methods, tree class_methods, + tree protocol_list) +{ + tree expr, ltyp; + location_t loc; + VEC(constructor_elt,gc) *v = NULL; + + /* TODO: pass the loc in or find it from args. */ + /* TODO: pass the loc in or find it from args. */ + loc = UNKNOWN_LOCATION; + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, cat_name); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, class_name); + + ltyp = objc_method_list_ptr; + if (inst_methods) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, inst_methods, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + if (class_methods) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, class_methods, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + /* protocol_list = */ + ltyp = build_pointer_type (build_pointer_type (objc_protocol_template)); + if (protocol_list) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, protocol_list, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + return objc_build_constructor (type, v); +} + +/* static struct objc_category _OBJC_CATEGORY_<name> = { ... }; */ + +static void +generate_category (struct imp_entry *impent) +{ + tree initlist, cat_name_expr, class_name_expr; + tree protocol_decl, category, cat_decl; + tree inst_methods = NULL_TREE, class_methods = NULL_TREE; + tree cat = impent->imp_context; + char buf[BUFSIZE]; + + cat_decl = impent->class_decl; + + add_class_reference (CLASS_NAME (cat)); + cat_name_expr = add_objc_string (CLASS_SUPER_NAME (cat), class_names); + + class_name_expr = add_objc_string (CLASS_NAME (cat), class_names); + + category = lookup_category (impent->imp_template, CLASS_SUPER_NAME (cat)); + + if (category && CLASS_PROTOCOL_LIST (category)) + { + generate_protocol_references (CLASS_PROTOCOL_LIST (category)); + protocol_decl = generate_protocol_list (category, cat); + } + else + protocol_decl = 0; + + if (CLASS_NST_METHODS (cat)) + { + snprintf (buf, BUFSIZE, "_OBJC_CategoryInstanceMethods_%s_%s", + IDENTIFIER_POINTER (CLASS_NAME (cat)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (cat))); + inst_methods = generate_dispatch_table (CLASS_NST_METHODS (cat), buf); + } + + if (CLASS_CLS_METHODS (cat)) + { + snprintf (buf, BUFSIZE, "_OBJC_CategoryClassMethods_%s_%s", + IDENTIFIER_POINTER (CLASS_NAME (cat)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (cat))); + class_methods = generate_dispatch_table (CLASS_CLS_METHODS (cat), buf); + } + + initlist = build_category_initializer (TREE_TYPE (cat_decl), + cat_name_expr, class_name_expr, + inst_methods, class_methods, + protocol_decl); + /* Finish and initialize the forward decl. */ + finish_var_decl (cat_decl, initlist); + impent->class_decl = cat_decl; +} + +/* struct _objc_class { + struct objc_class *isa; + struct objc_class *super_class; + char *name; + long version; + long info; + long instance_size; + struct objc_ivar_list *ivars; + struct objc_method_list *methods; + if (flag_next_runtime) + struct objc_cache *cache; + else { + struct sarray *dtable; + struct objc_class *subclass_list; + struct objc_class *sibling_class; + } + struct objc_protocol_list *protocols; + if (flag_next_runtime) + void *sel_id; + void *gc_object_type; + }; */ + +static tree +build_shared_structure_initializer (tree type, tree isa, tree super, + tree name, tree size, int status, + tree dispatch_table, tree ivar_list, + tree protocol_list) +{ + tree expr, ltyp; + VEC(constructor_elt,gc) *v = NULL; + + /* isa = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, isa); + + /* super_class = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, super); + + /* name = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, default_conversion (name)); + + /* version = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (long_integer_type_node, 0)); + + /* info = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (long_integer_type_node, status)); + + /* instance_size = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + convert (long_integer_type_node, size)); + + /* objc_ivar_list = */ + if (!ivar_list) + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (objc_ivar_list_ptr, 0)); + else + { + expr = convert (objc_ivar_list_ptr, + build_unary_op (input_location, ADDR_EXPR, + ivar_list, 0)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + + /* objc_method_list = */ + if (!dispatch_table) + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + convert (objc_method_list_ptr, null_pointer_node)); + else + { + expr = convert (objc_method_list_ptr, + build_unary_op (input_location, ADDR_EXPR, + dispatch_table, 0)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + + if (flag_next_runtime) + { + ltyp = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier ("objc_cache"))); + /* method_cache = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, convert (ltyp, null_pointer_node)); + } + else + { + /* dtable = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); + + /* subclass_list = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); + + /* sibling_class = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); + } + + /* protocol_list = */ + ltyp = build_pointer_type (build_pointer_type (objc_protocol_template)); + if (! protocol_list) + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (ltyp, 0)); + else + { + expr = convert (ltyp, + build_unary_op (input_location, ADDR_EXPR, + protocol_list, 0)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + + if (flag_next_runtime) + /* sel_id = NULL */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); + + /* gc_object_type = NULL */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); + + return objc_build_constructor (type, v); +} + + +static tree +generate_ivars_list (tree chain, const char *name) +{ + tree initlist, ivar_list_template, decl; + int size; + VEC(constructor_elt,gc) *inits = NULL; + + if (!chain) + return NULL_TREE; + + if (!objc_ivar_template) + objc_ivar_template = build_ivar_template (); + + size = ivar_list_length (chain); + + generating_instance_variables = 1; + ivar_list_template = build_ivar_list_template (objc_ivar_template, size); + initlist = build_ivar_list_initializer (objc_ivar_template, chain); + generating_instance_variables = 0; + + decl = start_var_decl (ivar_list_template, name); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, build_int_cst (NULL_TREE, size)); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, initlist); + + OBJCMETA (decl, objc_meta, meta_base); + finish_var_decl (decl, + objc_build_constructor (TREE_TYPE (decl), inits)); + + return decl; +} + +/* static struct objc_class _OBJC_METACLASS_Foo={ ... }; + static struct objc_class _OBJC_CLASS_Foo={ ... }; */ + +static void +generate_class_structures (struct imp_entry *impent) +{ + tree name_expr, super_expr, root_expr, class_decl, meta_decl; + tree my_root_id, my_super_id; + tree cast_type, initlist, protocol_decl; + tree inst_methods = NULL_TREE, class_methods = NULL_TREE; + tree chain, inst_ivars = NULL_TREE, class_ivars = NULL_TREE; + location_t loc; + char buf[BUFSIZE]; + int cls_flags = 0 ; + +/* objc_implementation_context = impent->imp_context; + implementation_template = impent->imp_template;*/ + class_decl = impent->class_decl; + meta_decl = impent->meta_decl; +/* UOBJC_CLASS_decl = impent->class_decl; + UOBJC_METACLASS_decl = impent->meta_decl;*/ + + loc = DECL_SOURCE_LOCATION (impent->class_decl); + + my_super_id = CLASS_SUPER_NAME (impent->imp_template); + if (my_super_id) + { + add_class_reference (my_super_id); + + /* Compute "my_root_id" - this is required for code generation. + the "isa" for all meta class structures points to the root of + the inheritance hierarchy (e.g. "__Object")... */ + my_root_id = my_super_id; + do + { + tree my_root_int = lookup_interface (my_root_id); + + if (my_root_int && CLASS_SUPER_NAME (my_root_int)) + my_root_id = CLASS_SUPER_NAME (my_root_int); + else + break; + } + while (1); + } + else + /* No super class. */ + my_root_id = CLASS_NAME (impent->imp_template); + + cast_type = build_pointer_type (objc_class_template); + name_expr = add_objc_string (CLASS_NAME (impent->imp_template), + class_names); + + /* Install class `isa' and `super' pointers at runtime. */ + if (my_super_id) + super_expr = add_objc_string (my_super_id, class_names); + else + super_expr = null_pointer_node; + + super_expr = build_c_cast (loc, cast_type, super_expr); + + root_expr = add_objc_string (my_root_id, class_names); + root_expr = build_c_cast (loc, cast_type, root_expr); + + if (CLASS_PROTOCOL_LIST (impent->imp_template)) + { + generate_protocol_references (CLASS_PROTOCOL_LIST (impent->imp_template)); + protocol_decl = generate_protocol_list (impent->imp_template, + impent->imp_context); + } + else + protocol_decl = NULL_TREE; + + if (CLASS_CLS_METHODS (impent->imp_context)) + { + snprintf (buf, BUFSIZE, "_OBJC_ClassMethods_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + class_methods = generate_dispatch_table (CLASS_CLS_METHODS (impent->imp_context), + buf); + } + + if (CLASS_SUPER_NAME (impent->imp_template) == NULL_TREE + && (chain = TYPE_FIELDS (objc_class_template))) + { + snprintf (buf, BUFSIZE, "_OBJC_ClassIvars_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + class_ivars = generate_ivars_list (chain, buf); + } + + /* static struct objc_class _OBJC_METACLASS_Foo = { ... }; */ + + initlist = + build_shared_structure_initializer + (TREE_TYPE (meta_decl), + root_expr, super_expr, name_expr, + convert (integer_type_node, + TYPE_SIZE_UNIT (objc_class_template)), + CLS_META, class_methods, class_ivars, + protocol_decl); + + finish_var_decl (meta_decl, initlist); + impent->meta_decl = meta_decl; + + /* static struct objc_class _OBJC_CLASS_Foo={ ... }; */ + if (CLASS_NST_METHODS (impent->imp_context)) + { + snprintf (buf, BUFSIZE, "_OBJC_InstanceMethods_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + inst_methods = generate_dispatch_table (CLASS_NST_METHODS (impent->imp_context), + buf); + } + + if ((chain = CLASS_IVARS (impent->imp_template))) + { + snprintf (buf, BUFSIZE, "_OBJC_InstanceIvars_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + inst_ivars = generate_ivars_list (chain, buf); + } + + initlist = + build_shared_structure_initializer + (TREE_TYPE (class_decl), + build_unary_op (loc, ADDR_EXPR, meta_decl, 0), + super_expr, name_expr, + convert (integer_type_node, + TYPE_SIZE_UNIT (CLASS_STATIC_TEMPLATE + (impent->imp_template))), + CLS_FACTORY | cls_flags, inst_methods, inst_ivars, + protocol_decl); + + finish_var_decl (class_decl, initlist); + impent->class_decl = class_decl; +} + +/* --- Output GNU Metadata --- */ + +/* TODO: Make this into an array of refs. */ +static void +handle_class_ref (tree chain) +{ + const char *name = IDENTIFIER_POINTER (TREE_VALUE (chain)); + char *string = (char *) alloca (strlen (name) + 30); + tree decl; + tree exp; + + sprintf (string, "__objc_class_name_%s", name); + + /* 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), TREE_TYPE (integer_zero_node)); + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + DECL_CONTEXT (decl) = NULL_TREE; + finish_var_decl (decl, 0); + + /* Make a decl for the address. */ + 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; + TREE_USED (decl) = 1; + DECL_READ_P (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_INITIAL (decl) = error_mark_node; + + /* We must force the reference. */ + DECL_PRESERVE_P (decl) = 1; + + DECL_CONTEXT (decl) = NULL_TREE; + finish_var_decl (decl, exp); +} + +static tree +get_proto_encoding (tree proto) +{ + tree encoding; + if (proto) + { + if (! METHOD_ENCODING (proto)) + { + encoding = encode_method_prototype (proto); + METHOD_ENCODING (proto) = encoding; + } + else + encoding = METHOD_ENCODING (proto); + + return add_objc_string (encoding, meth_var_types); + } + else + return build_int_cst (NULL_TREE, 0); +} + +static void +build_gnu_selector_translation_table (void) +{ + tree chain, expr; + VEC(constructor_elt,gc) *inits = NULL; + VEC(constructor_elt,gc) *v ; + + /* Cause the selector table (previously forward-declared) + to be actually output. */ + + for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain)) + { + tree encoding; + if (warn_selector) + { + /* TODO: improve on the location for the diagnostic. */ + location_t loc = input_location; + diagnose_missing_method (TREE_VALUE (chain), loc); + } + + v = NULL; + expr = build_selector (TREE_VALUE (chain)); + encoding = get_proto_encoding (TREE_PURPOSE (chain)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, encoding); + expr = objc_build_constructor (objc_selector_template, v); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + } /* each element in the chain */ + + /* List terminator. */ + v = NULL; + 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); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + expr = objc_build_constructor (TREE_TYPE (UOBJC_SELECTOR_TABLE_decl), + inits); + finish_var_decl (UOBJC_SELECTOR_TABLE_decl, expr); +} + +/* Output references to all statically allocated objects. Return the DECL + for the array built. */ + +static void +generate_static_references (void) +{ + tree expr = NULL_TREE; + tree class_name, klass, decl; + tree cl_chain, in_chain, type + = build_array_type (build_pointer_type (void_type_node), NULL_TREE); + int num_inst, num_class; + char buf[BUFSIZE]; + VEC(constructor_elt,gc) *decls = NULL; + + if (flag_next_runtime) + gcc_unreachable (); + + for (cl_chain = objc_static_instances, num_class = 0; + cl_chain; cl_chain = TREE_CHAIN (cl_chain), num_class++) + { + VEC(constructor_elt,gc) *v = NULL; + + for (num_inst = 0, in_chain = TREE_PURPOSE (cl_chain); + in_chain; num_inst++, in_chain = TREE_CHAIN (in_chain)); + + snprintf (buf, BUFSIZE, "_OBJC_STATIC_INSTANCES_%d", num_class); + decl = start_var_decl (type, buf); + + /* Output {class_name, ...}. */ + klass = TREE_VALUE (cl_chain); + class_name = get_objc_string_decl (OBJC_TYPE_NAME (klass), class_names); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_unary_op (input_location, + ADDR_EXPR, class_name, 1)); + + /* Output {..., instance, ...}. */ + for (in_chain = TREE_PURPOSE (cl_chain); + in_chain; in_chain = TREE_CHAIN (in_chain)) + { + expr = build_unary_op (input_location, + ADDR_EXPR, TREE_VALUE (in_chain), 1); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + + /* Output {..., NULL}. */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); + + expr = objc_build_constructor (TREE_TYPE (decl), v); + OBJCMETA (decl, objc_meta, meta_base); + finish_var_decl (decl, expr); + CONSTRUCTOR_APPEND_ELT (decls, NULL_TREE, + build_unary_op (input_location, + ADDR_EXPR, decl, 1)); + } + + CONSTRUCTOR_APPEND_ELT (decls, NULL_TREE, build_int_cst (NULL_TREE, 0)); + expr = objc_build_constructor (type, decls); + static_instances_decl = start_var_decl (type, "_OBJC_STATIC_INSTANCES"); + OBJCMETA (static_instances_decl, objc_meta, meta_base); + finish_var_decl (static_instances_decl, expr); +} + +/* Create the initial value for the `defs' field of _objc_symtab. + This is a CONSTRUCTOR. */ + +static tree +init_def_list (tree type) +{ + tree expr; + struct imp_entry *impent; + location_t loc; + VEC(constructor_elt,gc) *v = NULL; + + if (imp_count) + for (impent = imp_list; impent; impent = impent->next) + { + if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) + { + loc = DECL_SOURCE_LOCATION (impent->class_decl); + expr = build_unary_op (loc, + ADDR_EXPR, impent->class_decl, 0); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + } + + if (cat_count) + for (impent = imp_list; impent; impent = impent->next) + { + if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE) + { + loc = DECL_SOURCE_LOCATION (impent->class_decl); + expr = build_unary_op (loc, + ADDR_EXPR, impent->class_decl, 0); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + } + + loc = UNKNOWN_LOCATION; + /* statics = { ..., _OBJC_STATIC_INSTANCES, ... } */ + if (static_instances_decl) + expr = build_unary_op (loc, ADDR_EXPR, static_instances_decl, 0); + else + expr = integer_zero_node; + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + return objc_build_constructor (type, v); +} + +/* Take care of defining and initializing _OBJC_SYMBOLS. */ + +/* Predefine the following data type: + + struct _objc_symtab + { + long sel_ref_cnt; + SEL *refs; + short cls_def_cnt; + short cat_def_cnt; + void *defs[cls_def_cnt + cat_def_cnt]; + }; */ + +static void +build_objc_symtab_template (void) +{ + tree fields, array_type, *chain = NULL; + int index; + + objc_symtab_template = objc_start_struct (get_identifier (UTAG_SYMTAB)); + + /* long sel_ref_cnt; */ + fields = add_field_decl (long_integer_type_node, "sel_ref_cnt", &chain); + + /* SEL *refs; */ + add_field_decl (build_pointer_type (objc_selector_type), "refs", &chain); + + /* short cls_def_cnt; */ + add_field_decl (short_integer_type_node, "cls_def_cnt", &chain); + + /* short cat_def_cnt; */ + add_field_decl (short_integer_type_node, "cat_def_cnt", &chain); + + if (TARGET_64BIT) + add_field_decl (integer_type_node, "_explicit_padder", &chain); + + /* void *defs[imp_count + cat_count (+ 1)]; */ + /* NB: The index is one less than the size of the array. */ + index = imp_count + cat_count; + array_type = build_sized_array_type (ptr_type_node, index + 1); + add_field_decl (array_type, "defs", &chain); + + objc_finish_struct (objc_symtab_template, fields); +} +/* Construct the initial value for all of _objc_symtab. */ + +static tree +init_objc_symtab (tree type) +{ + tree field, expr, ltyp; + location_t loc; + VEC(constructor_elt,gc) *v = NULL; + + loc = UNKNOWN_LOCATION; + + /* sel_ref_cnt = { ..., 5, ... } */ + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (long_integer_type_node, 0)); + + /* refs = { ..., _OBJC_SELECTOR_TABLE, ... } */ + + ltyp = build_pointer_type (objc_selector_type); + if (sel_ref_chain) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, + UOBJC_SELECTOR_TABLE_decl, 1)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + /* cls_def_cnt = { ..., 5, ... } */ + + 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 (short_integer_type_node, cat_count)); + if (TARGET_64BIT) + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (integer_type_node, 0)); + + /* cls_def = { ..., { &Foo, &Bar, ...}, ... } */ + + field = TYPE_FIELDS (type); + if (TARGET_64BIT) + field = DECL_CHAIN (field); + field = DECL_CHAIN (DECL_CHAIN (DECL_CHAIN (DECL_CHAIN (field)))); + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init_def_list (TREE_TYPE (field))); + + return objc_build_constructor (type, v); +} + +/* Create the declaration of _OBJC_SYMBOLS, with type `struct _objc_symtab' + and initialized appropriately. */ + +static void +generate_objc_symtab_decl (void) +{ + build_objc_symtab_template (); + UOBJC_SYMBOLS_decl = start_var_decl (objc_symtab_template, "_OBJC_SYMBOLS"); + OBJCMETA (UOBJC_SYMBOLS_decl, objc_meta, meta_base); + finish_var_decl (UOBJC_SYMBOLS_decl, + init_objc_symtab (TREE_TYPE (UOBJC_SYMBOLS_decl))); +} + +static void +objc_generate_v1_gnu_metadata (void) +{ + struct imp_entry *impent; + tree chain; + + /* Process the static instances here because initialization of objc_symtab + depends on them. */ + if (objc_static_instances) + generate_static_references (); + + objc_implementation_context = + implementation_template = + UOBJC_CLASS_decl = + UOBJC_METACLASS_decl = NULL_TREE; + + for (impent = imp_list; impent; impent = impent->next) + { + /* If -gen-decls is present, Dump the @interface of each class. + TODO: Dump the classes in the order they were found, rather than in + reverse order as we are doing now. */ + if (flag_gen_declaration) + dump_interface (gen_declaration_file, impent->imp_context); + + /* all of the following reference the string pool... */ + if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) + generate_class_structures (impent); + else + generate_category (impent); + } + + /* If we are using an array of selectors, we must always + finish up the array decl even if no selectors were used. */ + build_gnu_selector_translation_table (); + + if (protocol_chain) + generate_protocols (); + + /* Arrange for ObjC data structures to be initialized at run time. */ + generate_objc_symtab_decl (); + /* Make sure that the meta-data are identified as being GNU-runtime. */ + build_module_descriptor (OBJC_VERSION, + build_tree_list (objc_meta, meta_base)); + build_module_initializer_routine (); + + /* Dump the class references. This forces the appropriate classes + to be linked into the executable image, preserving unix archive + semantics. This can be removed when we move to a more dynamically + linked environment. */ + + for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain)) + { + handle_class_ref (chain); + if (TREE_PURPOSE (chain)) + generate_classref_translation_entry (chain); + } + + for (impent = imp_list; impent; impent = impent->next) + handle_impent (impent); + + generate_strings (); +} + +/* --- exceptions --- */ + +static GTY(()) tree objc_eh_personality_decl; + +static tree +objc_eh_runtime_type (tree type) +{ + tree ident, eh_id, decl, str; + + if (type == error_mark_node + || errorcount || sorrycount) + { + /* Use 'ErrorMarkNode' as class name when error_mark_node is found + to prevent an ICE. Note that we know that the compiler will + terminate with an error and this 'ErrorMarkNode' class name will + never be actually used. */ + ident = get_identifier ("ErrorMarkNode"); + goto make_err_class; + } + + if (POINTER_TYPE_P (type) && objc_is_object_id (TREE_TYPE (type))) + /* We don't want to identify 'id' for GNU. Instead, build a 0 + entry in the exceptions table. */ + return null_pointer_node; + + if (!POINTER_TYPE_P (type) || !TYPED_OBJECT (TREE_TYPE (type))) + { +#ifdef OBJCPLUS + /* This routine is also called for c++ catch clauses; in which case, + we use the c++ typeinfo decl. */ + return build_eh_type_type (type); +#else + error ("non-objective-c type '%T' cannot be caught", type); + ident = get_identifier ("ErrorMarkNode"); + goto make_err_class; +#endif + } + else + ident = OBJC_TYPE_NAME (TREE_TYPE (type)); + +make_err_class: + /* If this class was already referenced, then it will be output during + meta-data emission, so we don't need to do it here. */ + decl = get_objc_string_decl (ident, class_names); + eh_id = add_objc_string (ident, class_names); + if (!decl) + { + /* Not found ... so we need to build it - from the freshly-entered id. */ + decl = get_objc_string_decl (ident, class_names); + str = my_build_string (IDENTIFIER_LENGTH (ident) + 1, + IDENTIFIER_POINTER (ident)); + /* We have to finalize this var here, because this might be called after + all the other metadata strings have been emitted. */ + finish_var_decl (decl, str); + } + return eh_id; +} + +static tree +objc_eh_personality (void) +{ + if (!objc_eh_personality_decl) +#ifndef OBJCPLUS + objc_eh_personality_decl = build_personality_function ("gnu_objc"); +#else + objc_eh_personality_decl = build_personality_function ("gxx"); +#endif + return objc_eh_personality_decl; +} + +/* -- interfaces --- */ + +static tree +build_throw_stmt (location_t loc, tree throw_expr, bool rethrown ATTRIBUTE_UNUSED) +{ + tree t; + VEC(tree, gc) *parms = VEC_alloc (tree, gc, 1); + /* A throw is just a call to the runtime throw function with the + object as a parameter. */ + VEC_quick_push (tree, parms, throw_expr); + t = build_function_call_vec (loc, objc_exception_throw_decl, parms, NULL); + VEC_free (tree, gc, parms); + return add_stmt (t); +} + +/* Build __builtin_eh_pointer. */ + +static tree +objc_build_exc_ptr (struct objc_try_context **x ATTRIBUTE_UNUSED) +{ + tree t; + t = built_in_decls[BUILT_IN_EH_POINTER]; + t = build_call_expr (t, 1, integer_zero_node); + return fold_convert (objc_object_type, t); +} + +static tree +begin_catch (struct objc_try_context **cur_try_context, tree type, + tree decl, tree compound, bool ellipsis ATTRIBUTE_UNUSED) +{ + tree t; + /* Record the data for the catch in the try context so that we can + finalize it later. */ + if (ellipsis) + t = build_stmt (input_location, CATCH_EXPR, NULL, compound); + else + t = build_stmt (input_location, CATCH_EXPR, type, compound); + (*cur_try_context)->current_catch = t; + + /* Initialize the decl from the EXC_PTR_EXPR we get from the runtime. */ + t = objc_build_exc_ptr (cur_try_context); + t = convert (TREE_TYPE (decl), t); + return build2 (MODIFY_EXPR, void_type_node, decl, t); +} + +static void +finish_catch (struct objc_try_context **cur_try_context, tree current_catch) +{ + append_to_statement_list (current_catch, &((*cur_try_context)->catch_list)); +} + +static tree +finish_try_stmt (struct objc_try_context **cur_try_context) +{ + struct objc_try_context *c = *cur_try_context; + tree stmt = c->try_body; + if (c->catch_list) + stmt = build_stmt (c->try_locus, TRY_CATCH_EXPR, stmt, c->catch_list); + if (c->finally_body) + stmt = build_stmt (c->try_locus, TRY_FINALLY_EXPR, stmt, c->finally_body); + return stmt; +} + +#include "gt-objc-objc-gnu-runtime-abi-01.h" diff --git a/gcc/objc/objc-lang.c b/gcc/objc/objc-lang.c index e4ae292..fd657765 100644 --- a/gcc/objc/objc-lang.c +++ b/gcc/objc/objc-lang.c @@ -1,5 +1,5 @@ /* Language-dependent hooks for Objective-C. - Copyright 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2010 + Copyright 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2010, 2011 Free Software Foundation, Inc. Contributed by Ziemowit Laski <zlaski@apple.com> @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "langhooks.h" #include "langhooks-def.h" #include "c-objc-common.h" +#include "c-lang.h" enum c_language_kind c_language = clk_objc; static void objc_init_ts (void); @@ -51,13 +52,6 @@ static void objc_init_ts (void); #undef LANG_HOOKS_INIT_TS #define LANG_HOOKS_INIT_TS objc_init_ts -#ifndef OBJCPLUS -#undef LANG_HOOKS_EH_PERSONALITY -#define LANG_HOOKS_EH_PERSONALITY objc_eh_personality -#undef LANG_HOOKS_EH_RUNTIME_TYPE -#define LANG_HOOKS_EH_RUNTIME_TYPE objc_eh_runtime_type -#endif - /* Each front end provides its own lang hook initializer. */ struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; diff --git a/gcc/objc/objc-next-metadata-tags.h b/gcc/objc/objc-next-metadata-tags.h new file mode 100644 index 0000000..db0026e --- /dev/null +++ b/gcc/objc/objc-next-metadata-tags.h @@ -0,0 +1,172 @@ +/* Declarations for meta-data attribute tags. + Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by Iain Sandoe + +This file is part of GCC. + +GCC 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, or (at your option) +any later version. + +GCC 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/>. */ + +/* These are identifiers used to flag meta-data attributes such that they + survive LTO and might be placed in correct sections for the target. */ + +enum objc_runtime_tree_index +{ + OCTI_RT_OBJC_META, + OCTI_RT_META_BASE, + + OCTI_RT_META_CLASS, + OCTI_RT_META_METACLASS, + OCTI_RT_META_CATEGORY, + OCTI_RT_META_PROTOCOL, + + OCTI_RT_META_CLASS_CLS_VARS, + OCTI_RT_META_CLASS_NST_VARS, + + OCTI_RT_META_CLASS_CLS_METH, + OCTI_RT_META_CLASS_NST_METH, + OCTI_RT_META_CATEG_CLS_METH, + OCTI_RT_META_CATEG_NST_METH, + OCTI_RT_META_PROTO_CLS_METH, + OCTI_RT_META_PROTO_NST_METH, + + OCTI_RT_META_CLASS_PROT, + OCTI_RT_META_CATEG_PROT, + OCTI_RT_META_PROT_REFS, + + OCTI_RT_META_MSG_REFS, + OCTI_RT_META_SEL_REFS, + + OCTI_RT_META_CLSLST_REFS, + OCTI_RT_META_CLASS_REF, + OCTI_RT_META_SUPER_REF, + OCTI_RT_META_CLSLST_NLZY_LAB, + OCTI_RT_META_CLSLST_LAB, + OCTI_RT_META_LAB_PROTOLIST, + OCTI_RT_META_LAB_NLZY_CAT, + OCTI_RT_META_LAB_CAT, + + OCTI_RT_META_PROPERTY_LIST, + OCTI_RT_META_PROTOCOL_EXT, + OCTI_RT_META_CLASS_EXT, + + OCTI_RT_META_CLASS_NAME, + OCTI_RT_META_METHD_NAME, + OCTI_RT_META_METHD_TYPE, + OCTI_RT_META_PROPN_ATTR, + + OCTI_RT_META_MODULES, + OCTI_RT_META_SYMTAB, + OCTI_RT_META_INFO, + + OCTI_RT_META_EHTYPE, + + OCTI_RT_META_CONST_STR, + + OCTI_RT_META_MAX +}; + +/* Tags for the META data so that the backend can put them in the correct + sections for targets/runtimes (Darwin/NeXT) that require this. + This information also survives LTO - which might produce mixed language + output. */ + +/* Objective-C meta data attribute tag */ +#define objc_meta objc_rt_trees[OCTI_RT_OBJC_META] +/* Attribute values, base = default section. */ +#define meta_base objc_rt_trees[OCTI_RT_META_BASE] + + /* CLASS. */ +#define meta_class objc_rt_trees[OCTI_RT_META_CLASS] + /* METACLASS. */ +#define meta_metaclass objc_rt_trees[OCTI_RT_META_METACLASS] + /* CLASS. */ +#define meta_category objc_rt_trees[OCTI_RT_META_CATEGORY] + /* PROTOCOL. */ +#define meta_protocol objc_rt_trees[OCTI_RT_META_PROTOCOL] + + /* Class class vars section. */ +#define meta_clac_vars objc_rt_trees[OCTI_RT_META_CLASS_CLS_VARS] + /* Class instance vars section. */ +#define meta_clai_vars objc_rt_trees[OCTI_RT_META_CLASS_NST_VARS] + /* Class class methods section. */ +#define meta_clac_meth objc_rt_trees[OCTI_RT_META_CLASS_CLS_METH] + /* Class instance methods section. */ +#define meta_clai_meth objc_rt_trees[OCTI_RT_META_CLASS_NST_METH] + /* Category class methods section. */ +#define meta_catc_meth objc_rt_trees[OCTI_RT_META_CATEG_CLS_METH] + /* Category instance methods section. */ +#define meta_cati_meth objc_rt_trees[OCTI_RT_META_CATEG_NST_METH] +#define meta_proto_cls_meth \ + objc_rt_trees[OCTI_RT_META_PROTO_CLS_METH] +#define meta_proto_nst_meth \ + objc_rt_trees[OCTI_RT_META_PROTO_NST_METH] + + /* Class protocols. */ +#define meta_clas_prot objc_rt_trees[OCTI_RT_META_CLASS_PROT] + /* Category protocols. */ +#define meta_catg_prot objc_rt_trees[OCTI_RT_META_CATEG_PROT] + /* Protocol references. */ +#define meta_proto_ref objc_rt_trees[OCTI_RT_META_PROT_REFS] + + /* Message refs. */ +#define meta_mref objc_rt_trees[OCTI_RT_META_MSG_REFS] + /* Selector refs. */ +#define meta_sel_refs objc_rt_trees[OCTI_RT_META_SEL_REFS] + + /* Class list refs. */ +#define meta_class_ref objc_rt_trees[OCTI_RT_META_CLSLST_REFS] +#define meta_class_reference \ + objc_rt_trees[OCTI_RT_META_CLASS_REF] +#define meta_superclass_ref \ + objc_rt_trees[OCTI_RT_META_SUPER_REF] + /* Class list Label. */ +#define meta_label_classlist \ + objc_rt_trees[OCTI_RT_META_CLSLST_LAB] + /* Class list Label (non lazy). */ +#define meta_label_nonlazy_classlist \ + objc_rt_trees[OCTI_RT_META_CLSLST_NLZY_LAB] +#define meta_label_categorylist \ + objc_rt_trees[OCTI_RT_META_LAB_CAT] +#define meta_label_nonlazy_categorylist \ + objc_rt_trees[OCTI_RT_META_LAB_NLZY_CAT] + +#define meta_label_protocollist \ + objc_rt_trees[OCTI_RT_META_LAB_PROTOLIST] + + +/* V1 - property list. */ +#define meta_proplist objc_rt_trees[OCTI_RT_META_PROPERTY_LIST] +#define meta_protocol_extension \ + objc_rt_trees[OCTI_RT_META_PROTOCOL_EXT] +#define meta_class_extension \ + objc_rt_trees[OCTI_RT_META_CLASS_EXT] + /* String sections. */ +#define meta_class_name objc_rt_trees[OCTI_RT_META_CLASS_NAME] +#define meta_meth_name objc_rt_trees[OCTI_RT_META_METHD_NAME] +#define meta_meth_type objc_rt_trees[OCTI_RT_META_METHD_TYPE] +#define meta_prop_name_attr \ + objc_rt_trees[OCTI_RT_META_PROPN_ATTR] + +#define meta_modules objc_rt_trees[OCTI_RT_META_MODULES] +#define meta_symtab objc_rt_trees[OCTI_RT_META_SYMTAB] +#define meta_info objc_rt_trees[OCTI_RT_META_INFO] + +#define meta_ehtype objc_rt_trees[OCTI_RT_META_EHTYPE] + +#define meta_const_str objc_rt_trees[OCTI_RT_META_CONST_STR] + +#define OBJCMETA(DECL,VERS,KIND) \ + if (VERS) \ + DECL_ATTRIBUTES (DECL) = build_tree_list ((VERS), (KIND)); diff --git a/gcc/objc/objc-next-runtime-abi-01.c b/gcc/objc/objc-next-runtime-abi-01.c new file mode 100644 index 0000000..2cfa862 --- /dev/null +++ b/gcc/objc/objc-next-runtime-abi-01.c @@ -0,0 +1,2969 @@ +/* Next Runtime (ABI-0/1) private. + Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by Iain Sandoe (split from objc-act.c) + +This file is part of GCC. + +GCC 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, or (at your option) +any later version. + +GCC 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/>. */ + +/* This implements the original NeXT ABI (0) used for m32 code and indicated + by module version 6. It also implements the small number of additions made + for properties and optional protocol methods as ABI=1 + (module version 7). */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" + +#ifdef OBJCPLUS +#include "cp-tree.h" +#else +#include "c-tree.h" +#include "c-lang.h" +#endif +#include "langhooks.h" +#include "c-family/c-objc.h" +#include "objc-act.h" + +/* When building Objective-C++, we are not linking against the C front-end + and so need to replicate the C tree-construction functions in some way. */ +#ifdef OBJCPLUS +#define OBJCP_REMAP_FUNCTIONS +#include "objcp-decl.h" +#endif /* OBJCPLUS */ + +#include "ggc.h" +#include "target.h" +#include "output.h" +#include "tree-iterator.h" + +#include "objc-runtime-hooks.h" +#include "objc-runtime-shared-support.h" + +/* NeXT ABI 0 and 1 private definitions. */ +#define DEF_CONSTANT_STRING_CLASS_NAME "NSConstantString" + +#define TAG_GETCLASS "objc_getClass" +#define TAG_GETMETACLASS "objc_getMetaClass" + +#define TAG_MSGSEND "objc_msgSend" +#define TAG_MSGSENDSUPER "objc_msgSendSuper" +#define TAG_MSGSEND_STRET "objc_msgSend_stret" +#define TAG_MSGSENDSUPER_STRET "objc_msgSendSuper_stret" + +/* NeXT-specific tags. */ + +#define TAG_MSGSEND_NONNIL "objc_msgSendNonNil" +#define TAG_MSGSEND_NONNIL_STRET "objc_msgSendNonNil_stret" +#define TAG_EXCEPTIONEXTRACT "objc_exception_extract" +#define TAG_EXCEPTIONTRYENTER "objc_exception_try_enter" +#define TAG_EXCEPTIONTRYEXIT "objc_exception_try_exit" +#define TAG_EXCEPTIONMATCH "objc_exception_match" +#define TAG_SETJMP "_setjmp" + +#define TAG_ASSIGNIVAR "objc_assign_ivar" +#define TAG_ASSIGNGLOBAL "objc_assign_global" +#define TAG_ASSIGNSTRONGCAST "objc_assign_strongCast" + +/* Branch entry points. All that matters here are the addresses; + functions with these names do not really exist in libobjc. */ + +#define TAG_MSGSEND_FAST "objc_msgSend_Fast" +#define TAG_ASSIGNIVAR_FAST "objc_assign_ivar_Fast" + +/* The version identifies which language generation and runtime + the module (file) was compiled for, and is recorded in the + module descriptor. */ +#define OBJC_VERSION (flag_objc_abi >= 1 ? 7 : 6) + +#define UTAG_CLASS_EXT "_objc_class_ext" +#define UTAG_PROPERTY_LIST "_prop_list_t" +#define UTAG_PROTOCOL_EXT "_objc_protocol_extension" + +#define CLS_HAS_CXX_STRUCTORS 0x2000L + +/* rt_trees identifiers - shared between NeXT implementations. These allow + the FE to tag meta-data in a manner that survives LTO and can be used when + the runtime requires that certain meta-data items appear in particular + named sections. */ + +#include "objc-next-metadata-tags.h" +extern GTY(()) tree objc_rt_trees[OCTI_RT_META_MAX]; + +static void next_runtime_01_initialize (void); + +static tree next_runtime_abi_01_super_superclassfield_id (void); + +static tree next_runtime_abi_01_class_decl (tree); +static tree next_runtime_abi_01_metaclass_decl (tree); +static tree next_runtime_abi_01_category_decl (tree); +static tree next_runtime_abi_01_protocol_decl (tree); +static tree next_runtime_abi_01_string_decl (tree, const char *, string_section); + +static tree next_runtime_abi_01_get_class_reference (tree); +static tree next_runtime_abi_01_build_selector_reference (location_t, tree, tree); +static tree next_runtime_abi_01_get_protocol_reference (location_t, tree); +static tree next_runtime_abi_01_build_ivar_ref (location_t, tree, tree); +static tree next_runtime_abi_01_get_class_super_ref (location_t, struct imp_entry *, bool); +static tree next_runtime_abi_01_get_category_super_ref (location_t, struct imp_entry *, bool); + +static tree next_runtime_abi_01_receiver_is_class_object (tree); +static tree next_runtime_abi_01_get_arg_type_list_base (tree, int, int); +static tree next_runtime_abi_01_build_objc_method_call (location_t, tree, tree, + tree, tree, tree, int); +static bool next_runtime_abi_01_setup_const_string_class_decl (void); +static tree next_runtime_abi_01_build_const_string_constructor (location_t, tree, int); + +static void objc_generate_v1_next_metadata (void); + +static void build_next_objc_exception_stuff (void); +static tree objc_eh_runtime_type (tree type); +static tree objc_eh_personality (void); +static tree build_throw_stmt (location_t, tree, bool); +static tree objc_build_exc_ptr (struct objc_try_context **); +static tree begin_catch (struct objc_try_context **, tree, tree, tree, bool); +static void finish_catch (struct objc_try_context **, tree); +static tree finish_try_stmt (struct objc_try_context **); + +bool +objc_next_runtime_abi_01_init (objc_runtime_hooks *rthooks) +{ + if (flag_objc_exceptions + && !flag_objc_sjlj_exceptions) + { + warning_at (UNKNOWN_LOCATION, OPT_Wall, + "%<-fobjc-sjlj-exceptions%> is the only supported exceptions " + "system for %<-fnext-runtime%> with %<-fobjc-abi-version%> < 2"); + } + + rthooks->initialize = next_runtime_01_initialize; + rthooks->default_constant_string_class_name = DEF_CONSTANT_STRING_CLASS_NAME; + rthooks->tag_getclass = TAG_GETCLASS; + rthooks->super_superclassfield_ident = next_runtime_abi_01_super_superclassfield_id; + + rthooks->class_decl = next_runtime_abi_01_class_decl; + rthooks->metaclass_decl = next_runtime_abi_01_metaclass_decl; + rthooks->category_decl = next_runtime_abi_01_category_decl; + rthooks->protocol_decl = next_runtime_abi_01_protocol_decl; + rthooks->string_decl = next_runtime_abi_01_string_decl; + + rthooks->get_class_reference = next_runtime_abi_01_get_class_reference; + rthooks->build_selector_reference = next_runtime_abi_01_build_selector_reference; + rthooks->get_protocol_reference = next_runtime_abi_01_get_protocol_reference; + rthooks->build_ivar_reference = next_runtime_abi_01_build_ivar_ref; + rthooks->get_class_super_ref = next_runtime_abi_01_get_class_super_ref; + rthooks->get_category_super_ref = next_runtime_abi_01_get_category_super_ref; + + rthooks->receiver_is_class_object = next_runtime_abi_01_receiver_is_class_object; + rthooks->get_arg_type_list_base = next_runtime_abi_01_get_arg_type_list_base; + rthooks->build_objc_method_call = next_runtime_abi_01_build_objc_method_call; + + rthooks->setup_const_string_class_decl = + next_runtime_abi_01_setup_const_string_class_decl; + rthooks->build_const_string_constructor = + next_runtime_abi_01_build_const_string_constructor; + + rthooks->build_throw_stmt = build_throw_stmt; + rthooks->build_exc_ptr = objc_build_exc_ptr; + rthooks->begin_catch = begin_catch; + rthooks->finish_catch = finish_catch; + rthooks->finish_try_stmt = finish_try_stmt; + + rthooks->generate_metadata = objc_generate_v1_next_metadata; + return true; +} + +/* We need a way to convey what kind of meta-data are represented by a given + variable, since each type is expected (by the runtime) to be found in a + specific named section. The solution must be usable with LTO. + + The scheme used for NeXT ABI 0/1 (partial matching of variable names) is not + satisfactory for LTO & ABI-2. We now tag ObjC meta-data with identification + attributes in the front end. The back-end may choose to act on these as it + requires. */ + +static void +next_runtime_abi_01_init_metadata_attributes (void) +{ + if (!objc_meta) + objc_meta = get_identifier ("OBJC1META"); + + if (!meta_base) + meta_base = get_identifier ("V1_BASE"); + + meta_class = get_identifier ("V1_CLAS"); + meta_metaclass = get_identifier ("V1_META"); + meta_category = get_identifier ("V1_CATG"); + meta_protocol = get_identifier ("V1_PROT"); + + meta_clac_vars = get_identifier ("V1_CLCV"); + meta_clai_vars = get_identifier ("V1_CLIV"); + + meta_clac_meth = get_identifier ("V1_CLCM"); + meta_clai_meth = get_identifier ("V1_CLIM"); + meta_catc_meth = get_identifier ("V1_CACM"); + meta_cati_meth = get_identifier ("V1_CAIM"); + meta_proto_cls_meth = get_identifier ("V1_PCLM"); + meta_proto_nst_meth = get_identifier ("V1_PNSM"); + + meta_clas_prot = get_identifier ("V1_CLPR"); + meta_catg_prot = get_identifier ("V1_CAPR"); + + meta_class_reference = get_identifier ("V1_CLRF"); + meta_proto_ref = get_identifier ("V1_PRFS"); + meta_sel_refs = get_identifier ("V1_SRFS"); + + meta_class_name = get_identifier ("V1_CLSN"); + meta_meth_name = get_identifier ("V1_METN"); + meta_meth_type = get_identifier ("V1_METT"); + meta_prop_name_attr = get_identifier ("V1_STRG"); + + meta_modules = get_identifier ("V1_MODU"); + meta_symtab = get_identifier ("V1_SYMT"); + meta_info = get_identifier ("V1_INFO"); + + meta_proplist = get_identifier ("V1_PLST"); + meta_protocol_extension = get_identifier ("V1_PEXT"); + meta_class_extension = get_identifier ("V1_CEXT"); + + meta_const_str = get_identifier ("V1_CSTR"); +} + +static void build_v1_class_template (void); +static void build_v1_category_template (void); +static void build_v1_protocol_template (void); + +static void next_runtime_01_initialize (void) +{ + tree type; + +#ifdef OBJCPLUS + /* For all NeXT objc ABIs -fobjc-call-cxx-cdtors is on by default. */ + if (!global_options_set.x_flag_objc_call_cxx_cdtors) + global_options.x_flag_objc_call_cxx_cdtors = 1; +#endif + + /* Set up attributes to be attached to the meta-data so that they + will be placed in the correct sections. */ + next_runtime_abi_01_init_metadata_attributes (); + + if (flag_objc_abi >= 1) + objc_prop_list_ptr = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier ("_prop_list_t"))); + + /* Declare type of selector-objects that represent an operation name. */ + /* `struct objc_selector *' */ + objc_selector_type = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (TAG_SELECTOR))); + + build_v1_class_template (); + build_super_template (); + build_v1_protocol_template (); + build_v1_category_template (); + + /* NB: In order to call one of the ..._stret (struct-returning) + functions, the function *MUST* first be cast to a signature that + corresponds to the actual ObjC method being invoked. This is + what is done by the build_objc_method_call() routine below. */ + + /* id objc_msgSend (id, SEL, ...); */ + /* id objc_msgSendNonNil (id, SEL, ...); */ + /* id objc_msgSend_stret (id, SEL, ...); */ + /* id objc_msgSendNonNil_stret (id, SEL, ...); */ + type = build_varargs_function_type_list (objc_object_type, + objc_object_type, + objc_selector_type, + NULL_TREE); + + umsg_decl = add_builtin_function (TAG_MSGSEND, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + umsg_nonnil_decl = add_builtin_function (TAG_MSGSEND_NONNIL, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + umsg_stret_decl = add_builtin_function (TAG_MSGSEND_STRET, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + umsg_nonnil_stret_decl = add_builtin_function (TAG_MSGSEND_NONNIL_STRET, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + /* These can throw, because the function that gets called can throw + in Obj-C++, or could itself call something that can throw even + in Obj-C. */ + TREE_NOTHROW (umsg_decl) = 0; + TREE_NOTHROW (umsg_nonnil_decl) = 0; + TREE_NOTHROW (umsg_stret_decl) = 0; + TREE_NOTHROW (umsg_nonnil_stret_decl) = 0; + + /* id objc_msgSend_Fast (id, SEL, ...) + __attribute__ ((hard_coded_address (OFFS_MSGSEND_FAST))); */ +#ifdef OFFS_MSGSEND_FAST + umsg_fast_decl = add_builtin_function (TAG_MSGSEND_FAST, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (umsg_fast_decl) = 0; + DECL_ATTRIBUTES (umsg_fast_decl) + = tree_cons (get_identifier ("hard_coded_address"), + build_int_cst (NULL_TREE, OFFS_MSGSEND_FAST), + NULL_TREE); +#else + /* No direct dispatch available. */ + umsg_fast_decl = umsg_decl; +#endif + + /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */ + /* id objc_msgSendSuper_stret (struct objc_super *, SEL, ...); */ + type = build_varargs_function_type_list (objc_object_type, + objc_super_type, + objc_selector_type, + NULL_TREE); + umsg_super_decl = add_builtin_function (TAG_MSGSENDSUPER, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + umsg_super_stret_decl = add_builtin_function (TAG_MSGSENDSUPER_STRET, + type, 0, NOT_BUILT_IN, 0, + NULL_TREE); + TREE_NOTHROW (umsg_super_decl) = 0; + TREE_NOTHROW (umsg_super_stret_decl) = 0; + + type = build_function_type_list (objc_object_type, + const_string_type_node, + NULL_TREE); + + /* id objc_getClass (const char *); */ + objc_get_class_decl + = add_builtin_function (TAG_GETCLASS, type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + /* id objc_getMetaClass (const char *); */ + objc_get_meta_class_decl + = add_builtin_function (TAG_GETMETACLASS, type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + + /* This is the type of all of the following functions objc_copyStruct(). */ + type = build_function_type_list (void_type_node, + ptr_type_node, + const_ptr_type_node, + ptrdiff_type_node, + boolean_type_node, + boolean_type_node, + NULL_TREE); + /* Declare the following function: + void + objc_copyStruct (void *destination, const void *source, + ptrdiff_t size, BOOL is_atomic, BOOL has_strong); */ + objc_copyStruct_decl = add_builtin_function ("objc_copyStruct", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (objc_copyStruct_decl) = 0; + objc_getPropertyStruct_decl = NULL_TREE; + objc_setPropertyStruct_decl = NULL_TREE; + + build_next_objc_exception_stuff (); + if (flag_objc_exceptions && !flag_objc_sjlj_exceptions) + using_eh_for_cleanups (); + lang_hooks.eh_runtime_type = objc_eh_runtime_type; + lang_hooks.eh_personality = objc_eh_personality; +} + +/* --- templates --- */ + +/* struct _objc_class { + struct _objc_class *isa; + struct _objc_class *super_class; + char *name; + long version; + long info; + long instance_size; + struct _objc_ivar_list *ivars; + struct _objc_method_list *methods; + struct objc_cache *cache; + struct _objc_protocol_list *protocols; + #if ABI=1 + const char *ivar_layout; + struct _objc_class_ext *ext; + #else + void *sel_id; + void *gc_object_type; + #endif + }; */ + +/* The 'sel_id' & 'gc_object_type' fields are not used by the NeXT runtime. + We generate them for ABI==0 to maintain backward binary compatibility. */ + +static void +build_v1_class_template (void) +{ + tree ptype, decls, *chain = NULL; + + objc_class_template = objc_start_struct (get_identifier (UTAG_CLASS)); + + /* struct _objc_class *isa; */ + decls = add_field_decl (build_pointer_type (objc_class_template), + "isa", &chain); + + /* struct _objc_class *super_class; */ + add_field_decl (build_pointer_type (objc_class_template), + "super_class", &chain); + + /* char *name; */ + add_field_decl (string_type_node, "name", &chain); + + /* long version; */ + add_field_decl (long_integer_type_node, "version", &chain); + + /* long info; */ + add_field_decl (long_integer_type_node, "info", &chain); + + /* long instance_size; */ + add_field_decl (long_integer_type_node, "instance_size", &chain); + + /* struct _objc_ivar_list *ivars; */ + add_field_decl (objc_ivar_list_ptr,"ivars", &chain); + + /* struct _objc_method_list *methods; */ + add_field_decl (objc_method_list_ptr, "methods", &chain); + + /* struct objc_cache *cache; */ + ptype = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier ("objc_cache"))); + add_field_decl (ptype, "cache", &chain); + + /* struct _objc_protocol **protocol_list; */ + ptype = build_pointer_type (build_pointer_type + (xref_tag (RECORD_TYPE, + get_identifier (UTAG_PROTOCOL)))); + add_field_decl (ptype, "protocol_list", &chain); + + if (flag_objc_abi >= 1) + { + /* const char *ivar_layout; */ + add_field_decl (const_string_type_node, "ivar_layout", &chain); + + /* struct _objc_class_ext *ext; */ + ptype = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (UTAG_CLASS_EXT))); + add_field_decl (ptype, "ext", &chain); + } + else + { + /* void *sel_id; */ + add_field_decl (build_pointer_type (void_type_node), "sel_id", &chain); + /* void *gc_object_type; */ + add_field_decl (build_pointer_type (void_type_node), "gc_object_type", + &chain); + } + + objc_finish_struct (objc_class_template, decls); +} + +/* struct _objc_category { + char *category_name; + char *class_name; + struct _objc_method_list *instance_methods; + struct _objc_method_list *class_methods; + struct _objc_protocol_list *protocols; + if ABI=1 + uint32_t size; // sizeof (struct _objc_category) + struct _objc_property_list *instance_properties; // category's own @property decl. + END + }; */ + +static void +build_v1_category_template (void) +{ + tree ptype, decls, *chain = NULL; + + objc_category_template = objc_start_struct (get_identifier (UTAG_CATEGORY)); + + /* char *category_name; */ + decls = add_field_decl (string_type_node, "category_name", &chain); + + /* char *class_name; */ + add_field_decl (string_type_node, "class_name", &chain); + + /* struct _objc_method_list *instance_methods; */ + add_field_decl (objc_method_list_ptr, "instance_methods", &chain); + + /* struct _objc_method_list *class_methods; */ + add_field_decl (objc_method_list_ptr, "class_methods", &chain); + + /* struct _objc_protocol **protocol_list; */ + ptype = build_pointer_type (build_pointer_type (objc_protocol_template)); + add_field_decl (ptype, "protocol_list", &chain); + + if (flag_objc_abi >= 1) + { + add_field_decl (integer_type_node, "size", &chain); + + /* struct _objc_property_list *instance_properties; + This field describes a category's @property declarations. + Properties from inherited protocols are not included. */ + ptype = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (UTAG_PROPERTY_LIST))); + add_field_decl (ptype, "instance_properties", &chain); + } + objc_finish_struct (objc_category_template, decls); +} + +/* Begin code generation for protocols... + Modified for ObjC #1 extensions. */ + +/* struct _objc_protocol { + IF ABI=1 + struct _objc_protocol_extension *isa; + ElSE + struct _objc_class *isa; + + char *protocol_name; + struct _objc_protocol **protocol_list; + struct _objc__method_prototype_list *instance_methods; + struct _objc__method_prototype_list *class_methods; + }; */ + +static void +build_v1_protocol_template (void) +{ + tree ptype, decls, *chain = NULL; + + objc_protocol_template = objc_start_struct (get_identifier (UTAG_PROTOCOL)); + + if (flag_objc_abi >= 1) + /* struct _objc_protocol_extension *isa; */ + ptype = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (UTAG_PROTOCOL_EXT))); + else + /* struct _objc_class *isa; */ + ptype = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (UTAG_CLASS))); + + decls = add_field_decl (ptype, "isa", &chain); + + /* char *protocol_name; */ + add_field_decl (string_type_node, "protocol_name", &chain); + + /* struct _objc_protocol **protocol_list; */ + ptype = build_pointer_type (build_pointer_type (objc_protocol_template)); + add_field_decl (ptype, "protocol_list", &chain); + + /* struct _objc__method_prototype_list *instance_methods; */ + add_field_decl (objc_method_proto_list_ptr, "instance_methods", &chain); + + /* struct _objc__method_prototype_list *class_methods; */ + add_field_decl (objc_method_proto_list_ptr, "class_methods", &chain); + + objc_finish_struct (objc_protocol_template, decls); +} + +/* --- names, decls identifers --- */ + +static tree +next_runtime_abi_01_super_superclassfield_id (void) +{ + if (!super_superclassfield_id) + super_superclassfield_id = get_identifier ("super_class"); + return super_superclassfield_id; +} + +static tree +next_runtime_abi_01_class_decl (tree klass) +{ + tree decl; + char buf[BUFSIZE]; + snprintf (buf, BUFSIZE, "_OBJC_Class_%s", + IDENTIFIER_POINTER (CLASS_NAME (klass))); + decl = start_var_decl (objc_class_template, buf); + OBJCMETA (decl, objc_meta, meta_class); + return decl; +} + +static tree +next_runtime_abi_01_metaclass_decl (tree klass) +{ + tree decl; + char buf[BUFSIZE]; + snprintf (buf, BUFSIZE, "_OBJC_MetaClass_%s", + IDENTIFIER_POINTER (CLASS_NAME (klass))); + decl = start_var_decl (objc_class_template, buf); + OBJCMETA (decl, objc_meta, meta_metaclass); + return decl; +} + +static tree +next_runtime_abi_01_category_decl (tree klass) +{ + tree decl; + char buf[BUFSIZE]; + snprintf (buf, BUFSIZE, "_OBJC_Category_%s_on_%s", + IDENTIFIER_POINTER (CLASS_SUPER_NAME (klass)), + IDENTIFIER_POINTER (CLASS_NAME (klass))); + decl = start_var_decl (objc_category_template, buf); + OBJCMETA (decl, objc_meta, meta_category); + return decl; +} + +static tree +next_runtime_abi_01_protocol_decl (tree p) +{ + tree decl; + char buf[BUFSIZE]; + + /* static struct _objc_protocol _OBJC_Protocol_<mumble>; */ + + snprintf (buf, BUFSIZE, "_OBJC_Protocol_%s", + IDENTIFIER_POINTER (PROTOCOL_NAME (p))); + decl = start_var_decl (objc_protocol_template, buf); + OBJCMETA (decl, objc_meta, meta_protocol); + return decl; +} + +static tree +next_runtime_abi_01_string_decl (tree type, const char *name, string_section where) +{ + tree var = start_var_decl (type, name); + switch (where) + { + case class_names: + OBJCMETA (var, objc_meta, meta_class_name); + break; + case meth_var_names: + OBJCMETA (var, objc_meta, meta_meth_name); + break; + case meth_var_types: + OBJCMETA (var, objc_meta, meta_meth_type); + break; + case prop_names_attr: + OBJCMETA (var, objc_meta, meta_prop_name_attr); + break; + default: + OBJCMETA (var, objc_meta, meta_base); + break; + } + return var; +} + +/* --- entry --- */ + +static GTY(()) int class_reference_idx; + +static tree +build_class_reference_decl (void) +{ + tree decl; + char buf[BUFSIZE]; + + sprintf (buf, "_OBJC_ClassRefs_%d", class_reference_idx++); + decl = start_var_decl (objc_class_type, buf); + + return decl; +} + +static tree +next_runtime_abi_01_get_class_reference (tree ident) +{ + if (!flag_zero_link) + { + tree *chain; + tree decl; + + for (chain = &cls_ref_chain; *chain; chain = &TREE_CHAIN (*chain)) + if (TREE_VALUE (*chain) == ident) + { + if (! TREE_PURPOSE (*chain)) + TREE_PURPOSE (*chain) = build_class_reference_decl (); + + return TREE_PURPOSE (*chain); + } + + decl = build_class_reference_decl (); + *chain = tree_cons (decl, ident, NULL_TREE); + return decl; + } + else + { + tree params; + + add_class_reference (ident); + + params = build_tree_list (NULL_TREE, + my_build_string_pointer + (IDENTIFIER_LENGTH (ident) + 1, + IDENTIFIER_POINTER (ident))); + + return build_function_call (input_location, objc_get_class_decl, params); + } +} + +/* Used by get_arg_type_list. + Return the types for receiver & _cmd at the start of a method argument list. + context is either METHOD_DEF or METHOD_REF, saying whether we are trying + to define a method or call one. superflag says this is for a send to super. + meth may be NULL, in the case that there is no prototype. */ + +static tree +next_runtime_abi_01_get_arg_type_list_base (tree meth, int context, int superflag) +{ + tree arglist; + + /* Receiver type. */ + if (superflag) + arglist = build_tree_list (NULL_TREE, objc_super_type); + else if (context == METHOD_DEF && TREE_CODE (meth) == INSTANCE_METHOD_DECL) + arglist = build_tree_list (NULL_TREE, objc_instance_type); + else + arglist = build_tree_list (NULL_TREE, objc_object_type); + + /* Selector type - will eventually change to `int'. */ + chainon (arglist, build_tree_list (NULL_TREE, objc_selector_type)); + return arglist; +} + +static tree +next_runtime_abi_01_receiver_is_class_object (tree receiver) +{ + if (TREE_CODE (receiver) == VAR_DECL + && IS_CLASS (TREE_TYPE (receiver))) + { + /* The receiver is a variable created by build_class_reference_decl. */ + tree chain = cls_ref_chain ; + /* Look up the identifier in the relevant chain. */ + for (; chain; chain = TREE_CHAIN (chain)) + if (TREE_PURPOSE (chain) == receiver) + return TREE_VALUE (chain); + } + return NULL_TREE; +} + +static tree +build_selector_reference_decl (tree ident) +{ + tree decl; + char *t, buf[BUFSIZE]; + + snprintf (buf, BUFSIZE, "_OBJC_SelRef_%s", IDENTIFIER_POINTER (ident)); + t = buf; + while (*t) + { + if (*t==':') + *t = '$'; /* Underscore would clash between foo:bar and foo_bar. */ + t++; + } + decl = start_var_decl (objc_selector_type, buf); + OBJCMETA (decl, objc_meta, meta_sel_refs); + return decl; +} + +static tree +next_runtime_abi_01_build_selector_reference (location_t loc ATTRIBUTE_UNUSED, + tree ident, + tree proto ATTRIBUTE_UNUSED) +{ + tree *chain = &sel_ref_chain; + tree expr; + + while (*chain) + { + if (TREE_VALUE (*chain) == ident) + return TREE_PURPOSE (*chain); + + chain = &TREE_CHAIN (*chain); + } + + expr = build_selector_reference_decl (ident); + + *chain = tree_cons (expr, ident, NULL_TREE); + + return expr; +} + +/* Build a tree expression to send OBJECT the operation SELECTOR, + looking up the method on object LOOKUP_OBJECT (often same as OBJECT), + assuming the method has prototype METHOD_PROTOTYPE. + (That is an INSTANCE_METHOD_DECL or CLASS_METHOD_DECL.) + LOC is the location of the expression to build. + Use METHOD_PARAMS as list of args to pass to the method. + If SUPER_FLAG is nonzero, we look up the superclass's method. */ + +static tree +build_objc_method_call (location_t loc, int super_flag, tree method_prototype, + tree lookup_object, tree selector, + tree method_params) +{ + tree sender, sender_cast, method, t; + tree rcv_p = (super_flag ? objc_super_type : objc_object_type); + VEC(tree, gc) *parms; + unsigned nparm = (method_params ? list_length (method_params) : 0); + + /* If a prototype for the method to be called exists, then cast + the sender's return type and arguments to match that of the method. + Otherwise, leave sender as is. */ + tree ret_type + = (method_prototype + ? TREE_VALUE (TREE_TYPE (method_prototype)) + : objc_object_type); + + tree method_param_types = + get_arg_type_list (method_prototype, METHOD_REF, super_flag); + tree ftype = build_function_type (ret_type, method_param_types); + + if (method_prototype && METHOD_TYPE_ATTRIBUTES (method_prototype)) + ftype = build_type_attribute_variant (ftype, + METHOD_TYPE_ATTRIBUTES + (method_prototype)); + + sender_cast = build_pointer_type (ftype); + + lookup_object = build_c_cast (loc, rcv_p, lookup_object); + + /* Use SAVE_EXPR to avoid evaluating the receiver twice. */ + lookup_object = save_expr (lookup_object); + + /* Param list + 2 slots for object and selector. */ + parms = VEC_alloc (tree, gc, nparm + 2); + + /* If we are returning a struct in memory, and the address + of that memory location is passed as a hidden first + argument, then change which messenger entry point this + expr will call. NB: Note that sender_cast remains + unchanged (it already has a struct return type). */ + if (!targetm.calls.struct_value_rtx (0, 0) + && (TREE_CODE (ret_type) == RECORD_TYPE + || TREE_CODE (ret_type) == UNION_TYPE) + && targetm.calls.return_in_memory (ret_type, 0)) + sender = (super_flag ? umsg_super_stret_decl + : flag_nil_receivers ? umsg_stret_decl + : umsg_nonnil_stret_decl); + else + sender = (super_flag ? umsg_super_decl + : (flag_nil_receivers ? (flag_objc_direct_dispatch + ? umsg_fast_decl + : umsg_decl) + : umsg_nonnil_decl)); + method = build_fold_addr_expr_loc (loc, sender); + + /* Pass the object to the method. */ + VEC_quick_push (tree, parms, lookup_object); + /* Pass the selector to the method. */ + VEC_quick_push (tree, parms, selector); + /* Now append the remainder of the parms. */ + if (nparm) + for (; method_params; method_params = TREE_CHAIN (method_params)) + VEC_quick_push (tree, parms, TREE_VALUE (method_params)); + + /* Build an obj_type_ref, with the correct cast for the method call. */ + t = build3 (OBJ_TYPE_REF, sender_cast, method, + lookup_object, size_zero_node); + t = build_function_call_vec (loc, t, parms, NULL); + VEC_free (tree, gc, parms); + return t; +} + +static tree +next_runtime_abi_01_build_objc_method_call (location_t loc, + tree method_prototype, + tree receiver, + tree rtype ATTRIBUTE_UNUSED, + tree sel_name, + tree method_params, + int super) +{ + tree selector = next_runtime_abi_01_build_selector_reference (loc, sel_name, + NULL_TREE); + + return build_objc_method_call (loc, super, method_prototype, + receiver, selector, method_params); +} + +static tree +next_runtime_abi_01_get_protocol_reference (location_t loc, tree p) +{ + tree expr; + + if (!PROTOCOL_FORWARD_DECL (p)) + PROTOCOL_FORWARD_DECL (p) = next_runtime_abi_01_protocol_decl (p); + + expr = build_unary_op (loc, ADDR_EXPR, PROTOCOL_FORWARD_DECL (p), 0); + return convert (objc_protocol_type, expr); +} + +/* For ABI 0/1 and IVAR is just a fixed offset in the class struct. */ + +static tree +next_runtime_abi_01_build_ivar_ref (location_t loc ATTRIBUTE_UNUSED, + tree base, tree id) +{ + return objc_build_component_ref (base, id); +} + +/* We build super class references as we need them (but keep them once + built for the sake of efficiency). */ + +static tree +next_runtime_abi_01_get_class_super_ref (location_t loc ATTRIBUTE_UNUSED, + struct imp_entry *imp, bool inst_meth) +{ + if (inst_meth) + { + if (!ucls_super_ref) + ucls_super_ref = + objc_build_component_ref (imp->class_decl, + get_identifier ("super_class")); + return ucls_super_ref; + } + else + { + if (!uucls_super_ref) + uucls_super_ref = + objc_build_component_ref (imp->meta_decl, + get_identifier ("super_class")); + return uucls_super_ref; + } +} + +static tree +next_runtime_abi_01_get_category_super_ref (location_t loc ATTRIBUTE_UNUSED, + struct imp_entry *imp, bool inst_meth) +{ + tree super_name = CLASS_SUPER_NAME (imp->imp_template); + tree super_class; + + if (!flag_zero_link) + { + super_class = objc_get_class_reference (super_name); + + if (!inst_meth) + + /* If we are in a class method, we must retrieve the + _metaclass_ for the current class, pointed at by + the class's "isa" pointer. The following assumes that + "isa" is the first ivar in a class (which it must be). */ + super_class = + build_indirect_ref (input_location, + build_c_cast (input_location, + build_pointer_type (objc_class_type), + super_class), + RO_UNARY_STAR); + return super_class; + } + + /* else do it the slow way. */ + add_class_reference (super_name); + super_class = (inst_meth ? objc_get_class_decl : objc_get_meta_class_decl); +/* assemble_external (super_class);*/ + super_name = my_build_string_pointer (IDENTIFIER_LENGTH (super_name) + 1, + IDENTIFIER_POINTER (super_name)); + /* super_class = objc_get{Meta}Class("CLASS_SUPER_NAME"); */ + return build_function_call (input_location, + super_class, + build_tree_list (NULL_TREE, super_name)); +} + +static bool +next_runtime_abi_01_setup_const_string_class_decl (void) +{ + if (!constant_string_global_id) + { + /* Hopefully, this should not represent a serious limitation. */ + char buf[BUFSIZE]; + snprintf (buf, BUFSIZE, "_%sClassReference", constant_string_class_name); + constant_string_global_id = get_identifier (buf); + } + + string_class_decl = lookup_name (constant_string_global_id); + + return (string_class_decl != NULL_TREE); +} + +static tree +next_runtime_abi_01_build_const_string_constructor (location_t loc, tree string, + int length) +{ + tree constructor, fields, var; + VEC(constructor_elt,gc) *v = NULL; + + /* NeXT: (NSConstantString *) & ((__builtin_ObjCString) { isa, string, length }) */ + fields = TYPE_FIELDS (internal_const_str_type); + CONSTRUCTOR_APPEND_ELT (v, fields, + build_unary_op (loc, ADDR_EXPR, string_class_decl, 0)); + + fields = DECL_CHAIN (fields); + CONSTRUCTOR_APPEND_ELT (v, fields, + build_unary_op (loc, ADDR_EXPR, string, 1)); + + /* ??? check if this should be long. */ + fields = DECL_CHAIN (fields); + CONSTRUCTOR_APPEND_ELT (v, fields, build_int_cst (NULL_TREE, length)); + constructor = objc_build_constructor (internal_const_str_type, v); + + var = build_decl (input_location, CONST_DECL, NULL, TREE_TYPE (constructor)); + DECL_INITIAL (var) = constructor; + TREE_STATIC (var) = 1; + DECL_CONTEXT (var) = NULL; + OBJCMETA (var, objc_meta, meta_const_str); + return var; +} + +/* --- metadata templates --- */ + +/* This routine builds the following type: + struct _prop_t { + const char * const name; // property name + const char * const attributes; // comma-delimited, encoded, + // property attributes + }; +*/ + +static GTY(()) tree objc_v1_property_template; + +static tree +build_v1_property_template (void) +{ + tree prop_record; + tree decls, *chain = NULL; + + prop_record = objc_start_struct (get_identifier ("_prop_t")); + /* const char * name */ + decls = add_field_decl (string_type_node, "name", &chain); + + /* const char * attribute */ + add_field_decl (string_type_node, "attribute", &chain); + + objc_finish_struct (prop_record, decls); + return prop_record; +} + +/* Build the following type: + + struct _objc_protocol_extension + { + uint32_t size; // sizeof (struct _objc_protocol_extension) + struct objc_method_list *optional_instance_methods; + struct objc_method_list *optional_class_methods; + struct objc_prop_list *instance_properties; + } +*/ + +static GTY(()) tree objc_protocol_extension_template; + +static void +build_v1_objc_protocol_extension_template (void) +{ + tree decls, *chain = NULL; + + objc_protocol_extension_template = + objc_start_struct (get_identifier (UTAG_PROTOCOL_EXT)); + + /* uint32_t size; */ + decls = add_field_decl (integer_type_node, "size", &chain); + + /* struct objc_method_list *optional_instance_methods; */ + add_field_decl (objc_method_list_ptr, "optional_instance_methods", &chain); + + /* struct objc_method_list *optional_class_methods; */ + add_field_decl (objc_method_list_ptr, "optional_class_methods", &chain); + + /* struct objc_prop_list *instance_properties; */ + add_field_decl (objc_prop_list_ptr, "instance_properties", &chain); + + objc_finish_struct (objc_protocol_extension_template, decls); +} + +/* This routine build following struct type: + struct _objc_class_ext + { + uint32_t size; // sizeof(struct _objc_class_ext) + const char *weak_ivar_layout; + struct _prop_list_t *properties; + } +*/ + +static GTY(()) tree objc_class_ext_template; + +static void +build_objc_class_ext_template (void) +{ + tree ptrt, decls, *chain = NULL; + + objc_class_ext_template = objc_start_struct (get_identifier (UTAG_CLASS_EXT)); + + /* uint32_t size; */ + decls = add_field_decl (integer_type_node, "size", &chain); + + /* const char *weak_ivar_layout; */ + add_field_decl (const_string_type_node, "weak_ivar_layout", &chain); + + /* struct _prop_list_t *properties; */ + ptrt = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier(UTAG_PROPERTY_LIST))); + add_field_decl (ptrt, "properties", &chain); + + objc_finish_struct (objc_class_ext_template, decls); +} + +static void +build_metadata_templates (void) +{ + + if (!objc_method_template) + objc_method_template = build_method_template (); + + + +} + +/* --- emit metadata --- */ + +static tree +generate_v1_meth_descriptor_table (tree chain, tree protocol, + const char *prefix, tree attr) +{ + tree method_list_template, initlist, decl; + int size; + VEC(constructor_elt,gc) *v = NULL; + char buf[BUFSIZE]; + + if (!chain || !prefix) + return NULL_TREE; + + if (!objc_method_prototype_template) + objc_method_prototype_template = build_method_prototype_template (); + + size = list_length (chain); + method_list_template = + build_method_prototype_list_template (objc_method_prototype_template, + size); + snprintf (buf, BUFSIZE, "%s_%s", prefix, + IDENTIFIER_POINTER (PROTOCOL_NAME (protocol))); + + decl = start_var_decl (method_list_template, buf); + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, size)); + initlist = + build_descriptor_table_initializer (objc_method_prototype_template, + chain); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, initlist); + /* Get into the right section. */ + OBJCMETA (decl, objc_meta, attr); + finish_var_decl (decl, objc_build_constructor (method_list_template, v)); + return decl; +} + +/* Build protocol ext = + {size, opt_instance_meth, opt_class_meth, instance_props}; + or NULL_TREE if none are present. */ + +static tree +generate_v1_objc_protocol_extension (tree proto_interface, + tree opt_instance_meth, + tree opt_class_meth, + tree instance_props) +{ + int size; + location_t loc; + VEC(constructor_elt,gc) *v = NULL; + tree decl, expr; + char buf[BUFSIZE]; + + /* If there are no extensions, then don't bother... */ + if (!opt_instance_meth && !opt_class_meth && !instance_props) + return NULL_TREE; + + if (!objc_protocol_extension_template) + build_v1_objc_protocol_extension_template (); + + /* uint32_t size */ + size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (objc_protocol_extension_template)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, size)); + + /* Try for meaningful diagnostics. */ + loc = DECL_SOURCE_LOCATION (PROTOCOL_FORWARD_DECL (proto_interface)); + + /* struct objc_method_list *optional_instance_methods; */ + if (opt_instance_meth) + expr = convert (objc_method_list_ptr, + build_unary_op (loc, ADDR_EXPR, opt_instance_meth, 0)); + else + expr = convert (objc_method_list_ptr, null_pointer_node); + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + /* struct objc_method_list *optional_class_methods; */ + if (opt_class_meth) + expr = convert (objc_method_list_ptr, + build_unary_op (loc, ADDR_EXPR, opt_class_meth, 0)); + else + expr = convert (objc_method_list_ptr, null_pointer_node); + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + /* struct objc_prop_list *instance_properties; */ + if (instance_props) + expr = convert (objc_prop_list_ptr, + build_unary_op (loc, ADDR_EXPR, instance_props, 0)); + else + expr = convert (objc_prop_list_ptr, null_pointer_node); + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + snprintf (buf, BUFSIZE, "_OBJC_ProtocolExt_%s", + IDENTIFIER_POINTER (PROTOCOL_NAME (proto_interface))); + + decl = start_var_decl (objc_protocol_extension_template, buf); + expr = objc_build_constructor (TREE_TYPE (decl), v); + OBJCMETA (decl, objc_meta, meta_protocol_extension); + finish_var_decl (decl, expr); + return decl; +} + +/* This routine builds the following type: + struct _prop_list_t { + uint32_t entsize; // sizeof (struct _prop_t) + uint32_t prop_count; + struct _prop_t prop_list [prop_count]; + } +*/ + +static tree +build_v1_property_list_template (tree list_type, int size) +{ + tree property_list_t_record; + tree array_type, decls, *chain = NULL; + + /* anonymous. */ + property_list_t_record = objc_start_struct (NULL_TREE); + + /* uint32_t const entsize */ + decls = add_field_decl (integer_type_node, "entsize", &chain); + + /* int prop_count */ + add_field_decl (integer_type_node, "prop_count", &chain); + + /* struct _prop_t prop_list[]; */ + array_type = build_sized_array_type (list_type, size); + add_field_decl (array_type, "prop_list", &chain); + + objc_finish_struct (property_list_t_record, decls); + return property_list_t_record; +} + +/* This routine builds the initializer list to initialize the + 'struct _prop_t prop_list[]' field of 'struct _prop_list_t' meta-data. */ + +static tree +build_v1_property_table_initializer (tree type, tree context) +{ + tree x; + VEC(constructor_elt,gc) *inits = NULL; + + if (TREE_CODE (context) == PROTOCOL_INTERFACE_TYPE) + x = CLASS_PROPERTY_DECL (context); + else + x = IMPL_PROPERTY_DECL (context); + + for (; x; x = TREE_CHAIN (x)) + { + VEC(constructor_elt,gc) *elemlist = NULL; + tree attribute, name_ident = PROPERTY_NAME (x); + + CONSTRUCTOR_APPEND_ELT (elemlist, NULL_TREE, + add_objc_string (name_ident, prop_names_attr)); + + attribute = objc_v2_encode_prop_attr (x); + CONSTRUCTOR_APPEND_ELT (elemlist, NULL_TREE, + add_objc_string (attribute, prop_names_attr)); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, + objc_build_constructor (type, elemlist)); + } + + return objc_build_constructor (build_array_type (type, 0),inits); +} + +/* This routine builds the 'struct _prop_list_t' variable declaration and + initializes it with its initializer list. TYPE is 'struct _prop_list_t', + NAME is the internal name of this variable, SIZE is number of properties + for this class and LIST is the initializer list for its 'prop_list' field. */ + +static tree +generate_v1_property_table (tree context, tree klass_ctxt) +{ + tree x, decl, initlist, property_list_template; + bool is_proto = false; + VEC(constructor_elt,gc) *inits = NULL; + int init_val, size = 0; + char buf[BUFSIZE]; + + if (context) + { + gcc_assert (TREE_CODE (context) == PROTOCOL_INTERFACE_TYPE); + x = CLASS_PROPERTY_DECL (context); + is_proto = true; + } + else + x = IMPL_PROPERTY_DECL (klass_ctxt); + + for (; x; x = TREE_CHAIN (x)) + size++; + + if (size == 0) + return NULL_TREE; + + if (!objc_v1_property_template) + objc_v1_property_template = build_v1_property_template (); + + property_list_template = + build_v1_property_list_template (objc_v1_property_template, + size); + initlist = build_v1_property_table_initializer (objc_v1_property_template, + is_proto ? context + : klass_ctxt); + + init_val = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (objc_v1_property_template)); + if (is_proto) + snprintf (buf, BUFSIZE, "_OBJC_ProtocolPropList_%s", + IDENTIFIER_POINTER (PROTOCOL_NAME (context))); + else + snprintf (buf, BUFSIZE, "_OBJC_ClassPropList_%s", + IDENTIFIER_POINTER (CLASS_NAME (klass_ctxt))); + + decl = start_var_decl (property_list_template, buf); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, build_int_cst (NULL_TREE, init_val)); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, build_int_cst (NULL_TREE, size)); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, initlist); + x = objc_build_constructor (TREE_TYPE (decl), inits); + OBJCMETA (decl, objc_meta, meta_proplist); + finish_var_decl (decl, x); + return decl; +} + +static tree +generate_v1_protocol_list (tree i_or_p, tree klass_ctxt) +{ + tree array_type, ptype, refs_decl, lproto, e, plist, attr; + int size = 0; + VEC(constructor_elt,gc) *v = NULL; + char buf[BUFSIZE]; + + switch (TREE_CODE (i_or_p)) + { + case CLASS_INTERFACE_TYPE: + case CATEGORY_INTERFACE_TYPE: + plist = CLASS_PROTOCOL_LIST (i_or_p); + break; + case PROTOCOL_INTERFACE_TYPE: + plist = PROTOCOL_LIST (i_or_p); + break; + default: + gcc_unreachable (); + } + + /* Compute size. */ + for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) + if (TREE_CODE (TREE_VALUE (lproto)) == PROTOCOL_INTERFACE_TYPE + && PROTOCOL_FORWARD_DECL (TREE_VALUE (lproto))) + size++; + + /* Build initializer. */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); + e = build_int_cst (build_pointer_type (objc_protocol_template), size); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, e); + + for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) + { + tree pval = TREE_VALUE (lproto); + + if (TREE_CODE (pval) == PROTOCOL_INTERFACE_TYPE + && PROTOCOL_FORWARD_DECL (pval)) + { + tree fwref = PROTOCOL_FORWARD_DECL (pval); + location_t loc = DECL_SOURCE_LOCATION (fwref) ; + e = build_unary_op (loc, ADDR_EXPR, fwref, 0); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, e); + } + } + + /* static struct objc_protocol *refs[n]; */ + switch (TREE_CODE (i_or_p)) + { + case PROTOCOL_INTERFACE_TYPE: + snprintf (buf, BUFSIZE, "_OBJC_ProtocolRefs_%s", + IDENTIFIER_POINTER (PROTOCOL_NAME (i_or_p))); + attr = meta_proto_ref; + break; + case CLASS_INTERFACE_TYPE: + snprintf (buf, BUFSIZE, "_OBJC_ClassProtocols_%s", + IDENTIFIER_POINTER (CLASS_NAME (i_or_p))); + attr = meta_clas_prot; + break; + case CATEGORY_INTERFACE_TYPE: + snprintf (buf, BUFSIZE, "_OBJC_CategoryProtocols_%s_%s", + IDENTIFIER_POINTER (CLASS_NAME (klass_ctxt)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (klass_ctxt))); + attr = meta_catg_prot; + break; + default: + gcc_unreachable (); + } + + ptype = build_pointer_type (objc_protocol_template); + array_type = build_sized_array_type (ptype, size + 3); + refs_decl = start_var_decl (array_type, buf); + + OBJCMETA (refs_decl, objc_meta, attr); + finish_var_decl (refs_decl, + objc_build_constructor (TREE_TYPE (refs_decl), v)); + + return refs_decl; +} + +static tree +build_v1_protocol_initializer (tree type, tree protocol_name, tree protocol_list, + tree inst_methods, tree class_methods, + tree protocol_ext) +{ + tree expr, ttyp; + location_t loc; + VEC(constructor_elt,gc) *inits = NULL; + + if (!objc_protocol_extension_template) + build_v1_objc_protocol_extension_template (); + + /* TODO: find a better representation of location from the inputs. */ + loc = UNKNOWN_LOCATION; + ttyp = build_pointer_type (objc_protocol_extension_template); + /* Instead of jamming the protocol version number into the isa, we pass + either a pointer to the protocol extension - or NULL. */ + if (protocol_ext) + expr = convert (ttyp, build_unary_op (loc, ADDR_EXPR, protocol_ext, 0)); + else + expr = convert (ttyp, null_pointer_node); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, protocol_name); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, protocol_list); + + ttyp = objc_method_proto_list_ptr; + if (inst_methods) + expr = convert (ttyp, build_unary_op (loc, ADDR_EXPR, inst_methods, 0)); + else + expr = convert (ttyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + + if (class_methods) + expr = convert (ttyp, build_unary_op (loc, ADDR_EXPR, class_methods, 0)); + else + expr = convert (ttyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + + return objc_build_constructor (type, inits); +} + +/* An updated version of generate_protocols () that emit the protocol + extension for ABI=1. */ + +/* For each protocol which was referenced either from a @protocol() + expression, or because a class/category implements it (then a + pointer to the protocol is stored in the struct describing the + class/category), we create a statically allocated instance of the + Protocol class. The code is written in such a way as to generate + as few Protocol objects as possible; we generate a unique Protocol + instance for each protocol, and we don't generate a Protocol + instance if the protocol is never referenced (either from a + @protocol() or from a class/category implementation). These + statically allocated objects can be referred to via the static + (that is, private to this module) symbols _OBJC_PROTOCOL_n. + + The statically allocated Protocol objects that we generate here + need to be fixed up at runtime in order to be used: the 'isa' + pointer of the objects need to be set up to point to the 'Protocol' + class, as known at runtime. + + The NeXT runtime fixes up all protocols at program startup time, + before main() is entered. It uses a low-level trick to look up all + those symbols, then loops on them and fixes them up. */ + +/* TODO: finish getting rid of passing stuff around in globals. */ + +static GTY(()) tree V1_Protocol_OPT_NST_METHODS_decl; +static GTY(()) tree V1_Protocol_OPT_CLS_METHODS_decl; +static GTY(()) tree V1_ProtocolExt_decl; +static GTY(()) tree V1_Property_decl; + +static void +generate_v1_protocols (void) +{ + tree p; + + /* If a protocol was directly referenced, pull in indirect references. */ + for (p = protocol_chain; p; p = TREE_CHAIN (p)) + if (PROTOCOL_FORWARD_DECL (p) && PROTOCOL_LIST (p)) + generate_protocol_references (PROTOCOL_LIST (p)); + + for (p = protocol_chain; p; p = TREE_CHAIN (p)) + { + tree decl, encoding, initlist, protocol_name_expr; + tree refs_type, refs_decl, refs_expr; + location_t loc; + tree nst_methods = PROTOCOL_NST_METHODS (p); + tree cls_methods = PROTOCOL_CLS_METHODS (p); + + /* If protocol wasn't referenced, don't generate any code. */ + decl = PROTOCOL_FORWARD_DECL (p); + + if (!decl) + continue; + + /* Make sure we link in the Protocol class. */ + add_class_reference (get_identifier (PROTOCOL_OBJECT_CLASS_NAME)); + + while (nst_methods) + { + if (! METHOD_ENCODING (nst_methods)) + { + encoding = encode_method_prototype (nst_methods); + METHOD_ENCODING (nst_methods) = encoding; + } + nst_methods = TREE_CHAIN (nst_methods); + } + + UOBJC_INSTANCE_METHODS_decl = + generate_v1_meth_descriptor_table (PROTOCOL_NST_METHODS (p), p, + "_OBJC_ProtocolInstanceMethods", + meta_proto_nst_meth); + + while (cls_methods) + { + if (! METHOD_ENCODING (cls_methods)) + { + encoding = encode_method_prototype (cls_methods); + METHOD_ENCODING (cls_methods) = encoding; + } + + cls_methods = TREE_CHAIN (cls_methods); + } + + UOBJC_CLASS_METHODS_decl = + generate_v1_meth_descriptor_table (PROTOCOL_CLS_METHODS (p), p, + "_OBJC_ProtocolClassMethods", + meta_proto_cls_meth); + + /* There should be no optional methods for ABI-0 - but we need to + check all this here before the lists are made. */ + nst_methods = PROTOCOL_OPTIONAL_NST_METHODS (p); + while (nst_methods) + { + if (! METHOD_ENCODING (nst_methods)) + { + encoding = encode_method_prototype (nst_methods); + METHOD_ENCODING (nst_methods) = encoding; + } + nst_methods = TREE_CHAIN (nst_methods); + } + + V1_Protocol_OPT_NST_METHODS_decl = + generate_v1_meth_descriptor_table (PROTOCOL_OPTIONAL_NST_METHODS (p), p, + "_OBJC_OptionalProtocolInstanceMethods", + meta_proto_nst_meth); + + cls_methods = PROTOCOL_OPTIONAL_CLS_METHODS (p); + while (cls_methods) + { + if (! METHOD_ENCODING (cls_methods)) + { + encoding = encode_method_prototype (cls_methods); + METHOD_ENCODING (cls_methods) = encoding; + } + + cls_methods = TREE_CHAIN (cls_methods); + } + + V1_Protocol_OPT_CLS_METHODS_decl = + generate_v1_meth_descriptor_table (PROTOCOL_OPTIONAL_CLS_METHODS (p), p, + "_OBJC_OptionalProtocolClassMethods", + meta_proto_cls_meth); + + if (PROTOCOL_LIST (p)) + refs_decl = generate_v1_protocol_list (p, objc_implementation_context); + else + refs_decl = 0; + + /* static struct objc_protocol _OBJC_PROTOCOL_<mumble>; */ + protocol_name_expr = add_objc_string (PROTOCOL_NAME (p), class_names); + /* TODO: more locations to be fixed up... */ + loc = UNKNOWN_LOCATION; + refs_type = + build_pointer_type (build_pointer_type (objc_protocol_template)); + if (refs_decl) + refs_expr = convert (refs_type, + build_unary_op (loc, ADDR_EXPR, refs_decl, 0)); + else + refs_expr = convert (refs_type, null_pointer_node); + + if (flag_objc_abi < 1) + { + /* Original ABI. */ + initlist = + build_protocol_initializer (TREE_TYPE (decl), + protocol_name_expr, refs_expr, + UOBJC_INSTANCE_METHODS_decl, + UOBJC_CLASS_METHODS_decl); + finish_var_decl (decl, initlist); + continue; + } + + /* else - V1 extensions. */ + + V1_Property_decl = + generate_v1_property_table (p, NULL_TREE); + + V1_ProtocolExt_decl = + generate_v1_objc_protocol_extension (p, + V1_Protocol_OPT_NST_METHODS_decl, + V1_Protocol_OPT_CLS_METHODS_decl, + V1_Property_decl); + + initlist = build_v1_protocol_initializer (TREE_TYPE (decl), + protocol_name_expr, refs_expr, + UOBJC_INSTANCE_METHODS_decl, + UOBJC_CLASS_METHODS_decl, + V1_ProtocolExt_decl); + finish_var_decl (decl, initlist); + } +} + +static tree +generate_dispatch_table (tree chain, const char *name, tree attr) +{ + tree decl, method_list_template, initlist; + VEC(constructor_elt,gc) *v = NULL; + int size;; + + if (!chain || !name || !(size = list_length (chain))) + return NULL_TREE; + + if (!objc_method_template) + objc_method_template = build_method_template (); + + method_list_template = build_method_list_template (objc_method_template, + size); + initlist = build_dispatch_table_initializer (objc_method_template, chain); + + decl = start_var_decl (method_list_template, name); + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (integer_type_node, size)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, initlist); + + OBJCMETA (decl, objc_meta, attr); + finish_var_decl (decl, + objc_build_constructor (TREE_TYPE (decl), v)); + + return decl; +} + +/* Init a category. */ +static tree +build_v1_category_initializer (tree type, tree cat_name, tree class_name, + tree inst_methods, tree class_methods, + tree protocol_list, tree property_list, + location_t loc) +{ + tree expr, ltyp; + VEC(constructor_elt,gc) *v = NULL; + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, cat_name); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, class_name); + + ltyp = objc_method_list_ptr; + if (inst_methods) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, inst_methods, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + if (class_methods) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, class_methods, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + /* protocol_list = */ + ltyp = build_pointer_type (build_pointer_type (objc_protocol_template)); + if (protocol_list) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, protocol_list, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + if (flag_objc_abi >= 1) + { + int val = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (objc_category_template)); + expr = build_int_cst (NULL_TREE, val); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + ltyp = objc_prop_list_ptr; + if (property_list) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, property_list, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + + return objc_build_constructor (type, v); +} + +/* static struct objc_category _OBJC_CATEGORY_<name> = { ... }; */ +/* TODO: get rid of passing stuff around in globals. */ +static void +generate_v1_category (struct imp_entry *impent) +{ + tree initlist, cat_name_expr, class_name_expr; + tree protocol_decl, category, cat_decl; + tree inst_methods = NULL_TREE, class_methods = NULL_TREE; + tree cat = impent->imp_context; + location_t loc; + char buf[BUFSIZE]; + + cat_decl = impent->class_decl; + loc = DECL_SOURCE_LOCATION (cat_decl); + + add_class_reference (CLASS_NAME (cat)); + cat_name_expr = add_objc_string (CLASS_SUPER_NAME (cat), class_names); + class_name_expr = add_objc_string (CLASS_NAME (cat), class_names); + + category = lookup_category (impent->imp_template, CLASS_SUPER_NAME (cat)); + + if (category && CLASS_PROTOCOL_LIST (category)) + { + generate_protocol_references (CLASS_PROTOCOL_LIST (category)); + protocol_decl = generate_v1_protocol_list (category, cat); + } + else + protocol_decl = 0; + + if (flag_objc_abi >= 1) + V1_Property_decl = generate_v1_property_table (NULL_TREE, cat); + else + V1_Property_decl = NULL_TREE; + + if (CLASS_NST_METHODS (cat)) + { + snprintf (buf, BUFSIZE, "_OBJC_CategoryInstanceMethods_%s_%s", + IDENTIFIER_POINTER (CLASS_NAME (cat)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (cat))); + inst_methods = generate_dispatch_table (CLASS_NST_METHODS (cat), buf, + meta_cati_meth); + } + + if (CLASS_CLS_METHODS (cat)) + { + snprintf (buf, BUFSIZE, "_OBJC_CategoryClassMethods_%s_%s", + IDENTIFIER_POINTER (CLASS_NAME (cat)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (cat))); + class_methods = generate_dispatch_table (CLASS_CLS_METHODS (cat), buf, + meta_catc_meth); + } + + initlist = build_v1_category_initializer (TREE_TYPE (cat_decl), + cat_name_expr, class_name_expr, + inst_methods, class_methods, + protocol_decl, V1_Property_decl, + loc); + + finish_var_decl (cat_decl, initlist); + impent->class_decl = cat_decl; +} + +/* This routine builds the class extension used by v1 NeXT. +*/ + +static tree +generate_objc_class_ext (tree property_list, tree context) +{ + tree decl, expr, ltyp; + tree weak_ivar_layout_tree; + int size; + location_t loc; + VEC(constructor_elt,gc) *v = NULL; + char buf[BUFSIZE]; + + /* TODO: pass the loc in or find it from args. */ + loc = UNKNOWN_LOCATION; + + /* const char *weak_ivar_layout + TODO: Figure the ivar layouts out... */ + weak_ivar_layout_tree = NULL_TREE; + + if (!property_list && !weak_ivar_layout_tree) + return NULL_TREE; + + if (!objc_class_ext_template) + build_objc_class_ext_template (); + + /* uint32_t size */ + size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (objc_class_ext_template)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, size)); + + ltyp = const_string_type_node; + if (weak_ivar_layout_tree) + expr = convert (ltyp, weak_ivar_layout_tree); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + /* struct _prop_list_t *properties; */ + ltyp = objc_prop_list_ptr; + if (property_list) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, property_list, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + snprintf (buf, BUFSIZE, "_OBJC_ClassExt_%s", + IDENTIFIER_POINTER (CLASS_NAME (context))); + decl = start_var_decl (objc_class_ext_template, buf); + expr = objc_build_constructor (TREE_TYPE (decl), v); + OBJCMETA (decl, objc_meta, meta_class_extension); + finish_var_decl (decl, expr); + return decl; +} + +/* struct _objc_class { + struct objc_class *isa; + struct objc_class *super_class; + char *name; + long version; + long info; + long instance_size; + struct objc_ivar_list *ivars; + struct objc_method_list *methods; + struct objc_cache *cache; + struct objc_protocol_list *protocols; + #if ABI >= 1 + const char *ivar_layout; + struct _objc_class_ext *ext; + #else + void *sel_id; + void *gc_object_type; + #endif + }; */ + +static tree +build_v1_shared_structure_initializer (tree type, tree isa, tree super, + tree name, tree size, int status, + tree dispatch_table, tree ivar_list, + tree protocol_list, tree class_ext) +{ + tree expr, ltyp; + location_t loc; + VEC(constructor_elt,gc) *v = NULL; + + /* TODO: fish the location out of the input data. */ + loc = UNKNOWN_LOCATION; + + /* isa = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, isa); + + /* super_class = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, super); + + /* name = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, default_conversion (name)); + + /* version = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (long_integer_type_node, 0)); + + /* info = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (long_integer_type_node, status)); + + /* instance_size = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + convert (long_integer_type_node, size)); + + /* objc_ivar_list = */ + ltyp = objc_ivar_list_ptr; + if (ivar_list) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, ivar_list, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + /* objc_method_list = */ + ltyp = objc_method_list_ptr; + if (dispatch_table) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, dispatch_table, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + ltyp = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier ("objc_cache"))); + /* method_cache = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, convert (ltyp, null_pointer_node)); + + /* protocol_list = */ + ltyp = build_pointer_type (build_pointer_type (objc_protocol_template)); + if (protocol_list) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, protocol_list, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + if (flag_objc_abi >= 1) + { + /* TODO: figure out the ivar_layout stuff. */ + expr = convert (const_string_type_node, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + if (!objc_class_ext_template) + build_objc_class_ext_template (); + ltyp = build_pointer_type (objc_class_ext_template); + if (class_ext) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, class_ext, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + else + { + /* sel_id = NULL */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, null_pointer_node); + + /* gc_object_type = NULL */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, null_pointer_node); + } + return objc_build_constructor (type, v); +} + +static tree +generate_ivars_list (tree chain, const char *name, tree attr) +{ + tree initlist, ivar_list_template, decl; + int size; + VEC(constructor_elt,gc) *inits = NULL; + + if (!chain) + return NULL_TREE; + + if (!objc_ivar_template) + objc_ivar_template = build_ivar_template (); + + size = ivar_list_length (chain); + + generating_instance_variables = 1; + ivar_list_template = build_ivar_list_template (objc_ivar_template, size); + initlist = build_ivar_list_initializer (objc_ivar_template, chain); + generating_instance_variables = 0; + + decl = start_var_decl (ivar_list_template, name); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, build_int_cst (NULL_TREE, size)); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, initlist); + + OBJCMETA (decl, objc_meta, attr); + finish_var_decl (decl, + objc_build_constructor (TREE_TYPE (decl), inits)); + + return decl; +} + +/* static struct objc_class _OBJC_METACLASS_Foo={ ... }; + static struct objc_class _OBJC_CLASS_Foo={ ... }; */ + +static void +generate_v1_class_structs (struct imp_entry *impent) +{ + tree name_expr, super_expr, root_expr, class_decl, meta_decl; + tree my_root_id, my_super_id; + tree cast_type, initlist, protocol_decl; + tree class_ext_decl = NULL_TREE, props = NULL_TREE; + tree inst_methods = NULL_TREE, class_methods = NULL_TREE; + tree chain, inst_ivars = NULL_TREE, class_ivars = NULL_TREE; + int cls_flags; + location_t loc; + char buf[BUFSIZE]; + +/* objc_implementation_context = impent->imp_context; + implementation_template = impent->imp_template;*/ + class_decl = impent->class_decl; + meta_decl = impent->meta_decl; + cls_flags = impent->has_cxx_cdtors ? CLS_HAS_CXX_STRUCTORS : 0 ; + + loc = DECL_SOURCE_LOCATION (impent->class_decl); + + if (flag_objc_abi >= 1) + { + /* ABI=1 additions. */ + props = generate_v1_property_table (NULL_TREE, impent->imp_context); + class_ext_decl = generate_objc_class_ext (props, impent->imp_context); + } + + my_super_id = CLASS_SUPER_NAME (impent->imp_template); + if (my_super_id) + { + add_class_reference (my_super_id); + + /* Compute "my_root_id" - this is required for code generation. + the "isa" for all meta class structures points to the root of + the inheritance hierarchy (e.g. "__Object")... */ + my_root_id = my_super_id; + do + { + tree my_root_int = lookup_interface (my_root_id); + + if (my_root_int && CLASS_SUPER_NAME (my_root_int)) + my_root_id = CLASS_SUPER_NAME (my_root_int); + else + break; + } + while (1); + super_expr = add_objc_string (my_super_id, class_names); + } + else + { + /* No super class. */ + my_root_id = CLASS_NAME (impent->imp_template); + super_expr = null_pointer_node; + } + + /* Install class `isa' and `super' pointers at runtime. */ + cast_type = build_pointer_type (objc_class_template); + super_expr = build_c_cast (loc, cast_type, super_expr); + + root_expr = add_objc_string (my_root_id, class_names); + root_expr = build_c_cast (loc, cast_type, root_expr); + + if (CLASS_PROTOCOL_LIST (impent->imp_template)) + { + generate_protocol_references (CLASS_PROTOCOL_LIST (impent->imp_template)); + protocol_decl = generate_v1_protocol_list (impent->imp_template, + impent->imp_context); + } + else + protocol_decl = NULL_TREE; + + if (CLASS_CLS_METHODS (impent->imp_context)) + { + snprintf (buf, BUFSIZE, "_OBJC_ClassMethods_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + class_methods = generate_dispatch_table (CLASS_CLS_METHODS (impent->imp_context), + buf, meta_clac_meth); + } + + if (CLASS_SUPER_NAME (impent->imp_template) == NULL_TREE + && (chain = TYPE_FIELDS (objc_class_template))) + { + snprintf (buf, BUFSIZE, "_OBJC_ClassIvars_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + class_ivars = generate_ivars_list (chain, buf, meta_clac_vars); + } + /* TODO: get rid of hidden passing of stuff in globals. */ + /* UOBJC_INSTANCE/CLASS_Variables_decl made in generate_ivarlists(). */ + + name_expr = add_objc_string (CLASS_NAME (impent->imp_template), class_names); + + /* static struct objc_class _OBJC_METACLASS_Foo = { ... }; */ + + initlist = build_v1_shared_structure_initializer + (TREE_TYPE (meta_decl), + root_expr, super_expr, name_expr, + convert (integer_type_node, TYPE_SIZE_UNIT (objc_class_template)), + CLS_META, class_methods, class_ivars, + protocol_decl, NULL_TREE); + + finish_var_decl (meta_decl, initlist); + impent->meta_decl = meta_decl; + + /* static struct objc_class _OBJC_CLASS_Foo={ ... }; */ + if (CLASS_NST_METHODS (impent->imp_context)) + { + snprintf (buf, BUFSIZE, "_OBJC_InstanceMethods_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + inst_methods = generate_dispatch_table (CLASS_NST_METHODS (impent->imp_context), + buf, meta_clai_meth); + } + + if ((chain = CLASS_IVARS (impent->imp_template))) + { + snprintf (buf, BUFSIZE, "_OBJC_InstanceIvars_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + inst_ivars = generate_ivars_list (chain, buf, meta_clai_vars); + } + + initlist = build_v1_shared_structure_initializer + (TREE_TYPE (class_decl), + build_unary_op (loc, ADDR_EXPR, meta_decl, 0), + super_expr, name_expr, + convert (integer_type_node, + TYPE_SIZE_UNIT (CLASS_STATIC_TEMPLATE (impent->imp_template))), + CLS_FACTORY | cls_flags, inst_methods, inst_ivars, + protocol_decl, class_ext_decl); + + finish_var_decl (class_decl, initlist); + impent->class_decl = class_decl; +} + +/* --- Output NeXT V1 Metadata --- */ + +/* Create the initial value for the `defs' field of _objc_symtab. + This is a CONSTRUCTOR. */ + +static tree +init_def_list (tree type) +{ + tree expr; + location_t loc; + struct imp_entry *impent; + VEC(constructor_elt,gc) *v = NULL; + + if (imp_count) + for (impent = imp_list; impent; impent = impent->next) + { + if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) + { + loc = DECL_SOURCE_LOCATION (impent->class_decl); + expr = build_unary_op (loc, + ADDR_EXPR, impent->class_decl, 0); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + } + + if (cat_count) + for (impent = imp_list; impent; impent = impent->next) + { + if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE) + { + loc = DECL_SOURCE_LOCATION (impent->class_decl); + expr = build_unary_op (loc, + ADDR_EXPR, impent->class_decl, 0); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + } + + return objc_build_constructor (type, v); +} + +/* Take care of defining and initializing _OBJC_SYMBOLS. */ + +/* Predefine the following data type: + + struct _objc_symtab + { + long sel_ref_cnt; + SEL *refs; + short cls_def_cnt; + short cat_def_cnt; + void *defs[cls_def_cnt + cat_def_cnt]; + }; */ + +static void +build_objc_symtab_template (void) +{ + tree fields, *chain = NULL; + + objc_symtab_template = objc_start_struct (get_identifier (UTAG_SYMTAB)); + + /* long sel_ref_cnt; */ + fields = add_field_decl (long_integer_type_node, "sel_ref_cnt", &chain); + + /* SEL *refs; */ + add_field_decl (build_pointer_type (objc_selector_type), "refs", &chain); + + /* short cls_def_cnt; */ + add_field_decl (short_integer_type_node, "cls_def_cnt", &chain); + + /* short cat_def_cnt; */ + add_field_decl (short_integer_type_node, "cat_def_cnt", &chain); + + if (imp_count || cat_count) + { + /* void *defs[imp_count + cat_count (+ 1)]; */ + /* NB: The index is one less than the size of the array. */ + int index = imp_count + cat_count; + tree array_type = build_sized_array_type (ptr_type_node, index); + add_field_decl (array_type, "defs", &chain); + } + + objc_finish_struct (objc_symtab_template, fields); +} +/* Construct the initial value for all of _objc_symtab. */ + +static tree +init_objc_symtab (tree type) +{ + VEC(constructor_elt,gc) *v = NULL; + + /* sel_ref_cnt = { ..., 5, ... } */ + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (long_integer_type_node, 0)); + + /* refs = { ..., _OBJC_SELECTOR_TABLE, ... } */ + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + convert (build_pointer_type (objc_selector_type), + integer_zero_node)); + + /* cls_def_cnt = { ..., 5, ... } */ + + 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 (short_integer_type_node, cat_count)); + + /* cls_def = { ..., { &Foo, &Bar, ...}, ... } */ + + if (imp_count || cat_count) + { + tree field = TYPE_FIELDS (type); + field = DECL_CHAIN (DECL_CHAIN (DECL_CHAIN (DECL_CHAIN (field)))); + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init_def_list (TREE_TYPE (field))); + } + + return objc_build_constructor (type, v); +} + +/* Create the declaration of _OBJC_SYMBOLS, with type `struct _objc_symtab' + and initialized appropriately. */ + +static void +generate_objc_symtab_decl (void) +{ + build_objc_symtab_template (); + UOBJC_SYMBOLS_decl = start_var_decl (objc_symtab_template, "_OBJC_Symbols"); + /* Allow the runtime to mark meta-data such that it can be assigned to target + specific sections by the back-end. */ + OBJCMETA (UOBJC_SYMBOLS_decl, objc_meta, meta_symtab); + finish_var_decl (UOBJC_SYMBOLS_decl, + init_objc_symtab (TREE_TYPE (UOBJC_SYMBOLS_decl))); +} + + +static void +handle_next_class_ref (tree chain) +{ + const char *name = IDENTIFIER_POINTER (TREE_VALUE (chain)); + char *string = (char *) alloca (strlen (name) + 30); + + 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 +} + +static void +handle_next_impent (struct imp_entry *impent) +{ + char buf[BUFSIZE]; + + switch (TREE_CODE (impent->imp_context)) + { + case CLASS_IMPLEMENTATION_TYPE: + snprintf (buf, BUFSIZE, ".objc_class_name_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + break; + case CATEGORY_IMPLEMENTATION_TYPE: + snprintf (buf, BUFSIZE, "*.objc_category_name_%s_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (impent->imp_context))); + break; + default: + return; + } + +#ifdef ASM_DECLARE_CLASS_REFERENCE + ASM_DECLARE_CLASS_REFERENCE (asm_out_file, buf); +#else + return ; /* NULL build for targets other than Darwin. */ +#endif +} + +static void +generate_classref_translation_entry (tree chain) +{ + tree expr, decl, type; + + decl = TREE_PURPOSE (chain); + type = TREE_TYPE (decl); + + expr = add_objc_string (TREE_VALUE (chain), class_names); + expr = convert (type, expr); /* cast! */ + + /* 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; + OBJCMETA (decl, objc_meta, meta_class_reference); + finish_var_decl (decl, expr); + return; +} + + +/* The Fix-and-Continue functionality available in Mac OS X 10.3 and + later requires that ObjC translation units participating in F&C be + specially marked. The following routine accomplishes this. */ + +/* static int _OBJC_IMAGE_INFO[2] = { 0, 1 }; */ + +static void +generate_objc_image_info (void) +{ + tree decl; + int flags + = ((flag_replace_objc_classes && imp_count ? 1 : 0) + | (flag_objc_gc ? 2 : 0)); + VEC(constructor_elt,gc) *v = NULL; + tree array_type; + + array_type = build_sized_array_type (integer_type_node, 2); + + decl = start_var_decl (array_type, "_OBJC_ImageInfo"); + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (integer_type_node, flags)); + /* The runtime wants this and refers to it in a manner hidden from the compiler. + So we must force the output. */ + DECL_PRESERVE_P (decl) = 1; + OBJCMETA (decl, objc_meta, meta_info); + finish_var_decl (decl, objc_build_constructor (TREE_TYPE (decl), v)); +} + +static void +objc_generate_v1_next_metadata (void) +{ + struct imp_entry *impent; + tree chain, attr; + long vers; + + if (objc_static_instances) + gcc_unreachable (); /* Not for NeXT */ + + build_metadata_templates (); + objc_implementation_context = + implementation_template = + UOBJC_CLASS_decl = + UOBJC_METACLASS_decl = NULL_TREE; + + for (impent = imp_list; impent; impent = impent->next) + { + + /* If -gen-decls is present, Dump the @interface of each class. + TODO: Dump the classes in the order they were found, rather than in + reverse order as we are doing now. */ + if (flag_gen_declaration) + dump_interface (gen_declaration_file, impent->imp_context); + + /* all of the following reference the string pool... */ + if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) + generate_v1_class_structs (impent); + else + generate_v1_category (impent); + } + + /* If we are using an array of selectors, we must always + finish up the array decl even if no selectors were used. */ + build_next_selector_translation_table (); + + if (protocol_chain) + generate_v1_protocols (); + + /* Pass summary information to the runtime. */ + if (imp_count || cat_count) + generate_objc_symtab_decl (); + + vers = OBJC_VERSION; + attr = build_tree_list (objc_meta, meta_modules); + build_module_descriptor (vers, attr); + + /* This conveys information on GC usage and zero-link. */ + generate_objc_image_info (); + + /* Dump the class references. This forces the appropriate classes + to be linked into the executable image, preserving unix archive + semantics. This can be removed when we move to a more dynamically + linked environment. */ + + for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain)) + { + handle_next_class_ref (chain); + if (TREE_PURPOSE (chain)) + generate_classref_translation_entry (chain); + } + + for (impent = imp_list; impent; impent = impent->next) + handle_next_impent (impent); + + /* Emit the strings tables. */ + generate_strings (); +} + +/* --- exceptions stuff --- */ + +/* Predefine the following data type: + + struct _objc_exception_data + { + int buf[OBJC_JBLEN]; + void *pointers[4]; + }; */ + +/* The following yuckiness should prevent users from having to #include + <setjmp.h> in their code... */ + +/* Define to a harmless positive value so the below code doesn't die. */ +#ifndef OBJC_JBLEN +#define OBJC_JBLEN 18 +#endif + +static void +build_next_objc_exception_stuff (void) +{ + tree decls, temp_type, *chain = NULL; + + objc_exception_data_template + = objc_start_struct (get_identifier (UTAG_EXCDATA)); + + /* int buf[OBJC_JBLEN]; */ + + temp_type = build_sized_array_type (integer_type_node, OBJC_JBLEN); + decls = add_field_decl (temp_type, "buf", &chain); + + /* void *pointers[4]; */ + + temp_type = build_sized_array_type (ptr_type_node, 4); + add_field_decl (temp_type, "pointers", &chain); + + objc_finish_struct (objc_exception_data_template, decls); + + /* int _setjmp(...); */ + /* If the user includes <setjmp.h>, this shall be superseded by + 'int _setjmp(jmp_buf);' */ + temp_type = build_varargs_function_type_list (integer_type_node, NULL_TREE); + objc_setjmp_decl + = add_builtin_function (TAG_SETJMP, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + + /* id objc_exception_extract(struct _objc_exception_data *); */ + temp_type + = build_function_type_list (objc_object_type, + build_pointer_type (objc_exception_data_template), + NULL_TREE); + objc_exception_extract_decl + = add_builtin_function (TAG_EXCEPTIONEXTRACT, temp_type, 0, NOT_BUILT_IN, NULL, + NULL_TREE); + /* void objc_exception_try_enter(struct _objc_exception_data *); */ + /* void objc_exception_try_exit(struct _objc_exception_data *); */ + temp_type + = build_function_type_list (void_type_node, + build_pointer_type (objc_exception_data_template), + NULL_TREE); + objc_exception_try_enter_decl + = add_builtin_function (TAG_EXCEPTIONTRYENTER, temp_type, 0, NOT_BUILT_IN, NULL, + NULL_TREE); + objc_exception_try_exit_decl + = add_builtin_function (TAG_EXCEPTIONTRYEXIT, temp_type, 0, NOT_BUILT_IN, NULL, + NULL_TREE); + + /* int objc_exception_match(id, id); */ + temp_type + = build_function_type_list (integer_type_node, + objc_object_type, objc_object_type, NULL_TREE); + objc_exception_match_decl + = add_builtin_function (TAG_EXCEPTIONMATCH, temp_type, 0, NOT_BUILT_IN, NULL, + NULL_TREE); + + /* id objc_assign_ivar (id, id, unsigned int); */ + /* id objc_assign_ivar_Fast (id, id, unsigned int) + __attribute__ ((hard_coded_address (OFFS_ASSIGNIVAR_FAST))); */ + temp_type + = build_function_type_list (objc_object_type, + objc_object_type, + objc_object_type, + unsigned_type_node, + NULL_TREE); + objc_assign_ivar_decl + = add_builtin_function (TAG_ASSIGNIVAR, temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); +#ifdef OFFS_ASSIGNIVAR_FAST + objc_assign_ivar_fast_decl + = add_builtin_function (TAG_ASSIGNIVAR_FAST, temp_type, 0, + NOT_BUILT_IN, NULL, NULL_TREE); + DECL_ATTRIBUTES (objc_assign_ivar_fast_decl) + = tree_cons (get_identifier ("hard_coded_address"), + build_int_cst (NULL_TREE, OFFS_ASSIGNIVAR_FAST), + NULL_TREE); +#else + /* Default to slower ivar method. */ + objc_assign_ivar_fast_decl = objc_assign_ivar_decl; +#endif + + /* id objc_assign_global (id, id *); */ + /* id objc_assign_strongCast (id, id *); */ + temp_type = build_function_type_list (objc_object_type, + objc_object_type, + build_pointer_type (objc_object_type), + NULL_TREE); + objc_assign_global_decl + = add_builtin_function (TAG_ASSIGNGLOBAL, temp_type, 0, NOT_BUILT_IN, NULL, + NULL_TREE); + objc_assign_strong_cast_decl + = add_builtin_function (TAG_ASSIGNSTRONGCAST, temp_type, 0, NOT_BUILT_IN, NULL, + NULL_TREE); +} + +/* --- NeXT V1 SJLJ Exceptions --- */ + +/* Build "objc_exception_try_exit(&_stack)". */ + +static tree +next_sjlj_build_try_exit (struct objc_try_context **ctcp) +{ + tree t; + t = build_fold_addr_expr_loc (input_location, (*ctcp)->stack_decl); + t = tree_cons (NULL, t, NULL); + t = build_function_call (input_location, + objc_exception_try_exit_decl, t); + return t; +} + +/* Build + objc_exception_try_enter (&_stack); + if (_setjmp(&_stack.buf)) + ; + else + ; + Return the COND_EXPR. Note that the THEN and ELSE fields are left + empty, ready for the caller to fill them in. */ + +static tree +next_sjlj_build_enter_and_setjmp (struct objc_try_context **ctcp) +{ + tree t, enter, sj, cond; + + t = build_fold_addr_expr_loc (input_location, (*ctcp)->stack_decl); + t = tree_cons (NULL, t, NULL); + enter = build_function_call (input_location, + objc_exception_try_enter_decl, t); + + t = objc_build_component_ref ((*ctcp)->stack_decl, + get_identifier ("buf")); + t = build_fold_addr_expr_loc (input_location, t); +#ifdef OBJCPLUS + /* Convert _setjmp argument to type that is expected. */ + if (prototype_p (TREE_TYPE (objc_setjmp_decl))) + t = convert (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl))), t); + else + t = convert (ptr_type_node, t); +#else + t = convert (ptr_type_node, t); +#endif + t = tree_cons (NULL, t, NULL); + sj = build_function_call (input_location, + objc_setjmp_decl, t); + + cond = build2 (COMPOUND_EXPR, TREE_TYPE (sj), enter, sj); + cond = c_common_truthvalue_conversion (input_location, cond); + + return build3 (COND_EXPR, void_type_node, cond, NULL, NULL); +} + +/* Build: + + DECL = objc_exception_extract(&_stack); */ + +static tree +next_sjlj_build_exc_extract (struct objc_try_context **ctcp, tree decl) +{ + tree t; + + t = build_fold_addr_expr_loc (input_location, (*ctcp)->stack_decl); + t = tree_cons (NULL, t, NULL); + t = build_function_call (input_location, + objc_exception_extract_decl, t); + t = convert (TREE_TYPE (decl), t); + t = build2 (MODIFY_EXPR, void_type_node, decl, t); + + return t; +} + +/* Build + if (objc_exception_match(obj_get_class(TYPE), _caught) + BODY + else if (...) + ... + else + { + _rethrow = _caught; + objc_exception_try_exit(&_stack); + } + from the sequence of CATCH_EXPRs in the current try context. */ + +static tree +next_sjlj_build_catch_list (struct objc_try_context **ctcp) +{ + tree_stmt_iterator i = tsi_start ((*ctcp)->catch_list); + tree catch_seq, t; + tree *last = &catch_seq; + bool saw_id = false; + + for (; !tsi_end_p (i); tsi_next (&i)) + { + tree stmt = tsi_stmt (i); + tree type = CATCH_TYPES (stmt); + tree body = CATCH_BODY (stmt); + + if (type != error_mark_node + && objc_is_object_id (TREE_TYPE (type))) + { + *last = body; + saw_id = true; + break; + } + else + { + tree args, cond; + + if (type == error_mark_node) + cond = error_mark_node; + else + { + args = tree_cons (NULL, (*ctcp)->caught_decl, NULL); + t = objc_get_class_reference (OBJC_TYPE_NAME (TREE_TYPE (type))); + args = tree_cons (NULL, t, args); + t = build_function_call (input_location, + objc_exception_match_decl, args); + cond = c_common_truthvalue_conversion (input_location, t); + } + t = build3 (COND_EXPR, void_type_node, cond, body, NULL); + SET_EXPR_LOCATION (t, EXPR_LOCATION (stmt)); + + *last = t; + last = &COND_EXPR_ELSE (t); + } + } + + if (!saw_id) + { + t = build2 (MODIFY_EXPR, void_type_node, (*ctcp)->rethrow_decl, + (*ctcp)->caught_decl); + SET_EXPR_LOCATION (t, (*ctcp)->end_catch_locus); + append_to_statement_list (t, last); + + t = next_sjlj_build_try_exit (ctcp); + SET_EXPR_LOCATION (t, (*ctcp)->end_catch_locus); + append_to_statement_list (t, last); + } + + return catch_seq; +} + +/* Build a complete @try-@catch-@finally block for legacy Darwin setjmp + exception handling. We aim to build: + + { + struct _objc_exception_data _stack; + id _rethrow = 0; + try + { + objc_exception_try_enter (&_stack); + if (_setjmp(&_stack.buf)) + { + id _caught = objc_exception_extract(&_stack); + objc_exception_try_enter (&_stack); + if (_setjmp(&_stack.buf)) + _rethrow = objc_exception_extract(&_stack); + else + CATCH-LIST + } + else + TRY-BLOCK + } + finally + { + if (!_rethrow) + objc_exception_try_exit(&_stack); + FINALLY-BLOCK + if (_rethrow) + objc_exception_throw(_rethrow); + } + } + + If CATCH-LIST is empty, we can omit all of the block containing + "_caught" except for the setting of _rethrow. Note the use of + a real TRY_FINALLY_EXPR here, which is not involved in EH per-se, + but handles goto and other exits from the block. */ + +static tree +next_sjlj_build_try_catch_finally (struct objc_try_context **ctcp) +{ + tree rethrow_decl, stack_decl, t; + tree catch_seq, try_fin, bind; + struct objc_try_context *cur_try_context = *ctcp; + + /* Create the declarations involved. */ + t = xref_tag (RECORD_TYPE, get_identifier (UTAG_EXCDATA)); + stack_decl = objc_create_temporary_var (t, NULL); + cur_try_context->stack_decl = stack_decl; + + rethrow_decl = objc_create_temporary_var (objc_object_type, NULL); + cur_try_context->rethrow_decl = rethrow_decl; + TREE_CHAIN (rethrow_decl) = stack_decl; + + /* Build the outermost variable binding level. */ + bind = build3 (BIND_EXPR, void_type_node, rethrow_decl, NULL, NULL); + SET_EXPR_LOCATION (bind, cur_try_context->try_locus); + TREE_SIDE_EFFECTS (bind) = 1; + + /* Initialize rethrow_decl. */ + t = build2 (MODIFY_EXPR, void_type_node, rethrow_decl, + convert (objc_object_type, null_pointer_node)); + SET_EXPR_LOCATION (t, cur_try_context->try_locus); + append_to_statement_list (t, &BIND_EXPR_BODY (bind)); + + /* Build the outermost TRY_FINALLY_EXPR. */ + try_fin = build2 (TRY_FINALLY_EXPR, void_type_node, NULL, NULL); + SET_EXPR_LOCATION (try_fin, cur_try_context->try_locus); + TREE_SIDE_EFFECTS (try_fin) = 1; + append_to_statement_list (try_fin, &BIND_EXPR_BODY (bind)); + + /* Create the complete catch sequence. */ + if (cur_try_context->catch_list) + { + tree caught_decl = objc_build_exc_ptr (ctcp); + catch_seq = build_stmt (input_location, BIND_EXPR, caught_decl, NULL, NULL); + TREE_SIDE_EFFECTS (catch_seq) = 1; + + t = next_sjlj_build_exc_extract (ctcp, caught_decl); + append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq)); + + t = next_sjlj_build_enter_and_setjmp (ctcp); + COND_EXPR_THEN (t) = next_sjlj_build_exc_extract (ctcp, rethrow_decl); + COND_EXPR_ELSE (t) = next_sjlj_build_catch_list (ctcp); + append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq)); + } + else + catch_seq = next_sjlj_build_exc_extract (ctcp, rethrow_decl); + SET_EXPR_LOCATION (catch_seq, cur_try_context->end_try_locus); + + /* Build the main register-and-try if statement. */ + t = next_sjlj_build_enter_and_setjmp (ctcp); + SET_EXPR_LOCATION (t, cur_try_context->try_locus); + COND_EXPR_THEN (t) = catch_seq; + COND_EXPR_ELSE (t) = cur_try_context->try_body; + TREE_OPERAND (try_fin, 0) = t; + + /* Build the complete FINALLY statement list. */ + t = next_sjlj_build_try_exit (ctcp); + t = build_stmt (input_location, COND_EXPR, + c_common_truthvalue_conversion + (input_location, rethrow_decl), + NULL, t); + SET_EXPR_LOCATION (t, cur_try_context->finally_locus); + append_to_statement_list (t, &TREE_OPERAND (try_fin, 1)); + + append_to_statement_list (cur_try_context->finally_body, + &TREE_OPERAND (try_fin, 1)); + + t = tree_cons (NULL, rethrow_decl, NULL); + t = build_function_call (input_location, + objc_exception_throw_decl, t); + t = build_stmt (input_location, COND_EXPR, + c_common_truthvalue_conversion (input_location, + rethrow_decl), + t, NULL); + SET_EXPR_LOCATION (t, cur_try_context->end_finally_locus); + append_to_statement_list (t, &TREE_OPERAND (try_fin, 1)); + + return bind; +} + +/* We do not expect this to be used at the moment. + If (a) it is possible to implement unwinder exceptions. + (b) we do it... then it might be possibly useful. +*/ +static GTY(()) tree objc_eh_personality_decl; + +static tree +objc_eh_runtime_type (tree type) +{ + tree ident, eh_id, decl, str; + + gcc_unreachable (); + if (type == error_mark_node) + { + /* Use 'ErrorMarkNode' as class name when error_mark_node is found + to prevent an ICE. Note that we know that the compiler will + terminate with an error and this 'ErrorMarkNode' class name will + never be actually used. */ + ident = get_identifier ("ErrorMarkNode"); + goto make_err_class; + } + + if (POINTER_TYPE_P (type) && objc_is_object_id (TREE_TYPE (type))) + { + ident = get_identifier ("id"); + goto make_err_class; + } + + if (!POINTER_TYPE_P (type) || !TYPED_OBJECT (TREE_TYPE (type))) + { +#ifdef OBJCPLUS + /* This routine is also called for c++'s catch clause; in which case, + we use c++'s typeinfo decl. */ + return build_eh_type_type (type); +#else + error ("non-objective-c type '%T' cannot be caught", type); + ident = get_identifier ("ErrorMarkNode"); + goto make_err_class; +#endif + } + else + ident = OBJC_TYPE_NAME (TREE_TYPE (type)); + +make_err_class: + /* If this class was already referenced, then it will be output during + meta-data emission, so we don't need to do it here. */ + decl = get_objc_string_decl (ident, class_names); + eh_id = add_objc_string (ident, class_names); + if (!decl) + { + /* Not found ... so we need to build it - from the freshly-entered id. */ + decl = get_objc_string_decl (ident, class_names); + str = my_build_string (IDENTIFIER_LENGTH (ident) + 1, + IDENTIFIER_POINTER (ident)); + /* We have to finalize this var here, because this might be called after + all the other metadata strings have been emitted. */ + finish_var_decl (decl, str); + } + return eh_id; +} + +static tree +objc_eh_personality (void) +{ + if (!objc_eh_personality_decl) +#ifndef OBJCPLUS + objc_eh_personality_decl = build_personality_function ("objc"); +#else + objc_eh_personality_decl = build_personality_function ("gxx"); +#endif + return objc_eh_personality_decl; +} + +/* --- interfaces --- */ + +static tree +build_throw_stmt (location_t loc, tree throw_expr, bool rethrown ATTRIBUTE_UNUSED) +{ + tree t; + VEC(tree, gc) *parms = VEC_alloc (tree, gc, 1); + /* A throw is just a call to the runtime throw function with the + object as a parameter. */ + VEC_quick_push (tree, parms, throw_expr); + t = build_function_call_vec (loc, objc_exception_throw_decl, parms, NULL); + VEC_free (tree, gc, parms); + return add_stmt (t); +} + +/* Build __builtin_eh_pointer, or the moral equivalent. In the case + of Darwin, we'll arrange for it to be initialized (and associated + with a binding) later. */ + +static tree +objc_build_exc_ptr (struct objc_try_context **cur_try_context) +{ + if (flag_objc_sjlj_exceptions) + { + tree var = (*cur_try_context)->caught_decl; + if (!var) + { + var = objc_create_temporary_var (objc_object_type, NULL); + (*cur_try_context)->caught_decl = var; + } + return var; + } + else + { + tree t; + t = built_in_decls[BUILT_IN_EH_POINTER]; + t = build_call_expr (t, 1, integer_zero_node); + return fold_convert (objc_object_type, t); + } +} + +static tree +begin_catch (struct objc_try_context **cur_try_context, tree type, + tree decl, tree compound, bool ellipsis ATTRIBUTE_UNUSED) +{ + tree t; + /* Record the data for the catch in the try context so that we can + finalize it later. We treat ellipsis the same way as catching + with 'id xyz'. */ + t = build_stmt (input_location, CATCH_EXPR, type, compound); + (*cur_try_context)->current_catch = t; + + /* Initialize the decl from the EXC_PTR_EXPR we get from the runtime. */ + t = objc_build_exc_ptr (cur_try_context); + t = convert (TREE_TYPE (decl), t); + return build2 (MODIFY_EXPR, void_type_node, decl, t); +} + +static void +finish_catch (struct objc_try_context **cur_try_context, tree current_catch) +{ + append_to_statement_list (current_catch, &((*cur_try_context)->catch_list)); +} + +static tree +finish_try_stmt (struct objc_try_context **cur_try_context) +{ + tree stmt; + struct objc_try_context *c = *cur_try_context; + /* If we're doing Darwin setjmp exceptions, build the big nasty. */ + if (flag_objc_sjlj_exceptions) + { + bool save = in_late_binary_op; + in_late_binary_op = true; + if (!c->finally_body) + { + c->finally_locus = input_location; + c->end_finally_locus = input_location; + } + stmt = next_sjlj_build_try_catch_finally (cur_try_context); + in_late_binary_op = save; + } + else + /* This doesn't happen at the moment... but maybe one day... */ + { + /* Otherwise, nest the CATCH inside a FINALLY. */ + stmt = c->try_body; + if (c->catch_list) + stmt = build_stmt (c->try_locus, TRY_CATCH_EXPR, stmt, c->catch_list); + if (c->finally_body) + stmt = build_stmt (c->try_locus, TRY_FINALLY_EXPR, stmt, c->finally_body); + } + return stmt; +} + +#include "gt-objc-objc-next-runtime-abi-01.h" diff --git a/gcc/objc/objc-next-runtime-abi-02.c b/gcc/objc/objc-next-runtime-abi-02.c new file mode 100644 index 0000000..46e5693 --- /dev/null +++ b/gcc/objc/objc-next-runtime-abi-02.c @@ -0,0 +1,3750 @@ +/* Next Runtime (ABI-2) private. + Copyright (C) 2011 Free Software Foundation, Inc. + + Contributed by Iain Sandoe and based, in part, on an implementation in + 'branches/apple/trunk' contributed by Apple Computer Inc. + +This file is part of GCC. + +GCC 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, or (at your option) +any later version. + +GCC 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/>. */ + +/* The NeXT ABI2 is used for m64 implementations on Darwin/OSX machines. + + This version is intended to match (logically) output of Apple's 4.2.1 + compiler. + + References: + FSF GCC branches/apple/trunk. + objc4-371.2 Open Source release (Apple Computer). (objc-runtime-new.h) + gcc_42-5664 Apple Local modifications to GCC (Apple Computer). +*/ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" + +#ifdef OBJCPLUS +#include "cp-tree.h" +#else +#include "c-tree.h" +#include "c-lang.h" +#endif +#include "langhooks.h" +#include "c-family/c-objc.h" +#include "objc-act.h" + +/* When building Objective-C++, we are not linking against the C front-end + and so need to replicate the C tree-construction functions in some way. */ +#ifdef OBJCPLUS +#define OBJCP_REMAP_FUNCTIONS +#include "objcp-decl.h" +#endif /* OBJCPLUS */ + +#include "ggc.h" +#include "target.h" +#include "obstack.h" +#include "tree-iterator.h" + +/* These are only used for encoding ivars. */ +extern struct obstack util_obstack; +extern char *util_firstobj; + +#include "objc-runtime-hooks.h" + +#include "objc-runtime-shared-support.h" + +/* ABI 2 Private definitions. */ +#define DEF_CONSTANT_STRING_CLASS_NAME "NSConstantString" + +#define TAG_GETCLASS "objc_getClass" +#define TAG_GETMETACLASS "objc_getMetaClass" + +#define TAG_MSGSEND "objc_msgSend" +#define TAG_MSGSENDSUPER "objc_msgSendSuper" +#define TAG_MSGSEND_STRET "objc_msgSend_stret" +#define TAG_MSGSENDSUPER_STRET "objc_msgSendSuper_stret" + +#define TAG_NEXT_EHVTABLE_NAME "objc_ehtype_vtable" +#define TAG_V2_EH_TYPE "objc_ehtype_t" + +#define UTAG_V2_CLASS "_class_t" +#define UTAG_V2_CLASS_RO "_class_ro_t" +#define UTAG_V2_PROTOCOL "_protocol_t" +#define UTAG_V2_PROTOCOL_LIST "_protocol_list_t" + +#define UTAG_V2_EH_TYPE "_objc_ehtype_t" + +#define OBJC2_CLS_HAS_CXX_STRUCTORS 0x0004L + +enum objc_v2_tree_index +{ + /* Templates. */ + OCTI_V2_CLS_TEMPL, + OCTI_V2_CAT_TEMPL, + OCTI_V2_CLS_RO_TEMPL, + OCTI_V2_PROTO_TEMPL, + OCTI_V2_IVAR_TEMPL, + OCTI_V2_IVAR_LIST_TEMPL, + OCTI_V2_MESSAGE_REF_TEMPL, + OCTI_V2_SUPER_MESSAGE_REF_TEMPL, + + OCTI_V2_MESSAGE_SELECTOR_TYPE, + OCTI_V2_SUPER_MESSAGE_SELECTOR_TYPE, + OCTI_V2_IMP_TYPE, + OCTI_V2_SUPER_IMP_TYPE, + + OCTI_V2_CACHE_DECL, + OCTI_V2_VTABLE_DECL, + + OCTI_V2_PROPERTY_TEMPL, + + /* V2 messaging. */ + OCTI_V2_UMSG_FIXUP_DECL, + OCTI_V2_UMSG_STRET_FIXUP_DECL, + OCTI_V2_UMSG_ID_FIXUP_DECL, + OCTI_V2_UMSG_ID_STRET_FIXUP_DECL, + OCTI_V2_UMSG_SUPER2_FIXUP_DECL, + OCTI_V2_UMSG_SUPER2_STRET_FIXUP_DECL, + + /* Exceptions - related. */ + OCTI_V2_BEGIN_CATCH_DECL, + OCTI_V2_END_CATCH_DECL, + OCTI_V2_RETHROW_DECL, + + OCTI_V2_MAX +}; + +#define objc_v2_class_template objc_v2_global_trees[OCTI_V2_CLS_TEMPL] +#define objc_v2_class_ro_template \ + objc_v2_global_trees[OCTI_V2_CLS_RO_TEMPL] +#define objc_v2_category_template \ + objc_v2_global_trees[OCTI_V2_CAT_TEMPL] +#define objc_v2_protocol_template \ + objc_v2_global_trees[OCTI_V2_PROTO_TEMPL] + +/* struct message_ref_t */ +#define objc_v2_message_ref_template \ + objc_v2_global_trees[OCTI_V2_MESSAGE_REF_TEMPL] + +#define objc_v2_ivar_list_ptr objc_v2_global_trees[OCTI_V2_IVAR_LIST_TEMPL] + +/* struct super_message_ref_t */ +#define objc_v2_super_message_ref_template \ + objc_v2_global_trees[OCTI_V2_SUPER_MESSAGE_REF_TEMPL] + +/* struct message_ref_t* */ +#define objc_v2_selector_type objc_v2_global_trees[OCTI_V2_MESSAGE_SELECTOR_TYPE] +/* struct super_super_message_ref_t */ +#define objc_v2_super_selector_type \ + objc_v2_global_trees[OCTI_V2_SUPER_MESSAGE_SELECTOR_TYPE] +#define objc_v2_imp_type objc_v2_global_trees[OCTI_V2_IMP_TYPE] +#define objc_v2_super_imp_type objc_v2_global_trees[OCTI_V2_SUPER_IMP_TYPE] + +#define UOBJC_V2_CACHE_decl objc_v2_global_trees[OCTI_V2_CACHE_DECL] +#define UOBJC_V2_VTABLE_decl objc_v2_global_trees[OCTI_V2_VTABLE_DECL] + +#define objc_v2_ivar_template objc_v2_global_trees[OCTI_V2_IVAR_TEMPL] +#define objc_v2_property_template \ + objc_v2_global_trees[OCTI_V2_PROPERTY_TEMPL] + +/* V2 Messaging */ + +/* objc_msgSend_fixup_rtp */ +#define umsg_fixup_decl objc_v2_global_trees[OCTI_V2_UMSG_FIXUP_DECL] +/* objc_msgSend_stret_fixup_rtp */ +#define umsg_stret_fixup_decl objc_v2_global_trees[OCTI_V2_UMSG_STRET_FIXUP_DECL] +/* objc_msgSendId_fixup_rtp */ +#define umsg_id_fixup_decl objc_v2_global_trees[OCTI_V2_UMSG_ID_FIXUP_DECL] +/* objc_msgSendId_stret_fixup_rtp */ +#define umsg_id_stret_fixup_decl \ + objc_v2_global_trees[OCTI_V2_UMSG_ID_STRET_FIXUP_DECL] +/* objc_msgSendSuper2_fixup_rtp */ +#define umsg_id_super2_fixup_decl \ + objc_v2_global_trees[OCTI_V2_UMSG_SUPER2_FIXUP_DECL] +/* objc_msgSendSuper2_stret_fixup_rtp */ +#define umsg_id_super2_stret_fixup_decl \ + objc_v2_global_trees[OCTI_V2_UMSG_SUPER2_STRET_FIXUP_DECL] + +#define objc2_begin_catch_decl objc_v2_global_trees[OCTI_V2_BEGIN_CATCH_DECL] +#define objc2_end_catch_decl objc_v2_global_trees[OCTI_V2_END_CATCH_DECL] +#define objc_rethrow_exception_decl \ + objc_v2_global_trees[OCTI_V2_RETHROW_DECL] + +/* rt_trees identifiers - shared between NeXT implementations. These allow + the FE to tag meta-data in a manner that survives LTO and can be used when + the runtime requires that certain meta-data items appear in particular + named sections. */ + +#include "objc-next-metadata-tags.h" +extern GTY(()) tree objc_rt_trees[OCTI_RT_META_MAX]; + +/* The OCTI_V2_... enumeration itself is in above. */ +static GTY(()) tree objc_v2_global_trees[OCTI_V2_MAX]; + +static void next_runtime_02_initialize (void); + +static void build_v2_message_ref_templates (void); +static void build_v2_class_templates (void); +static void build_v2_super_template (void); +static void build_v2_category_template (void); +static void build_v2_protocol_template (void); + +static tree next_runtime_abi_02_super_superclassfield_id (void); + +static tree next_runtime_abi_02_class_decl (tree); +static tree next_runtime_abi_02_metaclass_decl (tree); +static tree next_runtime_abi_02_category_decl (tree); +static tree next_runtime_abi_02_protocol_decl (tree); +static tree next_runtime_abi_02_string_decl (tree, const char *, string_section); + +static tree next_runtime_abi_02_get_class_reference (tree); +static tree next_runtime_abi_02_build_selector_reference (location_t, tree, tree); +static tree next_runtime_abi_02_get_protocol_reference (location_t, tree); +static tree next_runtime_abi_02_build_ivar_ref (location_t, tree, tree); +static tree next_runtime_abi_02_get_class_super_ref (location_t, struct imp_entry *, bool); +static tree next_runtime_abi_02_get_category_super_ref (location_t, struct imp_entry *, bool); + +static tree next_runtime_abi_02_receiver_is_class_object (tree); +static tree next_runtime_abi_02_get_arg_type_list_base (tree, int, int); +static tree next_runtime_abi_02_build_objc_method_call (location_t, tree, tree, + tree, tree, tree, int); +static bool next_runtime_abi_02_setup_const_string_class_decl (void); +static tree next_runtime_abi_02_build_const_string_constructor (location_t, tree, int); + +static tree create_extern_decl (tree, const char *); + +static void objc_generate_v2_next_metadata (void); +static bool objc2_objc_exception_attr (tree); + +/* void build_v2_protocol_reference (tree);*/ +static void build_v2_ehtype_template (void); +static void build_v2_eh_catch_objects (void); +static tree next_runtime_02_eh_type (tree); +static tree objc_eh_personality (void); +static tree build_throw_stmt (location_t, tree, bool); +static tree objc_build_exc_ptr (struct objc_try_context **); +static tree begin_catch (struct objc_try_context **, tree, tree, tree, bool); +static void finish_catch (struct objc_try_context **, tree); +static tree finish_try_stmt (struct objc_try_context **); + +static GTY ((length ("SIZEHASHTABLE"))) hash *extern_names; + +bool +objc_next_runtime_abi_02_init (objc_runtime_hooks *rthooks) +{ + extern_names = ggc_alloc_cleared_vec_hash (SIZEHASHTABLE); + + if (flag_objc_exceptions && flag_objc_sjlj_exceptions) + { + inform (UNKNOWN_LOCATION, "%<-fobjc-sjlj-exceptions%> is ignored for " + "%<-fnext-runtime%> when %<-fobjc-abi-version%> >= 2"); + flag_objc_sjlj_exceptions = 0; + } + + rthooks->initialize = next_runtime_02_initialize; + rthooks->default_constant_string_class_name = DEF_CONSTANT_STRING_CLASS_NAME; + rthooks->tag_getclass = TAG_GETCLASS; + rthooks->super_superclassfield_ident = next_runtime_abi_02_super_superclassfield_id; + + rthooks->class_decl = next_runtime_abi_02_class_decl; + rthooks->metaclass_decl = next_runtime_abi_02_metaclass_decl; + rthooks->category_decl = next_runtime_abi_02_category_decl; + rthooks->protocol_decl = next_runtime_abi_02_protocol_decl; + rthooks->string_decl = next_runtime_abi_02_string_decl; + + rthooks->get_class_reference = next_runtime_abi_02_get_class_reference; + rthooks->build_selector_reference = next_runtime_abi_02_build_selector_reference; + rthooks->get_protocol_reference = next_runtime_abi_02_get_protocol_reference; + rthooks->build_ivar_reference = next_runtime_abi_02_build_ivar_ref; + rthooks->get_class_super_ref = next_runtime_abi_02_get_class_super_ref; + rthooks->get_category_super_ref = next_runtime_abi_02_get_category_super_ref; + + rthooks->receiver_is_class_object = next_runtime_abi_02_receiver_is_class_object; + rthooks->get_arg_type_list_base = next_runtime_abi_02_get_arg_type_list_base; + rthooks->build_objc_method_call = next_runtime_abi_02_build_objc_method_call; + + rthooks->setup_const_string_class_decl = + next_runtime_abi_02_setup_const_string_class_decl; + rthooks->build_const_string_constructor = + next_runtime_abi_02_build_const_string_constructor; + + rthooks->build_throw_stmt = build_throw_stmt; + rthooks->build_exc_ptr = objc_build_exc_ptr; + rthooks->begin_catch = begin_catch; + rthooks->finish_catch = finish_catch; + rthooks->finish_try_stmt = finish_try_stmt; + + rthooks->generate_metadata = objc_generate_v2_next_metadata; + return true; +} + +/* We need a way to convey what kind of meta-data are represented by a given + variable, since each type is expected (by the runtime) to be found in a + specific named section. The solution must be usable with LTO. + + The scheme used for NeXT ABI 0/1 (partial matching of variable names) is not + satisfactory when LTO is used with ABI-2. We now tag ObjC meta-data with + identification attributes in the front end. The back-end may choose to act + on these as it requires. */ + +static void +next_runtime_abi_02_init_metadata_attributes (void) +{ + if (!objc_meta) + objc_meta = get_identifier ("OBJC2META"); + + if (!meta_base) + meta_base = get_identifier ("V2_BASE"); + + meta_class = get_identifier ("G2_CLAS"); + meta_metaclass = get_identifier ("G2_META"); + meta_category = + meta_protocol = meta_base; + + meta_clac_vars = + meta_clai_vars = meta_base; + + meta_clac_meth = + meta_clai_meth = + meta_catc_meth = + meta_cati_meth = + meta_proto_cls_meth = + meta_proto_nst_meth = meta_base; + + meta_clas_prot = + meta_catg_prot = meta_base; + + meta_sel_refs = get_identifier ("V2_SRFS"); + + meta_class_name = + meta_meth_name = + meta_meth_type = + meta_prop_name_attr = get_identifier ("V2_STRG"); + + meta_mref = get_identifier ("V2_MREF"); + meta_class_ref = get_identifier ("V2_CLRF"); + meta_superclass_ref = get_identifier ("V2_SURF"); + + meta_label_classlist = get_identifier ("V2_CLAB"); + meta_label_nonlazy_classlist = get_identifier ("V2_NLCL"); + meta_label_categorylist = get_identifier ("V2_CALA"); + meta_label_nonlazy_categorylist = get_identifier ("V2_NLCA"); + + meta_label_protocollist = get_identifier ("V2_PLST"); + meta_proto_ref = get_identifier ("V2_PRFS"); + + meta_info = get_identifier ("V2_INFO"); + + meta_ehtype = get_identifier ("V2_EHTY"); + + meta_const_str = get_identifier ("V2_CSTR"); +} + +static void next_runtime_02_initialize (void) +{ + tree type; +#ifdef OBJCPLUS + /* For all objc ABIs -fobjc-call-cxx-cdtors is on by default. */ + if (!global_options_set.x_flag_objc_call_cxx_cdtors) + global_options.x_flag_objc_call_cxx_cdtors = 1; +#endif + + /* Set up attributes to be attached to the meta-data so that they + will be placed in the correct sections. */ + next_runtime_abi_02_init_metadata_attributes (); + + /* `struct objc_selector *' */ + objc_selector_type = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (TAG_SELECTOR))); + + /* IMP : id (*) (id, _message_ref_t*, ...) + SUPER_IMP : id (*) ( super_t*, _super_message_ref_t*, ...) + objc_v2_selector_type. */ + build_v2_message_ref_templates (); + + objc_v2_ivar_list_ptr = + build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier ("_ivar_list_t"))); + + objc_prop_list_ptr = + build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier ("_prop_list_t"))); + + build_v2_class_templates (); + build_v2_super_template (); + build_v2_protocol_template (); + build_v2_category_template (); + + /* id objc_msgSend_fixup_rtp (id, struct message_ref_t*, ...); */ + type = build_varargs_function_type_list (objc_object_type, + objc_object_type, + objc_v2_selector_type, + NULL_TREE); + umsg_fixup_decl = add_builtin_function ("objc_msgSend_fixup", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (umsg_fixup_decl) = 0; + + /* id objc_msgSend_stret_fixup_rtp (id, struct message_ref_t*, ...); */ + umsg_stret_fixup_decl = add_builtin_function ("objc_msgSend_stret_fixup", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (umsg_stret_fixup_decl) = 0; + + /* id objc_msgSendId_fixup_rtp (id, struct message_ref_t*, ...); */ + umsg_id_fixup_decl = add_builtin_function ("objc_msgSendId_fixup", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (umsg_id_fixup_decl) = 0; + + /* id objc_msgSendId_stret_fixup_rtp + (id, struct message_ref_t*, ...); */ + umsg_id_stret_fixup_decl = add_builtin_function ("objc_msgSendId_stret_fixup", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (umsg_id_stret_fixup_decl) = 0; + + /* id objc_msgSendSuper2_fixup_rtp + (struct objc_super *, struct message_ref_t*, ...); */ + type = build_varargs_function_type_list (objc_object_type, + objc_super_type, + objc_v2_super_selector_type, + NULL_TREE); + umsg_id_super2_fixup_decl = add_builtin_function ("objc_msgSendSuper2_fixup", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (umsg_id_super2_fixup_decl) = 0; + + /* id objc_msgSendSuper2_stret_fixup_rtp + (struct objc_super *, struct message_ref_t*, ...); */ + umsg_id_super2_stret_fixup_decl = + add_builtin_function ("objc_msgSendSuper2_stret_fixup", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (umsg_id_super2_stret_fixup_decl) = 0; + + /* Present in the library, but unused by the FE. */ + /* Protocol *objc_getProtocol (const char *) + type = build_function_type_list (objc_protocol_type, + const_string_type_node, + NULL_TREE); + objc_v2_getprotocol_decl = add_builtin_function ("objc_getProtocol", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (objc_v2_getprotocol_decl) = 0;*/ + + UOBJC_V2_CACHE_decl = create_extern_decl (ptr_type_node, + "_objc_empty_cache"); + + UOBJC_V2_VTABLE_decl = create_extern_decl (objc_v2_imp_type, + "_objc_empty_vtable"); + + /* id objc_getClass (const char *); */ + type = build_function_type_list (objc_object_type, + const_string_type_node, + NULL_TREE); + objc_get_class_decl = add_builtin_function (TAG_GETCLASS, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + /* id objc_getMetaClass (const char *); */ + objc_get_meta_class_decl = add_builtin_function (TAG_GETMETACLASS, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + /* This is the type of all of the following functions objc_copyStruct(). */ + type = build_function_type_list (void_type_node, + ptr_type_node, + const_ptr_type_node, + ptrdiff_type_node, + boolean_type_node, + boolean_type_node, + NULL_TREE); + /* Declare the following function: + void + objc_copyStruct (void *destination, const void *source, + ptrdiff_t size, BOOL is_atomic, BOOL has_strong); */ + objc_copyStruct_decl = add_builtin_function ("objc_copyStruct", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (objc_copyStruct_decl) = 0; + objc_getPropertyStruct_decl = NULL_TREE; + objc_setPropertyStruct_decl = NULL_TREE; + + gcc_assert (!flag_objc_sjlj_exceptions); + + /* Although we warn that fobjc-exceptions is required for exceptions + code, we carry on an create it anyway. */ + + /* This can be required, even when exceptions code is not present, + when an __attribute__((objc_exception)) is applied to a class. */ + build_v2_ehtype_template (); + + /* void * objc_begin_catch (void *) */ + type = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + OBJC_VOID_AT_END)); + + objc2_begin_catch_decl = add_builtin_function ("objc_begin_catch", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (objc2_begin_catch_decl) = 0; + + /* void objc_end_catch () */ + type = build_function_type (void_type_node, OBJC_VOID_AT_END); + objc2_end_catch_decl = add_builtin_function ("objc_end_catch", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (objc2_end_catch_decl) = 0; + + /* void objc_exception_rethrow (void) */ + type = build_function_type (void_type_node, OBJC_VOID_AT_END); + objc_rethrow_exception_decl = + add_builtin_function ("objc_exception_rethrow", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (objc_rethrow_exception_decl) = 0; + using_eh_for_cleanups (); + lang_hooks.eh_runtime_type = next_runtime_02_eh_type; + lang_hooks.eh_personality = objc_eh_personality; +} + +/* NOTE --- templates --- */ + +/* Set 'objc_v2_message_ref_template' to the data type node for 'struct _message_ref_t'. + This needs to be done just once per compilation. Also Set + 'objc_v2_super_message_ref_template' to data type node + for 'struct _super_message_ref_t'. */ + +/* struct _message_ref_t { + IMP messenger; + SEL name; + }; + where IMP is: id (*) (id, _message_ref_t*, ...) +*/ + +/* struct _super_message_ref_t { + SUPER_IMP messenger; + SEL name; + }; + where SUPER_IMP is: id (*) ( super_t*, _super_message_ref_t*, ...) +*/ + +static void +build_v2_message_ref_templates (void) +{ + tree ptr_message_ref_t; + tree decls, *chain = NULL; + + /* struct _message_ref_t {...} */ + objc_v2_message_ref_template = + objc_start_struct (get_identifier ("_message_ref_t")); + + /* IMP messenger; */ + ptr_message_ref_t = + build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier ("_message_ref_t"))); + + objc_v2_imp_type = + build_pointer_type (build_function_type_list + (objc_object_type, + objc_object_type, + ptr_message_ref_t, + NULL_TREE)); + + decls = add_field_decl (objc_v2_imp_type, "messenger", &chain); + + /* SEL name; */ + add_field_decl (objc_selector_type, "name", &chain); + + objc_finish_struct (objc_v2_message_ref_template, decls); + + objc_v2_selector_type = build_pointer_type (objc_v2_message_ref_template); + + chain = NULL; + /* struct _super_message_ref_t {...} */ + objc_v2_super_message_ref_template = + objc_start_struct (get_identifier ("_super_message_ref_t")); + + /* SUPER_IMP messenger; */ + ptr_message_ref_t = build_pointer_type + (xref_tag (RECORD_TYPE, + get_identifier ("_super_message_ref_t"))); + + objc_v2_super_imp_type = + build_pointer_type (build_function_type_list + (objc_object_type, + objc_super_type, + ptr_message_ref_t, + NULL_TREE)); + + add_field_decl (objc_v2_super_imp_type, "messenger", &chain); + + /* SEL name; */ + add_field_decl (objc_selector_type, "name", &chain); + + objc_finish_struct (objc_v2_super_message_ref_template, decls); + objc_v2_super_selector_type = + build_pointer_type (objc_v2_super_message_ref_template); +} + +/* Build following types which represent each class implementation. + +struct class_ro_t { + uint32_t const flags; + uint32_t const instanceStart; + uint32_t const instanceSize; +#ifdef __LP64__ + uint32_t const reserved; +#endif + const uint8_t * const ivarLayout; + const char *const name; + const struct method_list_t * const baseMethods; + const struct objc_protocol_list *const baseProtocols; + const struct ivar_list_t *const ivars; + const uint8_t * const weakIvarLayout; + const struct _prop_list_t * const properties; +}; + +struct class_t { + struct class_t *isa; + struct class_t *superclass; + void *cache; + IMP *vtable; + + ...When this is active - it will point to a rw version, but + when we build the meta-data we point it to the ro... + struct class_ro_t *data; +}; + +*/ + +static void +build_v2_class_templates (void) +{ + tree cnst_strg_type; + tree decls, *chain = NULL; + + /* struct class_ro_t {...} */ + objc_v2_class_ro_template = + objc_start_struct (get_identifier (UTAG_V2_CLASS_RO)); + + /* uint32_t const flags; */ + decls = add_field_decl (integer_type_node, "flags", &chain); + + /* uint32_t const instanceStart */ + add_field_decl (integer_type_node, "instanceStart", &chain); + + /* uint32_t const instanceSize */ + add_field_decl (integer_type_node, "instanceSize", &chain); + + /* This ABI is currently only used on m64 NeXT, we choose to + make the alignment padding explicit. */ + /* uint32_t const reserved. */ + add_field_decl (integer_type_node, "reserved", &chain); + + /* const uint8_t * const ivarLayout */ + cnst_strg_type = build_pointer_type (unsigned_char_type_node); + add_field_decl (cnst_strg_type, "ivarLayout", &chain); + + /* const char *const name; */ + add_field_decl (string_type_node, "name", &chain); + + /* const struct method_list_t * const baseMethods */ + add_field_decl (objc_method_list_ptr, "baseMethods", &chain); + + /* const struct objc_protocol_list *const baseProtocols */ + add_field_decl (build_pointer_type + (xref_tag (RECORD_TYPE, + get_identifier (UTAG_V2_PROTOCOL_LIST))), + "baseProtocols", &chain); + + /* const struct ivar_list_t *const ivars */ + add_field_decl (objc_v2_ivar_list_ptr, "ivars", &chain); + + /* const uint8_t * const weakIvarLayout; */ + add_field_decl (cnst_strg_type, "weakIvarLayout", &chain); + + /* struct _prop_list_t * baseProperties */ + add_field_decl (objc_prop_list_ptr, "baseProperties", &chain); + + objc_finish_struct (objc_v2_class_ro_template, decls); + + chain = NULL; + /* struct class_t {...} */ + objc_v2_class_template = + objc_start_struct (get_identifier (UTAG_V2_CLASS)); + + /* struct class_t *isa; */ + decls = add_field_decl (build_pointer_type (objc_v2_class_template), + "isa", &chain); + + /* struct class_t * const superclass */ + add_field_decl (build_pointer_type (objc_v2_class_template), + "superclass", &chain); + + /* void *cache; */ + add_field_decl (build_pointer_type (void_type_node), "cache", &chain); + + /* IMP *vtable; */ + add_field_decl (build_pointer_type (objc_v2_imp_type), "vtable", &chain); + + /* struct class_ro_t *ro; */ + add_field_decl (build_pointer_type (objc_v2_class_ro_template), "ro", &chain); + + objc_finish_struct (objc_v2_class_template, decls); +} + +/* struct _objc_super { + struct _objc_object *self; + Class cls; + }; */ + +void +build_v2_super_template (void) +{ + tree decls, *chain = NULL; + + objc_super_template = objc_start_struct (get_identifier (UTAG_SUPER)); + + /* struct _objc_object *self; */ + decls = add_field_decl (objc_object_type, "self", &chain); + + /* Class cls; */ + add_field_decl (objc_class_type, "cls", &chain); + + objc_finish_struct (objc_super_template, decls); +} + +/* struct protocol_t { + Class isa; + const char * const protocol_name; + const struct protocol_list_t * const protocol_list; + const struct method_list_t * const instance_methods; + const struct method_list_t * const class_methods; + const struct method_list_t * optionalInstanceMethods; + const struct method_list_t * optionalClassMethod + const struct _prop_list_t * const properties; + const uint32_t size; + const uint32_t flags; + } +*/ +static void +build_v2_protocol_template (void) +{ + tree decls, *chain = NULL; + + objc_v2_protocol_template = + objc_start_struct (get_identifier (UTAG_V2_PROTOCOL)); + + /* Class isa; */ + decls = add_field_decl (objc_object_type, "isa", &chain); + + /* char *protocol_name; */ + add_field_decl (string_type_node, "protocol_name", &chain); + + /* const struct protocol_list_t * const protocol_list; */ + add_field_decl (build_pointer_type (objc_v2_protocol_template), + "protocol_list", &chain); + + /* const struct method_list_t * const instance_methods; */ + add_field_decl (objc_method_proto_list_ptr, "instance_methods", &chain); + + /* const struct method_list_t * const class_methods; */ + add_field_decl (objc_method_proto_list_ptr, "class_methods", &chain); + + /* const struct method_list_t * optionalInstanceMethods */ + add_field_decl (objc_method_proto_list_ptr, "optionalInstanceMethods", &chain); + + /* const struct method_list_t * optionalClassMethods */ + add_field_decl (objc_method_proto_list_ptr, "optionalClassMethods", &chain); + + /* struct _prop_list_t * properties; */ + add_field_decl (objc_prop_list_ptr, "properties", &chain); + + /* const uint32_t size; */ + add_field_decl (integer_type_node, "size", &chain); + + /* const uint32_t flags; */ + add_field_decl (integer_type_node, "flags", &chain); + + objc_finish_struct (objc_v2_protocol_template, decls); +} + +/* Build type for a category: + struct category_t { + const char * const name; + struct class_t *const cls; + const struct method_list_t * const instance_methods; + const struct method_list_t * const class_methods; + const struct protocol_list_t * const protocols; + const struct _prop_list_t * const properties; + } +*/ + +static void +build_v2_category_template (void) +{ + tree decls, *chain = NULL; + + objc_v2_category_template = + objc_start_struct (get_identifier ("_category_t")); + + /* char *name; */ + decls = add_field_decl (string_type_node, "name", &chain); + + /* struct class_t *const cls; */ + add_field_decl (build_pointer_type (objc_v2_class_template), "cls", &chain); + + /* struct method_list_t *instance_methods; */ + add_field_decl (objc_method_list_ptr, "instance_methods", &chain); + + /* struct method_list_t *class_methods; */ + add_field_decl (objc_method_list_ptr, "class_methods", &chain); + + /* struct protocol_list_t *protocol_list; */ + add_field_decl (build_pointer_type (objc_v2_protocol_template), + "protocol_list", &chain ); + + /* struct _prop_list_t * properties; */ + add_field_decl (objc_prop_list_ptr, "properties", &chain); + + objc_finish_struct (objc_v2_category_template, decls); +} + +/* NOTE --- Decls, Identifiers, Names etc. --- */ + +/* This routine is given a name and returns a matching extern variable if + one is found. +*/ + +static tree +hash_name_lookup (hash *hashlist, tree name) +{ + hash target; + + target = hashlist[IDENTIFIER_HASH_VALUE (name) % SIZEHASHTABLE]; + + while (target) + { + if (name == DECL_NAME (target->key)) + return target->key; + + target = target->next; + } + return 0; +} + +/* This routine is given an extern variable and enters it in its hash table. + Note that hashing is done on its inner IDENTIFIER_NODE node. +*/ + +static void +hash_name_enter (hash *hashlist, tree id) +{ + hash obj; + int slot = IDENTIFIER_HASH_VALUE (DECL_NAME (id)) % SIZEHASHTABLE; + + obj = ggc_alloc_hashed_entry (); + obj->list = 0; + obj->next = hashlist[slot]; + obj->key = id; + + hashlist[slot] = obj; /* append to front */ +} + +/* Create a declaration "extern <type> <name>;" + The var will need to be finalized (e.g. by calling finish_var_decl()). */ + +static tree +create_extern_decl (tree type, const char *name) +{ + tree id = get_identifier (name); + tree var = hash_name_lookup (extern_names, id); + if (var) + return var; + /* New name. */ + var = start_var_decl (type, name); + TREE_STATIC (var) = 0; + DECL_EXTERNAL (var) = 1; + TREE_PUBLIC (var) = 1; + hash_name_enter (extern_names, var); + return var; +} + +/* Create a globally visible definition for variable NAME of a given TYPE. The + finish_var_decl() routine will need to be called on it afterwards. */ + +static tree +create_global_decl (tree type, const char *name) +{ + tree id = get_identifier (name); + tree var = hash_name_lookup (extern_names, id); + if (var) + { + DECL_EXTERNAL (var) = 0; + TREE_STATIC (var) = 1; + } + else + { + var = start_var_decl (type, name); + hash_name_enter (extern_names, var); + } + TREE_PUBLIC (var) = 1; + return var; +} + +/* Create a symbol with __attribute__ ((visibility ("hidden"))) + attribute (private extern) */ + +static tree +create_hidden_decl (tree type, const char *name) +{ + tree decl = create_global_decl (type, name); + DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN; + DECL_VISIBILITY_SPECIFIED (decl) = 1; + return decl; +} + +/* Irritatingly, we have a different superclass field name for ABI=2. */ + +static tree +next_runtime_abi_02_super_superclassfield_id (void) +{ + if (!super_superclassfield_id) + super_superclassfield_id = get_identifier ("cls"); + return super_superclassfield_id; +} + +static tree +next_runtime_abi_02_class_decl (tree klass) +{ + tree decl; + char buf[BUFSIZE]; + snprintf (buf, BUFSIZE, "OBJC_CLASS_$_%s", + IDENTIFIER_POINTER (CLASS_NAME (klass))); + /* ObjC2 classes are extern visible. */ + decl = create_global_decl (objc_v2_class_template, buf); + OBJCMETA (decl, objc_meta, meta_class); + return decl; +} + +static tree +next_runtime_abi_02_metaclass_decl (tree klass) +{ + tree decl; + char buf[BUFSIZE]; + snprintf (buf, BUFSIZE, "OBJC_METACLASS_$_%s", + IDENTIFIER_POINTER (CLASS_NAME (klass))); + /* ObjC2 classes are extern visible. */ + decl = create_global_decl (objc_v2_class_template, buf); + OBJCMETA (decl, objc_meta, meta_metaclass); + return decl; +} + +static tree +next_runtime_abi_02_category_decl (tree klass) +{ + tree decl; + char buf[BUFSIZE]; + snprintf (buf, BUFSIZE, "_OBJC_Category_%s_on_%s", + IDENTIFIER_POINTER (CLASS_SUPER_NAME (klass)), + IDENTIFIER_POINTER (CLASS_NAME (klass))); + decl = start_var_decl (objc_v2_category_template, buf); + OBJCMETA (decl, objc_meta, meta_category); + return decl; +} + +static tree +next_runtime_abi_02_protocol_decl (tree p) +{ + tree decl; + char buf[BUFSIZE]; + + /* static struct _objc_protocol _OBJC_Protocol_<mumble>; */ + snprintf (buf, BUFSIZE, "_OBJC_Protocol_%s", + IDENTIFIER_POINTER (PROTOCOL_NAME (p))); + decl = start_var_decl (objc_v2_protocol_template, buf); + OBJCMETA (decl, objc_meta, meta_protocol); + return decl; +} + +static tree +next_runtime_abi_02_string_decl (tree type, const char *name, string_section where) +{ + tree var = start_var_decl (type, name); + switch (where) + { + case class_names: + OBJCMETA (var, objc_meta, meta_class_name); + break; + case meth_var_names: + OBJCMETA (var, objc_meta, meta_meth_name); + break; + case meth_var_types: + OBJCMETA (var, objc_meta, meta_meth_type); + break; + case prop_names_attr: + OBJCMETA (var, objc_meta, meta_prop_name_attr); + break; + default: + OBJCMETA (var, objc_meta, meta_base); + break; + } + return var; +} + +/* NOTE --- entry --- */ + +typedef struct GTY(()) ident_data_tuple { + tree ident; + tree data; +} ident_data_tuple ; +DEF_VEC_O(ident_data_tuple); +DEF_VEC_ALLOC_O(ident_data_tuple, gc); + +/* This routine creates a file scope static variable of type 'Class' to hold + the address of a class. */ + +static tree +build_v2_class_reference_decl (tree ident) +{ + tree decl; + char buf[BUFSIZE]; + + snprintf (buf, BUFSIZE, "_OBJC_ClassRef_%s", IDENTIFIER_POINTER (ident)); + decl = start_var_decl (objc_class_type, buf); + OBJCMETA (decl, objc_meta, meta_class_ref); + return decl; +} + +/* This routine builds a class refs entry for each class name used. + Initially, a (static-ref, IDENT) tuple is added to the list. + The ident is replaced with address of the class metadata (of type 'Class') + in the output routine. */ + +static GTY (()) VEC (ident_data_tuple, gc) * classrefs; + +static tree +objc_v2_get_class_reference (tree ident) +{ + tree decl; + ident_data_tuple e; + if (classrefs) + { + int count; + ident_data_tuple *ref; + FOR_EACH_VEC_ELT (ident_data_tuple, classrefs, count, ref) + { + if (ref->ident == ident) + { + if (!ref->data) + ref->data = build_v2_class_reference_decl (ident); + return ref->data; + } + } + } + else + /* Somewhat arbitrary initial provision. */ + classrefs = VEC_alloc (ident_data_tuple, gc, 16); + /* We come here if we don't find the entry - or if the table was yet + to be created. */ + decl = build_v2_class_reference_decl (ident); + e.ident = ident; + e.data = decl; + VEC_safe_push (ident_data_tuple, gc, classrefs, &e); + return decl; +} + +static tree +next_runtime_abi_02_get_class_reference (tree ident) +{ + if (!flag_zero_link) + return objc_v2_get_class_reference (ident); + else + { + /* We fall back to using objc_getClass (). */ + VEC(tree,gc) *vec = VEC_alloc (tree, gc, 1); + tree t; + /* ??? add_class_reference (ident); - is pointless, since the + system lib does not export the equivalent symbols. Maybe we + need to build a class ref anyway. */ + t = my_build_string_pointer (IDENTIFIER_LENGTH (ident) + 1, + IDENTIFIER_POINTER (ident)); + VEC_quick_push (tree, vec, t); + t = build_function_call_vec (input_location, objc_get_class_decl, + vec, NULL); + VEC_free (tree, gc, vec); + return t; + } +} + +/* Used by get_arg_type_list. + Return the types for receiver & _cmd at the start of a method argument list. + context is either METHOD_DEF or METHOD_REF, saying whether we are trying + to define a method or call one. superflag says this is for a send to super. + meth may be NULL, in the case that there is no prototype. */ + +static tree +next_runtime_abi_02_get_arg_type_list_base (tree meth, int context, int superflag) +{ + tree arglist; + + /* Receiver type. */ + if (superflag) + arglist = build_tree_list (NULL_TREE, objc_super_type); + else if (context == METHOD_DEF && TREE_CODE (meth) == INSTANCE_METHOD_DECL) + arglist = build_tree_list (NULL_TREE, objc_instance_type); + else + arglist = build_tree_list (NULL_TREE, objc_object_type); + + /* Selector type - will eventually change to `int'. */ + chainon (arglist, build_tree_list (NULL_TREE, + (superflag ? objc_v2_super_selector_type + : objc_v2_selector_type))); + return arglist; +} + +/* TODO: Merge this with the message refs. */ +static tree +build_selector_reference_decl (tree ident) +{ + tree decl; + char *t, buf[BUFSIZE]; + + snprintf (buf, BUFSIZE, "_OBJC_SelRef_%s", IDENTIFIER_POINTER (ident)); + t = buf; + while (*t) + { + if (*t==':') + *t = '$'; /* Underscore would clash between foo:bar and foo_bar. */ + t++; + } + decl = start_var_decl (objc_selector_type, buf); + OBJCMETA (decl, objc_meta, meta_sel_refs); + return decl; +} + +static tree +next_runtime_abi_02_build_selector_reference (location_t loc ATTRIBUTE_UNUSED, + tree ident, + tree proto ATTRIBUTE_UNUSED) +{ + tree *chain = &sel_ref_chain; + tree expr; + + while (*chain) + { + if (TREE_VALUE (*chain) == ident) + return TREE_PURPOSE (*chain); + + chain = &TREE_CHAIN (*chain); + } + + expr = build_selector_reference_decl (ident); + *chain = tree_cons (expr, ident, NULL_TREE); + + return expr; +} + +/* Declare a variable of type 'struct message_ref_t'. */ +/* This will be finished in build_v2_message_ref_translation_table (). + We take an idea from LLVM in making the names a bit more connected + and thus the asm more readable. */ + +static tree +build_v2_message_reference_decl (tree sel_name, tree message_func_ident) +{ + tree decl; + char buf[BUFSIZE], *t; + int offset = 12; + + /* Skip past the objc_msgSend it's the same for all... */ + if (IDENTIFIER_POINTER (message_func_ident)[offset] == '_') + offset++; + + snprintf (buf, BUFSIZE, "_OBJC_MsgRef_%s_%s", + &(IDENTIFIER_POINTER (message_func_ident)[offset]), + IDENTIFIER_POINTER (sel_name)); + t = buf; + while (*t) + { + if (*t==':') + *t = '$'; /* Underscore would clash between foo:bar and foo_bar. */ + t++; + } + decl = start_var_decl (objc_v2_message_ref_template, buf); + OBJCMETA (decl, objc_meta, meta_mref); + return decl; +} + +typedef struct GTY(()) msgref_entry { + tree func; + tree selname; + tree refdecl; +} msgref_entry; +DEF_VEC_O(msgref_entry); +DEF_VEC_ALLOC_O(msgref_entry, gc); + +static GTY (()) VEC (msgref_entry, gc) * msgrefs; + +/* Build the list of (objc_msgSend_fixup_xxx, selector name) Used later on to + initialize the table of 'struct message_ref_t' elements. */ + +static tree +build_v2_selector_messenger_reference (tree sel_name, tree message_func_decl) +{ + tree decl; + msgref_entry e; + if (msgrefs) + { + int count; + msgref_entry *ref; + FOR_EACH_VEC_ELT (msgref_entry, msgrefs, count, ref) + if (ref->func == message_func_decl && ref->selname == sel_name) + return ref->refdecl; + } + else + /* Somewhat arbitrary initial provision. */ + msgrefs = VEC_alloc (msgref_entry, gc, 32); + /* We come here if we don't find a match or at the start. */ + decl = build_v2_message_reference_decl (sel_name, + DECL_NAME (message_func_decl)); + e.func = message_func_decl; + e.selname = sel_name; + e.refdecl = decl; + VEC_safe_push (msgref_entry, gc, msgrefs, &e); + return decl; +} + +static tree +build_v2_protocollist_ref_decl (tree protocol) +{ + tree decl; + tree protocol_ident = PROTOCOL_NAME (protocol); + char buf[BUFSIZE]; + + snprintf (buf, BUFSIZE, "_OBJC_ProtocolRef_%s", + IDENTIFIER_POINTER (protocol_ident)); + /* TODO: other compiler versions make these hidden & weak. */ + decl = create_global_decl (objc_protocol_type, buf); + /* Let optimizer know that this decl is not removable. */ + DECL_PRESERVE_P (decl) = 1; + OBJCMETA (decl, objc_meta, meta_proto_ref); + return decl; +} + +typedef struct GTY(()) prot_list_entry { + tree id; + tree refdecl; +} prot_list_entry; +DEF_VEC_O(prot_list_entry); +DEF_VEC_ALLOC_O(prot_list_entry, gc); +static GTY (()) VEC (prot_list_entry, gc) * protrefs; + +static tree +objc_v2_get_protocol_reference (tree ident) +{ + tree decl; + prot_list_entry e; + if (protrefs) + { + int count; + prot_list_entry *ref; + FOR_EACH_VEC_ELT (prot_list_entry, protrefs, count, ref) + { + if (ref->id == ident) + { + if (!ref->refdecl) + ref->refdecl = build_v2_protocollist_ref_decl (ident); + return ref->refdecl; + } + } + } + else + /* Somewhat arbitrary initial provision. */ + protrefs = VEC_alloc (prot_list_entry, gc, 32); + /* We come here if we don't find the entry - or if the table was yet + to be created. */ + decl = build_v2_protocollist_ref_decl (ident); + e.id = ident; + e.refdecl = decl; + VEC_safe_push (prot_list_entry, gc, protrefs, &e); + return decl; +} + +static tree +next_runtime_abi_02_get_protocol_reference (location_t loc ATTRIBUTE_UNUSED, + tree p) +{ + if (!PROTOCOL_FORWARD_DECL (p)) + PROTOCOL_FORWARD_DECL (p) = next_runtime_abi_02_protocol_decl (p); + + return objc_v2_get_protocol_reference (p); +} + +/* This routine returns the ivar declaration, if component is a valid ivar field; + NULL_TREE otherwise. On finding an ivar, it also returns the class name in CLASS. +*/ + +static tree +objc_is_ivar (tree expr, tree component, tree *klass) +{ + tree field = NULL_TREE; + tree basetype = TYPE_MAIN_VARIANT (TREE_TYPE (expr)); + + if (TREE_CODE (basetype) == RECORD_TYPE + && TYPE_HAS_OBJC_INFO (basetype) && TYPE_OBJC_INTERFACE (basetype)) + { + *klass = lookup_interface (OBJC_TYPE_NAME (basetype)); + if (*klass) + { + do + { + tree ivar_chain = CLASS_RAW_IVARS (*klass); + if (ivar_chain) + { + field = is_ivar (ivar_chain, component); + if (field != NULL_TREE) + break; + } + *klass = lookup_interface (CLASS_SUPER_NAME (*klass)); + } + while (*klass); + } + } + return field; +} + +static void +create_ivar_offset_name (char *buf, tree class_name, tree field_decl) +{ + tree fname = DECL_NAME (field_decl); + + sprintf (buf, "OBJC_IVAR_$_%s.%s", IDENTIFIER_POINTER (class_name), + IDENTIFIER_POINTER (fname)); + return; +} + +/* This routine generates new abi's ivar reference tree. It amounts to generating + *(TYPE*)((char*)pObj + OFFSET_IVAR) when we normally generate pObj->IVAR + OFFSET_IVAR is an 'extern' variable holding the offset for 'IVAR' field. TYPE + is type of IVAR field. +*/ + +static tree +objc_v2_build_ivar_ref (tree datum, tree component) +{ + tree field, ref, class_name, offset, ftype, expr; + char var_offset_name[512]; + + field = objc_is_ivar (datum, component, &class_name); + if (!field) + return NULL_TREE; + + /* This routine only handles non-bitfield fields */ + /* DECL_INITIAL macro is set to width of bitfield and can be relied on to + check for bitfield ivars. Note that I cannot rely on DECL_BIT_FIELD macro + because it is only set when the whole struct is seen (at finish_struct) + and not when the ivar chain is built. */ + if (DECL_INITIAL (field)) + return NULL_TREE; + + create_ivar_offset_name (var_offset_name, CLASS_NAME (class_name), field); + + offset = create_extern_decl (TREE_TYPE (size_zero_node), var_offset_name); + + ftype = TREE_TYPE (field); + + /* (char*)datum */ + expr = build_c_cast (input_location, + string_type_node, build_fold_addr_expr (datum)); + + /* (char*)datum + offset */ + expr = fold_build2_loc (input_location, + POINTER_PLUS_EXPR, string_type_node, expr, offset); + + /* (ftype*)((char*)datum + offset) */ + expr = build_c_cast (input_location, build_pointer_type (ftype), expr); + + /* Finally: *(ftype*)((char*)datum + offset) */ + ref = build_indirect_ref (input_location, expr, RO_UNARY_STAR); + + /* We must set type of the resulting expression to be the same as the + field type. This is because, build_indirect_ref (...) rebuilds the + type which may result in lost information; as in the case of + protocol-qualified types (id <protocol> ). */ + TREE_TYPE (ref) = ftype; + + if (TREE_READONLY (datum) || TREE_READONLY (field)) + TREE_READONLY (ref) = 1; + + if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field)) + TREE_THIS_VOLATILE (ref) = 1; + + if (TREE_DEPRECATED (field)) + warn_deprecated_use (field, NULL_TREE); + + return ref; +} + +/* IVAR refs are made via an externally referenceable offset and built + on the fly. That is, unless they refer to (private) fields in the + class stucture. */ +static tree +next_runtime_abi_02_build_ivar_ref (location_t loc ATTRIBUTE_UNUSED, + tree base, tree id) +{ + tree ivar; + if ((ivar = objc_v2_build_ivar_ref (base, id))) + return ivar; + return objc_build_component_ref (base, id); +} + +/* [super ...] references are listed here (and built into a table at meta + -data emit time). */ + +static tree +build_v2_superclass_ref_decl (tree ident, bool inst) +{ + tree decl; + char buf[BUFSIZE]; + + snprintf (buf, BUFSIZE, "_OBJC_%sSuperRef_%s", (inst?"":"Meta"), + IDENTIFIER_POINTER (ident)); + decl = start_var_decl (objc_class_type, buf); + OBJCMETA (decl, objc_meta, meta_superclass_ref); + return decl; +} + +static GTY (()) VEC (ident_data_tuple, gc) * class_super_refs; +static GTY (()) VEC (ident_data_tuple, gc) * metaclass_super_refs; + +static tree +next_runtime_abi_02_get_class_super_ref (location_t loc ATTRIBUTE_UNUSED, + struct imp_entry *imp, bool inst_meth) +{ + tree decl; + ident_data_tuple e; + tree id = CLASS_NAME (imp->imp_context); + VEC (ident_data_tuple, gc) *list = inst_meth ? class_super_refs + : metaclass_super_refs; + + if (list) + { + int count; + ident_data_tuple *ref; + FOR_EACH_VEC_ELT (ident_data_tuple, list, count, ref) + { + if (ref->ident == id) + { + if (!ref->data) + ref->data = build_v2_superclass_ref_decl (id, inst_meth); + return ref->data; + } + } + } + else + { + /* Somewhat arbitrary initial provision. */ + if (inst_meth) + list = class_super_refs = VEC_alloc (ident_data_tuple, gc, 16); + else + list = metaclass_super_refs = VEC_alloc (ident_data_tuple, gc, 16); + } + /* We come here if we don't find the entry - or if the table was yet + to be created. */ + decl = build_v2_superclass_ref_decl (id, inst_meth); + e.ident = id; + e.data = decl; + VEC_safe_push (ident_data_tuple, gc, list, &e); + return decl; +} + +static tree +next_runtime_abi_02_get_category_super_ref (location_t loc ATTRIBUTE_UNUSED, + struct imp_entry *imp, bool inst_meth) +{ + /* ??? is this OK when zero-link = true? */ + tree super_name = CLASS_SUPER_NAME (imp->imp_template); + tree super_class; + + if (!flag_zero_link) + { + super_class = objc_get_class_reference (CLASS_NAME (imp->imp_template)); + + if (!inst_meth) + + /* If we are in a class method, we must retrieve the + _metaclass_ for the current class, pointed at by + the class's "isa" pointer. The following assumes that + "isa" is the first ivar in a class (which it must be). */ + super_class = + build_indirect_ref (input_location, + build_c_cast (input_location, + build_pointer_type (objc_class_type), + super_class), + RO_UNARY_STAR); + return super_class; + } + /* ??? Do we need to add the class ref anway for zero-link? */ + /* else do it the slow way. */ + super_class = (inst_meth ? objc_get_class_decl : objc_get_meta_class_decl); +/* assemble_external (super_class);*/ + super_name = my_build_string_pointer (IDENTIFIER_LENGTH (super_name) + 1, + IDENTIFIER_POINTER (super_name)); + /* super_class = objc_get{Meta}Class("CLASS_SUPER_NAME"); */ + return build_function_call (input_location, + super_class, + build_tree_list (NULL_TREE, super_name)); +} + +static tree +next_runtime_abi_02_receiver_is_class_object (tree receiver) +{ + if (TREE_CODE (receiver) == VAR_DECL + && IS_CLASS (TREE_TYPE (receiver)) + && classrefs + && VEC_length (ident_data_tuple, classrefs)) + { + int count; + ident_data_tuple *ref; + /* The receiver is a variable created by build_class_reference_decl. */ + FOR_EACH_VEC_ELT (ident_data_tuple, classrefs, count, ref) + if (ref->data == receiver) + return ref->ident; + } + return NULL_TREE; +} + +/* Assign all arguments in VALUES which have side-effect to a temporary and + replaced that argument in VALUES list with the temporary. TYPELIST is the + list of argument types. */ + +static tree +objc_copy_to_temp_side_effect_params (tree typelist, tree values) +{ + tree valtail, typetail; + /* skip over receiver and the &_msf_ref types */ + gcc_assert (TREE_CHAIN (typelist)); + typetail = TREE_CHAIN (TREE_CHAIN (typelist)); + + for (valtail = values; valtail; + valtail = TREE_CHAIN (valtail), typetail = TREE_CHAIN (typetail)) + { + tree value = TREE_VALUE (valtail); + tree type = typetail ? TREE_VALUE (typetail) : NULL_TREE; + if (type == NULL_TREE) + break; + if (!TREE_SIDE_EFFECTS (value)) + continue; + /* To prevent re-evaluation */ + value = save_expr (value); + add_stmt (value); + TREE_VALUE (valtail) = value; + } + return values; +} + +/* Build the new abi's messaging library call. It looks like: + (*_msg.messenger) (receiver, &_msg, ...) +*/ + +static tree +build_v2_build_objc_method_call (int super_flag, tree method_prototype, + tree lookup_object, tree selector, + tree method_params, + bool check_for_nil) +{ + tree ret_val; + tree sender, rcv_p, t; + tree ret_type + = (method_prototype + ? TREE_VALUE (TREE_TYPE (method_prototype)) + : objc_object_type); + tree method_param_types = get_arg_type_list (method_prototype, + METHOD_REF, super_flag); + + tree ftype = build_function_type (ret_type, method_param_types); + tree sender_cast; + + if (method_prototype && METHOD_TYPE_ATTRIBUTES (method_prototype)) + ftype = build_type_attribute_variant ( + ftype, METHOD_TYPE_ATTRIBUTES (method_prototype)); + + sender_cast = build_pointer_type (ftype); + + if (check_for_nil) + method_params = objc_copy_to_temp_side_effect_params (method_param_types, + method_params); + + /* Get &message_ref_t.messenger */ + sender = build_c_cast (input_location, + build_pointer_type (super_flag + ? objc_v2_super_imp_type + : objc_v2_imp_type), + selector); + + sender = build_indirect_ref (input_location, sender, RO_UNARY_STAR); + + rcv_p = (super_flag ? objc_super_type : objc_object_type); + + lookup_object = build_c_cast (input_location, rcv_p, lookup_object); + + /* Use SAVE_EXPR to avoid evaluating the receiver twice. */ + lookup_object = save_expr (lookup_object); + + method_params = tree_cons (NULL_TREE, lookup_object, + tree_cons (NULL_TREE, selector, + method_params)); + t = build3 (OBJ_TYPE_REF, sender_cast, sender, lookup_object, size_zero_node); + ret_val = build_function_call (input_location, t, method_params); + if (check_for_nil) + { + /* receiver != nil ? ret_val : 0 */ + tree ftree; + tree ifexp; + + if (TREE_CODE (ret_type) == RECORD_TYPE + || TREE_CODE (ret_type) == UNION_TYPE) + { + VEC(constructor_elt,gc) *rtt = NULL; + /* ??? CHECKME. hmmm..... think we need something more here. */ + CONSTRUCTOR_APPEND_ELT (rtt, NULL_TREE, NULL_TREE); + ftree = objc_build_constructor (ret_type, rtt); + } + else + ftree = fold_convert (ret_type, integer_zero_node); + + ifexp = build_binary_op (input_location, NE_EXPR, + lookup_object, + fold_convert (rcv_p, integer_zero_node), 1); + +#ifdef OBJCPLUS + ret_val = build_conditional_expr (ifexp, ret_val, ftree, tf_warning_or_error); +#else + /* ??? CHECKME. */ + ret_val = build_conditional_expr (input_location, + ifexp, 1, + ret_val, NULL_TREE, + ftree, NULL_TREE); +#endif + } + return ret_val; +} + +static tree +next_runtime_abi_02_build_objc_method_call (location_t loc, + tree method_prototype, + tree receiver, + tree rtype, + tree sel_name, + tree method_params, + int super) +{ + tree ret_type, selector; + tree message_func_decl; + bool check_for_nil = flag_objc_nilcheck; + + ret_type = (method_prototype ? + TREE_VALUE (TREE_TYPE (method_prototype)) : + objc_object_type); + + /* Do we need to check for nil receivers ? */ + /* For now, message sent to classes need no nil check. In future, class + declaration marked as weak_import must be nil checked. */ + if (super + || (TREE_CODE (receiver) == VAR_DECL + && TREE_TYPE (receiver) == objc_class_type)) + check_for_nil = false; + + if (!targetm.calls.struct_value_rtx (0, 0) + && (TREE_CODE (ret_type) == RECORD_TYPE + || TREE_CODE (ret_type) == UNION_TYPE) + && targetm.calls.return_in_memory (ret_type, 0)) + { + if (super) + message_func_decl = umsg_id_super2_stret_fixup_decl; + else + message_func_decl = objc_is_id (rtype) + ? umsg_id_stret_fixup_decl + : umsg_stret_fixup_decl; + } + else + { + if (super) + message_func_decl = umsg_id_super2_fixup_decl; + else + message_func_decl = objc_is_id (rtype) + ? umsg_id_fixup_decl + : umsg_fixup_decl; + } + + selector = build_v2_selector_messenger_reference (sel_name, + message_func_decl); + + /* selector = &_msg; */ + selector = build_unary_op (loc, ADDR_EXPR, selector, 0); + + selector = build_c_cast (loc, (super ? objc_v2_super_selector_type + : objc_v2_selector_type), + selector); + + /* (*_msg.messenger) (receiver, &_msg, ...); */ + return build_v2_build_objc_method_call (super, method_prototype, + receiver, selector, + method_params, check_for_nil); +} + +/* NOTE --- Constant String Class Stuff --- */ + +static bool +next_runtime_abi_02_setup_const_string_class_decl (void) +{ + if (!constant_string_global_id) + { + /* Hopefully, this should not represent a serious limitation. */ + char buf[BUFSIZE]; + snprintf (buf, BUFSIZE, "OBJC_CLASS_$_%s", constant_string_class_name); + constant_string_global_id = get_identifier (buf); + } + + string_class_decl = lookup_name (constant_string_global_id); + + /* In OBJC2 abi constant string class reference refers to + class name for NSConstantString class. This declaration may not be + available yet (in fact it is not in most cases). So, declare an extern + OBJC_CLASS_$_NSConstantString in its place. */ + if (!string_class_decl) + string_class_decl = + create_extern_decl (objc_v2_class_template, + IDENTIFIER_POINTER (constant_string_global_id)); + + return (string_class_decl != NULL_TREE); +} + +static tree +next_runtime_abi_02_build_const_string_constructor (location_t loc, tree string, + int length) +{ + tree constructor, fields, var; + VEC(constructor_elt,gc) *v = NULL; + + /* NeXT: (NSConstantString *) & ((__builtin_ObjCString) { isa, string, length }) */ + fields = TYPE_FIELDS (internal_const_str_type); + CONSTRUCTOR_APPEND_ELT (v, fields, + build_unary_op (loc, ADDR_EXPR, string_class_decl, 0)); + + fields = DECL_CHAIN (fields); + CONSTRUCTOR_APPEND_ELT (v, fields, + build_unary_op (loc, ADDR_EXPR, string, 1)); + + /* ??? check if this should be long. */ + fields = DECL_CHAIN (fields); + CONSTRUCTOR_APPEND_ELT (v, fields, build_int_cst (NULL_TREE, length)); + constructor = objc_build_constructor (internal_const_str_type, v); + + var = build_decl (input_location, CONST_DECL, NULL, TREE_TYPE (constructor)); + DECL_INITIAL (var) = constructor; + TREE_STATIC (var) = 1; + DECL_CONTEXT (var) = NULL; + OBJCMETA (var, objc_meta, meta_const_str); + return var; +} + +/* NOTE --- NeXT V2 Metadata templates --- */ + +/* This routine builds the following type: + struct _prop_t { + const char * const name; // property name + const char * const attributes; // comma-delimited, encoded, + // property attributes + }; +*/ + +static tree +build_v2_property_template (void) +{ + tree prop_record; + tree decls, *chain = NULL; + + prop_record = objc_start_struct (get_identifier ("_prop_t")); + /* const char * name */ + decls = add_field_decl (string_type_node, "name", &chain); + + /* const char * attribute */ + add_field_decl (string_type_node, "attribute", &chain); + + objc_finish_struct (prop_record, decls); + return prop_record; +} + +/* struct ivar_t { + unsigned long int *offset; + char *name; + char *type; + uint32_t alignment; + uint32_t size; + }; +*/ + +static tree +build_v2_ivar_t_template (void) +{ + tree objc_ivar_id, objc_ivar_record; + tree decls, *chain = NULL; + + objc_ivar_id = get_identifier ("_ivar_t"); + objc_ivar_record = objc_start_struct (objc_ivar_id); + + /* unsigned long int *offset */ + decls = add_field_decl (build_pointer_type + (TREE_TYPE (size_zero_node)), "offset", &chain); + + /* char *name; */ + add_field_decl (string_type_node, "name", &chain); + + /* char *type; */ + add_field_decl (string_type_node, "type", &chain); + + /* uint32_t alignment; */ + add_field_decl (integer_type_node, "alignment", &chain); + + /* uint32_t size; */ + add_field_decl (integer_type_node, "size", &chain); + + objc_finish_struct (objc_ivar_record, decls); + return objc_ivar_record; +} + +static void +build_metadata_templates (void) +{ + + if (!objc_method_template) + objc_method_template = build_method_template (); + + if (!objc_v2_property_template) + objc_v2_property_template = build_v2_property_template (); + + if (!objc_v2_ivar_template) + objc_v2_ivar_template = build_v2_ivar_t_template (); + +} + +/* NOTE --- Output NeXT V2 Metadata --- */ + +/* Routine builds name of Interface's main meta-data of type class_t. */ + +static char * +objc_build_internal_classname (tree ident, bool metaclass) +{ + static char string[512]; + snprintf (string, 512, "%s_%s", metaclass ? "OBJC_METACLASS_$" + : "OBJC_CLASS_$", + IDENTIFIER_POINTER (ident)); + return string; +} + +/* Build the name for object of type struct class_ro_t */ + +static const char * +newabi_append_ro (const char *name) +{ + char *dollar; + char *p; + static char string[BUFSIZE]; + dollar = strchr (name, '$'); + gcc_assert (dollar); + p = string; + *p = '_'; p++; + strncpy (p, name, (int)(dollar - name)); + p += (int)(dollar - name); + sprintf (p, "RO_%s", dollar); + return string; +} + +/* Build the struct message_ref_t msg = + {objc_msgSend_fixup_xxx, @selector(func)} + table. +*/ + +static +void build_v2_message_ref_translation_table (void) +{ + int count; + msgref_entry *ref; + + if (!msgrefs || !VEC_length (msgref_entry,msgrefs)) + return; + + FOR_EACH_VEC_ELT (msgref_entry, msgrefs, count, ref) + { + VEC(constructor_elt,gc) *initializer; + tree expr, constructor; + tree struct_type = TREE_TYPE (ref->refdecl); + location_t loc = DECL_SOURCE_LOCATION (ref->refdecl); + + initializer = NULL; + /* First 'IMP messenger' field.. */ + expr = build_unary_op (loc, ADDR_EXPR, ref->func, 0); + expr = convert (objc_v2_imp_type, expr); + CONSTRUCTOR_APPEND_ELT (initializer, NULL_TREE, expr); + + /* then.. 'SEL name' field */ + expr = build_selector (ref->selname); + CONSTRUCTOR_APPEND_ELT (initializer, NULL_TREE, expr); + constructor = objc_build_constructor (struct_type, initializer); + finish_var_decl (ref->refdecl, constructor); + } +} + +/* Build decl = initializer; for each externally visible class reference. */ + +static void +build_v2_classrefs_table (void) +{ + int count; + ident_data_tuple *ref; + + if (!classrefs || !VEC_length (ident_data_tuple, classrefs)) + return; + + FOR_EACH_VEC_ELT (ident_data_tuple, classrefs, count, ref) + { + tree expr = ref->ident; + tree decl = ref->data; + /* Interface with no implementation and yet one of its messages has been + used. Need to generate a full address-of tree for it here. */ + if (TREE_CODE (expr) == IDENTIFIER_NODE) + { + const char *name = objc_build_internal_classname (expr, false); + expr = create_extern_decl (objc_v2_class_template, name); + expr = convert (objc_class_type, build_fold_addr_expr (expr)); + } + /* The runtime wants this, even if it appears unused, so we must force the + output. + DECL_PRESERVE_P (decl) = 1; */ + finish_var_decl (decl, expr); + } +} + +/* Build decl = initializer; for each externally visible class reference. */ + +static void +build_v2_super_classrefs_table (bool metaclass) +{ + int count; + ident_data_tuple *ref; + VEC (ident_data_tuple, gc) *list = metaclass ? metaclass_super_refs + : class_super_refs; + + if (!list || !VEC_length (ident_data_tuple, list)) + return; + + FOR_EACH_VEC_ELT (ident_data_tuple, list, count, ref) + { + tree expr = ref->ident; + tree decl = ref->data; + /* Interface with no implementation and yet one of its messages has been + used. Need to generate a full address-of tree for it here. */ + if (TREE_CODE (expr) == IDENTIFIER_NODE) + { + const char * name = objc_build_internal_classname (expr, metaclass); + expr = create_extern_decl (objc_v2_class_template, name); + expr = convert (objc_class_type, build_fold_addr_expr (expr)); + } + finish_var_decl (decl, expr); + } +} + +/* Add the global class meta-data declaration to the list which later on + ends up in the __class_list section. */ + +static GTY(()) VEC(tree,gc) *class_list; + +static void +objc_v2_add_to_class_list (tree global_class_decl) +{ + if (!class_list) + class_list = VEC_alloc (tree, gc, imp_count?imp_count:1); + VEC_safe_push (tree, gc, class_list, global_class_decl); +} + +static GTY(()) VEC(tree,gc) *nonlazy_class_list; + +/* Add the global class meta-data declaration to the list which later on + ends up in the __nonlazy_class section. */ + +static void +objc_v2_add_to_nonlazy_class_list (tree global_class_decl) +{ + if (!nonlazy_class_list) + nonlazy_class_list = VEC_alloc (tree, gc, imp_count?imp_count:1); + VEC_safe_push (tree, gc, nonlazy_class_list, global_class_decl); +} + +static GTY(()) VEC(tree,gc) *category_list; + +/* Add the category meta-data declaration to the list which later on ends up + in the __nonlazy_category section. */ + +static void +objc_v2_add_to_category_list (tree decl) +{ + if (!category_list) + category_list = VEC_alloc (tree, gc, cat_count?cat_count:1); + VEC_safe_push (tree, gc, category_list, decl); +} + +static GTY(()) VEC(tree,gc) *nonlazy_category_list; + +/* Add the category meta-data declaration to the list which later on ends up + in the __category_list section. */ + +static void +objc_v2_add_to_nonlazy_category_list (tree decl) +{ + if (!nonlazy_category_list) + nonlazy_category_list = VEC_alloc (tree, gc, cat_count?cat_count:1); + VEC_safe_push (tree, gc, nonlazy_category_list, decl); +} + +static bool +has_load_impl (tree clsmeth) +{ + while (clsmeth) + { + tree id = METHOD_SEL_NAME (clsmeth); + if (IDENTIFIER_LENGTH (id) == 4 + && strncmp (IDENTIFIER_POINTER (id), "load", 4) == 0) + return true; + clsmeth = DECL_CHAIN (clsmeth); + } + + return false; +} + +/* Build a __{class,category}_list section table containing address of all + @implemented {class,category} meta-data. */ + +static void +build_v2_address_table (VEC(tree,gc) *src, const char *nam, tree attr) +{ + int count=0; + tree type, decl, expr; + VEC(constructor_elt,gc) *initlist = NULL; + + if (!src || !VEC_length(tree,src)) + return; + + FOR_EACH_VEC_ELT (tree, src, count, decl) + { +#ifndef OBJCPLUS + tree purpose = build_int_cst (NULL_TREE, count); +#else + tree purpose = NULL_TREE; +#endif + expr = convert (objc_class_type, build_fold_addr_expr (decl)); + CONSTRUCTOR_APPEND_ELT (initlist, purpose, expr); + } + gcc_assert (count > 0); + type = build_array_type (objc_class_type, + build_index_type (build_int_cst (NULL_TREE, count - 1))); + decl = start_var_decl (type, nam); + /* The runtime wants this, even if it appears unused, so we must force the + output. */ + DECL_PRESERVE_P (decl) = 1; + expr = objc_build_constructor (type, initlist); + OBJCMETA (decl, objc_meta, attr); + finish_var_decl (decl, expr); +} + +/* Build decl = initializer; + for each protocol referenced in @protocol(MyProt) expression. + Refs as built in the entry section above. */ + +static void +build_v2_protocol_list_translation_table (void) +{ + int count; + prot_list_entry *ref; + + if (!protrefs) + return; + + FOR_EACH_VEC_ELT (prot_list_entry, protrefs, count, ref) + { + char buf[BUFSIZE]; + tree expr; + gcc_assert (TREE_CODE (ref->id) == PROTOCOL_INTERFACE_TYPE); + snprintf (buf, BUFSIZE, "_OBJC_Protocol_%s", + IDENTIFIER_POINTER (PROTOCOL_NAME (ref->id))); + expr = start_var_decl (objc_v2_protocol_template, buf); + expr = convert (objc_protocol_type, build_fold_addr_expr (expr)); + finish_var_decl (ref->refdecl, expr); + } + /* TODO: Maybe we could explicitly delete the vec. now? */ +} + +static GTY (()) VEC (prot_list_entry, gc) * protlist; + +/* Add the local protocol meta-data declaration to the list which later on ends up + in the __protocol_list section. */ + +static void +objc_add_to_protocol_list (tree protocol_interface_decl, tree protocol_decl) +{ + prot_list_entry e; + if (!protlist) + /* Arbitrary init count. */ + protlist = VEC_alloc (prot_list_entry, gc, 32); + e.id = protocol_interface_decl; + e.refdecl = protocol_decl; + VEC_safe_push (prot_list_entry, gc, protlist, &e); +} + +/* Build the __protocol_list section table containing address of all generate protocol_t + meta-data. */ + +static void +build_v2_protocol_list_address_table (void) +{ + int count; + prot_list_entry *ref; + if (!protlist || !VEC_length (prot_list_entry, protlist)) + return; + + FOR_EACH_VEC_ELT (prot_list_entry, protlist, count, ref) + { + tree decl, expr; + char buf[BUFSIZE]; + gcc_assert (ref->id && TREE_CODE (ref->id) == PROTOCOL_INTERFACE_TYPE); + snprintf (buf, BUFSIZE, "_OBJC_LabelProtocol_%s", + IDENTIFIER_POINTER (PROTOCOL_NAME (ref->id))); + decl = create_global_decl (objc_protocol_type, buf); + expr = convert (objc_protocol_type, build_fold_addr_expr (ref->refdecl)); + OBJCMETA (decl, objc_meta, meta_label_protocollist); + finish_var_decl (decl, expr); + } + + /* TODO: delete the vec. */ + /* TODO: upgrade to the the clang/llvm hidden version. */ +} + +/* This routine declares a variable to hold meta data for + 'struct protocol_list_t'. */ + +static tree +generate_v2_protocol_list (tree i_or_p, tree klass_ctxt) +{ + tree refs_decl, lproto, e, plist, ptempl_p_t; + int size = 0; + VEC(constructor_elt,gc) *initlist = NULL; + char buf[BUFSIZE]; + + if (TREE_CODE (i_or_p) == CLASS_INTERFACE_TYPE + || TREE_CODE (i_or_p) == CATEGORY_INTERFACE_TYPE) + plist = CLASS_PROTOCOL_LIST (i_or_p); + else if (TREE_CODE (i_or_p) == PROTOCOL_INTERFACE_TYPE) + plist = PROTOCOL_LIST (i_or_p); + else + gcc_unreachable (); + + /* Compute size. */ + for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) + if (TREE_CODE (TREE_VALUE (lproto)) == PROTOCOL_INTERFACE_TYPE + && PROTOCOL_FORWARD_DECL (TREE_VALUE (lproto))) + size++; + + /* Build initializer. */ + + ptempl_p_t = build_pointer_type (objc_v2_protocol_template); + e = build_int_cst (ptempl_p_t, size); + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, e); + + for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) + { + tree pval = TREE_VALUE (lproto); + + if (TREE_CODE (pval) == PROTOCOL_INTERFACE_TYPE + && PROTOCOL_FORWARD_DECL (pval)) + { + tree fwref = PROTOCOL_FORWARD_DECL (pval); + location_t loc = DECL_SOURCE_LOCATION (fwref) ; + e = build_unary_op (loc, ADDR_EXPR, fwref, 0); + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, e); + } + } + + /* static struct protocol_list_t *list[size]; */ + + switch (TREE_CODE (i_or_p)) + { + case PROTOCOL_INTERFACE_TYPE: + snprintf (buf, BUFSIZE, "_OBJC_ProtocolRefs_%s", + IDENTIFIER_POINTER (PROTOCOL_NAME (i_or_p))); + break; + case CLASS_INTERFACE_TYPE: + snprintf (buf, BUFSIZE, "_OBJC_ClassProtocols_%s", + IDENTIFIER_POINTER (CLASS_NAME (i_or_p))); + break; + case CATEGORY_INTERFACE_TYPE: + snprintf (buf, BUFSIZE, "_OBJC_CategoryProtocols_%s_%s", + IDENTIFIER_POINTER (CLASS_NAME (klass_ctxt)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (klass_ctxt))); + break; + default: + gcc_unreachable (); + } + + refs_decl = start_var_decl (build_sized_array_type (ptempl_p_t, size+1), + buf); + /* ObjC2 puts all these in the base section. */ + OBJCMETA (refs_decl, objc_meta, meta_base); + DECL_PRESERVE_P (refs_decl) = 1; + finish_var_decl (refs_decl, + objc_build_constructor (TREE_TYPE (refs_decl),initlist)); + return refs_decl; +} + +/* This routine builds one 'struct method_t' initializer list. Note that the + old ABI is supposed to build 'struct objc_method' which has 3 fields, but + it does not build the initialization expression for 'method_imp' which for + protocols is NULL any way. To be consistant with declaration of + 'struct method_t', in the new ABI we set the method_t.imp to NULL. +*/ + +static tree +build_v2_descriptor_table_initializer (tree type, tree entries) +{ + VEC(constructor_elt,gc) *initlist = NULL; + do + { + VEC(constructor_elt,gc) *eltlist = NULL; + CONSTRUCTOR_APPEND_ELT (eltlist, NULL_TREE, + build_selector (METHOD_SEL_NAME (entries))); + CONSTRUCTOR_APPEND_ELT (eltlist, NULL_TREE, + add_objc_string (METHOD_ENCODING (entries), + meth_var_types)); + CONSTRUCTOR_APPEND_ELT (eltlist, NULL_TREE, null_pointer_node); + + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, + objc_build_constructor (type, eltlist)); + entries = TREE_CHAIN (entries); + } + while (entries); + + return objc_build_constructor (build_array_type (type, 0), initlist); +} + +/* struct method_list_t { + uint32_t entsize; + uint32_t method_count; + struct objc_method method_list[method_count]; + }; */ + +static tree +build_v2_method_list_template (tree list_type, int size) +{ + tree method_list_t_record; + tree array_type, decls, *chain = NULL; + + method_list_t_record = objc_start_struct (NULL_TREE); + + /* uint32_t const entsize */ + decls = add_field_decl (integer_type_node, "entsize", &chain); + + /* int method_count; */ + add_field_decl (integer_type_node, "method_count", &chain); + + /* struct objc_method method_list[]; */ + array_type = build_sized_array_type (list_type, size); + add_field_decl (array_type, "method_list", &chain); + + objc_finish_struct (method_list_t_record, decls); + return method_list_t_record; +} + +/* Note, as above that we are building to the objc_method_template + which has the *imp field. ABI0/1 build with objc_method_prototype_template + which is missing this field. */ +static tree +generate_v2_meth_descriptor_table (tree chain, tree protocol, + const char *prefix, tree attr) +{ + tree method_list_template, initlist, decl, methods; + int size, entsize; + VEC(constructor_elt,gc) *v = NULL; + char buf[BUFSIZE]; + + if (!chain || !prefix) + return NULL_TREE; + + methods = chain; + size = 0; + while (methods) + { + if (! METHOD_ENCODING (methods)) + METHOD_ENCODING (methods) = encode_method_prototype (methods); + methods = TREE_CHAIN (methods); + size++; + } + + gcc_assert (size); + method_list_template = build_v2_method_list_template (objc_method_template, + size); + snprintf (buf, BUFSIZE, "%s_%s", prefix, + IDENTIFIER_POINTER (PROTOCOL_NAME (protocol))); + + decl = start_var_decl (method_list_template, buf); + + entsize = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (objc_method_template)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, entsize)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, size)); + initlist = + build_v2_descriptor_table_initializer (objc_method_template, + chain); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, initlist); + /* Get into the right section. */ + OBJCMETA (decl, objc_meta, attr); + finish_var_decl (decl, objc_build_constructor (method_list_template, v)); + return decl; +} + +/* This routine builds the initializer list to initialize the + 'struct _prop_t prop_list[]' field of 'struct _prop_list_t' meta-data. */ + +static tree +build_v2_property_table_initializer (tree type, tree context) +{ + tree x; + VEC(constructor_elt,gc) *inits = NULL; + if (TREE_CODE (context) == PROTOCOL_INTERFACE_TYPE) + x = CLASS_PROPERTY_DECL (context); + else + x = IMPL_PROPERTY_DECL (context); + + for (; x; x = TREE_CHAIN (x)) + { + VEC(constructor_elt,gc) *elemlist = NULL; + /* NOTE! sections where property name/attribute go MUST change later. */ + tree attribute, name_ident = PROPERTY_NAME (x); + + CONSTRUCTOR_APPEND_ELT (elemlist, NULL_TREE, + add_objc_string (name_ident, prop_names_attr)); + + attribute = objc_v2_encode_prop_attr (x); + CONSTRUCTOR_APPEND_ELT (elemlist, NULL_TREE, + add_objc_string (attribute, prop_names_attr)); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, + objc_build_constructor (type, elemlist)); + } + + return objc_build_constructor (build_array_type (type, 0),inits); +} + +/* This routine builds the following type: + struct _prop_list_t { + uint32_t entsize; // sizeof (struct _prop_t) + uint32_t prop_count; + struct _prop_t prop_list [prop_count]; + } +*/ + +static tree +build_v2_property_list_template (tree list_type, int size) +{ + tree property_list_t_record; + tree array_type, decls, *chain = NULL; + + /* anonymous. */ + property_list_t_record = objc_start_struct (NULL_TREE); + + /* uint32_t const entsize */ + decls = add_field_decl (integer_type_node, "entsize", &chain); + + /* int prop_count */ + add_field_decl (integer_type_node, "prop_count", &chain); + + /* struct _prop_t prop_list[]; */ + array_type = build_sized_array_type (list_type, size); + add_field_decl (array_type, "prop_list", &chain); + + objc_finish_struct (property_list_t_record, decls); + return property_list_t_record; +} + +/* + Top-level routine to generate property tables for each implementation. +*/ + +static tree +generate_v2_property_table (tree context, tree klass_ctxt) +{ + tree x, decl, initlist, property_list_template; + bool is_proto = false; + VEC(constructor_elt,gc) *inits = NULL; + int init_val, size = 0; + char buf[BUFSIZE]; + + if (context) + { + gcc_assert (TREE_CODE (context) == PROTOCOL_INTERFACE_TYPE); + x = CLASS_PROPERTY_DECL (context); + is_proto = true; + } + else + x = IMPL_PROPERTY_DECL (klass_ctxt); + + for (; x; x = TREE_CHAIN (x)) + size++; + + if (size == 0) + return NULL_TREE; + + property_list_template = + build_v2_property_list_template (objc_v2_property_template, + size); + + initlist = build_v2_property_table_initializer (objc_v2_property_template, + is_proto ? context + : klass_ctxt); + + init_val = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (objc_v2_property_template)); + if (is_proto) + snprintf (buf, BUFSIZE, "_OBJC_ProtocolPropList_%s", + IDENTIFIER_POINTER (PROTOCOL_NAME (context))); + else + snprintf (buf, BUFSIZE, "_OBJC_ClassPropList_%s", + IDENTIFIER_POINTER (CLASS_NAME (klass_ctxt))); + + decl = start_var_decl (property_list_template, buf); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, + build_int_cst (NULL_TREE, init_val)); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, + build_int_cst (NULL_TREE, size)); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, initlist); + + OBJCMETA (decl, objc_meta, meta_base); + finish_var_decl (decl, objc_build_constructor (TREE_TYPE (decl), inits)); + return decl; +} + +static tree +build_v2_protocol_initializer (tree type, tree protocol_name, tree protocol_list, + tree inst_methods, tree class_methods, + tree opt_ins_meth, tree opt_cls_meth, + tree property_list) +{ + tree expr, ttyp; + location_t loc; + VEC(constructor_elt,gc) *inits = NULL; + + /* TODO: find a better representation of location from the inputs. */ + loc = UNKNOWN_LOCATION; + + /* This is NULL for the new ABI. */ + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, + convert (objc_object_type, null_pointer_node)); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, protocol_name); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, protocol_list); + + ttyp = objc_method_proto_list_ptr; + if (inst_methods) + expr = convert (ttyp, build_unary_op (loc, ADDR_EXPR, inst_methods, 0)); + else + expr = convert (ttyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + + if (class_methods) + expr = convert (ttyp, build_unary_op (loc, ADDR_EXPR, class_methods, 0)); + else + expr = convert (ttyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + + if (opt_ins_meth) + expr = convert (ttyp, build_unary_op (loc, ADDR_EXPR, opt_ins_meth, 0)); + else + expr = convert (ttyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + + if (opt_cls_meth) + expr = convert (ttyp, build_unary_op (loc, ADDR_EXPR, opt_cls_meth, 0)); + else + expr = convert (ttyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + + ttyp = objc_prop_list_ptr; + if (property_list) + expr = convert (ttyp, build_unary_op (loc, ADDR_EXPR, property_list, 0)); + else + expr = convert (ttyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + + /* const uint32_t size; = sizeof(struct protocol_t) */ + expr = build_int_cst (integer_type_node, + TREE_INT_CST_LOW (TYPE_SIZE_UNIT (objc_v2_protocol_template))); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + /* const uint32_t flags; = 0 */ + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, integer_zero_node); + + return objc_build_constructor (type, inits); +} + +/* + Main routine to build all meta data for all protocols used in a translation unit. +*/ + +static void +generate_v2_protocols (void) +{ + tree p ; + bool some = false; + + if (!protocol_chain) + return ; + + /* If a protocol was directly referenced, pull in indirect references. */ + for (p = protocol_chain; p; p = TREE_CHAIN (p)) + if (PROTOCOL_FORWARD_DECL (p) && PROTOCOL_LIST (p)) + generate_protocol_references (PROTOCOL_LIST (p)); + + for (p = protocol_chain; p; p = TREE_CHAIN (p)) + { + location_t loc; + tree inst_meth, class_meth, opt_inst_meth, opt_class_meth, props; + tree decl, initlist, protocol_name_expr, refs_decl, refs_expr; + + /* If protocol wasn't referenced, don't generate any code. */ + decl = PROTOCOL_FORWARD_DECL (p); + + if (!decl) + continue; + + loc = DECL_SOURCE_LOCATION (decl); + some = true; + + inst_meth = + generate_v2_meth_descriptor_table (PROTOCOL_NST_METHODS (p), p, + "_OBJC_ProtocolInstanceMethods", + meta_proto_nst_meth); + + class_meth = + generate_v2_meth_descriptor_table (PROTOCOL_CLS_METHODS (p), p, + "_OBJC_ProtocolClassMethods", + meta_proto_cls_meth); + + opt_inst_meth = + generate_v2_meth_descriptor_table (PROTOCOL_OPTIONAL_NST_METHODS (p), p, + "_OBJC_OptProtocolInstMethods", + meta_proto_nst_meth); + + opt_class_meth = + generate_v2_meth_descriptor_table (PROTOCOL_OPTIONAL_CLS_METHODS (p), p, + "_OBJC_OptProtocolClassMethods", + meta_proto_cls_meth); + + if (PROTOCOL_LIST (p)) + refs_decl = generate_v2_protocol_list (p, NULL_TREE); + else + refs_decl = 0; + + /* static struct objc_protocol _OBJC_Protocol_<mumble>; */ + protocol_name_expr = add_objc_string (PROTOCOL_NAME (p), class_names); + + if (refs_decl) + refs_expr = convert (build_pointer_type (objc_v2_protocol_template), + build_unary_op (loc, ADDR_EXPR, refs_decl, 0)); + else + refs_expr = build_int_cst (NULL_TREE, 0); + + props = generate_v2_property_table (p, NULL_TREE); + + initlist = build_v2_protocol_initializer (TREE_TYPE (decl), + protocol_name_expr, refs_expr, + inst_meth, class_meth, + opt_inst_meth, opt_class_meth, + props); + finish_var_decl (decl, initlist); + objc_add_to_protocol_list (p, decl); + } + + if (some) + { + /* Make sure we get the Protocol class linked in - reference it... */ + p = objc_v2_get_class_reference (get_identifier (PROTOCOL_OBJECT_CLASS_NAME)); + /* .. but since we don't specifically use the ref.. + we need to force it. */ + DECL_PRESERVE_P (p) = 1; + } +} + +static tree +generate_v2_dispatch_table (tree chain, const char *name, tree attr) +{ + tree decl, method_list_template, initlist; + VEC(constructor_elt,gc) *v = NULL; + int size, init_val; + + if (!chain || !name || !(size = list_length (chain))) + return NULL_TREE; + + method_list_template + = build_v2_method_list_template (objc_method_template, size); + initlist + = build_dispatch_table_initializer (objc_method_template, chain); + + decl = start_var_decl (method_list_template, name); + + init_val = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (objc_method_template)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (integer_type_node, init_val)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (integer_type_node, size)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, initlist); + + OBJCMETA (decl, objc_meta, attr); + finish_var_decl (decl, + objc_build_constructor (TREE_TYPE (decl), v)); + return decl; +} + +/* Init a category. */ +static tree +build_v2_category_initializer (tree type, tree cat_name, tree class_name, + tree inst_methods, tree class_methods, + tree protocol_list, tree property_list, + location_t loc) +{ + tree expr, ltyp; + VEC(constructor_elt,gc) *v = NULL; + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, cat_name); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, class_name); + + ltyp = objc_method_list_ptr; + if (inst_methods) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, inst_methods, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + if (class_methods) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, class_methods, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + /* protocol_list = */ + ltyp = build_pointer_type (objc_v2_protocol_template); + if (protocol_list) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, protocol_list, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + ltyp = objc_prop_list_ptr; + if (property_list) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, property_list, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + return objc_build_constructor (type, v); +} + +/* static struct category_t _OBJC_CATEGORY_$_<name> = { ... }; */ + +static void +generate_v2_category (struct imp_entry *impent) +{ + tree initlist, cat_name_expr, class_name_expr; + tree protocol_decl, category, props, t; + tree inst_methods = NULL_TREE, class_methods = NULL_TREE; + tree cat = impent->imp_context; + tree cat_decl = impent->class_decl; + location_t loc; + char buf[BUFSIZE]; + + loc = DECL_SOURCE_LOCATION (cat_decl); + + /* ??? not sure this is really necessary, the following references should + force appropriate linkage linkage... + -- but ... ensure a reference to the class... */ + t = objc_v2_get_class_reference (CLASS_NAME (cat)); + /* ... which we ignore so force it out.. */ + DECL_PRESERVE_P (t) = 1; + + snprintf (buf, BUFSIZE, "OBJC_CLASS_$_%s", IDENTIFIER_POINTER (CLASS_NAME (cat))); + class_name_expr = create_extern_decl (objc_v2_class_template, buf); + class_name_expr = build_fold_addr_expr (class_name_expr); + + cat_name_expr = add_objc_string (CLASS_SUPER_NAME (cat), class_names); + category = lookup_category (impent->imp_template, CLASS_SUPER_NAME (cat)); + + if (category && CLASS_PROTOCOL_LIST (category)) + { + generate_protocol_references (CLASS_PROTOCOL_LIST (category)); + protocol_decl = generate_v2_protocol_list (category, cat); + } + else + protocol_decl = NULL_TREE; + +/* decl = update_var_decl(impent->class_decl);*/ + + props = generate_v2_property_table (NULL_TREE, cat); + + if (CLASS_NST_METHODS (cat)) + { + snprintf (buf, BUFSIZE, "_OBJC_CategoryInstanceMethods_%s_%s", + IDENTIFIER_POINTER (CLASS_NAME (cat)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (cat))); + inst_methods = generate_v2_dispatch_table (CLASS_NST_METHODS (cat), buf, + meta_cati_meth); + } + + if (CLASS_CLS_METHODS (cat)) + { + snprintf (buf, BUFSIZE, "_OBJC_CategoryClassMethods_%s_%s", + IDENTIFIER_POINTER (CLASS_NAME (cat)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (cat))); + class_methods = generate_v2_dispatch_table (CLASS_CLS_METHODS (cat), buf, + meta_catc_meth); + } + + initlist = build_v2_category_initializer (TREE_TYPE (cat_decl), + cat_name_expr, class_name_expr, + inst_methods, class_methods, + protocol_decl, props, loc); + + finish_var_decl (cat_decl, initlist); + impent->class_decl = cat_decl; + + /* Add to list of pointers in __category_list section */ + objc_v2_add_to_category_list (cat_decl); + if (has_load_impl (CLASS_CLS_METHODS (impent->imp_context))) + objc_v2_add_to_nonlazy_category_list (cat_decl); +} + +/* This routine declares a variable to hold the offset for ivar FIELD_DECL. + Variable name is .objc_ivar.ClassName.IvarName. */ + +typedef struct GTY(()) ivarref_entry { + tree decl; + tree offset; +} ivarref_entry; +DEF_VEC_O(ivarref_entry); +DEF_VEC_ALLOC_O(ivarref_entry, gc); + +static GTY (()) VEC (ivarref_entry, gc) * ivar_offset_refs; + +static tree +ivar_offset_ref (tree class_name, tree field_decl) +{ + tree decl, field_decl_id; + ivarref_entry e; + bool global_var; + char buf[512]; + + create_ivar_offset_name (buf, class_name, field_decl); + field_decl_id = get_identifier (buf); + + if (ivar_offset_refs) + { + int count; + ivarref_entry *ref; + FOR_EACH_VEC_ELT (ivarref_entry, ivar_offset_refs, count, ref) + if (DECL_NAME (ref->decl) == field_decl_id) + return ref->decl; + } + else + /* Somewhat arbitrary initial provision. */ + ivar_offset_refs = VEC_alloc (ivarref_entry, gc, 32); + + /* We come here if we don't find a match or at the start. */ + global_var = (TREE_PUBLIC (field_decl) || TREE_PROTECTED (field_decl)); + if (global_var) + decl = create_global_decl (TREE_TYPE (size_zero_node), buf); + else + decl = create_hidden_decl (TREE_TYPE (size_zero_node), buf); + + /* Make sure it ends up in an ObjC section. */ + OBJCMETA (decl, objc_meta, meta_base); + + e.decl = decl; + e.offset = byte_position (field_decl); + VEC_safe_push (ivarref_entry, gc, ivar_offset_refs, &e); + return decl; +} + +/* This routine builds initializer-list needed to initialize + 'struct ivar_t list[count] + of 'struct ivar_list_t' meta data. TYPE is 'struct ivar_t' and + FIELD_DECL is list of ivars for the target class. +*/ + +static tree +build_v2_ivar_list_initializer (tree class_name, tree type, tree field_decl) +{ + VEC(constructor_elt,gc) *inits = NULL; + + do + { + VEC(constructor_elt,gc) *ivar = NULL; + int val; + tree id; + + /* Unnamed bitfields are ignored. */ + if (!DECL_NAME (field_decl)) + { + field_decl = DECL_CHAIN (field_decl); + continue; + } + + /* Set offset */ + CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, + build_unary_op (input_location, + ADDR_EXPR, + ivar_offset_ref (class_name, + field_decl), 0)); + + /* Set name */ + CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, + add_objc_string (DECL_NAME (field_decl), + meth_var_names)); + + /* Set type */ + encode_field_decl (field_decl, + obstack_object_size (&util_obstack), + OBJC_ENCODE_DONT_INLINE_DEFS); + /* Null terminate string. */ + obstack_1grow (&util_obstack, 0); + id = add_objc_string (get_identifier (XOBFINISH (&util_obstack, char *)), + meth_var_types); + CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, id); + obstack_free (&util_obstack, util_firstobj); + + /* Set alignment */ + val = DECL_ALIGN_UNIT (field_decl); + val = exact_log2 (val); + CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, + build_int_cst (integer_type_node, val)); + + /* Set size */ + val = TREE_INT_CST_LOW (DECL_SIZE_UNIT (field_decl)); + CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, + build_int_cst (integer_type_node, val)); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, + objc_build_constructor (type, ivar)); + + do + field_decl = DECL_CHAIN (field_decl); + while (field_decl && TREE_CODE (field_decl) != FIELD_DECL); + } + while (field_decl); + + return objc_build_constructor (build_array_type (type, 0), inits); +} + +/* + struct ivar_list_t { + uint32 entsize; + uint32 count; + struct iver_t list[count]; + }; +*/ + +static tree +build_v2_ivar_list_t_template (tree list_type, int size) +{ + tree objc_ivar_list_record; + tree decls, *chain = NULL; + + /* Anonymous. */ + objc_ivar_list_record = objc_start_struct (NULL_TREE); + + /* uint32 entsize; */ + decls = add_field_decl (integer_type_node, "entsize", &chain); + + /* uint32 count; */ + add_field_decl (integer_type_node, "count", &chain); + + /* struct objc_ivar ivar_list[]; */ + add_field_decl (build_sized_array_type (list_type, size), + "list", &chain); + + objc_finish_struct (objc_ivar_list_record, decls); + return objc_ivar_list_record; +} + +/* This routine declares a static variable of type 'struct ivar_list_t' and + initializes it. + chain is the source of the data, name is the name for the var. + attr is the meta-data section tag attribute + templ is the implementation template for the class. */ + +static tree +generate_v2_ivars_list (tree chain, const char *name, tree attr, tree templ) +{ + tree decl, initlist, ivar_list_template; + VEC(constructor_elt,gc) *inits = NULL; + int size, ivar_t_size; + + if (!chain || !name || !(size = ivar_list_length (chain))) + return NULL_TREE; + + generating_instance_variables = 1; + ivar_list_template = build_v2_ivar_list_t_template (objc_v2_ivar_template, + size); + + initlist = build_v2_ivar_list_initializer (CLASS_NAME (templ), + objc_v2_ivar_template, chain); + ivar_t_size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (objc_v2_ivar_template)); + + decl = start_var_decl (ivar_list_template, name); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, + build_int_cst (integer_type_node, ivar_t_size)); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, + build_int_cst (integer_type_node, size)); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, initlist); + OBJCMETA (decl, objc_meta, attr); + finish_var_decl (decl, objc_build_constructor (TREE_TYPE (decl), inits)); + generating_instance_variables = 0; + return decl; +} + +/* Routine to build initializer list to initialize objects of type struct class_t; */ + +static tree +build_v2_class_t_initializer (tree type, tree isa, tree superclass, + tree ro, tree cache, tree vtable) +{ + VEC(constructor_elt,gc) *initlist = NULL; + + /* isa */ + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, isa); + + /* superclass */ + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, superclass); + + /* cache */ + if (cache) + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, cache); + else + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, null_pointer_node); + + /* vtable */ + if (vtable) + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, vtable); + else + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, null_pointer_node); + + /* ro */ + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, ro); + + return objc_build_constructor (type, initlist); +} + +/* Routine to build object of struct class_ro_t { ... }; */ + +static tree +build_v2_class_ro_t_initializer (tree type, tree name, + unsigned int flags, unsigned int instanceStart, + unsigned int instanceSize, + tree ivarLayout, + tree baseMethods, tree baseProtocols, + tree ivars, tree property_list) +{ + tree expr, unsigned_char_star, ltyp; + location_t loc; + VEC(constructor_elt,gc) *initlist = NULL; + + /* TODO: fish out the real location from somewhere. */ + loc = UNKNOWN_LOCATION; + + /* flags */ + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, + build_int_cst (integer_type_node, flags)); + + /* instanceStart */ + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, + build_int_cst (integer_type_node, instanceStart)); + + /* instanceSize */ + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, + build_int_cst (integer_type_node, instanceSize)); + + /* This ABI is currently only used on m64 NeXT, we choose to + make the alignment padding explicit. */ + /* reserved, pads alignment. */ + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, + build_int_cst (integer_type_node, 0)); + + /* ivarLayout */ + unsigned_char_star = build_pointer_type (unsigned_char_type_node); + if (ivarLayout) + expr = ivarLayout; + else + expr = convert (unsigned_char_star, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, expr); + + /* name */ + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, default_conversion (name)); + + /* baseMethods */ + ltyp = objc_method_list_ptr; + if (baseMethods) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, baseMethods, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, expr); + + /* baseProtocols */ + ltyp = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (UTAG_V2_PROTOCOL_LIST))); + if (baseProtocols) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, baseProtocols, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, expr); + + /* ivars */ + ltyp = objc_v2_ivar_list_ptr; + if (ivars) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, ivars, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, expr); + + /* TODO: We don't yet have the weak/strong stuff... */ + /* weakIvarLayout */ + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, + convert (unsigned_char_star, null_pointer_node)); + + /* property list */ + ltyp = objc_prop_list_ptr; + if (property_list) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, property_list, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, expr); + return objc_build_constructor (type, initlist); +} + +static GTY (()) VEC (ident_data_tuple, gc) * ehtype_list; + +/* Record a name as needing a catcher. */ +static void +objc_v2_add_to_ehtype_list (tree name) +{ + ident_data_tuple e; + if (ehtype_list) + { + int count = 0; + ident_data_tuple *ref; + + FOR_EACH_VEC_ELT (ident_data_tuple, ehtype_list, count, ref) + if (ref->ident == name) + return; /* Already entered. */ + } + else + /* Arbitrary initial count. */ + ehtype_list = VEC_alloc (ident_data_tuple, gc, 8); + /* Not found, or new list. */ + e.ident = name; + e.data = NULL_TREE; + VEC_safe_push (ident_data_tuple, gc, ehtype_list, &e); +} + +static void +generate_v2_class_structs (struct imp_entry *impent) +{ + tree decl, name_expr, initlist, protocol_decl, metaclass_decl, class_decl; + tree field, firstIvar, chain; + tree class_superclass_expr, metaclass_superclass_expr, props; + /* TODO: figure out how to compute this. */ + tree ivarLayout = NULL_TREE; + tree my_super_id = NULL_TREE, root_expr = NULL_TREE; + tree inst_methods = NULL_TREE, class_methods = NULL_TREE; + tree inst_ivars = NULL_TREE, class_ivars = NULL_TREE; + location_t loc; + char buf[BUFSIZE]; + unsigned int instanceStart, instanceSize; + unsigned int flags = 0x01; /* RO_META */ + int cls_flags = impent->has_cxx_cdtors ? OBJC2_CLS_HAS_CXX_STRUCTORS + : 0 ; + + class_decl = impent->class_decl; + metaclass_decl = impent->meta_decl; + loc = DECL_SOURCE_LOCATION (class_decl); + + DECL_EXTERNAL (class_decl) = DECL_EXTERNAL (metaclass_decl) = 0; + TREE_PUBLIC (class_decl) = TREE_PUBLIC (metaclass_decl) = 1; +#ifdef OBJCPLUS + gcc_assert (!CP_DECL_CONTEXT (class_decl) || CP_DECL_CONTEXT (class_decl) == global_namespace); + gcc_assert (!CP_DECL_CONTEXT (metaclass_decl) || CP_DECL_CONTEXT (metaclass_decl) == global_namespace); +#endif + + /* Generation of data for meta class */ + my_super_id = CLASS_SUPER_NAME (impent->imp_template); + if (my_super_id) + { + /* compute reference to root's name. For meta class, "isa" is reference + to root class name. */ + tree my_root_id = my_super_id; + tree my_root_int, interface; + do + { + my_root_int = lookup_interface (my_root_id); + + if (my_root_int && CLASS_SUPER_NAME (my_root_int)) + my_root_id = CLASS_SUPER_NAME (my_root_int); + else + break; + } + while (1); + + /* {extern} struct class_t OBJC_METACLASS_$_<my_root_int> + create extern if not already declared. */ + snprintf (buf, BUFSIZE, "OBJC_METACLASS_$_%s", + IDENTIFIER_POINTER (CLASS_NAME (my_root_int))); + root_expr = create_extern_decl (objc_v2_class_template, buf); + root_expr = build_fold_addr_expr (root_expr); + + /* Install class `isa' and `super' pointers at runtime. */ + interface = lookup_interface (my_super_id); + gcc_assert (interface); + /* Similarly, for OBJC_CLASS_$_<interface>... */ + snprintf (buf, BUFSIZE, "OBJC_CLASS_$_%s", + IDENTIFIER_POINTER (CLASS_NAME (interface))); + class_superclass_expr = create_extern_decl (objc_v2_class_template, buf); + class_superclass_expr = build_fold_addr_expr (class_superclass_expr); + /* ... and for OBJC_METACLASS_$_<interface>. */ + snprintf (buf, BUFSIZE, "OBJC_METACLASS_$_%s", + IDENTIFIER_POINTER (CLASS_NAME (interface))); + metaclass_superclass_expr = create_extern_decl (objc_v2_class_template, buf); + metaclass_superclass_expr = build_fold_addr_expr (metaclass_superclass_expr); + } + else + { + /* root class. */ + root_expr = build_unary_op (loc, ADDR_EXPR, metaclass_decl, 0); + metaclass_superclass_expr = build_unary_op (loc, ADDR_EXPR, class_decl, 0); + class_superclass_expr = build_int_cst (NULL_TREE, 0); + flags |= 0x02; /* RO_ROOT: it is also a root meta class */ + } + + if (CLASS_PROTOCOL_LIST (impent->imp_template)) + { + generate_protocol_references (CLASS_PROTOCOL_LIST (impent->imp_template)); + protocol_decl = generate_v2_protocol_list (impent->imp_template, + impent->imp_context); + } + else + protocol_decl = 0; + + name_expr = add_objc_string (CLASS_NAME (impent->imp_template), + class_names); + + if (CLASS_CLS_METHODS (impent->imp_context)) + { + snprintf (buf, BUFSIZE, "_OBJC_ClassMethods_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + class_methods = + generate_v2_dispatch_table (CLASS_CLS_METHODS (impent->imp_context), + buf, meta_clac_meth); + } + + instanceStart = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (objc_v2_class_template)); + + /* Currently there are no class ivars and generation of class variables for + the root of the inheritance has been removed. It causes multiple defines + if there are two root classes in the link, because each will define its + own identically-named offset variable. */ + + class_ivars = NULL_TREE; + /* TODO: Add total size of class variables when implemented. */ + instanceSize = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (objc_v2_class_template)); + + /* So now build the META CLASS structs. */ + /* static struct class_ro_t _OBJC_METACLASS_Foo = { ... }; */ + + decl = start_var_decl (objc_v2_class_ro_template, + newabi_append_ro (IDENTIFIER_POINTER + (DECL_NAME (metaclass_decl)))); + + /* TODO: ivarLayout needs t be built. */ + initlist = + build_v2_class_ro_t_initializer (TREE_TYPE (decl), name_expr, + (flags | cls_flags), instanceStart, + instanceSize, ivarLayout, + class_methods, protocol_decl, + class_ivars, NULL_TREE); + /* The ROs sit in the default const section. */ + OBJCMETA (decl, objc_meta, meta_base); + finish_var_decl (decl, initlist); + + /* static struct class_t _OBJC_METACLASS_Foo = { ... }; */ + initlist = + build_v2_class_t_initializer (TREE_TYPE (metaclass_decl), + root_expr, + metaclass_superclass_expr, + build_fold_addr_expr (decl), + build_fold_addr_expr (UOBJC_V2_CACHE_decl), + build_fold_addr_expr (UOBJC_V2_VTABLE_decl)); + /* The class section attributes are set when they are created. */ + finish_var_decl (metaclass_decl, initlist); + impent->meta_decl = metaclass_decl; + + /* So now build the CLASS structs. */ + + flags = 0x0; /* ... */ + if (!my_super_id) + flags |= 0x02; /* RO_ROOT: this is a root class */ + + if (DECL_VISIBILITY (class_decl) == VISIBILITY_HIDDEN) + flags |= 0x10; /* RO_HIDDEN, OBJC2_CLS_HIDDEN; */ + + if (objc2_objc_exception_attr (impent->imp_template)) + flags |= 0x20; /* RO_EXCEPTION */ + + if (CLASS_NST_METHODS (impent->imp_context)) + { + snprintf (buf, BUFSIZE, "_OBJC_InstanceMethods_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + inst_methods = + generate_v2_dispatch_table (CLASS_NST_METHODS (impent->imp_context), + buf, meta_clai_meth); + } + + /* Sort out the ivars before we try to compute the class sizes. */ + if ((chain = CLASS_IVARS (impent->imp_template))) + { + snprintf (buf, BUFSIZE, "_OBJC_InstanceIvars_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + inst_ivars = generate_v2_ivars_list (chain, buf, meta_clai_vars, + impent->imp_template); + } + + /* Compute instanceStart */ + gcc_assert (CLASS_STATIC_TEMPLATE (impent->imp_template)); + field = TYPE_FIELDS (CLASS_STATIC_TEMPLATE (impent->imp_template)); + if (my_super_id && field && TREE_CHAIN (field)) + field = TREE_CHAIN (field); + + firstIvar = field; + + while (firstIvar && TREE_CODE (firstIvar) != FIELD_DECL) + firstIvar = TREE_CHAIN (firstIvar); + + gcc_assert (inst_ivars? (firstIvar != NULL_TREE): true); + + /* Compute instanceSize */ + while (field && TREE_CHAIN (field) + && TREE_CODE (TREE_CHAIN (field)) == FIELD_DECL) + field = TREE_CHAIN (field); + + if (field && TREE_CODE (field) == FIELD_DECL) + instanceSize = int_byte_position (field) * BITS_PER_UNIT + + tree_low_cst (DECL_SIZE (field), 0); + else + instanceSize = 0; + instanceSize /= BITS_PER_UNIT; + + props = generate_v2_property_table (NULL_TREE, impent->imp_context); + + /* If the class has no ivars, instanceStart should be set to the superclass's + instanceSize */ + instanceStart = + (inst_ivars != NULL_TREE) ? (unsigned) int_byte_position (firstIvar) + : instanceSize; + + /* static struct class_ro_t _OBJC_CLASS_Foo = { ... }; */ + decl = start_var_decl (objc_v2_class_ro_template, + newabi_append_ro (IDENTIFIER_POINTER + (DECL_NAME (class_decl)))); + + initlist = + build_v2_class_ro_t_initializer (TREE_TYPE (decl), name_expr, + (flags | cls_flags), instanceStart, + instanceSize, ivarLayout, + inst_methods, protocol_decl, + inst_ivars, props); + /* The ROs sit in the default const section. */ + OBJCMETA (decl, objc_meta, meta_base); + finish_var_decl (decl, initlist); + + /* static struct class_t _OBJC_CLASS_Foo = { ... }; */ + initlist = build_v2_class_t_initializer (TREE_TYPE (class_decl), + build_fold_addr_expr (metaclass_decl), + class_superclass_expr, + build_fold_addr_expr (decl), + build_fold_addr_expr (UOBJC_V2_CACHE_decl), + build_fold_addr_expr (UOBJC_V2_VTABLE_decl)); + + /* The class section attributes are set when they are created. */ + finish_var_decl (class_decl, initlist); + impent->class_decl = class_decl; + + objc_v2_add_to_class_list (class_decl); + if (has_load_impl (CLASS_CLS_METHODS (impent->imp_context))) + objc_v2_add_to_nonlazy_class_list (class_decl); + + if (flags & 0x20) /* RO_EXCEPTION */ + objc_v2_add_to_ehtype_list (CLASS_NAME (impent->imp_template)); +} + +/* This routine outputs the (ivar_reference_offset, offset) tuples. */ + +static void +build_v2_ivar_offset_ref_table (void) +{ + int count; + ivarref_entry *ref; + + if (!ivar_offset_refs || !VEC_length (ivarref_entry, ivar_offset_refs)) + return; + + FOR_EACH_VEC_ELT (ivarref_entry, ivar_offset_refs, count, ref) + finish_var_decl (ref->decl, ref->offset); +} + +/* static int _OBJC_IMAGE_INFO[2] = { 0, 16 | flags }; */ + +static void +generate_v2_objc_image_info (void) +{ + tree decl, array_type; + VEC(constructor_elt,gc) *v = NULL; + int flags = + ((flag_replace_objc_classes && imp_count ? 1 : 0) + | (flag_objc_gc ? 2 : 0)); + + flags |= 16; + + array_type = build_sized_array_type (integer_type_node, 2); + + decl = start_var_decl (array_type, "_OBJC_ImageInfo"); + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (integer_type_node, flags)); + /* The Runtime wants this. */ + DECL_PRESERVE_P (decl) = 1; + OBJCMETA (decl, objc_meta, meta_info); + finish_var_decl (decl, objc_build_constructor (TREE_TYPE (decl), v)); +} + +static void +objc_generate_v2_next_metadata (void) +{ + struct imp_entry *impent; + + gcc_assert (!objc_static_instances); /* Not for NeXT */ + + build_metadata_templates (); + + for (impent = imp_list; impent; impent = impent->next) + { + /* If -gen-decls is present, Dump the @interface of each class. + TODO: Dump the classes in the order they were found, rather than in + reverse order as we are doing now. */ + if (flag_gen_declaration) + dump_interface (gen_declaration_file, impent->imp_context); + + /* all of the following reference the string pool... */ + if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) + generate_v2_class_structs (impent); + else + generate_v2_category (impent); + } + + build_next_selector_translation_table (); + build_v2_message_ref_translation_table (); + + /* This will add "Protocol" to the class refs. */ + generate_v2_protocols (); + + build_v2_classrefs_table (); + build_v2_super_classrefs_table (/*metaclass= */false); + build_v2_super_classrefs_table (/*metaclass= */true); + + build_v2_ivar_offset_ref_table (); + + build_v2_protocol_list_translation_table (); + build_v2_protocol_list_address_table (); + + build_v2_address_table (class_list, "_OBJC_ClassList$", + meta_label_classlist); + build_v2_address_table (category_list, "_OBJC_CategoryList$", + meta_label_categorylist); + build_v2_address_table (nonlazy_class_list, "_OBJC_NonLazyClassList$", + meta_label_nonlazy_classlist); + build_v2_address_table (nonlazy_category_list, "_OBJC_NonLazyCategoryList$", + meta_label_nonlazy_categorylist); + + /* This conveys information on GC usage and zero-link. */ + generate_v2_objc_image_info (); + + /* Generate catch objects for eh, if any are needed. */ + build_v2_eh_catch_objects (); + + /* Emit the string table last. */ + generate_strings (); +} + +/* NOTE --- Output NeXT V2 Exceptions --- */ + +static GTY(()) tree objc_v2_ehtype_template; +static GTY(()) tree next_v2_ehvtable_decl; +static GTY(()) tree next_v2_EHTYPE_id_decl; + +static void +build_v2_ehtype_template (void) +{ + tree decls, *chain = NULL; + objc_v2_ehtype_template = objc_start_struct (get_identifier (UTAG_V2_EH_TYPE)); + + /* void *_objc_ehtype_vtable; */ + decls = add_field_decl (ptr_type_node, "_objc_ehtype_vtable_ptr", &chain); + + /* const char *className; */ + add_field_decl (string_type_node, "className", &chain); + + /* struct class_t *const cls; */ + add_field_decl (build_pointer_type (objc_v2_class_template), "cls", &chain); + + objc_finish_struct (objc_v2_ehtype_template, decls); +} + +/* Template for the Objective-C family typeinfo type for ABI=2. + This starts off the same as the gxx/cxx eh typeinfo. + + struct _objc_ehtype_t { + void *_objc_ehtype_vtable_ptr; - as per c++ + const char *className; - as per c++ + struct class_t *const cls; + } +*/ + +/* This routine builds initializer list for object of type struct _objc_ehtype_t. +*/ + +static tree +objc2_build_ehtype_initializer (tree name, tree cls) +{ + VEC(constructor_elt,gc) *initlist = NULL; + tree addr, offs; + + /* This is done the same way as c++, missing the two first entries in the + parent vtable. NOTE: there is a fix-me in the Apple/NeXT runtime source + about this so, perhaps, this will change at some point. */ + /* _objc_ehtype_vtable + 2*sizeof(void*) */ + if (!next_v2_ehvtable_decl) + { + next_v2_ehvtable_decl = + start_var_decl (ptr_type_node, TAG_NEXT_EHVTABLE_NAME); + TREE_STATIC (next_v2_ehvtable_decl) = 0; + DECL_EXTERNAL (next_v2_ehvtable_decl) = 1; + TREE_PUBLIC (next_v2_ehvtable_decl) = 1; + } + addr = build_fold_addr_expr_with_type (next_v2_ehvtable_decl, ptr_type_node); + offs = size_int (2 * int_cst_value (TYPE_SIZE_UNIT (ptr_type_node))); + addr = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, addr, offs); + + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, addr); + + /* className */ + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, name); + + /* cls */ + CONSTRUCTOR_APPEND_ELT (initlist, NULL_TREE, cls); + + return objc_build_constructor (objc_v2_ehtype_template, initlist); +} + +static tree +build_ehtype (tree name, const char *eh_name, bool weak) +{ + tree name_expr, class_name_expr, ehtype_decl, inits; + + name_expr = add_objc_string (name, class_names); + /* Extern ref. for the class. ??? maybe we can look this up somewhere. */ + class_name_expr = + create_extern_decl (objc_v2_class_template, + objc_build_internal_classname (name, false)); + class_name_expr = build_fold_addr_expr (class_name_expr); + ehtype_decl = create_global_decl (objc_v2_ehtype_template, eh_name); + if (weak) + DECL_WEAK (ehtype_decl) = 1; + inits = objc2_build_ehtype_initializer (name_expr, class_name_expr); + OBJCMETA (ehtype_decl, objc_meta, meta_ehtype); + finish_var_decl (ehtype_decl, inits); + return ehtype_decl; +} + +/* This routine returns TRUE if CLS or any of its super classes has + __attribute__ ((objc_exception)). +*/ + +static bool +objc2_objc_exception_attr (tree cls) +{ + while (cls) + { + if (CLASS_HAS_EXCEPTION_ATTR (cls)) + return true; + cls = lookup_interface (CLASS_SUPER_NAME (cls)); + } + + return false; +} + +static bool +is_implemented (tree name) +{ + struct imp_entry *t; + for (t = imp_list; t; t = t->next) + if (TREE_CODE (t->imp_context) == CLASS_IMPLEMENTATION_TYPE + && CLASS_NAME (t->imp_template) == name) + return true; + + return false; +} + +/* We will build catch objects: + for any type implemented here. + for any type used in a catch that has no exception attribute. */ +static void build_v2_eh_catch_objects (void) +{ + int count=0; + ident_data_tuple *ref; + + if (!ehtype_list || !VEC_length (ident_data_tuple, ehtype_list)) + return; + + FOR_EACH_VEC_ELT (ident_data_tuple, ehtype_list, count, ref) + { + char buf[BUFSIZE]; + bool impl = is_implemented (ref->ident); + bool excpt = objc2_objc_exception_attr (lookup_interface (ref->ident)); + snprintf (buf, BUFSIZE, "OBJC_EHTYPE_$_%s", IDENTIFIER_POINTER (ref->ident)); + if (!impl && excpt) + /* The User says this class has a catcher already. */ + ref->data = create_extern_decl (objc_v2_ehtype_template, buf); + else + /* Create a catcher, weak if it wasn't marked. */ + ref->data = build_ehtype (ref->ident, buf, !excpt); + } +} + +static tree +lookup_ehtype_ref (tree id) +{ + int count=0; + ident_data_tuple *ref; + + if (!ehtype_list || !VEC_length (ident_data_tuple, ehtype_list)) + return NULL_TREE; + + FOR_EACH_VEC_ELT (ident_data_tuple, ehtype_list, count, ref) + if (ref->ident == id) + return ref->data; + return NULL_TREE; +} + +/* This hook, called via lang_eh_runtime_type, generates a runtime object + which is either the address of the 'OBJC_EHTYPE_$_class' object or + address of external OBJC_EHTYPE_id object. +*/ +static tree +next_runtime_02_eh_type (tree type) +{ + tree t; + + if (type == error_mark_node + /*|| errorcount || sorrycount*/) + goto err_mark_in; + + if (POINTER_TYPE_P (type) && objc_is_object_id (TREE_TYPE (type))) + { + if (!next_v2_EHTYPE_id_decl) + { + /* This is provided by the Apple/NeXT libobjc.dylib so we need + only to reference it. */ + next_v2_EHTYPE_id_decl = + start_var_decl (objc_v2_ehtype_template, "OBJC_EHTYPE_id"); + DECL_EXTERNAL (next_v2_EHTYPE_id_decl) = 1; + TREE_PUBLIC (next_v2_EHTYPE_id_decl) = 1; + TREE_STATIC (next_v2_EHTYPE_id_decl) = 0; + } + return build_fold_addr_expr (next_v2_EHTYPE_id_decl); + } + + if (!POINTER_TYPE_P (type) || !TYPED_OBJECT (TREE_TYPE (type))) + { +#ifdef OBJCPLUS + /* This routine is also called for c++'s catch clause; in which case, + we use c++'s typeinfo decl. */ + return build_eh_type_type (type); +#else + error ("non-objective-c type '%T' cannot be caught", type); + goto err_mark_in; +#endif + } + else + t = OBJC_TYPE_NAME (TREE_TYPE (type)); + + /* We have to build a reference to the OBJC_EHTYPE_<Class>. */ + t = lookup_ehtype_ref (t); + if (!t) + goto err_mark_in; + + return build_fold_addr_expr (t); + +err_mark_in: + return error_mark_node; +} + +static GTY(()) tree objc_eh_personality_decl; + +static tree +objc_eh_personality (void) +{ + if (!objc_eh_personality_decl) + objc_eh_personality_decl = build_personality_function ("objc"); + return objc_eh_personality_decl; +} + +/* NOTE --- interfaces --- */ + +static tree +build_throw_stmt (location_t loc, tree throw_expr, bool rethrown) +{ + tree t; + if (rethrown) + /* We have a separate re-throw entry. */ + t = build_function_call_vec (loc, objc_rethrow_exception_decl, NULL, NULL); + else + { + /* Throw like the others .. */ + VEC(tree, gc) *parms = VEC_alloc (tree, gc, 1); + VEC_quick_push (tree, parms, throw_expr); + t = build_function_call_vec (loc, objc_exception_throw_decl, parms, NULL); + VEC_free (tree, gc, parms); + } + return add_stmt (t); +} + +/* Build __builtin_eh_pointer. */ + +static tree +objc_build_exc_ptr (struct objc_try_context **x ATTRIBUTE_UNUSED) +{ + tree t; + t = built_in_decls[BUILT_IN_EH_POINTER]; + t = build_call_expr (t, 1, integer_zero_node); + return fold_convert (objc_object_type, t); +} + +static tree begin_catch (struct objc_try_context **cur_try_context, tree type, + tree decl, tree compound, bool ellipsis ATTRIBUTE_UNUSED) +{ + tree t; + + /* Record the data for the catch in the try context so that we can + finalize it later. Ellipsis is signalled by a NULL entry. */ + if (ellipsis) + t = build_stmt (input_location, CATCH_EXPR, NULL_TREE, compound); + else + t = build_stmt (input_location, CATCH_EXPR, type, compound); + (*cur_try_context)->current_catch = t; + + /* Initialize the decl from the EXC_PTR_EXPR we get from the runtime. */ + t = objc_build_exc_ptr (cur_try_context); + t = convert (TREE_TYPE (decl), t); + /* TODO location stuff. */ + if (type && type != error_mark_node) + { + t = build1(NOP_EXPR, ptr_type_node, t); + t = build_function_call (input_location, objc2_begin_catch_decl, + tree_cons (NULL_TREE, t, NULL_TREE)); + + /* We might want to build a catch object for this (if it's not id). */ + if (POINTER_TYPE_P (type) + && !objc_is_object_id (TREE_TYPE (type)) + && TYPED_OBJECT (TREE_TYPE (type))) + objc_v2_add_to_ehtype_list (OBJC_TYPE_NAME (TREE_TYPE (type))); + } + return build2 (MODIFY_EXPR, void_type_node, decl, t); +} + +/* try { catch-body } finally { objc_end_catch (); } */ +static void +finish_catch (struct objc_try_context **cur_try_context, tree curr_catch) +{ + struct objc_try_context *ct; + tree try_exp, func, *l, t ; + location_t loc = (*cur_try_context)->try_locus; + + if (!curr_catch || curr_catch == error_mark_node) + return; + + t = CATCH_BODY (curr_catch); + if (TREE_CODE (t) == BIND_EXPR) + { + /* usual case of @catch (objc-expr). */ + objc_begin_try_stmt (loc, BIND_EXPR_BODY (t)); + BIND_EXPR_BODY (t) = NULL_TREE; + l = &BIND_EXPR_BODY (t); + } + else + { + /* NULL entry, @catch (...) */ + objc_begin_try_stmt (loc, t); + CATCH_BODY (curr_catch) = NULL_TREE; + l = &CATCH_BODY (curr_catch); + } + + /* Pick up the new context we made in begin_try above.. */ + ct = *cur_try_context; + func = build_function_call_vec (loc, objc2_end_catch_decl, NULL, NULL); + append_to_statement_list (func, &ct->finally_body); + try_exp = build_stmt (loc, TRY_FINALLY_EXPR, ct->try_body, ct->finally_body); + *cur_try_context = ct->outer; + free (ct); + append_to_statement_list (try_exp, l); + append_to_statement_list (curr_catch, &((*cur_try_context)->catch_list)); +} + +static tree +finish_try_stmt (struct objc_try_context **cur_try_context) +{ + struct objc_try_context *c = *cur_try_context; + tree stmt = c->try_body; + if (c->catch_list) + stmt = build_stmt (c->try_locus, TRY_CATCH_EXPR, stmt, c->catch_list); + if (c->finally_body) + stmt = build_stmt (c->try_locus, TRY_FINALLY_EXPR, stmt, c->finally_body); + return stmt; +} + +#include "gt-objc-objc-next-runtime-abi-02.h" diff --git a/gcc/objc/objc-runtime-hooks.h b/gcc/objc/objc-runtime-hooks.h new file mode 100644 index 0000000..d071c8b --- /dev/null +++ b/gcc/objc/objc-runtime-hooks.h @@ -0,0 +1,108 @@ +/* Hooks to abstract the runtime meta-data generation for Objective C. + Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by Iain Sandoe + +This file is part of GCC. + +GCC 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, or (at your option) +any later version. + +GCC 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/>. */ + +#ifndef _OBJC_RUNTIME_HOOKS_H_ +#define _OBJC_RUNTIME_HOOKS_H_ + +/* A set of hooks for the front end to obtain runtime-specific actions. */ + +/* Objective-C supports several runtime library variants: + + "GNU" runtime selected by -fgnu-runtime (currently at API version 1). + "NeXT" runtime (selected by -fnext-runtime) and installed on OSX/Darwin + systems at API version 1 (for m32 code) and version 2 (for m64 code). + + The runtimes require different data types/layouts, method call mechanisms + and so on, and the purpose of this interface is to abstract such + differences from the parser's perspective. */ + +typedef struct _objc_runtime_hooks_r +{ + /* Initialize for this runtime. */ + void (*initialize) (void); + const char *default_constant_string_class_name; + + /* FIXME: Having to check this name should not be necessary. */ + const char *tag_getclass; + /* id for superclass class field - named differently in the existing + runtimes. */ + tree (*super_superclassfield_ident) (void); + + /* Obtain a class decl for the identifier. */ + tree (*class_decl) (tree); + /* Obtain a metaclass decl for the identifier. */ + tree (*metaclass_decl) (tree); + /* Obtain a category decl for the identifier. */ + tree (*category_decl) (tree); + /* Obtain a protocol decl for the identifier. */ + tree (*protocol_decl) (tree); + /* Obtain a string decl, to be placed in the nominated string-section. */ + tree (*string_decl) (tree, const char *, string_section); + + /* Obtain a class reference, generating the fwd def. if necessary. */ + tree (*get_class_reference) (tree); + /* build/get selector reference. */ + tree (*build_selector_reference) (location_t, tree, tree); + /* Get a protocol reference, generating the forward def. if necessary. */ + tree (*get_protocol_reference) (location_t, tree); + /* Get an ivar ref. re the base. */ + tree (*build_ivar_reference) (location_t, tree, tree); + /* Get a reference to {meta}class' super. */ + tree (*get_class_super_ref) (location_t, struct imp_entry *, bool); + /* Get a reference to Category {meta}class' super. */ + tree (*get_category_super_ref) (location_t, struct imp_entry *, bool); + + /* Receiver is class Object, check runtime-specific. */ + tree (*receiver_is_class_object) (tree); + /* Get the start of a method argument type list (receiver, _cmd). */ + tree (*get_arg_type_list_base) (tree, int, int); + /* Build method call. */ + tree (*build_objc_method_call) (location_t, tree, tree, tree, tree, tree, int); + + /* Check for or otherwise handle a request to check that the constant + string class reference is set-up & OK. */ + bool (*setup_const_string_class_decl) (void); + /* Return the tree reprenting a const string constructor for the arg. + Most of the data are in global trees. */ + tree (*build_const_string_constructor) (location_t, tree, int); + + /* Exceptions. */ + tree (*build_throw_stmt) (location_t, tree, bool); + tree (*build_exc_ptr) (struct objc_try_context **); + tree (*begin_catch) (struct objc_try_context **, tree, tree, tree, bool); + void (*finish_catch) (struct objc_try_context **, tree); + tree (*finish_try_stmt) (struct objc_try_context **); + + /* Emit all the metadata required by the runtime - based on the tables built + during parsing. */ + void (*generate_metadata) (void); + +} objc_runtime_hooks; + +/* For shared support that needs to access these. */ +extern objc_runtime_hooks runtime; + +/* One per runtime at present. + TODO: Make into some kind of configury-generated table. */ +extern bool objc_gnu_runtime_abi_01_init (objc_runtime_hooks *); +extern bool objc_next_runtime_abi_01_init (objc_runtime_hooks *); +extern bool objc_next_runtime_abi_02_init (objc_runtime_hooks *); + +#endif /* _OBJC_RUNTIME_HOOKS_H_ */ diff --git a/gcc/objc/objc-runtime-shared-support.c b/gcc/objc/objc-runtime-shared-support.c new file mode 100644 index 0000000..dff1d46 --- /dev/null +++ b/gcc/objc/objc-runtime-shared-support.c @@ -0,0 +1,733 @@ +/* Support routines shared by all runtimes. + Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by Iain Sandoe (partially split from objc-act.c) + +This file is part of GCC. + +GCC 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, or (at your option) +any later version. + +GCC 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/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" + +#ifdef OBJCPLUS +#include "cp-tree.h" +#else +#include "c-tree.h" +#include "c-lang.h" +#endif +#include "langhooks.h" +#include "c-family/c-objc.h" +#include "objc-act.h" + +/* When building Objective-C++, we are not linking against the C front-end + and so need to replicate the C tree-construction functions in some way. */ +#ifdef OBJCPLUS +#define OBJCP_REMAP_FUNCTIONS +#include "objcp-decl.h" +#endif /* OBJCPLUS */ + +#include "obstack.h" + +/* These are only used for encoding ivars. */ +extern struct obstack util_obstack; +extern char *util_firstobj; + +/* Hooks for string decls etc. */ +#include "objc-runtime-hooks.h" + +#include "objc-runtime-shared-support.h" + +/* rt_trees identifiers - shared between NeXT implementations. These allow + the FE to tag meta-data in a manner that survives LTO and can be used when + the runtime requires that certain meta-data items appear in particular + named sections. */ +#include "objc-next-metadata-tags.h" +extern GTY(()) tree objc_rt_trees[OCTI_RT_META_MAX]; + +/* Rather than repeatedly looking up the identifiers, we save them here. */ +tree objc_rt_trees[OCTI_RT_META_MAX]; + +/* For building an objc struct. These might not be used when this file + is compiled as part of obj-c++. */ + +static bool objc_building_struct; +static struct c_struct_parse_info *objc_struct_info ATTRIBUTE_UNUSED; + +/* Start building a struct for objc. */ + +tree +objc_start_struct (tree name) +{ + gcc_assert (!objc_building_struct); + objc_building_struct = true; + return start_struct (input_location, RECORD_TYPE, name, &objc_struct_info); +} + +/* Finish building a struct for objc. */ + +tree +objc_finish_struct (tree type, tree fieldlist) +{ + gcc_assert (objc_building_struct); + objc_building_struct = false; + return finish_struct (input_location, type, fieldlist, NULL_TREE, + objc_struct_info); +} + +tree +build_sized_array_type (tree base_type, int size) +{ + tree index_type = build_index_type (build_int_cst (NULL_TREE, size - 1)); + return build_array_type (base_type, index_type); +} + +/* Create a declaration for field NAME of a given TYPE. */ + +static tree +create_field_decl (tree type, const char *name) +{ + return build_decl (input_location, + FIELD_DECL, get_identifier (name), type); +} + +tree +add_field_decl (tree type, const char *name, tree **chain) +{ + tree field = create_field_decl (type, name); + + if (*chain != NULL) + **chain = field; + *chain = &DECL_CHAIN (field); + + return field; +} + +/* Create a global, static declaration for variable NAME of a given TYPE. The + finish_var_decl() routine will need to be called on it afterwards. */ + +tree +start_var_decl (tree type, const char *name) +{ + tree var = build_decl (input_location, + VAR_DECL, get_identifier (name), type); + TREE_STATIC (var) = 1; + DECL_INITIAL (var) = error_mark_node; /* A real initializer is coming... */ + DECL_IGNORED_P (var) = 1; + DECL_ARTIFICIAL (var) = 1; + DECL_CONTEXT (var) = NULL_TREE; +#ifdef OBJCPLUS + DECL_THIS_STATIC (var) = 1; /* squash redeclaration errors */ +#endif + return var; +} + +/* Finish off the variable declaration created by start_var_decl(). */ + +void +finish_var_decl (tree var, tree initializer) +{ + finish_decl (var, input_location, initializer, NULL_TREE, NULL_TREE); +} + +/* Just a handy wrapper for add_objc_string. */ + +tree +build_selector (tree ident) +{ + return convert (objc_selector_type, add_objc_string (ident, meth_var_names)); +} + +/* --- templates --- */ + +/* Set 'objc_super_template' to the data type node for 'struct _objc_super'. + This needs to be done just once per compilation. */ + +/* struct _objc_super { + struct _objc_object *self; + struct _objc_class *super_class; + [or Class cls; for the abi v2] + }; */ + +void +build_super_template (void) +{ + tree decls, *chain = NULL; + + objc_super_template = objc_start_struct (get_identifier (UTAG_SUPER)); + + /* struct _objc_object *self; */ + decls = add_field_decl (objc_object_type, "self", &chain); + + /* struct _objc_class *super_class; */ + add_field_decl (build_pointer_type (objc_class_template), + "super_class", &chain); + + objc_finish_struct (objc_super_template, decls); +} + +/* To accomplish method prototyping without generating all kinds of + inane warnings, the definition of the dispatch table entries were + changed from: + + struct objc_method { SEL _cmd; ...; id (*_imp)(); }; + to: + struct objc_method { SEL _cmd; ...; void *_imp; }; */ + +tree +build_method_template (void) +{ + tree _SLT_record; + tree decls, *chain = NULL; + + _SLT_record = objc_start_struct (get_identifier (UTAG_METHOD)); + + /* SEL _cmd; */ + decls = add_field_decl (objc_selector_type, "_cmd", &chain); + + /* char *method_types; */ + add_field_decl (string_type_node, "method_types", &chain); + + /* void *_imp; */ + add_field_decl (build_pointer_type (void_type_node), "_imp", &chain); + + objc_finish_struct (_SLT_record, decls); + + return _SLT_record; +} + +tree +build_method_prototype_template (void) +{ + tree proto_record; + tree decls, *chain = NULL; + + proto_record = objc_start_struct (get_identifier (UTAG_METHOD_PROTOTYPE)); + + /* SEL _cmd; */ + decls = add_field_decl (objc_selector_type, "_cmd", &chain); + + /* char *method_types; */ + add_field_decl (string_type_node, "method_types", &chain); + + objc_finish_struct (proto_record, decls); + + return proto_record; +} + +/* struct { + struct _objc__method_prototype_list *method_next; + int method_count; + struct objc_method method_list[method_count]; + }; */ + +tree +build_method_list_template (tree list_type, int size) +{ + tree objc_ivar_list_record; + tree array_type, decls, *chain = NULL; + + objc_ivar_list_record = objc_start_struct (NULL_TREE); + + /* struct _objc__method_prototype_list *method_next; */ + decls = add_field_decl (objc_method_proto_list_ptr, "method_next", &chain); + + /* int method_count; */ + add_field_decl (integer_type_node, "method_count", &chain); + + /* struct objc_method method_list[]; */ + array_type = build_sized_array_type (list_type, size); + add_field_decl (array_type, "method_list", &chain); + + objc_finish_struct (objc_ivar_list_record, decls); + + return objc_ivar_list_record; +} + +/* struct objc_method_prototype_list { + int count; + struct objc_method_prototype { + SEL name; + char *types; + } list[1]; + }; */ + +tree +build_method_prototype_list_template (tree list_type, int size) +{ + tree objc_ivar_list_record; + tree array_type, decls, *chain = NULL; + + /* Generate an unnamed struct definition. */ + + objc_ivar_list_record = objc_start_struct (NULL_TREE); + + /* int method_count; */ + decls = add_field_decl (integer_type_node, "method_count", &chain); + + /* struct objc_method method_list[]; */ + array_type = build_sized_array_type (list_type, size); + add_field_decl (array_type, "method_list", &chain); + + objc_finish_struct (objc_ivar_list_record, decls); + + return objc_ivar_list_record; +} + +/* --- names, decls entry --- */ + +/* For each string section we have a chain which maps identifier nodes + to decls for the strings. */ + +static GTY(()) int meth_var_names_idx; +static GTY(()) int meth_var_types_idx; +static GTY(()) int property_name_attr_idx; + +tree +add_objc_string (tree ident, string_section section) +{ + tree *chain, decl, type; + char buf[BUFSIZE]; + + switch (section) + { + case class_names: + chain = &class_names_chain; + snprintf (buf, BUFSIZE, "_OBJC_ClassName_%s", IDENTIFIER_POINTER (ident)); + break; + case meth_var_names: + chain = &meth_var_names_chain; + snprintf (buf, BUFSIZE, "_OBJC_METH_VAR_NAME_%d", meth_var_names_idx++); + break; + case meth_var_types: + chain = &meth_var_types_chain; + snprintf (buf, BUFSIZE, "_OBJC_METH_VAR_TYPE_%d", meth_var_types_idx++); + break; + case prop_names_attr: + chain = &prop_names_attr_chain; + snprintf (buf, BUFSIZE, "_OBJC_PropertyAttributeOrName_%d", property_name_attr_idx++); + break; + default: + gcc_unreachable (); + } + + while (*chain) + { + if (TREE_VALUE (*chain) == ident) + return convert (string_type_node, + build_unary_op (input_location, + ADDR_EXPR, TREE_PURPOSE (*chain), 1)); + + chain = &TREE_CHAIN (*chain); + } + + type = build_sized_array_type (char_type_node, IDENTIFIER_LENGTH (ident) + 1); + /* Get a runtime-specific string decl which will be finish_var()'ed in + generate_strings (). */ + decl = (*runtime.string_decl) (type, buf, section); + TREE_CONSTANT (decl) = 1; + *chain = tree_cons (decl, ident, NULL_TREE); + + return convert (string_type_node, + build_unary_op (input_location, ADDR_EXPR, decl, 1)); +} + +/* --- shared metadata routines --- */ + +tree +build_descriptor_table_initializer (tree type, tree entries) +{ + VEC(constructor_elt,gc) *inits = NULL; + + do + { + VEC(constructor_elt,gc) *elts = NULL; + + CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, + build_selector (METHOD_SEL_NAME (entries))); + CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, + add_objc_string (METHOD_ENCODING (entries), + meth_var_types)); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, + objc_build_constructor (type, elts)); + + entries = DECL_CHAIN (entries); + } + while (entries); + + return objc_build_constructor (build_array_type (type, 0), inits); +} + +tree +build_dispatch_table_initializer (tree type, tree entries) +{ + VEC(constructor_elt,gc) *inits = NULL; + + do + { + VEC(constructor_elt,gc) *elems = NULL; + tree expr; + + CONSTRUCTOR_APPEND_ELT (elems, NULL_TREE, + build_selector (METHOD_SEL_NAME (entries))); + + /* Generate the method encoding if we don't have one already. */ + if (! METHOD_ENCODING (entries)) + METHOD_ENCODING (entries) = + encode_method_prototype (entries); + + CONSTRUCTOR_APPEND_ELT (elems, NULL_TREE, + add_objc_string (METHOD_ENCODING (entries), + meth_var_types)); + + expr = convert (ptr_type_node, + build_unary_op (input_location, ADDR_EXPR, + METHOD_DEFINITION (entries), 1)); + CONSTRUCTOR_APPEND_ELT (elems, NULL_TREE, expr); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, + objc_build_constructor (type, elems)); + + entries = DECL_CHAIN (entries); + } + while (entries); + + return objc_build_constructor (build_array_type (type, 0), inits); +} + +/* Used only by 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 tree +init_module_descriptor (tree type, long vers) +{ + tree expr, ltyp; + location_t loc; + VEC(constructor_elt,gc) *v = NULL; + + /* No really useful place to point to. */ + loc = UNKNOWN_LOCATION; + + /* version = { 1, ... } */ + + expr = build_int_cst (long_integer_type_node, vers); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + /* size = { ..., sizeof (struct _objc_module), ... } */ + + expr = convert (long_integer_type_node, + size_in_bytes (objc_module_template)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + /* Don't provide any file name for security reasons. */ + /* name = { ..., "", ... } */ + + expr = add_objc_string (get_identifier (""), class_names); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + /* symtab = { ..., _OBJC_SYMBOLS, ... } */ + + ltyp = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (UTAG_SYMTAB))); + if (UOBJC_SYMBOLS_decl) + expr = convert (ltyp, build_unary_op (loc, + ADDR_EXPR, UOBJC_SYMBOLS_decl, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + return objc_build_constructor (type, v); +} + +/* Write out the data structures to describe Objective C classes defined. + + struct _objc_module { ... } _OBJC_MODULE = { ... }; */ + +void +build_module_descriptor (long vers, tree attr) +{ + tree decls, *chain = NULL; + +#ifdef OBJCPLUS + push_lang_context (lang_name_c); /* extern "C" */ +#endif + + objc_module_template = objc_start_struct (get_identifier (UTAG_MODULE)); + + /* long version; */ + decls = add_field_decl (long_integer_type_node, "version", &chain); + + /* long size; */ + add_field_decl (long_integer_type_node, "size", &chain); + + /* char *name; */ + add_field_decl (string_type_node, "name", &chain); + + /* struct _objc_symtab *symtab; */ + add_field_decl (build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (UTAG_SYMTAB))), + "symtab", &chain); + + objc_finish_struct (objc_module_template, decls); + + /* Create an instance of "_objc_module". */ + UOBJC_MODULES_decl = start_var_decl (objc_module_template, + flag_next_runtime ? "_OBJC_Module" : "_OBJC_Module"); + + /* 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; + + /* Allow the runtime to mark meta-data such that it can be assigned to target + specific sections by the back-end. */ + if (attr) + DECL_ATTRIBUTES (UOBJC_MODULES_decl) = attr; + + finish_var_decl (UOBJC_MODULES_decl, + init_module_descriptor (TREE_TYPE (UOBJC_MODULES_decl), + vers)); + +#ifdef OBJCPLUS + pop_lang_context (); +#endif +} + +tree +build_ivar_list_initializer (tree type, tree field_decl) +{ + VEC(constructor_elt,gc) *inits = NULL; + + do + { + VEC(constructor_elt,gc) *ivar = NULL; + tree id; + + /* Set name. */ + if (DECL_NAME (field_decl)) + CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, + add_objc_string (DECL_NAME (field_decl), + meth_var_names)); + else + /* Unnamed bit-field ivar (yuck). */ + CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, build_int_cst (NULL_TREE, 0)); + + /* Set type. */ + encode_field_decl (field_decl, + obstack_object_size (&util_obstack), + OBJC_ENCODE_DONT_INLINE_DEFS); + + /* Null terminate string. */ + obstack_1grow (&util_obstack, 0); + id = add_objc_string (get_identifier (XOBFINISH (&util_obstack, char *)), + meth_var_types); + CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, id); + obstack_free (&util_obstack, util_firstobj); + + /* Set offset. */ + CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, byte_position (field_decl)); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, + objc_build_constructor (type, ivar)); + do + field_decl = DECL_CHAIN (field_decl); + while (field_decl && TREE_CODE (field_decl) != FIELD_DECL); + } + while (field_decl); + + return objc_build_constructor (build_array_type (type, 0), inits); +} + +/* struct { + int ivar_count; + struct objc_ivar ivar_list[ivar_count]; + }; */ + +tree +build_ivar_list_template (tree list_type, int size) +{ + tree objc_ivar_list_record; + tree array_type, decls, *chain = NULL; + + objc_ivar_list_record = objc_start_struct (NULL_TREE); + + /* int ivar_count; */ + decls = add_field_decl (integer_type_node, "ivar_count", &chain); + + /* struct objc_ivar ivar_list[]; */ + array_type = build_sized_array_type (list_type, size); + add_field_decl (array_type, "ivar_list", &chain); + + objc_finish_struct (objc_ivar_list_record, decls); + + return objc_ivar_list_record; +} + +/* struct _objc_ivar { + char *ivar_name; + char *ivar_type; + int ivar_offset; + }; */ + +tree +build_ivar_template (void) +{ + tree objc_ivar_id, objc_ivar_record; + tree decls, *chain = NULL; + + objc_ivar_id = get_identifier (UTAG_IVAR); + objc_ivar_record = objc_start_struct (objc_ivar_id); + + /* char *ivar_name; */ + decls = add_field_decl (string_type_node, "ivar_name", &chain); + + /* char *ivar_type; */ + add_field_decl (string_type_node, "ivar_type", &chain); + + /* int ivar_offset; */ + add_field_decl (integer_type_node, "ivar_offset", &chain); + + objc_finish_struct (objc_ivar_record, decls); + + return objc_ivar_record; +} + +/* Used by NeXT ABI=0..2 */ +void +build_next_selector_translation_table (void) +{ + tree chain; + for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain)) + { + tree expr; + tree decl = TREE_PURPOSE (chain); + if (warn_selector) + { + location_t loc; + if (decl) + loc = DECL_SOURCE_LOCATION (decl); + else + loc = UNKNOWN_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 on start-up, but the compiler can't see + that and optimizes it away unless we force it. */ + DECL_PRESERVE_P (decl) = 1; + finish_var_decl (decl, expr); + } + } +} + +void +generate_protocol_references (tree plist) +{ + tree lproto; + + /* Forward declare protocols referenced. */ + for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) + { + tree proto = TREE_VALUE (lproto); + + if (TREE_CODE (proto) == PROTOCOL_INTERFACE_TYPE + && PROTOCOL_NAME (proto)) + { + if (! PROTOCOL_FORWARD_DECL (proto)) + PROTOCOL_FORWARD_DECL (proto) = (*runtime.protocol_decl) (proto); + + if (PROTOCOL_LIST (proto)) + generate_protocol_references (PROTOCOL_LIST (proto)); + } + } +} + +/* --- new routines --- */ + +/* Output all strings. */ + +/* FIXME: don't use global vars for all this... */ + +/* This emits all the meta-data string tables (and finalizes each var + as it goes). */ +void +generate_strings (void) +{ + tree chain, string_expr; + tree string, decl; /* , type;*/ + + for (chain = class_names_chain; chain; chain = TREE_CHAIN (chain)) + { + string = TREE_VALUE (chain); + decl = TREE_PURPOSE (chain); + string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1, + IDENTIFIER_POINTER (string)); + finish_var_decl (decl, string_expr); + } + + for (chain = meth_var_names_chain; chain; chain = TREE_CHAIN (chain)) + { + string = TREE_VALUE (chain); + decl = TREE_PURPOSE (chain); + string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1, + IDENTIFIER_POINTER (string)); + finish_var_decl (decl, string_expr); + } + + for (chain = meth_var_types_chain; chain; chain = TREE_CHAIN (chain)) + { + string = TREE_VALUE (chain); + decl = TREE_PURPOSE (chain); + string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1, + IDENTIFIER_POINTER (string)); + finish_var_decl (decl, string_expr); + } + + for (chain = prop_names_attr_chain; chain; chain = TREE_CHAIN (chain)) + { + string = TREE_VALUE (chain); + decl = TREE_PURPOSE (chain); + string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1, + IDENTIFIER_POINTER (string)); + finish_var_decl (decl, string_expr); + } +} + +#include "gt-objc-objc-runtime-shared-support.h" diff --git a/gcc/objc/objc-runtime-shared-support.h b/gcc/objc/objc-runtime-shared-support.h new file mode 100644 index 0000000..8e4693d --- /dev/null +++ b/gcc/objc/objc-runtime-shared-support.h @@ -0,0 +1,90 @@ +/* Support routines shared by all runtimes. + Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by Iain Sandoe + +This file is part of GCC. + +GCC 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, or (at your option) +any later version. + +GCC 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/>. */ + +#ifndef _OBJC_RUNTIME_SHARED_SUPPORT_H_ +#define _OBJC_RUNTIME_SHARED_SUPPORT_H_ + +/* Left in obj-act.c for now... */ + +extern tree objc_start_struct (tree); +extern tree objc_finish_struct (tree, tree); +extern tree add_field_decl (tree, const char *, tree **); +extern tree build_sized_array_type (tree, int); + +extern tree lookup_interface (tree); +extern tree objc_build_constructor (tree, VEC(constructor_elt,gc) *); + +extern tree start_var_decl (tree, const char *); +extern void finish_var_decl (tree, tree); + +extern tree my_build_string (int, const char *); +extern tree my_build_string_pointer (int, const char *); +extern tree add_objc_string (tree ident, string_section); +extern tree get_objc_string_decl (tree, string_section); + +extern void add_class_reference (tree); + +#ifdef OBJCPLUS +extern void objc_start_function (tree, tree, tree, tree); +extern tree objc_get_parm_info (int); +#else +extern void objc_start_function (tree, tree, tree, struct c_arg_info *); +extern struct c_arg_info *objc_get_parm_info (int); +#endif +extern void objc_push_parm (tree); +extern tree get_arg_type_list (tree, int, int); + +/* Stuff that should be migrated to shared support (or some v1-only file). */ +extern void build_super_template (void); + +extern tree objc_build_component_ref (tree, tree); + +extern tree objc_v2_encode_prop_attr (tree); +extern tree build_descriptor_table_initializer (tree, tree); +extern tree build_method_prototype_list_template (tree, int); +extern tree build_protocol_initializer (tree, tree, tree, tree, tree); + +/* Stuff that should be migrated to shared encode. */ +extern tree encode_method_prototype (tree); +extern void encode_field_decl (tree, int, int); + +/* Moved or new routines in objc-runtime-shared-support.c */ + +extern tree build_selector (tree); +extern tree build_method_template (void); +extern tree build_method_prototype_template (void); +extern tree build_method_list_template (tree, int); + +extern tree build_dispatch_table_initializer (tree, tree); +extern void diagnose_missing_method (tree, location_t); +extern void build_next_selector_translation_table (void); +extern void generate_protocol_references (tree); +extern void build_module_descriptor (long, tree); +extern tree build_ivar_list_initializer (tree, tree); +extern tree build_ivar_list_template (tree, int); +extern tree build_ivar_template (void); + +extern void generate_strings (void); + +extern void dump_interface (FILE *, tree); +extern int generating_instance_variables; +extern FILE *gen_declaration_file; + +#endif /* _OBJC_RUNTIME_SHARED_SUPPORT_H_ */ diff --git a/gcc/objcp/ChangeLog b/gcc/objcp/ChangeLog index 83999f7..a327707 100644 --- a/gcc/objcp/ChangeLog +++ b/gcc/objcp/ChangeLog @@ -1,3 +1,19 @@ +2011-02-17 Iain Sandoe <iains@gcc.gnu.org> + + * Make-lang.in (START_HDRS): New. + (OBJCXX_OBJS): Added new object files from objc/. + (objcp/objcp-act.o): Updated prerequisites. + (objcp/objcp-lang.o): Updated prerequisites. + (objcp/objc-runtime-shared-support.o): New. + (objcp/objc-gnu-runtime-abi-01.o): New. + (objcp/objc-next-runtime-abi-01.o): New. + (objcp/objc-next-runtime-abi-02.o): New. + * config-lang.in (gtfiles): Updated. + * objcp-lang.c (objcxx_eh_personality): Removed. + (LANG_HOOKS_EH_PERSONALITY): Removed. + (LANG_HOOKS_EH_RUNTIME_TYPE): Removed. + (objcp_eh_personality_decl): Removed. + 2011-02-07 Mike Stump <mikestump@comcast.net> * Make-lang.in (obj-c++.tags): Don't include *.y. diff --git a/gcc/objcp/Make-lang.in b/gcc/objcp/Make-lang.in index 2122d2d..5bbd27e 100644 --- a/gcc/objcp/Make-lang.in +++ b/gcc/objcp/Make-lang.in @@ -1,5 +1,5 @@ # Top level -*- makefile -*- fragment for GNU Objective-C++ -# Copyright (C) 2005, 2007, 2008, 2009, 2010 +# Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011 # Free Software Foundation, Inc. # Contributed by Ziemowit Laski <zlaski@apple.com> @@ -44,12 +44,19 @@ obj-c++: cc1objplus$(exeext) # Tell GNU make to ignore these if they exist. .PHONY: obj-c++ +START_HDRS = $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(CXX_TREE_H) \ + langhooks.h c-family/c-objc.h objc/objc-act.h + # Use maximal warnings for this front end. Also, make ObjC and C++ # headers accessible. objcp-warn = $(STRICT_WARN) -DOBJCPLUS -I$(srcdir)/objc -I$(srcdir)/cp # Language-specific object files for Objective C++. OBJCXX_OBJS = objcp/objcp-act.o objcp/objcp-lang.o objcp/objcp-decl.o \ + objcp/objc-runtime-shared-support.o \ + objcp/objc-gnu-runtime-abi-01.o \ + objcp/objc-next-runtime-abi-01.o \ + objcp/objc-next-runtime-abi-02.o \ $(CXX_AND_OBJCXX_OBJS) obj-c++_OBJS = $(OBJCXX_OBJS) cc1objplus-checksum.o @@ -69,23 +76,48 @@ cc1objplus$(exeext): $(OBJCXX_OBJS) cc1objplus-checksum.o $(BACKEND) $(LIBDEPS) # Objective C++ language specific files. -objcp/objcp-lang.o : objcp/objcp-lang.c \ - $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(CXX_TREE_H) \ - $(C_COMMON_H) $(LANGHOOKS_DEF_H) objc/objc-act.h cp/cp-objcp-common.h \ - $(TARGET_H) gtype-objcp.h c-family/c-objc.h +objcp/objcp-lang.o : objcp/objcp-lang.c $(START_HDRS) \ + $(C_COMMON_H) $(LANGHOOKS_DEF_H) cp/cp-objcp-common.h \ + $(TARGET_H) gtype-objcp.h objcp/objcp-decl.o : objcp/objcp-decl.c \ $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(CXX_TREE_H) \ objc/objc-act.h objcp/objcp-decl.h c-family/c-objc.h +objcp/objc-runtime-shared-support.o : objc/objc-runtime-shared-support.c \ + $(START_HDRS) objc/objc-runtime-shared-support.h $(OBSTACK_H) \ + objc/objc-next-metadata-tags.h gt-objc-objc-runtime-shared-support.h + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< \ + $(OUTPUT_OPTION) + +objcp/objc-gnu-runtime-abi-01.o: objc/objc-gnu-runtime-abi-01.c $(START_HDRS) \ + objc/objc-runtime-hooks.h $(GGC_H) \ + gt-objc-objc-gnu-runtime-abi-01.h toplev.h + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< \ + $(OUTPUT_OPTION) + +objcp/objc-next-runtime-abi-01.o: objc/objc-next-runtime-abi-01.c $(START_HDRS) \ + $(GGC_H) objc/objc-runtime-hooks.h \ + objc/objc-next-metadata-tags.h gt-objc-objc-next-runtime-abi-01.h output.h \ + objc/objc-runtime-shared-support.h $(TARGET_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< \ + $(OUTPUT_OPTION) + +objcp/objc-next-runtime-abi-02.o: objc/objc-next-runtime-abi-02.c $(START_HDRS) \ + $(GGC_H) objc/objc-runtime-hooks.h \ + objc/objc-next-metadata-tags.h gt-objc-objc-next-runtime-abi-02.h $(TARGET_H) \ + objc/objc-runtime-shared-support.h $(OBSTACK_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< \ + $(OUTPUT_OPTION) + + # The following must be an explicit rule; please keep in sync with the implicit # one in Makefile.in. -objcp/objcp-act.o : objc/objc-act.c \ - $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) $(TM_P_H) \ - $(EXPR_H) $(TARGET_H) $(CXX_TREE_H) $(DIAGNOSTIC_H) toplev.h $(FLAGS_H) \ - objc/objc-act.h input.h $(FUNCTION_H) output.h debug.h langhooks.h \ +objcp/objcp-act.o : objc/objc-act.c $(START_HDRS) $(GGC_H) \ + $(RTL_H) $(EXPR_H) $(TARGET_H) $(DIAGNOSTIC_H) toplev.h $(FLAGS_H) \ + input.h $(FUNCTION_H) output.h debug.h $(OBSTACK_H) \ objcp/objcp-decl.h $(LANGHOOKS_DEF_H) $(HASHTAB_H) gt-objc-objc-act.h \ - $(GIMPLE_H) c-family/c-objc.h + $(GIMPLE_H) objc/objc-runtime-hooks.h objc/objc-runtime-shared-support.h $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< \ $(OUTPUT_OPTION) diff --git a/gcc/objcp/config-lang.in b/gcc/objcp/config-lang.in index 962b9a8..b8565d8 100644 --- a/gcc/objcp/config-lang.in +++ b/gcc/objcp/config-lang.in @@ -1,5 +1,5 @@ # Top level configure fragment for GNU Objective-C++. -# Copyright (C) 2005, 2007, 2010 Free Software Foundation, Inc. +# Copyright (C) 2005, 2007, 2010, 2011 Free Software Foundation, Inc. # Contributed by Ziemowit Laski <zlaski@apple.com> #This file is part of GCC. @@ -37,4 +37,4 @@ build_by_default="no" lang_requires="objc c++" subdir_requires="objc cp" -gtfiles="\$(srcdir)/objcp/objcp-decl.c \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-act.h \$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/cp-objcp-common.c" +gtfiles="\$(srcdir)/objc/objc-act.h \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-runtime-shared-support.c \$(srcdir)/objc/objc-gnu-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-02.c \$(srcdir)/cp/call.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/method.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/parser.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/rtti.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c " diff --git a/gcc/objcp/objcp-lang.c b/gcc/objcp/objcp-lang.c index fa674aa..fe2be66 100644 --- a/gcc/objcp/objcp-lang.c +++ b/gcc/objcp/objcp-lang.c @@ -1,5 +1,5 @@ /* Language-dependent hooks for Objective-C++. - Copyright 2005, 2007, 2008, 2010 Free Software Foundation, Inc. + Copyright 2005, 2007, 2008, 2010, 2011 Free Software Foundation, Inc. Contributed by Ziemowit Laski <zlaski@apple.com> This file is part of GCC. @@ -18,7 +18,6 @@ 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/>. */ - #include "config.h" #include "system.h" #include "coretypes.h" @@ -35,7 +34,6 @@ along with GCC; see the file COPYING3. If not see enum c_language_kind c_language = clk_objcxx; static void objcxx_init_ts (void); -static tree objcxx_eh_personality (void); /* Lang hooks common to C++ and ObjC++ are declared in cp/cp-objcp-common.h; consequently, there should be very few hooks below. */ @@ -48,10 +46,6 @@ static tree objcxx_eh_personality (void); #define LANG_HOOKS_GIMPLIFY_EXPR objc_gimplify_expr #undef LANG_HOOKS_INIT_TS #define LANG_HOOKS_INIT_TS objcxx_init_ts -#undef LANG_HOOKS_EH_PERSONALITY -#define LANG_HOOKS_EH_PERSONALITY objcxx_eh_personality -#undef LANG_HOOKS_EH_RUNTIME_TYPE -#define LANG_HOOKS_EH_RUNTIME_TYPE build_eh_type_type /* Each front end provides its own lang hook initializer. */ struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; @@ -145,14 +139,4 @@ objcxx_init_ts (void) init_shadowed_var_for_decl (); } -static GTY(()) tree objcp_eh_personality_decl; - -static tree -objcxx_eh_personality (void) -{ - if (!objcp_eh_personality_decl) - objcp_eh_personality_decl = build_personality_function ("gxx"); - return objcp_eh_personality_decl; -} - #include "gtype-objcp.h" diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4d6fae0..274da7e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,55 @@ +2011-02-17 Iain Sandoe <iains@gcc.gnu.org> + + * objc.dg/special/unclaimed-category-1.h: Updated for + new ABI support. + * objc.dg/special/unclaimed-category-1.m: Same. + * objc.dg/zero-link-1.m: Same. + * objc.dg/lookup-1.m: Same. + * objc.dg/torture/strings/const-str-9.m + * objc.dg/torture/strings/const-str-10.m: Same. + * objc.dg/torture/strings/const-str-11.m: Same. + * objc.dg/torture/forward-1.m: Same. + * objc.dg/zero-link-2.m: Same. + * objc.dg/encode-7-next-64bit.m: Same. + * objc.dg/method-4.m: Same. + * objc.dg/next-runtime-1.m: Same. + * objc.dg/image-info.m: Same. + * objc.dg/pr23214.m: Same. + * objc.dg/symtab-1.m: Same. + * obj-c++.dg/basic.m: Same.m + * obj-c++.dg/proto-lossage-3.m: Same.m + * obj-c++.dg/torture/strings/const-str-10.m: Same.m + * obj-c++.dg/torture/strings/const-str-11.m: Same.m + * obj-c++.dg/torture/strings/const-str-9.m: Same.m + * obj-c++.dg/method-11.m: Same.m + * objc/execute/enumeration-1.m: Same. + * objc/execute/object_is_class.m: Same. + * objc/execute/formal_protocol-2.m: Same. + * objc/execute/formal_protocol-4.m: Same. + * objc/execute/formal_protocol-6.m: Same. + * objc/execute/bycopy-3.m: Same. + * objc/execute/exceptions/catchall-1.m: Same. + * objc/execute/exceptions/finally-1.m: Same. + * objc/execute/exceptions/local-variables-1.m: Same. + * objc/execute/exceptions/foward-1.m: Same. + * objc/execute/bf-common.h + * objc/execute/enumeration-2.m: Same. + * objc/execute/formal_protocol-1.m: Same. + * objc/execute/formal_protocol-3.m: Same. + * objc/execute/formal_protocol-5.m: Same. + * objc/execute/accessing_ivars.m: Same. + * objc/execute/bycopy-2.m: Same. + * objc/execute/formal_protocol-7.m: Same. + * objc/execute/compatibility_alias.m: Same. + * objc/execute/no_clash.m: Same. + * objc/execute/object_is_meta_class.m: Same. + * objc/execute/exceptions/exceptions.exp: Load target-supports.exp + * objc/execute/class-tests-1.h: Include stdio.h. + * objc/execute/class-tests-2.h: Same. + * obj-c++.dg/try-catch-9.mm: xfail-run the test with both + runtimes. + * obj-c++.dg/try-catch-2.mm: Same. + 2011-02-17 Jakub Jelinek <jakub@redhat.com> PR c++/47783 diff --git a/gcc/testsuite/obj-c++.dg/basic.mm b/gcc/testsuite/obj-c++.dg/basic.mm index 8fb0204..bd593c1 100644 --- a/gcc/testsuite/obj-c++.dg/basic.mm +++ b/gcc/testsuite/obj-c++.dg/basic.mm @@ -1,22 +1,41 @@ // A basic sanity check for Objective-C++. // { dg-do run } /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ -#include "../objc-obj-c++-shared/Object1.h" + +//#include "../objc-obj-c++-shared/Object1.h" #include <iostream> +#include <objc/Object.h> + +#ifdef __OBJC2__ +@interface Object (ADDITIONS) ++ initialize; +- init; ++ alloc; ++ new; +@end +@implementation Object (ADDITIONS) ++ initialize { return self; } +- init { return self; } ++ alloc { return class_createInstance (self, 0); } ++ new { return [[self alloc] init]; } +@end +#endif + @interface Greeter : Object - (void) greet: (const char *)msg; @end @implementation Greeter -- (void) greet: (const char *)msg { std::cout << msg; } +- (void) greet: (const char *)msg +{ std::cout << msg << __VERSION__ << std::endl;} @end int main () { - std::cout << "Hello from C++\n"; + std::cout << "Hello from C++" << __VERSION__ << std::endl; Greeter *obj = [Greeter new]; - [obj greet: "Hello from Objective-C\n"]; + [obj greet: "Hello from Objective-C++"]; } -#include "../objc-obj-c++-shared/Object1-implementation.h" +//#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/obj-c++.dg/method-11.mm b/gcc/testsuite/obj-c++.dg/method-11.mm index 6c6b1a0..74192e8 100644 --- a/gcc/testsuite/obj-c++.dg/method-11.mm +++ b/gcc/testsuite/obj-c++.dg/method-11.mm @@ -22,5 +22,8 @@ void foo(void) { obj = [ObjectAlias2 new]; } -/* { dg-final { scan-assembler "_OBJC_CLASS_REFERENCES_0" } } */ -/* { dg-final { scan-assembler-not "_OBJC_CLASS_REFERENCES_1" } } */ +/* { dg-final { scan-assembler "_OBJC_ClassRefs_0" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler "_OBJC_ClassRef_Object" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler-not "_OBJC_ClassRefs_1" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler-not "_OBJC_ClassRef_ObjectTypedef" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler-not "_OBJC_ClassRef_ObjectAlias" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/obj-c++.dg/proto-lossage-3.mm b/gcc/testsuite/obj-c++.dg/proto-lossage-3.mm index 8a6623e..ac66ace 100644 --- a/gcc/testsuite/obj-c++.dg/proto-lossage-3.mm +++ b/gcc/testsuite/obj-c++.dg/proto-lossage-3.mm @@ -19,9 +19,16 @@ int main() { +#ifdef __OBJC2__ +protocol_getMethodDescription(@protocol(NoInstanceMethods), @selector(name), NO, YES); +protocol_getMethodDescription(@protocol(NoInstanceMethods), @selector(name), NO, NO); +protocol_getMethodDescription(@protocol(NoClassMethods), @selector(name), NO, YES); +protocol_getMethodDescription(@protocol(NoClassMethods), @selector(name), NO, NO); +#else [@protocol(NoInstanceMethods) descriptionForInstanceMethod: @selector(name)]; [@protocol(NoInstanceMethods) descriptionForClassMethod: @selector(name)]; [@protocol(NoClassMethods) descriptionForInstanceMethod: @selector(name)]; [@protocol(NoClassMethods) descriptionForClassMethod: @selector(name)]; +#endif return 0; } diff --git a/gcc/testsuite/obj-c++.dg/torture/strings/const-str-10.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-10.mm index f61a474..3cb3acf 100644 --- a/gcc/testsuite/obj-c++.dg/torture/strings/const-str-10.mm +++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-10.mm @@ -29,6 +29,7 @@ extern struct objc_class _NSConstantStringClassReference; const NSConstantString *appKey = @"MyApp"; -/* { dg-final { scan-assembler ".section __OBJC, __cstring_object" } } */ +/* { dg-final { scan-assembler ".section __OBJC, __cstring_object" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler ".section __DATA, __objc_stringobj" { target { *-*-darwin* && { lp64 } } } } } */ /* { dg-final { scan-assembler ".long\t__NSConstantStringClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ -/* { dg-final { scan-assembler ".quad\t__NSConstantStringClassReference\n\t.quad\t.*\n\t.long\t5\n\t.space 4\n\t.data" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler ".quad\t_OBJC_CLASS_._NSConstantString\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/obj-c++.dg/torture/strings/const-str-11.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-11.mm index 4abab36..8674646 100644 --- a/gcc/testsuite/obj-c++.dg/torture/strings/const-str-11.mm +++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-11.mm @@ -29,6 +29,7 @@ extern struct objc_class _XStrClassReference; const XStr *appKey = @"MyApp"; -/* { dg-final { scan-assembler ".section __OBJC, __cstring_object" } } */ -/* { dg-final { scan-assembler ".long\t__XStrClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ -/* { dg-final { scan-assembler ".quad\t__XStrClassReference\n\t.quad\t.*\n\t.long\t5\n\t.space 4\n\t.data" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler ".section __OBJC, __cstring_object" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler ".section __DATA, __objc_stringobj" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler ".long\t__XStrClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler ".quad\t_OBJC_CLASS_._XStr\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/obj-c++.dg/torture/strings/const-str-9.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-9.mm index 7c99f6b..e05c62b 100644 --- a/gcc/testsuite/obj-c++.dg/torture/strings/const-str-9.mm +++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-9.mm @@ -21,6 +21,7 @@ extern struct objc_class _NSConstantStringClassReference; const NSConstantString *appKey = @"MyApp"; -/* { dg-final { scan-assembler ".section __OBJC, __cstring_object" } } */ -/* { dg-final { scan-assembler ".long\t__NSConstantStringClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } }} } */ -/* { dg-final { scan-assembler ".quad\t__NSConstantStringClassReference\n\t.quad\t.*\n\t.long\t5\n\t.space 4\n\t.data" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler ".section __OBJC, __cstring_object" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler ".section __DATA, __objc_stringobj" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler ".long\t__NSConstantStringClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler ".quad\t_OBJC_CLASS_._NSConstantString\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/obj-c++.dg/try-catch-2.mm b/gcc/testsuite/obj-c++.dg/try-catch-2.mm index cf5189a..05aba36 100644 --- a/gcc/testsuite/obj-c++.dg/try-catch-2.mm +++ b/gcc/testsuite/obj-c++.dg/try-catch-2.mm @@ -3,7 +3,7 @@ /* Developed by Ziemowit Laski <zlaski@apple.com>. */ /* { dg-do run } */ -/* { dg-xfail-if "PR23616" { *-*-* } { "-fgnu-runtime" } { "-fnext-runtime" } } */ +/* { dg-xfail-run-if "PR23616" { *-*-* } { "-fgnu-runtime" } { "-fnext-runtime" } } */ /* { dg-xfail-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" "-fgnu-runtime" } { "" } } /* { dg-options "-fobjc-exceptions" } */ diff --git a/gcc/testsuite/obj-c++.dg/try-catch-9.mm b/gcc/testsuite/obj-c++.dg/try-catch-9.mm index c4033c7..a4331fc 100644 --- a/gcc/testsuite/obj-c++.dg/try-catch-9.mm +++ b/gcc/testsuite/obj-c++.dg/try-catch-9.mm @@ -3,7 +3,7 @@ /* Developed by Ziemowit Laski <zlaski@apple.com>. */ /* { dg-do run } */ -/* { dg-xfail-if "PR23616" { *-*-* } { "-fgnu-runtime" } { "-fnext-runtime" } } */ +/* { dg-xfail-run-if "PR23616" { *-*-* } { "-fgnu-runtime" } { "-fnext-runtime" } } */ /* { dg-xfail-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" "-fgnu-runtime" } { "" } } /* { dg-prune-output ".*internal compiler error.*" } */ /* { dg-options "-fobjc-exceptions -O2" } */ diff --git a/gcc/testsuite/objc.dg/encode-7-next-64bit.m b/gcc/testsuite/objc.dg/encode-7-next-64bit.m index 3a5e61d..60129f9 100644 --- a/gcc/testsuite/objc.dg/encode-7-next-64bit.m +++ b/gcc/testsuite/objc.dg/encode-7-next-64bit.m @@ -2,16 +2,15 @@ /* { dg-do run { target *-*-darwin* } } */ /* { dg-require-effective-target lp64 } */ -/* { dg-options "-Wno-deprecated-declarations" } */ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ -/* { dg-additional-sources "../objc-obj-c++-shared/Object1.m" } */ -#include "../objc-obj-c++-shared/Object1.h" -#include "../objc-obj-c++-shared/next-mapping.h" #include <stdbool.h> #include <string.h> #include <stdlib.h> +#include <objc/Object.h> +#include "../objc-obj-c++-shared/next-mapping.h" + #define CHECK_IF(E) if (!(E)) abort () @class NSDictionary, NSFont, NSError, _NSATSTypesetterGuts, NSString, NSMenu, NSArray; @@ -195,69 +194,70 @@ NSRange globalRange; int main(void) { Class fooClass = objc_getClass ("Foo"); Method meth; - struct objc_ivar_list *ivars; - struct objc_ivar *ivar; + Ivar *ivars; + unsigned int ivar_count; + Ivar ivar; meth = class_getInstanceMethod (fooClass, @selector(_errorWithOSStatus:ref1:ref2:reading:)); - CHECK_IF (!strcmp (meth->method_types, "@44@0:8q16r^{FSRef=[80C]}24r^{FSRef=[80C]}32c40")); + CHECK_IF (!strcmp (method_getTypeEncoding(meth), "@44@0:8q16r^{FSRef=[80C]}24r^{FSRef=[80C]}32c40")); meth = class_getInstanceMethod (fooClass, @selector(_attributeRunForCharacterAtIndex:)); - CHECK_IF (!strcmp (meth->method_types, "r^{?=@@QQ^Qffff{_NSRect={_NSPoint=ff}{_NSSize=ff}}q^qQ^Q@@@:::****{?=b1b1b1b1b1b27}}24@0:8Q16")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "r^{?=@@QQ^Qffff{_NSRect={_NSPoint=ff}{_NSSize=ff}}q^qQ^Q@@@:::****{?=b1b1b1b1b1b27}}24@0:8Q16")); meth = class_getInstanceMethod (fooClass, @selector(_getATSTypesetterGuts:)); - CHECK_IF (!strcmp (meth->method_types, "r@24@0:8r:16")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "r@24@0:8r:16")); meth = class_getInstanceMethod (fooClass, @selector(resumeWithSuspensionID:and:)); - CHECK_IF (!strcmp (meth->method_types, "v32@0:8^{__NSAppleEventManagerSuspension=}16r^Q24")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "v32@0:8^{__NSAppleEventManagerSuspension=}16r^Q24")); meth = class_getInstanceMethod (fooClass, @selector(anotherMeth:and:and:)); - CHECK_IF (!strcmp (meth->method_types, "r@40@0:8r:16r@24r@32")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "r@40@0:8r:16r@24r@32")); meth = class_getInstanceMethod (fooClass, @selector(str1:str2:str3:str4:)); - CHECK_IF (!strcmp (meth->method_types, "@48@0:8r*16*24*32r*40")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "@48@0:8r*16*24*32r*40")); meth = class_getInstanceMethod (fooClass, @selector(foo1:foo2:foo3:foo4:)); - CHECK_IF (!strcmp (meth->method_types, "Vv48@0:8@16r@24@32r@40")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "Vv48@0:8@16r@24@32r@40")); meth = class_getInstanceMethod (fooClass, @selector(sel1:id1:)); - CHECK_IF (!strcmp (meth->method_types, "rn*32@0:8r:16r@24")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "rn*32@0:8r:16r@24")); meth = class_getInstanceMethod (fooClass, @selector(obj1:obj2:obj3:)); - CHECK_IF (!strcmp (meth->method_types, "N@40@0:8r@16@24^{Object=#}32")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "N@40@0:8r@16@24^{Object=#}32")); meth = class_getClassMethod (fooClass, @selector(_defaultScriptingComponent)); - CHECK_IF (!strcmp (meth->method_types, "^{ComponentInstanceRecord=[1q]}16@0:8")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "^{ComponentInstanceRecord=[1q]}16@0:8")); meth = class_getInstanceMethod (fooClass, @selector(_formatCocoaErrorString:parameters:applicableFormatters:count:)); - CHECK_IF (!strcmp (meth->method_types, "@44@0:8@16r*24^^{?}32i40")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "@44@0:8@16r*24^^{?}32i40")); meth = class_getInstanceMethod (fooClass, @selector(formatter_func:run:)); - CHECK_IF (!strcmp (meth->method_types, "^{?=^?@I}32@0:8@16r^^{?}24")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "^{?=^?@I}32@0:8@16r^^{?}24")); meth = class_getInstanceMethod (fooClass, @selector(_forgetWord:inDictionary:)); - CHECK_IF (!strcmp (meth->method_types, "c32@0:8nO@16nO@24")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "c32@0:8nO@16nO@24")); meth = class_getInstanceMethod (fooClass, @selector(_registerServicesMenu:withSendTypes:andReturnTypes:addToList:)); - CHECK_IF (!strcmp (meth->method_types, "v44@0:8@16r^*24r^*32c40")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "v44@0:8@16r^*24r^*32c40")); meth = class_getClassMethod (fooClass, @selector(_proxySharePointer)); - CHECK_IF (!strcmp (meth->method_types, "^^{__CFSet}16@0:8")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "^^{__CFSet}16@0:8")); meth = class_getInstanceMethod (fooClass, @selector(_checkGrammarInString:language:details:)); - CHECK_IF (!strcmp (meth->method_types, "{_NSRange=II}40@0:8n@16nO@24oO^@32")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "{_NSRange=II}40@0:8n@16nO@24oO^@32")); meth = class_getInstanceMethod (fooClass, @selector(_resolvePositionalStakeGlyphsForLineFragment:lineFragmentRect:minPosition:maxPosition:maxLineFragmentWidth:breakHint:)); - CHECK_IF (!strcmp (meth->method_types, "B60@0:8^{__CTLine=}16{_NSRect={_NSPoint=ff}{_NSSize=ff}}24f40f44f48^Q52")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "B60@0:8^{__CTLine=}16{_NSRect={_NSPoint=ff}{_NSSize=ff}}24f40f44f48^Q52")); meth = class_getClassMethod (fooClass, @selector(findVoiceByIdentifier:returningCreator:returningID:)); - CHECK_IF (!strcmp (meth->method_types, "c40@0:8@16^I24^I32")); + CHECK_IF (!strcmp (method_getTypeEncoding (meth), "c40@0:8@16^I24^I32")); - ivars = fooClass->ivars; - CHECK_IF (ivars->ivar_count == 1); + ivars = class_copyIvarList (fooClass, &ivar_count); + CHECK_IF (ivar_count == 1); - ivar = ivars->ivar_list; - CHECK_IF (!strcmp (ivar->ivar_name, "r")); - CHECK_IF (!strcmp (ivar->ivar_type, + ivar = ivars[0]; + CHECK_IF (!strcmp (ivar_getName(ivar), "r")); + CHECK_IF (!strcmp (ivar_getTypeEncoding(ivar), "{?=\"_attributes\"@\"NSDictionary\"\"_font\"@\"NSFont\"\"_characterLength\"" "Q\"_nominalGlyphLocation\"Q\"p\"^Q\"_defaultLineHeight\"f\"_defaultBaselineOffset\"" "f\"_horizExpansion\"f\"_baselineDelta\"f\"_attachmentBBox\"{_NSRect=\"origin\"" diff --git a/gcc/testsuite/objc.dg/image-info.m b/gcc/testsuite/objc.dg/image-info.m index e9e9de6..194d366 100644 --- a/gcc/testsuite/objc.dg/image-info.m +++ b/gcc/testsuite/objc.dg/image-info.m @@ -7,13 +7,19 @@ /* { dg-skip-if "NeXT-only" { *-*-* } { "-fgnu-runtime" } { "" } } */ /* { dg-options "-freplace-objc-classes" } */ -#include "../objc-obj-c++-shared/Object1.h" #include <objc/objc.h> +#include <objc/Object.h> extern void abort(void); - #define CHECK_IF(expr) if(!(expr)) abort(); +@interface Object (TEST_SUITE_C1) +- init; +@end +@implementation Object (TEST_SUITE_C1) +- init {return self;} +@end + @interface Base: Object { @public int a; @@ -33,4 +39,5 @@ extern void abort(void); } @end -/* { dg-final { scan-assembler "\t.section __OBJC, __image_info.*\n\t.align.*\nL_OBJC_IMAGE_INFO.*:\n\t.long\t0\n\t.long\t1" } } */ +/* { dg-final { scan-assembler "\t.section __OBJC, __image_info.*\n\t.align.*\nL_OBJC_ImageInfo.*:\n\t.long\t0\n\t.long\t1" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler "\t.section __DATA, __objc_imageinfo.*\n\t.align.*\nL_OBJC_ImageInfo.*:\n\t.long\t0\n\t.long\t17" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/objc.dg/lookup-1.m b/gcc/testsuite/objc.dg/lookup-1.m index ff59b7e..737d58a 100644 --- a/gcc/testsuite/objc.dg/lookup-1.m +++ b/gcc/testsuite/objc.dg/lookup-1.m @@ -1,5 +1,6 @@ /* { dg-do run } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-sources "../objc-obj-c++-shared/Object1.m" } */ #include <stdlib.h> #include "../objc-obj-c++-shared/Object1.h" @@ -53,5 +54,3 @@ int main(void) { return 0; } - -#include "../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/method-4.m b/gcc/testsuite/objc.dg/method-4.m index c5fa1a0..df25bba 100644 --- a/gcc/testsuite/objc.dg/method-4.m +++ b/gcc/testsuite/objc.dg/method-4.m @@ -22,5 +22,5 @@ void foo(void) { obj = [ObjectAlias2 new]; } -/* { dg-final { scan-assembler "_OBJC_CLASS_REFERENCES_0" } } */ -/* { dg-final { scan-assembler-not "_OBJC_CLASS_REFERENCES_1" } } */ +/* { dg-final { scan-assembler "_OBJC_ClassRefs_0" } } */ +/* { dg-final { scan-assembler-not "_OBJC_ClassRefs_1" } } */ diff --git a/gcc/testsuite/objc.dg/next-runtime-1.m b/gcc/testsuite/objc.dg/next-runtime-1.m index 9a0951c..c76b616 100644 --- a/gcc/testsuite/objc.dg/next-runtime-1.m +++ b/gcc/testsuite/objc.dg/next-runtime-1.m @@ -1,13 +1,14 @@ /* Test that the correct version number (6) is set in the module descriptor - when compiling for the NeXT runtime. */ -/* Author: Ziemowit Laski <zlaski@apple.com> */ + when compiling for the NeXT runtime ABI=0 - and that the MODULE descriptor + is not emitted at all for ABI 2. */ +/* modified from a testcase added by: Ziemowit Laski <zlaski@apple.com> */ /* { dg-do compile { target *-*-darwin* } } */ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-skip-if "" { *-*-* } { "-fobjc-abi-version=1" } { "" } } */ +/* { dg-options "-fobjc-abi-version=0" { target { *-*-darwin* && { ! lp64 } } } } */ -#include "../objc-obj-c++-shared/Object1.h" - -@interface FooBar: Object +@interface FooBar - (void)boo; @end @@ -15,5 +16,5 @@ - (void)boo { } @end -/* { dg-final { scan-assembler "L_OBJC_MODULES:\n\[ \t\]*\.long\t6\n" { target { *-*-darwin* && { ! lp64 } } } } } */ -/* { dg-final { scan-assembler "L_OBJC_MODULES:\n\[ \t\]*\.quad\t6\n" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler "L_OBJC_Module:\n\[ \t\]*\.long\t6\n" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler-not "L_OBJC_Module" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/objc.dg/pr23214.m b/gcc/testsuite/objc.dg/pr23214.m index 8443c94..d8092a8 100644 --- a/gcc/testsuite/objc.dg/pr23214.m +++ b/gcc/testsuite/objc.dg/pr23214.m @@ -3,10 +3,19 @@ /* { dg-do run } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ -/* { dg-additional-sources "../objc-obj-c++-shared/Object1.m" } */ -#import "../objc-obj-c++-shared/Object1.h" -#import "../objc-obj-c++-shared/Protocol1.h" +#include <objc/Protocol.h> + +#ifdef __OBJC2__ +/* The ObjC V2 "Object" does not provide -class. */ +@interface Object (TS_CAT) +- class; +@end + +@implementation Object (TS_CAT) +- class { return isa; } +@end +#endif @protocol A @end diff --git a/gcc/testsuite/objc.dg/special/unclaimed-category-1.h b/gcc/testsuite/objc.dg/special/unclaimed-category-1.h index 0453033..bf507a7 100644 --- a/gcc/testsuite/objc.dg/special/unclaimed-category-1.h +++ b/gcc/testsuite/objc.dg/special/unclaimed-category-1.h @@ -5,7 +5,11 @@ @interface TestClass { +#ifdef __OBJC2__ + Class isa; +#else id isa; +#endif } - (int)D; @end diff --git a/gcc/testsuite/objc.dg/special/unclaimed-category-1.m b/gcc/testsuite/objc.dg/special/unclaimed-category-1.m index 472ad8b..88e3d8e 100644 --- a/gcc/testsuite/objc.dg/special/unclaimed-category-1.m +++ b/gcc/testsuite/objc.dg/special/unclaimed-category-1.m @@ -2,11 +2,11 @@ /* { dg-do run } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ -#import "../../objc-obj-c++-shared/next-mapping.h" #include <objc/objc.h> #ifndef __NEXT_RUNTIME__ #include <objc/objc-api.h> #endif +#include "../../objc-obj-c++-shared/next-mapping.h" extern void abort (void); @@ -73,5 +73,3 @@ int main (void) return 0; } - -#import "../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc.dg/symtab-1.m b/gcc/testsuite/objc.dg/symtab-1.m index 100b245..936f8d4 100644 --- a/gcc/testsuite/objc.dg/symtab-1.m +++ b/gcc/testsuite/objc.dg/symtab-1.m @@ -4,7 +4,7 @@ /* { dg-do compile { target { *-*-darwin* } } } */ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ -#include "../objc-obj-c++-shared/Object1.h" +#include <objc/Object.h> @interface Base: Object - (void)setValues; @@ -22,7 +22,6 @@ -(void)checkValues { } @end -/* { dg-final { scan-assembler "L_OBJC_SYMBOLS.*:\n\t.long\t0\n\t.long\t0\n\t.word\t2\n\t.word\t0\n\t.long\tL_OBJC_CLASS_Derived.*\n\t.long\tL_OBJC_CLASS_Base.*\n" { target { *86*-*-darwin* && { ! lp64 } } } } } */ -/* { dg-final { scan-assembler "L_OBJC_SYMBOLS.*:\n\t.long\t0\n\t.long\t0\n\t.short\t2\n\t.short\t0\n\t.long\tL_OBJC_CLASS_Derived.*\n\t.long\tL_OBJC_CLASS_Base.*\n" { target { powerpc*-*-darwin* && { ! lp64 } } } } } */ -/* { dg-final { scan-assembler "L_OBJC_SYMBOLS.*:\n\t.quad\t0\n\t.quad\t0\n\t.word\t2\n\t.word\t0\n\t.space 4\n\t.quad\tL_OBJC_CLASS_Derived.*\n\t.quad\tL_OBJC_CLASS_Base.*\n" { target { *86*-*-darwin* && { lp64 } } } } } */ -/* { dg-final { scan-assembler "L_OBJC_SYMBOLS.*:\n\t.quad\t0\n\t.quad\t0\n\t.short\t2\n\t.short\t0\n\t.space 4\n\t.quad\tL_OBJC_CLASS_Derived.*\n\t.quad\tL_OBJC_CLASS_Base.*\n" { target { powerpc*-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler "L_OBJC_Symbols.*:\n\t.long\t0\n\t.long\t0\n\t.word\t2\n\t.word\t0\n\t.long\tL_OBJC_Class_Derived.*\n\t.long\tL_OBJC_Class_Base.*\n" { target { *86*-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler "L_OBJC_Symbols.*:\n\t.long\t0\n\t.long\t0\n\t.short\t2\n\t.short\t0\n\t.long\tL_OBJC_Class_Derived.*\n\t.long\tL_OBJC_Class_Base.*\n" { target { powerpc*-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler-not "L_OBJC_Symbols" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/objc.dg/torture/forward-1.m b/gcc/testsuite/objc.dg/torture/forward-1.m index 518bf27..bccf4a1 100644 --- a/gcc/testsuite/objc.dg/torture/forward-1.m +++ b/gcc/testsuite/objc.dg/torture/forward-1.m @@ -1,14 +1,18 @@ /* { dg-do run } */ /* See if -forward::/-performv:: is able to work. */ /* { dg-xfail-run-if "PR36610" { ! { { i?86-*-* x86_64-*-* } && ilp32 } } { "-fgnu-runtime" } { "" } } */ -/* { dg-skip-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-skip-if "Needs OBJC2 Implementation" { *-*-darwin* && { lp64 } } { "-fnext-runtime" } { "" } } */ +/* There is no implementation of forward: in the NeXT m64 libobjc/Object + neither have we implemented this in our extensions - so we have to skip it + for now. */ #include <stdio.h> #include <stdlib.h> -#import "../../objc-obj-c++-shared/Object1.h" -#import "../../objc-obj-c++-shared/next-mapping.h" -#include <objc/objc-api.h> +#ifndef __NEXT_RUNTIME__ +# include <objc/objc-api.h> +#endif +#include <objc/Object.h> #define VALUETOUSE 1234567890 diff --git a/gcc/testsuite/objc.dg/torture/strings/const-str-10.m b/gcc/testsuite/objc.dg/torture/strings/const-str-10.m index c170f38..f0f2823 100644 --- a/gcc/testsuite/objc.dg/torture/strings/const-str-10.m +++ b/gcc/testsuite/objc.dg/torture/strings/const-str-10.m @@ -29,6 +29,7 @@ extern Class _NSConstantStringClassReference; const NSConstantString *appKey = @"MyApp"; -/* { dg-final { scan-assembler ".section __OBJC, __cstring_object" } } */ +/* { dg-final { scan-assembler ".section __OBJC, __cstring_object" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler ".section __DATA, __objc_stringobj" { target { *-*-darwin* && { lp64 } } } } } */ /* { dg-final { scan-assembler ".long\t__NSConstantStringClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ -/* { dg-final { scan-assembler ".quad\t__NSConstantStringClassReference\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler ".quad\t_OBJC_CLASS_._NSConstantString\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/objc.dg/torture/strings/const-str-11.m b/gcc/testsuite/objc.dg/torture/strings/const-str-11.m index 9f3705e..fa9dbd9 100644 --- a/gcc/testsuite/objc.dg/torture/strings/const-str-11.m +++ b/gcc/testsuite/objc.dg/torture/strings/const-str-11.m @@ -29,6 +29,7 @@ extern Class _XStrClassReference; const XStr *appKey = @"MyApp"; -/* { dg-final { scan-assembler ".section __OBJC, __cstring_object" } } */ +/* { dg-final { scan-assembler ".section __OBJC, __cstring_object" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler ".section __DATA, __objc_stringobj" { target { *-*-darwin* && { lp64 } } } } } */ /* { dg-final { scan-assembler ".long\t__XStrClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ -/* { dg-final { scan-assembler ".quad\t__XStrClassReference\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler ".quad\t_OBJC_CLASS_._XStr\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/objc.dg/torture/strings/const-str-9.m b/gcc/testsuite/objc.dg/torture/strings/const-str-9.m index ddbe93d..39bd102 100644 --- a/gcc/testsuite/objc.dg/torture/strings/const-str-9.m +++ b/gcc/testsuite/objc.dg/torture/strings/const-str-9.m @@ -21,6 +21,7 @@ Class _NSConstantStringClassReference; const NSConstantString *appKey = @"MyApp"; -/* { dg-final { scan-assembler ".section __OBJC, __cstring_object" } } */ +/* { dg-final { scan-assembler ".section __OBJC, __cstring_object" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler ".section __DATA, __objc_stringobj" { target { *-*-darwin* && { lp64 } } } } } */ /* { dg-final { scan-assembler ".long\t__NSConstantStringClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ -/* { dg-final { scan-assembler ".quad\t__NSConstantStringClassReference\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ +/* { dg-final { scan-assembler ".quad\t_OBJC_CLASS_._NSConstantString\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ diff --git a/gcc/testsuite/objc.dg/zero-link-1.m b/gcc/testsuite/objc.dg/zero-link-1.m index 35cabfa..c040031 100644 --- a/gcc/testsuite/objc.dg/zero-link-1.m +++ b/gcc/testsuite/objc.dg/zero-link-1.m @@ -25,6 +25,7 @@ int main(void) { return 0; } -/* { dg-final { scan-assembler-not "_OBJC_CLASS_REFERENCES_0" } } */ +/* { dg-final { scan-assembler-not "_OBJC_ClassRefs_0" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler-not "_OBJC_ClassRef_Base" { target { *-*-darwin* && { lp64 } } } } } */ /* { dg-final { scan-assembler "objc_getClass" } } */ diff --git a/gcc/testsuite/objc.dg/zero-link-2.m b/gcc/testsuite/objc.dg/zero-link-2.m index 443090a..ff82e5e 100644 --- a/gcc/testsuite/objc.dg/zero-link-2.m +++ b/gcc/testsuite/objc.dg/zero-link-2.m @@ -5,8 +5,7 @@ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ /* { dg-options "-fno-zero-link" } */ -#include "../objc-obj-c++-shared/Object1.h" -#include <objc/objc.h> +#include <objc/Object.h> extern void abort(void); #define CHECK_IF(expr) if(!(expr)) abort(); @@ -25,5 +24,6 @@ int main(void) { return 0; } -/* { dg-final { scan-assembler "_OBJC_CLASS_REFERENCES_0" } } */ +/* { dg-final { scan-assembler "_OBJC_ClassRefs_0" { target { *-*-darwin* && { ! lp64 } } } } } */ +/* { dg-final { scan-assembler "_OBJC_ClassRef_Base" { target { *-*-darwin* && { lp64 } } } } } */ /* { dg-final { scan-assembler-not "objc_getClass" } } */ diff --git a/gcc/testsuite/objc/execute/accessing_ivars.m b/gcc/testsuite/objc/execute/accessing_ivars.m index dbde8cd..e4c9cf4 100644 --- a/gcc/testsuite/objc/execute/accessing_ivars.m +++ b/gcc/testsuite/objc/execute/accessing_ivars.m @@ -1,7 +1,9 @@ /* Contributed by Nicola Pero - Thu Mar 8 16:27:46 CET 2001 */ #include <stdlib.h> -#import "../../objc-obj-c++-shared/Object1.h" +#ifndef __NEXT_RUNTIME__ #include <objc/objc-api.h> +#endif +#include "../../objc-obj-c++-shared/Object1.h" /* Test that by using -> we can access ivars of other objects of the same class */ @@ -53,3 +55,4 @@ int main (void) return 0; } +#include "../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc/execute/bf-common.h b/gcc/testsuite/objc/execute/bf-common.h index c79c3ef..ca70c21 100644 --- a/gcc/testsuite/objc/execute/bf-common.h +++ b/gcc/testsuite/objc/execute/bf-common.h @@ -11,6 +11,7 @@ #define objc_get_class(C) objc_getClass(C) #endif +#ifndef __OBJC2__ void print_ivars (Class class) { struct objc_ivar_list* ivars = class->ivars; @@ -61,9 +62,11 @@ void compare_structures (Class class, const char* type) printf ("%d ivars checked\n", i); } +#endif int main () { +#ifndef __OBJC2__ struct class_vars { @defs (MyObject); @@ -80,8 +83,10 @@ int main () printf ("sizes don't match (computed %d, exact %d)\n", size1, size2); abort (); } +#endif exit (0); } - +#ifndef __OBJC2__ #include "../../objc-obj-c++-shared/objc-test-suite-next-encode-assist-impl.h" +#endif diff --git a/gcc/testsuite/objc/execute/bycopy-2.m b/gcc/testsuite/objc/execute/bycopy-2.m index 8e7f169..840881f 100644 --- a/gcc/testsuite/objc/execute/bycopy-2.m +++ b/gcc/testsuite/objc/execute/bycopy-2.m @@ -27,5 +27,4 @@ int main (void) exit (0); } - - +#include "../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc/execute/bycopy-3.m b/gcc/testsuite/objc/execute/bycopy-3.m index 4c2bd27..15c49a5 100644 --- a/gcc/testsuite/objc/execute/bycopy-3.m +++ b/gcc/testsuite/objc/execute/bycopy-3.m @@ -24,6 +24,12 @@ extern int printf (const char *, ...); /* This no-op class to keep it compile under broken gcc 3.x */ @interface MyObject : Object <MyProtocol> +#ifdef __OBJC2__ ++ (id) initialize; ++ (id) alloc; ++ new; +- init; +#endif @end @implementation MyObject @@ -31,6 +37,12 @@ extern int printf (const char *, ...); { return [MyObject alloc]; } +#ifdef __OBJC2__ ++ initialize {return self;} ++ alloc { return class_createInstance (self, 0);} ++ new { return [[self alloc] init]; } +- init {return self;} +#endif @end /* The following header, together with the implementation included below, diff --git a/gcc/testsuite/objc/execute/class-tests-1.h b/gcc/testsuite/objc/execute/class-tests-1.h index ebc49b6..54a77d2 100644 --- a/gcc/testsuite/objc/execute/class-tests-1.h +++ b/gcc/testsuite/objc/execute/class-tests-1.h @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero on Tue Mar 6 23:05:53 CET 2001 */ +#include <stdio.h> #include <stdlib.h> #include "../../objc-obj-c++-shared/Object1.h" #include <objc/objc.h> diff --git a/gcc/testsuite/objc/execute/class-tests-2.h b/gcc/testsuite/objc/execute/class-tests-2.h index cc14abb..1aa7394 100644 --- a/gcc/testsuite/objc/execute/class-tests-2.h +++ b/gcc/testsuite/objc/execute/class-tests-2.h @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero on Tue Mar 6 23:05:53 CET 2001 */ #include <objc/objc.h> #include <objc/objc-api.h> +#include <stdio.h> #include <stdlib.h> /* diff --git a/gcc/testsuite/objc/execute/compatibility_alias.m b/gcc/testsuite/objc/execute/compatibility_alias.m index b134f0c..61d7625 100644 --- a/gcc/testsuite/objc/execute/compatibility_alias.m +++ b/gcc/testsuite/objc/execute/compatibility_alias.m @@ -10,3 +10,4 @@ int main (void) return 0; } +#include "../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc/execute/enumeration-1.m b/gcc/testsuite/objc/execute/enumeration-1.m index 1adcfd0..57d1a4b 100644 --- a/gcc/testsuite/objc/execute/enumeration-1.m +++ b/gcc/testsuite/objc/execute/enumeration-1.m @@ -48,3 +48,4 @@ int main (void) return 0; } +#include "../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc/execute/enumeration-2.m b/gcc/testsuite/objc/execute/enumeration-2.m index c47bb8a..3094963 100644 --- a/gcc/testsuite/objc/execute/enumeration-2.m +++ b/gcc/testsuite/objc/execute/enumeration-2.m @@ -50,3 +50,4 @@ int main (void) return 0; } +#include "../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc/execute/exceptions/catchall-1.m b/gcc/testsuite/objc/execute/exceptions/catchall-1.m index 01eff92..2db40a8 100644 --- a/gcc/testsuite/objc/execute/exceptions/catchall-1.m +++ b/gcc/testsuite/objc/execute/exceptions/catchall-1.m @@ -74,3 +74,4 @@ int main (void) { test((Object *)-1); return 0; } +#import "../../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc/execute/exceptions/exceptions.exp b/gcc/testsuite/objc/execute/exceptions/exceptions.exp index 173f656..0443ca1 100644 --- a/gcc/testsuite/objc/execute/exceptions/exceptions.exp +++ b/gcc/testsuite/objc/execute/exceptions/exceptions.exp @@ -28,6 +28,7 @@ lappend additional_flags "-fobjc-exceptions" # load support procs load_lib objc-torture.exp load_lib torture-options.exp +load_lib target-supports.exp torture-init objc-set-runtime-options "execute" "additional_flags=-fobjc-exceptions" diff --git a/gcc/testsuite/objc/execute/exceptions/finally-1.m b/gcc/testsuite/objc/execute/exceptions/finally-1.m index 5206c77..370b19b 100644 --- a/gcc/testsuite/objc/execute/exceptions/finally-1.m +++ b/gcc/testsuite/objc/execute/exceptions/finally-1.m @@ -1,6 +1,22 @@ #include <stdio.h> #include <stdlib.h> +//#import "../../../objc-obj-c++-shared/Object1.h" +#ifdef __OBJC2__ +#include <objc/runtime.h> +@interface Object ++ initialize; ++ new; +- free; +@end +@implementation Object ++ initialize { return self; } ++ new { return class_createInstance (self, 0); } +- free { return object_dispose(self);} +@end + +#else #import "../../../objc-obj-c++-shared/Object1.h" +#endif static int made_try = 0; @@ -57,3 +73,4 @@ main(int ac, char *av[]) abort (); return 0; } +//#import "../../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc/execute/exceptions/foward-1.m b/gcc/testsuite/objc/execute/exceptions/foward-1.m index ae5d927..6b31d7c 100644 --- a/gcc/testsuite/objc/execute/exceptions/foward-1.m +++ b/gcc/testsuite/objc/execute/exceptions/foward-1.m @@ -2,12 +2,33 @@ /* Developed by Marcin Koziej <creep@desk.pl>. */ #include <stdlib.h> -#import "../../../objc-obj-c++-shared/Object1.h" +#include <objc/Object.h> +#ifndef __NEXT_RUNTIME__ #import <objc/objc-api.h> +#endif + +#ifdef __OBJC2__ +@interface Object (TEST_SUITE_ADDITIONS) ++ initialize; ++ alloc; ++ new; +- init; +- free; +@end + +@implementation Object (TEST_SUITE_ADDITIONS) ++ initialize { return self; } ++ alloc { return class_createInstance (self, 0); } ++ new { return [[self alloc] init]; } +- init { return self; } +- free { return object_dispose(self); } +@end +#endif static int i; -@interface Thrower : Object +__attribute__((objc_exception)) +@interface Thrower : Object - forward: (SEL) s : (void*) a; @end @@ -16,8 +37,10 @@ static int i; { i++; @throw [Object new]; + return nil; } @end + int main() { diff --git a/gcc/testsuite/objc/execute/exceptions/local-variables-1.m b/gcc/testsuite/objc/execute/exceptions/local-variables-1.m index fa419f9..0488d79 100644 --- a/gcc/testsuite/objc/execute/exceptions/local-variables-1.m +++ b/gcc/testsuite/objc/execute/exceptions/local-variables-1.m @@ -60,3 +60,4 @@ int main(void) { foo(15, &gf1); return 0; } +#import "../../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc/execute/formal_protocol-1.m b/gcc/testsuite/objc/execute/formal_protocol-1.m index a62def3..6514449 100644 --- a/gcc/testsuite/objc/execute/formal_protocol-1.m +++ b/gcc/testsuite/objc/execute/formal_protocol-1.m @@ -42,4 +42,4 @@ int main (void) return 0; } - +#include "../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc/execute/formal_protocol-2.m b/gcc/testsuite/objc/execute/formal_protocol-2.m index a0f7eec..b830cd9 100644 --- a/gcc/testsuite/objc/execute/formal_protocol-2.m +++ b/gcc/testsuite/objc/execute/formal_protocol-2.m @@ -43,4 +43,4 @@ int main (void) return 0; } - +#include "../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc/execute/formal_protocol-3.m b/gcc/testsuite/objc/execute/formal_protocol-3.m index c55773a..f28c95f 100644 --- a/gcc/testsuite/objc/execute/formal_protocol-3.m +++ b/gcc/testsuite/objc/execute/formal_protocol-3.m @@ -56,4 +56,4 @@ int main (void) return 0; } - +#include "../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc/execute/formal_protocol-4.m b/gcc/testsuite/objc/execute/formal_protocol-4.m index 92f0521..10aba89 100644 --- a/gcc/testsuite/objc/execute/formal_protocol-4.m +++ b/gcc/testsuite/objc/execute/formal_protocol-4.m @@ -38,4 +38,4 @@ int main (void) return 0; } - +#include "../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc/execute/formal_protocol-5.m b/gcc/testsuite/objc/execute/formal_protocol-5.m index 8bb63ec..c3bd53d 100644 --- a/gcc/testsuite/objc/execute/formal_protocol-5.m +++ b/gcc/testsuite/objc/execute/formal_protocol-5.m @@ -1,7 +1,8 @@ /* Contributed by Nicola Pero - Fri Mar 9 21:35:47 CET 2001 */ #include <stdlib.h> -#include "../../objc-obj-c++-shared/Protocol1.h" +#include <objc/Protocol.h> +#include "../../objc-obj-c++-shared/next-mapping.h" /* Test defining a protocol, and accessing it using @protocol */ @@ -35,4 +36,3 @@ int main (void) return 0; } - diff --git a/gcc/testsuite/objc/execute/formal_protocol-6.m b/gcc/testsuite/objc/execute/formal_protocol-6.m index dd42b37..b02fc1e 100644 --- a/gcc/testsuite/objc/execute/formal_protocol-6.m +++ b/gcc/testsuite/objc/execute/formal_protocol-6.m @@ -1,7 +1,8 @@ /* Contributed by Nicola Pero - Fri Mar 9 21:35:47 CET 2001 */ #include <stdlib.h> -#include "../../objc-obj-c++-shared/Protocol1.h" +#include <objc/Protocol.h> +#include "../../objc-obj-c++-shared/next-mapping.h" /* Test defining a protocol, and accessing it using @protocol */ diff --git a/gcc/testsuite/objc/execute/formal_protocol-7.m b/gcc/testsuite/objc/execute/formal_protocol-7.m index c4e1850..d15013a 100644 --- a/gcc/testsuite/objc/execute/formal_protocol-7.m +++ b/gcc/testsuite/objc/execute/formal_protocol-7.m @@ -41,4 +41,4 @@ int main (void) return 0; } - +#include "../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc/execute/no_clash.m b/gcc/testsuite/objc/execute/no_clash.m index 9cb004d..d4ab4cb 100644 --- a/gcc/testsuite/objc/execute/no_clash.m +++ b/gcc/testsuite/objc/execute/no_clash.m @@ -39,3 +39,4 @@ int main (void) return 0; } +#include "../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc/execute/object_is_class.m b/gcc/testsuite/objc/execute/object_is_class.m index 199517e..14a7f52 100644 --- a/gcc/testsuite/objc/execute/object_is_class.m +++ b/gcc/testsuite/objc/execute/object_is_class.m @@ -1,8 +1,10 @@ /* Contributed by Nicola Pero - Tue Jul 3 10:55:21 BST 2001 */ -#import "../../objc-obj-c++-shared/next-mapping.h" -#import "../../objc-obj-c++-shared/Object1.h" -#include <objc/objc.h> -#include <objc/objc-api.h> +#ifdef __NEXT_RUNTIME__ +# include "../../objc-obj-c++-shared/next-mapping.h" +#else +# include <objc/objc-api.h> +#endif +#include "../../objc-obj-c++-shared/Object1.h" /* This test demonstrate a failure in object_is_class which was fixed */ @@ -41,3 +43,4 @@ int main (void) return 0; } +#include "../../objc-obj-c++-shared/Object1-implementation.h" diff --git a/gcc/testsuite/objc/execute/object_is_meta_class.m b/gcc/testsuite/objc/execute/object_is_meta_class.m index d5aedca..91a628e 100644 --- a/gcc/testsuite/objc/execute/object_is_meta_class.m +++ b/gcc/testsuite/objc/execute/object_is_meta_class.m @@ -1,7 +1,10 @@ /* Contributed by Nicola Pero - Tue Jul 3 10:55:21 BST 2001 */ -#import "../../objc-obj-c++-shared/Object1.h" -#import "../../objc-obj-c++-shared/next-mapping.h" -#include <objc/objc-api.h> +#ifdef __NEXT_RUNTIME__ +# include "../../objc-obj-c++-shared/next-mapping.h" +#else +# include <objc/objc-api.h> +#endif +#include "../../objc-obj-c++-shared/Object1.h" /* This test demonstrate a failure in object_is_meta_class which was fixed */ @@ -38,4 +41,4 @@ int main (void) return 0; } - +#include "../../objc-obj-c++-shared/Object1-implementation.h" |