From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- gcc/objc/objc-next-runtime-abi-02.c | 3778 +++++++++++++++++++++++++++++++++++ 1 file changed, 3778 insertions(+) create mode 100644 gcc/objc/objc-next-runtime-abi-02.c (limited to 'gcc/objc/objc-next-runtime-abi-02.c') 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 000000000..3de0d05bf --- /dev/null +++ b/gcc/objc/objc-next-runtime-abi-02.c @@ -0,0 +1,3778 @@ +/* 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 +. */ + +/* The NeXT ABI2 is used for m64 implementations on Darwin/OSX machines. + + This version is intended to match (logically) the output of Apple's + 4.2.1 compiler. */ + +#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 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_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 and 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 always + explicitly declare the alignment padding. */ + /* 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 ;" + 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. */ +/* PS/TODO: The field name does not matter, it is only used internally + by the compiler. We can rename it to whatever we want. ;-) */ + +static tree +next_runtime_abi_02_super_superclassfield_id (void) +{ + /* TODO: Simplify. Just always return get_identifier ("cls"), or at + most look it once at startup then always return it. */ + 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_; */ + 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 ). */ + 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 the + 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 super 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_; */ + 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 reference... 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_$_ = { ... }; */ + +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 always + explicitly declare the alignment padding. */ + /* 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 a meta class, "isa" is + a reference to the 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_$_ + 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_$_... */ + 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_$_. */ + 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; + + /* FIXME: Make sure that we generate no metadata if there is nothing + to put into it. */ + + 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_. */ + 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); + /* FIXME: location. */ + 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, meaning @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" -- cgit v1.2.3