diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /gcc/objc/objc-gnu-runtime-abi-01.c | |
download | cbb-gcc-4.6.4-15d2061ac0796199866debe9ac87130894b0cdd3.tar.bz2 cbb-gcc-4.6.4-15d2061ac0796199866debe9ac87130894b0cdd3.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
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.
Diffstat (limited to 'gcc/objc/objc-gnu-runtime-abi-01.c')
-rw-r--r-- | gcc/objc/objc-gnu-runtime-abi-01.c | 2269 |
1 files changed, 2269 insertions, 0 deletions
diff --git a/gcc/objc/objc-gnu-runtime-abi-01.c b/gcc/objc/objc-gnu-runtime-abi-01.c new file mode 100644 index 000000000..7fb87611d --- /dev/null +++ b/gcc/objc/objc-gnu-runtime-abi-01.c @@ -0,0 +1,2269 @@ +/* GNU Runtime ABI version 8 + Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by Iain Sandoe (split from objc-act.c) + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" + +#ifdef OBJCPLUS +#include "cp-tree.h" +#else +#include "c-tree.h" +#include "c-lang.h" +#endif + +#include "langhooks.h" +#include "c-family/c-objc.h" +#include "objc-act.h" + +/* When building Objective-C++, we are not linking against the C front-end + and so need to replicate the C tree-construction functions in some way. */ +#ifdef OBJCPLUS +#define OBJCP_REMAP_FUNCTIONS +#include "objcp-decl.h" +#endif /* OBJCPLUS */ + +#include "toplev.h" +#include "ggc.h" +#include "tree-iterator.h" + +#include "objc-runtime-hooks.h" +#include "objc-runtime-shared-support.h" + +/* GNU runtime private definitions. */ +#define DEF_CONSTANT_STRING_CLASS_NAME "NXConstantString" + +#define TAG_GETCLASS "objc_get_class" +#define TAG_GETMETACLASS "objc_get_meta_class" + +#define TAG_MSGSEND "objc_msg_lookup" +#define TAG_MSGSENDSUPER "objc_msg_lookup_super" + +/* GNU-specific tags. */ + +#define TAG_EXECCLASS "__objc_exec_class" +#define TAG_GNUINIT "__objc_gnu_init" + +/* The version identifies which language generation and runtime + the module (file) was compiled for, and is recorded in the + module descriptor. */ +#define OBJC_VERSION 8 + +#define PROTOCOL_VERSION 2 + +/* This macro provides a method of removing ambiguity between runtimes + when LTO is in use on targets supporting multiple runtimes. + + For example, at present, any target that includes an implementation of + the NeXT runtime needs to place Objective-C meta-data into specific + named sections. This should _not_ be done for the GNU runtime, and the + folowing macro is used to attach Objective-C private attributes that may + be used to identify the runtime for which the meta-data are intended. */ + +#define OBJCMETA(DECL,VERS,KIND) \ + if (VERS) \ + DECL_ATTRIBUTES (DECL) = build_tree_list ((VERS), (KIND)); + +static void gnu_runtime_01_initialize (void); + +static void build_selector_template (void); + +static tree gnu_runtime_abi_01_super_superclassfield_id (void); + +static tree gnu_runtime_abi_01_class_decl (tree); +static tree gnu_runtime_abi_01_metaclass_decl (tree); +static tree gnu_runtime_abi_01_category_decl (tree); +static tree gnu_runtime_abi_01_protocol_decl (tree); +static tree gnu_runtime_abi_01_string_decl (tree, const char *, string_section); + +static tree gnu_runtime_abi_01_get_class_reference (tree); +static tree gnu_runtime_abi_01_build_typed_selector_reference (location_t, tree, + tree); +static tree gnu_runtime_abi_01_get_protocol_reference (location_t, tree); +static tree gnu_runtime_abi_01_build_ivar_ref (location_t, tree, tree); +static tree gnu_runtime_abi_01_get_class_super_ref (location_t, struct imp_entry *, bool); +static tree gnu_runtime_abi_01_get_category_super_ref (location_t, struct imp_entry *, bool); + +static tree gnu_runtime_abi_01_receiver_is_class_object (tree); +static tree gnu_runtime_abi_01_get_arg_type_list_base (tree, int, int); +static tree gnu_runtime_abi_01_build_objc_method_call (location_t, tree, tree, + tree, tree, tree, int); + +static bool gnu_runtime_abi_01_setup_const_string_class_decl (void); +static tree gnu_runtime_abi_01_build_const_string_constructor (location_t, tree,int); + +static void objc_generate_v1_gnu_metadata (void); + +static tree objc_eh_runtime_type (tree type); +static tree objc_eh_personality (void); +static tree objc_build_exc_ptr (struct objc_try_context **); +static tree build_throw_stmt (location_t, tree, bool); +static tree begin_catch (struct objc_try_context **, tree, tree, tree, bool); +static void finish_catch (struct objc_try_context **, tree); +static tree finish_try_stmt (struct objc_try_context **); + +bool +objc_gnu_runtime_abi_01_init (objc_runtime_hooks *rthooks) +{ + /* GNU runtime does not need the compiler to change code in order to do GC. */ + if (flag_objc_gc) + { + warning_at (0, 0, "%<-fobjc-gc%> is ignored for %<-fgnu-runtime%>"); + flag_objc_gc = 0; + } + + /* Although I guess we could, we don't currently support SJLJ exceptions for the + GNU runtime. */ + if (flag_objc_sjlj_exceptions) + { + inform (UNKNOWN_LOCATION, "%<-fobjc-sjlj-exceptions%> is ignored for %<-fgnu-runtime%>"); + flag_objc_sjlj_exceptions = 0; + } + + /* TODO: Complain if -fobjc-abi-version=N was used. */ + + /* TODO: Complain if -fobj-nilcheck was used. */ + + rthooks->initialize = gnu_runtime_01_initialize; + rthooks->default_constant_string_class_name = DEF_CONSTANT_STRING_CLASS_NAME; + rthooks->tag_getclass = TAG_GETCLASS; + rthooks->super_superclassfield_ident = gnu_runtime_abi_01_super_superclassfield_id; + + rthooks->class_decl = gnu_runtime_abi_01_class_decl; + rthooks->metaclass_decl = gnu_runtime_abi_01_metaclass_decl; + rthooks->category_decl = gnu_runtime_abi_01_category_decl; + rthooks->protocol_decl = gnu_runtime_abi_01_protocol_decl; + rthooks->string_decl = gnu_runtime_abi_01_string_decl; + + rthooks->get_class_reference = gnu_runtime_abi_01_get_class_reference; + rthooks->build_selector_reference = gnu_runtime_abi_01_build_typed_selector_reference; + rthooks->get_protocol_reference = gnu_runtime_abi_01_get_protocol_reference; + rthooks->build_ivar_reference = gnu_runtime_abi_01_build_ivar_ref; + rthooks->get_class_super_ref = gnu_runtime_abi_01_get_class_super_ref; + rthooks->get_category_super_ref = gnu_runtime_abi_01_get_category_super_ref; + + rthooks->receiver_is_class_object = gnu_runtime_abi_01_receiver_is_class_object; + rthooks->get_arg_type_list_base = gnu_runtime_abi_01_get_arg_type_list_base; + rthooks->build_objc_method_call = gnu_runtime_abi_01_build_objc_method_call; + + rthooks->setup_const_string_class_decl = + gnu_runtime_abi_01_setup_const_string_class_decl; + rthooks->build_const_string_constructor = + gnu_runtime_abi_01_build_const_string_constructor; + + rthooks->build_throw_stmt = build_throw_stmt; + rthooks->build_exc_ptr = objc_build_exc_ptr; + rthooks->begin_catch = begin_catch; + rthooks->finish_catch = finish_catch; + rthooks->finish_try_stmt = finish_try_stmt; + + rthooks->generate_metadata = objc_generate_v1_gnu_metadata; + return true; +} + +static void build_selector_table_decl (void); +static void build_class_template (void); +static void build_category_template (void); +static void build_protocol_template (void); + +static GTY(()) tree objc_meta; +static GTY(()) tree meta_base; + +static void gnu_runtime_01_initialize (void) +{ + tree type, ftype, IMP_type; + + /* We do not need to mark GNU ObjC metadata for different sections, + however, we do need to make sure that it is not mistaken for NeXT + metadata. */ + objc_meta = get_identifier ("OBJC1METG"); + meta_base = get_identifier ("NONE"); + + /* Declare type of selector-objects that represent an operation name. */ + /* `const struct objc_selector *' */ + type = xref_tag (RECORD_TYPE, get_identifier (TAG_SELECTOR)); + type = build_qualified_type (type, TYPE_QUAL_CONST); + objc_selector_type = build_pointer_type (type); + + /* typedef id (*IMP)(id, SEL, ...); */ + ftype = build_varargs_function_type_list (objc_object_type, + objc_object_type, + objc_selector_type, + NULL_TREE); + + IMP_type = build_pointer_type (ftype); + + build_class_template (); + build_super_template (); + build_protocol_template (); + build_category_template (); + + /* GNU runtime messenger entry points. */ + /* TREE_NOTHROW is cleared for the message-sending functions, + because the function that gets called can throw in Obj-C++, or + could itself call something that can throw even in Obj-C. */ + + /* IMP objc_msg_lookup (id, SEL); */ + type = build_function_type_list (IMP_type, + objc_object_type, + objc_selector_type, + NULL_TREE); + + umsg_decl = add_builtin_function (TAG_MSGSEND, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (umsg_decl) = 0; + + /* IMP objc_msg_lookup_super (struct objc_super *, SEL); */ + type = build_function_type_list (IMP_type, + objc_super_type, + objc_selector_type, + NULL_TREE); + + umsg_super_decl = add_builtin_function (TAG_MSGSENDSUPER, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (umsg_super_decl) = 0; + + /* The following GNU runtime entry point is called to initialize + each module: + + __objc_exec_class (void *); */ + type = build_function_type_list (void_type_node, + ptr_type_node, + NULL_TREE); + + execclass_decl = add_builtin_function (TAG_EXECCLASS, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + type = build_function_type_list (objc_object_type, + const_string_type_node, + NULL_TREE); + + /* id objc_getClass (const char *); */ + objc_get_class_decl + = add_builtin_function (TAG_GETCLASS, type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + /* id objc_getMetaClass (const char *); */ + objc_get_meta_class_decl = add_builtin_function (TAG_GETMETACLASS, type, + 0, NOT_BUILT_IN, NULL, + NULL_TREE); + + /* static SEL _OBJC_SELECTOR_TABLE[]; */ + build_selector_table_decl (); + + /* Stuff for properties. + The codegen relies on this being NULL for GNU. */ + objc_copyStruct_decl = NULL_TREE; + + /* This is the type of all of the following functions + bjc_getPropertyStruct() and objc_setPropertyStruct(). */ + type = build_function_type_list (void_type_node, + ptr_type_node, + const_ptr_type_node, + ptrdiff_type_node, + boolean_type_node, + boolean_type_node, + NULL_TREE); + + /* Declare the following function: + void + objc_getPropertyStruct (void *destination, const void *source, + ptrdiff_t size, BOOL is_atomic, BOOL has_strong); */ + objc_getPropertyStruct_decl = add_builtin_function ("objc_getPropertyStruct", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (objc_getPropertyStruct_decl) = 0; + /* Declare the following function: + void + objc_setPropertyStruct (void *destination, const void *source, + ptrdiff_t size, BOOL is_atomic, BOOL has_strong); */ + objc_setPropertyStruct_decl = add_builtin_function ("objc_setPropertyStruct", + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (objc_setPropertyStruct_decl) = 0; + + using_eh_for_cleanups (); + lang_hooks.eh_runtime_type = objc_eh_runtime_type; + lang_hooks.eh_personality = objc_eh_personality; +} + +/* --- templates --- */ +/* struct _objc_selector { + SEL sel_id; + char *sel_type; + }; */ + +static void +build_selector_template (void) +{ + tree decls, *chain = NULL; + + objc_selector_template = objc_start_struct (get_identifier (UTAG_SELECTOR)); + + /* SEL sel_id; */ + decls = add_field_decl (objc_selector_type, "sel_id", &chain); + + /* char *sel_type; */ + add_field_decl (string_type_node, "sel_type", &chain); + + objc_finish_struct (objc_selector_template, decls); +} + +/* struct _objc_class { + struct _objc_class *isa; + struct _objc_class *super_class; + char *name; + long version; + long info; + long instance_size; + struct _objc_ivar_list *ivars; + struct _objc_method_list *methods; + struct sarray *dtable; + struct _objc_class *subclass_list; + struct _objc_class *sibling_class; + struct _objc_protocol_list *protocols; + void *gc_object_type; + }; */ + +static void +build_class_template (void) +{ + tree ptype, decls, *chain = NULL; + + objc_class_template = objc_start_struct (get_identifier (UTAG_CLASS)); + + /* struct _objc_class *isa; */ + decls = add_field_decl (build_pointer_type (objc_class_template), + "isa", &chain); + + /* struct _objc_class *super_class; */ + add_field_decl (build_pointer_type (objc_class_template), + "super_class", &chain); + + /* char *name; */ + add_field_decl (string_type_node, "name", &chain); + + /* long version; */ + add_field_decl (long_integer_type_node, "version", &chain); + + /* long info; */ + add_field_decl (long_integer_type_node, "info", &chain); + + /* long instance_size; */ + add_field_decl (long_integer_type_node, "instance_size", &chain); + + /* struct _objc_ivar_list *ivars; */ + add_field_decl (objc_ivar_list_ptr,"ivars", &chain); + + /* struct _objc_method_list *methods; */ + add_field_decl (objc_method_list_ptr, "methods", &chain); + + /* struct sarray *dtable; */ + ptype = build_pointer_type(xref_tag (RECORD_TYPE, + get_identifier ("sarray"))); + add_field_decl (ptype, "dtable", &chain); + + /* struct objc_class *subclass_list; */ + ptype = build_pointer_type (objc_class_template); + add_field_decl (ptype, "subclass_list", &chain); + + /* struct objc_class *sibling_class; */ + ptype = build_pointer_type (objc_class_template); + add_field_decl (ptype, "sibling_class", &chain); + + /* struct _objc_protocol **protocol_list; */ + ptype = build_pointer_type (build_pointer_type + (xref_tag (RECORD_TYPE, + get_identifier (UTAG_PROTOCOL)))); + add_field_decl (ptype, "protocol_list", &chain); + + /* void *gc_object_type; */ + add_field_decl (build_pointer_type (void_type_node), + "gc_object_type", &chain); + + objc_finish_struct (objc_class_template, decls); +} + +/* struct _objc_category { + char *category_name; + char *class_name; + struct _objc_method_list *instance_methods; + struct _objc_method_list *class_methods; + struct _objc_protocol_list *protocols; + }; */ + +static void +build_category_template (void) +{ + tree ptype, decls, *chain = NULL; + + objc_category_template = objc_start_struct (get_identifier (UTAG_CATEGORY)); + + /* char *category_name; */ + decls = add_field_decl (string_type_node, "category_name", &chain); + + /* char *class_name; */ + add_field_decl (string_type_node, "class_name", &chain); + + /* struct _objc_method_list *instance_methods; */ + add_field_decl (objc_method_list_ptr, "instance_methods", &chain); + + /* struct _objc_method_list *class_methods; */ + add_field_decl (objc_method_list_ptr, "class_methods", &chain); + + /* struct _objc_protocol **protocol_list; */ + ptype = build_pointer_type (build_pointer_type (objc_protocol_template)); + add_field_decl (ptype, "protocol_list", &chain); + + objc_finish_struct (objc_category_template, decls); +} + +/* struct _objc_protocol { + struct _objc_class *isa; + char *protocol_name; + struct _objc_protocol **protocol_list; + struct _objc__method_prototype_list *instance_methods; + struct _objc__method_prototype_list *class_methods; + }; */ + +static void +build_protocol_template (void) +{ + tree ptype, decls, *chain = NULL; + + objc_protocol_template = objc_start_struct (get_identifier (UTAG_PROTOCOL)); + + /* struct _objc_class *isa; */ + ptype = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (UTAG_CLASS))); + decls = add_field_decl (ptype, "isa", &chain); + + /* char *protocol_name; */ + add_field_decl (string_type_node, "protocol_name", &chain); + + /* struct _objc_protocol **protocol_list; */ + ptype = build_pointer_type (build_pointer_type (objc_protocol_template)); + add_field_decl (ptype, "protocol_list", &chain); + + /* struct _objc__method_prototype_list *instance_methods; */ + add_field_decl (objc_method_proto_list_ptr, "instance_methods", &chain); + + /* struct _objc__method_prototype_list *class_methods; */ + add_field_decl (objc_method_proto_list_ptr, "class_methods", &chain); + + objc_finish_struct (objc_protocol_template, decls); +} + +/* --- names, decls + identifers --- */ + +static void +build_selector_table_decl (void) +{ + tree temp; + + build_selector_template (); + temp = build_array_type (objc_selector_template, NULL_TREE); + + UOBJC_SELECTOR_TABLE_decl = start_var_decl (temp, "_OBJC_SELECTOR_TABLE"); + OBJCMETA (UOBJC_SELECTOR_TABLE_decl, objc_meta, meta_base); +} + + +static tree +gnu_runtime_abi_01_super_superclassfield_id (void) +{ + if (!super_superclassfield_id) + super_superclassfield_id = get_identifier ("super_class"); + return super_superclassfield_id; +} + + +static tree +gnu_runtime_abi_01_class_decl (tree klass) +{ + tree decl; + char buf[BUFSIZE]; + snprintf (buf, BUFSIZE, "_OBJC_Class_%s", + IDENTIFIER_POINTER (CLASS_NAME (klass))); + decl = start_var_decl (objc_class_template, buf); + OBJCMETA (decl, objc_meta, meta_base); + return decl; +} + +static tree +gnu_runtime_abi_01_metaclass_decl (tree klass) +{ + tree decl; + char buf[BUFSIZE]; + snprintf (buf, BUFSIZE, "_OBJC_MetaClass_%s", + IDENTIFIER_POINTER (CLASS_NAME (klass))); + decl = start_var_decl (objc_class_template, buf); + OBJCMETA (decl, objc_meta, meta_base); + return decl; +} + +static tree +gnu_runtime_abi_01_category_decl (tree klass) +{ + tree decl; + char buf[BUFSIZE]; + snprintf (buf, BUFSIZE, "_OBJC_Category_%s_on_%s", + IDENTIFIER_POINTER (CLASS_SUPER_NAME (klass)), + IDENTIFIER_POINTER (CLASS_NAME (klass))); + decl = start_var_decl (objc_category_template, buf); + OBJCMETA (decl, objc_meta, meta_base); + return decl; +} + +static tree +gnu_runtime_abi_01_protocol_decl (tree p) +{ + tree decl; + char buf[BUFSIZE]; + + /* static struct _objc_protocol _OBJC_Protocol_<mumble>; */ + snprintf (buf, BUFSIZE, "_OBJC_Protocol_%s", + IDENTIFIER_POINTER (PROTOCOL_NAME (p))); + decl = start_var_decl (objc_protocol_template, buf); + OBJCMETA (decl, objc_meta, meta_base); + return decl; +} + +static tree +gnu_runtime_abi_01_string_decl (tree type, const char *name, + string_section where ATTRIBUTE_UNUSED) +{ + tree decl = start_var_decl (type, name); + OBJCMETA (decl, objc_meta, meta_base); + return decl; +} + +/* --- entry --- */ + +static tree +gnu_runtime_abi_01_get_class_reference (tree ident) +{ + tree params; + + add_class_reference (ident); + + params = build_tree_list (NULL_TREE, my_build_string_pointer + (IDENTIFIER_LENGTH (ident) + 1, + IDENTIFIER_POINTER (ident))); + + /* FIXME: Do we need this assemble_external() ? */ + /* assemble_external (objc_get_class_decl);*/ + return build_function_call (input_location, objc_get_class_decl, params); +} + +/* Used by get_arg_type_list. + Return the types for receiver & _cmd at the start of a method argument list. + context is either METHOD_DEF or METHOD_REF, saying whether we are trying + to define a method or call one. superflag says this is for a send to super. + meth may be NULL, in the case that there is no prototype. */ + +static tree +gnu_runtime_abi_01_get_arg_type_list_base (tree meth, int context, + int superflag ATTRIBUTE_UNUSED) +{ + tree arglist; + + /* Receiver type. */ + if (context == METHOD_DEF && TREE_CODE (meth) == INSTANCE_METHOD_DECL) + arglist = build_tree_list (NULL_TREE, objc_instance_type); + else + arglist = build_tree_list (NULL_TREE, objc_object_type); + + /* Selector type - will eventually change to `int'. */ + chainon (arglist, build_tree_list (NULL_TREE, objc_selector_type)); + return arglist; +} + +/* Unused for GNU runtime. */ +static tree +gnu_runtime_abi_01_receiver_is_class_object (tree a ATTRIBUTE_UNUSED) +{ + return NULL_TREE; +} + +/* sel_ref_chain is a list whose "value" fields will be instances of + identifier_node that represent the selector. LOC is the location of + the @selector. */ + +static tree +gnu_runtime_abi_01_build_typed_selector_reference (location_t loc, tree ident, + tree prototype) +{ + tree *chain = &sel_ref_chain; + tree expr; + int index = 0; + + while (*chain) + { + /* When we do a lookup for @selector () we have no idea of the + prototype - so match the first we find. */ + if (TREE_VALUE (*chain) == ident + && (!prototype || TREE_PURPOSE (*chain) == prototype)) + goto return_at_index; + + index++; + chain = &TREE_CHAIN (*chain); + } + + *chain = tree_cons (prototype, ident, NULL_TREE); + + /* TODO: Use a vec and keep this in it to (a) avoid re-creating and + (b) provide better diagnostics for the first time an undefined + selector is used. */ + return_at_index: + expr = build_unary_op (loc, ADDR_EXPR, + build_array_ref (loc, UOBJC_SELECTOR_TABLE_decl, + build_int_cst (NULL_TREE, index)), + 1); + return convert (objc_selector_type, expr); +} + +/* Build a tree expression to send OBJECT the operation SELECTOR, + looking up the method on object LOOKUP_OBJECT (often same as OBJECT), + assuming the method has prototype METHOD_PROTOTYPE. + (That is an INSTANCE_METHOD_DECL or CLASS_METHOD_DECL.) + LOC is the location of the expression to build. + Use METHOD_PARAMS as list of args to pass to the method. + If SUPER_FLAG is nonzero, we look up the superclass's method. */ + +static tree +build_objc_method_call (location_t loc, int super_flag, tree method_prototype, + tree lookup_object, tree selector, + tree method_params) +{ + tree sender = (super_flag ? umsg_super_decl + : (flag_objc_direct_dispatch ? umsg_fast_decl + : umsg_decl)); + tree rcv_p = (super_flag ? objc_super_type : objc_object_type); + VEC(tree, gc) *parms; + VEC(tree, gc) *tv; + unsigned nparm = (method_params ? list_length (method_params) : 0); + + /* If a prototype for the method to be called exists, then cast + the sender's return type and arguments to match that of the method. + Otherwise, leave sender as is. */ + tree ret_type + = (method_prototype + ? TREE_VALUE (TREE_TYPE (method_prototype)) + : objc_object_type); + + tree method_param_types = + get_arg_type_list (method_prototype, METHOD_REF, super_flag); + tree ftype = build_function_type (ret_type, method_param_types); + tree sender_cast; + tree method, t; + + if (method_prototype && METHOD_TYPE_ATTRIBUTES (method_prototype)) + ftype = build_type_attribute_variant (ftype, + METHOD_TYPE_ATTRIBUTES + (method_prototype)); + + sender_cast = build_pointer_type (ftype); + + lookup_object = build_c_cast (loc, rcv_p, lookup_object); + + /* Use SAVE_EXPR to avoid evaluating the receiver twice. */ + lookup_object = save_expr (lookup_object); + + /* Param list + 2 slots for object and selector. */ + parms = VEC_alloc (tree, gc, nparm + 2); + tv = VEC_alloc (tree, gc, 2); + + /* First, call the lookup function to get a pointer to the method, + then cast the pointer, then call it with the method arguments. */ + VEC_quick_push (tree, tv, lookup_object); + VEC_quick_push (tree, tv, selector); + method = build_function_call_vec (loc, sender, tv, NULL); + VEC_free (tree, gc, tv); + + /* Pass the appropriate object to the method. */ + VEC_quick_push (tree, parms, (super_flag ? self_decl : lookup_object)); + + /* Pass the selector to the method. */ + VEC_quick_push (tree, parms, selector); + /* Now append the remainder of the parms. */ + if (nparm) + for (; method_params; method_params = TREE_CHAIN (method_params)) + VEC_quick_push (tree, parms, TREE_VALUE (method_params)); + + /* Build an obj_type_ref, with the correct cast for the method call. */ + t = build3 (OBJ_TYPE_REF, sender_cast, method, lookup_object, size_zero_node); + t = build_function_call_vec (loc, t, parms, NULL); + VEC_free (tree, gc, parms); + return t; +} + +static tree +gnu_runtime_abi_01_build_objc_method_call (location_t loc, + tree method_prototype, + tree receiver, + tree rtype ATTRIBUTE_UNUSED, + tree sel_name, + tree method_params, + int super ATTRIBUTE_UNUSED) +{ + tree selector = + gnu_runtime_abi_01_build_typed_selector_reference (loc, + sel_name, + method_prototype); + + return build_objc_method_call (loc, super, method_prototype, receiver, + selector, method_params); +} + +static tree +gnu_runtime_abi_01_get_protocol_reference (location_t loc, tree p) +{ + tree expr, protocol_struct_type, *chain; + if (!PROTOCOL_FORWARD_DECL (p)) + PROTOCOL_FORWARD_DECL (p) = gnu_runtime_abi_01_protocol_decl (p); + + expr = build_unary_op (loc, ADDR_EXPR, PROTOCOL_FORWARD_DECL (p), 0); + + /* ??? Ideally we'd build the reference with objc_protocol_type directly, + if we have it, rather than converting it here. */ + expr = convert (objc_protocol_type, expr); + + /* The @protocol() expression is being compiled into a pointer to a + statically allocated instance of the Protocol class. To become + usable at runtime, the 'isa' pointer of the instance need to be + fixed up at runtime by the runtime library, to point to the + actual 'Protocol' class. */ + + /* For the GNU runtime, put the static Protocol instance in the list + of statically allocated instances, so that we make sure that its + 'isa' pointer is fixed up at runtime by the GNU runtime library + to point to the Protocol class (at runtime, when loading the + module, the GNU runtime library loops on the statically allocated + instances (as found in the defs field in objc_symtab) and fixups + all the 'isa' pointers of those objects). */ + + /* This type is a struct containing the fields of a Protocol + object. (Cfr. objc_protocol_type instead is the type of a pointer + to such a struct). */ + protocol_struct_type = xref_tag (RECORD_TYPE, + get_identifier (PROTOCOL_OBJECT_CLASS_NAME)); + + /* Look for the list of Protocol statically allocated instances + to fixup at runtime. Create a new list to hold Protocol + statically allocated instances, if the list is not found. At + present there is only another list, holding NSConstantString + static instances to be fixed up at runtime. */ + + for (chain = &objc_static_instances; + *chain && TREE_VALUE (*chain) != protocol_struct_type; + chain = &TREE_CHAIN (*chain)); + + if (!*chain) + { + *chain = tree_cons (NULL_TREE, protocol_struct_type, NULL_TREE); + add_objc_string (OBJC_TYPE_NAME (protocol_struct_type), + class_names); + } + + /* Add this statically allocated instance to the Protocol list. */ + TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, + PROTOCOL_FORWARD_DECL (p), + TREE_PURPOSE (*chain)); + return expr; +} + +/* For ABI 8 an IVAR is just a fixed offset in the class struct. */ + +static tree +gnu_runtime_abi_01_build_ivar_ref (location_t loc ATTRIBUTE_UNUSED, + tree base, tree id) +{ + return objc_build_component_ref (base, id); +} + +/* We build super class references as we need them (but keep them once + built for the sake of efficiency). */ + +static tree +gnu_runtime_abi_01_get_class_super_ref (location_t loc ATTRIBUTE_UNUSED, + struct imp_entry *imp, bool inst_meth) +{ + if (inst_meth) + { + if (!ucls_super_ref) + ucls_super_ref = + objc_build_component_ref (imp->class_decl, + get_identifier ("super_class")); + return ucls_super_ref; + } + else + { + if (!uucls_super_ref) + uucls_super_ref = + objc_build_component_ref (imp->meta_decl, + get_identifier ("super_class")); + return uucls_super_ref; + } +} + +static tree +gnu_runtime_abi_01_get_category_super_ref (location_t loc ATTRIBUTE_UNUSED, + struct imp_entry *imp, bool inst_meth) +{ + tree super_name = CLASS_SUPER_NAME (imp->imp_template); + tree super_class; + + add_class_reference (super_name); + super_class = (inst_meth ? objc_get_class_decl : objc_get_meta_class_decl); + /* FIXME: Do we need this assemble_external() ? */ + /* assemble_external (super_class);*/ + super_name = my_build_string_pointer (IDENTIFIER_LENGTH (super_name) + 1, + IDENTIFIER_POINTER (super_name)); + /* super_class = get_{meta_}class("CLASS_SUPER_NAME"); */ + return build_function_call (input_location, + super_class, + build_tree_list (NULL_TREE, super_name)); +} + +static bool +gnu_runtime_abi_01_setup_const_string_class_decl (void) +{ + /* Do nothing, and create no error. */ + return true; +} + +/* Declare a static instance of CLASS_DECL initialized by CONSTRUCTOR. */ + +static GTY(()) int num_static_inst; + +static tree +objc_add_static_instance (tree constructor, tree class_decl) +{ + tree *chain, decl; + char buf[BUFSIZE]; + + /* Find the list of static instances for the CLASS_DECL. Create one if + not found. */ + for (chain = &objc_static_instances; + *chain && TREE_VALUE (*chain) != class_decl; + chain = &TREE_CHAIN (*chain)); + if (!*chain) + { + *chain = tree_cons (NULL_TREE, class_decl, NULL_TREE); + add_objc_string (OBJC_TYPE_NAME (class_decl), class_names); + } + + snprintf (buf, BUFSIZE, "_OBJC_INSTANCE_%d", num_static_inst++); + decl = build_decl (input_location, + VAR_DECL, get_identifier (buf), class_decl); + TREE_STATIC (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + TREE_USED (decl) = 1; + DECL_INITIAL (decl) = constructor; + DECL_CONTEXT (decl) = NULL; + OBJCMETA (decl, objc_meta, meta_base); + + /* We may be writing something else just now. + Postpone till end of input. */ + DECL_DEFER_OUTPUT (decl) = 1; + pushdecl_top_level (decl); + rest_of_decl_compilation (decl, 1, 0); + + /* Add the DECL to the head of this CLASS' list. */ + TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, decl, TREE_PURPOSE (*chain)); + + return decl; +} + +static tree +gnu_runtime_abi_01_build_const_string_constructor (location_t loc, tree string, + int length) +{ + tree constructor, fields; + VEC(constructor_elt,gc) *v = NULL; + + /* GNU: (NXConstantString *) & ((__builtin_ObjCString) { NULL, string, length }) */ + fields = TYPE_FIELDS (internal_const_str_type); + CONSTRUCTOR_APPEND_ELT (v, fields, build_int_cst (NULL_TREE, 0)); + + fields = DECL_CHAIN (fields); + CONSTRUCTOR_APPEND_ELT (v, fields, build_unary_op (loc, + ADDR_EXPR, string, 1)); + + fields = DECL_CHAIN (fields); + CONSTRUCTOR_APPEND_ELT (v, fields, build_int_cst (NULL_TREE, length)); + constructor = objc_build_constructor (internal_const_str_type, v); + + constructor = objc_add_static_instance (constructor, constant_string_type); + return constructor; +} + +/* --- metadata - module initializer --- */ + +/* The GNU runtime requires us to provide a static initializer function + for each module: + + static void __objc_gnu_init (void) { + __objc_exec_class (&L_OBJC_MODULES); + } */ + + +static void +build_module_initializer_routine (void) +{ + tree body; + +#ifdef OBJCPLUS + push_lang_context (lang_name_c); /* extern "C" */ +#endif + + objc_push_parm (build_decl (input_location, + PARM_DECL, NULL_TREE, void_type_node)); +#ifdef OBJCPLUS + objc_start_function (get_identifier (TAG_GNUINIT), + build_function_type_list (void_type_node, NULL_TREE), + NULL_TREE, NULL_TREE); +#else + objc_start_function (get_identifier (TAG_GNUINIT), + build_function_type_list (void_type_node, NULL_TREE), + NULL_TREE, objc_get_parm_info (0)); +#endif + body = c_begin_compound_stmt (true); + add_stmt (build_function_call + (input_location, + execclass_decl, + build_tree_list + (NULL_TREE, + build_unary_op (input_location, ADDR_EXPR, + UOBJC_MODULES_decl, 0)))); + add_stmt (c_end_compound_stmt (input_location, body, true)); + + TREE_PUBLIC (current_function_decl) = 0; + +#ifndef OBJCPLUS + /* For Objective-C++, we will need to call __objc_gnu_init + from objc_generate_static_init_call() below. */ + DECL_STATIC_CONSTRUCTOR (current_function_decl) = 1; +#endif + + GNU_INIT_decl = current_function_decl; + finish_function (); + +#ifdef OBJCPLUS + pop_lang_context (); +#endif +} + +#ifdef OBJCPLUS +/* Return 1 if the __objc_gnu_init function has been synthesized and needs + to be called by the module initializer routine. */ + +int +objc_static_init_needed_p (void) +{ + return (GNU_INIT_decl != NULL_TREE); +} + +/* Generate a call to the __objc_gnu_init initializer function. */ + +tree +objc_generate_static_init_call (tree ctors ATTRIBUTE_UNUSED) +{ + add_stmt (build_stmt (input_location, EXPR_STMT, + build_function_call (input_location, + GNU_INIT_decl, NULL_TREE))); + + return ctors; +} +#endif /* OBJCPLUS */ + +/* --- Output GNU Meta-data --- */ + +static void +generate_classref_translation_entry (tree chain) +{ + tree expr, decl, type; + + decl = TREE_PURPOSE (chain); + type = TREE_TYPE (decl); + + expr = add_objc_string (TREE_VALUE (chain), class_names); + expr = convert (type, expr); /* cast! */ + + /* This is a class reference. It is re-written by the runtime, + but will be optimized away unless we force it. */ + DECL_PRESERVE_P (decl) = 1; + OBJCMETA (decl, objc_meta, meta_base); + finish_var_decl (decl, expr); + return; +} + + +static void +handle_impent (struct imp_entry *impent) +{ + char *string; + +/* objc_implementation_context = impent->imp_context; + implementation_template = impent->imp_template;*/ + + switch (TREE_CODE (impent->imp_context)) + { + case CLASS_IMPLEMENTATION_TYPE: + { + const char *const class_name = + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)); + + string = (char *) alloca (strlen (class_name) + 30); + + sprintf (string, "__objc_class_name_%s", class_name); + break; + } + case CATEGORY_IMPLEMENTATION_TYPE: + { + const char *const class_name = + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)); + const char *const class_super_name = + IDENTIFIER_POINTER (CLASS_SUPER_NAME (impent->imp_context)); + + string = (char *) alloca (strlen (class_name) + + strlen (class_super_name) + 30); + + /* Do the same for categories. Even though no references to + these symbols are generated automatically by the compiler, + it gives you a handle to pull them into an archive by + hand. */ + sprintf (string, "*__objc_category_name_%s_%s", class_name, class_super_name); + break; + } + default: + return; + } + + { + tree decl, init; + + init = integer_zero_node; + decl = build_decl (input_location, + VAR_DECL, get_identifier (string), TREE_TYPE (init)); + TREE_PUBLIC (decl) = 1; + TREE_READONLY (decl) = 1; + TREE_USED (decl) = 1; + TREE_CONSTANT (decl) = 1; + DECL_CONTEXT (decl) = NULL_TREE; + DECL_ARTIFICIAL (decl) = 1; + TREE_STATIC (decl) = 1; + DECL_INITIAL (decl) = error_mark_node; /* A real initializer is coming... */ + /* We must force the reference. */ + DECL_PRESERVE_P (decl) = 1; + + finish_var_decl(decl, init) ; + } +} + +tree +build_protocol_initializer (tree type, tree protocol_name, tree protocol_list, + tree inst_methods, tree class_methods) +{ + tree expr, ttyp; + location_t loc; + VEC(constructor_elt,gc) *inits = NULL; + + /* TODO: pass the loc in or find it from args. */ + loc = input_location; + ttyp = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (UTAG_CLASS))); + /* Filling the "isa" in with a version allows the runtime system to + detect this ... */ + expr = build_int_cst (ttyp, PROTOCOL_VERSION); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, protocol_name); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, protocol_list); + + ttyp = objc_method_proto_list_ptr; + if (inst_methods) + expr = convert (ttyp, build_unary_op (loc, ADDR_EXPR, inst_methods, 0)); + else + expr = convert (ttyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + + if (class_methods) + expr = convert (ttyp, build_unary_op (loc, ADDR_EXPR, class_methods, 0)); + else + expr = convert (ttyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + + return objc_build_constructor (type, inits); +} + +static tree +generate_protocol_list (tree i_or_p, tree klass_ctxt) +{ + tree array_type, ptype, refs_decl, lproto, e, plist; + VEC(constructor_elt,gc) *v = NULL; + char buf[BUFSIZE]; + int size = 0; + + switch (TREE_CODE (i_or_p)) + { + case CLASS_INTERFACE_TYPE: + case CATEGORY_INTERFACE_TYPE: + plist = CLASS_PROTOCOL_LIST (i_or_p); + break; + case PROTOCOL_INTERFACE_TYPE: + plist = PROTOCOL_LIST (i_or_p); + break; + default: + gcc_unreachable (); + } + + /* Compute size. */ + for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) + if (TREE_CODE (TREE_VALUE (lproto)) == PROTOCOL_INTERFACE_TYPE + && PROTOCOL_FORWARD_DECL (TREE_VALUE (lproto))) + size++; + + /* Build initializer. */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); + e = build_int_cst (build_pointer_type (objc_protocol_template), size); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, e); + + for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) + { + tree pval = TREE_VALUE (lproto); + + if (TREE_CODE (pval) == PROTOCOL_INTERFACE_TYPE + && PROTOCOL_FORWARD_DECL (pval)) + { + tree fwref = PROTOCOL_FORWARD_DECL (pval); + location_t loc = DECL_SOURCE_LOCATION (fwref) ; + e = build_unary_op (loc, ADDR_EXPR, fwref, 0); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, e); + } + } + + /* static struct objc_protocol *refs[n]; */ + + switch (TREE_CODE (i_or_p)) + { + case PROTOCOL_INTERFACE_TYPE: + snprintf (buf, BUFSIZE, "_OBJC_ProtocolRefs_%s", + IDENTIFIER_POINTER (PROTOCOL_NAME (i_or_p))); + break; + case CLASS_INTERFACE_TYPE: + snprintf (buf, BUFSIZE, "_OBJC_ClassProtocols_%s", + IDENTIFIER_POINTER (CLASS_NAME (i_or_p))); + break; + case CATEGORY_INTERFACE_TYPE: + snprintf (buf, BUFSIZE, "_OBJC_CategoryProtocols_%s_%s", + IDENTIFIER_POINTER (CLASS_NAME (klass_ctxt)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (klass_ctxt))); + break; + default: + gcc_unreachable (); + } + + ptype = build_pointer_type (objc_protocol_template); + array_type = build_sized_array_type (ptype, size + 3); + refs_decl = start_var_decl (array_type, buf); + OBJCMETA (refs_decl, objc_meta, meta_base); + finish_var_decl (refs_decl, + objc_build_constructor (TREE_TYPE (refs_decl), v)); + + return refs_decl; +} + +static tree +generate_v1_meth_descriptor_table (tree chain, tree protocol, const char *prefix) +{ + tree method_list_template, initlist, decl; + int size; + VEC(constructor_elt,gc) *v = NULL; + char buf[BUFSIZE]; + + if (!chain || !prefix) + return NULL_TREE; + + if (!objc_method_prototype_template) + objc_method_prototype_template = build_method_prototype_template (); + + size = list_length (chain); + method_list_template = + build_method_prototype_list_template (objc_method_prototype_template, + size); + snprintf (buf, BUFSIZE, "%s_%s", prefix, + IDENTIFIER_POINTER (PROTOCOL_NAME (protocol))); + + decl = start_var_decl (method_list_template, buf); + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, size)); + initlist = + build_descriptor_table_initializer (objc_method_prototype_template, + chain); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, initlist); + OBJCMETA (decl, objc_meta, meta_base); + finish_var_decl (decl, objc_build_constructor (method_list_template, v)); + return decl; +} + +/* For each protocol which was referenced either from a @protocol() + expression, or because a class/category implements it (then a + pointer to the protocol is stored in the struct describing the + class/category), we create a statically allocated instance of the + Protocol class. The code is written in such a way as to generate + as few Protocol objects as possible; we generate a unique Protocol + instance for each protocol, and we don't generate a Protocol + instance if the protocol is never referenced (either from a + @protocol() or from a class/category implementation). These + statically allocated objects can be referred to via the static + (that is, private to this module) symbols _OBJC_PROTOCOL_n. + + The statically allocated Protocol objects that we generate here + need to be fixed up at runtime in order to be used: the 'isa' + pointer of the objects need to be set up to point to the 'Protocol' + class, as known at runtime. + + The GNU runtime fixes up all protocols before user code from the module + is executed; it requires pointers to those symbols + to be put in the objc_symtab (which is then passed as argument to + the function __objc_exec_class() which the compiler sets up to be + executed automatically when the module is loaded); setup of those + Protocol objects happen in two ways in the GNU runtime: all + Protocol objects referred to by a class or category implementation + are fixed up when the class/category is loaded; all Protocol + objects referred to by a @protocol() expression are added by the + compiler to the list of statically allocated instances to fixup + (the same list holding the statically allocated constant string + objects). Because, as explained above, the compiler generates as + few Protocol objects as possible, some Protocol object might end up + being referenced multiple times when compiled with the GNU runtime, + and end up being fixed up multiple times at runtime initialization. + But that doesn't hurt, it's just a little inefficient. */ + +static void +generate_protocols (void) +{ + tree p, encoding; + tree decl; + tree initlist, protocol_name_expr, refs_decl, refs_expr; + + /* If a protocol was directly referenced, pull in indirect references. */ + for (p = protocol_chain; p; p = TREE_CHAIN (p)) + if (PROTOCOL_FORWARD_DECL (p) && PROTOCOL_LIST (p)) + generate_protocol_references (PROTOCOL_LIST (p)); + + for (p = protocol_chain; p; p = TREE_CHAIN (p)) + { + tree nst_methods = PROTOCOL_NST_METHODS (p); + tree cls_methods = PROTOCOL_CLS_METHODS (p); + + /* If protocol wasn't referenced, don't generate any code. */ + decl = PROTOCOL_FORWARD_DECL (p); + + if (!decl) + continue; + + /* Make sure we link in the Protocol class. */ + add_class_reference (get_identifier (PROTOCOL_OBJECT_CLASS_NAME)); + + while (nst_methods) + { + if (! METHOD_ENCODING (nst_methods)) + { + encoding = encode_method_prototype (nst_methods); + METHOD_ENCODING (nst_methods) = encoding; + } + nst_methods = DECL_CHAIN (nst_methods); + } + + UOBJC_INSTANCE_METHODS_decl = + generate_v1_meth_descriptor_table (PROTOCOL_NST_METHODS (p), p, + "_OBJC_PROTOCOL_INSTANCE_METHODS"); + + while (cls_methods) + { + if (! METHOD_ENCODING (cls_methods)) + { + encoding = encode_method_prototype (cls_methods); + METHOD_ENCODING (cls_methods) = encoding; + } + + cls_methods = DECL_CHAIN (cls_methods); + } + + UOBJC_CLASS_METHODS_decl = + generate_v1_meth_descriptor_table (PROTOCOL_CLS_METHODS (p), p, + "_OBJC_PROTOCOL_CLASS_METHODS"); +/* generate_method_descriptors (p);*/ + + if (PROTOCOL_LIST (p)) + refs_decl = generate_protocol_list (p, NULL_TREE); + else + refs_decl = 0; + + /* static struct objc_protocol _OBJC_PROTOCOL_<mumble>; */ + protocol_name_expr = add_objc_string (PROTOCOL_NAME (p), class_names); + + if (refs_decl) + refs_expr = convert (build_pointer_type (build_pointer_type + (objc_protocol_template)), + build_unary_op (input_location, + ADDR_EXPR, refs_decl, 0)); + else + refs_expr = build_int_cst (NULL_TREE, 0); + + /* UOBJC_INSTANCE_METHODS_decl/UOBJC_CLASS_METHODS_decl are set + by generate_method_descriptors, which is called above. */ + initlist = build_protocol_initializer (TREE_TYPE (decl), + protocol_name_expr, refs_expr, + UOBJC_INSTANCE_METHODS_decl, + UOBJC_CLASS_METHODS_decl); + finish_var_decl (decl, initlist); + } +} + +static tree +generate_dispatch_table (tree chain, const char *name) +{ + tree decl, method_list_template, initlist; + VEC(constructor_elt,gc) *v = NULL; + int size = list_length (chain); + + if (!objc_method_template) + objc_method_template = build_method_template (); + + method_list_template = build_method_list_template (objc_method_template, + size); + initlist = build_dispatch_table_initializer (objc_method_template, chain); + + decl = start_var_decl (method_list_template, name); + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (integer_type_node, size)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, initlist); + + OBJCMETA (decl, objc_meta, meta_base); + finish_var_decl (decl, + objc_build_constructor (TREE_TYPE (decl), v)); + + return decl; +} + +/* Init a category. */ +static tree +build_category_initializer (tree type, tree cat_name, tree class_name, + tree inst_methods, tree class_methods, + tree protocol_list) +{ + tree expr, ltyp; + location_t loc; + VEC(constructor_elt,gc) *v = NULL; + + /* TODO: pass the loc in or find it from args. */ + /* TODO: pass the loc in or find it from args. */ + loc = UNKNOWN_LOCATION; + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, cat_name); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, class_name); + + ltyp = objc_method_list_ptr; + if (inst_methods) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, inst_methods, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + if (class_methods) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, class_methods, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + /* protocol_list = */ + ltyp = build_pointer_type (build_pointer_type (objc_protocol_template)); + if (protocol_list) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, protocol_list, 0)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + return objc_build_constructor (type, v); +} + +/* static struct objc_category _OBJC_CATEGORY_<name> = { ... }; */ + +static void +generate_category (struct imp_entry *impent) +{ + tree initlist, cat_name_expr, class_name_expr; + tree protocol_decl, category, cat_decl; + tree inst_methods = NULL_TREE, class_methods = NULL_TREE; + tree cat = impent->imp_context; + char buf[BUFSIZE]; + + cat_decl = impent->class_decl; + + add_class_reference (CLASS_NAME (cat)); + cat_name_expr = add_objc_string (CLASS_SUPER_NAME (cat), class_names); + + class_name_expr = add_objc_string (CLASS_NAME (cat), class_names); + + category = lookup_category (impent->imp_template, CLASS_SUPER_NAME (cat)); + + if (category && CLASS_PROTOCOL_LIST (category)) + { + generate_protocol_references (CLASS_PROTOCOL_LIST (category)); + protocol_decl = generate_protocol_list (category, cat); + } + else + protocol_decl = 0; + + if (CLASS_NST_METHODS (cat)) + { + snprintf (buf, BUFSIZE, "_OBJC_CategoryInstanceMethods_%s_%s", + IDENTIFIER_POINTER (CLASS_NAME (cat)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (cat))); + inst_methods = generate_dispatch_table (CLASS_NST_METHODS (cat), buf); + } + + if (CLASS_CLS_METHODS (cat)) + { + snprintf (buf, BUFSIZE, "_OBJC_CategoryClassMethods_%s_%s", + IDENTIFIER_POINTER (CLASS_NAME (cat)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (cat))); + class_methods = generate_dispatch_table (CLASS_CLS_METHODS (cat), buf); + } + + initlist = build_category_initializer (TREE_TYPE (cat_decl), + cat_name_expr, class_name_expr, + inst_methods, class_methods, + protocol_decl); + /* Finish and initialize the forward decl. */ + finish_var_decl (cat_decl, initlist); + impent->class_decl = cat_decl; +} + +/* struct _objc_class { + struct objc_class *isa; + struct objc_class *super_class; + char *name; + long version; + long info; + long instance_size; + struct objc_ivar_list *ivars; + struct objc_method_list *methods; + struct sarray *dtable; + struct objc_class *subclass_list; + struct objc_class *sibling_class; + struct objc_protocol_list *protocols; + void *gc_object_type; + }; */ + +static tree +build_shared_structure_initializer (tree type, tree isa, tree super, + tree name, tree size, int status, + tree dispatch_table, tree ivar_list, + tree protocol_list) +{ + tree expr, ltyp; + VEC(constructor_elt,gc) *v = NULL; + + /* isa = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, isa); + + /* super_class = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, super); + + /* name = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, default_conversion (name)); + + /* version = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (long_integer_type_node, 0)); + + /* info = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (long_integer_type_node, status)); + + /* instance_size = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + convert (long_integer_type_node, size)); + + /* objc_ivar_list = */ + if (!ivar_list) + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (objc_ivar_list_ptr, 0)); + else + { + expr = convert (objc_ivar_list_ptr, + build_unary_op (input_location, ADDR_EXPR, + ivar_list, 0)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + + /* objc_method_list = */ + if (!dispatch_table) + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + convert (objc_method_list_ptr, null_pointer_node)); + else + { + expr = convert (objc_method_list_ptr, + build_unary_op (input_location, ADDR_EXPR, + dispatch_table, 0)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + + /* FIXME: Remove NeXT runtime code. */ + if (flag_next_runtime) + { + ltyp = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier ("objc_cache"))); + /* method_cache = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, convert (ltyp, null_pointer_node)); + } + else + { + /* dtable = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); + + /* subclass_list = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); + + /* sibling_class = */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); + } + + /* protocol_list = */ + ltyp = build_pointer_type (build_pointer_type (objc_protocol_template)); + if (! protocol_list) + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (ltyp, 0)); + else + { + expr = convert (ltyp, + build_unary_op (input_location, ADDR_EXPR, + protocol_list, 0)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + + /* FIXME: Remove NeXT runtime code. */ + if (flag_next_runtime) + /* sel_id = NULL */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); + + /* gc_object_type = NULL */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); + + return objc_build_constructor (type, v); +} + + +static tree +generate_ivars_list (tree chain, const char *name) +{ + tree initlist, ivar_list_template, decl; + int size; + VEC(constructor_elt,gc) *inits = NULL; + + if (!chain) + return NULL_TREE; + + if (!objc_ivar_template) + objc_ivar_template = build_ivar_template (); + + size = ivar_list_length (chain); + + generating_instance_variables = 1; + ivar_list_template = build_ivar_list_template (objc_ivar_template, size); + initlist = build_ivar_list_initializer (objc_ivar_template, chain); + generating_instance_variables = 0; + + decl = start_var_decl (ivar_list_template, name); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, build_int_cst (NULL_TREE, size)); + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, initlist); + + OBJCMETA (decl, objc_meta, meta_base); + finish_var_decl (decl, + objc_build_constructor (TREE_TYPE (decl), inits)); + + return decl; +} + +/* static struct objc_class _OBJC_METACLASS_Foo={ ... }; + static struct objc_class _OBJC_CLASS_Foo={ ... }; */ + +static void +generate_class_structures (struct imp_entry *impent) +{ + tree name_expr, super_expr, root_expr, class_decl, meta_decl; + tree my_root_id, my_super_id; + tree cast_type, initlist, protocol_decl; + tree inst_methods = NULL_TREE, class_methods = NULL_TREE; + tree chain, inst_ivars = NULL_TREE, class_ivars = NULL_TREE; + location_t loc; + char buf[BUFSIZE]; + int cls_flags = 0 ; + +/* objc_implementation_context = impent->imp_context; + implementation_template = impent->imp_template;*/ + class_decl = impent->class_decl; + meta_decl = impent->meta_decl; +/* UOBJC_CLASS_decl = impent->class_decl; + UOBJC_METACLASS_decl = impent->meta_decl;*/ + + loc = DECL_SOURCE_LOCATION (impent->class_decl); + + my_super_id = CLASS_SUPER_NAME (impent->imp_template); + if (my_super_id) + { + add_class_reference (my_super_id); + + /* Compute "my_root_id" - this is required for code generation. + the "isa" for all meta class structures points to the root of + the inheritance hierarchy (e.g. "__Object")... */ + my_root_id = my_super_id; + do + { + tree my_root_int = lookup_interface (my_root_id); + + if (my_root_int && CLASS_SUPER_NAME (my_root_int)) + my_root_id = CLASS_SUPER_NAME (my_root_int); + else + break; + } + while (1); + } + else + /* No super class. */ + my_root_id = CLASS_NAME (impent->imp_template); + + cast_type = build_pointer_type (objc_class_template); + name_expr = add_objc_string (CLASS_NAME (impent->imp_template), + class_names); + + /* Install class `isa' and `super' pointers at runtime. */ + if (my_super_id) + super_expr = add_objc_string (my_super_id, class_names); + else + super_expr = null_pointer_node; + + super_expr = build_c_cast (loc, cast_type, super_expr); + + root_expr = add_objc_string (my_root_id, class_names); + root_expr = build_c_cast (loc, cast_type, root_expr); + + if (CLASS_PROTOCOL_LIST (impent->imp_template)) + { + generate_protocol_references (CLASS_PROTOCOL_LIST (impent->imp_template)); + protocol_decl = generate_protocol_list (impent->imp_template, + impent->imp_context); + } + else + protocol_decl = NULL_TREE; + + if (CLASS_CLS_METHODS (impent->imp_context)) + { + snprintf (buf, BUFSIZE, "_OBJC_ClassMethods_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + class_methods = generate_dispatch_table (CLASS_CLS_METHODS (impent->imp_context), + buf); + } + + if (CLASS_SUPER_NAME (impent->imp_template) == NULL_TREE + && (chain = TYPE_FIELDS (objc_class_template))) + { + snprintf (buf, BUFSIZE, "_OBJC_ClassIvars_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + class_ivars = generate_ivars_list (chain, buf); + } + + /* static struct objc_class _OBJC_METACLASS_Foo = { ... }; */ + + initlist = + build_shared_structure_initializer + (TREE_TYPE (meta_decl), + root_expr, super_expr, name_expr, + convert (integer_type_node, + TYPE_SIZE_UNIT (objc_class_template)), + CLS_META, class_methods, class_ivars, + protocol_decl); + + finish_var_decl (meta_decl, initlist); + impent->meta_decl = meta_decl; + + /* static struct objc_class _OBJC_CLASS_Foo={ ... }; */ + if (CLASS_NST_METHODS (impent->imp_context)) + { + snprintf (buf, BUFSIZE, "_OBJC_InstanceMethods_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + inst_methods = generate_dispatch_table (CLASS_NST_METHODS (impent->imp_context), + buf); + } + + if ((chain = CLASS_IVARS (impent->imp_template))) + { + snprintf (buf, BUFSIZE, "_OBJC_InstanceIvars_%s", + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); + inst_ivars = generate_ivars_list (chain, buf); + } + + initlist = + build_shared_structure_initializer + (TREE_TYPE (class_decl), + build_unary_op (loc, ADDR_EXPR, meta_decl, 0), + super_expr, name_expr, + convert (integer_type_node, + TYPE_SIZE_UNIT (CLASS_STATIC_TEMPLATE + (impent->imp_template))), + CLS_FACTORY | cls_flags, inst_methods, inst_ivars, + protocol_decl); + + finish_var_decl (class_decl, initlist); + impent->class_decl = class_decl; +} + +/* --- Output GNU Metadata --- */ + +/* TODO: Make this into an array of refs. */ +static void +handle_class_ref (tree chain) +{ + const char *name = IDENTIFIER_POINTER (TREE_VALUE (chain)); + char *string = (char *) alloca (strlen (name) + 30); + tree decl; + tree exp; + + sprintf (string, "__objc_class_name_%s", name); + + /* Make a decl for this name, so we can use its address in a tree. */ + decl = build_decl (input_location, + VAR_DECL, get_identifier (string), TREE_TYPE (integer_zero_node)); + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + DECL_CONTEXT (decl) = NULL_TREE; + finish_var_decl (decl, 0); + + /* Make a decl for the address. */ + sprintf (string, "__objc_class_ref_%s", name); + exp = build1 (ADDR_EXPR, string_type_node, decl); + decl = build_decl (input_location, + VAR_DECL, get_identifier (string), string_type_node); + TREE_STATIC (decl) = 1; + TREE_USED (decl) = 1; + DECL_READ_P (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_INITIAL (decl) = error_mark_node; + + /* We must force the reference. */ + DECL_PRESERVE_P (decl) = 1; + + DECL_CONTEXT (decl) = NULL_TREE; + finish_var_decl (decl, exp); +} + +static tree +get_proto_encoding (tree proto) +{ + tree encoding; + if (proto) + { + if (! METHOD_ENCODING (proto)) + { + encoding = encode_method_prototype (proto); + METHOD_ENCODING (proto) = encoding; + } + else + encoding = METHOD_ENCODING (proto); + + return add_objc_string (encoding, meth_var_types); + } + else + return build_int_cst (NULL_TREE, 0); +} + +static void +build_gnu_selector_translation_table (void) +{ + tree chain, expr; + VEC(constructor_elt,gc) *inits = NULL; + VEC(constructor_elt,gc) *v ; + + /* Cause the selector table (previously forward-declared) + to be actually output. */ + + for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain)) + { + tree encoding; + if (warn_selector) + { + /* TODO: improve on the location for the diagnostic. */ + location_t loc = input_location; + diagnose_missing_method (TREE_VALUE (chain), loc); + } + + v = NULL; + expr = build_selector (TREE_VALUE (chain)); + encoding = get_proto_encoding (TREE_PURPOSE (chain)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, encoding); + expr = objc_build_constructor (objc_selector_template, v); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + } /* each element in the chain */ + + /* List terminator. */ + v = NULL; + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node); + expr = objc_build_constructor (objc_selector_template, v); + + CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); + expr = objc_build_constructor (TREE_TYPE (UOBJC_SELECTOR_TABLE_decl), + inits); + finish_var_decl (UOBJC_SELECTOR_TABLE_decl, expr); +} + +/* Output references to all statically allocated objects. Return the DECL + for the array built. */ + +static void +generate_static_references (void) +{ + tree expr = NULL_TREE; + tree class_name, klass, decl; + tree cl_chain, in_chain, type + = build_array_type (build_pointer_type (void_type_node), NULL_TREE); + int num_inst, num_class; + char buf[BUFSIZE]; + VEC(constructor_elt,gc) *decls = NULL; + + /* FIXME: Remove NeXT runtime code. */ + if (flag_next_runtime) + gcc_unreachable (); + + for (cl_chain = objc_static_instances, num_class = 0; + cl_chain; cl_chain = TREE_CHAIN (cl_chain), num_class++) + { + VEC(constructor_elt,gc) *v = NULL; + + for (num_inst = 0, in_chain = TREE_PURPOSE (cl_chain); + in_chain; num_inst++, in_chain = TREE_CHAIN (in_chain)); + + snprintf (buf, BUFSIZE, "_OBJC_STATIC_INSTANCES_%d", num_class); + decl = start_var_decl (type, buf); + + /* Output {class_name, ...}. */ + klass = TREE_VALUE (cl_chain); + class_name = get_objc_string_decl (OBJC_TYPE_NAME (klass), class_names); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_unary_op (input_location, + ADDR_EXPR, class_name, 1)); + + /* Output {..., instance, ...}. */ + for (in_chain = TREE_PURPOSE (cl_chain); + in_chain; in_chain = TREE_CHAIN (in_chain)) + { + expr = build_unary_op (input_location, + ADDR_EXPR, TREE_VALUE (in_chain), 1); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + + /* Output {..., NULL}. */ + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); + + expr = objc_build_constructor (TREE_TYPE (decl), v); + OBJCMETA (decl, objc_meta, meta_base); + finish_var_decl (decl, expr); + CONSTRUCTOR_APPEND_ELT (decls, NULL_TREE, + build_unary_op (input_location, + ADDR_EXPR, decl, 1)); + } + + CONSTRUCTOR_APPEND_ELT (decls, NULL_TREE, build_int_cst (NULL_TREE, 0)); + expr = objc_build_constructor (type, decls); + static_instances_decl = start_var_decl (type, "_OBJC_STATIC_INSTANCES"); + OBJCMETA (static_instances_decl, objc_meta, meta_base); + finish_var_decl (static_instances_decl, expr); +} + +/* Create the initial value for the `defs' field of _objc_symtab. + This is a CONSTRUCTOR. */ + +static tree +init_def_list (tree type) +{ + tree expr; + struct imp_entry *impent; + location_t loc; + VEC(constructor_elt,gc) *v = NULL; + + if (imp_count) + for (impent = imp_list; impent; impent = impent->next) + { + if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) + { + loc = DECL_SOURCE_LOCATION (impent->class_decl); + expr = build_unary_op (loc, + ADDR_EXPR, impent->class_decl, 0); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + } + + if (cat_count) + for (impent = imp_list; impent; impent = impent->next) + { + if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE) + { + loc = DECL_SOURCE_LOCATION (impent->class_decl); + expr = build_unary_op (loc, + ADDR_EXPR, impent->class_decl, 0); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + } + } + + loc = UNKNOWN_LOCATION; + /* statics = { ..., _OBJC_STATIC_INSTANCES, ... } */ + if (static_instances_decl) + expr = build_unary_op (loc, ADDR_EXPR, static_instances_decl, 0); + else + expr = integer_zero_node; + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + return objc_build_constructor (type, v); +} + +/* Take care of defining and initializing _OBJC_SYMBOLS. */ + +/* Predefine the following data type: + + struct _objc_symtab + { + long sel_ref_cnt; + SEL *refs; + short cls_def_cnt; + short cat_def_cnt; + void *defs[cls_def_cnt + cat_def_cnt]; + }; */ + +static void +build_objc_symtab_template (void) +{ + tree fields, array_type, *chain = NULL; + int index; + + objc_symtab_template = objc_start_struct (get_identifier (UTAG_SYMTAB)); + + /* long sel_ref_cnt; */ + fields = add_field_decl (long_integer_type_node, "sel_ref_cnt", &chain); + + /* SEL *refs; */ + add_field_decl (build_pointer_type (objc_selector_type), "refs", &chain); + + /* short cls_def_cnt; */ + add_field_decl (short_integer_type_node, "cls_def_cnt", &chain); + + /* short cat_def_cnt; */ + add_field_decl (short_integer_type_node, "cat_def_cnt", &chain); + + /* Note that padding will be added here on LP64. */ + + /* void *defs[imp_count + cat_count (+ 1)]; */ + /* NB: The index is one less than the size of the array. */ + index = imp_count + cat_count; + array_type = build_sized_array_type (ptr_type_node, index + 1); + add_field_decl (array_type, "defs", &chain); + + objc_finish_struct (objc_symtab_template, fields); +} +/* Construct the initial value for all of _objc_symtab. */ + +static tree +init_objc_symtab (tree type) +{ + tree field, expr, ltyp; + location_t loc; + VEC(constructor_elt,gc) *v = NULL; + + loc = UNKNOWN_LOCATION; + + /* sel_ref_cnt = { ..., 5, ... } */ + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (long_integer_type_node, 0)); + + /* refs = { ..., _OBJC_SELECTOR_TABLE, ... } */ + + ltyp = build_pointer_type (objc_selector_type); + if (sel_ref_chain) + expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, + UOBJC_SELECTOR_TABLE_decl, 1)); + else + expr = convert (ltyp, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); + + /* cls_def_cnt = { ..., 5, ... } */ + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (short_integer_type_node, imp_count)); + + /* cat_def_cnt = { ..., 5, ... } */ + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_int_cst (short_integer_type_node, cat_count)); + + /* cls_def = { ..., { &Foo, &Bar, ...}, ... } */ + + field = TYPE_FIELDS (type); + field = DECL_CHAIN (DECL_CHAIN (DECL_CHAIN (DECL_CHAIN (field)))); + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init_def_list (TREE_TYPE (field))); + + return objc_build_constructor (type, v); +} + +/* Create the declaration of _OBJC_SYMBOLS, with type `struct _objc_symtab' + and initialized appropriately. */ + +static void +generate_objc_symtab_decl (void) +{ + build_objc_symtab_template (); + UOBJC_SYMBOLS_decl = start_var_decl (objc_symtab_template, "_OBJC_SYMBOLS"); + OBJCMETA (UOBJC_SYMBOLS_decl, objc_meta, meta_base); + finish_var_decl (UOBJC_SYMBOLS_decl, + init_objc_symtab (TREE_TYPE (UOBJC_SYMBOLS_decl))); +} + +static void +objc_generate_v1_gnu_metadata (void) +{ + struct imp_entry *impent; + tree chain; + + /* Process the static instances here because initialization of objc_symtab + depends on them. */ + if (objc_static_instances) + generate_static_references (); + + objc_implementation_context = + implementation_template = + UOBJC_CLASS_decl = + UOBJC_METACLASS_decl = NULL_TREE; + + for (impent = imp_list; impent; impent = impent->next) + { + /* If -gen-decls is present, Dump the @interface of each class. + TODO: Dump the classes in the order they were found, rather than in + reverse order as we are doing now. */ + if (flag_gen_declaration) + dump_interface (gen_declaration_file, impent->imp_context); + + /* all of the following reference the string pool... */ + if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) + generate_class_structures (impent); + else + generate_category (impent); + } + + /* If we are using an array of selectors, we must always + finish up the array decl even if no selectors were used. */ + build_gnu_selector_translation_table (); + + if (protocol_chain) + generate_protocols (); + + /* Arrange for ObjC data structures to be initialized at run time. */ + /* FIXME: Have some more elegant way to determine if we need to + generate objc_symtab_decl or not, instead of checking these + global symbols. */ + if (imp_list || class_names_chain + || meth_var_names_chain || meth_var_types_chain || sel_ref_chain + || prop_names_attr_chain) + generate_objc_symtab_decl (); + + if (imp_list || class_names_chain || objc_static_instances + || meth_var_names_chain || meth_var_types_chain || sel_ref_chain) + { + /* Make sure that the meta-data are identified as being + GNU-runtime. */ + build_module_descriptor (OBJC_VERSION, + build_tree_list (objc_meta, meta_base)); + build_module_initializer_routine (); + } + + /* Dump the class references. This forces the appropriate classes + to be linked into the executable image, preserving unix archive + semantics. This can be removed when we move to a more dynamically + linked environment. */ + + for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain)) + { + handle_class_ref (chain); + if (TREE_PURPOSE (chain)) + generate_classref_translation_entry (chain); + } + + for (impent = imp_list; impent; impent = impent->next) + handle_impent (impent); + + generate_strings (); +} + +/* --- exceptions --- */ + +static GTY(()) tree objc_eh_personality_decl; + +static tree +objc_eh_runtime_type (tree type) +{ + tree ident, eh_id, decl, str; + + if (type == error_mark_node + || errorcount || sorrycount) + { + /* Use 'ErrorMarkNode' as class name when error_mark_node is found + to prevent an ICE. Note that we know that the compiler will + terminate with an error and this 'ErrorMarkNode' class name will + never be actually used. */ + ident = get_identifier ("ErrorMarkNode"); + goto make_err_class; + } + + if (POINTER_TYPE_P (type) && objc_is_object_id (TREE_TYPE (type))) + /* We don't want to identify 'id' for GNU. Instead, build a 0 + entry in the exceptions table. */ + return null_pointer_node; + + if (!POINTER_TYPE_P (type) || !TYPED_OBJECT (TREE_TYPE (type))) + { +#ifdef OBJCPLUS + /* This routine is also called for c++ catch clauses; in which case, + we use the c++ typeinfo decl. */ + return build_eh_type_type (type); +#else + error ("non-objective-c type '%T' cannot be caught", type); + ident = get_identifier ("ErrorMarkNode"); + goto make_err_class; +#endif + } + else + ident = OBJC_TYPE_NAME (TREE_TYPE (type)); + +make_err_class: + /* If this class was already referenced, then it will be output during + meta-data emission, so we don't need to do it here. */ + decl = get_objc_string_decl (ident, class_names); + eh_id = add_objc_string (ident, class_names); + if (!decl) + { + /* Not found ... so we need to build it - from the freshly-entered id. */ + decl = get_objc_string_decl (ident, class_names); + str = my_build_string (IDENTIFIER_LENGTH (ident) + 1, + IDENTIFIER_POINTER (ident)); + /* We have to finalize this var here, because this might be called after + all the other metadata strings have been emitted. */ + finish_var_decl (decl, str); + } + return eh_id; +} + +static tree +objc_eh_personality (void) +{ + if (!objc_eh_personality_decl) +#ifndef OBJCPLUS + objc_eh_personality_decl = build_personality_function ("gnu_objc"); +#else + objc_eh_personality_decl = build_personality_function ("gxx"); +#endif + return objc_eh_personality_decl; +} + +/* -- interfaces --- */ + +static tree +build_throw_stmt (location_t loc, tree throw_expr, bool rethrown ATTRIBUTE_UNUSED) +{ + tree t; + VEC(tree, gc) *parms = VEC_alloc (tree, gc, 1); + /* A throw is just a call to the runtime throw function with the + object as a parameter. */ + VEC_quick_push (tree, parms, throw_expr); + t = build_function_call_vec (loc, objc_exception_throw_decl, parms, NULL); + VEC_free (tree, gc, parms); + return add_stmt (t); +} + +/* Build __builtin_eh_pointer. */ + +static tree +objc_build_exc_ptr (struct objc_try_context **x ATTRIBUTE_UNUSED) +{ + tree t; + t = built_in_decls[BUILT_IN_EH_POINTER]; + t = build_call_expr (t, 1, integer_zero_node); + return fold_convert (objc_object_type, t); +} + +static tree +begin_catch (struct objc_try_context **cur_try_context, tree type, + tree decl, tree compound, bool ellipsis ATTRIBUTE_UNUSED) +{ + tree t; + /* Record the data for the catch in the try context so that we can + finalize it later. */ + if (ellipsis) + t = build_stmt (input_location, CATCH_EXPR, NULL, compound); + else + t = build_stmt (input_location, CATCH_EXPR, type, compound); + (*cur_try_context)->current_catch = t; + + /* Initialize the decl from the EXC_PTR_EXPR we get from the runtime. */ + t = objc_build_exc_ptr (cur_try_context); + t = convert (TREE_TYPE (decl), t); + return build2 (MODIFY_EXPR, void_type_node, decl, t); +} + +static void +finish_catch (struct objc_try_context **cur_try_context, tree current_catch) +{ + append_to_statement_list (current_catch, &((*cur_try_context)->catch_list)); +} + +static tree +finish_try_stmt (struct objc_try_context **cur_try_context) +{ + struct objc_try_context *c = *cur_try_context; + tree stmt = c->try_body; + if (c->catch_list) + stmt = build_stmt (c->try_locus, TRY_CATCH_EXPR, stmt, c->catch_list); + if (c->finally_body) + stmt = build_stmt (c->try_locus, TRY_FINALLY_EXPR, stmt, c->finally_body); + return stmt; +} + +#include "gt-objc-objc-gnu-runtime-abi-01.h" |