From: Hasso Tepper Date: Mon, 30 Jun 2008 11:22:39 +0000 (+0000) Subject: Add objc to the gcc-4.1.2. X-Git-Tag: v2.0.1~253^2 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/b52d95930f9c03ffaddebfd49d3a1b3de7746b92?hp=-c Add objc to the gcc-4.1.2. --- b52d95930f9c03ffaddebfd49d3a1b3de7746b92 diff --git a/contrib/gcc-4.1/gcc/objc/README b/contrib/gcc-4.1/gcc/objc/README new file mode 100644 index 0000000000..f478d67dec --- /dev/null +++ b/contrib/gcc-4.1/gcc/objc/README @@ -0,0 +1,97 @@ + +GNU Objective C notes +********************* + +This document is to explain what has been done, and a little about how +specific features differ from other implementations. The runtime has +been completely rewritten in gcc 2.4. The earlier runtime had several +severe bugs and was rather incomplete. The compiler has had several +new features added as well. + +This is not documentation for Objective C, it is usable to someone +who knows Objective C from somewhere else. + + +Runtime API functions +===================== + +The runtime is modeled after the NeXT Objective C runtime. That is, +most functions have semantics as it is known from the NeXT. The +names, however, have changed. All runtime API functions have names +of lowercase letters and underscores as opposed to the +`traditional' mixed case names. + The runtime api functions are not documented as of now. +Someone offered to write it, and did it, but we were not allowed to +use it by his university (Very sad story). We have started writing +the documentation over again. This will be announced in appropriate +places when it becomes available. + + +Protocols +========= + +Protocols are now fully supported. The semantics is exactly as on the +NeXT. There is a flag to specify how protocols should be typechecked +when adopted to classes. The normal typechecker requires that all +methods in a given protocol must be implemented in the class that +adopts it -- it is not enough to inherit them. The flag +`-Wno-protocol' causes it to allow inherited methods, while +`-Wprotocols' is the default which requires them defined. + + ++initialize +=========== + +This method, if defined, is called before any other instance or class +methods of that particular class. This method is not inherited, and +is thus not called as initializer for a subclass that doesn't define +it itself. Thus, each +initialize method is called exactly once (or +never if no methods of that particular class is never called). +Besides this, it is allowed to have several +initialize methods, one +for each category. The order in which these (multiple methods) are +called is not well defined. I am not completely certain what the +semantics of this method is for other implementations, but this is +how it works for GNU Objective C. + + +Passivation/Activation/Typedstreams +=================================== + +This is supported in the style of NeXT TypedStream's. Consult the +headerfile Typedstreams.h for api functions. I (Kresten) have +rewritten it in Objective C, but this implementation is not part of +2.4, it is available from the GNU Objective C prerelease archive. + There is one difference worth noting concerning objects stored with +objc_write_object_reference (aka NXWriteObjectReference). When these +are read back in, their object is not guaranteed to be available until +the `-awake' method is called in the object that requests that object. +To objc_read_object you must pass a pointer to an id, which is valid +after exit from the function calling it (like e.g. an instance +variable). In general, you should not use objects read in until the +-awake method is called. + + +Acknowledgements +================ + +The GNU Objective C team: Geoffrey Knauth (manager), +Tom Wood (compiler) and Kresten Krab Thorup + (runtime) would like to thank a some people for +participating in the development of the present GNU Objective C. + +Paul Burchard and Andrew McCallum + has been very helpful debugging the +runtime. Eric Herring has been very helpful +cleaning up after the documentation-copyright disaster and is now +helping with the new documentation. + +Steve Naroff and Richard Stallman + has been very helpful with implementation details +in the compiler. + + +Bug Reports +=========== + +Please read the section `Submitting Bugreports' of the gcc manual +before you submit any bugs. diff --git a/contrib/gcc-4.1/gcc/objc/lang-specs.h b/contrib/gcc-4.1/gcc/objc/lang-specs.h new file mode 100644 index 0000000000..446fd5336b --- /dev/null +++ b/contrib/gcc-4.1/gcc/objc/lang-specs.h @@ -0,0 +1,54 @@ +/* Definitions for specs for Objective-C. + Copyright (C) 1998, 1999, 2002, 2002, 2003, 2005 + Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* This is the contribution to the `default_compilers' array in gcc.c for + objc. */ + + {".m", "@objective-c", 0, 0, 0}, + {"@objective-c", + "%{E|M|MM:cc1obj -E %{traditional|ftraditional|traditional-cpp:-traditional-cpp}\ + %(cpp_options) %(cpp_debug_options)}\ + %{!E:%{!M:%{!MM:\ + %{traditional|ftraditional|traditional-cpp:\ +%eGNU Objective C no longer supports traditional compilation}\ + %{save-temps|no-integrated-cpp:cc1obj -E %(cpp_options) -o %{save-temps:%b.mi} %{!save-temps:%g.mi} \n\ + cc1obj -fpreprocessed %{save-temps:%b.mi} %{!save-temps:%g.mi} %(cc1_options) %{print-objc-runtime-info} %{gen-decls}}\ + %{!save-temps:%{!no-integrated-cpp:\ + cc1obj %(cpp_unique_options) %(cc1_options) %{print-objc-runtime-info} %{gen-decls}}}\ + %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 0}, + {".mi", "@objc-cpp-output", 0, 0, 0}, + {"@objc-cpp-output", + "%{!M:%{!MM:%{!E:cc1obj -fpreprocessed %i %(cc1_options) %{print-objc-runtime-info} %{gen-decls}\ + %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 0}, + {"@objective-c-header", + "%{E|M|MM:cc1obj -E %{traditional|ftraditional|traditional-cpp:-traditional-cpp}\ + %(cpp_options) %(cpp_debug_options)}\ + %{!E:%{!M:%{!MM:\ + %{traditional|ftraditional|traditional-cpp:\ +%eGNU Objective C no longer supports traditional compilation}\ + %{save-temps|no-integrated-cpp:cc1obj -E %(cpp_options) -o %{save-temps:%b.mi} %{!save-temps:%g.mi} \n\ + cc1obj -fpreprocessed %b.mi %(cc1_options) %{print-objc-runtime-info} %{gen-decls}\ + -o %g.s %{!o*:--output-pch=%i.gch}\ + %W{o*:--output-pch=%*}%V}\ + %{!save-temps:%{!no-integrated-cpp:\ + cc1obj %(cpp_unique_options) %(cc1_options) %{print-objc-runtime-info} %{gen-decls}\ + -o %g.s %{!o*:--output-pch=%i.gch}\ + %W{o*:--output-pch=%*}%V}}}}}", 0, 0, 0}, diff --git a/contrib/gcc-4.1/gcc/objc/objc-act.c b/contrib/gcc-4.1/gcc/objc/objc-act.c new file mode 100644 index 0000000000..8f07158e3e --- /dev/null +++ b/contrib/gcc-4.1/gcc/objc/objc-act.c @@ -0,0 +1,9509 @@ +/* Implement classes and message passing for Objective C. + Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Contributed by Steve Naroff. + +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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* Purpose: This module implements the Objective-C 4.0 language. + + compatibility issues (with the Stepstone translator): + + - does not recognize the following 3.3 constructs. + @requires, @classes, @messages, = (...) + - methods with variable arguments must conform to ANSI standard. + - tagged structure definitions that appear in BOTH the interface + and implementation are not allowed. + - public/private: all instance variables are public within the + context of the implementation...I consider this to be a bug in + the translator. + - statically allocated objects are not supported. the user will + receive an error if this service is requested. + + code generation `options': + + */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "tm_p.h" +#include "expr.h" + +#ifdef OBJCPLUS +#include "cp-tree.h" +#else +#include "c-tree.h" +#endif + +#include "c-common.h" +#include "c-pragma.h" +#include "flags.h" +#include "langhooks.h" +#include "objc-act.h" +#include "input.h" +#include "except.h" +#include "function.h" +#include "output.h" +#include "toplev.h" +#include "ggc.h" +#include "varray.h" +#include "debug.h" +#include "target.h" +#include "diagnostic.h" +#include "cgraph.h" +#include "tree-iterator.h" +#include "libfuncs.h" +#include "hashtab.h" +#include "langhooks-def.h" + +#define OBJC_VOID_AT_END void_list_node + +static unsigned int should_call_super_dealloc = 0; + +/* When building Objective-C++, we are not linking against the C front-end + 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 */ + +/* This is the default way of generating a method name. */ +/* I am not sure it is really correct. + Perhaps there's a danger that it will make name conflicts + if method names contain underscores. -- rms. */ +#ifndef OBJC_GEN_METHOD_LABEL +#define OBJC_GEN_METHOD_LABEL(BUF, IS_INST, CLASS_NAME, CAT_NAME, SEL_NAME, NUM) \ + do { \ + char *temp; \ + sprintf ((BUF), "_%s_%s_%s_%s", \ + ((IS_INST) ? "i" : "c"), \ + (CLASS_NAME), \ + ((CAT_NAME)? (CAT_NAME) : ""), \ + (SEL_NAME)); \ + for (temp = (BUF); *temp; temp++) \ + if (*temp == ':') *temp = '_'; \ + } while (0) +#endif + +/* These need specifying. */ +#ifndef OBJC_FORWARDING_STACK_OFFSET +#define OBJC_FORWARDING_STACK_OFFSET 0 +#endif + +#ifndef OBJC_FORWARDING_MIN_OFFSET +#define OBJC_FORWARDING_MIN_OFFSET 0 +#endif + +/* Set up for use of obstacks. */ + +#include "obstack.h" + +/* This obstack is used to accumulate the encoding of a data type. */ +static struct obstack util_obstack; + +/* This points to the beginning of obstack contents, so we can free + the whole contents. */ +char *util_firstobj; + +/* The version identifies which language generation and runtime + the module (file) was compiled for, and is recorded in the + module descriptor. */ + +#define OBJC_VERSION (flag_next_runtime ? 6 : 8) +#define PROTOCOL_VERSION 2 + +/* (Decide if these can ever be validly changed.) */ +#define OBJC_ENCODE_INLINE_DEFS 0 +#define OBJC_ENCODE_DONT_INLINE_DEFS 1 + +/*** Private Interface (procedures) ***/ + +/* Used by compile_file. */ + +static void init_objc (void); +static void finish_objc (void); + +/* Code generation. */ + +static tree objc_build_constructor (tree, tree); +static tree build_objc_method_call (int, tree, tree, tree, tree); +static tree get_proto_encoding (tree); +static tree lookup_interface (tree); +static tree objc_add_static_instance (tree, tree); + +static tree start_class (enum tree_code, tree, tree, tree); +static tree continue_class (tree); +static void finish_class (tree); +static void start_method_def (tree); +#ifdef OBJCPLUS +static void objc_start_function (tree, tree, tree, tree); +#else +static void objc_start_function (tree, tree, tree, struct c_arg_info *); +#endif +static tree start_protocol (enum tree_code, tree, tree); +static tree build_method_decl (enum tree_code, tree, tree, tree, bool); +static tree objc_add_method (tree, tree, int); +static tree add_instance_variable (tree, int, tree); +static tree build_ivar_reference (tree); +static tree is_ivar (tree, tree); + +static void build_objc_exception_stuff (void); +static void build_next_objc_exception_stuff (void); + +/* We only need the following for ObjC; ObjC++ will use C++'s definition + of DERIVED_FROM_P. */ +#ifndef OBJCPLUS +static bool objc_derived_from_p (tree, tree); +#define DERIVED_FROM_P(PARENT, CHILD) objc_derived_from_p (PARENT, CHILD) +#endif +static void objc_xref_basetypes (tree, tree); + +static void build_class_template (void); +static void build_selector_template (void); +static void build_category_template (void); +static void build_super_template (void); +static tree build_protocol_initializer (tree, tree, tree, tree, tree); +static tree get_class_ivars (tree, bool); +static tree generate_protocol_list (tree); +static void build_protocol_reference (tree); +static tree objc_build_volatilized_type (tree); + +#ifdef OBJCPLUS +static void objc_generate_cxx_cdtors (void); +#endif + +static const char *synth_id_with_class_suffix (const char *, tree); + +/* Hash tables to manage the global pool of method prototypes. */ + +hash *nst_method_hash_list = 0; +hash *cls_method_hash_list = 0; + +static hash hash_lookup (hash *, tree); +static tree lookup_method (tree, tree); +static tree lookup_method_static (tree, tree, int); + +enum string_section +{ + class_names, /* class, category, protocol, module names */ + meth_var_names, /* method and variable names */ + meth_var_types /* method and variable type descriptors */ +}; + +static tree add_objc_string (tree, enum string_section); +static tree build_objc_string_decl (enum string_section); +static void build_selector_table_decl (void); + +/* Protocol additions. */ + +static tree lookup_protocol (tree); +static tree lookup_and_install_protocols (tree); + +/* Type encoding. */ + +static void encode_type_qualifiers (tree); +static void encode_type (tree, int, int); +static void encode_field_decl (tree, int, int); + +#ifdef OBJCPLUS +static void really_start_method (tree, tree); +#else +static void really_start_method (tree, struct c_arg_info *); +#endif +static int comp_proto_with_proto (tree, tree, int); +static void objc_push_parm (tree); +#ifdef OBJCPLUS +static tree objc_get_parm_info (int); +#else +static struct c_arg_info *objc_get_parm_info (int); +#endif + +/* Utilities for debugging and error diagnostics. */ + +static void warn_with_method (const char *, int, tree); +static char *gen_type_name (tree); +static char *gen_type_name_0 (tree); +static char *gen_method_decl (tree); +static char *gen_declaration (tree); + +/* Everything else. */ + +static tree create_field_decl (tree, const char *); +static void add_class_reference (tree); +static void build_protocol_template (void); +static tree encode_method_prototype (tree); +static void generate_classref_translation_entry (tree); +static void handle_class_ref (tree); +static void generate_struct_by_value_array (void) + ATTRIBUTE_NORETURN; +static void mark_referenced_methods (void); +static void generate_objc_image_info (void); + +/*** Private Interface (data) ***/ + +/* Reserved tag definitions. */ + +#define OBJECT_TYPEDEF_NAME "id" +#define CLASS_TYPEDEF_NAME "Class" + +#define TAG_OBJECT "objc_object" +#define TAG_CLASS "objc_class" +#define TAG_SUPER "objc_super" +#define TAG_SELECTOR "objc_selector" + +#define UTAG_CLASS "_objc_class" +#define UTAG_IVAR "_objc_ivar" +#define UTAG_IVAR_LIST "_objc_ivar_list" +#define UTAG_METHOD "_objc_method" +#define UTAG_METHOD_LIST "_objc_method_list" +#define UTAG_CATEGORY "_objc_category" +#define UTAG_MODULE "_objc_module" +#define UTAG_SYMTAB "_objc_symtab" +#define UTAG_SUPER "_objc_super" +#define UTAG_SELECTOR "_objc_selector" + +#define UTAG_PROTOCOL "_objc_protocol" +#define UTAG_METHOD_PROTOTYPE "_objc_method_prototype" +#define UTAG_METHOD_PROTOTYPE_LIST "_objc__method_prototype_list" + +/* Note that the string object global name is only needed for the + NeXT runtime. */ +#define STRING_OBJECT_GLOBAL_FORMAT "_%sClassReference" + +#define PROTOCOL_OBJECT_CLASS_NAME "Protocol" + +static const char *TAG_GETCLASS; +static const char *TAG_GETMETACLASS; +static const char *TAG_MSGSEND; +static const char *TAG_MSGSENDSUPER; +/* The NeXT Objective-C messenger may have two extra entry points, for use + when returning a structure. */ +static const char *TAG_MSGSEND_STRET; +static const char *TAG_MSGSENDSUPER_STRET; +static const char *default_constant_string_class_name; + +/* Runtime metadata flags. */ +#define CLS_FACTORY 0x0001L +#define CLS_META 0x0002L +#define CLS_HAS_CXX_STRUCTORS 0x2000L + +#define OBJC_MODIFIER_STATIC 0x00000001 +#define OBJC_MODIFIER_FINAL 0x00000002 +#define OBJC_MODIFIER_PUBLIC 0x00000004 +#define OBJC_MODIFIER_PRIVATE 0x00000008 +#define OBJC_MODIFIER_PROTECTED 0x00000010 +#define OBJC_MODIFIER_NATIVE 0x00000020 +#define OBJC_MODIFIER_SYNCHRONIZED 0x00000040 +#define OBJC_MODIFIER_ABSTRACT 0x00000080 +#define OBJC_MODIFIER_VOLATILE 0x00000100 +#define OBJC_MODIFIER_TRANSIENT 0x00000200 +#define OBJC_MODIFIER_NONE_SPECIFIED 0x80000000 + +/* NeXT-specific tags. */ + +#define TAG_MSGSEND_NONNIL "objc_msgSendNonNil" +#define TAG_MSGSEND_NONNIL_STRET "objc_msgSendNonNil_stret" +#define TAG_EXCEPTIONEXTRACT "objc_exception_extract" +#define TAG_EXCEPTIONTRYENTER "objc_exception_try_enter" +#define TAG_EXCEPTIONTRYEXIT "objc_exception_try_exit" +#define TAG_EXCEPTIONMATCH "objc_exception_match" +#define TAG_EXCEPTIONTHROW "objc_exception_throw" +#define TAG_SYNCENTER "objc_sync_enter" +#define TAG_SYNCEXIT "objc_sync_exit" +#define TAG_SETJMP "_setjmp" +#define UTAG_EXCDATA "_objc_exception_data" + +#define TAG_ASSIGNIVAR "objc_assign_ivar" +#define TAG_ASSIGNGLOBAL "objc_assign_global" +#define TAG_ASSIGNSTRONGCAST "objc_assign_strongCast" + +/* Branch entry points. All that matters here are the addresses; + functions with these names do not really exist in libobjc. */ + +#define TAG_MSGSEND_FAST "objc_msgSend_Fast" +#define TAG_ASSIGNIVAR_FAST "objc_assign_ivar_Fast" + +#define TAG_CXX_CONSTRUCT ".cxx_construct" +#define TAG_CXX_DESTRUCT ".cxx_destruct" + +/* GNU-specific tags. */ + +#define TAG_EXECCLASS "__objc_exec_class" +#define TAG_GNUINIT "__objc_gnu_init" + +/* Flags for lookup_method_static(). */ +#define OBJC_LOOKUP_CLASS 1 /* Look for class methods. */ +#define OBJC_LOOKUP_NO_SUPER 2 /* Do not examine superclasses. */ + +/* The OCTI_... enumeration itself is in objc/objc-act.h. */ +tree objc_global_trees[OCTI_MAX]; + +static void handle_impent (struct imp_entry *); + +struct imp_entry *imp_list = 0; +int imp_count = 0; /* `@implementation' */ +int cat_count = 0; /* `@category' */ + +enum tree_code objc_inherit_code; +int objc_public_flag; + +/* Use to generate method labels. */ +static int method_slot = 0; + +#define BUFSIZE 1024 + +static char *errbuf; /* Buffer for error diagnostics */ + +/* Data imported from tree.c. */ + +extern enum debug_info_type write_symbols; + +/* Data imported from toplev.c. */ + +extern const char *dump_base_name; + +static int flag_typed_selectors; + +/* Store all constructed constant strings in a hash table so that + they get uniqued properly. */ + +struct string_descriptor GTY(()) +{ + /* The literal argument . */ + tree literal; + + /* The resulting constant string. */ + tree constructor; +}; + +static GTY((param_is (struct string_descriptor))) htab_t string_htab; + +/* Store the EH-volatilized types in a hash table, for easy retrieval. */ +struct volatilized_type GTY(()) +{ + tree type; +}; + +static GTY((param_is (struct volatilized_type))) htab_t volatilized_htab; + +FILE *gen_declaration_file; + +/* Tells "encode_pointer/encode_aggregate" whether we are generating + type descriptors for instance variables (as opposed to methods). + Type descriptors for instance variables contain more information + than methods (for static typing and embedded structures). */ + +static int generating_instance_variables = 0; + +/* Some platforms pass small structures through registers versus + through an invisible pointer. Determine at what size structure is + the transition point between the two possibilities. */ + +static void +generate_struct_by_value_array (void) +{ + tree type; + tree field_decl, field_decl_chain; + int i, j; + int aggregate_in_mem[32]; + int found = 0; + + /* Presumably no platform passes 32 byte structures in a register. */ + for (i = 1; i < 32; i++) + { + char buffer[5]; + + /* Create an unnamed struct that has `i' character components */ + type = start_struct (RECORD_TYPE, NULL_TREE); + + strcpy (buffer, "c1"); + field_decl = create_field_decl (char_type_node, + buffer); + field_decl_chain = field_decl; + + for (j = 1; j < i; j++) + { + sprintf (buffer, "c%d", j + 1); + field_decl = create_field_decl (char_type_node, + buffer); + chainon (field_decl_chain, field_decl); + } + finish_struct (type, field_decl_chain, NULL_TREE); + + aggregate_in_mem[i] = aggregate_value_p (type, 0); + if (!aggregate_in_mem[i]) + found = 1; + } + + /* We found some structures that are returned in registers instead of memory + so output the necessary data. */ + if (found) + { + for (i = 31; i >= 0; i--) + if (!aggregate_in_mem[i]) + break; + printf ("#define OBJC_MAX_STRUCT_BY_VALUE %d\n\n", i); + + /* The first member of the structure is always 0 because we don't handle + structures with 0 members */ + printf ("static int struct_forward_array[] = {\n 0"); + + for (j = 1; j <= i; j++) + printf (", %d", aggregate_in_mem[j]); + printf ("\n};\n"); + } + + exit (0); +} + +bool +objc_init (void) +{ +#ifdef OBJCPLUS + if (cxx_init () == false) +#else + if (c_objc_common_init () == false) +#endif + return false; + +#ifndef USE_MAPPED_LOCATION + /* Force the line number back to 0; check_newline will have + raised it to 1, which will make the builtin functions appear + not to be built in. */ + input_line = 0; +#endif + + /* If gen_declaration desired, open the output file. */ + if (flag_gen_declaration) + { + register char * const dumpname = concat (dump_base_name, ".decl", NULL); + gen_declaration_file = fopen (dumpname, "w"); + if (gen_declaration_file == 0) + fatal_error ("can't open %s: %m", dumpname); + free (dumpname); + } + + if (flag_next_runtime) + { + TAG_GETCLASS = "objc_getClass"; + TAG_GETMETACLASS = "objc_getMetaClass"; + TAG_MSGSEND = "objc_msgSend"; + TAG_MSGSENDSUPER = "objc_msgSendSuper"; + TAG_MSGSEND_STRET = "objc_msgSend_stret"; + TAG_MSGSENDSUPER_STRET = "objc_msgSendSuper_stret"; + default_constant_string_class_name = "NSConstantString"; + } + else + { + TAG_GETCLASS = "objc_get_class"; + TAG_GETMETACLASS = "objc_get_meta_class"; + TAG_MSGSEND = "objc_msg_lookup"; + TAG_MSGSENDSUPER = "objc_msg_lookup_super"; + /* GNU runtime does not provide special functions to support + structure-returning methods. */ + default_constant_string_class_name = "NXConstantString"; + flag_typed_selectors = 1; + } + + init_objc (); + + if (print_struct_values) + generate_struct_by_value_array (); + + return true; +} + +void +objc_finish_file (void) +{ + mark_referenced_methods (); + +#ifdef OBJCPLUS + /* We need to instantiate templates _before_ we emit ObjC metadata; + if we do not, some metadata (such as selectors) may go missing. */ + at_eof = 1; + instantiate_pending_templates (0); +#endif + + /* Finalize Objective-C runtime data. No need to generate tables + and code if only checking syntax, or if generating a PCH file. */ + if (!flag_syntax_only && !pch_file) + finish_objc (); + + if (gen_declaration_file) + fclose (gen_declaration_file); + +#ifdef OBJCPLUS + cp_finish_file (); +#endif +} + +/* Return the first occurrence of a method declaration corresponding + to sel_name in rproto_list. Search rproto_list recursively. + If is_class is 0, search for instance methods, otherwise for class + methods. */ +static tree +lookup_method_in_protocol_list (tree rproto_list, tree sel_name, + int is_class) +{ + tree rproto, p; + tree fnd = 0; + + for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) + { + p = TREE_VALUE (rproto); + + if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) + { + if ((fnd = lookup_method (is_class + ? PROTOCOL_CLS_METHODS (p) + : PROTOCOL_NST_METHODS (p), sel_name))) + ; + else if (PROTOCOL_LIST (p)) + fnd = lookup_method_in_protocol_list (PROTOCOL_LIST (p), + sel_name, is_class); + } + else + { + ; /* An identifier...if we could not find a protocol. */ + } + + if (fnd) + return fnd; + } + + return 0; +} + +static tree +lookup_protocol_in_reflist (tree rproto_list, tree lproto) +{ + tree rproto, p; + + /* Make sure the protocol is supported by the object on the rhs. */ + if (TREE_CODE (lproto) == PROTOCOL_INTERFACE_TYPE) + { + tree fnd = 0; + for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto)) + { + p = TREE_VALUE (rproto); + + if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) + { + if (lproto == p) + fnd = lproto; + + else if (PROTOCOL_LIST (p)) + fnd = lookup_protocol_in_reflist (PROTOCOL_LIST (p), lproto); + } + + if (fnd) + return fnd; + } + } + else + { + ; /* An identifier...if we could not find a protocol. */ + } + + return 0; +} + +void +objc_start_class_interface (tree class, tree super_class, tree protos) +{ + objc_interface_context + = objc_ivar_context + = start_class (CLASS_INTERFACE_TYPE, class, super_class, protos); + objc_public_flag = 0; +} + +void +objc_start_category_interface (tree class, tree categ, tree protos) +{ + objc_interface_context + = start_class (CATEGORY_INTERFACE_TYPE, class, categ, protos); + objc_ivar_chain + = continue_class (objc_interface_context); +} + +void +objc_start_protocol (tree name, tree protos) +{ + objc_interface_context + = start_protocol (PROTOCOL_INTERFACE_TYPE, name, protos); +} + +void +objc_continue_interface (void) +{ + objc_ivar_chain + = continue_class (objc_interface_context); +} + +void +objc_finish_interface (void) +{ + finish_class (objc_interface_context); + objc_interface_context = NULL_TREE; +} + +void +objc_start_class_implementation (tree class, tree super_class) +{ + objc_implementation_context + = objc_ivar_context + = start_class (CLASS_IMPLEMENTATION_TYPE, class, super_class, NULL_TREE); + objc_public_flag = 0; +} + +void +objc_start_category_implementation (tree class, tree categ) +{ + objc_implementation_context + = start_class (CATEGORY_IMPLEMENTATION_TYPE, class, categ, NULL_TREE); + objc_ivar_chain + = continue_class (objc_implementation_context); +} + +void +objc_continue_implementation (void) +{ + objc_ivar_chain + = continue_class (objc_implementation_context); +} + +void +objc_finish_implementation (void) +{ +#ifdef OBJCPLUS + if (flag_objc_call_cxx_cdtors) + objc_generate_cxx_cdtors (); +#endif + + if (objc_implementation_context) + { + finish_class (objc_implementation_context); + objc_ivar_chain = NULL_TREE; + objc_implementation_context = NULL_TREE; + } + else + warning (0, "%<@end%> must appear in an @implementation context"); +} + +void +objc_set_visibility (int visibility) +{ + objc_public_flag = visibility; +} + +void +objc_set_method_type (enum tree_code type) +{ + objc_inherit_code = (type == PLUS_EXPR + ? CLASS_METHOD_DECL + : INSTANCE_METHOD_DECL); +} + +tree +objc_build_method_signature (tree rettype, tree selector, + tree optparms, bool ellipsis) +{ + return build_method_decl (objc_inherit_code, rettype, selector, + optparms, ellipsis); +} + +void +objc_add_method_declaration (tree decl) +{ + if (!objc_interface_context) + fatal_error ("method declaration not in @interface context"); + + objc_add_method (objc_interface_context, + decl, + objc_inherit_code == CLASS_METHOD_DECL); +} + +void +objc_start_method_definition (tree decl) +{ + if (!objc_implementation_context) + fatal_error ("method definition not in @implementation context"); + + objc_add_method (objc_implementation_context, + decl, + objc_inherit_code == CLASS_METHOD_DECL); + start_method_def (decl); +} + +void +objc_add_instance_variable (tree decl) +{ + (void) add_instance_variable (objc_ivar_context, + objc_public_flag, + decl); +} + +/* Return 1 if IDENT is an ObjC/ObjC++ reserved keyword in the context of + an '@'. */ + +int +objc_is_reserved_word (tree ident) +{ + unsigned char code = C_RID_CODE (ident); + + return (OBJC_IS_AT_KEYWORD (code) +#ifdef OBJCPLUS + || code == RID_CLASS || code == RID_PUBLIC + || code == RID_PROTECTED || code == RID_PRIVATE + || code == RID_TRY || code == RID_THROW || code == RID_CATCH +#endif + ); +} + +/* Return true if TYPE is 'id'. */ + +static bool +objc_is_object_id (tree type) +{ + return OBJC_TYPE_NAME (type) == objc_object_id; +} + +static bool +objc_is_class_id (tree type) +{ + return OBJC_TYPE_NAME (type) == objc_class_id; +} + +/* Construct a C struct with same name as CLASS, a base struct with tag + SUPER_NAME (if any), and FIELDS indicated. */ + +static tree +objc_build_struct (tree class, tree fields, tree super_name) +{ + tree name = CLASS_NAME (class); + tree s = start_struct (RECORD_TYPE, name); + tree super = (super_name ? xref_tag (RECORD_TYPE, super_name) : NULL_TREE); + tree t, objc_info = NULL_TREE; + + if (super) + { + /* Prepend a packed variant of the base class into the layout. This + is necessary to preserve ObjC ABI compatibility. */ + tree base = build_decl (FIELD_DECL, NULL_TREE, super); + tree field = TYPE_FIELDS (super); + + while (field && TREE_CHAIN (field) + && TREE_CODE (TREE_CHAIN (field)) == FIELD_DECL) + field = TREE_CHAIN (field); + + /* For ObjC ABI purposes, the "packed" size of a base class is the + the sum of the offset and the size (in bits) of the last field + in the class. */ + DECL_SIZE (base) + = (field && TREE_CODE (field) == FIELD_DECL + ? size_binop (PLUS_EXPR, + size_binop (PLUS_EXPR, + size_binop + (MULT_EXPR, + convert (bitsizetype, + DECL_FIELD_OFFSET (field)), + bitsize_int (BITS_PER_UNIT)), + DECL_FIELD_BIT_OFFSET (field)), + DECL_SIZE (field)) + : bitsize_zero_node); + DECL_SIZE_UNIT (base) + = size_binop (FLOOR_DIV_EXPR, convert (sizetype, DECL_SIZE (base)), + size_int (BITS_PER_UNIT)); + DECL_ARTIFICIAL (base) = 1; + DECL_ALIGN (base) = 1; + DECL_FIELD_CONTEXT (base) = s; +#ifdef OBJCPLUS + DECL_FIELD_IS_BASE (base) = 1; + + if (fields) + TREE_NO_WARNING (fields) = 1; /* Suppress C++ ABI warnings -- we */ +#endif /* are following the ObjC ABI here. */ + TREE_CHAIN (base) = fields; + fields = base; + } + + /* NB: Calling finish_struct() may cause type TYPE_LANG_SPECIFIC fields + in all variants of this RECORD_TYPE to be clobbered, but it is therein + that we store protocol conformance info (e.g., 'NSObject '). + Hence, we must squirrel away the ObjC-specific information before calling + finish_struct(), and then reinstate it afterwards. */ + + for (t = TYPE_NEXT_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t)) + objc_info + = chainon (objc_info, + build_tree_list (NULL_TREE, TYPE_OBJC_INFO (t))); + + /* Point the struct at its related Objective-C class. */ + INIT_TYPE_OBJC_INFO (s); + TYPE_OBJC_INTERFACE (s) = class; + + s = finish_struct (s, fields, NULL_TREE); + + for (t = TYPE_NEXT_VARIANT (s); t; + t = TYPE_NEXT_VARIANT (t), objc_info = TREE_CHAIN (objc_info)) + { + TYPE_OBJC_INFO (t) = TREE_VALUE (objc_info); + /* Replace the IDENTIFIER_NODE with an actual @interface. */ + TYPE_OBJC_INTERFACE (t) = class; + } + + /* Use TYPE_BINFO structures to point at the super class, if any. */ + objc_xref_basetypes (s, super); + + /* Mark this struct as a class template. */ + CLASS_STATIC_TEMPLATE (class) = s; + + return s; +} + +/* Build a type differing from TYPE only in that TYPE_VOLATILE is set. + Unlike tree.c:build_qualified_type(), preserve TYPE_LANG_SPECIFIC in the + process. */ +static tree +objc_build_volatilized_type (tree type) +{ + tree t; + + /* Check if we have not constructed the desired variant already. */ + for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) + { + /* The type qualifiers must (obviously) match up. */ + if (!TYPE_VOLATILE (t) + || (TYPE_READONLY (t) != TYPE_READONLY (type)) + || (TYPE_RESTRICT (t) != TYPE_RESTRICT (type))) + continue; + + /* For pointer types, the pointees (and hence their TYPE_LANG_SPECIFIC + info, if any) must match up. */ + if (POINTER_TYPE_P (t) + && (TREE_TYPE (t) != TREE_TYPE (type))) + continue; + + /* Everything matches up! */ + return t; + } + + /* Ok, we could not re-use any of the pre-existing variants. Create + a new one. */ + t = build_variant_type_copy (type); + TYPE_VOLATILE (t) = 1; + + return t; +} + +/* Mark DECL as being 'volatile' for purposes of Darwin + _setjmp()/_longjmp() exception handling. Called from + objc_mark_locals_volatile(). */ +void +objc_volatilize_decl (tree decl) +{ + /* Do not mess with variables that are 'static' or (already) + 'volatile'. */ + if (!TREE_THIS_VOLATILE (decl) && !TREE_STATIC (decl) + && (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == PARM_DECL)) + { + tree t = TREE_TYPE (decl); + struct volatilized_type key; + void **loc; + + t = objc_build_volatilized_type (t); + key.type = t; + loc = htab_find_slot (volatilized_htab, &key, INSERT); + + if (!*loc) + { + *loc = ggc_alloc (sizeof (key)); + ((struct volatilized_type *) *loc)->type = t; + } + + TREE_TYPE (decl) = t; + TREE_THIS_VOLATILE (decl) = 1; + TREE_SIDE_EFFECTS (decl) = 1; + DECL_REGISTER (decl) = 0; +#ifndef OBJCPLUS + C_DECL_REGISTER (decl) = 0; +#endif + } +} + +/* Check if protocol PROTO is adopted (directly or indirectly) by class CLS + (including its categoreis and superclasses) or by object type TYP. + Issue a warning if PROTO is not adopted anywhere and WARN is set. */ + +static bool +objc_lookup_protocol (tree proto, tree cls, tree typ, bool warn) +{ + bool class_type = (cls != NULL_TREE); + + while (cls) + { + tree c; + + /* Check protocols adopted by the class and its categories. */ + for (c = cls; c; c = CLASS_CATEGORY_LIST (c)) + { + if (lookup_protocol_in_reflist (CLASS_PROTOCOL_LIST (c), proto)) + return true; + } + + /* Repeat for superclasses. */ + cls = lookup_interface (CLASS_SUPER_NAME (cls)); + } + + /* Check for any protocols attached directly to the object type. */ + if (TYPE_HAS_OBJC_INFO (typ)) + { + if (lookup_protocol_in_reflist (TYPE_OBJC_PROTOCOL_LIST (typ), proto)) + return true; + } + + if (warn) + { + strcpy (errbuf, class_type ? "class \'" : "type \'"); + gen_type_name_0 (class_type ? typ : TYPE_POINTER_TO (typ)); + strcat (errbuf, "\' does not "); + /* NB: Types 'id' and 'Class' cannot reasonably be described as + "implementing" a given protocol, since they do not have an + implementation. */ + strcat (errbuf, class_type ? "implement" : "conform to"); + strcat (errbuf, " the \'"); + strcat (errbuf, IDENTIFIER_POINTER (PROTOCOL_NAME (proto))); + strcat (errbuf, "\' protocol"); + warning (0, errbuf); + } + + return false; +} + +/* Check if class RCLS and instance struct type RTYP conform to at least the + same protocols that LCLS and LTYP conform to. */ + +static bool +objc_compare_protocols (tree lcls, tree ltyp, tree rcls, tree rtyp, bool warn) +{ + tree p; + bool have_lproto = false; + + while (lcls) + { + /* NB: We do _not_ look at categories defined for LCLS; these may or + may not get loaded in, and therefore it is unreasonable to require + that RCLS/RTYP must implement any of their protocols. */ + for (p = CLASS_PROTOCOL_LIST (lcls); p; p = TREE_CHAIN (p)) + { + have_lproto = true; + + if (!objc_lookup_protocol (TREE_VALUE (p), rcls, rtyp, warn)) + return warn; + } + + /* Repeat for superclasses. */ + lcls = lookup_interface (CLASS_SUPER_NAME (lcls)); + } + + /* Check for any protocols attached directly to the object type. */ + if (TYPE_HAS_OBJC_INFO (ltyp)) + { + for (p = TYPE_OBJC_PROTOCOL_LIST (ltyp); p; p = TREE_CHAIN (p)) + { + have_lproto = true; + + if (!objc_lookup_protocol (TREE_VALUE (p), rcls, rtyp, warn)) + return warn; + } + } + + /* NB: If LTYP and LCLS have no protocols to search for, return 'true' + vacuously, _unless_ RTYP is a protocol-qualified 'id'. We can get + away with simply checking for 'id' or 'Class' (!RCLS), since this + routine will not get called in other cases. */ + return have_lproto || (rcls != NULL_TREE); +} + +/* Determine if it is permissible to assign (if ARGNO is greater than -3) + an instance of RTYP to an instance of LTYP or to compare the two + (if ARGNO is equal to -3), per ObjC type system rules. Before + returning 'true', this routine may issue warnings related to, e.g., + protocol conformance. When returning 'false', the routine must + produce absolutely no warnings; the C or C++ front-end will do so + instead, if needed. If either LTYP or RTYP is not an Objective-C type, + the routine must return 'false'. + + The ARGNO parameter is encoded as follows: + >= 1 Parameter number (CALLEE contains function being called); + 0 Return value; + -1 Assignment; + -2 Initialization; + -3 Comparison (LTYP and RTYP may match in either direction). */ + +bool +objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee) +{ + tree lcls, rcls, lproto, rproto; + bool pointers_compatible; + + /* We must be dealing with pointer types */ + if (!POINTER_TYPE_P (ltyp) || !POINTER_TYPE_P (rtyp)) + return false; + + do + { + ltyp = TREE_TYPE (ltyp); /* Remove indirections. */ + rtyp = TREE_TYPE (rtyp); + } + while (POINTER_TYPE_P (ltyp) && POINTER_TYPE_P (rtyp)); + + /* Past this point, we are only interested in ObjC class instances, + or 'id' or 'Class'. */ + if (TREE_CODE (ltyp) != RECORD_TYPE || TREE_CODE (rtyp) != RECORD_TYPE) + return false; + + if (!objc_is_object_id (ltyp) && !objc_is_class_id (ltyp) + && !TYPE_HAS_OBJC_INFO (ltyp)) + return false; + + if (!objc_is_object_id (rtyp) && !objc_is_class_id (rtyp) + && !TYPE_HAS_OBJC_INFO (rtyp)) + return false; + + /* Past this point, we are committed to returning 'true' to the caller. + However, we can still warn about type and/or protocol mismatches. */ + + if (TYPE_HAS_OBJC_INFO (ltyp)) + { + lcls = TYPE_OBJC_INTERFACE (ltyp); + lproto = TYPE_OBJC_PROTOCOL_LIST (ltyp); + } + else + lcls = lproto = NULL_TREE; + + if (TYPE_HAS_OBJC_INFO (rtyp)) + { + rcls = TYPE_OBJC_INTERFACE (rtyp); + rproto = TYPE_OBJC_PROTOCOL_LIST (rtyp); + } + else + rcls = rproto = NULL_TREE; + + /* If we could not find an @interface declaration, we must have + only seen a @class declaration; for purposes of type comparison, + treat it as a stand-alone (root) class. */ + + if (lcls && TREE_CODE (lcls) == IDENTIFIER_NODE) + lcls = NULL_TREE; + + if (rcls && TREE_CODE (rcls) == IDENTIFIER_NODE) + rcls = NULL_TREE; + + /* If either type is an unqualified 'id', we're done. */ + if ((!lproto && objc_is_object_id (ltyp)) + || (!rproto && objc_is_object_id (rtyp))) + return true; + + pointers_compatible = (TYPE_MAIN_VARIANT (ltyp) == TYPE_MAIN_VARIANT (rtyp)); + + /* If the underlying types are the same, and at most one of them has + a protocol list, we do not need to issue any diagnostics. */ + if (pointers_compatible && (!lproto || !rproto)) + return true; + + /* If exactly one of the types is 'Class', issue a diagnostic; any + exceptions of this rule have already been handled. */ + if (objc_is_class_id (ltyp) ^ objc_is_class_id (rtyp)) + pointers_compatible = false; + /* Otherwise, check for inheritance relations. */ + else + { + if (!pointers_compatible) + pointers_compatible + = (objc_is_object_id (ltyp) || objc_is_object_id (rtyp)); + + if (!pointers_compatible) + pointers_compatible = DERIVED_FROM_P (ltyp, rtyp); + + if (!pointers_compatible && argno == -3) + pointers_compatible = DERIVED_FROM_P (rtyp, ltyp); + } + + /* If the pointers match modulo protocols, check for protocol conformance + mismatches. */ + if (pointers_compatible) + { + pointers_compatible = objc_compare_protocols (lcls, ltyp, rcls, rtyp, + argno != -3); + + if (!pointers_compatible && argno == -3) + pointers_compatible = objc_compare_protocols (rcls, rtyp, lcls, ltyp, + argno != -3); + } + + if (!pointers_compatible) + { + /* NB: For the time being, we shall make our warnings look like their + C counterparts. In the future, we may wish to make them more + ObjC-specific. */ + switch (argno) + { + case -3: + warning (0, "comparison of distinct Objective-C types lacks a cast"); + break; + + case -2: + warning (0, "initialization from distinct Objective-C type"); + break; + + case -1: + warning (0, "assignment from distinct Objective-C type"); + break; + + case 0: + warning (0, "distinct Objective-C type in return"); + break; + + default: + warning (0, "passing argument %d of %qE from distinct " + "Objective-C type", argno, callee); + break; + } + } + + return true; +} + +/* Check if LTYP and RTYP have the same type qualifiers. If either type + lives in the volatilized hash table, ignore the 'volatile' bit when + making the comparison. */ + +bool +objc_type_quals_match (tree ltyp, tree rtyp) +{ + int lquals = TYPE_QUALS (ltyp), rquals = TYPE_QUALS (rtyp); + struct volatilized_type key; + + key.type = ltyp; + + if (htab_find_slot (volatilized_htab, &key, NO_INSERT)) + lquals &= ~TYPE_QUAL_VOLATILE; + + key.type = rtyp; + + if (htab_find_slot (volatilized_htab, &key, NO_INSERT)) + rquals &= ~TYPE_QUAL_VOLATILE; + + return (lquals == rquals); +} + +#ifndef OBJCPLUS +/* Determine if CHILD is derived from PARENT. The routine assumes that + both parameters are RECORD_TYPEs, and is non-reflexive. */ + +static bool +objc_derived_from_p (tree parent, tree child) +{ + parent = TYPE_MAIN_VARIANT (parent); + + for (child = TYPE_MAIN_VARIANT (child); + TYPE_BINFO (child) && BINFO_N_BASE_BINFOS (TYPE_BINFO (child));) + { + child = TYPE_MAIN_VARIANT (BINFO_TYPE (BINFO_BASE_BINFO + (TYPE_BINFO (child), + 0))); + + if (child == parent) + return true; + } + + return false; +} +#endif + +static tree +objc_build_component_ref (tree datum, tree component) +{ + /* If COMPONENT is NULL, the caller is referring to the anonymous + base class field. */ + if (!component) + { + tree base = TYPE_FIELDS (TREE_TYPE (datum)); + + return build3 (COMPONENT_REF, TREE_TYPE (base), datum, base, NULL_TREE); + } + + /* The 'build_component_ref' routine has been removed from the C++ + front-end, but 'finish_class_member_access_expr' seems to be + a worthy substitute. */ +#ifdef OBJCPLUS + return finish_class_member_access_expr (datum, component, false); +#else + return build_component_ref (datum, component); +#endif +} + +/* Recursively copy inheritance information rooted at BINFO. To do this, + we emulate the song and dance performed by cp/tree.c:copy_binfo(). */ + +static tree +objc_copy_binfo (tree binfo) +{ + tree btype = BINFO_TYPE (binfo); + tree binfo2 = make_tree_binfo (BINFO_N_BASE_BINFOS (binfo)); + tree base_binfo; + int ix; + + BINFO_TYPE (binfo2) = btype; + BINFO_OFFSET (binfo2) = BINFO_OFFSET (binfo); + BINFO_BASE_ACCESSES (binfo2) = BINFO_BASE_ACCESSES (binfo); + + /* Recursively copy base binfos of BINFO. */ + for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++) + { + tree base_binfo2 = objc_copy_binfo (base_binfo); + + BINFO_INHERITANCE_CHAIN (base_binfo2) = binfo2; + BINFO_BASE_APPEND (binfo2, base_binfo2); + } + + return binfo2; +} + +/* Record superclass information provided in BASETYPE for ObjC class REF. + This is loosely based on cp/decl.c:xref_basetypes(). */ + +static void +objc_xref_basetypes (tree ref, tree basetype) +{ + tree binfo = make_tree_binfo (basetype ? 1 : 0); + + TYPE_BINFO (ref) = binfo; + BINFO_OFFSET (binfo) = size_zero_node; + BINFO_TYPE (binfo) = ref; + + if (basetype) + { + tree base_binfo = objc_copy_binfo (TYPE_BINFO (basetype)); + + BINFO_INHERITANCE_CHAIN (base_binfo) = binfo; + BINFO_BASE_ACCESSES (binfo) = VEC_alloc (tree, gc, 1); + BINFO_BASE_APPEND (binfo, base_binfo); + BINFO_BASE_ACCESS_APPEND (binfo, access_public_node); + } +} + +static hashval_t +volatilized_hash (const void *ptr) +{ + tree typ = ((struct volatilized_type *)ptr)->type; + + return htab_hash_pointer(typ); +} + +static int +volatilized_eq (const void *ptr1, const void *ptr2) +{ + tree typ1 = ((struct volatilized_type *)ptr1)->type; + tree typ2 = ((struct volatilized_type *)ptr2)->type; + + return typ1 == typ2; +} + +/* Called from finish_decl. */ + +void +objc_check_decl (tree decl) +{ + tree type = TREE_TYPE (decl); + + if (TREE_CODE (type) != RECORD_TYPE) + return; + if (OBJC_TYPE_NAME (type) && (type = objc_is_class_name (OBJC_TYPE_NAME (type)))) + error ("statically allocated instance of Objective-C class %qs", + IDENTIFIER_POINTER (type)); +} + +/* Construct a PROTOCOLS-qualified variant of INTERFACE, where INTERFACE may + either name an Objective-C class, or refer to the special 'id' or 'Class' + types. If INTERFACE is not a valid ObjC type, just return it unchanged. */ + +tree +objc_get_protocol_qualified_type (tree interface, tree protocols) +{ + /* If INTERFACE is not provided, default to 'id'. */ + tree type = (interface ? objc_is_id (interface) : objc_object_type); + bool is_ptr = (type != NULL_TREE); + + if (!is_ptr) + { + type = objc_is_class_name (interface); + + if (type) + type = xref_tag (RECORD_TYPE, type); + else + return interface; + } + + if (protocols) + { + type = build_variant_type_copy (type); + + /* For pointers (i.e., 'id' or 'Class'), attach the protocol(s) + to the pointee. */ + if (is_ptr) + { + TREE_TYPE (type) = build_variant_type_copy (TREE_TYPE (type)); + TYPE_POINTER_TO (TREE_TYPE (type)) = type; + type = TREE_TYPE (type); + } + + /* Look up protocols and install in lang specific list. */ + DUP_TYPE_OBJC_INFO (type, TYPE_MAIN_VARIANT (type)); + TYPE_OBJC_PROTOCOL_LIST (type) = lookup_and_install_protocols (protocols); + + /* For RECORD_TYPEs, point to the @interface; for 'id' and 'Class', + return the pointer to the new pointee variant. */ + if (is_ptr) + type = TYPE_POINTER_TO (type); + else + TYPE_OBJC_INTERFACE (type) + = TYPE_OBJC_INTERFACE (TYPE_MAIN_VARIANT (type)); + } + + return type; +} + +/* Check for circular dependencies in protocols. The arguments are + PROTO, the protocol to check, and LIST, a list of protocol it + conforms to. */ + +static void +check_protocol_recursively (tree proto, tree list) +{ + tree p; + + for (p = list; p; p = TREE_CHAIN (p)) + { + tree pp = TREE_VALUE (p); + + if (TREE_CODE (pp) == IDENTIFIER_NODE) + pp = lookup_protocol (pp); + + if (pp == proto) + fatal_error ("protocol %qs has circular dependency", + IDENTIFIER_POINTER (PROTOCOL_NAME (pp))); + if (pp) + check_protocol_recursively (proto, PROTOCOL_LIST (pp)); + } +} + +/* Look up PROTOCOLS, and return a list of those that are found. + If none are found, return NULL. */ + +static tree +lookup_and_install_protocols (tree protocols) +{ + tree proto; + tree return_value = NULL_TREE; + + for (proto = protocols; proto; proto = TREE_CHAIN (proto)) + { + tree ident = TREE_VALUE (proto); + tree p = lookup_protocol (ident); + + if (!p) + error ("cannot find protocol declaration for %qs", + IDENTIFIER_POINTER (ident)); + else + return_value = chainon (return_value, + build_tree_list (NULL_TREE, p)); + } + + return return_value; +} + +/* Create a declaration for field NAME of a given TYPE. */ + +static tree +create_field_decl (tree type, const char *name) +{ + return build_decl (FIELD_DECL, get_identifier (name), type); +} + +/* Create a global, static declaration for variable NAME of a given TYPE. The + finish_var_decl() routine will need to be called on it afterwards. */ + +static tree +start_var_decl (tree type, const char *name) +{ + tree var = build_decl (VAR_DECL, get_identifier (name), type); + + TREE_STATIC (var) = 1; + DECL_INITIAL (var) = error_mark_node; /* A real initializer is coming... */ + DECL_IGNORED_P (var) = 1; + DECL_ARTIFICIAL (var) = 1; + DECL_CONTEXT (var) = NULL_TREE; +#ifdef OBJCPLUS + DECL_THIS_STATIC (var) = 1; /* squash redeclaration errors */ +#endif + + return var; +} + +/* Finish off the variable declaration created by start_var_decl(). */ + +static void +finish_var_decl (tree var, tree initializer) +{ + finish_decl (var, initializer, NULL_TREE); + /* Ensure that the variable actually gets output. */ + mark_decl_referenced (var); + /* Mark the decl to avoid "defined but not used" warning. */ + TREE_USED (var) = 1; +} + +/* Find the decl for the constant string class reference. This is only + used for the NeXT runtime. */ + +static tree +setup_string_decl (void) +{ + char *name; + size_t length; + + /* %s in format will provide room for terminating null */ + length = strlen (STRING_OBJECT_GLOBAL_FORMAT) + + strlen (constant_string_class_name); + name = xmalloc (length); + sprintf (name, STRING_OBJECT_GLOBAL_FORMAT, + constant_string_class_name); + constant_string_global_id = get_identifier (name); + string_class_decl = lookup_name (constant_string_global_id); + + return string_class_decl; +} + +/* Purpose: "play" parser, creating/installing representations + of the declarations that are required by Objective-C. + + Model: + + type_spec--------->sc_spec + (tree_list) (tree_list) + | | + | | + identifier_node identifier_node */ + +static void +synth_module_prologue (void) +{ + tree type; + enum debug_info_type save_write_symbols = write_symbols; + const struct gcc_debug_hooks *const save_hooks = debug_hooks; + + /* Suppress outputting debug symbols, because + dbxout_init hasn'r been called yet. */ + write_symbols = NO_DEBUG; + debug_hooks = &do_nothing_debug_hooks; + +#ifdef OBJCPLUS + push_lang_context (lang_name_c); /* extern "C" */ +#endif + + /* The following are also defined in and friends. */ + + objc_object_id = get_identifier (TAG_OBJECT); + objc_class_id = get_identifier (TAG_CLASS); + + objc_object_reference = xref_tag (RECORD_TYPE, objc_object_id); + objc_class_reference = xref_tag (RECORD_TYPE, objc_class_id); + + objc_object_type = build_pointer_type (objc_object_reference); + objc_class_type = build_pointer_type (objc_class_reference); + + objc_object_name = get_identifier (OBJECT_TYPEDEF_NAME); + objc_class_name = get_identifier (CLASS_TYPEDEF_NAME); + + /* Declare the 'id' and 'Class' typedefs. */ + + type = lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, + objc_object_name, + objc_object_type)); + DECL_IN_SYSTEM_HEADER (type) = 1; + type = lang_hooks.decls.pushdecl (build_decl (TYPE_DECL, + objc_class_name, + objc_class_type)); + DECL_IN_SYSTEM_HEADER (type) = 1; + + /* Forward-declare '@interface Protocol'. */ + + type = get_identifier (PROTOCOL_OBJECT_CLASS_NAME); + objc_declare_class (tree_cons (NULL_TREE, type, NULL_TREE)); + objc_protocol_type = build_pointer_type (xref_tag (RECORD_TYPE, + type)); + + /* Declare type of selector-objects that represent an operation name. */ + + if (flag_next_runtime) + /* `struct objc_selector *' */ + objc_selector_type + = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (TAG_SELECTOR))); + else + /* `const struct objc_selector *' */ + objc_selector_type + = build_pointer_type + (build_qualified_type (xref_tag (RECORD_TYPE, + get_identifier (TAG_SELECTOR)), + TYPE_QUAL_CONST)); + + /* Declare receiver type used for dispatching messages to 'super'. */ + + /* `struct objc_super *' */ + objc_super_type = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (TAG_SUPER))); + + /* Declare pointers to method and ivar lists. */ + objc_method_list_ptr = build_pointer_type + (xref_tag (RECORD_TYPE, + get_identifier (UTAG_METHOD_LIST))); + objc_method_proto_list_ptr + = build_pointer_type (xref_tag (RECORD_TYPE, + get_identifier (UTAG_METHOD_PROTOTYPE_LIST))); + objc_ivar_list_ptr = build_pointer_type + (xref_tag (RECORD_TYPE, + get_identifier (UTAG_IVAR_LIST))); + + /* TREE_NOTHROW is cleared for the message-sending functions, + because the function that gets called can throw in Obj-C++, or + could itself call something that can throw even in Obj-C. */ + + if (flag_next_runtime) + { + /* NB: In order to call one of the ..._stret (struct-returning) + functions, the function *MUST* first be cast to a signature that + corresponds to the actual ObjC method being invoked. This is + what is done by the build_objc_method_call() routine below. */ + + /* id objc_msgSend (id, SEL, ...); */ + /* id objc_msgSendNonNil (id, SEL, ...); */ + /* id objc_msgSend_stret (id, SEL, ...); */ + /* id objc_msgSendNonNil_stret (id, SEL, ...); */ + type + = build_function_type (objc_object_type, + tree_cons (NULL_TREE, objc_object_type, + tree_cons (NULL_TREE, objc_selector_type, + NULL_TREE))); + umsg_decl = builtin_function (TAG_MSGSEND, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + umsg_nonnil_decl = builtin_function (TAG_MSGSEND_NONNIL, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + umsg_stret_decl = builtin_function (TAG_MSGSEND_STRET, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + umsg_nonnil_stret_decl = builtin_function (TAG_MSGSEND_NONNIL_STRET, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + /* These can throw, because the function that gets called can throw + in Obj-C++, or could itself call something that can throw even + in Obj-C. */ + TREE_NOTHROW (umsg_decl) = 0; + TREE_NOTHROW (umsg_nonnil_decl) = 0; + TREE_NOTHROW (umsg_stret_decl) = 0; + TREE_NOTHROW (umsg_nonnil_stret_decl) = 0; + + /* id objc_msgSend_Fast (id, SEL, ...) + __attribute__ ((hard_coded_address (OFFS_MSGSEND_FAST))); */ +#ifdef OFFS_MSGSEND_FAST + umsg_fast_decl = builtin_function (TAG_MSGSEND_FAST, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (umsg_fast_decl) = 0; + DECL_ATTRIBUTES (umsg_fast_decl) + = tree_cons (get_identifier ("hard_coded_address"), + build_int_cst (NULL_TREE, OFFS_MSGSEND_FAST), + NULL_TREE); +#else + /* No direct dispatch availible. */ + umsg_fast_decl = umsg_decl; +#endif + + /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */ + /* id objc_msgSendSuper_stret (struct objc_super *, SEL, ...); */ + type + = build_function_type (objc_object_type, + tree_cons (NULL_TREE, objc_super_type, + tree_cons (NULL_TREE, objc_selector_type, + NULL_TREE))); + umsg_super_decl = builtin_function (TAG_MSGSENDSUPER, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + umsg_super_stret_decl = builtin_function (TAG_MSGSENDSUPER_STRET, + type, 0, NOT_BUILT_IN, 0, + NULL_TREE); + TREE_NOTHROW (umsg_super_decl) = 0; + TREE_NOTHROW (umsg_super_stret_decl) = 0; + } + else + { + /* GNU runtime messenger entry points. */ + + /* typedef id (*IMP)(id, SEL, ...); */ + tree IMP_type + = build_pointer_type + (build_function_type (objc_object_type, + tree_cons (NULL_TREE, objc_object_type, + tree_cons (NULL_TREE, objc_selector_type, + NULL_TREE)))); + + /* IMP objc_msg_lookup (id, SEL); */ + type + = build_function_type (IMP_type, + tree_cons (NULL_TREE, objc_object_type, + tree_cons (NULL_TREE, objc_selector_type, + OBJC_VOID_AT_END))); + umsg_decl = 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 (IMP_type, + tree_cons (NULL_TREE, objc_super_type, + tree_cons (NULL_TREE, objc_selector_type, + OBJC_VOID_AT_END))); + umsg_super_decl = 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 (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + OBJC_VOID_AT_END)); + execclass_decl = builtin_function (TAG_EXECCLASS, + type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + } + + /* id objc_getClass (const char *); */ + + type = build_function_type (objc_object_type, + tree_cons (NULL_TREE, + const_string_type_node, + OBJC_VOID_AT_END)); + + objc_get_class_decl + = builtin_function (TAG_GETCLASS, type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + + /* id objc_getMetaClass (const char *); */ + + objc_get_meta_class_decl + = builtin_function (TAG_GETMETACLASS, type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + + build_class_template (); + build_super_template (); + build_protocol_template (); + build_category_template (); + build_objc_exception_stuff (); + + if (flag_next_runtime) + build_next_objc_exception_stuff (); + + /* static SEL _OBJC_SELECTOR_TABLE[]; */ + + if (! flag_next_runtime) + build_selector_table_decl (); + + /* Forward declare constant_string_id and constant_string_type. */ + if (!constant_string_class_name) + constant_string_class_name = default_constant_string_class_name; + + constant_string_id = get_identifier (constant_string_class_name); + objc_declare_class (tree_cons (NULL_TREE, constant_string_id, NULL_TREE)); + + /* Pre-build the following entities - for speed/convenience. */ + self_id = get_identifier ("self"); + ucmd_id = get_identifier ("_cmd"); + +#ifdef OBJCPLUS + pop_lang_context (); +#endif + + write_symbols = save_write_symbols; + debug_hooks = save_hooks; +} + +/* Ensure that the ivar list for NSConstantString/NXConstantString + (or whatever was specified via `-fconstant-string-class') + contains fields at least as large as the following three, so that + the runtime can stomp on them with confidence: + + struct STRING_OBJECT_CLASS_NAME + { + Object isa; + char *cString; + unsigned int length; + }; */ + +static int +check_string_class_template (void) +{ + tree field_decl = objc_get_class_ivars (constant_string_id); + +#define AT_LEAST_AS_LARGE_AS(F, T) \ + (F && TREE_CODE (F) == FIELD_DECL \ + && (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (F))) \ + >= TREE_INT_CST_LOW (TYPE_SIZE (T)))) + + if (!AT_LEAST_AS_LARGE_AS (field_decl, ptr_type_node)) + return 0; + + field_decl = TREE_CHAIN (field_decl); + if (!AT_LEAST_AS_LARGE_AS (field_decl, ptr_type_node)) + return 0; + + field_decl = TREE_CHAIN (field_decl); + return AT_LEAST_AS_LARGE_AS (field_decl, unsigned_type_node); + +#undef AT_LEAST_AS_LARGE_AS +} + +/* Avoid calling `check_string_class_template ()' more than once. */ +static GTY(()) int string_layout_checked; + +/* Construct an internal string layout to be used as a template for + creating NSConstantString/NXConstantString instances. */ + +static tree +objc_build_internal_const_str_type (void) +{ + tree type = (*lang_hooks.types.make_type) (RECORD_TYPE); + tree fields = build_decl (FIELD_DECL, NULL_TREE, ptr_type_node); + tree field = build_decl (FIELD_DECL, NULL_TREE, ptr_type_node); + + TREE_CHAIN (field) = fields; fields = field; + field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node); + TREE_CHAIN (field) = fields; fields = field; + /* NB: The finish_builtin_struct() routine expects FIELD_DECLs in + reverse order! */ + finish_builtin_struct (type, "__builtin_ObjCString", + fields, NULL_TREE); + + return type; +} + +/* Custom build_string which sets TREE_TYPE! */ + +static tree +my_build_string (int len, const char *str) +{ + return fix_string_type (build_string (len, str)); +} + +/* Build a string with contents STR and length LEN and convert it to a + pointer. */ + +static tree +my_build_string_pointer (int len, const char *str) +{ + tree string = my_build_string (len, str); + tree ptrtype = build_pointer_type (TREE_TYPE (TREE_TYPE (string))); + return build1 (ADDR_EXPR, ptrtype, string); +} + +static hashval_t +string_hash (const void *ptr) +{ + tree str = ((struct string_descriptor *)ptr)->literal; + const unsigned char *p = (const unsigned char *) TREE_STRING_POINTER (str); + int i, len = TREE_STRING_LENGTH (str); + hashval_t h = len; + + for (i = 0; i < len; i++) + h = ((h * 613) + p[i]); + + return h; +} + +static int +string_eq (const void *ptr1, const void *ptr2) +{ + tree str1 = ((struct string_descriptor *)ptr1)->literal; + tree str2 = ((struct string_descriptor *)ptr2)->literal; + int len1 = TREE_STRING_LENGTH (str1); + + return (len1 == TREE_STRING_LENGTH (str2) + && !memcmp (TREE_STRING_POINTER (str1), TREE_STRING_POINTER (str2), + len1)); +} + +/* Given a chain of STRING_CST's, build a static instance of + NXConstantString which points at the concatenation of those + strings. We place the string object in the __string_objects + section of the __OBJC segment. The Objective-C runtime will + initialize the isa pointers of the string objects to point at the + NXConstantString class object. */ + +tree +objc_build_string_object (tree string) +{ + tree initlist, constructor, constant_string_class; + int length; + tree fields, addr; + struct string_descriptor *desc, key; + void **loc; + + /* Prep the string argument. */ + string = fix_string_type (string); + TREE_SET_CODE (string, STRING_CST); + length = TREE_STRING_LENGTH (string) - 1; + + /* Check whether the string class being used actually exists and has the + correct ivar layout. */ + if (!string_layout_checked) + { + string_layout_checked = -1; + constant_string_class = lookup_interface (constant_string_id); + internal_const_str_type = objc_build_internal_const_str_type (); + + if (!constant_string_class + || !(constant_string_type + = CLASS_STATIC_TEMPLATE (constant_string_class))) + error ("cannot find interface declaration for %qs", + IDENTIFIER_POINTER (constant_string_id)); + /* The NSConstantString/NXConstantString ivar layout is now known. */ + else if (!check_string_class_template ()) + error ("interface %qs does not have valid constant string layout", + IDENTIFIER_POINTER (constant_string_id)); + /* For the NeXT runtime, we can generate a literal reference + to the string class, don't need to run a constructor. */ + else if (flag_next_runtime && !setup_string_decl ()) + error ("cannot find reference tag for class %qs", + IDENTIFIER_POINTER (constant_string_id)); + else + { + string_layout_checked = 1; /* Success! */ + add_class_reference (constant_string_id); + } + } + + if (string_layout_checked == -1) + return error_mark_node; + + /* Perhaps we already constructed a constant string just like this one? */ + key.literal = string; + loc = htab_find_slot (string_htab, &key, INSERT); + desc = *loc; + + if (!desc) + { + tree var; + *loc = desc = ggc_alloc (sizeof (*desc)); + desc->literal = string; + + /* GNU: (NXConstantString *) & ((__builtin_ObjCString) { NULL, string, length }) */ + /* NeXT: (NSConstantString *) & ((__builtin_ObjCString) { isa, string, length }) */ + fields = TYPE_FIELDS (internal_const_str_type); + initlist + = build_tree_list (fields, + flag_next_runtime + ? build_unary_op (ADDR_EXPR, string_class_decl, 0) + : build_int_cst (NULL_TREE, 0)); + fields = TREE_CHAIN (fields); + initlist = tree_cons (fields, build_unary_op (ADDR_EXPR, string, 1), + initlist); + fields = TREE_CHAIN (fields); + initlist = tree_cons (fields, build_int_cst (NULL_TREE, length), + initlist); + constructor = objc_build_constructor (internal_const_str_type, + nreverse (initlist)); + TREE_INVARIANT (constructor) = true; + + if (!flag_next_runtime) + constructor + = objc_add_static_instance (constructor, constant_string_type); + else + { + var = build_decl (CONST_DECL, NULL, TREE_TYPE (constructor)); + DECL_INITIAL (var) = constructor; + TREE_STATIC (var) = 1; + pushdecl_top_level (var); + constructor = var; + } + desc->constructor = constructor; + } + + addr = convert (build_pointer_type (constant_string_type), + build_unary_op (ADDR_EXPR, desc->constructor, 1)); + + return addr; +} + +/* Declare a static instance of CLASS_DECL initialized by CONSTRUCTOR. */ + +static GTY(()) int num_static_inst; + +static tree +objc_add_static_instance (tree constructor, tree class_decl) +{ + tree *chain, decl; + char buf[256]; + + /* Find the list of static instances for the CLASS_DECL. Create one if + not found. */ + for (chain = &objc_static_instances; + *chain && TREE_VALUE (*chain) != class_decl; + chain = &TREE_CHAIN (*chain)); + if (!*chain) + { + *chain = tree_cons (NULL_TREE, class_decl, NULL_TREE); + add_objc_string (OBJC_TYPE_NAME (class_decl), class_names); + } + + sprintf (buf, "_OBJC_INSTANCE_%d", num_static_inst++); + decl = build_decl (VAR_DECL, get_identifier (buf), class_decl); + DECL_COMMON (decl) = 1; + TREE_STATIC (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + TREE_USED (decl) = 1; + DECL_INITIAL (decl) = constructor; + + /* We may be writing something else just now. + Postpone till end of input. */ + DECL_DEFER_OUTPUT (decl) = 1; + pushdecl_top_level (decl); + rest_of_decl_compilation (decl, 1, 0); + + /* Add the DECL to the head of this CLASS' list. */ + TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, decl, TREE_PURPOSE (*chain)); + + return decl; +} + +/* Build a static constant CONSTRUCTOR + with type TYPE and elements ELTS. */ + +static tree +objc_build_constructor (tree type, tree elts) +{ + tree constructor = build_constructor_from_list (type, elts); + + TREE_CONSTANT (constructor) = 1; + TREE_STATIC (constructor) = 1; + TREE_READONLY (constructor) = 1; + +#ifdef OBJCPLUS + /* Adjust for impedance mismatch. We should figure out how to build + CONSTRUCTORs that consistently please both the C and C++ gods. */ + if (!TREE_PURPOSE (elts)) + TREE_TYPE (constructor) = NULL_TREE; + TREE_HAS_CONSTRUCTOR (constructor) = 1; +#endif + + return constructor; +} + +/* Take care of defining and initializing _OBJC_SYMBOLS. */ + +/* Predefine the following data type: + + struct _objc_symtab + { + long sel_ref_cnt; + SEL *refs; + short cls_def_cnt; + short cat_def_cnt; + void *defs[cls_def_cnt + cat_def_cnt]; + }; */ + +static void +build_objc_symtab_template (void) +{ + tree field_decl, field_decl_chain; + + objc_symtab_template + = start_struct (RECORD_TYPE, get_identifier (UTAG_SYMTAB)); + + /* long sel_ref_cnt; */ + field_decl = create_field_decl (long_integer_type_node, "sel_ref_cnt"); + field_decl_chain = field_decl; + + /* SEL *refs; */ + field_decl = create_field_decl (build_pointer_type (objc_selector_type), + "refs"); + chainon (field_decl_chain, field_decl); + + /* short cls_def_cnt; */ + field_decl = create_field_decl (short_integer_type_node, "cls_def_cnt"); + chainon (field_decl_chain, field_decl); + + /* short cat_def_cnt; */ + field_decl = create_field_decl (short_integer_type_node, + "cat_def_cnt"); + chainon (field_decl_chain, field_decl); + + if (imp_count || cat_count || !flag_next_runtime) + { + /* void *defs[imp_count + cat_count (+ 1)]; */ + /* NB: The index is one less than the size of the array. */ + int index = imp_count + cat_count + + (flag_next_runtime? -1: 0); + field_decl = create_field_decl + (build_array_type + (ptr_type_node, + build_index_type (build_int_cst (NULL_TREE, index))), + "defs"); + chainon (field_decl_chain, field_decl); + } + + finish_struct (objc_symtab_template, field_decl_chain, NULL_TREE); +} + +/* Create the initial value for the `defs' field of _objc_symtab. + This is a CONSTRUCTOR. */ + +static tree +init_def_list (tree type) +{ + tree expr, initlist = NULL_TREE; + struct imp_entry *impent; + + if (imp_count) + for (impent = imp_list; impent; impent = impent->next) + { + if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) + { + expr = build_unary_op (ADDR_EXPR, impent->class_decl, 0); + initlist = tree_cons (NULL_TREE, expr, initlist); + } + } + + if (cat_count) + for (impent = imp_list; impent; impent = impent->next) + { + if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE) + { + expr = build_unary_op (ADDR_EXPR, impent->class_decl, 0); + initlist = tree_cons (NULL_TREE, expr, initlist); + } + } + + if (!flag_next_runtime) + { + /* statics = { ..., _OBJC_STATIC_INSTANCES, ... } */ + tree expr; + + if (static_instances_decl) + expr = build_unary_op (ADDR_EXPR, static_instances_decl, 0); + else + expr = build_int_cst (NULL_TREE, 0); + + initlist = tree_cons (NULL_TREE, expr, initlist); + } + + return objc_build_constructor (type, nreverse (initlist)); +} + +/* Construct the initial value for all of _objc_symtab. */ + +static tree +init_objc_symtab (tree type) +{ + tree initlist; + + /* sel_ref_cnt = { ..., 5, ... } */ + + initlist = build_tree_list (NULL_TREE, + build_int_cst (long_integer_type_node, 0)); + + /* refs = { ..., _OBJC_SELECTOR_TABLE, ... } */ + + if (flag_next_runtime || ! sel_ref_chain) + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + else + initlist + = tree_cons (NULL_TREE, + convert (build_pointer_type (objc_selector_type), + build_unary_op (ADDR_EXPR, + UOBJC_SELECTOR_TABLE_decl, 1)), + initlist); + + /* cls_def_cnt = { ..., 5, ... } */ + + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, imp_count), initlist); + + /* cat_def_cnt = { ..., 5, ... } */ + + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, cat_count), initlist); + + /* cls_def = { ..., { &Foo, &Bar, ...}, ... } */ + + if (imp_count || cat_count || !flag_next_runtime) + { + + tree field = TYPE_FIELDS (type); + field = TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (field)))); + + initlist = tree_cons (NULL_TREE, init_def_list (TREE_TYPE (field)), + initlist); + } + + return objc_build_constructor (type, nreverse (initlist)); +} + +/* Generate forward declarations for metadata such as + 'OBJC_CLASS_...'. */ + +static tree +build_metadata_decl (const char *name, tree type) +{ + tree decl; + + /* struct TYPE NAME_; */ + decl = start_var_decl (type, synth_id_with_class_suffix + (name, + objc_implementation_context)); + + return decl; +} + +/* Push forward-declarations of all the categories so that + init_def_list can use them in a CONSTRUCTOR. */ + +static void +forward_declare_categories (void) +{ + struct imp_entry *impent; + tree sav = objc_implementation_context; + + for (impent = imp_list; impent; impent = impent->next) + { + if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE) + { + /* Set an invisible arg to synth_id_with_class_suffix. */ + objc_implementation_context = impent->imp_context; + /* extern struct objc_category _OBJC_CATEGORY_; */ + impent->class_decl = build_metadata_decl ("_OBJC_CATEGORY", + objc_category_template); + } + } + objc_implementation_context = sav; +} + +/* Create the declaration of _OBJC_SYMBOLS, with type `struct _objc_symtab' + and initialized appropriately. */ + +static void +generate_objc_symtab_decl (void) +{ + /* forward declare categories */ + if (cat_count) + forward_declare_categories (); + + build_objc_symtab_template (); + UOBJC_SYMBOLS_decl = start_var_decl (objc_symtab_template, "_OBJC_SYMBOLS"); + finish_var_decl (UOBJC_SYMBOLS_decl, + init_objc_symtab (TREE_TYPE (UOBJC_SYMBOLS_decl))); +} + +static tree +init_module_descriptor (tree type) +{ + tree initlist, expr; + + /* version = { 1, ... } */ + + expr = build_int_cst (long_integer_type_node, OBJC_VERSION); + initlist = build_tree_list (NULL_TREE, expr); + + /* size = { ..., sizeof (struct _objc_module), ... } */ + + expr = convert (long_integer_type_node, + size_in_bytes (objc_module_template)); + initlist = tree_cons (NULL_TREE, expr, initlist); + + /* name = { ..., "foo.m", ... } */ + + expr = add_objc_string (get_identifier (input_filename), class_names); + initlist = tree_cons (NULL_TREE, expr, initlist); + + /* symtab = { ..., _OBJC_SYMBOLS, ... } */ + + if (UOBJC_SYMBOLS_decl) + expr = build_unary_op (ADDR_EXPR, UOBJC_SYMBOLS_decl, 0); + else + expr = build_int_cst (NULL_TREE, 0); + initlist = tree_cons (NULL_TREE, expr, initlist); + + return objc_build_constructor (type, nreverse (initlist)); +} + +/* Write out the data structures to describe Objective C classes defined. + + struct _objc_module { ... } _OBJC_MODULE = { ... }; */ + +static void +build_module_descriptor (void) +{ + tree field_decl, field_decl_chain; + +#ifdef OBJCPLUS + push_lang_context (lang_name_c); /* extern "C" */ +#endif + + objc_module_template + = start_struct (RECORD_TYPE, get_identifier (UTAG_MODULE)); + + /* long version; */ + field_decl = create_field_decl (long_integer_type_node, "version"); + field_decl_chain = field_decl; + + /* long size; */ + field_decl = create_field_decl (long_integer_type_node, "size"); + chainon (field_decl_chain, field_decl); + + /* char *name; */ + field_decl = create_field_decl (string_type_node, "name"); + chainon (field_decl_chain, field_decl); + + /* struct _objc_symtab *symtab; */ + field_decl + = create_field_decl (build_pointer_type + (xref_tag (RECORD_TYPE, + get_identifier (UTAG_SYMTAB))), + "symtab"); + chainon (field_decl_chain, field_decl); + + finish_struct (objc_module_template, field_decl_chain, NULL_TREE); + + /* Create an instance of "_objc_module". */ + UOBJC_MODULES_decl = start_var_decl (objc_module_template, "_OBJC_MODULES"); + finish_var_decl (UOBJC_MODULES_decl, + init_module_descriptor (TREE_TYPE (UOBJC_MODULES_decl))); + +#ifdef OBJCPLUS + pop_lang_context (); +#endif +} + +/* The GNU runtime requires us to provide a static initializer function + for each module: + + static void __objc_gnu_init (void) { + __objc_exec_class (&L_OBJC_MODULES); + } */ + +static void +build_module_initializer_routine (void) +{ + tree body; + +#ifdef OBJCPLUS + push_lang_context (lang_name_c); /* extern "C" */ +#endif + + objc_push_parm (build_decl (PARM_DECL, NULL_TREE, void_type_node)); + objc_start_function (get_identifier (TAG_GNUINIT), + build_function_type (void_type_node, + OBJC_VOID_AT_END), + NULL_TREE, objc_get_parm_info (0)); + + body = c_begin_compound_stmt (true); + add_stmt (build_function_call + (execclass_decl, + build_tree_list + (NULL_TREE, + build_unary_op (ADDR_EXPR, + UOBJC_MODULES_decl, 0)))); + add_stmt (c_end_compound_stmt (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 (EXPR_STMT, + build_function_call (GNU_INIT_decl, NULL_TREE))); + + return ctors; +} +#endif /* OBJCPLUS */ + +/* Return the DECL of the string IDENT in the SECTION. */ + +static tree +get_objc_string_decl (tree ident, enum string_section section) +{ + tree chain; + + if (section == class_names) + chain = class_names_chain; + else if (section == meth_var_names) + chain = meth_var_names_chain; + else if (section == meth_var_types) + chain = meth_var_types_chain; + else + abort (); + + for (; chain != 0; chain = TREE_CHAIN (chain)) + if (TREE_VALUE (chain) == ident) + return (TREE_PURPOSE (chain)); + + abort (); + return NULL_TREE; +} + +/* Output references to all statically allocated objects. Return the DECL + for the array built. */ + +static void +generate_static_references (void) +{ + tree decls = NULL_TREE, expr = NULL_TREE; + tree class_name, class, decl, initlist; + tree cl_chain, in_chain, type + = build_array_type (build_pointer_type (void_type_node), NULL_TREE); + int num_inst, num_class; + char buf[256]; + + if (flag_next_runtime) + abort (); + + for (cl_chain = objc_static_instances, num_class = 0; + cl_chain; cl_chain = TREE_CHAIN (cl_chain), num_class++) + { + for (num_inst = 0, in_chain = TREE_PURPOSE (cl_chain); + in_chain; num_inst++, in_chain = TREE_CHAIN (in_chain)); + + sprintf (buf, "_OBJC_STATIC_INSTANCES_%d", num_class); + decl = start_var_decl (type, buf); + + /* Output {class_name, ...}. */ + class = TREE_VALUE (cl_chain); + class_name = get_objc_string_decl (OBJC_TYPE_NAME (class), class_names); + initlist = build_tree_list (NULL_TREE, + build_unary_op (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 (ADDR_EXPR, TREE_VALUE (in_chain), 1); + initlist = tree_cons (NULL_TREE, expr, initlist); + } + + /* Output {..., NULL}. */ + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + + expr = objc_build_constructor (TREE_TYPE (decl), nreverse (initlist)); + finish_var_decl (decl, expr); + decls + = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, decl, 1), decls); + } + + decls = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), decls); + expr = objc_build_constructor (type, nreverse (decls)); + static_instances_decl = start_var_decl (type, "_OBJC_STATIC_INSTANCES"); + finish_var_decl (static_instances_decl, expr); +} + +static GTY(()) int selector_reference_idx; + +static tree +build_selector_reference_decl (void) +{ + tree decl; + char buf[256]; + + sprintf (buf, "_OBJC_SELECTOR_REFERENCES_%d", selector_reference_idx++); + decl = start_var_decl (objc_selector_type, buf); + + return decl; +} + +static void +build_selector_table_decl (void) +{ + tree temp; + + if (flag_typed_selectors) + { + build_selector_template (); + temp = build_array_type (objc_selector_template, NULL_TREE); + } + else + temp = build_array_type (objc_selector_type, NULL_TREE); + + UOBJC_SELECTOR_TABLE_decl = start_var_decl (temp, "_OBJC_SELECTOR_TABLE"); +} + +/* Just a handy wrapper for add_objc_string. */ + +static tree +build_selector (tree ident) +{ + return convert (objc_selector_type, + add_objc_string (ident, meth_var_names)); +} + +static void +build_selector_translation_table (void) +{ + tree chain, initlist = NULL_TREE; + int offset = 0; + tree decl = NULL_TREE; + + for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain)) + { + tree expr; + + if (warn_selector && objc_implementation_context) + { + tree method_chain; + bool found = false; + for (method_chain = meth_var_names_chain; + method_chain; + method_chain = TREE_CHAIN (method_chain)) + { + if (TREE_VALUE (method_chain) == TREE_VALUE (chain)) + { + found = true; + break; + } + } + if (!found) + { + location_t *loc; + if (flag_next_runtime && TREE_PURPOSE (chain)) + loc = &DECL_SOURCE_LOCATION (TREE_PURPOSE (chain)); + else + loc = &input_location; + warning (0, "%Hcreating selector for nonexistent method %qE", + loc, TREE_VALUE (chain)); + } + } + + expr = build_selector (TREE_VALUE (chain)); + /* add one for the '\0' character */ + offset += IDENTIFIER_LENGTH (TREE_VALUE (chain)) + 1; + + if (flag_next_runtime) + { + decl = TREE_PURPOSE (chain); + finish_var_decl (decl, expr); + } + else + { + if (flag_typed_selectors) + { + tree eltlist = NULL_TREE; + tree encoding = get_proto_encoding (TREE_PURPOSE (chain)); + eltlist = tree_cons (NULL_TREE, expr, NULL_TREE); + eltlist = tree_cons (NULL_TREE, encoding, eltlist); + expr = objc_build_constructor (objc_selector_template, + nreverse (eltlist)); + } + + initlist = tree_cons (NULL_TREE, expr, initlist); + } + } + + if (! flag_next_runtime) + { + /* Cause the selector table (previously forward-declared) + to be actually output. */ + initlist = tree_cons (NULL_TREE, + flag_typed_selectors + ? objc_build_constructor + (objc_selector_template, + tree_cons (NULL_TREE, + build_int_cst (NULL_TREE, 0), + tree_cons (NULL_TREE, + build_int_cst (NULL_TREE, 0), + NULL_TREE))) + : build_int_cst (NULL_TREE, 0), initlist); + initlist = objc_build_constructor (TREE_TYPE (UOBJC_SELECTOR_TABLE_decl), + nreverse (initlist)); + finish_var_decl (UOBJC_SELECTOR_TABLE_decl, initlist); + } +} + +static tree +get_proto_encoding (tree proto) +{ + tree encoding; + if (proto) + { + if (! METHOD_ENCODING (proto)) + { + encoding = encode_method_prototype (proto); + METHOD_ENCODING (proto) = encoding; + } + else + encoding = METHOD_ENCODING (proto); + + return add_objc_string (encoding, meth_var_types); + } + else + return build_int_cst (NULL_TREE, 0); +} + +/* sel_ref_chain is a list whose "value" fields will be instances of + identifier_node that represent the selector. */ + +static tree +build_typed_selector_reference (tree ident, tree prototype) +{ + tree *chain = &sel_ref_chain; + tree expr; + int index = 0; + + while (*chain) + { + if (TREE_PURPOSE (*chain) == prototype && TREE_VALUE (*chain) == ident) + goto return_at_index; + + index++; + chain = &TREE_CHAIN (*chain); + } + + *chain = tree_cons (prototype, ident, NULL_TREE); + + return_at_index: + expr = build_unary_op (ADDR_EXPR, + build_array_ref (UOBJC_SELECTOR_TABLE_decl, + build_int_cst (NULL_TREE, index)), + 1); + return convert (objc_selector_type, expr); +} + +static tree +build_selector_reference (tree ident) +{ + tree *chain = &sel_ref_chain; + tree expr; + int index = 0; + + while (*chain) + { + if (TREE_VALUE (*chain) == ident) + return (flag_next_runtime + ? TREE_PURPOSE (*chain) + : build_array_ref (UOBJC_SELECTOR_TABLE_decl, + build_int_cst (NULL_TREE, index))); + + index++; + chain = &TREE_CHAIN (*chain); + } + + expr = (flag_next_runtime ? build_selector_reference_decl (): NULL_TREE); + + *chain = tree_cons (expr, ident, NULL_TREE); + + return (flag_next_runtime + ? expr + : build_array_ref (UOBJC_SELECTOR_TABLE_decl, + build_int_cst (NULL_TREE, index))); +} + +static GTY(()) int class_reference_idx; + +static tree +build_class_reference_decl (void) +{ + tree decl; + char buf[256]; + + sprintf (buf, "_OBJC_CLASS_REFERENCES_%d", class_reference_idx++); + decl = start_var_decl (objc_class_type, buf); + + return decl; +} + +/* Create a class reference, but don't create a variable to reference + it. */ + +static void +add_class_reference (tree ident) +{ + tree chain; + + if ((chain = cls_ref_chain)) + { + tree tail; + do + { + if (ident == TREE_VALUE (chain)) + return; + + tail = chain; + chain = TREE_CHAIN (chain); + } + while (chain); + + /* Append to the end of the list */ + TREE_CHAIN (tail) = tree_cons (NULL_TREE, ident, NULL_TREE); + } + else + cls_ref_chain = tree_cons (NULL_TREE, ident, NULL_TREE); +} + +/* Get a class reference, creating it if necessary. Also create the + reference variable. */ + +tree +objc_get_class_reference (tree ident) +{ + tree orig_ident = (DECL_P (ident) + ? DECL_NAME (ident) + : TYPE_P (ident) + ? OBJC_TYPE_NAME (ident) + : ident); + bool local_scope = false; + +#ifdef OBJCPLUS + if (processing_template_decl) + /* Must wait until template instantiation time. */ + return build_min_nt (CLASS_REFERENCE_EXPR, ident); +#endif + + if (TREE_CODE (ident) == TYPE_DECL) + ident = (DECL_ORIGINAL_TYPE (ident) + ? DECL_ORIGINAL_TYPE (ident) + : TREE_TYPE (ident)); + +#ifdef OBJCPLUS + if (TYPE_P (ident) && TYPE_CONTEXT (ident) + && TYPE_CONTEXT (ident) != global_namespace) + local_scope = true; +#endif + + if (local_scope || !(ident = objc_is_class_name (ident))) + { + error ("%qs is not an Objective-C class name or alias", + IDENTIFIER_POINTER (orig_ident)); + return error_mark_node; + } + + if (flag_next_runtime && !flag_zero_link) + { + tree *chain; + tree decl; + + for (chain = &cls_ref_chain; *chain; chain = &TREE_CHAIN (*chain)) + if (TREE_VALUE (*chain) == ident) + { + if (! TREE_PURPOSE (*chain)) + TREE_PURPOSE (*chain) = build_class_reference_decl (); + + return TREE_PURPOSE (*chain); + } + + decl = build_class_reference_decl (); + *chain = tree_cons (decl, ident, NULL_TREE); + return decl; + } + else + { + tree params; + + add_class_reference (ident); + + params = build_tree_list (NULL_TREE, + my_build_string_pointer + (IDENTIFIER_LENGTH (ident) + 1, + IDENTIFIER_POINTER (ident))); + + assemble_external (objc_get_class_decl); + return build_function_call (objc_get_class_decl, params); + } +} + +/* For each string section we have a chain which maps identifier nodes + to decls for the strings. */ + +static tree +add_objc_string (tree ident, enum string_section section) +{ + tree *chain, decl, type, string_expr; + + if (section == class_names) + chain = &class_names_chain; + else if (section == meth_var_names) + chain = &meth_var_names_chain; + else if (section == meth_var_types) + chain = &meth_var_types_chain; + else + abort (); + + while (*chain) + { + if (TREE_VALUE (*chain) == ident) + return convert (string_type_node, + build_unary_op (ADDR_EXPR, TREE_PURPOSE (*chain), 1)); + + chain = &TREE_CHAIN (*chain); + } + + decl = build_objc_string_decl (section); + + type = build_array_type + (char_type_node, + build_index_type + (build_int_cst (NULL_TREE, + IDENTIFIER_LENGTH (ident)))); + decl = start_var_decl (type, IDENTIFIER_POINTER (DECL_NAME (decl))); + string_expr = my_build_string (IDENTIFIER_LENGTH (ident) + 1, + IDENTIFIER_POINTER (ident)); + finish_var_decl (decl, string_expr); + + *chain = tree_cons (decl, ident, NULL_TREE); + + return convert (string_type_node, build_unary_op (ADDR_EXPR, decl, 1)); +} + +static GTY(()) int class_names_idx; +static GTY(()) int meth_var_names_idx; +static GTY(()) int meth_var_types_idx; + +static tree +build_objc_string_decl (enum string_section section) +{ + tree decl, ident; + char buf[256]; + + if (section == class_names) + sprintf (buf, "_OBJC_CLASS_NAME_%d", class_names_idx++); + else if (section == meth_var_names) + sprintf (buf, "_OBJC_METH_VAR_NAME_%d", meth_var_names_idx++); + else if (section == meth_var_types) + sprintf (buf, "_OBJC_METH_VAR_TYPE_%d", meth_var_types_idx++); + + ident = get_identifier (buf); + + decl = build_decl (VAR_DECL, ident, build_array_type (char_type_node, 0)); + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 0; + TREE_USED (decl) = 1; + TREE_CONSTANT (decl) = 1; + DECL_CONTEXT (decl) = 0; + DECL_ARTIFICIAL (decl) = 1; +#ifdef OBJCPLUS + DECL_THIS_STATIC (decl) = 1; /* squash redeclaration errors */ +#endif + + make_decl_rtl (decl); + pushdecl_top_level (decl); + + return decl; +} + + +void +objc_declare_alias (tree alias_ident, tree class_ident) +{ + tree underlying_class; + +#ifdef OBJCPLUS + if (current_namespace != global_namespace) { + error ("Objective-C declarations may only appear in global scope"); + } +#endif /* OBJCPLUS */ + + if (!(underlying_class = objc_is_class_name (class_ident))) + warning (0, "cannot find class %qs", IDENTIFIER_POINTER (class_ident)); + else if (objc_is_class_name (alias_ident)) + warning (0, "class %qs already exists", IDENTIFIER_POINTER (alias_ident)); + else + { + /* Implement @compatibility_alias as a typedef. */ +#ifdef OBJCPLUS + push_lang_context (lang_name_c); /* extern "C" */ +#endif + lang_hooks.decls.pushdecl (build_decl + (TYPE_DECL, + alias_ident, + xref_tag (RECORD_TYPE, underlying_class))); +#ifdef OBJCPLUS + pop_lang_context (); +#endif + alias_chain = tree_cons (underlying_class, alias_ident, alias_chain); + } +} + +void +objc_declare_class (tree ident_list) +{ + tree list; +#ifdef OBJCPLUS + if (current_namespace != global_namespace) { + error ("Objective-C declarations may only appear in global scope"); + } +#endif /* OBJCPLUS */ + + for (list = ident_list; list; list = TREE_CHAIN (list)) + { + tree ident = TREE_VALUE (list); + + if (! objc_is_class_name (ident)) + { + tree record = lookup_name (ident), type = record; + + if (record) + { + if (TREE_CODE (record) == TYPE_DECL) + type = DECL_ORIGINAL_TYPE (record); + + if (!TYPE_HAS_OBJC_INFO (type) + || !TYPE_OBJC_INTERFACE (type)) + { + error ("%qs redeclared as different kind of symbol", + IDENTIFIER_POINTER (ident)); + error ("previous declaration of %q+D", + record); + } + } + + record = xref_tag (RECORD_TYPE, ident); + INIT_TYPE_OBJC_INFO (record); + TYPE_OBJC_INTERFACE (record) = ident; + class_chain = tree_cons (NULL_TREE, ident, class_chain); + } + } +} + +tree +objc_is_class_name (tree ident) +{ + tree chain; + + if (ident && TREE_CODE (ident) == IDENTIFIER_NODE + && identifier_global_value (ident)) + ident = identifier_global_value (ident); + while (ident && TREE_CODE (ident) == TYPE_DECL && DECL_ORIGINAL_TYPE (ident)) + ident = OBJC_TYPE_NAME (DECL_ORIGINAL_TYPE (ident)); + + if (ident && TREE_CODE (ident) == RECORD_TYPE) + ident = OBJC_TYPE_NAME (ident); +#ifdef OBJCPLUS + if (ident && TREE_CODE (ident) == TYPE_DECL) + ident = DECL_NAME (ident); +#endif + if (!ident || TREE_CODE (ident) != IDENTIFIER_NODE) + return NULL_TREE; + + if (lookup_interface (ident)) + return ident; + + for (chain = class_chain; chain; chain = TREE_CHAIN (chain)) + { + if (ident == TREE_VALUE (chain)) + return ident; + } + + for (chain = alias_chain; chain; chain = TREE_CHAIN (chain)) + { + if (ident == TREE_VALUE (chain)) + return TREE_PURPOSE (chain); + } + + return 0; +} + +/* Check whether TYPE is either 'id' or 'Class'. */ + +tree +objc_is_id (tree type) +{ + if (type && TREE_CODE (type) == IDENTIFIER_NODE + && identifier_global_value (type)) + type = identifier_global_value (type); + + if (type && TREE_CODE (type) == TYPE_DECL) + type = TREE_TYPE (type); + + /* NB: This function may be called before the ObjC front-end has + been initialized, in which case OBJC_OBJECT_TYPE will (still) be NULL. */ + return (objc_object_type && type + && (IS_ID (type) || IS_CLASS (type) || IS_SUPER (type)) + ? type + : NULL_TREE); +} + +/* Check whether TYPE is either 'id', 'Class', or a pointer to an ObjC + class instance. This is needed by other parts of the compiler to + handle ObjC types gracefully. */ + +tree +objc_is_object_ptr (tree type) +{ + tree ret; + + type = TYPE_MAIN_VARIANT (type); + if (!POINTER_TYPE_P (type)) + return 0; + + ret = objc_is_id (type); + if (!ret) + ret = objc_is_class_name (TREE_TYPE (type)); + + return ret; +} + +static int +objc_is_gcable_type (tree type, int or_strong_p) +{ + tree name; + + if (!TYPE_P (type)) + return 0; + if (objc_is_id (TYPE_MAIN_VARIANT (type))) + return 1; + if (or_strong_p && lookup_attribute ("objc_gc", TYPE_ATTRIBUTES (type))) + return 1; + if (TREE_CODE (type) != POINTER_TYPE && TREE_CODE (type) != INDIRECT_REF) + return 0; + type = TREE_TYPE (type); + if (TREE_CODE (type) != RECORD_TYPE) + return 0; + name = TYPE_NAME (type); + return (objc_is_class_name (name) != NULL_TREE); +} + +static tree +objc_substitute_decl (tree expr, tree oldexpr, tree newexpr) +{ + if (expr == oldexpr) + return newexpr; + + switch (TREE_CODE (expr)) + { + case COMPONENT_REF: + return objc_build_component_ref + (objc_substitute_decl (TREE_OPERAND (expr, 0), + oldexpr, + newexpr), + DECL_NAME (TREE_OPERAND (expr, 1))); + case ARRAY_REF: + return build_array_ref (objc_substitute_decl (TREE_OPERAND (expr, 0), + oldexpr, + newexpr), + TREE_OPERAND (expr, 1)); + case INDIRECT_REF: + return build_indirect_ref (objc_substitute_decl (TREE_OPERAND (expr, 0), + oldexpr, + newexpr), "->"); + default: + return expr; + } +} + +static tree +objc_build_ivar_assignment (tree outervar, tree lhs, tree rhs) +{ + tree func_params; + /* The LHS parameter contains the expression 'outervar->memberspec'; + we need to transform it into '&((typeof(outervar) *) 0)->memberspec', + where memberspec may be arbitrarily complex (e.g., 'g->f.d[2].g[3]'). + */ + tree offs + = objc_substitute_decl + (lhs, outervar, convert (TREE_TYPE (outervar), integer_zero_node)); + tree func + = (flag_objc_direct_dispatch + ? objc_assign_ivar_fast_decl + : objc_assign_ivar_decl); + + offs = convert (integer_type_node, build_unary_op (ADDR_EXPR, offs, 0)); + offs = fold (offs); + func_params = tree_cons (NULL_TREE, + convert (objc_object_type, rhs), + tree_cons (NULL_TREE, convert (objc_object_type, outervar), + tree_cons (NULL_TREE, offs, + NULL_TREE))); + + assemble_external (func); + return build_function_call (func, func_params); +} + +static tree +objc_build_global_assignment (tree lhs, tree rhs) +{ + tree func_params = tree_cons (NULL_TREE, + convert (objc_object_type, rhs), + tree_cons (NULL_TREE, convert (build_pointer_type (objc_object_type), + build_unary_op (ADDR_EXPR, lhs, 0)), + NULL_TREE)); + + assemble_external (objc_assign_global_decl); + return build_function_call (objc_assign_global_decl, func_params); +} + +static tree +objc_build_strong_cast_assignment (tree lhs, tree rhs) +{ + tree func_params = tree_cons (NULL_TREE, + convert (objc_object_type, rhs), + tree_cons (NULL_TREE, convert (build_pointer_type (objc_object_type), + build_unary_op (ADDR_EXPR, lhs, 0)), + NULL_TREE)); + + assemble_external (objc_assign_strong_cast_decl); + return build_function_call (objc_assign_strong_cast_decl, func_params); +} + +static int +objc_is_gcable_p (tree expr) +{ + return (TREE_CODE (expr) == COMPONENT_REF + ? objc_is_gcable_p (TREE_OPERAND (expr, 1)) + : TREE_CODE (expr) == ARRAY_REF + ? (objc_is_gcable_p (TREE_TYPE (expr)) + || objc_is_gcable_p (TREE_OPERAND (expr, 0))) + : TREE_CODE (expr) == ARRAY_TYPE + ? objc_is_gcable_p (TREE_TYPE (expr)) + : TYPE_P (expr) + ? objc_is_gcable_type (expr, 1) + : (objc_is_gcable_p (TREE_TYPE (expr)) + || (DECL_P (expr) + && lookup_attribute ("objc_gc", DECL_ATTRIBUTES (expr))))); +} + +static int +objc_is_ivar_reference_p (tree expr) +{ + return (TREE_CODE (expr) == ARRAY_REF + ? objc_is_ivar_reference_p (TREE_OPERAND (expr, 0)) + : TREE_CODE (expr) == COMPONENT_REF + ? TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL + : 0); +} + +static int +objc_is_global_reference_p (tree expr) +{ + return (TREE_CODE (expr) == INDIRECT_REF || TREE_CODE (expr) == PLUS_EXPR + ? objc_is_global_reference_p (TREE_OPERAND (expr, 0)) + : DECL_P (expr) + ? (!DECL_CONTEXT (expr) || TREE_STATIC (expr)) + : 0); +} + +tree +objc_generate_write_barrier (tree lhs, enum tree_code modifycode, tree rhs) +{ + tree result = NULL_TREE, outer; + int strong_cast_p = 0, outer_gc_p = 0, indirect_p = 0; + + /* See if we have any lhs casts, and strip them out. NB: The lvalue casts + will have been transformed to the form '*(type *)&expr'. */ + if (TREE_CODE (lhs) == INDIRECT_REF) + { + outer = TREE_OPERAND (lhs, 0); + + while (!strong_cast_p + && (TREE_CODE (outer) == CONVERT_EXPR + || TREE_CODE (outer) == NOP_EXPR + || TREE_CODE (outer) == NON_LVALUE_EXPR)) + { + tree lhstype = TREE_TYPE (outer); + + /* Descend down the cast chain, and record the first objc_gc + attribute found. */ + if (POINTER_TYPE_P (lhstype)) + { + tree attr + = lookup_attribute ("objc_gc", + TYPE_ATTRIBUTES (TREE_TYPE (lhstype))); + + if (attr) + strong_cast_p = 1; + } + + outer = TREE_OPERAND (outer, 0); + } + } + + /* If we have a __strong cast, it trumps all else. */ + if (strong_cast_p) + { + if (modifycode != NOP_EXPR) + goto invalid_pointer_arithmetic; + + if (warn_assign_intercept) + warning (0, "strong-cast assignment has been intercepted"); + + result = objc_build_strong_cast_assignment (lhs, rhs); + + goto exit_point; + } + + /* the lhs must be of a suitable type, regardless of its underlying + structure. */ + if (!objc_is_gcable_p (lhs)) + goto exit_point; + + outer = lhs; + + while (outer + && (TREE_CODE (outer) == COMPONENT_REF + || TREE_CODE (outer) == ARRAY_REF)) + outer = TREE_OPERAND (outer, 0); + + if (TREE_CODE (outer) == INDIRECT_REF) + { + outer = TREE_OPERAND (outer, 0); + indirect_p = 1; + } + + outer_gc_p = objc_is_gcable_p (outer); + + /* Handle ivar assignments. */ + if (objc_is_ivar_reference_p (lhs)) + { + /* if the struct to the left of the ivar is not an Objective-C object (__strong + doesn't cut it here), the best we can do here is suggest a cast. */ + if (!objc_is_gcable_type (TREE_TYPE (outer), 0)) + { + /* We may still be able to use the global write barrier... */ + if (!indirect_p && objc_is_global_reference_p (outer)) + goto global_reference; + + suggest_cast: + if (modifycode == NOP_EXPR) + { + if (warn_assign_intercept) + warning (0, "strong-cast may possibly be needed"); + } + + goto exit_point; + } + + if (modifycode != NOP_EXPR) + goto invalid_pointer_arithmetic; + + if (warn_assign_intercept) + warning (0, "instance variable assignment has been intercepted"); + + result = objc_build_ivar_assignment (outer, lhs, rhs); + + goto exit_point; + } + + /* Likewise, intercept assignment to global/static variables if their type is + GC-marked. */ + if (objc_is_global_reference_p (outer)) + { + if (indirect_p) + goto suggest_cast; + + global_reference: + if (modifycode != NOP_EXPR) + { + invalid_pointer_arithmetic: + if (outer_gc_p) + warning (0, "pointer arithmetic for garbage-collected objects not allowed"); + + goto exit_point; + } + + if (warn_assign_intercept) + warning (0, "global/static variable assignment has been intercepted"); + + result = objc_build_global_assignment (lhs, rhs); + } + + /* In all other cases, fall back to the normal mechanism. */ + exit_point: + return result; +} + +struct interface_tuple GTY(()) +{ + tree id; + tree class_name; +}; + +static GTY ((param_is (struct interface_tuple))) htab_t interface_htab; + +static hashval_t +hash_interface (const void *p) +{ + const struct interface_tuple *d = p; + return IDENTIFIER_HASH_VALUE (d->id); +} + +static int +eq_interface (const void *p1, const void *p2) +{ + const struct interface_tuple *d = p1; + return d->id == p2; +} + +static tree +lookup_interface (tree ident) +{ +#ifdef OBJCPLUS + if (ident && TREE_CODE (ident) == TYPE_DECL) + ident = DECL_NAME (ident); +#endif + + if (ident == NULL_TREE || TREE_CODE (ident) != IDENTIFIER_NODE) + return NULL_TREE; + + { + struct interface_tuple **slot; + tree i = NULL_TREE; + + if (interface_htab) + { + slot = (struct interface_tuple **) + htab_find_slot_with_hash (interface_htab, ident, + IDENTIFIER_HASH_VALUE (ident), + NO_INSERT); + if (slot && *slot) + i = (*slot)->class_name; + } + return i; + } +} + +/* Implement @defs () within struct bodies. */ + +tree +objc_get_class_ivars (tree class_name) +{ + tree interface = lookup_interface (class_name); + + if (interface) + return get_class_ivars (interface, true); + + error ("cannot find interface declaration for %qs", + IDENTIFIER_POINTER (class_name)); + + return error_mark_node; +} + +/* Used by: build_private_template, continue_class, + and for @defs constructs. */ + +static tree +get_class_ivars (tree interface, bool inherited) +{ + tree ivar_chain = copy_list (CLASS_RAW_IVARS (interface)); + + /* Both CLASS_RAW_IVARS and CLASS_IVARS contain a list of ivars declared + by the current class (i.e., they do not include super-class ivars). + However, the CLASS_IVARS list will be side-effected by a call to + finish_struct(), which will fill in field offsets. */ + if (!CLASS_IVARS (interface)) + CLASS_IVARS (interface) = ivar_chain; + + if (!inherited) + return ivar_chain; + + while (CLASS_SUPER_NAME (interface)) + { + /* Prepend super-class ivars. */ + interface = lookup_interface (CLASS_SUPER_NAME (interface)); + ivar_chain = chainon (copy_list (CLASS_RAW_IVARS (interface)), + ivar_chain); + } + + return ivar_chain; +} + +static tree +objc_create_temporary_var (tree type) +{ + tree decl; + + decl = build_decl (VAR_DECL, NULL_TREE, type); + TREE_USED (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_IGNORED_P (decl) = 1; + DECL_CONTEXT (decl) = current_function_decl; + + return decl; +} + +/* Exception handling constructs. We begin by having the parser do most + of the work and passing us blocks. What we do next depends on whether + we're doing "native" exception handling or legacy Darwin setjmp exceptions. + We abstract all of this in a handful of appropriately named routines. */ + +/* Stack of open try blocks. */ + +struct objc_try_context +{ + struct objc_try_context *outer; + + /* Statements (or statement lists) as processed by the parser. */ + tree try_body; + tree finally_body; + + /* Some file position locations. */ + location_t try_locus; + location_t end_try_locus; + location_t end_catch_locus; + location_t finally_locus; + location_t end_finally_locus; + + /* A STATEMENT_LIST of CATCH_EXPRs, appropriate for sticking into op1 + of a TRY_CATCH_EXPR. Even when doing Darwin setjmp. */ + tree catch_list; + + /* The CATCH_EXPR of an open @catch clause. */ + tree current_catch; + + /* The VAR_DECL holding the Darwin equivalent of EXC_PTR_EXPR. */ + tree caught_decl; + tree stack_decl; + tree rethrow_decl; +}; + +static struct objc_try_context *cur_try_context; + +/* This hook, called via lang_eh_runtime_type, generates a runtime object + that represents TYPE. For Objective-C, this is just the class name. */ +/* ??? Isn't there a class object or some such? Is it easy to get? */ + +#ifndef OBJCPLUS +static tree +objc_eh_runtime_type (tree type) +{ + return add_objc_string (OBJC_TYPE_NAME (TREE_TYPE (type)), class_names); +} +#endif + +/* Initialize exception handling. */ + +static void +objc_init_exceptions (void) +{ + static bool done = false; + if (done) + return; + done = true; + + if (flag_objc_sjlj_exceptions) + { + /* On Darwin, ObjC exceptions require a sufficiently recent + version of the runtime, so the user must ask for them explicitly. */ + if (!flag_objc_exceptions) + warning (0, "use %<-fobjc-exceptions%> to enable Objective-C " + "exception syntax"); + } +#ifndef OBJCPLUS + else + { + c_eh_initialized_p = true; + eh_personality_libfunc + = init_one_libfunc (USING_SJLJ_EXCEPTIONS + ? "__gnu_objc_personality_sj0" + : "__gnu_objc_personality_v0"); + default_init_unwind_resume_libfunc (); + using_eh_for_cleanups (); + lang_eh_runtime_type = objc_eh_runtime_type; + } +#endif +} + +/* Build an EXC_PTR_EXPR, or the moral equivalent. In the case of Darwin, + we'll arrange for it to be initialized (and associated with a binding) + later. */ + +static tree +objc_build_exc_ptr (void) +{ + if (flag_objc_sjlj_exceptions) + { + tree var = cur_try_context->caught_decl; + if (!var) + { + var = objc_create_temporary_var (objc_object_type); + cur_try_context->caught_decl = var; + } + return var; + } + else + return build (EXC_PTR_EXPR, objc_object_type); +} + +/* Build "objc_exception_try_exit(&_stack)". */ + +static tree +next_sjlj_build_try_exit (void) +{ + tree t; + t = build_fold_addr_expr (cur_try_context->stack_decl); + t = tree_cons (NULL, t, NULL); + t = build_function_call (objc_exception_try_exit_decl, t); + return t; +} + +/* Build + objc_exception_try_enter (&_stack); + if (_setjmp(&_stack.buf)) + ; + else + ; + Return the COND_EXPR. Note that the THEN and ELSE fields are left + empty, ready for the caller to fill them in. */ + +static tree +next_sjlj_build_enter_and_setjmp (void) +{ + tree t, enter, sj, cond; + + t = build_fold_addr_expr (cur_try_context->stack_decl); + t = tree_cons (NULL, t, NULL); + enter = build_function_call (objc_exception_try_enter_decl, t); + + t = objc_build_component_ref (cur_try_context->stack_decl, + get_identifier ("buf")); + t = build_fold_addr_expr (t); +#ifdef OBJCPLUS + /* Convert _setjmp argument to type that is expected. */ + if (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl))) + t = convert (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl))), t); + else + t = convert (ptr_type_node, t); +#else + t = convert (ptr_type_node, t); +#endif + t = tree_cons (NULL, t, NULL); + sj = build_function_call (objc_setjmp_decl, t); + + cond = build (COMPOUND_EXPR, TREE_TYPE (sj), enter, sj); + cond = c_common_truthvalue_conversion (cond); + + return build (COND_EXPR, void_type_node, cond, NULL, NULL); +} + +/* Build + DECL = objc_exception_extract(&_stack); +*/ + +static tree +next_sjlj_build_exc_extract (tree decl) +{ + tree t; + + t = build_fold_addr_expr (cur_try_context->stack_decl); + t = tree_cons (NULL, t, NULL); + t = build_function_call (objc_exception_extract_decl, t); + t = convert (TREE_TYPE (decl), t); + t = build (MODIFY_EXPR, void_type_node, decl, t); + + return t; +} + +/* Build + if (objc_exception_match(obj_get_class(TYPE), _caught) + BODY + else if (...) + ... + else + { + _rethrow = _caught; + objc_exception_try_exit(&_stack); + } + from the sequence of CATCH_EXPRs in the current try context. */ + +static tree +next_sjlj_build_catch_list (void) +{ + tree_stmt_iterator i = tsi_start (cur_try_context->catch_list); + tree catch_seq, t; + tree *last = &catch_seq; + bool saw_id = false; + + for (; !tsi_end_p (i); tsi_next (&i)) + { + tree stmt = tsi_stmt (i); + tree type = CATCH_TYPES (stmt); + tree body = CATCH_BODY (stmt); + + if (type == NULL) + { + *last = body; + saw_id = true; + break; + } + else + { + tree args, cond; + + if (type == error_mark_node) + cond = error_mark_node; + else + { + args = tree_cons (NULL, cur_try_context->caught_decl, NULL); + t = objc_get_class_reference (OBJC_TYPE_NAME (TREE_TYPE (type))); + args = tree_cons (NULL, t, args); + t = build_function_call (objc_exception_match_decl, args); + cond = c_common_truthvalue_conversion (t); + } + t = build (COND_EXPR, void_type_node, cond, body, NULL); + SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); + + *last = t; + last = &COND_EXPR_ELSE (t); + } + } + + if (!saw_id) + { + t = build (MODIFY_EXPR, void_type_node, cur_try_context->rethrow_decl, + cur_try_context->caught_decl); + SET_EXPR_LOCATION (t, cur_try_context->end_catch_locus); + append_to_statement_list (t, last); + + t = next_sjlj_build_try_exit (); + SET_EXPR_LOCATION (t, cur_try_context->end_catch_locus); + append_to_statement_list (t, last); + } + + return catch_seq; +} + +/* Build a complete @try-@catch-@finally block for legacy Darwin setjmp + exception handling. We aim to build: + + { + struct _objc_exception_data _stack; + id volatile _rethrow = 0; + try + { + objc_exception_try_enter (&_stack); + if (_setjmp(&_stack.buf)) + { + id _caught = objc_exception_extract(&_stack); + objc_exception_try_enter (&_stack); + if (_setjmp(&_stack.buf)) + _rethrow = objc_exception_extract(&_stack); + else + CATCH-LIST + } + else + TRY-BLOCK + } + finally + { + if (!_rethrow) + objc_exception_try_exit(&_stack); + FINALLY-BLOCK + if (_rethrow) + objc_exception_throw(_rethrow); + } + } + + If CATCH-LIST is empty, we can omit all of the block containing + "_caught" except for the setting of _rethrow. Note the use of + a real TRY_FINALLY_EXPR here, which is not involved in EH per-se, + but handles goto and other exits from the block. */ + +static tree +next_sjlj_build_try_catch_finally (void) +{ + tree rethrow_decl, stack_decl, t; + tree catch_seq, try_fin, bind; + + /* Create the declarations involved. */ + t = xref_tag (RECORD_TYPE, get_identifier (UTAG_EXCDATA)); + stack_decl = objc_create_temporary_var (t); + cur_try_context->stack_decl = stack_decl; + + rethrow_decl = objc_create_temporary_var (objc_object_type); + cur_try_context->rethrow_decl = rethrow_decl; + TREE_THIS_VOLATILE (rethrow_decl) = 1; + TREE_CHAIN (rethrow_decl) = stack_decl; + + /* Build the outermost variable binding level. */ + bind = build (BIND_EXPR, void_type_node, rethrow_decl, NULL, NULL); + SET_EXPR_LOCATION (bind, cur_try_context->try_locus); + TREE_SIDE_EFFECTS (bind) = 1; + + /* Initialize rethrow_decl. */ + t = build (MODIFY_EXPR, void_type_node, rethrow_decl, + convert (objc_object_type, null_pointer_node)); + SET_EXPR_LOCATION (t, cur_try_context->try_locus); + append_to_statement_list (t, &BIND_EXPR_BODY (bind)); + + /* Build the outermost TRY_FINALLY_EXPR. */ + try_fin = build (TRY_FINALLY_EXPR, void_type_node, NULL, NULL); + SET_EXPR_LOCATION (try_fin, cur_try_context->try_locus); + TREE_SIDE_EFFECTS (try_fin) = 1; + append_to_statement_list (try_fin, &BIND_EXPR_BODY (bind)); + + /* Create the complete catch sequence. */ + if (cur_try_context->catch_list) + { + tree caught_decl = objc_build_exc_ptr (); + catch_seq = build_stmt (BIND_EXPR, caught_decl, NULL, NULL); + TREE_SIDE_EFFECTS (catch_seq) = 1; + + t = next_sjlj_build_exc_extract (caught_decl); + append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq)); + + t = next_sjlj_build_enter_and_setjmp (); + COND_EXPR_THEN (t) = next_sjlj_build_exc_extract (rethrow_decl); + COND_EXPR_ELSE (t) = next_sjlj_build_catch_list (); + append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq)); + } + else + catch_seq = next_sjlj_build_exc_extract (rethrow_decl); + SET_EXPR_LOCATION (catch_seq, cur_try_context->end_try_locus); + + /* Build the main register-and-try if statement. */ + t = next_sjlj_build_enter_and_setjmp (); + SET_EXPR_LOCATION (t, cur_try_context->try_locus); + COND_EXPR_THEN (t) = catch_seq; + COND_EXPR_ELSE (t) = cur_try_context->try_body; + TREE_OPERAND (try_fin, 0) = t; + + /* Build the complete FINALLY statement list. */ + t = next_sjlj_build_try_exit (); + t = build_stmt (COND_EXPR, + c_common_truthvalue_conversion (rethrow_decl), + NULL, t); + SET_EXPR_LOCATION (t, cur_try_context->finally_locus); + append_to_statement_list (t, &TREE_OPERAND (try_fin, 1)); + + append_to_statement_list (cur_try_context->finally_body, + &TREE_OPERAND (try_fin, 1)); + + t = tree_cons (NULL, rethrow_decl, NULL); + t = build_function_call (objc_exception_throw_decl, t); + t = build_stmt (COND_EXPR, + c_common_truthvalue_conversion (rethrow_decl), + t, NULL); + SET_EXPR_LOCATION (t, cur_try_context->end_finally_locus); + append_to_statement_list (t, &TREE_OPERAND (try_fin, 1)); + + return bind; +} + +/* Called just after parsing the @try and its associated BODY. We now + must prepare for the tricky bits -- handling the catches and finally. */ + +void +objc_begin_try_stmt (location_t try_locus, tree body) +{ + struct objc_try_context *c = xcalloc (1, sizeof (*c)); + c->outer = cur_try_context; + c->try_body = body; + c->try_locus = try_locus; + c->end_try_locus = input_location; + cur_try_context = c; + + objc_init_exceptions (); + + if (flag_objc_sjlj_exceptions) + objc_mark_locals_volatile (NULL); +} + +/* Called just after parsing "@catch (parm)". Open a binding level, + enter DECL into the binding level, and initialize it. Leave the + binding level open while the body of the compound statement is parsed. */ + +void +objc_begin_catch_clause (tree decl) +{ + tree compound, type, t; + + /* Begin a new scope that the entire catch clause will live in. */ + compound = c_begin_compound_stmt (true); + + /* The parser passed in a PARM_DECL, but what we really want is a VAR_DECL. */ + decl = build_decl (VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl)); + lang_hooks.decls.pushdecl (decl); + + /* Since a decl is required here by syntax, don't warn if its unused. */ + /* ??? As opposed to __attribute__((unused))? Anyway, this appears to + be what the previous objc implementation did. */ + TREE_USED (decl) = 1; + + /* Verify that the type of the catch is valid. It must be a pointer + to an Objective-C class, or "id" (which is catch-all). */ + type = TREE_TYPE (decl); + + if (POINTER_TYPE_P (type) && objc_is_object_id (TREE_TYPE (type))) + type = NULL; + else if (!POINTER_TYPE_P (type) || !TYPED_OBJECT (TREE_TYPE (type))) + { + error ("@catch parameter is not a known Objective-C class type"); + type = error_mark_node; + } + else if (cur_try_context->catch_list) + { + /* Examine previous @catch clauses and see if we've already + caught the type in question. */ + tree_stmt_iterator i = tsi_start (cur_try_context->catch_list); + for (; !tsi_end_p (i); tsi_next (&i)) + { + tree stmt = tsi_stmt (i); + t = CATCH_TYPES (stmt); + if (t == error_mark_node) + continue; + if (!t || DERIVED_FROM_P (TREE_TYPE (t), TREE_TYPE (type))) + { + warning (0, "exception of type %<%T%> will be caught", + TREE_TYPE (type)); + warning (0, "%H by earlier handler for %<%T%>", + EXPR_LOCUS (stmt), TREE_TYPE (t ? t : objc_object_type)); + break; + } + } + } + + /* Record the data for the catch in the try context so that we can + finalize it later. */ + t = build_stmt (CATCH_EXPR, type, compound); + cur_try_context->current_catch = t; + + /* Initialize the decl from the EXC_PTR_EXPR we get from the runtime. */ + t = objc_build_exc_ptr (); + t = convert (TREE_TYPE (decl), t); + t = build (MODIFY_EXPR, void_type_node, decl, t); + add_stmt (t); +} + +/* Called just after parsing the closing brace of a @catch clause. Close + the open binding level, and record a CATCH_EXPR for it. */ + +void +objc_finish_catch_clause (void) +{ + tree c = cur_try_context->current_catch; + cur_try_context->current_catch = NULL; + cur_try_context->end_catch_locus = input_location; + + CATCH_BODY (c) = c_end_compound_stmt (CATCH_BODY (c), 1); + append_to_statement_list (c, &cur_try_context->catch_list); +} + +/* Called after parsing a @finally clause and its associated BODY. + Record the body for later placement. */ + +void +objc_build_finally_clause (location_t finally_locus, tree body) +{ + cur_try_context->finally_body = body; + cur_try_context->finally_locus = finally_locus; + cur_try_context->end_finally_locus = input_location; +} + +/* Called to finalize a @try construct. */ + +tree +objc_finish_try_stmt (void) +{ + struct objc_try_context *c = cur_try_context; + tree stmt; + + if (c->catch_list == NULL && c->finally_body == NULL) + error ("%<@try%> without %<@catch%> or %<@finally%>"); + + /* If we're doing Darwin setjmp exceptions, build the big nasty. */ + if (flag_objc_sjlj_exceptions) + { + if (!cur_try_context->finally_body) + { + cur_try_context->finally_locus = input_location; + cur_try_context->end_finally_locus = input_location; + } + stmt = next_sjlj_build_try_catch_finally (); + } + else + { + /* Otherwise, nest the CATCH inside a FINALLY. */ + stmt = c->try_body; + if (c->catch_list) + { + stmt = build_stmt (TRY_CATCH_EXPR, stmt, c->catch_list); + SET_EXPR_LOCATION (stmt, cur_try_context->try_locus); + } + if (c->finally_body) + { + stmt = build_stmt (TRY_FINALLY_EXPR, stmt, c->finally_body); + SET_EXPR_LOCATION (stmt, cur_try_context->try_locus); + } + } + add_stmt (stmt); + + cur_try_context = c->outer; + free (c); + return stmt; +} + +tree +objc_build_throw_stmt (tree throw_expr) +{ + tree args; + + objc_init_exceptions (); + + if (throw_expr == NULL) + { + /* If we're not inside a @catch block, there is no "current + exception" to be rethrown. */ + if (cur_try_context == NULL + || cur_try_context->current_catch == NULL) + { + error ("%<@throw%> (rethrow) used outside of a @catch block"); + return NULL_TREE; + } + + /* Otherwise the object is still sitting in the EXC_PTR_EXPR + value that we get from the runtime. */ + throw_expr = objc_build_exc_ptr (); + } + + /* A throw is just a call to the runtime throw function with the + object as a parameter. */ + args = tree_cons (NULL, throw_expr, NULL); + return add_stmt (build_function_call (objc_exception_throw_decl, args)); +} + +tree +objc_build_synchronized (location_t start_locus, tree mutex, tree body) +{ + tree args, call; + + /* First lock the mutex. */ + mutex = save_expr (mutex); + args = tree_cons (NULL, mutex, NULL); + call = build_function_call (objc_sync_enter_decl, args); + SET_EXPR_LOCATION (call, start_locus); + add_stmt (call); + + /* Build the mutex unlock. */ + args = tree_cons (NULL, mutex, NULL); + call = build_function_call (objc_sync_exit_decl, args); + SET_EXPR_LOCATION (call, input_location); + + /* Put the that and the body in a TRY_FINALLY. */ + objc_begin_try_stmt (start_locus, body); + objc_build_finally_clause (input_location, call); + return objc_finish_try_stmt (); +} + + +/* Predefine the following data type: + + struct _objc_exception_data + { + int buf[_JBLEN]; + void *pointers[4]; + }; */ + +/* The following yuckiness should prevent users from having to #include + in their code... */ + +#ifdef TARGET_POWERPC +/* snarfed from /usr/include/ppc/setjmp.h */ +#define _JBLEN (26 + 36 + 129 + 1) +#else +/* snarfed from /usr/include/i386/{setjmp,signal}.h */ +#define _JBLEN 18 +#endif + +static void +build_next_objc_exception_stuff (void) +{ + tree field_decl, field_decl_chain, index, temp_type; + + objc_exception_data_template + = start_struct (RECORD_TYPE, get_identifier (UTAG_EXCDATA)); + + /* int buf[_JBLEN]; */ + + index = build_index_type (build_int_cst (NULL_TREE, _JBLEN - 1)); + field_decl = create_field_decl (build_array_type (integer_type_node, index), + "buf"); + field_decl_chain = field_decl; + + /* void *pointers[4]; */ + + index = build_index_type (build_int_cst (NULL_TREE, 4 - 1)); + field_decl = create_field_decl (build_array_type (ptr_type_node, index), + "pointers"); + chainon (field_decl_chain, field_decl); + + finish_struct (objc_exception_data_template, field_decl_chain, NULL_TREE); + + /* int _setjmp(...); */ + /* If the user includes , this shall be superseded by + 'int _setjmp(jmp_buf);' */ + temp_type = build_function_type (integer_type_node, NULL_TREE); + objc_setjmp_decl + = builtin_function (TAG_SETJMP, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + + /* id objc_exception_extract(struct _objc_exception_data *); */ + temp_type + = build_function_type (objc_object_type, + tree_cons (NULL_TREE, + build_pointer_type (objc_exception_data_template), + OBJC_VOID_AT_END)); + objc_exception_extract_decl + = builtin_function (TAG_EXCEPTIONEXTRACT, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + /* void objc_exception_try_enter(struct _objc_exception_data *); */ + /* void objc_exception_try_exit(struct _objc_exception_data *); */ + temp_type + = build_function_type (void_type_node, + tree_cons (NULL_TREE, + build_pointer_type (objc_exception_data_template), + OBJC_VOID_AT_END)); + objc_exception_try_enter_decl + = builtin_function (TAG_EXCEPTIONTRYENTER, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + objc_exception_try_exit_decl + = builtin_function (TAG_EXCEPTIONTRYEXIT, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + + /* int objc_exception_match(id, id); */ + temp_type + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, objc_object_type, + tree_cons (NULL_TREE, objc_object_type, + OBJC_VOID_AT_END))); + objc_exception_match_decl + = builtin_function (TAG_EXCEPTIONMATCH, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + + /* id objc_assign_ivar (id, id, unsigned int); */ + /* id objc_assign_ivar_Fast (id, id, unsigned int) + __attribute__ ((hard_coded_address (OFFS_ASSIGNIVAR_FAST))); */ + temp_type + = build_function_type (objc_object_type, + tree_cons + (NULL_TREE, objc_object_type, + tree_cons (NULL_TREE, objc_object_type, + tree_cons (NULL_TREE, + unsigned_type_node, + OBJC_VOID_AT_END)))); + objc_assign_ivar_decl + = builtin_function (TAG_ASSIGNIVAR, temp_type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); +#ifdef OFFS_ASSIGNIVAR_FAST + objc_assign_ivar_fast_decl + = builtin_function (TAG_ASSIGNIVAR_FAST, temp_type, 0, + NOT_BUILT_IN, NULL, NULL_TREE); + DECL_ATTRIBUTES (objc_assign_ivar_fast_decl) + = tree_cons (get_identifier ("hard_coded_address"), + build_int_cst (NULL_TREE, OFFS_ASSIGNIVAR_FAST), + NULL_TREE); +#else + /* Default to slower ivar method. */ + objc_assign_ivar_fast_decl = objc_assign_ivar_decl; +#endif + + /* id objc_assign_global (id, id *); */ + /* id objc_assign_strongCast (id, id *); */ + temp_type = build_function_type (objc_object_type, + tree_cons (NULL_TREE, objc_object_type, + tree_cons (NULL_TREE, build_pointer_type (objc_object_type), + OBJC_VOID_AT_END))); + objc_assign_global_decl + = builtin_function (TAG_ASSIGNGLOBAL, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); + objc_assign_strong_cast_decl + = builtin_function (TAG_ASSIGNSTRONGCAST, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); +} + +static void +build_objc_exception_stuff (void) +{ + tree noreturn_list, nothrow_list, temp_type; + + noreturn_list = tree_cons (get_identifier ("noreturn"), NULL, NULL); + nothrow_list = tree_cons (get_identifier ("nothrow"), NULL, NULL); + + /* void objc_exception_throw(id) __attribute__((noreturn)); */ + /* void objc_sync_enter(id); */ + /* void objc_sync_exit(id); */ + temp_type = build_function_type (void_type_node, + tree_cons (NULL_TREE, objc_object_type, + OBJC_VOID_AT_END)); + objc_exception_throw_decl + = builtin_function (TAG_EXCEPTIONTHROW, temp_type, 0, NOT_BUILT_IN, NULL, + noreturn_list); + objc_sync_enter_decl + = builtin_function (TAG_SYNCENTER, temp_type, 0, NOT_BUILT_IN, + NULL, nothrow_list); + objc_sync_exit_decl + = builtin_function (TAG_SYNCEXIT, temp_type, 0, NOT_BUILT_IN, + NULL, nothrow_list); +} + +/* Construct a C struct corresponding to ObjC class CLASS, with the same + name as the class: + + struct { + struct _objc_class *isa; + ... + }; */ + +static void +build_private_template (tree class) +{ + if (!CLASS_STATIC_TEMPLATE (class)) + { + tree record = objc_build_struct (class, + get_class_ivars (class, false), + CLASS_SUPER_NAME (class)); + + /* Set the TREE_USED bit for this struct, so that stab generator + can emit stabs for this struct type. */ + if (flag_debug_only_used_symbols && TYPE_STUB_DECL (record)) + TREE_USED (TYPE_STUB_DECL (record)) = 1; + } +} + +/* Begin code generation for protocols... */ + +/* struct _objc_protocol { + struct _objc_class *isa; + char *protocol_name; + struct _objc_protocol **protocol_list; + struct _objc__method_prototype_list *instance_methods; + struct _objc__method_prototype_list *class_methods; + }; */ + +static void +build_protocol_template (void) +{ + tree field_decl, field_decl_chain; + + objc_protocol_template = start_struct (RECORD_TYPE, + get_identifier (UTAG_PROTOCOL)); + + /* struct _objc_class *isa; */ + field_decl = create_field_decl (build_pointer_type + (xref_tag (RECORD_TYPE, + get_identifier (UTAG_CLASS))), + "isa"); + field_decl_chain = field_decl; + + /* char *protocol_name; */ + field_decl = create_field_decl (string_type_node, "protocol_name"); + chainon (field_decl_chain, field_decl); + + /* struct _objc_protocol **protocol_list; */ + field_decl = create_field_decl (build_pointer_type + (build_pointer_type + (objc_protocol_template)), + "protocol_list"); + chainon (field_decl_chain, field_decl); + + /* struct _objc__method_prototype_list *instance_methods; */ + field_decl = create_field_decl (objc_method_proto_list_ptr, + "instance_methods"); + chainon (field_decl_chain, field_decl); + + /* struct _objc__method_prototype_list *class_methods; */ + field_decl = create_field_decl (objc_method_proto_list_ptr, + "class_methods"); + chainon (field_decl_chain, field_decl); + + finish_struct (objc_protocol_template, field_decl_chain, NULL_TREE); +} + +static tree +build_descriptor_table_initializer (tree type, tree entries) +{ + tree initlist = NULL_TREE; + + do + { + tree eltlist = NULL_TREE; + + eltlist + = tree_cons (NULL_TREE, + build_selector (METHOD_SEL_NAME (entries)), NULL_TREE); + eltlist + = tree_cons (NULL_TREE, + add_objc_string (METHOD_ENCODING (entries), + meth_var_types), + eltlist); + + initlist + = tree_cons (NULL_TREE, + objc_build_constructor (type, nreverse (eltlist)), + initlist); + + entries = TREE_CHAIN (entries); + } + while (entries); + + return objc_build_constructor (build_array_type (type, 0), + nreverse (initlist)); +} + +/* struct objc_method_prototype_list { + int count; + struct objc_method_prototype { + SEL name; + char *types; + } list[1]; + }; */ + +static tree +build_method_prototype_list_template (tree list_type, int size) +{ + tree objc_ivar_list_record; + tree field_decl, field_decl_chain; + + /* Generate an unnamed struct definition. */ + + objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE); + + /* int method_count; */ + field_decl = create_field_decl (integer_type_node, "method_count"); + field_decl_chain = field_decl; + + /* struct objc_method method_list[]; */ + field_decl = create_field_decl (build_array_type + (list_type, + build_index_type + (build_int_cst (NULL_TREE, size - 1))), + "method_list"); + chainon (field_decl_chain, field_decl); + + finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE); + + return objc_ivar_list_record; +} + +static tree +build_method_prototype_template (void) +{ + tree proto_record; + tree field_decl, field_decl_chain; + + proto_record + = start_struct (RECORD_TYPE, get_identifier (UTAG_METHOD_PROTOTYPE)); + + /* SEL _cmd; */ + field_decl = create_field_decl (objc_selector_type, "_cmd"); + field_decl_chain = field_decl; + + /* char *method_types; */ + field_decl = create_field_decl (string_type_node, "method_types"); + chainon (field_decl_chain, field_decl); + + finish_struct (proto_record, field_decl_chain, NULL_TREE); + + return proto_record; +} + +static tree +objc_method_parm_type (tree type) +{ + type = TREE_VALUE (TREE_TYPE (type)); + if (TREE_CODE (type) == TYPE_DECL) + type = TREE_TYPE (type); + return type; +} + +static int +objc_encoded_type_size (tree type) +{ + int sz = int_size_in_bytes (type); + + /* Make all integer and enum types at least as large + as an int. */ + if (sz > 0 && INTEGRAL_TYPE_P (type)) + sz = MAX (sz, int_size_in_bytes (integer_type_node)); + /* Treat arrays as pointers, since that's how they're + passed in. */ + else if (TREE_CODE (type) == ARRAY_TYPE) + sz = int_size_in_bytes (ptr_type_node); + return sz; +} + +static tree +encode_method_prototype (tree method_decl) +{ + tree parms; + int parm_offset, i; + char buf[40]; + tree result; + + /* ONEWAY and BYCOPY, for remote object are the only method qualifiers. */ + encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (method_decl))); + + /* Encode return type. */ + encode_type (objc_method_parm_type (method_decl), + obstack_object_size (&util_obstack), + OBJC_ENCODE_INLINE_DEFS); + + /* Stack size. */ + /* The first two arguments (self and _cmd) are pointers; account for + their size. */ + i = int_size_in_bytes (ptr_type_node); + parm_offset = 2 * i; + for (parms = METHOD_SEL_ARGS (method_decl); parms; + parms = TREE_CHAIN (parms)) + { + tree type = objc_method_parm_type (parms); + int sz = objc_encoded_type_size (type); + + /* If a type size is not known, bail out. */ + if (sz < 0) + { + error ("type %q+D does not have a known size", + type); + /* Pretend that the encoding succeeded; the compilation will + fail nevertheless. */ + goto finish_encoding; + } + parm_offset += sz; + } + + sprintf (buf, "%d@0:%d", parm_offset, i); + obstack_grow (&util_obstack, buf, strlen (buf)); + + /* Argument types. */ + parm_offset = 2 * i; + for (parms = METHOD_SEL_ARGS (method_decl); parms; + parms = TREE_CHAIN (parms)) + { + tree type = objc_method_parm_type (parms); + + /* Process argument qualifiers for user supplied arguments. */ + encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (parms))); + + /* Type. */ + encode_type (type, obstack_object_size (&util_obstack), + OBJC_ENCODE_INLINE_DEFS); + + /* Compute offset. */ + sprintf (buf, "%d", parm_offset); + parm_offset += objc_encoded_type_size (type); + + obstack_grow (&util_obstack, buf, strlen (buf)); + } + + finish_encoding: + obstack_1grow (&util_obstack, '\0'); + result = get_identifier (obstack_finish (&util_obstack)); + obstack_free (&util_obstack, util_firstobj); + return result; +} + +static tree +generate_descriptor_table (tree type, const char *name, int size, tree list, + tree proto) +{ + tree decl, initlist; + + decl = start_var_decl (type, synth_id_with_class_suffix (name, proto)); + + initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, size)); + initlist = tree_cons (NULL_TREE, list, initlist); + + finish_var_decl (decl, objc_build_constructor (type, nreverse (initlist))); + + return decl; +} + +static void +generate_method_descriptors (tree protocol) +{ + tree initlist, chain, method_list_template; + int size; + + if (!objc_method_prototype_template) + objc_method_prototype_template = build_method_prototype_template (); + + chain = PROTOCOL_CLS_METHODS (protocol); + if (chain) + { + size = list_length (chain); + + method_list_template + = build_method_prototype_list_template (objc_method_prototype_template, + size); + + initlist + = build_descriptor_table_initializer (objc_method_prototype_template, + chain); + + UOBJC_CLASS_METHODS_decl + = generate_descriptor_table (method_list_template, + "_OBJC_PROTOCOL_CLASS_METHODS", + size, initlist, protocol); + } + else + UOBJC_CLASS_METHODS_decl = 0; + + chain = PROTOCOL_NST_METHODS (protocol); + if (chain) + { + size = list_length (chain); + + method_list_template + = build_method_prototype_list_template (objc_method_prototype_template, + size); + initlist + = build_descriptor_table_initializer (objc_method_prototype_template, + chain); + + UOBJC_INSTANCE_METHODS_decl + = generate_descriptor_table (method_list_template, + "_OBJC_PROTOCOL_INSTANCE_METHODS", + size, initlist, protocol); + } + else + UOBJC_INSTANCE_METHODS_decl = 0; +} + +static void +generate_protocol_references (tree plist) +{ + tree lproto; + + /* Forward declare protocols referenced. */ + for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) + { + tree proto = TREE_VALUE (lproto); + + if (TREE_CODE (proto) == PROTOCOL_INTERFACE_TYPE + && PROTOCOL_NAME (proto)) + { + if (! PROTOCOL_FORWARD_DECL (proto)) + build_protocol_reference (proto); + + if (PROTOCOL_LIST (proto)) + generate_protocol_references (PROTOCOL_LIST (proto)); + } + } +} + +/* Generate either '- .cxx_construct' or '- .cxx_destruct' for the + current class. */ +#ifdef OBJCPLUS +static void +objc_generate_cxx_ctor_or_dtor (bool dtor) +{ + tree fn, body, compound_stmt, ivar; + + /* - (id) .cxx_construct { ... return self; } */ + /* - (void) .cxx_construct { ... } */ + + objc_set_method_type (MINUS_EXPR); + objc_start_method_definition + (objc_build_method_signature (build_tree_list (NULL_TREE, + dtor + ? void_type_node + : objc_object_type), + get_identifier (dtor + ? TAG_CXX_DESTRUCT + : TAG_CXX_CONSTRUCT), + make_node (TREE_LIST), + false)); + body = begin_function_body (); + compound_stmt = begin_compound_stmt (0); + + ivar = CLASS_IVARS (implementation_template); + /* Destroy ivars in reverse order. */ + if (dtor) + ivar = nreverse (copy_list (ivar)); + + for (; ivar; ivar = TREE_CHAIN (ivar)) + { + if (TREE_CODE (ivar) == FIELD_DECL) + { + tree type = TREE_TYPE (ivar); + + /* Call the ivar's default constructor or destructor. Do not + call the destructor unless a corresponding constructor call + has also been made (or is not needed). */ + if (IS_AGGR_TYPE (type) + && (dtor + ? (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) + && (!TYPE_NEEDS_CONSTRUCTING (type) + || TYPE_HAS_DEFAULT_CONSTRUCTOR (type))) + : (TYPE_NEEDS_CONSTRUCTING (type) + && TYPE_HAS_DEFAULT_CONSTRUCTOR (type)))) + finish_expr_stmt + (build_special_member_call + (build_ivar_reference (DECL_NAME (ivar)), + dtor ? complete_dtor_identifier : complete_ctor_identifier, + NULL_TREE, type, LOOKUP_NORMAL)); + } + } + + /* The constructor returns 'self'. */ + if (!dtor) + finish_return_stmt (self_decl); + + finish_compound_stmt (compound_stmt); + finish_function_body (body); + fn = current_function_decl; + finish_function (); + objc_finish_method_definition (fn); +} + +/* The following routine will examine the current @interface for any + non-POD C++ ivars requiring non-trivial construction and/or + destruction, and then synthesize special '- .cxx_construct' and/or + '- .cxx_destruct' methods which will run the appropriate + construction or destruction code. Note that ivars inherited from + super-classes are _not_ considered. */ +static void +objc_generate_cxx_cdtors (void) +{ + bool need_ctor = false, need_dtor = false; + tree ivar; + + /* We do not want to do this for categories, since they do not have + their own ivars. */ + + if (TREE_CODE (objc_implementation_context) != CLASS_IMPLEMENTATION_TYPE) + return; + + /* First, determine if we even need a constructor and/or destructor. */ + + for (ivar = CLASS_IVARS (implementation_template); ivar; + ivar = TREE_CHAIN (ivar)) + { + if (TREE_CODE (ivar) == FIELD_DECL) + { + tree type = TREE_TYPE (ivar); + + if (IS_AGGR_TYPE (type)) + { + if (TYPE_NEEDS_CONSTRUCTING (type) + && TYPE_HAS_DEFAULT_CONSTRUCTOR (type)) + /* NB: If a default constructor is not available, we will not + be able to initialize this ivar; the add_instance_variable() + routine will already have warned about this. */ + need_ctor = true; + + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) + && (!TYPE_NEEDS_CONSTRUCTING (type) + || TYPE_HAS_DEFAULT_CONSTRUCTOR (type))) + /* NB: If a default constructor is not available, we will not + call the destructor either, for symmetry. */ + need_dtor = true; + } + } + } + + /* Generate '- .cxx_construct' if needed. */ + + if (need_ctor) + objc_generate_cxx_ctor_or_dtor (false); + + /* Generate '- .cxx_destruct' if needed. */ + + if (need_dtor) + objc_generate_cxx_ctor_or_dtor (true); + + /* The 'imp_list' variable points at an imp_entry record for the current + @implementation. Record the existence of '- .cxx_construct' and/or + '- .cxx_destruct' methods therein; it will be included in the + metadata for the class. */ + if (flag_next_runtime) + imp_list->has_cxx_cdtors = (need_ctor || need_dtor); +} +#endif + +/* For each protocol which was referenced either from a @protocol() + expression, or because a class/category implements it (then a + pointer to the protocol is stored in the struct describing the + class/category), we create a statically allocated instance of the + Protocol class. The code is written in such a way as to generate + as few Protocol objects as possible; we generate a unique Protocol + instance for each protocol, and we don't generate a Protocol + instance if the protocol is never referenced (either from a + @protocol() or from a class/category implementation). These + statically allocated objects can be referred to via the static + (that is, private to this module) symbols _OBJC_PROTOCOL_n. + + The statically allocated Protocol objects that we generate here + need to be fixed up at runtime in order to be used: the 'isa' + pointer of the objects need to be set up to point to the 'Protocol' + class, as known at runtime. + + The NeXT runtime fixes up all protocols at program startup time, + before main() is entered. It uses a low-level trick to look up all + those symbols, then loops on them and fixes them up. + + The GNU runtime as well fixes up all protocols before user code + from the module is executed; it requires pointers to those symbols + to be put in the objc_symtab (which is then passed as argument to + the function __objc_exec_class() which the compiler sets up to be + executed automatically when the module is loaded); setup of those + Protocol objects happen in two ways in the GNU runtime: all + Protocol objects referred to by a class or category implementation + are fixed up when the class/category is loaded; all Protocol + objects referred to by a @protocol() expression are added by the + compiler to the list of statically allocated instances to fixup + (the same list holding the statically allocated constant string + objects). Because, as explained above, the compiler generates as + few Protocol objects as possible, some Protocol object might end up + being referenced multiple times when compiled with the GNU runtime, + and end up being fixed up multiple times at runtime initialization. + But that doesn't hurt, it's just a little inefficient. */ + +static void +generate_protocols (void) +{ + tree p, encoding; + tree decl; + tree initlist, protocol_name_expr, refs_decl, refs_expr; + + /* If a protocol was directly referenced, pull in indirect references. */ + for (p = protocol_chain; p; p = TREE_CHAIN (p)) + if (PROTOCOL_FORWARD_DECL (p) && PROTOCOL_LIST (p)) + generate_protocol_references (PROTOCOL_LIST (p)); + + for (p = protocol_chain; p; p = TREE_CHAIN (p)) + { + tree nst_methods = PROTOCOL_NST_METHODS (p); + tree cls_methods = PROTOCOL_CLS_METHODS (p); + + /* If protocol wasn't referenced, don't generate any code. */ + decl = PROTOCOL_FORWARD_DECL (p); + + if (!decl) + continue; + + /* Make sure we link in the Protocol class. */ + add_class_reference (get_identifier (PROTOCOL_OBJECT_CLASS_NAME)); + + while (nst_methods) + { + if (! METHOD_ENCODING (nst_methods)) + { + encoding = encode_method_prototype (nst_methods); + METHOD_ENCODING (nst_methods) = encoding; + } + nst_methods = TREE_CHAIN (nst_methods); + } + + while (cls_methods) + { + if (! METHOD_ENCODING (cls_methods)) + { + encoding = encode_method_prototype (cls_methods); + METHOD_ENCODING (cls_methods) = encoding; + } + + cls_methods = TREE_CHAIN (cls_methods); + } + generate_method_descriptors (p); + + if (PROTOCOL_LIST (p)) + refs_decl = generate_protocol_list (p); + 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 (build_pointer_type + (objc_protocol_template)), + build_unary_op (ADDR_EXPR, refs_decl, 0)); + else + refs_expr = build_int_cst (NULL_TREE, 0); + + /* UOBJC_INSTANCE_METHODS_decl/UOBJC_CLASS_METHODS_decl are set + by generate_method_descriptors, which is called above. */ + initlist = build_protocol_initializer (TREE_TYPE (decl), + protocol_name_expr, refs_expr, + UOBJC_INSTANCE_METHODS_decl, + UOBJC_CLASS_METHODS_decl); + finish_var_decl (decl, initlist); + } +} + +static tree +build_protocol_initializer (tree type, tree protocol_name, + tree protocol_list, tree instance_methods, + tree class_methods) +{ + tree initlist = NULL_TREE, expr; + tree cast_type = build_pointer_type + (xref_tag (RECORD_TYPE, + get_identifier (UTAG_CLASS))); + + /* Filling the "isa" in with one allows the runtime system to + detect that the version change...should remove before final release. */ + + expr = build_int_cst (cast_type, PROTOCOL_VERSION); + initlist = tree_cons (NULL_TREE, expr, initlist); + initlist = tree_cons (NULL_TREE, protocol_name, initlist); + initlist = tree_cons (NULL_TREE, protocol_list, initlist); + + if (!instance_methods) + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + else + { + expr = convert (objc_method_proto_list_ptr, + build_unary_op (ADDR_EXPR, instance_methods, 0)); + initlist = tree_cons (NULL_TREE, expr, initlist); + } + + if (!class_methods) + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + else + { + expr = convert (objc_method_proto_list_ptr, + build_unary_op (ADDR_EXPR, class_methods, 0)); + initlist = tree_cons (NULL_TREE, expr, initlist); + } + + return objc_build_constructor (type, nreverse (initlist)); +} + +/* 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 field_decl, field_decl_chain; + + objc_category_template = start_struct (RECORD_TYPE, + get_identifier (UTAG_CATEGORY)); + + /* char *category_name; */ + field_decl = create_field_decl (string_type_node, "category_name"); + field_decl_chain = field_decl; + + /* char *class_name; */ + field_decl = create_field_decl (string_type_node, "class_name"); + chainon (field_decl_chain, field_decl); + + /* struct _objc_method_list *instance_methods; */ + field_decl = create_field_decl (objc_method_list_ptr, + "instance_methods"); + chainon (field_decl_chain, field_decl); + + /* struct _objc_method_list *class_methods; */ + field_decl = create_field_decl (objc_method_list_ptr, + "class_methods"); + chainon (field_decl_chain, field_decl); + + /* struct _objc_protocol **protocol_list; */ + field_decl = create_field_decl (build_pointer_type + (build_pointer_type + (objc_protocol_template)), + "protocol_list"); + chainon (field_decl_chain, field_decl); + + finish_struct (objc_category_template, field_decl_chain, NULL_TREE); +} + +/* struct _objc_selector { + SEL sel_id; + char *sel_type; + }; */ + +static void +build_selector_template (void) +{ + + tree field_decl, field_decl_chain; + + objc_selector_template + = start_struct (RECORD_TYPE, get_identifier (UTAG_SELECTOR)); + + /* SEL sel_id; */ + field_decl = create_field_decl (objc_selector_type, "sel_id"); + field_decl_chain = field_decl; + + /* char *sel_type; */ + field_decl = create_field_decl (string_type_node, "sel_type"); + chainon (field_decl_chain, field_decl); + + finish_struct (objc_selector_template, field_decl_chain, NULL_TREE); +} + +/* struct _objc_class { + struct _objc_class *isa; + struct _objc_class *super_class; + char *name; + long version; + long info; + long instance_size; + struct _objc_ivar_list *ivars; + struct _objc_method_list *methods; + #ifdef __NEXT_RUNTIME__ + struct objc_cache *cache; + #else + struct sarray *dtable; + struct _objc_class *subclass_list; + struct _objc_class *sibling_class; + #endif + struct _objc_protocol_list *protocols; + #ifdef __NEXT_RUNTIME__ + void *sel_id; + #endif + void *gc_object_type; + }; */ + +/* NB: The 'sel_id' and 'gc_object_type' fields are not being used by + the NeXT/Apple runtime; still, the compiler must generate them to + maintain backward binary compatibility (and to allow for future + expansion). */ + +static void +build_class_template (void) +{ + tree field_decl, field_decl_chain; + + objc_class_template + = start_struct (RECORD_TYPE, get_identifier (UTAG_CLASS)); + + /* struct _objc_class *isa; */ + field_decl = create_field_decl (build_pointer_type (objc_class_template), + "isa"); + field_decl_chain = field_decl; + + /* struct _objc_class *super_class; */ + field_decl = create_field_decl (build_pointer_type (objc_class_template), + "super_class"); + chainon (field_decl_chain, field_decl); + + /* char *name; */ + field_decl = create_field_decl (string_type_node, "name"); + chainon (field_decl_chain, field_decl); + + /* long version; */ + field_decl = create_field_decl (long_integer_type_node, "version"); + chainon (field_decl_chain, field_decl); + + /* long info; */ + field_decl = create_field_decl (long_integer_type_node, "info"); + chainon (field_decl_chain, field_decl); + + /* long instance_size; */ + field_decl = create_field_decl (long_integer_type_node, "instance_size"); + chainon (field_decl_chain, field_decl); + + /* struct _objc_ivar_list *ivars; */ + field_decl = create_field_decl (objc_ivar_list_ptr, + "ivars"); + chainon (field_decl_chain, field_decl); + + /* struct _objc_method_list *methods; */ + field_decl = create_field_decl (objc_method_list_ptr, + "methods"); + chainon (field_decl_chain, field_decl); + + if (flag_next_runtime) + { + /* struct objc_cache *cache; */ + field_decl = create_field_decl (build_pointer_type + (xref_tag (RECORD_TYPE, + get_identifier + ("objc_cache"))), + "cache"); + chainon (field_decl_chain, field_decl); + } + else + { + /* struct sarray *dtable; */ + field_decl = create_field_decl (build_pointer_type + (xref_tag (RECORD_TYPE, + get_identifier + ("sarray"))), + "dtable"); + chainon (field_decl_chain, field_decl); + + /* struct objc_class *subclass_list; */ + field_decl = create_field_decl (build_pointer_type + (objc_class_template), + "subclass_list"); + chainon (field_decl_chain, field_decl); + + /* struct objc_class *sibling_class; */ + field_decl = create_field_decl (build_pointer_type + (objc_class_template), + "sibling_class"); + chainon (field_decl_chain, field_decl); + } + + /* struct _objc_protocol **protocol_list; */ + field_decl = create_field_decl (build_pointer_type + (build_pointer_type + (xref_tag (RECORD_TYPE, + get_identifier + (UTAG_PROTOCOL)))), + "protocol_list"); + chainon (field_decl_chain, field_decl); + + if (flag_next_runtime) + { + /* void *sel_id; */ + field_decl = create_field_decl (build_pointer_type (void_type_node), + "sel_id"); + chainon (field_decl_chain, field_decl); + } + + /* void *gc_object_type; */ + field_decl = create_field_decl (build_pointer_type (void_type_node), + "gc_object_type"); + chainon (field_decl_chain, field_decl); + + finish_struct (objc_class_template, field_decl_chain, NULL_TREE); +} + +/* Generate appropriate forward declarations for an implementation. */ + +static void +synth_forward_declarations (void) +{ + tree an_id; + + /* static struct objc_class _OBJC_CLASS_; */ + UOBJC_CLASS_decl = build_metadata_decl ("_OBJC_CLASS", + objc_class_template); + + /* static struct objc_class _OBJC_METACLASS_; */ + UOBJC_METACLASS_decl = build_metadata_decl ("_OBJC_METACLASS", + objc_class_template); + + /* Pre-build the following entities - for speed/convenience. */ + + an_id = get_identifier ("super_class"); + ucls_super_ref = objc_build_component_ref (UOBJC_CLASS_decl, an_id); + uucls_super_ref = objc_build_component_ref (UOBJC_METACLASS_decl, an_id); +} + +static void +error_with_ivar (const char *message, tree decl) +{ + error ("%J%s %qs", decl, + message, gen_declaration (decl)); + +} + +static void +check_ivars (tree inter, tree imp) +{ + tree intdecls = CLASS_RAW_IVARS (inter); + tree impdecls = CLASS_RAW_IVARS (imp); + + while (1) + { + tree t1, t2; + +#ifdef OBJCPLUS + if (intdecls && TREE_CODE (intdecls) == TYPE_DECL) + intdecls = TREE_CHAIN (intdecls); +#endif + if (intdecls == 0 && impdecls == 0) + break; + if (intdecls == 0 || impdecls == 0) + { + error ("inconsistent instance variable specification"); + break; + } + + t1 = TREE_TYPE (intdecls); t2 = TREE_TYPE (impdecls); + + if (!comptypes (t1, t2) + || !tree_int_cst_equal (DECL_INITIAL (intdecls), + DECL_INITIAL (impdecls))) + { + if (DECL_NAME (intdecls) == DECL_NAME (impdecls)) + { + error_with_ivar ("conflicting instance variable type", + impdecls); + error_with_ivar ("previous declaration of", + intdecls); + } + else /* both the type and the name don't match */ + { + error ("inconsistent instance variable specification"); + break; + } + } + + else if (DECL_NAME (intdecls) != DECL_NAME (impdecls)) + { + error_with_ivar ("conflicting instance variable name", + impdecls); + error_with_ivar ("previous declaration of", + intdecls); + } + + intdecls = TREE_CHAIN (intdecls); + impdecls = TREE_CHAIN (impdecls); + } +} + +/* Set 'objc_super_template' to the data type node for 'struct _objc_super'. + This needs to be done just once per compilation. */ + +/* struct _objc_super { + struct _objc_object *self; + struct _objc_class *super_class; + }; */ + +static void +build_super_template (void) +{ + tree field_decl, field_decl_chain; + + objc_super_template = start_struct (RECORD_TYPE, get_identifier (UTAG_SUPER)); + + /* struct _objc_object *self; */ + field_decl = create_field_decl (objc_object_type, "self"); + field_decl_chain = field_decl; + + /* struct _objc_class *super_class; */ + field_decl = create_field_decl (build_pointer_type (objc_class_template), + "super_class"); + chainon (field_decl_chain, field_decl); + + finish_struct (objc_super_template, field_decl_chain, NULL_TREE); +} + +/* struct _objc_ivar { + char *ivar_name; + char *ivar_type; + int ivar_offset; + }; */ + +static tree +build_ivar_template (void) +{ + tree objc_ivar_id, objc_ivar_record; + tree field_decl, field_decl_chain; + + objc_ivar_id = get_identifier (UTAG_IVAR); + objc_ivar_record = start_struct (RECORD_TYPE, objc_ivar_id); + + /* char *ivar_name; */ + field_decl = create_field_decl (string_type_node, "ivar_name"); + field_decl_chain = field_decl; + + /* char *ivar_type; */ + field_decl = create_field_decl (string_type_node, "ivar_type"); + chainon (field_decl_chain, field_decl); + + /* int ivar_offset; */ + field_decl = create_field_decl (integer_type_node, "ivar_offset"); + chainon (field_decl_chain, field_decl); + + finish_struct (objc_ivar_record, field_decl_chain, NULL_TREE); + + return objc_ivar_record; +} + +/* struct { + int ivar_count; + struct objc_ivar ivar_list[ivar_count]; + }; */ + +static tree +build_ivar_list_template (tree list_type, int size) +{ + tree objc_ivar_list_record; + tree field_decl, field_decl_chain; + + objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE); + + /* int ivar_count; */ + field_decl = create_field_decl (integer_type_node, "ivar_count"); + field_decl_chain = field_decl; + + /* struct objc_ivar ivar_list[]; */ + field_decl = create_field_decl (build_array_type + (list_type, + build_index_type + (build_int_cst (NULL_TREE, size - 1))), + "ivar_list"); + chainon (field_decl_chain, field_decl); + + finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE); + + return objc_ivar_list_record; +} + +/* struct { + struct _objc__method_prototype_list *method_next; + int method_count; + struct objc_method method_list[method_count]; + }; */ + +static tree +build_method_list_template (tree list_type, int size) +{ + tree objc_ivar_list_record; + tree field_decl, field_decl_chain; + + objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE); + + /* struct _objc__method_prototype_list *method_next; */ + field_decl = create_field_decl (objc_method_proto_list_ptr, + "method_next"); + field_decl_chain = field_decl; + + /* int method_count; */ + field_decl = create_field_decl (integer_type_node, "method_count"); + chainon (field_decl_chain, field_decl); + + /* struct objc_method method_list[]; */ + field_decl = create_field_decl (build_array_type + (list_type, + build_index_type + (build_int_cst (NULL_TREE, size - 1))), + "method_list"); + chainon (field_decl_chain, field_decl); + + finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE); + + return objc_ivar_list_record; +} + +static tree +build_ivar_list_initializer (tree type, tree field_decl) +{ + tree initlist = NULL_TREE; + + do + { + tree ivar = NULL_TREE; + + /* Set name. */ + if (DECL_NAME (field_decl)) + ivar = tree_cons (NULL_TREE, + add_objc_string (DECL_NAME (field_decl), + meth_var_names), + ivar); + else + /* Unnamed bit-field ivar (yuck). */ + ivar = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), ivar); + + /* 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); + ivar + = tree_cons + (NULL_TREE, + add_objc_string (get_identifier (obstack_finish (&util_obstack)), + meth_var_types), + ivar); + obstack_free (&util_obstack, util_firstobj); + + /* Set offset. */ + ivar = tree_cons (NULL_TREE, byte_position (field_decl), ivar); + initlist = tree_cons (NULL_TREE, + objc_build_constructor (type, nreverse (ivar)), + initlist); + do + field_decl = TREE_CHAIN (field_decl); + while (field_decl && TREE_CODE (field_decl) != FIELD_DECL); + } + while (field_decl); + + return objc_build_constructor (build_array_type (type, 0), + nreverse (initlist)); +} + +static tree +generate_ivars_list (tree type, const char *name, int size, tree list) +{ + tree decl, initlist; + + decl = start_var_decl (type, synth_id_with_class_suffix + (name, objc_implementation_context)); + + initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, size)); + initlist = tree_cons (NULL_TREE, list, initlist); + + finish_var_decl (decl, + objc_build_constructor (TREE_TYPE (decl), + nreverse (initlist))); + + return decl; +} + +/* Count only the fields occurring in T. */ +static int +ivar_list_length (tree t) +{ + int count = 0; + + for (; t; t = TREE_CHAIN (t)) + if (TREE_CODE (t) == FIELD_DECL) + ++count; + + return count; +} + +static void +generate_ivar_lists (void) +{ + tree initlist, ivar_list_template, chain; + int size; + + generating_instance_variables = 1; + + if (!objc_ivar_template) + objc_ivar_template = build_ivar_template (); + + /* Only generate class variables for the root of the inheritance + hierarchy since these will be the same for every class. */ + + if (CLASS_SUPER_NAME (implementation_template) == NULL_TREE + && (chain = TYPE_FIELDS (objc_class_template))) + { + size = ivar_list_length (chain); + + ivar_list_template = build_ivar_list_template (objc_ivar_template, size); + initlist = build_ivar_list_initializer (objc_ivar_template, chain); + + UOBJC_CLASS_VARIABLES_decl + = generate_ivars_list (ivar_list_template, "_OBJC_CLASS_VARIABLES", + size, initlist); + } + else + UOBJC_CLASS_VARIABLES_decl = 0; + + chain = CLASS_IVARS (implementation_template); + if (chain) + { + size = ivar_list_length (chain); + ivar_list_template = build_ivar_list_template (objc_ivar_template, size); + initlist = build_ivar_list_initializer (objc_ivar_template, chain); + + UOBJC_INSTANCE_VARIABLES_decl + = generate_ivars_list (ivar_list_template, "_OBJC_INSTANCE_VARIABLES", + size, initlist); + } + else + UOBJC_INSTANCE_VARIABLES_decl = 0; + + generating_instance_variables = 0; +} + +static tree +build_dispatch_table_initializer (tree type, tree entries) +{ + tree initlist = NULL_TREE; + + do + { + tree elemlist = NULL_TREE; + + elemlist = tree_cons (NULL_TREE, + build_selector (METHOD_SEL_NAME (entries)), + NULL_TREE); + + /* Generate the method encoding if we don't have one already. */ + if (! METHOD_ENCODING (entries)) + METHOD_ENCODING (entries) = + encode_method_prototype (entries); + + elemlist = tree_cons (NULL_TREE, + add_objc_string (METHOD_ENCODING (entries), + meth_var_types), + elemlist); + + elemlist + = tree_cons (NULL_TREE, + convert (ptr_type_node, + build_unary_op (ADDR_EXPR, + METHOD_DEFINITION (entries), 1)), + elemlist); + + initlist = tree_cons (NULL_TREE, + objc_build_constructor (type, nreverse (elemlist)), + initlist); + + entries = TREE_CHAIN (entries); + } + while (entries); + + return objc_build_constructor (build_array_type (type, 0), + nreverse (initlist)); +} + +/* To accomplish method prototyping without generating all kinds of + inane warnings, the definition of the dispatch table entries were + changed from: + + struct objc_method { SEL _cmd; ...; id (*_imp)(); }; + to: + struct objc_method { SEL _cmd; ...; void *_imp; }; */ + +static tree +build_method_template (void) +{ + tree _SLT_record; + tree field_decl, field_decl_chain; + + _SLT_record = start_struct (RECORD_TYPE, get_identifier (UTAG_METHOD)); + + /* SEL _cmd; */ + field_decl = create_field_decl (objc_selector_type, "_cmd"); + field_decl_chain = field_decl; + + /* char *method_types; */ + field_decl = create_field_decl (string_type_node, "method_types"); + chainon (field_decl_chain, field_decl); + + /* void *_imp; */ + field_decl = create_field_decl (build_pointer_type (void_type_node), + "_imp"); + chainon (field_decl_chain, field_decl); + + finish_struct (_SLT_record, field_decl_chain, NULL_TREE); + + return _SLT_record; +} + + +static tree +generate_dispatch_table (tree type, const char *name, int size, tree list) +{ + tree decl, initlist; + + decl = start_var_decl (type, synth_id_with_class_suffix + (name, objc_implementation_context)); + + initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, 0)); + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, size), initlist); + initlist = tree_cons (NULL_TREE, list, initlist); + + finish_var_decl (decl, + objc_build_constructor (TREE_TYPE (decl), + nreverse (initlist))); + + return decl; +} + +static void +mark_referenced_methods (void) +{ + struct imp_entry *impent; + tree chain; + + for (impent = imp_list; impent; impent = impent->next) + { + chain = CLASS_CLS_METHODS (impent->imp_context); + while (chain) + { + cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain))); + chain = TREE_CHAIN (chain); + } + + chain = CLASS_NST_METHODS (impent->imp_context); + while (chain) + { + cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain))); + chain = TREE_CHAIN (chain); + } + } +} + +static void +generate_dispatch_tables (void) +{ + tree initlist, chain, method_list_template; + int size; + + if (!objc_method_template) + objc_method_template = build_method_template (); + + chain = CLASS_CLS_METHODS (objc_implementation_context); + if (chain) + { + size = list_length (chain); + + method_list_template + = build_method_list_template (objc_method_template, size); + initlist + = build_dispatch_table_initializer (objc_method_template, chain); + + UOBJC_CLASS_METHODS_decl + = generate_dispatch_table (method_list_template, + ((TREE_CODE (objc_implementation_context) + == CLASS_IMPLEMENTATION_TYPE) + ? "_OBJC_CLASS_METHODS" + : "_OBJC_CATEGORY_CLASS_METHODS"), + size, initlist); + } + else + UOBJC_CLASS_METHODS_decl = 0; + + chain = CLASS_NST_METHODS (objc_implementation_context); + if (chain) + { + size = list_length (chain); + + method_list_template + = build_method_list_template (objc_method_template, size); + initlist + = build_dispatch_table_initializer (objc_method_template, chain); + + if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) + UOBJC_INSTANCE_METHODS_decl + = generate_dispatch_table (method_list_template, + "_OBJC_INSTANCE_METHODS", + size, initlist); + else + /* We have a category. */ + UOBJC_INSTANCE_METHODS_decl + = generate_dispatch_table (method_list_template, + "_OBJC_CATEGORY_INSTANCE_METHODS", + size, initlist); + } + else + UOBJC_INSTANCE_METHODS_decl = 0; +} + +static tree +generate_protocol_list (tree i_or_p) +{ + tree initlist; + tree refs_decl, lproto, e, plist; + int size = 0; + const char *ref_name; + + 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 + abort (); + + /* 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. */ + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), NULL_TREE); + e = build_int_cst (build_pointer_type (objc_protocol_template), size); + initlist = tree_cons (NULL_TREE, e, initlist); + + for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) + { + tree pval = TREE_VALUE (lproto); + + if (TREE_CODE (pval) == PROTOCOL_INTERFACE_TYPE + && PROTOCOL_FORWARD_DECL (pval)) + { + e = build_unary_op (ADDR_EXPR, PROTOCOL_FORWARD_DECL (pval), 0); + initlist = tree_cons (NULL_TREE, e, initlist); + } + } + + /* static struct objc_protocol *refs[n]; */ + + if (TREE_CODE (i_or_p) == PROTOCOL_INTERFACE_TYPE) + ref_name = synth_id_with_class_suffix ("_OBJC_PROTOCOL_REFS", i_or_p); + else if (TREE_CODE (i_or_p) == CLASS_INTERFACE_TYPE) + ref_name = synth_id_with_class_suffix ("_OBJC_CLASS_PROTOCOLS", i_or_p); + else if (TREE_CODE (i_or_p) == CATEGORY_INTERFACE_TYPE) + ref_name = synth_id_with_class_suffix ("_OBJC_CATEGORY_PROTOCOLS", i_or_p); + else + abort (); + + refs_decl = start_var_decl + (build_array_type + (build_pointer_type (objc_protocol_template), + build_index_type (build_int_cst (NULL_TREE, size + 2))), + ref_name); + + finish_var_decl (refs_decl, objc_build_constructor (TREE_TYPE (refs_decl), + nreverse (initlist))); + + return refs_decl; +} + +static tree +build_category_initializer (tree type, tree cat_name, tree class_name, + tree instance_methods, tree class_methods, + tree protocol_list) +{ + tree initlist = NULL_TREE, expr; + + initlist = tree_cons (NULL_TREE, cat_name, initlist); + initlist = tree_cons (NULL_TREE, class_name, initlist); + + if (!instance_methods) + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + else + { + expr = convert (objc_method_list_ptr, + build_unary_op (ADDR_EXPR, instance_methods, 0)); + initlist = tree_cons (NULL_TREE, expr, initlist); + } + if (!class_methods) + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + else + { + expr = convert (objc_method_list_ptr, + build_unary_op (ADDR_EXPR, class_methods, 0)); + initlist = tree_cons (NULL_TREE, expr, initlist); + } + + /* protocol_list = */ + if (!protocol_list) + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + else + { + expr = convert (build_pointer_type + (build_pointer_type + (objc_protocol_template)), + build_unary_op (ADDR_EXPR, protocol_list, 0)); + initlist = tree_cons (NULL_TREE, expr, initlist); + } + + return objc_build_constructor (type, nreverse (initlist)); +} + +/* struct _objc_class { + struct objc_class *isa; + struct objc_class *super_class; + char *name; + long version; + long info; + long instance_size; + struct objc_ivar_list *ivars; + struct objc_method_list *methods; + if (flag_next_runtime) + struct objc_cache *cache; + else { + struct sarray *dtable; + struct objc_class *subclass_list; + struct objc_class *sibling_class; + } + struct objc_protocol_list *protocols; + if (flag_next_runtime) + void *sel_id; + void *gc_object_type; + }; */ + +static tree +build_shared_structure_initializer (tree type, tree isa, tree super, + tree name, tree size, int status, + tree dispatch_table, tree ivar_list, + tree protocol_list) +{ + tree initlist = NULL_TREE, expr; + + /* isa = */ + initlist = tree_cons (NULL_TREE, isa, initlist); + + /* super_class = */ + initlist = tree_cons (NULL_TREE, super, initlist); + + /* name = */ + initlist = tree_cons (NULL_TREE, default_conversion (name), initlist); + + /* version = */ + initlist = tree_cons (NULL_TREE, build_int_cst (long_integer_type_node, 0), + initlist); + + /* info = */ + initlist = tree_cons (NULL_TREE, + build_int_cst (long_integer_type_node, status), + initlist); + + /* instance_size = */ + initlist = tree_cons (NULL_TREE, convert (long_integer_type_node, size), + initlist); + + /* objc_ivar_list = */ + if (!ivar_list) + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + else + { + expr = convert (objc_ivar_list_ptr, + build_unary_op (ADDR_EXPR, ivar_list, 0)); + initlist = tree_cons (NULL_TREE, expr, initlist); + } + + /* objc_method_list = */ + if (!dispatch_table) + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + else + { + expr = convert (objc_method_list_ptr, + build_unary_op (ADDR_EXPR, dispatch_table, 0)); + initlist = tree_cons (NULL_TREE, expr, initlist); + } + + if (flag_next_runtime) + /* method_cache = */ + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + else + { + /* dtable = */ + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + + /* subclass_list = */ + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + + /* sibling_class = */ + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + } + + /* protocol_list = */ + if (! protocol_list) + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + else + { + expr = convert (build_pointer_type + (build_pointer_type + (objc_protocol_template)), + build_unary_op (ADDR_EXPR, protocol_list, 0)); + initlist = tree_cons (NULL_TREE, expr, initlist); + } + + if (flag_next_runtime) + /* sel_id = NULL */ + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + + /* gc_object_type = NULL */ + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, 0), initlist); + + return objc_build_constructor (type, nreverse (initlist)); +} + +/* Retrieve category interface CAT_NAME (if any) associated with CLASS. */ + +static inline tree +lookup_category (tree class, tree cat_name) +{ + tree category = CLASS_CATEGORY_LIST (class); + + while (category && CLASS_SUPER_NAME (category) != cat_name) + category = CLASS_CATEGORY_LIST (category); + return category; +} + +/* static struct objc_category _OBJC_CATEGORY_ = { ... }; */ + +static void +generate_category (tree cat) +{ + tree decl; + tree initlist, cat_name_expr, class_name_expr; + tree protocol_decl, category; + + add_class_reference (CLASS_NAME (cat)); + cat_name_expr = add_objc_string (CLASS_SUPER_NAME (cat), class_names); + + class_name_expr = add_objc_string (CLASS_NAME (cat), class_names); + + category = lookup_category (implementation_template, + CLASS_SUPER_NAME (cat)); + + if (category && CLASS_PROTOCOL_LIST (category)) + { + generate_protocol_references (CLASS_PROTOCOL_LIST (category)); + protocol_decl = generate_protocol_list (category); + } + else + protocol_decl = 0; + + decl = start_var_decl (objc_category_template, + synth_id_with_class_suffix + ("_OBJC_CATEGORY", objc_implementation_context)); + + initlist = build_category_initializer (TREE_TYPE (decl), + cat_name_expr, class_name_expr, + UOBJC_INSTANCE_METHODS_decl, + UOBJC_CLASS_METHODS_decl, + protocol_decl); + + finish_var_decl (decl, initlist); +} + +/* static struct objc_class _OBJC_METACLASS_Foo={ ... }; + static struct objc_class _OBJC_CLASS_Foo={ ... }; */ + +static void +generate_shared_structures (int cls_flags) +{ + tree sc_spec, decl_specs, decl; + tree name_expr, super_expr, root_expr; + tree my_root_id = NULL_TREE, my_super_id = NULL_TREE; + tree cast_type, initlist, protocol_decl; + + my_super_id = CLASS_SUPER_NAME (implementation_template); + if (my_super_id) + { + add_class_reference (my_super_id); + + /* Compute "my_root_id" - this is required for code generation. + the "isa" for all meta class structures points to the root of + the inheritance hierarchy (e.g. "__Object")... */ + my_root_id = my_super_id; + do + { + tree my_root_int = lookup_interface (my_root_id); + + if (my_root_int && CLASS_SUPER_NAME (my_root_int)) + my_root_id = CLASS_SUPER_NAME (my_root_int); + else + break; + } + while (1); + } + else + /* No super class. */ + my_root_id = CLASS_NAME (implementation_template); + + cast_type = build_pointer_type (objc_class_template); + name_expr = add_objc_string (CLASS_NAME (implementation_template), + class_names); + + /* Install class `isa' and `super' pointers at runtime. */ + if (my_super_id) + { + super_expr = add_objc_string (my_super_id, class_names); + super_expr = build_c_cast (cast_type, super_expr); /* cast! */ + } + else + super_expr = build_int_cst (NULL_TREE, 0); + + root_expr = add_objc_string (my_root_id, class_names); + root_expr = build_c_cast (cast_type, root_expr); /* cast! */ + + if (CLASS_PROTOCOL_LIST (implementation_template)) + { + generate_protocol_references + (CLASS_PROTOCOL_LIST (implementation_template)); + protocol_decl = generate_protocol_list (implementation_template); + } + else + protocol_decl = 0; + + /* static struct objc_class _OBJC_METACLASS_Foo = { ... }; */ + + sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC]); + decl_specs = tree_cons (NULL_TREE, objc_class_template, sc_spec); + + decl = start_var_decl (objc_class_template, + IDENTIFIER_POINTER + (DECL_NAME (UOBJC_METACLASS_decl))); + + initlist + = build_shared_structure_initializer + (TREE_TYPE (decl), + root_expr, super_expr, name_expr, + convert (integer_type_node, TYPE_SIZE_UNIT (objc_class_template)), + 2 /*CLS_META*/, + UOBJC_CLASS_METHODS_decl, + UOBJC_CLASS_VARIABLES_decl, + protocol_decl); + + finish_var_decl (decl, initlist); + + /* static struct objc_class _OBJC_CLASS_Foo={ ... }; */ + + decl = start_var_decl (objc_class_template, + IDENTIFIER_POINTER + (DECL_NAME (UOBJC_CLASS_decl))); + + initlist + = build_shared_structure_initializer + (TREE_TYPE (decl), + build_unary_op (ADDR_EXPR, UOBJC_METACLASS_decl, 0), + super_expr, name_expr, + convert (integer_type_node, + TYPE_SIZE_UNIT (CLASS_STATIC_TEMPLATE + (implementation_template))), + 1 /*CLS_FACTORY*/ | cls_flags, + UOBJC_INSTANCE_METHODS_decl, + UOBJC_INSTANCE_VARIABLES_decl, + protocol_decl); + + finish_var_decl (decl, initlist); +} + + +static const char * +synth_id_with_class_suffix (const char *preamble, tree ctxt) +{ + static char string[BUFSIZE]; + + if (TREE_CODE (ctxt) == CLASS_IMPLEMENTATION_TYPE + || TREE_CODE (ctxt) == CLASS_INTERFACE_TYPE) + { + sprintf (string, "%s_%s", preamble, + IDENTIFIER_POINTER (CLASS_NAME (ctxt))); + } + else if (TREE_CODE (ctxt) == CATEGORY_IMPLEMENTATION_TYPE + || TREE_CODE (ctxt) == CATEGORY_INTERFACE_TYPE) + { + /* We have a category. */ + const char *const class_name + = IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context)); + const char *const class_super_name + = IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context)); + sprintf (string, "%s_%s_%s", preamble, class_name, class_super_name); + } + else if (TREE_CODE (ctxt) == PROTOCOL_INTERFACE_TYPE) + { + const char *protocol_name = IDENTIFIER_POINTER (PROTOCOL_NAME (ctxt)); + sprintf (string, "%s_%s", preamble, protocol_name); + } + else + abort (); + + return string; +} + +/* If type is empty or only type qualifiers are present, add default + type of id (otherwise grokdeclarator will default to int). */ + +static tree +adjust_type_for_id_default (tree type) +{ + if (!type) + type = make_node (TREE_LIST); + + if (!TREE_VALUE (type)) + TREE_VALUE (type) = objc_object_type; + else if (TREE_CODE (TREE_VALUE (type)) == RECORD_TYPE + && TYPED_OBJECT (TREE_VALUE (type))) + error ("can not use an object as parameter to a method"); + + return type; +} + +/* Usage: + keyworddecl: + selector ':' '(' typename ')' identifier + + Purpose: + Transform an Objective-C keyword argument into + the C equivalent parameter declarator. + + In: key_name, an "identifier_node" (optional). + arg_type, a "tree_list" (optional). + arg_name, an "identifier_node". + + Note: It would be really nice to strongly type the preceding + arguments in the function prototype; however, then I + could not use the "accessor" macros defined in "tree.h". + + Out: an instance of "keyword_decl". */ + +tree +objc_build_keyword_decl (tree key_name, tree arg_type, tree arg_name) +{ + tree keyword_decl; + + /* If no type is specified, default to "id". */ + arg_type = adjust_type_for_id_default (arg_type); + + keyword_decl = make_node (KEYWORD_DECL); + + TREE_TYPE (keyword_decl) = arg_type; + KEYWORD_ARG_NAME (keyword_decl) = arg_name; + KEYWORD_KEY_NAME (keyword_decl) = key_name; + + return keyword_decl; +} + +/* Given a chain of keyword_decl's, synthesize the full keyword selector. */ + +static tree +build_keyword_selector (tree selector) +{ + int len = 0; + tree key_chain, key_name; + char *buf; + + /* Scan the selector to see how much space we'll need. */ + for (key_chain = selector; key_chain; key_chain = TREE_CHAIN (key_chain)) + { + if (TREE_CODE (selector) == KEYWORD_DECL) + key_name = KEYWORD_KEY_NAME (key_chain); + else if (TREE_CODE (selector) == TREE_LIST) + key_name = TREE_PURPOSE (key_chain); + else + abort (); + + if (key_name) + len += IDENTIFIER_LENGTH (key_name) + 1; + else + /* Just a ':' arg. */ + len++; + } + + buf = (char *) alloca (len + 1); + /* Start the buffer out as an empty string. */ + buf[0] = '\0'; + + for (key_chain = selector; key_chain; key_chain = TREE_CHAIN (key_chain)) + { + if (TREE_CODE (selector) == KEYWORD_DECL) + key_name = KEYWORD_KEY_NAME (key_chain); + else if (TREE_CODE (selector) == TREE_LIST) + { + key_name = TREE_PURPOSE (key_chain); + /* The keyword decl chain will later be used as a function argument + chain. Unhook the selector itself so as to not confuse other + parts of the compiler. */ + TREE_PURPOSE (key_chain) = NULL_TREE; + } + else + abort (); + + if (key_name) + strcat (buf, IDENTIFIER_POINTER (key_name)); + strcat (buf, ":"); + } + + return get_identifier (buf); +} + +/* Used for declarations and definitions. */ + +static tree +build_method_decl (enum tree_code code, tree ret_type, tree selector, + tree add_args, bool ellipsis) +{ + tree method_decl; + + /* If no type is specified, default to "id". */ + ret_type = adjust_type_for_id_default (ret_type); + + method_decl = make_node (code); + TREE_TYPE (method_decl) = ret_type; + + /* If we have a keyword selector, create an identifier_node that + represents the full selector name (`:' included)... */ + if (TREE_CODE (selector) == KEYWORD_DECL) + { + METHOD_SEL_NAME (method_decl) = build_keyword_selector (selector); + METHOD_SEL_ARGS (method_decl) = selector; + METHOD_ADD_ARGS (method_decl) = add_args; + METHOD_ADD_ARGS_ELLIPSIS_P (method_decl) = ellipsis; + } + else + { + METHOD_SEL_NAME (method_decl) = selector; + METHOD_SEL_ARGS (method_decl) = NULL_TREE; + METHOD_ADD_ARGS (method_decl) = NULL_TREE; + } + + return method_decl; +} + +#define METHOD_DEF 0 +#define METHOD_REF 1 + +/* Used by `build_objc_method_call' and `comp_proto_with_proto'. Return + an argument list for method METH. 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; this makes a + difference for the NeXT calling sequence in which the lookup and + the method call are done together. If METH is null, user-defined + arguments (i.e., beyond self and _cmd) shall be represented by `...'. */ + +static tree +get_arg_type_list (tree meth, int context, int superflag) +{ + tree arglist, akey; + + /* Receiver type. */ + if (flag_next_runtime && superflag) + arglist = build_tree_list (NULL_TREE, objc_super_type); + else if (context == METHOD_DEF && TREE_CODE (meth) == INSTANCE_METHOD_DECL) + arglist = build_tree_list (NULL_TREE, objc_instance_type); + else + arglist = build_tree_list (NULL_TREE, objc_object_type); + + /* Selector type - will eventually change to `int'. */ + chainon (arglist, build_tree_list (NULL_TREE, objc_selector_type)); + + /* No actual method prototype given -- assume that remaining arguments + are `...'. */ + if (!meth) + return arglist; + + /* Build a list of argument types. */ + for (akey = METHOD_SEL_ARGS (meth); akey; akey = TREE_CHAIN (akey)) + { + tree arg_type = TREE_VALUE (TREE_TYPE (akey)); + + /* Decay arrays and functions into pointers. */ + if (TREE_CODE (arg_type) == ARRAY_TYPE) + arg_type = build_pointer_type (TREE_TYPE (arg_type)); + else if (TREE_CODE (arg_type) == FUNCTION_TYPE) + arg_type = build_pointer_type (arg_type); + + chainon (arglist, build_tree_list (NULL_TREE, arg_type)); + } + + if (METHOD_ADD_ARGS (meth)) + { + for (akey = TREE_CHAIN (METHOD_ADD_ARGS (meth)); + akey; akey = TREE_CHAIN (akey)) + { + tree arg_type = TREE_TYPE (TREE_VALUE (akey)); + + chainon (arglist, build_tree_list (NULL_TREE, arg_type)); + } + + if (!METHOD_ADD_ARGS_ELLIPSIS_P (meth)) + goto lack_of_ellipsis; + } + else + { + lack_of_ellipsis: + chainon (arglist, OBJC_VOID_AT_END); + } + + return arglist; +} + +static tree +check_duplicates (hash hsh, int methods, int is_class) +{ + tree meth = NULL_TREE; + + if (hsh) + { + meth = hsh->key; + + if (hsh->list) + { + /* We have two or more methods with the same name but + different types. */ + attr loop; + + /* But just how different are those types? If + -Wno-strict-selector-match is specified, we shall not + complain if the differences are solely among types with + identical size and alignment. */ + if (!warn_strict_selector_match) + { + for (loop = hsh->list; loop; loop = loop->next) + if (!comp_proto_with_proto (meth, loop->value, 0)) + goto issue_warning; + + return meth; + } + + issue_warning: + warning (0, "multiple %s named %<%c%s%> found", + methods ? "methods" : "selectors", + (is_class ? '+' : '-'), + IDENTIFIER_POINTER (METHOD_SEL_NAME (meth))); + + warn_with_method (methods ? "using" : "found", + ((TREE_CODE (meth) == INSTANCE_METHOD_DECL) + ? '-' + : '+'), + meth); + for (loop = hsh->list; loop; loop = loop->next) + warn_with_method ("also found", + ((TREE_CODE (loop->value) == INSTANCE_METHOD_DECL) + ? '-' + : '+'), + loop->value); + } + } + return meth; +} + +/* If RECEIVER is a class reference, return the identifier node for + the referenced class. RECEIVER is created by objc_get_class_reference, + so we check the exact form created depending on which runtimes are + used. */ + +static tree +receiver_is_class_object (tree receiver, int self, int super) +{ + tree chain, exp, arg; + + /* The receiver is 'self' or 'super' in the context of a class method. */ + if (objc_method_context + && TREE_CODE (objc_method_context) == CLASS_METHOD_DECL + && (self || super)) + return (super + ? CLASS_SUPER_NAME (implementation_template) + : CLASS_NAME (implementation_template)); + + if (flag_next_runtime) + { + /* The receiver is a variable created by + build_class_reference_decl. */ + if (TREE_CODE (receiver) == VAR_DECL && IS_CLASS (TREE_TYPE (receiver))) + /* Look up the identifier. */ + for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain)) + if (TREE_PURPOSE (chain) == receiver) + return TREE_VALUE (chain); + } + + /* The receiver is a function call that returns an id. Check if + it is a call to objc_getClass, if so, pick up the class name. */ + if (TREE_CODE (receiver) == CALL_EXPR + && (exp = TREE_OPERAND (receiver, 0)) + && TREE_CODE (exp) == ADDR_EXPR + && (exp = TREE_OPERAND (exp, 0)) + && TREE_CODE (exp) == FUNCTION_DECL + /* For some reason, we sometimes wind up with multiple FUNCTION_DECL + prototypes for objc_get_class(). Thankfully, they seem to share the + same function type. */ + && TREE_TYPE (exp) == TREE_TYPE (objc_get_class_decl) + && !strcmp (IDENTIFIER_POINTER (DECL_NAME (exp)), TAG_GETCLASS) + /* We have a call to objc_get_class/objc_getClass! */ + && (arg = TREE_OPERAND (receiver, 1)) + && TREE_CODE (arg) == TREE_LIST + && (arg = TREE_VALUE (arg))) + { + STRIP_NOPS (arg); + if (TREE_CODE (arg) == ADDR_EXPR + && (arg = TREE_OPERAND (arg, 0)) + && TREE_CODE (arg) == STRING_CST) + /* Finally, we have the class name. */ + return get_identifier (TREE_STRING_POINTER (arg)); + } + return 0; +} + +/* If we are currently building a message expr, this holds + the identifier of the selector of the message. This is + used when printing warnings about argument mismatches. */ + +static tree current_objc_message_selector = 0; + +tree +objc_message_selector (void) +{ + return current_objc_message_selector; +} + +/* Construct an expression for sending a message. + MESS has the object to send to in TREE_PURPOSE + and the argument list (including selector) in TREE_VALUE. + + (*((*)())_msg)(receiver, selTransTbl[n], ...); + (*((*)())_msgSuper)(receiver, selTransTbl[n], ...); */ + +tree +objc_build_message_expr (tree mess) +{ + tree receiver = TREE_PURPOSE (mess); + tree sel_name; +#ifdef OBJCPLUS + tree args = TREE_PURPOSE (TREE_VALUE (mess)); +#else + tree args = TREE_VALUE (mess); +#endif + tree method_params = NULL_TREE; + + if (TREE_CODE (receiver) == ERROR_MARK) + return error_mark_node; + + /* Obtain the full selector name. */ + if (TREE_CODE (args) == IDENTIFIER_NODE) + /* A unary selector. */ + sel_name = args; + else if (TREE_CODE (args) == TREE_LIST) + sel_name = build_keyword_selector (args); + else + abort (); + + /* Build the parameter list to give to the method. */ + if (TREE_CODE (args) == TREE_LIST) +#ifdef OBJCPLUS + method_params = chainon (args, TREE_VALUE (TREE_VALUE (mess))); +#else + { + tree chain = args, prev = NULL_TREE; + + /* We have a keyword selector--check for comma expressions. */ + while (chain) + { + tree element = TREE_VALUE (chain); + + /* We have a comma expression, must collapse... */ + if (TREE_CODE (element) == TREE_LIST) + { + if (prev) + TREE_CHAIN (prev) = element; + else + args = element; + } + prev = chain; + chain = TREE_CHAIN (chain); + } + method_params = args; + } +#endif + +#ifdef OBJCPLUS + if (processing_template_decl) + /* Must wait until template instantiation time. */ + return build_min_nt (MESSAGE_SEND_EXPR, receiver, sel_name, + method_params); +#endif + + return objc_finish_message_expr (receiver, sel_name, method_params); +} + +/* Look up method SEL_NAME that would be suitable for receiver + of type 'id' (if IS_CLASS is zero) or 'Class' (if IS_CLASS is + nonzero), and report on any duplicates. */ + +static tree +lookup_method_in_hash_lists (tree sel_name, int is_class) +{ + hash method_prototype = NULL; + + if (!is_class) + method_prototype = hash_lookup (nst_method_hash_list, + sel_name); + + if (!method_prototype) + { + method_prototype = hash_lookup (cls_method_hash_list, + sel_name); + is_class = 1; + } + + return check_duplicates (method_prototype, 1, is_class); +} + +/* The 'objc_finish_message_expr' routine is called from within + 'objc_build_message_expr' for non-template functions. In the case of + C++ template functions, it is called from 'build_expr_from_tree' + (in decl2.c) after RECEIVER and METHOD_PARAMS have been expanded. */ + +tree +objc_finish_message_expr (tree receiver, tree sel_name, tree method_params) +{ + tree method_prototype = NULL_TREE, rprotos = NULL_TREE, rtype; + tree selector, retval, class_tree; + int self, super, have_cast; + + /* Extract the receiver of the message, as well as its type + (where the latter may take the form of a cast or be inferred + from the implementation context). */ + rtype = receiver; + while (TREE_CODE (rtype) == COMPOUND_EXPR + || TREE_CODE (rtype) == MODIFY_EXPR + || TREE_CODE (rtype) == NOP_EXPR + || TREE_CODE (rtype) == CONVERT_EXPR + || TREE_CODE (rtype) == COMPONENT_REF) + rtype = TREE_OPERAND (rtype, 0); + self = (rtype == self_decl); + super = (rtype == UOBJC_SUPER_decl); + rtype = TREE_TYPE (receiver); + have_cast = (TREE_CODE (receiver) == NOP_EXPR + || (TREE_CODE (receiver) == COMPOUND_EXPR + && !IS_SUPER (rtype))); + + /* If we are calling [super dealloc], reset our warning flag. */ + if (super && !strcmp ("dealloc", IDENTIFIER_POINTER (sel_name))) + should_call_super_dealloc = 0; + + /* If the receiver is a class object, retrieve the corresponding + @interface, if one exists. */ + class_tree = receiver_is_class_object (receiver, self, super); + + /* Now determine the receiver type (if an explicit cast has not been + provided). */ + if (!have_cast) + { + if (class_tree) + rtype = lookup_interface (class_tree); + /* Handle `self' and `super'. */ + else if (super) + { + if (!CLASS_SUPER_NAME (implementation_template)) + { + error ("no super class declared in @interface for %qs", + IDENTIFIER_POINTER (CLASS_NAME (implementation_template))); + return error_mark_node; + } + rtype = lookup_interface (CLASS_SUPER_NAME (implementation_template)); + } + else if (self) + rtype = lookup_interface (CLASS_NAME (implementation_template)); + } + + /* If receiver is of type `id' or `Class' (or if the @interface for a + class is not visible), we shall be satisfied with the existence of + any instance or class method. */ + if (objc_is_id (rtype)) + { + class_tree = (IS_CLASS (rtype) ? objc_class_name : NULL_TREE); + rprotos = (TYPE_HAS_OBJC_INFO (TREE_TYPE (rtype)) + ? TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rtype)) + : NULL_TREE); + rtype = NULL_TREE; + + if (rprotos) + { + /* If messaging 'id ' or 'Class ', first search + in protocols themselves for the method prototype. */ + method_prototype + = lookup_method_in_protocol_list (rprotos, sel_name, + class_tree != NULL_TREE); + + /* If messaging 'Class ' but did not find a class method + prototype, search for an instance method instead, and warn + about having done so. */ + if (!method_prototype && !rtype && class_tree != NULL_TREE) + { + method_prototype + = lookup_method_in_protocol_list (rprotos, sel_name, 0); + + if (method_prototype) + warning (0, "found %<-%s%> instead of %<+%s%> in protocol(s)", + IDENTIFIER_POINTER (sel_name), + IDENTIFIER_POINTER (sel_name)); + } + } + } + else if (rtype) + { + tree orig_rtype = rtype, saved_rtype; + + if (TREE_CODE (rtype) == POINTER_TYPE) + rtype = TREE_TYPE (rtype); + /* Traverse typedef aliases */ + while (TREE_CODE (rtype) == RECORD_TYPE && OBJC_TYPE_NAME (rtype) + && TREE_CODE (OBJC_TYPE_NAME (rtype)) == TYPE_DECL + && DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (rtype))) + rtype = DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (rtype)); + saved_rtype = rtype; + if (TYPED_OBJECT (rtype)) + { + rprotos = TYPE_OBJC_PROTOCOL_LIST (rtype); + rtype = TYPE_OBJC_INTERFACE (rtype); + } + /* If we could not find an @interface declaration, we must have + only seen a @class declaration; so, we cannot say anything + more intelligent about which methods the receiver will + understand. */ + if (!rtype || TREE_CODE (rtype) == IDENTIFIER_NODE) + rtype = NULL_TREE; + else if (TREE_CODE (rtype) == CLASS_INTERFACE_TYPE + || TREE_CODE (rtype) == CLASS_IMPLEMENTATION_TYPE) + { + /* We have a valid ObjC class name. Look up the method name + in the published @interface for the class (and its + superclasses). */ + method_prototype + = lookup_method_static (rtype, sel_name, class_tree != NULL_TREE); + + /* If the method was not found in the @interface, it may still + exist locally as part of the @implementation. */ + if (!method_prototype && objc_implementation_context + && CLASS_NAME (objc_implementation_context) + == OBJC_TYPE_NAME (rtype)) + method_prototype + = lookup_method + ((class_tree + ? CLASS_CLS_METHODS (objc_implementation_context) + : CLASS_NST_METHODS (objc_implementation_context)), + sel_name); + + /* If we haven't found a candidate method by now, try looking for + it in the protocol list. */ + if (!method_prototype && rprotos) + method_prototype + = lookup_method_in_protocol_list (rprotos, sel_name, + class_tree != NULL_TREE); + } + else + { + warning (0, "invalid receiver type %qs", + gen_type_name (orig_rtype)); + /* After issuing the "invalid receiver" warning, perform method + lookup as if we were messaging 'id'. */ + rtype = rprotos = NULL_TREE; + } + } + + + /* For 'id' or 'Class' receivers, search in the global hash table + as a last resort. For all receivers, warn if protocol searches + have failed. */ + if (!method_prototype) + { + if (rprotos) + warning (0, "%<%c%s%> not found in protocol(s)", + (class_tree ? '+' : '-'), + IDENTIFIER_POINTER (sel_name)); + + if (!rtype) + method_prototype + = lookup_method_in_hash_lists (sel_name, class_tree != NULL_TREE); + } + + if (!method_prototype) + { + static bool warn_missing_methods = false; + + if (rtype) + warning (0, "%qs may not respond to %<%c%s%>", + IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype)), + (class_tree ? '+' : '-'), + IDENTIFIER_POINTER (sel_name)); + /* If we are messaging an 'id' or 'Class' object and made it here, + then we have failed to find _any_ instance or class method, + respectively. */ + else + warning (0, "no %<%c%s%> method found", + (class_tree ? '+' : '-'), + IDENTIFIER_POINTER (sel_name)); + + if (!warn_missing_methods) + { + warning (0, "(Messages without a matching method signature"); + warning (0, "will be assumed to return % and accept"); + warning (0, "%<...%> as arguments.)"); + warn_missing_methods = true; + } + } + + /* Save the selector name for printing error messages. */ + current_objc_message_selector = sel_name; + + /* Build the parameters list for looking up the method. + These are the object itself and the selector. */ + + if (flag_typed_selectors) + selector = build_typed_selector_reference (sel_name, method_prototype); + else + selector = build_selector_reference (sel_name); + + retval = build_objc_method_call (super, method_prototype, + receiver, + selector, method_params); + + current_objc_message_selector = 0; + + return retval; +} + +/* Build a tree expression to send OBJECT the operation SELECTOR, + looking up the method on object LOOKUP_OBJECT (often same as OBJECT), + assuming the method has prototype METHOD_PROTOTYPE. + (That is an INSTANCE_METHOD_DECL or CLASS_METHOD_DECL.) + 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 (int super_flag, tree method_prototype, + tree lookup_object, tree selector, + tree method_params) +{ + tree sender = (super_flag ? umsg_super_decl : + (!flag_next_runtime || flag_nil_receivers + ? (flag_objc_direct_dispatch + ? umsg_fast_decl + : umsg_decl) + : umsg_nonnil_decl)); + tree rcv_p = (super_flag ? objc_super_type : objc_object_type); + + /* 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 sender_cast + = build_pointer_type + (build_function_type + (ret_type, + get_arg_type_list + (method_prototype, METHOD_REF, super_flag))); + tree method, t; + + lookup_object = build_c_cast (rcv_p, lookup_object); + + /* Use SAVE_EXPR to avoid evaluating the receiver twice. */ + lookup_object = save_expr (lookup_object); + + if (flag_next_runtime) + { + /* If we are returning a struct in memory, and the address + of that memory location is passed as a hidden first + argument, then change which messenger entry point this + expr will call. NB: Note that sender_cast remains + unchanged (it already has a struct return type). */ + if (!targetm.calls.struct_value_rtx (0, 0) + && (TREE_CODE (ret_type) == RECORD_TYPE + || TREE_CODE (ret_type) == UNION_TYPE) + && targetm.calls.return_in_memory (ret_type, 0)) + sender = (super_flag ? umsg_super_stret_decl : + flag_nil_receivers ? umsg_stret_decl : umsg_nonnil_stret_decl); + + method_params = tree_cons (NULL_TREE, lookup_object, + tree_cons (NULL_TREE, selector, + method_params)); + method = build_fold_addr_expr (sender); + } + else + { + /* This is the portable (GNU) way. */ + tree object; + + /* First, call the lookup function to get a pointer to the method, + then cast the pointer, then call it with the method arguments. */ + + object = (super_flag ? self_decl : lookup_object); + + t = tree_cons (NULL_TREE, selector, NULL_TREE); + t = tree_cons (NULL_TREE, lookup_object, t); + method = build_function_call (sender, t); + + /* Pass the object to the method. */ + method_params = tree_cons (NULL_TREE, object, + tree_cons (NULL_TREE, selector, + method_params)); + } + + /* ??? Selector is not at this point something we can use inside + the compiler itself. Set it to garbage for the nonce. */ + t = build (OBJ_TYPE_REF, sender_cast, method, lookup_object, size_zero_node); + return build_function_call (t, method_params); +} + +static void +build_protocol_reference (tree p) +{ + tree decl; + const char *proto_name; + + /* static struct _objc_protocol _OBJC_PROTOCOL_; */ + + proto_name = synth_id_with_class_suffix ("_OBJC_PROTOCOL", p); + decl = start_var_decl (objc_protocol_template, proto_name); + + PROTOCOL_FORWARD_DECL (p) = decl; +} + +/* This function is called by the parser when (and only when) a + @protocol() expression is found, in order to compile it. */ +tree +objc_build_protocol_expr (tree protoname) +{ + tree expr; + tree p = lookup_protocol (protoname); + + if (!p) + { + error ("cannot find protocol declaration for %qs", + IDENTIFIER_POINTER (protoname)); + return error_mark_node; + } + + if (!PROTOCOL_FORWARD_DECL (p)) + build_protocol_reference (p); + + expr = build_unary_op (ADDR_EXPR, PROTOCOL_FORWARD_DECL (p), 0); + + /* ??? Ideally we'd build the reference with objc_protocol_type directly, + if we have it, rather than converting it here. */ + expr = convert (objc_protocol_type, expr); + + /* The @protocol() expression is being compiled into a pointer to a + statically allocated instance of the Protocol class. To become + usable at runtime, the 'isa' pointer of the instance need to be + fixed up at runtime by the runtime library, to point to the + actual 'Protocol' class. */ + + /* For the GNU runtime, put the static Protocol instance in the list + of statically allocated instances, so that we make sure that its + 'isa' pointer is fixed up at runtime by the GNU runtime library + to point to the Protocol class (at runtime, when loading the + module, the GNU runtime library loops on the statically allocated + instances (as found in the defs field in objc_symtab) and fixups + all the 'isa' pointers of those objects). */ + if (! flag_next_runtime) + { + /* This type is a struct containing the fields of a Protocol + object. (Cfr. objc_protocol_type instead is the type of a pointer + to such a struct). */ + tree protocol_struct_type = xref_tag + (RECORD_TYPE, get_identifier (PROTOCOL_OBJECT_CLASS_NAME)); + tree *chain; + + /* Look for the list of Protocol statically allocated instances + to fixup at runtime. Create a new list to hold Protocol + statically allocated instances, if the list is not found. At + present there is only another list, holding NSConstantString + static instances to be fixed up at runtime. */ + for (chain = &objc_static_instances; + *chain && TREE_VALUE (*chain) != protocol_struct_type; + chain = &TREE_CHAIN (*chain)); + if (!*chain) + { + *chain = tree_cons (NULL_TREE, protocol_struct_type, NULL_TREE); + add_objc_string (OBJC_TYPE_NAME (protocol_struct_type), + class_names); + } + + /* Add this statically allocated instance to the Protocol list. */ + TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, + PROTOCOL_FORWARD_DECL (p), + TREE_PURPOSE (*chain)); + } + + + return expr; +} + +/* This function is called by the parser when a @selector() expression + is found, in order to compile it. It is only called by the parser + and only to compile a @selector(). */ +tree +objc_build_selector_expr (tree selnamelist) +{ + tree selname; + + /* Obtain the full selector name. */ + if (TREE_CODE (selnamelist) == IDENTIFIER_NODE) + /* A unary selector. */ + selname = selnamelist; + else if (TREE_CODE (selnamelist) == TREE_LIST) + selname = build_keyword_selector (selnamelist); + else + abort (); + + /* If we are required to check @selector() expressions as they + are found, check that the selector has been declared. */ + if (warn_undeclared_selector) + { + /* Look the selector up in the list of all known class and + instance methods (up to this line) to check that the selector + exists. */ + hash hsh; + + /* First try with instance methods. */ + hsh = hash_lookup (nst_method_hash_list, selname); + + /* If not found, try with class methods. */ + if (!hsh) + { + hsh = hash_lookup (cls_method_hash_list, selname); + } + + /* If still not found, print out a warning. */ + if (!hsh) + { + warning (0, "undeclared selector %qs", IDENTIFIER_POINTER (selname)); + } + } + + + if (flag_typed_selectors) + return build_typed_selector_reference (selname, 0); + else + return build_selector_reference (selname); +} + +tree +objc_build_encode_expr (tree type) +{ + tree result; + const char *string; + + encode_type (type, obstack_object_size (&util_obstack), + OBJC_ENCODE_INLINE_DEFS); + obstack_1grow (&util_obstack, 0); /* null terminate string */ + string = obstack_finish (&util_obstack); + + /* Synthesize a string that represents the encoded struct/union. */ + result = my_build_string (strlen (string) + 1, string); + obstack_free (&util_obstack, util_firstobj); + return result; +} + +static tree +build_ivar_reference (tree id) +{ + if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL) + { + /* Historically, a class method that produced objects (factory + method) would assign `self' to the instance that it + allocated. This would effectively turn the class method into + an instance method. Following this assignment, the instance + variables could be accessed. That practice, while safe, + violates the simple rule that a class method should not refer + to an instance variable. It's better to catch the cases + where this is done unknowingly than to support the above + paradigm. */ + warning (0, "instance variable %qs accessed in class method", + IDENTIFIER_POINTER (id)); + self_decl = convert (objc_instance_type, self_decl); /* cast */ + } + + return objc_build_component_ref (build_indirect_ref (self_decl, "->"), id); +} + +/* Compute a hash value for a given method SEL_NAME. */ + +static size_t +hash_func (tree sel_name) +{ + const unsigned char *s + = (const unsigned char *)IDENTIFIER_POINTER (sel_name); + size_t h = 0; + + while (*s) + h = h * 67 + *s++ - 113; + return h; +} + +static void +hash_init (void) +{ + nst_method_hash_list + = (hash *) ggc_alloc_cleared (SIZEHASHTABLE * sizeof (hash)); + cls_method_hash_list + = (hash *) ggc_alloc_cleared (SIZEHASHTABLE * sizeof (hash)); + + /* Initialize the hash table used to hold the constant string objects. */ + string_htab = htab_create_ggc (31, string_hash, + string_eq, NULL); + + /* Initialize the hash table used to hold EH-volatilized types. */ + volatilized_htab = htab_create_ggc (31, volatilized_hash, + volatilized_eq, NULL); +} + +/* WARNING!!!! hash_enter is called with a method, and will peek + inside to find its selector! But hash_lookup is given a selector + directly, and looks for the selector that's inside the found + entry's key (method) for comparison. */ + +static void +hash_enter (hash *hashlist, tree method) +{ + hash obj; + int slot = hash_func (METHOD_SEL_NAME (method)) % SIZEHASHTABLE; + + obj = (hash) ggc_alloc (sizeof (struct hashed_entry)); + obj->list = 0; + obj->next = hashlist[slot]; + obj->key = method; + + hashlist[slot] = obj; /* append to front */ +} + +static hash +hash_lookup (hash *hashlist, tree sel_name) +{ + hash target; + + target = hashlist[hash_func (sel_name) % SIZEHASHTABLE]; + + while (target) + { + if (sel_name == METHOD_SEL_NAME (target->key)) + return target; + + target = target->next; + } + return 0; +} + +static void +hash_add_attr (hash entry, tree value) +{ + attr obj; + + obj = (attr) ggc_alloc (sizeof (struct hashed_attribute)); + obj->next = entry->list; + obj->value = value; + + entry->list = obj; /* append to front */ +} + +static tree +lookup_method (tree mchain, tree method) +{ + tree key; + + if (TREE_CODE (method) == IDENTIFIER_NODE) + key = method; + else + key = METHOD_SEL_NAME (method); + + while (mchain) + { + if (METHOD_SEL_NAME (mchain) == key) + return mchain; + + mchain = TREE_CHAIN (mchain); + } + return NULL_TREE; +} + +/* Look up a class (if OBJC_LOOKUP_CLASS is set in FLAGS) or instance method + in INTERFACE, along with any categories and protocols attached thereto. + If method is not found, and the OBJC_LOOKUP_NO_SUPER is _not_ set in FLAGS, + recursively examine the INTERFACE's superclass. If OBJC_LOOKUP_CLASS is + set, OBJC_LOOKUP_NO_SUPER is cleared, and no suitable class method could + be found in INTERFACE or any of its superclasses, look for an _instance_ + method of the same name in the root class as a last resort. + + If a suitable method cannot be found, return NULL_TREE. */ + +static tree +lookup_method_static (tree interface, tree ident, int flags) +{ + tree meth = NULL_TREE, root_inter = NULL_TREE; + tree inter = interface; + int is_class = (flags & OBJC_LOOKUP_CLASS); + int no_superclasses = (flags & OBJC_LOOKUP_NO_SUPER); + + while (inter) + { + tree chain = is_class ? CLASS_CLS_METHODS (inter) : CLASS_NST_METHODS (inter); + tree category = inter; + + /* First, look up the method in the class itself. */ + if ((meth = lookup_method (chain, ident))) + return meth; + + /* Failing that, look for the method in each category of the class. */ + while ((category = CLASS_CATEGORY_LIST (category))) + { + chain = is_class ? CLASS_CLS_METHODS (category) : CLASS_NST_METHODS (category); + + /* Check directly in each category. */ + if ((meth = lookup_method (chain, ident))) + return meth; + + /* Failing that, check in each category's protocols. */ + if (CLASS_PROTOCOL_LIST (category)) + { + if ((meth = (lookup_method_in_protocol_list + (CLASS_PROTOCOL_LIST (category), ident, is_class)))) + return meth; + } + } + + /* If not found in categories, check in protocols of the main class. */ + if (CLASS_PROTOCOL_LIST (inter)) + { + if ((meth = (lookup_method_in_protocol_list + (CLASS_PROTOCOL_LIST (inter), ident, is_class)))) + return meth; + } + + /* If we were instructed not to look in superclasses, don't. */ + if (no_superclasses) + return NULL_TREE; + + /* Failing that, climb up the inheritance hierarchy. */ + root_inter = inter; + inter = lookup_interface (CLASS_SUPER_NAME (inter)); + } + while (inter); + + /* If no class (factory) method was found, check if an _instance_ + method of the same name exists in the root class. This is what + the Objective-C runtime will do. If an instance method was not + found, return 0. */ + return is_class ? lookup_method_static (root_inter, ident, 0): NULL_TREE; +} + +/* Add the method to the hash list if it doesn't contain an identical + method already. */ +static void +add_method_to_hash_list (hash *hash_list, tree method) +{ + hash hsh; + + if (!(hsh = hash_lookup (hash_list, METHOD_SEL_NAME (method)))) + { + /* Install on a global chain. */ + hash_enter (hash_list, method); + } + else + { + /* Check types against those; if different, add to a list. */ + attr loop; + int already_there = comp_proto_with_proto (method, hsh->key, 1); + for (loop = hsh->list; !already_there && loop; loop = loop->next) + already_there |= comp_proto_with_proto (method, loop->value, 1); + if (!already_there) + hash_add_attr (hsh, method); + } +} + +static tree +objc_add_method (tree class, tree method, int is_class) +{ + tree mth; + + if (!(mth = lookup_method (is_class + ? CLASS_CLS_METHODS (class) + : CLASS_NST_METHODS (class), method))) + { + /* put method on list in reverse order */ + if (is_class) + { + TREE_CHAIN (method) = CLASS_CLS_METHODS (class); + CLASS_CLS_METHODS (class) = method; + } + else + { + TREE_CHAIN (method) = CLASS_NST_METHODS (class); + CLASS_NST_METHODS (class) = method; + } + } + else + { + /* When processing an @interface for a class or category, give hard + errors on methods with identical selectors but differing argument + and/or return types. We do not do this for @implementations, because + C/C++ will do it for us (i.e., there will be duplicate function + definition errors). */ + if ((TREE_CODE (class) == CLASS_INTERFACE_TYPE + || TREE_CODE (class) == CATEGORY_INTERFACE_TYPE) + && !comp_proto_with_proto (method, mth, 1)) + error ("duplicate declaration of method %<%c%s%>", + is_class ? '+' : '-', + IDENTIFIER_POINTER (METHOD_SEL_NAME (mth))); + } + + if (is_class) + add_method_to_hash_list (cls_method_hash_list, method); + else + { + add_method_to_hash_list (nst_method_hash_list, method); + + /* Instance methods in root classes (and categories thereof) + may act as class methods as a last resort. We also add + instance methods listed in @protocol declarations to + the class hash table, on the assumption that @protocols + may be adopted by root classes or categories. */ + if (TREE_CODE (class) == CATEGORY_INTERFACE_TYPE + || TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE) + class = lookup_interface (CLASS_NAME (class)); + + if (TREE_CODE (class) == PROTOCOL_INTERFACE_TYPE + || !CLASS_SUPER_NAME (class)) + add_method_to_hash_list (cls_method_hash_list, method); + } + + return method; +} + +static tree +add_class (tree class_name, tree name) +{ + struct interface_tuple **slot; + + /* Put interfaces on list in reverse order. */ + TREE_CHAIN (class_name) = interface_chain; + interface_chain = class_name; + + if (interface_htab == NULL) + interface_htab = htab_create_ggc (31, hash_interface, eq_interface, NULL); + slot = (struct interface_tuple **) + htab_find_slot_with_hash (interface_htab, name, + IDENTIFIER_HASH_VALUE (name), + INSERT); + if (!*slot) + { + *slot = (struct interface_tuple *) ggc_alloc_cleared (sizeof (struct interface_tuple)); + (*slot)->id = name; + } + (*slot)->class_name = class_name; + + return interface_chain; +} + +static void +add_category (tree class, tree category) +{ + /* Put categories on list in reverse order. */ + tree cat = lookup_category (class, CLASS_SUPER_NAME (category)); + + if (cat) + { + warning (0, "duplicate interface declaration for category %<%s(%s)%>", + IDENTIFIER_POINTER (CLASS_NAME (class)), + IDENTIFIER_POINTER (CLASS_SUPER_NAME (category))); + } + else + { + CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class); + CLASS_CATEGORY_LIST (class) = category; + } +} + +/* Called after parsing each instance variable declaration. Necessary to + preserve typedefs and implement public/private... + + PUBLIC is 1 for public, 0 for protected, and 2 for private. */ + +static tree +add_instance_variable (tree class, int public, tree field_decl) +{ + tree field_type = TREE_TYPE (field_decl); + const char *ivar_name = DECL_NAME (field_decl) + ? IDENTIFIER_POINTER (DECL_NAME (field_decl)) + : ""; + +#ifdef OBJCPLUS + if (TREE_CODE (field_type) == REFERENCE_TYPE) + { + error ("illegal reference type specified for instance variable %qs", + ivar_name); + /* Return class as is without adding this ivar. */ + return class; + } +#endif + + if (field_type == error_mark_node || !TYPE_SIZE (field_type) + || TYPE_SIZE (field_type) == error_mark_node) + /* 'type[0]' is allowed, but 'type[]' is not! */ + { + error ("instance variable %qs has unknown size", ivar_name); + /* Return class as is without adding this ivar. */ + return class; + } + +#ifdef OBJCPLUS + /* Check if the ivar being added has a non-POD C++ type. If so, we will + need to either (1) warn the user about it or (2) generate suitable + constructor/destructor call from '- .cxx_construct' or '- .cxx_destruct' + methods (if '-fobjc-call-cxx-cdtors' was specified). */ + if (IS_AGGR_TYPE (field_type) + && (TYPE_NEEDS_CONSTRUCTING (field_type) + || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type) + || TYPE_POLYMORPHIC_P (field_type))) + { + const char *type_name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (field_type)); + + if (flag_objc_call_cxx_cdtors) + { + /* Since the ObjC runtime will be calling the constructors and + destructors for us, the only thing we can't handle is the lack + of a default constructor. */ + if (TYPE_NEEDS_CONSTRUCTING (field_type) + && !TYPE_HAS_DEFAULT_CONSTRUCTOR (field_type)) + { + warning (0, "type %qs has no default constructor to call", + type_name); + + /* If we cannot call a constructor, we should also avoid + calling the destructor, for symmetry. */ + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type)) + warning (0, "destructor for %qs shall not be run either", + type_name); + } + } + else + { + static bool warn_cxx_ivars = false; + + if (TYPE_POLYMORPHIC_P (field_type)) + { + /* Vtable pointers are Real Bad(tm), since Obj-C cannot + initialize them. */ + error ("type %qs has virtual member functions", type_name); + error ("illegal aggregate type %qs specified " + "for instance variable %qs", + type_name, ivar_name); + /* Return class as is without adding this ivar. */ + return class; + } + + /* User-defined constructors and destructors are not known to Obj-C + and hence will not be called. This may or may not be a problem. */ + if (TYPE_NEEDS_CONSTRUCTING (field_type)) + warning (0, "type %qs has a user-defined constructor", type_name); + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (field_type)) + warning (0, "type %qs has a user-defined destructor", type_name); + + if (!warn_cxx_ivars) + { + warning (0, "C++ constructors and destructors will not " + "be invoked for Objective-C fields"); + warn_cxx_ivars = true; + } + } + } +#endif + + /* Overload the public attribute, it is not used for FIELD_DECLs. */ + switch (public) + { + case 0: + TREE_PUBLIC (field_decl) = 0; + TREE_PRIVATE (field_decl) = 0; + TREE_PROTECTED (field_decl) = 1; + break; + + case 1: + TREE_PUBLIC (field_decl) = 1; + TREE_PRIVATE (field_decl) = 0; + TREE_PROTECTED (field_decl) = 0; + break; + + case 2: + TREE_PUBLIC (field_decl) = 0; + TREE_PRIVATE (field_decl) = 1; + TREE_PROTECTED (field_decl) = 0; + break; + + } + + CLASS_RAW_IVARS (class) = chainon (CLASS_RAW_IVARS (class), field_decl); + + return class; +} + +static tree +is_ivar (tree decl_chain, tree ident) +{ + for ( ; decl_chain; decl_chain = TREE_CHAIN (decl_chain)) + if (DECL_NAME (decl_chain) == ident) + return decl_chain; + return NULL_TREE; +} + +/* True if the ivar is private and we are not in its implementation. */ + +static int +is_private (tree decl) +{ + return (TREE_PRIVATE (decl) + && ! is_ivar (CLASS_IVARS (implementation_template), + DECL_NAME (decl))); +} + +/* We have an instance variable reference;, check to see if it is public. */ + +int +objc_is_public (tree expr, tree identifier) +{ + tree basetype, decl; + +#ifdef OBJCPLUS + if (processing_template_decl) + return 1; +#endif + + if (TREE_TYPE (expr) == error_mark_node) + return 1; + + basetype = TYPE_MAIN_VARIANT (TREE_TYPE (expr)); + + if (basetype && TREE_CODE (basetype) == RECORD_TYPE) + { + if (TYPE_HAS_OBJC_INFO (basetype) && TYPE_OBJC_INTERFACE (basetype)) + { + tree class = lookup_interface (OBJC_TYPE_NAME (basetype)); + + if (!class) + { + error ("cannot find interface declaration for %qs", + IDENTIFIER_POINTER (OBJC_TYPE_NAME (basetype))); + return 0; + } + + if ((decl = is_ivar (get_class_ivars (class, true), identifier))) + { + if (TREE_PUBLIC (decl)) + return 1; + + /* Important difference between the Stepstone translator: + all instance variables should be public within the context + of the implementation. */ + if (objc_implementation_context + && ((TREE_CODE (objc_implementation_context) + == CLASS_IMPLEMENTATION_TYPE) + || (TREE_CODE (objc_implementation_context) + == CATEGORY_IMPLEMENTATION_TYPE))) + { + tree curtype = TYPE_MAIN_VARIANT + (CLASS_STATIC_TEMPLATE + (implementation_template)); + + if (basetype == curtype + || DERIVED_FROM_P (basetype, curtype)) + { + int private = is_private (decl); + + if (private) + error ("instance variable %qs is declared private", + IDENTIFIER_POINTER (DECL_NAME (decl))); + + return !private; + } + } + + /* The 2.95.2 compiler sometimes allowed C functions to access + non-@public ivars. We will let this slide for now... */ + if (!objc_method_context) + { + warning (0, "instance variable %qs is %s; " + "this will be a hard error in the future", + IDENTIFIER_POINTER (identifier), + TREE_PRIVATE (decl) ? "@private" : "@protected"); + return 1; + } + + error ("instance variable %qs is declared %s", + IDENTIFIER_POINTER (identifier), + TREE_PRIVATE (decl) ? "private" : "protected"); + return 0; + } + } + } + + return 1; +} + +/* Make sure all entries in CHAIN are also in LIST. */ + +static int +check_methods (tree chain, tree list, int mtype) +{ + int first = 1; + + while (chain) + { + if (!lookup_method (list, chain)) + { + if (first) + { + if (TREE_CODE (objc_implementation_context) + == CLASS_IMPLEMENTATION_TYPE) + warning (0, "incomplete implementation of class %qs", + IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context))); + else if (TREE_CODE (objc_implementation_context) + == CATEGORY_IMPLEMENTATION_TYPE) + warning (0, "incomplete implementation of category %qs", + IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context))); + first = 0; + } + + warning (0, "method definition for %<%c%s%> not found", + mtype, IDENTIFIER_POINTER (METHOD_SEL_NAME (chain))); + } + + chain = TREE_CHAIN (chain); + } + + return first; +} + +/* Check if CLASS, or its superclasses, explicitly conforms to PROTOCOL. */ + +static int +conforms_to_protocol (tree class, tree protocol) +{ + if (TREE_CODE (protocol) == PROTOCOL_INTERFACE_TYPE) + { + tree p = CLASS_PROTOCOL_LIST (class); + while (p && TREE_VALUE (p) != protocol) + p = TREE_CHAIN (p); + + if (!p) + { + tree super = (CLASS_SUPER_NAME (class) + ? lookup_interface (CLASS_SUPER_NAME (class)) + : NULL_TREE); + int tmp = super ? conforms_to_protocol (super, protocol) : 0; + if (!tmp) + return 0; + } + } + + return 1; +} + +/* Make sure all methods in CHAIN are accessible as MTYPE methods in + CONTEXT. This is one of two mechanisms to check protocol integrity. */ + +static int +check_methods_accessible (tree chain, tree context, int mtype) +{ + int first = 1; + tree list; + tree base_context = context; + + while (chain) + { + context = base_context; + while (context) + { + if (mtype == '+') + list = CLASS_CLS_METHODS (context); + else + list = CLASS_NST_METHODS (context); + + if (lookup_method (list, chain)) + break; + + else if (TREE_CODE (context) == CLASS_IMPLEMENTATION_TYPE + || TREE_CODE (context) == CLASS_INTERFACE_TYPE) + context = (CLASS_SUPER_NAME (context) + ? lookup_interface (CLASS_SUPER_NAME (context)) + : NULL_TREE); + + else if (TREE_CODE (context) == CATEGORY_IMPLEMENTATION_TYPE + || TREE_CODE (context) == CATEGORY_INTERFACE_TYPE) + context = (CLASS_NAME (context) + ? lookup_interface (CLASS_NAME (context)) + : NULL_TREE); + else + abort (); + } + + if (context == NULL_TREE) + { + if (first) + { + if (TREE_CODE (objc_implementation_context) + == CLASS_IMPLEMENTATION_TYPE) + warning (0, "incomplete implementation of class %qs", + IDENTIFIER_POINTER + (CLASS_NAME (objc_implementation_context))); + else if (TREE_CODE (objc_implementation_context) + == CATEGORY_IMPLEMENTATION_TYPE) + warning (0, "incomplete implementation of category %qs", + IDENTIFIER_POINTER + (CLASS_SUPER_NAME (objc_implementation_context))); + first = 0; + } + warning (0, "method definition for %<%c%s%> not found", + mtype, IDENTIFIER_POINTER (METHOD_SEL_NAME (chain))); + } + + chain = TREE_CHAIN (chain); /* next method... */ + } + return first; +} + +/* Check whether the current interface (accessible via + 'objc_implementation_context') actually implements protocol P, along + with any protocols that P inherits. */ + +static void +check_protocol (tree p, const char *type, const char *name) +{ + if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE) + { + int f1, f2; + + /* Ensure that all protocols have bodies! */ + if (warn_protocol) + { + f1 = check_methods (PROTOCOL_CLS_METHODS (p), + CLASS_CLS_METHODS (objc_implementation_context), + '+'); + f2 = check_methods (PROTOCOL_NST_METHODS (p), + CLASS_NST_METHODS (objc_implementation_context), + '-'); + } + else + { + f1 = check_methods_accessible (PROTOCOL_CLS_METHODS (p), + objc_implementation_context, + '+'); + f2 = check_methods_accessible (PROTOCOL_NST_METHODS (p), + objc_implementation_context, + '-'); + } + + if (!f1 || !f2) + warning (0, "%s %qs does not fully implement the %qs protocol", + type, name, IDENTIFIER_POINTER (PROTOCOL_NAME (p))); + } + + /* Check protocols recursively. */ + if (PROTOCOL_LIST (p)) + { + tree subs = PROTOCOL_LIST (p); + tree super_class = + lookup_interface (CLASS_SUPER_NAME (implementation_template)); + + while (subs) + { + tree sub = TREE_VALUE (subs); + + /* If the superclass does not conform to the protocols + inherited by P, then we must! */ + if (!super_class || !conforms_to_protocol (super_class, sub)) + check_protocol (sub, type, name); + subs = TREE_CHAIN (subs); + } + } +} + +/* Check whether the current interface (accessible via + 'objc_implementation_context') actually implements the protocols listed + in PROTO_LIST. */ + +static void +check_protocols (tree proto_list, const char *type, const char *name) +{ + for ( ; proto_list; proto_list = TREE_CHAIN (proto_list)) + { + tree p = TREE_VALUE (proto_list); + + check_protocol (p, type, name); + } +} + +/* Make sure that the class CLASS_NAME is defined + CODE says which kind of thing CLASS_NAME ought to be. + It can be CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE, + CATEGORY_INTERFACE_TYPE, or CATEGORY_IMPLEMENTATION_TYPE. */ + +static tree +start_class (enum tree_code code, tree class_name, tree super_name, + tree protocol_list) +{ + tree class, decl; + +#ifdef OBJCPLUS + if (current_namespace != global_namespace) { + error ("Objective-C declarations may only appear in global scope"); + } +#endif /* OBJCPLUS */ + + if (objc_implementation_context) + { + warning (0, "%<@end%> missing in implementation context"); + finish_class (objc_implementation_context); + objc_ivar_chain = NULL_TREE; + objc_implementation_context = NULL_TREE; + } + + class = make_node (code); + TYPE_LANG_SLOT_1 (class) = make_tree_vec (CLASS_LANG_SLOT_ELTS); + + /* Check for existence of the super class, if one was specified. Note + that we must have seen an @interface, not just a @class. If we + are looking at a @compatibility_alias, traverse it first. */ + if ((code == CLASS_INTERFACE_TYPE || code == CLASS_IMPLEMENTATION_TYPE) + && super_name) + { + tree super = objc_is_class_name (super_name); + + if (!super || !lookup_interface (super)) + { + error ("cannot find interface declaration for %qs, superclass of %qs", + IDENTIFIER_POINTER (super ? super : super_name), + IDENTIFIER_POINTER (class_name)); + super_name = NULL_TREE; + } + else + super_name = super; + } + + CLASS_NAME (class) = class_name; + CLASS_SUPER_NAME (class) = super_name; + CLASS_CLS_METHODS (class) = NULL_TREE; + + if (! objc_is_class_name (class_name) + && (decl = lookup_name (class_name))) + { + error ("%qs redeclared as different kind of symbol", + IDENTIFIER_POINTER (class_name)); + error ("previous declaration of %q+D", + decl); + } + + if (code == CLASS_IMPLEMENTATION_TYPE) + { + { + tree chain; + + for (chain = implemented_classes; chain; chain = TREE_CHAIN (chain)) + if (TREE_VALUE (chain) == class_name) + { + error ("reimplementation of class %qs", + IDENTIFIER_POINTER (class_name)); + return error_mark_node; + } + implemented_classes = tree_cons (NULL_TREE, class_name, + implemented_classes); + } + + /* Reset for multiple classes per file. */ + method_slot = 0; + + objc_implementation_context = class; + + /* Lookup the interface for this implementation. */ + + if (!(implementation_template = lookup_interface (class_name))) + { + warning (0, "cannot find interface declaration for %qs", + IDENTIFIER_POINTER (class_name)); + add_class (implementation_template = objc_implementation_context, + class_name); + } + + /* If a super class has been specified in the implementation, + insure it conforms to the one specified in the interface. */ + + if (super_name + && (super_name != CLASS_SUPER_NAME (implementation_template))) + { + tree previous_name = CLASS_SUPER_NAME (implementation_template); + const char *const name = + previous_name ? IDENTIFIER_POINTER (previous_name) : ""; + error ("conflicting super class name %qs", + IDENTIFIER_POINTER (super_name)); + error ("previous declaration of %qs", name); + } + + else if (! super_name) + { + CLASS_SUPER_NAME (objc_implementation_context) + = CLASS_SUPER_NAME (implementation_template); + } + } + + else if (code == CLASS_INTERFACE_TYPE) + { + if (lookup_interface (class_name)) +#ifdef OBJCPLUS + error ("duplicate interface declaration for class %qs", +#else + warning (0, "duplicate interface declaration for class %qs", +#endif + IDENTIFIER_POINTER (class_name)); + else + add_class (class, class_name); + + if (protocol_list) + CLASS_PROTOCOL_LIST (class) + = lookup_and_install_protocols (protocol_list); + } + + else if (code == CATEGORY_INTERFACE_TYPE) + { + tree class_category_is_assoc_with; + + /* For a category, class_name is really the name of the class that + the following set of methods will be associated with. We must + find the interface so that can derive the objects template. */ + + if (!(class_category_is_assoc_with = lookup_interface (class_name))) + { + error ("cannot find interface declaration for %qs", + IDENTIFIER_POINTER (class_name)); + exit (FATAL_EXIT_CODE); + } + else + add_category (class_category_is_assoc_with, class); + + if (protocol_list) + CLASS_PROTOCOL_LIST (class) + = lookup_and_install_protocols (protocol_list); + } + + else if (code == CATEGORY_IMPLEMENTATION_TYPE) + { + /* Reset for multiple classes per file. */ + method_slot = 0; + + objc_implementation_context = class; + + /* For a category, class_name is really the name of the class that + the following set of methods will be associated with. We must + find the interface so that can derive the objects template. */ + + if (!(implementation_template = lookup_interface (class_name))) + { + error ("cannot find interface declaration for %qs", + IDENTIFIER_POINTER (class_name)); + exit (FATAL_EXIT_CODE); + } + } + return class; +} + +static tree +continue_class (tree class) +{ + if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE + || TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE) + { + struct imp_entry *imp_entry; + + /* Check consistency of the instance variables. */ + + if (CLASS_RAW_IVARS (class)) + check_ivars (implementation_template, class); + + /* code generation */ + +#ifdef OBJCPLUS + push_lang_context (lang_name_c); +#endif + + build_private_template (implementation_template); + uprivate_record = CLASS_STATIC_TEMPLATE (implementation_template); + objc_instance_type = build_pointer_type (uprivate_record); + + imp_entry = (struct imp_entry *) ggc_alloc (sizeof (struct imp_entry)); + + imp_entry->next = imp_list; + imp_entry->imp_context = class; + imp_entry->imp_template = implementation_template; + + synth_forward_declarations (); + imp_entry->class_decl = UOBJC_CLASS_decl; + imp_entry->meta_decl = UOBJC_METACLASS_decl; + imp_entry->has_cxx_cdtors = 0; + + /* Append to front and increment count. */ + imp_list = imp_entry; + if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE) + imp_count++; + else + cat_count++; + +#ifdef OBJCPLUS + pop_lang_context (); +#endif /* OBJCPLUS */ + + return get_class_ivars (implementation_template, true); + } + + else if (TREE_CODE (class) == CLASS_INTERFACE_TYPE) + { +#ifdef OBJCPLUS + push_lang_context (lang_name_c); +#endif /* OBJCPLUS */ + + build_private_template (class); + +#ifdef OBJCPLUS + pop_lang_context (); +#endif /* OBJCPLUS */ + + return NULL_TREE; + } + + else + return error_mark_node; +} + +/* This is called once we see the "@end" in an interface/implementation. */ + +static void +finish_class (tree class) +{ + if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE) + { + /* All code generation is done in finish_objc. */ + + if (implementation_template != objc_implementation_context) + { + /* Ensure that all method listed in the interface contain bodies. */ + check_methods (CLASS_CLS_METHODS (implementation_template), + CLASS_CLS_METHODS (objc_implementation_context), '+'); + check_methods (CLASS_NST_METHODS (implementation_template), + CLASS_NST_METHODS (objc_implementation_context), '-'); + + if (CLASS_PROTOCOL_LIST (implementation_template)) + check_protocols (CLASS_PROTOCOL_LIST (implementation_template), + "class", + IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context))); + } + } + + else if (TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE) + { + tree category = lookup_category (implementation_template, CLASS_SUPER_NAME (class)); + + if (category) + { + /* Ensure all method listed in the interface contain bodies. */ + check_methods (CLASS_CLS_METHODS (category), + CLASS_CLS_METHODS (objc_implementation_context), '+'); + check_methods (CLASS_NST_METHODS (category), + CLASS_NST_METHODS (objc_implementation_context), '-'); + + if (CLASS_PROTOCOL_LIST (category)) + check_protocols (CLASS_PROTOCOL_LIST (category), + "category", + IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context))); + } + } +} + +static tree +add_protocol (tree protocol) +{ + /* Put protocol on list in reverse order. */ + TREE_CHAIN (protocol) = protocol_chain; + protocol_chain = protocol; + return protocol_chain; +} + +static tree +lookup_protocol (tree ident) +{ + tree chain; + + for (chain = protocol_chain; chain; chain = TREE_CHAIN (chain)) + if (ident == PROTOCOL_NAME (chain)) + return chain; + + return NULL_TREE; +} + +/* This function forward declares the protocols named by NAMES. If + they are already declared or defined, the function has no effect. */ + +void +objc_declare_protocols (tree names) +{ + tree list; + +#ifdef OBJCPLUS + if (current_namespace != global_namespace) { + error ("Objective-C declarations may only appear in global scope"); + } +#endif /* OBJCPLUS */ + + for (list = names; list; list = TREE_CHAIN (list)) + { + tree name = TREE_VALUE (list); + + if (lookup_protocol (name) == NULL_TREE) + { + tree protocol = make_node (PROTOCOL_INTERFACE_TYPE); + + TYPE_LANG_SLOT_1 (protocol) + = make_tree_vec (PROTOCOL_LANG_SLOT_ELTS); + PROTOCOL_NAME (protocol) = name; + PROTOCOL_LIST (protocol) = NULL_TREE; + add_protocol (protocol); + PROTOCOL_DEFINED (protocol) = 0; + PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE; + } + } +} + +static tree +start_protocol (enum tree_code code, tree name, tree list) +{ + tree protocol; + +#ifdef OBJCPLUS + if (current_namespace != global_namespace) { + error ("Objective-C declarations may only appear in global scope"); + } +#endif /* OBJCPLUS */ + + protocol = lookup_protocol (name); + + if (!protocol) + { + protocol = make_node (code); + TYPE_LANG_SLOT_1 (protocol) = make_tree_vec (PROTOCOL_LANG_SLOT_ELTS); + + PROTOCOL_NAME (protocol) = name; + PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list); + add_protocol (protocol); + PROTOCOL_DEFINED (protocol) = 1; + PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE; + + check_protocol_recursively (protocol, list); + } + else if (! PROTOCOL_DEFINED (protocol)) + { + PROTOCOL_DEFINED (protocol) = 1; + PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list); + + check_protocol_recursively (protocol, list); + } + else + { + warning (0, "duplicate declaration for protocol %qs", + IDENTIFIER_POINTER (name)); + } + return protocol; +} + + +/* "Encode" a data type into a string, which grows in util_obstack. + ??? What is the FORMAT? Someone please document this! */ + +static void +encode_type_qualifiers (tree declspecs) +{ + tree spec; + + for (spec = declspecs; spec; spec = TREE_CHAIN (spec)) + { + if (ridpointers[(int) RID_IN] == TREE_VALUE (spec)) + obstack_1grow (&util_obstack, 'n'); + else if (ridpointers[(int) RID_INOUT] == TREE_VALUE (spec)) + obstack_1grow (&util_obstack, 'N'); + else if (ridpointers[(int) RID_OUT] == TREE_VALUE (spec)) + obstack_1grow (&util_obstack, 'o'); + else if (ridpointers[(int) RID_BYCOPY] == TREE_VALUE (spec)) + obstack_1grow (&util_obstack, 'O'); + else if (ridpointers[(int) RID_BYREF] == TREE_VALUE (spec)) + obstack_1grow (&util_obstack, 'R'); + else if (ridpointers[(int) RID_ONEWAY] == TREE_VALUE (spec)) + obstack_1grow (&util_obstack, 'V'); + } +} + +/* Encode a pointer type. */ + +static void +encode_pointer (tree type, int curtype, int format) +{ + tree pointer_to = TREE_TYPE (type); + + if (TREE_CODE (pointer_to) == RECORD_TYPE) + { + if (OBJC_TYPE_NAME (pointer_to) + && TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE) + { + const char *name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (pointer_to)); + + if (strcmp (name, TAG_OBJECT) == 0) /* '@' */ + { + obstack_1grow (&util_obstack, '@'); + return; + } + else if (TYPE_HAS_OBJC_INFO (pointer_to) + && TYPE_OBJC_INTERFACE (pointer_to)) + { + if (generating_instance_variables) + { + obstack_1grow (&util_obstack, '@'); + obstack_1grow (&util_obstack, '"'); + obstack_grow (&util_obstack, name, strlen (name)); + obstack_1grow (&util_obstack, '"'); + return; + } + else + { + obstack_1grow (&util_obstack, '@'); + return; + } + } + else if (strcmp (name, TAG_CLASS) == 0) /* '#' */ + { + obstack_1grow (&util_obstack, '#'); + return; + } + else if (strcmp (name, TAG_SELECTOR) == 0) /* ':' */ + { + obstack_1grow (&util_obstack, ':'); + return; + } + } + } + else if (TREE_CODE (pointer_to) == INTEGER_TYPE + && TYPE_MODE (pointer_to) == QImode) + { + tree pname = TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE + ? OBJC_TYPE_NAME (pointer_to) + : DECL_NAME (OBJC_TYPE_NAME (pointer_to)); + + if (!flag_next_runtime || strcmp (IDENTIFIER_POINTER (pname), "BOOL")) + { + /* It appears that "r*" means "const char *" rather than + "char *const". */ + if (TYPE_READONLY (pointer_to)) + obstack_1grow (&util_obstack, 'r'); + + obstack_1grow (&util_obstack, '*'); + return; + } + } + + /* We have a type that does not get special treatment. */ + + /* NeXT extension */ + obstack_1grow (&util_obstack, '^'); + encode_type (pointer_to, curtype, format); +} + +static void +encode_array (tree type, int curtype, int format) +{ + tree an_int_cst = TYPE_SIZE (type); + tree array_of = TREE_TYPE (type); + char buffer[40]; + + /* An incomplete array is treated like a pointer. */ + if (an_int_cst == NULL) + { + encode_pointer (type, curtype, format); + return; + } + + sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, + (TREE_INT_CST_LOW (an_int_cst) + / TREE_INT_CST_LOW (TYPE_SIZE (array_of)))); + + obstack_grow (&util_obstack, buffer, strlen (buffer)); + encode_type (array_of, curtype, format); + obstack_1grow (&util_obstack, ']'); + return; +} + +static void +encode_aggregate_fields (tree type, int pointed_to, int curtype, int format) +{ + tree field = TYPE_FIELDS (type); + + for (; field; field = TREE_CHAIN (field)) + { +#ifdef OBJCPLUS + /* C++ static members, and things that are not field at all, + should not appear in the encoding. */ + if (TREE_CODE (field) != FIELD_DECL || TREE_STATIC (field)) + continue; +#endif + + /* Recursively encode fields of embedded base classes. */ + if (DECL_ARTIFICIAL (field) && !DECL_NAME (field) + && TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE) + { + encode_aggregate_fields (TREE_TYPE (field), + pointed_to, curtype, format); + continue; + } + + if (generating_instance_variables && !pointed_to) + { + tree fname = DECL_NAME (field); + + obstack_1grow (&util_obstack, '"'); + + if (fname && TREE_CODE (fname) == IDENTIFIER_NODE) + obstack_grow (&util_obstack, + IDENTIFIER_POINTER (fname), + strlen (IDENTIFIER_POINTER (fname))); + + obstack_1grow (&util_obstack, '"'); + } + + encode_field_decl (field, curtype, format); + } +} + +static void +encode_aggregate_within (tree type, int curtype, int format, int left, + int right) +{ + tree name; + /* NB: aggregates that are pointed to have slightly different encoding + rules in that you never encode the names of instance variables. */ + int ob_size = obstack_object_size (&util_obstack); + char c1 = ob_size > 1 ? *(obstack_next_free (&util_obstack) - 2) : 0; + char c0 = ob_size > 0 ? *(obstack_next_free (&util_obstack) - 1) : 0; + int pointed_to = (c0 == '^' || (c1 == '^' && c0 == 'r')); + int inline_contents + = ((format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables) + && (!pointed_to || ob_size - curtype == (c1 == 'r' ? 2 : 1))); + + /* Traverse struct aliases; it is important to get the + original struct and its tag name (if any). */ + type = TYPE_MAIN_VARIANT (type); + name = OBJC_TYPE_NAME (type); + /* Open parenth/bracket. */ + obstack_1grow (&util_obstack, left); + + /* Encode the struct/union tag name, or '?' if a tag was + not provided. Typedef aliases do not qualify. */ + if (name && TREE_CODE (name) == IDENTIFIER_NODE +#ifdef OBJCPLUS + /* Did this struct have a tag? */ + && !TYPE_WAS_ANONYMOUS (type) +#endif + ) + obstack_grow (&util_obstack, + IDENTIFIER_POINTER (name), + strlen (IDENTIFIER_POINTER (name))); + else + obstack_1grow (&util_obstack, '?'); + + /* Encode the types (and possibly names) of the inner fields, + if required. */ + if (inline_contents) + { + obstack_1grow (&util_obstack, '='); + encode_aggregate_fields (type, pointed_to, curtype, format); + } + /* Close parenth/bracket. */ + obstack_1grow (&util_obstack, right); +} + +static void +encode_aggregate (tree type, int curtype, int format) +{ + enum tree_code code = TREE_CODE (type); + + switch (code) + { + case RECORD_TYPE: + { + encode_aggregate_within (type, curtype, format, '{', '}'); + break; + } + case UNION_TYPE: + { + encode_aggregate_within (type, curtype, format, '(', ')'); + break; + } + + case ENUMERAL_TYPE: + obstack_1grow (&util_obstack, 'i'); + break; + + default: + break; + } +} + +/* Encode a bitfield NeXT-style (i.e., without a bit offset or the underlying + field type. */ + +static void +encode_next_bitfield (int width) +{ + char buffer[40]; + sprintf (buffer, "b%d", width); + obstack_grow (&util_obstack, buffer, strlen (buffer)); +} + +/* FORMAT will be OBJC_ENCODE_INLINE_DEFS or OBJC_ENCODE_DONT_INLINE_DEFS. */ +static void +encode_type (tree type, int curtype, int format) +{ + enum tree_code code = TREE_CODE (type); + char c; + + if (TYPE_READONLY (type)) + obstack_1grow (&util_obstack, 'r'); + + if (code == INTEGER_TYPE) + { + switch (GET_MODE_BITSIZE (TYPE_MODE (type))) + { + case 8: c = TYPE_UNSIGNED (type) ? 'C' : 'c'; break; + case 16: c = TYPE_UNSIGNED (type) ? 'S' : 's'; break; + case 32: + if (type == long_unsigned_type_node + || type == long_integer_type_node) + c = TYPE_UNSIGNED (type) ? 'L' : 'l'; + else + c = TYPE_UNSIGNED (type) ? 'I' : 'i'; + break; + case 64: c = TYPE_UNSIGNED (type) ? 'Q' : 'q'; break; + default: abort (); + } + obstack_1grow (&util_obstack, c); + } + + else if (code == REAL_TYPE) + { + /* Floating point types. */ + switch (GET_MODE_BITSIZE (TYPE_MODE (type))) + { + case 32: c = 'f'; break; + case 64: + case 96: + case 128: c = 'd'; break; + default: abort (); + } + obstack_1grow (&util_obstack, c); + } + + else if (code == VOID_TYPE) + obstack_1grow (&util_obstack, 'v'); + + else if (code == BOOLEAN_TYPE) + obstack_1grow (&util_obstack, 'B'); + + else if (code == ARRAY_TYPE) + encode_array (type, curtype, format); + + else if (code == POINTER_TYPE) + encode_pointer (type, curtype, format); + + else if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE) + encode_aggregate (type, curtype, format); + + else if (code == FUNCTION_TYPE) /* '?' */ + obstack_1grow (&util_obstack, '?'); +} + +static void +encode_gnu_bitfield (int position, tree type, int size) +{ + enum tree_code code = TREE_CODE (type); + char buffer[40]; + char charType = '?'; + + if (code == INTEGER_TYPE) + { + if (integer_zerop (TYPE_MIN_VALUE (type))) + { + /* Unsigned integer types. */ + + if (TYPE_MODE (type) == QImode) + charType = 'C'; + else if (TYPE_MODE (type) == HImode) + charType = 'S'; + else if (TYPE_MODE (type) == SImode) + { + if (type == long_unsigned_type_node) + charType = 'L'; + else + charType = 'I'; + } + else if (TYPE_MODE (type) == DImode) + charType = 'Q'; + } + + else + /* Signed integer types. */ + { + if (TYPE_MODE (type) == QImode) + charType = 'c'; + else if (TYPE_MODE (type) == HImode) + charType = 's'; + else if (TYPE_MODE (type) == SImode) + { + if (type == long_integer_type_node) + charType = 'l'; + else + charType = 'i'; + } + + else if (TYPE_MODE (type) == DImode) + charType = 'q'; + } + } + else if (code == ENUMERAL_TYPE) + charType = 'i'; + else + abort (); + + sprintf (buffer, "b%d%c%d", position, charType, size); + obstack_grow (&util_obstack, buffer, strlen (buffer)); +} + +static void +encode_field_decl (tree field_decl, int curtype, int format) +{ + tree type; + +#ifdef OBJCPLUS + /* C++ static members, and things that are not fields at all, + should not appear in the encoding. */ + if (TREE_CODE (field_decl) != FIELD_DECL || TREE_STATIC (field_decl)) + return; +#endif + + type = TREE_TYPE (field_decl); + + /* Generate the bitfield typing information, if needed. Note the difference + between GNU and NeXT runtimes. */ + if (DECL_BIT_FIELD_TYPE (field_decl)) + { + int size = tree_low_cst (DECL_SIZE (field_decl), 1); + + if (flag_next_runtime) + encode_next_bitfield (size); + else + encode_gnu_bitfield (int_bit_position (field_decl), + DECL_BIT_FIELD_TYPE (field_decl), size); + } + else + encode_type (TREE_TYPE (field_decl), curtype, format); +} + +static GTY(()) tree objc_parmlist = NULL_TREE; + +/* Append PARM to a list of formal parameters of a method, making a necessary + array-to-pointer adjustment along the way. */ + +static void +objc_push_parm (tree parm) +{ + bool relayout_needed = false; + /* Decay arrays and functions into pointers. */ + if (TREE_CODE (TREE_TYPE (parm)) == ARRAY_TYPE) + { + TREE_TYPE (parm) = build_pointer_type (TREE_TYPE (TREE_TYPE (parm))); + relayout_needed = true; + } + else if (TREE_CODE (TREE_TYPE (parm)) == FUNCTION_TYPE) + { + TREE_TYPE (parm) = build_pointer_type (TREE_TYPE (parm)); + relayout_needed = true; + } + + if (relayout_needed) + relayout_decl (parm); + + + DECL_ARG_TYPE (parm) + = lang_hooks.types.type_promotes_to (TREE_TYPE (parm)); + + /* Record constancy and volatility. */ + c_apply_type_quals_to_decl + ((TYPE_READONLY (TREE_TYPE (parm)) ? TYPE_QUAL_CONST : 0) + | (TYPE_RESTRICT (TREE_TYPE (parm)) ? TYPE_QUAL_RESTRICT : 0) + | (TYPE_VOLATILE (TREE_TYPE (parm)) ? TYPE_QUAL_VOLATILE : 0), parm); + + objc_parmlist = chainon (objc_parmlist, parm); +} + +/* Retrieve the formal parameter list constructed via preceding calls to + objc_push_parm(). */ + +#ifdef OBJCPLUS +static tree +objc_get_parm_info (int have_ellipsis ATTRIBUTE_UNUSED) +#else +static struct c_arg_info * +objc_get_parm_info (int have_ellipsis) +#endif +{ +#ifdef OBJCPLUS + tree parm_info = objc_parmlist; + objc_parmlist = NULL_TREE; + + return parm_info; +#else + tree parm_info = objc_parmlist; + struct c_arg_info *arg_info; + /* The C front-end requires an elaborate song and dance at + this point. */ + push_scope (); + declare_parm_level (); + while (parm_info) + { + tree next = TREE_CHAIN (parm_info); + + TREE_CHAIN (parm_info) = NULL_TREE; + parm_info = pushdecl (parm_info); + finish_decl (parm_info, NULL_TREE, NULL_TREE); + parm_info = next; + } + arg_info = get_parm_info (have_ellipsis); + pop_scope (); + objc_parmlist = NULL_TREE; + return arg_info; +#endif +} + +/* Synthesize the formal parameters 'id self' and 'SEL _cmd' needed for ObjC + method definitions. In the case of instance methods, we can be more + specific as to the type of 'self'. */ + +static void +synth_self_and_ucmd_args (void) +{ + tree self_type; + + if (objc_method_context + && TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL) + self_type = objc_instance_type; + else + /* Really a `struct objc_class *'. However, we allow people to + assign to self, which changes its type midstream. */ + self_type = objc_object_type; + + /* id self; */ + objc_push_parm (build_decl (PARM_DECL, self_id, self_type)); + + /* SEL _cmd; */ + objc_push_parm (build_decl (PARM_DECL, ucmd_id, objc_selector_type)); +} + +/* Transform an Objective-C method definition into a static C function + definition, synthesizing the first two arguments, "self" and "_cmd", + in the process. */ + +static void +start_method_def (tree method) +{ + tree parmlist; +#ifdef OBJCPLUS + tree parm_info; +#else + struct c_arg_info *parm_info; +#endif + int have_ellipsis = 0; + + /* If we are defining a "dealloc" method in a non-root class, we + will need to check if a [super dealloc] is missing, and warn if + it is. */ + if(CLASS_SUPER_NAME (objc_implementation_context) + && !strcmp ("dealloc", IDENTIFIER_POINTER (METHOD_SEL_NAME (method)))) + should_call_super_dealloc = 1; + else + should_call_super_dealloc = 0; + + /* Required to implement _msgSuper. */ + objc_method_context = method; + UOBJC_SUPER_decl = NULL_TREE; + + /* Generate prototype declarations for arguments..."new-style". */ + synth_self_and_ucmd_args (); + + /* Generate argument declarations if a keyword_decl. */ + parmlist = METHOD_SEL_ARGS (method); + while (parmlist) + { + tree type = TREE_VALUE (TREE_TYPE (parmlist)), parm; + + parm = build_decl (PARM_DECL, KEYWORD_ARG_NAME (parmlist), type); + objc_push_parm (parm); + parmlist = TREE_CHAIN (parmlist); + } + + if (METHOD_ADD_ARGS (method)) + { + tree akey; + + for (akey = TREE_CHAIN (METHOD_ADD_ARGS (method)); + akey; akey = TREE_CHAIN (akey)) + { + objc_push_parm (TREE_VALUE (akey)); + } + + if (METHOD_ADD_ARGS_ELLIPSIS_P (method)) + have_ellipsis = 1; + } + + parm_info = objc_get_parm_info (have_ellipsis); + + really_start_method (objc_method_context, parm_info); +} + +static void +warn_with_method (const char *message, int mtype, tree method) +{ + /* Add a readable method name to the warning. */ + warning (0, "%J%s %<%c%s%>", method, + message, mtype, gen_method_decl (method)); +} + +/* Return 1 if TYPE1 is equivalent to TYPE2 + for purposes of method overloading. */ + +static int +objc_types_are_equivalent (tree type1, tree type2) +{ + if (type1 == type2) + return 1; + + /* Strip away indirections. */ + while ((TREE_CODE (type1) == ARRAY_TYPE || TREE_CODE (type1) == POINTER_TYPE) + && (TREE_CODE (type1) == TREE_CODE (type2))) + type1 = TREE_TYPE (type1), type2 = TREE_TYPE (type2); + if (TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2)) + return 0; + + type1 = (TYPE_HAS_OBJC_INFO (type1) + ? TYPE_OBJC_PROTOCOL_LIST (type1) + : NULL_TREE); + type2 = (TYPE_HAS_OBJC_INFO (type2) + ? TYPE_OBJC_PROTOCOL_LIST (type2) + : NULL_TREE); + + if (list_length (type1) == list_length (type2)) + { + for (; type2; type2 = TREE_CHAIN (type2)) + if (!lookup_protocol_in_reflist (type1, TREE_VALUE (type2))) + return 0; + return 1; + } + return 0; +} + +/* Return 1 if TYPE1 has the same size and alignment as TYPE2. */ + +static int +objc_types_share_size_and_alignment (tree type1, tree type2) +{ + return (simple_cst_equal (TYPE_SIZE (type1), TYPE_SIZE (type2)) + && TYPE_ALIGN (type1) == TYPE_ALIGN (type2)); +} + +/* Return 1 if PROTO1 is equivalent to PROTO2 + for purposes of method overloading. Ordinarily, the type signatures + should match up exactly, unless STRICT is zero, in which case we + shall allow differences in which the size and alignment of a type + is the same. */ + +static int +comp_proto_with_proto (tree proto1, tree proto2, int strict) +{ + tree type1, type2; + + /* The following test is needed in case there are hashing + collisions. */ + if (METHOD_SEL_NAME (proto1) != METHOD_SEL_NAME (proto2)) + return 0; + + /* Compare return types. */ + type1 = TREE_VALUE (TREE_TYPE (proto1)); + type2 = TREE_VALUE (TREE_TYPE (proto2)); + + if (!objc_types_are_equivalent (type1, type2) + && (strict || !objc_types_share_size_and_alignment (type1, type2))) + return 0; + + /* Compare argument types. */ + for (type1 = get_arg_type_list (proto1, METHOD_REF, 0), + type2 = get_arg_type_list (proto2, METHOD_REF, 0); + type1 && type2; + type1 = TREE_CHAIN (type1), type2 = TREE_CHAIN (type2)) + { + if (!objc_types_are_equivalent (TREE_VALUE (type1), TREE_VALUE (type2)) + && (strict + || !objc_types_share_size_and_alignment (TREE_VALUE (type1), + TREE_VALUE (type2)))) + return 0; + } + + return (!type1 && !type2); +} + +/* Fold an OBJ_TYPE_REF expression for ObjC method dispatches, where + this occurs. ObjC method dispatches are _not_ like C++ virtual + member function dispatches, and we account for the difference here. */ +tree +#ifdef OBJCPLUS +objc_fold_obj_type_ref (tree ref, tree known_type) +#else +objc_fold_obj_type_ref (tree ref ATTRIBUTE_UNUSED, + tree known_type ATTRIBUTE_UNUSED) +#endif +{ +#ifdef OBJCPLUS + tree v = BINFO_VIRTUALS (TYPE_BINFO (known_type)); + + /* If the receiver does not have virtual member functions, there + is nothing we can (or need to) do here. */ + if (!v) + return NULL_TREE; + + /* Let C++ handle C++ virtual functions. */ + return cp_fold_obj_type_ref (ref, known_type); +#else + /* For plain ObjC, we currently do not need to do anything. */ + return NULL_TREE; +#endif +} + +static void +objc_start_function (tree name, tree type, tree attrs, +#ifdef OBJCPLUS + tree params +#else + struct c_arg_info *params +#endif + ) +{ + tree fndecl = build_decl (FUNCTION_DECL, name, type); + +#ifdef OBJCPLUS + DECL_ARGUMENTS (fndecl) = params; + DECL_INITIAL (fndecl) = error_mark_node; + DECL_EXTERNAL (fndecl) = 0; + TREE_STATIC (fndecl) = 1; + retrofit_lang_decl (fndecl); + cplus_decl_attributes (&fndecl, attrs, 0); + start_preparsed_function (fndecl, attrs, /*flags=*/SF_DEFAULT); +#else + struct c_label_context_se *nstack_se; + struct c_label_context_vm *nstack_vm; + nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se); + nstack_se->labels_def = NULL; + nstack_se->labels_used = NULL; + nstack_se->next = label_context_stack_se; + label_context_stack_se = nstack_se; + nstack_vm = XOBNEW (&parser_obstack, struct c_label_context_vm); + nstack_vm->labels_def = NULL; + nstack_vm->labels_used = NULL; + nstack_vm->scope = 0; + nstack_vm->next = label_context_stack_vm; + label_context_stack_vm = nstack_vm; + current_function_returns_value = 0; /* Assume, until we see it does. */ + current_function_returns_null = 0; + + decl_attributes (&fndecl, attrs, 0); + announce_function (fndecl); + DECL_INITIAL (fndecl) = error_mark_node; + DECL_EXTERNAL (fndecl) = 0; + TREE_STATIC (fndecl) = 1; + current_function_decl = pushdecl (fndecl); + push_scope (); + declare_parm_level (); + DECL_RESULT (current_function_decl) + = build_decl (RESULT_DECL, NULL_TREE, + TREE_TYPE (TREE_TYPE (current_function_decl))); + DECL_ARTIFICIAL (DECL_RESULT (current_function_decl)) = 1; + DECL_IGNORED_P (DECL_RESULT (current_function_decl)) = 1; + start_fname_decls (); + store_parm_decls_from (params); +#endif + + TREE_USED (current_function_decl) = 1; +} + +/* - Generate an identifier for the function. the format is "_n_cls", + where 1 <= n <= nMethods, and cls is the name the implementation we + are processing. + - Install the return type from the method declaration. + - If we have a prototype, check for type consistency. */ + +static void +really_start_method (tree method, +#ifdef OBJCPLUS + tree parmlist +#else + struct c_arg_info *parmlist +#endif + ) +{ + tree ret_type, meth_type; + tree method_id; + const char *sel_name, *class_name, *cat_name; + char *buf; + + /* Synth the storage class & assemble the return type. */ + ret_type = TREE_VALUE (TREE_TYPE (method)); + + sel_name = IDENTIFIER_POINTER (METHOD_SEL_NAME (method)); + class_name = IDENTIFIER_POINTER (CLASS_NAME (objc_implementation_context)); + cat_name = ((TREE_CODE (objc_implementation_context) + == CLASS_IMPLEMENTATION_TYPE) + ? NULL + : IDENTIFIER_POINTER (CLASS_SUPER_NAME (objc_implementation_context))); + method_slot++; + + /* Make sure this is big enough for any plausible method label. */ + buf = (char *) alloca (50 + strlen (sel_name) + strlen (class_name) + + (cat_name ? strlen (cat_name) : 0)); + + OBJC_GEN_METHOD_LABEL (buf, TREE_CODE (method) == INSTANCE_METHOD_DECL, + class_name, cat_name, sel_name, method_slot); + + method_id = get_identifier (buf); + +#ifdef OBJCPLUS + /* Objective-C methods cannot be overloaded, so we don't need + the type encoding appended. It looks bad anyway... */ + push_lang_context (lang_name_c); +#endif + + meth_type + = build_function_type (ret_type, + get_arg_type_list (method, METHOD_DEF, 0)); + objc_start_function (method_id, meth_type, NULL_TREE, parmlist); + + /* Set self_decl from the first argument. */ + self_decl = DECL_ARGUMENTS (current_function_decl); + + /* Suppress unused warnings. */ + TREE_USED (self_decl) = 1; + TREE_USED (TREE_CHAIN (self_decl)) = 1; +#ifdef OBJCPLUS + pop_lang_context (); +#endif + + METHOD_DEFINITION (method) = current_function_decl; + + /* Check consistency...start_function, pushdecl, duplicate_decls. */ + + if (implementation_template != objc_implementation_context) + { + tree proto + = lookup_method_static (implementation_template, + METHOD_SEL_NAME (method), + ((TREE_CODE (method) == CLASS_METHOD_DECL) + | OBJC_LOOKUP_NO_SUPER)); + + if (proto) + { + if (!comp_proto_with_proto (method, proto, 1)) + { + char type = (TREE_CODE (method) == INSTANCE_METHOD_DECL ? '-' : '+'); + + warn_with_method ("conflicting types for", type, method); + warn_with_method ("previous declaration of", type, proto); + } + } + else + { + /* We have a method @implementation even though we did not + see a corresponding @interface declaration (which is allowed + by Objective-C rules). Go ahead and place the method in + the @interface anyway, so that message dispatch lookups + will see it. */ + tree interface = implementation_template; + + if (TREE_CODE (objc_implementation_context) + == CATEGORY_IMPLEMENTATION_TYPE) + interface = lookup_category + (interface, + CLASS_SUPER_NAME (objc_implementation_context)); + + if (interface) + objc_add_method (interface, copy_node (method), + TREE_CODE (method) == CLASS_METHOD_DECL); + } + } +} + +static void *UOBJC_SUPER_scope = 0; + +/* _n_Method (id self, SEL sel, ...) + { + struct objc_super _S; + _msgSuper ((_S.self = self, _S.class = _cls, &_S), ...); + } */ + +static tree +get_super_receiver (void) +{ + if (objc_method_context) + { + tree super_expr, super_expr_list; + + if (!UOBJC_SUPER_decl) + { + UOBJC_SUPER_decl = build_decl (VAR_DECL, get_identifier (TAG_SUPER), + objc_super_template); + /* This prevents `unused variable' warnings when compiling with -Wall. */ + TREE_USED (UOBJC_SUPER_decl) = 1; + lang_hooks.decls.pushdecl (UOBJC_SUPER_decl); + finish_decl (UOBJC_SUPER_decl, NULL_TREE, NULL_TREE); + UOBJC_SUPER_scope = objc_get_current_scope (); + } + + /* Set receiver to self. */ + super_expr = objc_build_component_ref (UOBJC_SUPER_decl, self_id); + super_expr = build_modify_expr (super_expr, NOP_EXPR, self_decl); + super_expr_list = super_expr; + + /* Set class to begin searching. */ + super_expr = objc_build_component_ref (UOBJC_SUPER_decl, + get_identifier ("super_class")); + + if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) + { + /* [_cls, __cls]Super are "pre-built" in + synth_forward_declarations. */ + + super_expr = build_modify_expr (super_expr, NOP_EXPR, + ((TREE_CODE (objc_method_context) + == INSTANCE_METHOD_DECL) + ? ucls_super_ref + : uucls_super_ref)); + } + + else + /* We have a category. */ + { + tree super_name = CLASS_SUPER_NAME (implementation_template); + tree super_class; + + /* Barf if super used in a category of Object. */ + if (!super_name) + { + error ("no super class declared in interface for %qs", + IDENTIFIER_POINTER (CLASS_NAME (implementation_template))); + return error_mark_node; + } + + if (flag_next_runtime && !flag_zero_link) + { + super_class = objc_get_class_reference (super_name); + if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL) + /* If we are in a class method, we must retrieve the + _metaclass_ for the current class, pointed at by + the class's "isa" pointer. The following assumes that + "isa" is the first ivar in a class (which it must be). */ + super_class + = build_indirect_ref + (build_c_cast (build_pointer_type (objc_class_type), + super_class), "unary *"); + } + else + { + add_class_reference (super_name); + super_class = (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL + ? objc_get_class_decl : objc_get_meta_class_decl); + assemble_external (super_class); + super_class + = build_function_call + (super_class, + build_tree_list + (NULL_TREE, + my_build_string_pointer + (IDENTIFIER_LENGTH (super_name) + 1, + IDENTIFIER_POINTER (super_name)))); + } + + super_expr + = build_modify_expr (super_expr, NOP_EXPR, + build_c_cast (TREE_TYPE (super_expr), + super_class)); + } + + super_expr_list = build_compound_expr (super_expr_list, super_expr); + + super_expr = build_unary_op (ADDR_EXPR, UOBJC_SUPER_decl, 0); + super_expr_list = build_compound_expr (super_expr_list, super_expr); + + return super_expr_list; + } + else + { + error ("[super ...] must appear in a method context"); + return error_mark_node; + } +} + +/* When exiting a scope, sever links to a 'super' declaration (if any) + therein contained. */ + +void +objc_clear_super_receiver (void) +{ + if (objc_method_context + && UOBJC_SUPER_scope == objc_get_current_scope ()) { + UOBJC_SUPER_decl = 0; + UOBJC_SUPER_scope = 0; + } +} + +void +objc_finish_method_definition (tree fndecl) +{ + /* We cannot validly inline ObjC methods, at least not without a language + extension to declare that a method need not be dynamically + dispatched, so suppress all thoughts of doing so. */ + DECL_INLINE (fndecl) = 0; + DECL_UNINLINABLE (fndecl) = 1; + +#ifndef OBJCPLUS + /* The C++ front-end will have called finish_function() for us. */ + finish_function (); +#endif + + METHOD_ENCODING (objc_method_context) + = encode_method_prototype (objc_method_context); + + /* Required to implement _msgSuper. This must be done AFTER finish_function, + since the optimizer may find "may be used before set" errors. */ + objc_method_context = NULL_TREE; + + if (should_call_super_dealloc) + warning (0, "method possibly missing a [super dealloc] call"); +} + +#if 0 +int +lang_report_error_function (tree decl) +{ + if (objc_method_context) + { + fprintf (stderr, "In method %qs\n", + IDENTIFIER_POINTER (METHOD_SEL_NAME (objc_method_context))); + return 1; + } + + else + return 0; +} +#endif + +/* Given a tree DECL node, produce a printable description of it in the given + buffer, overwriting the buffer. */ + +static char * +gen_declaration (tree decl) +{ + errbuf[0] = '\0'; + + if (DECL_P (decl)) + { + gen_type_name_0 (TREE_TYPE (decl)); + + if (DECL_NAME (decl)) + { + if (!POINTER_TYPE_P (TREE_TYPE (decl))) + strcat (errbuf, " "); + + strcat (errbuf, IDENTIFIER_POINTER (DECL_NAME (decl))); + } + + if (DECL_INITIAL (decl) + && TREE_CODE (DECL_INITIAL (decl)) == INTEGER_CST) + sprintf (errbuf + strlen (errbuf), ": " HOST_WIDE_INT_PRINT_DEC, + TREE_INT_CST_LOW (DECL_INITIAL (decl))); + } + + return errbuf; +} + +/* Given a tree TYPE node, produce a printable description of it in the given + buffer, overwriting the buffer. */ + +static char * +gen_type_name_0 (tree type) +{ + tree orig = type, proto; + + if (TYPE_P (type) && TYPE_NAME (type)) + type = TYPE_NAME (type); + else if (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) + { + tree inner = TREE_TYPE (type); + + while (TREE_CODE (inner) == ARRAY_TYPE) + inner = TREE_TYPE (inner); + + gen_type_name_0 (inner); + + if (!POINTER_TYPE_P (inner)) + strcat (errbuf, " "); + + if (POINTER_TYPE_P (type)) + strcat (errbuf, "*"); + else + while (type != inner) + { + strcat (errbuf, "["); + + if (TYPE_DOMAIN (type)) + { + char sz[20]; + + sprintf (sz, HOST_WIDE_INT_PRINT_DEC, + (TREE_INT_CST_LOW + (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + 1)); + strcat (errbuf, sz); + } + + strcat (errbuf, "]"); + type = TREE_TYPE (type); + } + + goto exit_function; + } + + if (TREE_CODE (type) == TYPE_DECL && DECL_NAME (type)) + type = DECL_NAME (type); + + strcat (errbuf, IDENTIFIER_POINTER (type)); + + /* For 'id' and 'Class', adopted protocols are stored in the pointee. */ + if (objc_is_id (orig)) + orig = TREE_TYPE (orig); + + proto = TYPE_HAS_OBJC_INFO (orig) ? TYPE_OBJC_PROTOCOL_LIST (orig) : NULL_TREE; + + if (proto) + { + strcat (errbuf, " <"); + + while (proto) { + strcat (errbuf, + IDENTIFIER_POINTER (PROTOCOL_NAME (TREE_VALUE (proto)))); + proto = TREE_CHAIN (proto); + strcat (errbuf, proto ? ", " : ">"); + } + } + + exit_function: + return errbuf; +} + +static char * +gen_type_name (tree type) +{ + errbuf[0] = '\0'; + + return gen_type_name_0 (type); +} + +/* Given a method tree, put a printable description into the given + buffer (overwriting) and return a pointer to the buffer. */ + +static char * +gen_method_decl (tree method) +{ + tree chain; + + strcpy (errbuf, "("); /* NB: Do _not_ call strcat() here. */ + gen_type_name_0 (TREE_VALUE (TREE_TYPE (method))); + strcat (errbuf, ")"); + chain = METHOD_SEL_ARGS (method); + + if (chain) + { + /* We have a chain of keyword_decls. */ + do + { + if (KEYWORD_KEY_NAME (chain)) + strcat (errbuf, IDENTIFIER_POINTER (KEYWORD_KEY_NAME (chain))); + + strcat (errbuf, ":("); + gen_type_name_0 (TREE_VALUE (TREE_TYPE (chain))); + strcat (errbuf, ")"); + + strcat (errbuf, IDENTIFIER_POINTER (KEYWORD_ARG_NAME (chain))); + if ((chain = TREE_CHAIN (chain))) + strcat (errbuf, " "); + } + while (chain); + + if (METHOD_ADD_ARGS (method)) + { + chain = TREE_CHAIN (METHOD_ADD_ARGS (method)); + + /* Know we have a chain of parm_decls. */ + while (chain) + { + strcat (errbuf, ", "); + gen_type_name_0 (TREE_TYPE (TREE_VALUE (chain))); + chain = TREE_CHAIN (chain); + } + + if (METHOD_ADD_ARGS_ELLIPSIS_P (method)) + strcat (errbuf, ", ..."); + } + } + + else + /* We have a unary selector. */ + strcat (errbuf, IDENTIFIER_POINTER (METHOD_SEL_NAME (method))); + + return errbuf; +} + +/* Debug info. */ + + +/* Dump an @interface declaration of the supplied class CHAIN to the + supplied file FP. Used to implement the -gen-decls option (which + prints out an @interface declaration of all classes compiled in + this run); potentially useful for debugging the compiler too. */ +static void +dump_interface (FILE *fp, tree chain) +{ + /* FIXME: A heap overflow here whenever a method (or ivar) + declaration is so long that it doesn't fit in the buffer. The + code and all the related functions should be rewritten to avoid + using fixed size buffers. */ + const char *my_name = IDENTIFIER_POINTER (CLASS_NAME (chain)); + tree ivar_decls = CLASS_RAW_IVARS (chain); + tree nst_methods = CLASS_NST_METHODS (chain); + tree cls_methods = CLASS_CLS_METHODS (chain); + + fprintf (fp, "\n@interface %s", my_name); + + /* CLASS_SUPER_NAME is used to store the superclass name for + classes, and the category name for categories. */ + if (CLASS_SUPER_NAME (chain)) + { + const char *name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (chain)); + + if (TREE_CODE (chain) == CATEGORY_IMPLEMENTATION_TYPE + || TREE_CODE (chain) == CATEGORY_INTERFACE_TYPE) + { + fprintf (fp, " (%s)\n", name); + } + else + { + fprintf (fp, " : %s\n", name); + } + } + else + fprintf (fp, "\n"); + + /* FIXME - the following doesn't seem to work at the moment. */ + if (ivar_decls) + { + fprintf (fp, "{\n"); + do + { + fprintf (fp, "\t%s;\n", gen_declaration (ivar_decls)); + ivar_decls = TREE_CHAIN (ivar_decls); + } + while (ivar_decls); + fprintf (fp, "}\n"); + } + + while (nst_methods) + { + fprintf (fp, "- %s;\n", gen_method_decl (nst_methods)); + nst_methods = TREE_CHAIN (nst_methods); + } + + while (cls_methods) + { + fprintf (fp, "+ %s;\n", gen_method_decl (cls_methods)); + cls_methods = TREE_CHAIN (cls_methods); + } + + fprintf (fp, "@end\n"); +} + +/* Demangle function for Objective-C */ +static const char * +objc_demangle (const char *mangled) +{ + char *demangled, *cp; + + if (mangled[0] == '_' && + (mangled[1] == 'i' || mangled[1] == 'c') && + mangled[2] == '_') + { + cp = demangled = xmalloc(strlen(mangled) + 2); + if (mangled[1] == 'i') + *cp++ = '-'; /* for instance method */ + else + *cp++ = '+'; /* for class method */ + *cp++ = '['; /* opening left brace */ + strcpy(cp, mangled+3); /* tack on the rest of the mangled name */ + while (*cp && *cp == '_') + cp++; /* skip any initial underbars in class name */ + cp = strchr(cp, '_'); /* find first non-initial underbar */ + if (cp == NULL) + { + free(demangled); /* not mangled name */ + return mangled; + } + if (cp[1] == '_') /* easy case: no category name */ + { + *cp++ = ' '; /* replace two '_' with one ' ' */ + strcpy(cp, mangled + (cp - demangled) + 2); + } + else + { + *cp++ = '('; /* less easy case: category name */ + cp = strchr(cp, '_'); + if (cp == 0) + { + free(demangled); /* not mangled name */ + return mangled; + } + *cp++ = ')'; + *cp++ = ' '; /* overwriting 1st char of method name... */ + strcpy(cp, mangled + (cp - demangled)); /* get it back */ + } + while (*cp && *cp == '_') + cp++; /* skip any initial underbars in method name */ + for (; *cp; cp++) + if (*cp == '_') + *cp = ':'; /* replace remaining '_' with ':' */ + *cp++ = ']'; /* closing right brace */ + *cp++ = 0; /* string terminator */ + return demangled; + } + else + return mangled; /* not an objc mangled name */ +} + +const char * +objc_printable_name (tree decl, int kind ATTRIBUTE_UNUSED) +{ + return objc_demangle (IDENTIFIER_POINTER (DECL_NAME (decl))); +} + +static void +init_objc (void) +{ + gcc_obstack_init (&util_obstack); + util_firstobj = (char *) obstack_finish (&util_obstack); + + errbuf = (char *) xmalloc (1024 * 10); + hash_init (); + synth_module_prologue (); +} + +static void +finish_objc (void) +{ + struct imp_entry *impent; + tree chain; + /* The internally generated initializers appear to have missing braces. + Don't warn about this. */ + int save_warn_missing_braces = warn_missing_braces; + warn_missing_braces = 0; + + /* A missing @end may not be detected by the parser. */ + if (objc_implementation_context) + { + warning (0, "%<@end%> missing in implementation context"); + finish_class (objc_implementation_context); + objc_ivar_chain = NULL_TREE; + objc_implementation_context = NULL_TREE; + } + + /* Process the static instances here because initialization of objc_symtab + depends on them. */ + if (objc_static_instances) + generate_static_references (); + + if (imp_list || class_names_chain + || meth_var_names_chain || meth_var_types_chain || sel_ref_chain) + generate_objc_symtab_decl (); + + for (impent = imp_list; impent; impent = impent->next) + { + objc_implementation_context = impent->imp_context; + implementation_template = impent->imp_template; + + UOBJC_CLASS_decl = impent->class_decl; + UOBJC_METACLASS_decl = impent->meta_decl; + + /* Dump the @interface of each class as we compile it, if the + -gen-decls option is in use. TODO: Dump the classes in the + order they were found, rather than in reverse order as we + are doing now. */ + if (flag_gen_declaration) + { + dump_interface (gen_declaration_file, objc_implementation_context); + } + + if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE) + { + /* all of the following reference the string pool... */ + generate_ivar_lists (); + generate_dispatch_tables (); + generate_shared_structures (impent->has_cxx_cdtors + ? CLS_HAS_CXX_STRUCTORS + : 0); + } + else + { + generate_dispatch_tables (); + generate_category (objc_implementation_context); + } + } + + /* If we are using an array of selectors, we must always + finish up the array decl even if no selectors were used. */ + if (! flag_next_runtime || sel_ref_chain) + build_selector_translation_table (); + + if (protocol_chain) + generate_protocols (); + + if ((flag_replace_objc_classes && imp_list) || flag_objc_gc) + generate_objc_image_info (); + + /* Arrange for ObjC data structures to be initialized at run time. */ + if (objc_implementation_context || class_names_chain || objc_static_instances + || meth_var_names_chain || meth_var_types_chain || sel_ref_chain) + { + build_module_descriptor (); + + if (!flag_next_runtime) + build_module_initializer_routine (); + } + + /* Dump the class references. This forces the appropriate classes + to be linked into the executable image, preserving unix archive + semantics. This can be removed when we move to a more dynamically + linked environment. */ + + for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain)) + { + handle_class_ref (chain); + if (TREE_PURPOSE (chain)) + generate_classref_translation_entry (chain); + } + + for (impent = imp_list; impent; impent = impent->next) + handle_impent (impent); + + if (warn_selector) + { + int slot; + hash hsh; + + /* Run through the selector hash tables and print a warning for any + selector which has multiple methods. */ + + for (slot = 0; slot < SIZEHASHTABLE; slot++) + { + for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next) + check_duplicates (hsh, 0, 1); + for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next) + check_duplicates (hsh, 0, 1); + } + } + + warn_missing_braces = save_warn_missing_braces; +} + +/* Subroutines of finish_objc. */ + +static void +generate_classref_translation_entry (tree chain) +{ + tree expr, decl, type; + + decl = TREE_PURPOSE (chain); + type = TREE_TYPE (decl); + + expr = add_objc_string (TREE_VALUE (chain), class_names); + expr = convert (type, expr); /* cast! */ + + /* The decl that is the one that we + forward declared in build_class_reference. */ + finish_var_decl (decl, expr); + return; +} + +static void +handle_class_ref (tree chain) +{ + const char *name = IDENTIFIER_POINTER (TREE_VALUE (chain)); + char *string = (char *) alloca (strlen (name) + 30); + tree decl; + tree exp; + + sprintf (string, "%sobjc_class_name_%s", + (flag_next_runtime ? "." : "__"), name); + +#ifdef ASM_DECLARE_UNRESOLVED_REFERENCE + if (flag_next_runtime) + { + ASM_DECLARE_UNRESOLVED_REFERENCE (asm_out_file, string); + return; + } +#endif + + /* Make a decl for this name, so we can use its address in a tree. */ + decl = build_decl (VAR_DECL, get_identifier (string), char_type_node); + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + + pushdecl (decl); + rest_of_decl_compilation (decl, 0, 0); + + /* Make a decl for the address. */ + sprintf (string, "%sobjc_class_ref_%s", + (flag_next_runtime ? "." : "__"), name); + exp = build1 (ADDR_EXPR, string_type_node, decl); + decl = build_decl (VAR_DECL, get_identifier (string), string_type_node); + DECL_INITIAL (decl) = exp; + TREE_STATIC (decl) = 1; + TREE_USED (decl) = 1; + /* Force the output of the decl as this forces the reference of the class. */ + mark_decl_referenced (decl); + + pushdecl (decl); + rest_of_decl_compilation (decl, 0, 0); +} + +static void +handle_impent (struct imp_entry *impent) +{ + char *string; + + objc_implementation_context = impent->imp_context; + implementation_template = impent->imp_template; + + if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) + { + const char *const class_name = + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)); + + string = (char *) alloca (strlen (class_name) + 30); + + sprintf (string, "%sobjc_class_name_%s", + (flag_next_runtime ? "." : "__"), class_name); + } + else if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE) + { + const char *const class_name = + IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)); + const char *const class_super_name = + IDENTIFIER_POINTER (CLASS_SUPER_NAME (impent->imp_context)); + + string = (char *) alloca (strlen (class_name) + + strlen (class_super_name) + 30); + + /* Do the same for categories. Even though no references to + these symbols are generated automatically by the compiler, it + gives you a handle to pull them into an archive by hand. */ + sprintf (string, "*%sobjc_category_name_%s_%s", + (flag_next_runtime ? "." : "__"), class_name, class_super_name); + } + else + return; + +#ifdef ASM_DECLARE_CLASS_REFERENCE + if (flag_next_runtime) + { + ASM_DECLARE_CLASS_REFERENCE (asm_out_file, string); + return; + } + else +#endif + { + tree decl, init; + + init = build_int_cst (c_common_type_for_size (BITS_PER_WORD, 1), 0); + decl = build_decl (VAR_DECL, get_identifier (string), TREE_TYPE (init)); + TREE_PUBLIC (decl) = 1; + TREE_READONLY (decl) = 1; + TREE_USED (decl) = 1; + TREE_CONSTANT (decl) = 1; + DECL_CONTEXT (decl) = 0; + DECL_ARTIFICIAL (decl) = 1; + DECL_INITIAL (decl) = init; + assemble_variable (decl, 1, 0, 0); + } +} + +/* The Fix-and-Continue functionality available in Mac OS X 10.3 and + later requires that ObjC translation units participating in F&C be + specially marked. The following routine accomplishes this. */ + +/* static int _OBJC_IMAGE_INFO[2] = { 0, 1 }; */ + +static void +generate_objc_image_info (void) +{ + tree decl, initlist; + int flags + = ((flag_replace_objc_classes && imp_list ? 1 : 0) + | (flag_objc_gc ? 2 : 0)); + + decl = start_var_decl (build_array_type + (integer_type_node, + build_index_type (build_int_cst (NULL_TREE, 2 - 1))), + "_OBJC_IMAGE_INFO"); + + initlist = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, 0)); + initlist = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, flags), initlist); + initlist = objc_build_constructor (TREE_TYPE (decl), nreverse (initlist)); + + finish_var_decl (decl, initlist); +} + +/* Look up ID as an instance variable. OTHER contains the result of + the C or C++ lookup, which we may want to use instead. */ + +tree +objc_lookup_ivar (tree other, tree id) +{ + tree ivar; + + /* If we are not inside of an ObjC method, ivar lookup makes no sense. */ + if (!objc_method_context) + return other; + + if (!strcmp (IDENTIFIER_POINTER (id), "super")) + /* We have a message to super. */ + return get_super_receiver (); + + /* In a class method, look up an instance variable only as a last + resort. */ + if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL + && other && other != error_mark_node) + return other; + + /* Look up the ivar, but do not use it if it is not accessible. */ + ivar = is_ivar (objc_ivar_chain, id); + + if (!ivar || is_private (ivar)) + return other; + + /* In an instance method, a local variable (or parameter) may hide the + instance variable. */ + if (TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL + && other && other != error_mark_node +#ifdef OBJCPLUS + && CP_DECL_CONTEXT (other) != global_namespace) +#else + && !DECL_FILE_SCOPE_P (other)) +#endif + { + warning (0, "local declaration of %qs hides instance variable", + IDENTIFIER_POINTER (id)); + + return other; + } + + /* At this point, we are either in an instance method with no obscuring + local definitions, or in a class method with no alternate definitions + at all. */ + return build_ivar_reference (id); +} + +/* Possibly rewrite a function CALL into an OBJ_TYPE_REF expression. This + needs to be done if we are calling a function through a cast. */ + +tree +objc_rewrite_function_call (tree function, tree params) +{ + if (TREE_CODE (function) == NOP_EXPR + && TREE_CODE (TREE_OPERAND (function, 0)) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (function, 0), 0)) + == FUNCTION_DECL) + { + function = build (OBJ_TYPE_REF, TREE_TYPE (function), + TREE_OPERAND (function, 0), + TREE_VALUE (params), size_zero_node); + } + + return function; +} + +/* Look for the special case of OBJC_TYPE_REF with the address of + a function in OBJ_TYPE_REF_EXPR (presumably objc_msgSend or one + of its cousins). */ + +enum gimplify_status +objc_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p) +{ + enum gimplify_status r0, r1; + if (TREE_CODE (*expr_p) == OBJ_TYPE_REF + && TREE_CODE (OBJ_TYPE_REF_EXPR (*expr_p)) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (OBJ_TYPE_REF_EXPR (*expr_p), 0)) + == FUNCTION_DECL) + { + /* Postincrements in OBJ_TYPE_REF_OBJECT don't affect the + value of the OBJ_TYPE_REF, so force them to be emitted + during subexpression evaluation rather than after the + OBJ_TYPE_REF. This permits objc_msgSend calls in Objective + C to use direct rather than indirect calls when the + object expression has a postincrement. */ + r0 = gimplify_expr (&OBJ_TYPE_REF_OBJECT (*expr_p), pre_p, NULL, + is_gimple_val, fb_rvalue); + r1 = gimplify_expr (&OBJ_TYPE_REF_EXPR (*expr_p), pre_p, post_p, + is_gimple_val, fb_rvalue); + + return MIN (r0, r1); + } + +#ifdef OBJCPLUS + return cp_gimplify_expr (expr_p, pre_p, post_p); +#else + return c_gimplify_expr (expr_p, pre_p, post_p); +#endif +} + +/* Given a CALL expression, find the function being called. The ObjC + version looks for the OBJ_TYPE_REF_EXPR which is used for objc_msgSend. */ + +tree +objc_get_callee_fndecl (tree call_expr) +{ + tree addr = TREE_OPERAND (call_expr, 0); + if (TREE_CODE (addr) != OBJ_TYPE_REF) + return 0; + + addr = OBJ_TYPE_REF_EXPR (addr); + + /* If the address is just `&f' for some function `f', then we know + that `f' is being called. */ + if (TREE_CODE (addr) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (addr, 0)) == FUNCTION_DECL) + return TREE_OPERAND (addr, 0); + + return 0; +} + +#include "gt-objc-objc-act.h" diff --git a/contrib/gcc-4.1/gcc/objc/objc-act.h b/contrib/gcc-4.1/gcc/objc/objc-act.h new file mode 100644 index 0000000000..d801865688 --- /dev/null +++ b/contrib/gcc-4.1/gcc/objc/objc-act.h @@ -0,0 +1,457 @@ +/* Declarations for objc-act.c. + Copyright (C) 1990, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifndef GCC_OBJC_ACT_H +#define GCC_OBJC_ACT_H + +/* For enum gimplify_status */ +#include "tree-gimple.h" + +/*** Language hooks ***/ + +bool objc_init (void); +const char *objc_printable_name (tree, int); +tree objc_get_callee_fndecl (tree); +void objc_finish_file (void); +tree objc_fold_obj_type_ref (tree, tree); +enum gimplify_status objc_gimplify_expr (tree *, tree *, tree *); + +/* NB: The remaining public functions are prototyped in c-common.h, for the + benefit of stub-objc.c and objc-act.c. */ + +/* Objective-C structures */ + +#define CLASS_LANG_SLOT_ELTS 5 +#define PROTOCOL_LANG_SLOT_ELTS 2 +#define OBJC_INFO_SLOT_ELTS 2 + +/* KEYWORD_DECL */ +#define KEYWORD_KEY_NAME(DECL) ((DECL)->decl_minimal.name) +#define KEYWORD_ARG_NAME(DECL) ((DECL)->decl_non_common.arguments) + +/* INSTANCE_METHOD_DECL, CLASS_METHOD_DECL */ +#define METHOD_SEL_NAME(DECL) ((DECL)->decl_minimal.name) +#define METHOD_SEL_ARGS(DECL) ((DECL)->decl_non_common.arguments) +#define METHOD_ADD_ARGS(DECL) ((DECL)->decl_non_common.result) +#define METHOD_ADD_ARGS_ELLIPSIS_P(DECL) ((DECL)->decl_common.lang_flag_0) +#define METHOD_DEFINITION(DECL) ((DECL)->decl_common.initial) +#define METHOD_ENCODING(DECL) ((DECL)->decl_minimal.context) + +/* CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE, + CATEGORY_INTERFACE_TYPE, CATEGORY_IMPLEMENTATION_TYPE, + PROTOCOL_INTERFACE_TYPE */ +#define CLASS_NAME(CLASS) ((CLASS)->type.name) +#define CLASS_SUPER_NAME(CLASS) (TYPE_CHECK (CLASS)->type.context) +#define CLASS_IVARS(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 0) +#define CLASS_RAW_IVARS(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 1) +#define CLASS_NST_METHODS(CLASS) ((CLASS)->type.minval) +#define CLASS_CLS_METHODS(CLASS) ((CLASS)->type.maxval) +#define CLASS_STATIC_TEMPLATE(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 2) +#define CLASS_CATEGORY_LIST(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 3) +#define CLASS_PROTOCOL_LIST(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 4) +#define PROTOCOL_NAME(CLASS) ((CLASS)->type.name) +#define PROTOCOL_LIST(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 0) +#define PROTOCOL_NST_METHODS(CLASS) ((CLASS)->type.minval) +#define PROTOCOL_CLS_METHODS(CLASS) ((CLASS)->type.maxval) +#define PROTOCOL_FORWARD_DECL(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 1) +#define PROTOCOL_DEFINED(CLASS) TREE_USED (CLASS) + +/* ObjC-specific information pertaining to RECORD_TYPEs are stored in + the LANG_SPECIFIC structures, which may itself need allocating first. */ + +/* The following three macros must be overridden (in objcp/objcp-decl.h) + for Objective-C++. */ +#define TYPE_OBJC_INFO(TYPE) TYPE_LANG_SPECIFIC (TYPE)->objc_info +#define SIZEOF_OBJC_TYPE_LANG_SPECIFIC sizeof (struct lang_type) +#define ALLOC_OBJC_TYPE_LANG_SPECIFIC(NODE) \ + do { \ + TYPE_LANG_SPECIFIC (NODE) = GGC_CNEW (struct lang_type); \ + } while (0) + +#define TYPE_HAS_OBJC_INFO(TYPE) \ + (TYPE_LANG_SPECIFIC (TYPE) && TYPE_OBJC_INFO (TYPE)) +#define TYPE_OBJC_INTERFACE(TYPE) TREE_VEC_ELT (TYPE_OBJC_INFO (TYPE), 0) +#define TYPE_OBJC_PROTOCOL_LIST(TYPE) TREE_VEC_ELT (TYPE_OBJC_INFO (TYPE), 1) + + +#define INIT_TYPE_OBJC_INFO(TYPE) \ + do \ + { \ + if (!TYPE_LANG_SPECIFIC (TYPE)) \ + ALLOC_OBJC_TYPE_LANG_SPECIFIC(TYPE); \ + if (!TYPE_OBJC_INFO (TYPE)) \ + TYPE_OBJC_INFO (TYPE) \ + = make_tree_vec (OBJC_INFO_SLOT_ELTS); \ + } \ + while (0) +#define DUP_TYPE_OBJC_INFO(DST, SRC) \ + do \ + { \ + ALLOC_OBJC_TYPE_LANG_SPECIFIC(DST); \ + if (TYPE_LANG_SPECIFIC (SRC)) \ + memcpy (TYPE_LANG_SPECIFIC (DST), \ + TYPE_LANG_SPECIFIC (SRC), \ + SIZEOF_OBJC_TYPE_LANG_SPECIFIC); \ + TYPE_OBJC_INFO (DST) \ + = make_tree_vec (OBJC_INFO_SLOT_ELTS); \ + } \ + while (0) + +#define TYPED_OBJECT(TYPE) \ + (TREE_CODE (TYPE) == RECORD_TYPE \ + && TYPE_HAS_OBJC_INFO (TYPE) \ + && TYPE_OBJC_INTERFACE (TYPE)) +#define OBJC_TYPE_NAME(TYPE) TYPE_NAME(TYPE) +#define OBJC_SET_TYPE_NAME(TYPE, NAME) (TYPE_NAME (TYPE) = NAME) + +/* Define the Objective-C or Objective-C++ language-specific tree codes. */ + +#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) SYM, +enum objc_tree_code { +#if defined (GCC_CP_TREE_H) + LAST_BASE_TREE_CODE = LAST_CPLUS_TREE_CODE, +#else +#if defined (GCC_C_TREE_H) + LAST_BASE_TREE_CODE = LAST_C_TREE_CODE, +#else + #error You must include or before +#endif +#endif +#include "objc-tree.def" + LAST_OBJC_TREE_CODE +}; +#undef DEFTREECODE + +/* Hash tables to manage the global pool of method prototypes. */ + +typedef struct hashed_entry *hash; +typedef struct hashed_attribute *attr; + +struct hashed_attribute GTY(()) +{ + attr next; + tree value; +}; +struct hashed_entry GTY(()) +{ + attr list; + hash next; + tree key; +}; + +extern GTY ((length ("SIZEHASHTABLE"))) hash *nst_method_hash_list; +extern GTY ((length ("SIZEHASHTABLE"))) hash *cls_method_hash_list; + +#define SIZEHASHTABLE 257 + +/* Objective-C/Objective-C++ @implementation list. */ + +struct imp_entry GTY(()) +{ + struct imp_entry *next; + tree imp_context; + tree imp_template; + tree class_decl; /* _OBJC_CLASS_; */ + tree meta_decl; /* _OBJC_METACLASS_; */ + BOOL_BITFIELD has_cxx_cdtors : 1; +}; + +extern GTY(()) struct imp_entry *imp_list; +extern GTY(()) int imp_count; /* `@implementation' */ +extern GTY(()) int cat_count; /* `@category' */ + +extern GTY(()) enum tree_code objc_inherit_code; +extern GTY(()) int objc_public_flag; + +/* Objective-C/Objective-C++ global tree enumeration. */ + +enum objc_tree_index +{ + OCTI_STATIC_NST, + OCTI_STATIC_NST_DECL, + OCTI_SELF_ID, + OCTI_UCMD_ID, + + OCTI_SELF_DECL, + OCTI_UMSG_DECL, + OCTI_UMSG_FAST_DECL, + OCTI_UMSG_SUPER_DECL, + OCTI_UMSG_STRET_DECL, + OCTI_UMSG_SUPER_STRET_DECL, + OCTI_GET_CLASS_DECL, + OCTI_GET_MCLASS_DECL, + OCTI_SUPER_TYPE, + OCTI_SEL_TYPE, + OCTI_ID_TYPE, + OCTI_CLS_TYPE, + OCTI_NST_TYPE, + OCTI_PROTO_TYPE, + + OCTI_CLS_CHAIN, + OCTI_ALIAS_CHAIN, + OCTI_INTF_CHAIN, + OCTI_PROTO_CHAIN, + OCTI_IMPL_CHAIN, + OCTI_CLS_REF_CHAIN, + OCTI_SEL_REF_CHAIN, + OCTI_IVAR_CHAIN, + OCTI_CLS_NAMES_CHAIN, + OCTI_METH_VAR_NAMES_CHAIN, + OCTI_METH_VAR_TYPES_CHAIN, + + OCTI_SYMBOLS_DECL, + OCTI_NST_VAR_DECL, + OCTI_CLS_VAR_DECL, + OCTI_NST_METH_DECL, + OCTI_CLS_METH_DECL, + OCTI_CLS_DECL, + OCTI_MCLS_DECL, + OCTI_SEL_TABLE_DECL, + OCTI_MODULES_DECL, + OCTI_GNU_INIT_DECL, + + OCTI_INTF_CTX, + OCTI_IMPL_CTX, + OCTI_METH_CTX, + OCTI_IVAR_CTX, + + OCTI_IMPL_TEMPL, + OCTI_CLS_TEMPL, + OCTI_CAT_TEMPL, + OCTI_UPRIV_REC, + OCTI_PROTO_TEMPL, + OCTI_SEL_TEMPL, + OCTI_UCLS_SUPER_REF, + OCTI_UUCLS_SUPER_REF, + OCTI_METH_TEMPL, + OCTI_IVAR_TEMPL, + OCTI_METH_LIST_TEMPL, + OCTI_METH_PROTO_LIST_TEMPL, + OCTI_IVAR_LIST_TEMPL, + OCTI_SYMTAB_TEMPL, + OCTI_MODULE_TEMPL, + OCTI_SUPER_TEMPL, + OCTI_OBJ_REF, + OCTI_CLS_REF, + OCTI_METH_PROTO_TEMPL, + OCTI_FUNCTION1_TEMPL, + OCTI_FUNCTION2_TEMPL, + + OCTI_OBJ_ID, + OCTI_CLS_ID, + OCTI_ID_NAME, + OCTI_CLASS_NAME, + OCTI_CNST_STR_ID, + OCTI_CNST_STR_TYPE, + OCTI_CNST_STR_GLOB_ID, + OCTI_STRING_CLASS_DECL, + OCTI_INTERNAL_CNST_STR_TYPE, + OCTI_SUPER_DECL, + OCTI_UMSG_NONNIL_DECL, + OCTI_UMSG_NONNIL_STRET_DECL, + OCTI_STORAGE_CLS, + OCTI_EXCEPTION_EXTRACT_DECL, + OCTI_EXCEPTION_TRY_ENTER_DECL, + OCTI_EXCEPTION_TRY_EXIT_DECL, + OCTI_EXCEPTION_MATCH_DECL, + OCTI_EXCEPTION_THROW_DECL, + OCTI_SYNC_ENTER_DECL, + OCTI_SYNC_EXIT_DECL, + OCTI_SETJMP_DECL, + OCTI_EXCDATA_TEMPL, + OCTI_STACK_EXCEPTION_DATA_DECL, + OCTI_LOCAL_EXCEPTION_DECL, + OCTI_RETHROW_EXCEPTION_DECL, + OCTI_EVAL_ONCE_DECL, + OCTI_CATCH_TYPE, + OCTI_EXECCLASS_DECL, + + OCTI_ASSIGN_IVAR_DECL, + OCTI_ASSIGN_IVAR_FAST_DECL, + OCTI_ASSIGN_GLOBAL_DECL, + OCTI_ASSIGN_STRONGCAST_DECL, + + OCTI_MAX +}; + +extern GTY(()) tree objc_global_trees[OCTI_MAX]; + +/* List of classes with list of their static instances. */ +#define objc_static_instances objc_global_trees[OCTI_STATIC_NST] + +/* The declaration of the array administrating the static instances. */ +#define static_instances_decl objc_global_trees[OCTI_STATIC_NST_DECL] + +/* Some commonly used instances of "identifier_node". */ + +#define self_id objc_global_trees[OCTI_SELF_ID] +#define ucmd_id objc_global_trees[OCTI_UCMD_ID] + +#define self_decl objc_global_trees[OCTI_SELF_DECL] +#define umsg_decl objc_global_trees[OCTI_UMSG_DECL] +#define umsg_fast_decl objc_global_trees[OCTI_UMSG_FAST_DECL] +#define umsg_super_decl objc_global_trees[OCTI_UMSG_SUPER_DECL] +#define umsg_stret_decl objc_global_trees[OCTI_UMSG_STRET_DECL] +#define umsg_super_stret_decl objc_global_trees[OCTI_UMSG_SUPER_STRET_DECL] +#define objc_get_class_decl objc_global_trees[OCTI_GET_CLASS_DECL] +#define objc_get_meta_class_decl \ + objc_global_trees[OCTI_GET_MCLASS_DECL] + +#define objc_super_type objc_global_trees[OCTI_SUPER_TYPE] +#define objc_selector_type objc_global_trees[OCTI_SEL_TYPE] +#define objc_object_type objc_global_trees[OCTI_ID_TYPE] +#define objc_class_type objc_global_trees[OCTI_CLS_TYPE] +#define objc_instance_type objc_global_trees[OCTI_NST_TYPE] +#define objc_protocol_type objc_global_trees[OCTI_PROTO_TYPE] + +/* Type checking macros. */ + +#define IS_ID(TYPE) \ + (TREE_CODE (TYPE) == POINTER_TYPE \ + && (TYPE_MAIN_VARIANT (TREE_TYPE (TYPE)) \ + == TREE_TYPE (objc_object_type))) +#define IS_CLASS(TYPE) \ + (TREE_CODE (TYPE) == POINTER_TYPE \ + && (TYPE_MAIN_VARIANT (TREE_TYPE (TYPE)) \ + == TREE_TYPE (objc_class_type))) +#define IS_PROTOCOL_QUALIFIED_UNTYPED(TYPE) \ + ((IS_ID (TYPE) || IS_CLASS (TYPE)) \ + && TYPE_HAS_OBJC_INFO (TREE_TYPE (TYPE)) \ + && TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (TYPE))) +#define IS_SUPER(TYPE) \ + (TREE_CODE (TYPE) == POINTER_TYPE \ + && TREE_TYPE (TYPE) == objc_super_template) + +#define class_chain objc_global_trees[OCTI_CLS_CHAIN] +#define alias_chain objc_global_trees[OCTI_ALIAS_CHAIN] +#define interface_chain objc_global_trees[OCTI_INTF_CHAIN] +#define protocol_chain objc_global_trees[OCTI_PROTO_CHAIN] +#define implemented_classes objc_global_trees[OCTI_IMPL_CHAIN] + +/* Chains to manage selectors that are referenced and defined in the + module. */ + +#define cls_ref_chain objc_global_trees[OCTI_CLS_REF_CHAIN] /* Classes referenced. */ +#define sel_ref_chain objc_global_trees[OCTI_SEL_REF_CHAIN] /* Selectors referenced. */ +#define objc_ivar_chain objc_global_trees[OCTI_IVAR_CHAIN] + +/* Chains to manage uniquing of strings. */ + +#define class_names_chain objc_global_trees[OCTI_CLS_NAMES_CHAIN] +#define meth_var_names_chain objc_global_trees[OCTI_METH_VAR_NAMES_CHAIN] +#define meth_var_types_chain objc_global_trees[OCTI_METH_VAR_TYPES_CHAIN] + + +/* Backend data declarations. */ + +#define UOBJC_SYMBOLS_decl objc_global_trees[OCTI_SYMBOLS_DECL] +#define UOBJC_INSTANCE_VARIABLES_decl objc_global_trees[OCTI_NST_VAR_DECL] +#define UOBJC_CLASS_VARIABLES_decl objc_global_trees[OCTI_CLS_VAR_DECL] +#define UOBJC_INSTANCE_METHODS_decl objc_global_trees[OCTI_NST_METH_DECL] +#define UOBJC_CLASS_METHODS_decl objc_global_trees[OCTI_CLS_METH_DECL] +#define UOBJC_CLASS_decl objc_global_trees[OCTI_CLS_DECL] +#define UOBJC_METACLASS_decl objc_global_trees[OCTI_MCLS_DECL] +#define UOBJC_SELECTOR_TABLE_decl objc_global_trees[OCTI_SEL_TABLE_DECL] +#define UOBJC_MODULES_decl objc_global_trees[OCTI_MODULES_DECL] +#define GNU_INIT_decl objc_global_trees[OCTI_GNU_INIT_DECL] + +/* The following are used when compiling a class implementation. + implementation_template will normally be an interface, however if + none exists this will be equal to objc_implementation_context...it is + set in start_class. */ + +#define objc_interface_context objc_global_trees[OCTI_INTF_CTX] +#define objc_implementation_context objc_global_trees[OCTI_IMPL_CTX] +#define objc_method_context objc_global_trees[OCTI_METH_CTX] +#define objc_ivar_context objc_global_trees[OCTI_IVAR_CTX] + +#define implementation_template objc_global_trees[OCTI_IMPL_TEMPL] +#define objc_class_template objc_global_trees[OCTI_CLS_TEMPL] +#define objc_category_template objc_global_trees[OCTI_CAT_TEMPL] +#define uprivate_record objc_global_trees[OCTI_UPRIV_REC] +#define objc_protocol_template objc_global_trees[OCTI_PROTO_TEMPL] +#define objc_selector_template objc_global_trees[OCTI_SEL_TEMPL] +#define ucls_super_ref objc_global_trees[OCTI_UCLS_SUPER_REF] +#define uucls_super_ref objc_global_trees[OCTI_UUCLS_SUPER_REF] + +#define umsg_nonnil_decl objc_global_trees[OCTI_UMSG_NONNIL_DECL] +#define umsg_nonnil_stret_decl objc_global_trees[OCTI_UMSG_NONNIL_STRET_DECL] +#define objc_storage_class objc_global_trees[OCTI_STORAGE_CLS] +#define objc_exception_extract_decl \ + objc_global_trees[OCTI_EXCEPTION_EXTRACT_DECL] +#define objc_exception_try_enter_decl \ + objc_global_trees[OCTI_EXCEPTION_TRY_ENTER_DECL] +#define objc_exception_try_exit_decl \ + objc_global_trees[OCTI_EXCEPTION_TRY_EXIT_DECL] +#define objc_exception_match_decl \ + objc_global_trees[OCTI_EXCEPTION_MATCH_DECL] +#define objc_exception_throw_decl \ + objc_global_trees[OCTI_EXCEPTION_THROW_DECL] +#define objc_sync_enter_decl objc_global_trees[OCTI_SYNC_ENTER_DECL] +#define objc_sync_exit_decl objc_global_trees[OCTI_SYNC_EXIT_DECL] +#define objc_exception_data_template \ + objc_global_trees[OCTI_EXCDATA_TEMPL] +#define objc_setjmp_decl objc_global_trees[OCTI_SETJMP_DECL] +#define objc_stack_exception_data \ + objc_global_trees[OCTI_STACK_EXCEPTION_DATA_DECL] +#define objc_caught_exception objc_global_trees[OCTI_LOCAL_EXCEPTION_DECL] +#define objc_rethrow_exception objc_global_trees[OCTI_RETHROW_EXCEPTION_DECL] +#define objc_eval_once objc_global_trees[OCTI_EVAL_ONCE_DECL] +#define objc_catch_type objc_global_trees[OCTI_CATCH_TYPE] + +#define execclass_decl objc_global_trees[OCTI_EXECCLASS_DECL] + +#define objc_assign_ivar_decl objc_global_trees[OCTI_ASSIGN_IVAR_DECL] +#define objc_assign_ivar_fast_decl \ + objc_global_trees[OCTI_ASSIGN_IVAR_FAST_DECL] +#define objc_assign_global_decl objc_global_trees[OCTI_ASSIGN_GLOBAL_DECL] +#define objc_assign_strong_cast_decl \ + objc_global_trees[OCTI_ASSIGN_STRONGCAST_DECL] + +#define objc_method_template objc_global_trees[OCTI_METH_TEMPL] +#define objc_ivar_template objc_global_trees[OCTI_IVAR_TEMPL] +#define objc_method_list_ptr objc_global_trees[OCTI_METH_LIST_TEMPL] +#define objc_method_proto_list_ptr \ + objc_global_trees[OCTI_METH_PROTO_LIST_TEMPL] +#define objc_ivar_list_ptr objc_global_trees[OCTI_IVAR_LIST_TEMPL] +#define objc_symtab_template objc_global_trees[OCTI_SYMTAB_TEMPL] +#define objc_module_template objc_global_trees[OCTI_MODULE_TEMPL] +#define objc_super_template objc_global_trees[OCTI_SUPER_TEMPL] +#define objc_object_reference objc_global_trees[OCTI_OBJ_REF] +#define objc_class_reference objc_global_trees[OCTI_CLS_REF] +#define objc_method_prototype_template \ + objc_global_trees[OCTI_METH_PROTO_TEMPL] +#define function1_template objc_global_trees[OCTI_FUNCTION1_TEMPL] +#define function2_template objc_global_trees[OCTI_FUNCTION2_TEMPL] + +#define objc_object_id objc_global_trees[OCTI_OBJ_ID] +#define objc_class_id objc_global_trees[OCTI_CLS_ID] +#define objc_object_name objc_global_trees[OCTI_ID_NAME] +#define objc_class_name objc_global_trees[OCTI_CLASS_NAME] +#define constant_string_id objc_global_trees[OCTI_CNST_STR_ID] +#define constant_string_type objc_global_trees[OCTI_CNST_STR_TYPE] +#define constant_string_global_id \ + objc_global_trees[OCTI_CNST_STR_GLOB_ID] +#define string_class_decl objc_global_trees[OCTI_STRING_CLASS_DECL] +#define internal_const_str_type objc_global_trees[OCTI_INTERNAL_CNST_STR_TYPE] +#define UOBJC_SUPER_decl objc_global_trees[OCTI_SUPER_DECL] + +#endif /* GCC_OBJC_ACT_H */ diff --git a/contrib/gcc-4.1/gcc/objc/objc-lang.c b/contrib/gcc-4.1/gcc/objc/objc-lang.c new file mode 100644 index 0000000000..b94f037c54 --- /dev/null +++ b/contrib/gcc-4.1/gcc/objc/objc-lang.c @@ -0,0 +1,133 @@ +/* Language-dependent hooks for Objective-C. + Copyright 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Contributed by Ziemowit Laski + +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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "c-tree.h" +#include "c-common.h" +#include "ggc.h" +#include "objc-act.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "diagnostic.h" +#include "c-objc-common.h" + +enum c_language_kind c_language = clk_objc; +static void objc_init_ts (void); + +/* Lang hooks common to C and ObjC are declared in c-objc-common.h; + consequently, there should be very few hooks below. */ + +#undef LANG_HOOKS_NAME +#define LANG_HOOKS_NAME "GNU Objective-C" +#undef LANG_HOOKS_INIT +#define LANG_HOOKS_INIT objc_init +#undef LANG_HOOKS_DECL_PRINTABLE_NAME +#define LANG_HOOKS_DECL_PRINTABLE_NAME objc_printable_name +#undef LANG_HOOKS_GIMPLIFY_EXPR +#define LANG_HOOKS_GIMPLIFY_EXPR objc_gimplify_expr +#undef LANG_HOOKS_GET_CALLEE_FNDECL +#define LANG_HOOKS_GET_CALLEE_FNDECL objc_get_callee_fndecl +#undef LANG_HOOKS_INIT_TS +#define LANG_HOOKS_INIT_TS objc_init_ts + +/* Each front end provides its own lang hook initializer. */ +const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; + +/* Table indexed by tree code giving a string containing a character + classifying the tree code. */ + +#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE, + +const enum tree_code_class tree_code_type[] = { +#include "tree.def" + tcc_exceptional, +#include "c-common.def" + tcc_exceptional, +#include "objc-tree.def" +}; +#undef DEFTREECODE + +/* Table indexed by tree code giving number of expression + operands beyond the fixed part of the node structure. + Not used for types or decls. */ + +#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH, + +const unsigned char tree_code_length[] = { +#include "tree.def" + 0, +#include "c-common.def" + 0, +#include "objc-tree.def" +}; +#undef DEFTREECODE + +/* Names of tree components. + Used for printing out the tree and error messages. */ +#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME, + +const char * const tree_code_name[] = { +#include "tree.def" + "@@dummy", +#include "c-common.def" + "@@dummy", +#include "objc-tree.def" +}; +#undef DEFTREECODE + +/* Lang hook routines common to C and ObjC appear in c-objc-common.c; + there should be very few (if any) routines below. */ + +static void +objc_init_ts (void) +{ + tree_contains_struct[CLASS_METHOD_DECL][TS_DECL_NON_COMMON] = 1; + tree_contains_struct[INSTANCE_METHOD_DECL][TS_DECL_NON_COMMON] = 1; + tree_contains_struct[KEYWORD_DECL][TS_DECL_NON_COMMON] = 1; + + tree_contains_struct[CLASS_METHOD_DECL][TS_DECL_WITH_VIS] = 1; + tree_contains_struct[INSTANCE_METHOD_DECL][TS_DECL_WITH_VIS] = 1; + tree_contains_struct[KEYWORD_DECL][TS_DECL_WITH_VIS] = 1; + + tree_contains_struct[CLASS_METHOD_DECL][TS_DECL_WRTL] = 1; + tree_contains_struct[INSTANCE_METHOD_DECL][TS_DECL_WRTL] = 1; + tree_contains_struct[KEYWORD_DECL][TS_DECL_WRTL] = 1; + + tree_contains_struct[CLASS_METHOD_DECL][TS_DECL_MINIMAL] = 1; + tree_contains_struct[INSTANCE_METHOD_DECL][TS_DECL_MINIMAL] = 1; + tree_contains_struct[KEYWORD_DECL][TS_DECL_MINIMAL] = 1; + + tree_contains_struct[CLASS_METHOD_DECL][TS_DECL_COMMON] = 1; + tree_contains_struct[INSTANCE_METHOD_DECL][TS_DECL_COMMON] = 1; + tree_contains_struct[KEYWORD_DECL][TS_DECL_COMMON] = 1; +} + +void +finish_file (void) +{ + objc_finish_file (); +} + +#include "gtype-objc.h" diff --git a/contrib/gcc-4.1/gcc/objc/objc-tree.def b/contrib/gcc-4.1/gcc/objc/objc-tree.def new file mode 100644 index 0000000000..bf847aa0a9 --- /dev/null +++ b/contrib/gcc-4.1/gcc/objc/objc-tree.def @@ -0,0 +1,47 @@ +/* This file contains the definitions and documentation for the + additional tree codes used in the Objective C front end (see tree.def + for the standard codes). + Copyright (C) 1990, 1997, 1998, 1999, 2000, 2001, 2003, 2004 + Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + + +/* Objective-C types. */ +DEFTREECODE (CLASS_INTERFACE_TYPE, "class_interface_type", tcc_type, 0) +DEFTREECODE (CLASS_IMPLEMENTATION_TYPE, "class_implementation_type", + tcc_type, 0) +DEFTREECODE (CATEGORY_INTERFACE_TYPE, "category_interface_type", tcc_type, 0) +DEFTREECODE (CATEGORY_IMPLEMENTATION_TYPE,"category_implementation_type", + tcc_type, 0) +DEFTREECODE (PROTOCOL_INTERFACE_TYPE, "protocol_interface_type", tcc_type, 0) + +/* Objective-C decls. */ +DEFTREECODE (KEYWORD_DECL, "keyword_decl", tcc_declaration, 0) +DEFTREECODE (INSTANCE_METHOD_DECL, "instance_method_decl", tcc_declaration, 0) +DEFTREECODE (CLASS_METHOD_DECL, "class_method_decl", tcc_declaration, 0) + +/* Objective-C expressions. */ +DEFTREECODE (MESSAGE_SEND_EXPR, "message_send_expr", tcc_expression, 3) +DEFTREECODE (CLASS_REFERENCE_EXPR, "class_reference_expr", tcc_expression, 1) + +/* +Local variables: +mode:c +End: +*/ diff --git a/contrib/gcc-4.1/libobjc/ChangeLog b/contrib/gcc-4.1/libobjc/ChangeLog new file mode 100644 index 0000000000..3a0be5c355 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/ChangeLog @@ -0,0 +1,1195 @@ +2007-02-13 Release Manager + + * GCC 4.1.2 released. + +2006-05-24 Release Manager + + * GCC 4.1.1 released. + +2006-02-28 Release Manager + + * GCC 4.1.0 released. + +2006-02-21 Rainer Orth + + PR libobjc/26309 + * thr-objc.c (_XOPEN_SOURCE): Don't define on Tru64 UNIX. + +2005-12-15 David Ayers + + PR libobjc/14382 + * README (+load,+initialize): Fix documentation to reflect + intended and implemented semantics for +load and +initialize. + +2005-11-09 Alexandre Oliva + + PR other/4372 + * thr-objc.c (_XOPEN_SOURCE): Define. + +2005-10-07 Ulrich Weigand + + PR libobjc/23612 + * objc/objc-api.h (struct objc_ivar): Move definition to + global scope. + +2005-09-04 Andrew Pinski + Rasmus Hahn + + PR libobjc/23108 + * archive.c (objc_write_type): Correct the element offset. + (objc_read_type): Likewise. + +2005-08-17 Kelley Cook + + * All files: Update FSF address. + +2005-08-13 Marcin Koziej + Andrew Pinski + + PR libobjc/22492 + * exception.c (PERSONALITY_FUNCTION): Fix the PC with finally. + +2005-08-13 Andrew Pinski + + * Makefile.in (extra_ldflags_libobjc): New. + (libobjc$(libext).la): Add extra_ldflags_libobjc to the link line. + (libobjc_gc$(libext).la): Likewise. + * configure.ac (extra_ldflags_libgfortran): Set for *-darwin* to + "-Wl,-single_module". + * configure: Regenerate. + * linking.m (_objcInit): Remove. + +2005-07-26 Andrew Pinski + + PR libobjc/22606 + * Makefile.in (ALL_CFLAGS): Add -fexceptions. + +2005-06-08 David Ayers + + * objc/NXConstStr.h, objc/Object.h, objc/Protocol.h, + objc/encoding.h, objc/hash.h, objc/objc-api.h, + objc/runtime.h, objc/sarray.h, objc/thr.h, + objc/typedstream.h: Do not include Objective-C headers as + system headers. + +2005-06-07 David Ayers + + * archive.c, init.c, selector.c: Include hash.h. + * archive.c, class.c, encoding.c, gc.c, hash.c, hash_compat.c, + init.c, misc.c, nil_method.c, objects.c, sarray.c, selector.c, + sendmsg.c, thr-dce.c, thr-decosf1.c, thr-irix.c, thr-mach.c, + thr-objc.c, thr-os2.c, thr-posix.c, thr-pthreads.c, thr-rtems.c, + thr-single.c, thr-solaris.c, thr-vxworks.c, thr-win32.c, thr.c: + Include Objective-C headers with quotes and objc/ directory + prefix. + +2005-05-19 Richard Henderson + + * exception.c: Revert last change. + +2005-05-19 David Ayers + + * exception.c: Include tsystem.h for unwind.h. + +2005-05-09 Mike Stump + + * configure: Regenerate. + +2005-04-12 Mike Stump + + * configure: Regenerate. + +2005-03-21 Zack Weinberg + + * Makefile.in: Set gcc_version here. + * configure.ac: Do not invoke TL_AC_GCC_VERSION. Adjust quoting + in definition of toolexeclibdir so that $(gcc_version) is expanded + by the Makefile. + * aclocal.m4, configure: Regenerate. + +2005-03-03 David Ayers + + * objc/hash.h (OBJC_IGNORE_DEPRECATED_API): Update deprecated + version reference. Correct typo. + +2005-03-02 David Ayers + + PR libobjc/19024 + * Makefile.in (OBJS): Add hash_compat.lo. + (OBJS_GC): Add hash_compat_gc.lo. + (hash_compat_gc.lo): New target and rule. + * objc/hash.h (hash_new, hash_delete, hash_add, hash_remove) + (hash_next, hash_value_for_key, hash_is_key_in_hash) + (hash_ptr, hash_string, compare_ptrs, compare_strings): Prefix + with objc_. Add deprecated non prefixed inlined versions. + (OBJC_IGNORE_DEPRECATED_API): New macro to hide deprecated + declarations. + * hash.c (hash_new, hash_delete, hash_add, hash_remove, hash_next) + (hash_value_for_key, hash_is_key_in_hash): Prefix with objc_ and + update callers. + * hash_compat.c: New file. + * archive.c: Update callers. + * init.c: Likewise. + * selector.c: Likewise. + * libobjc.def: Add objc_ versions of hash functions. + +2005-02-28 Andrew Pinski + + PR libobjc/20252 + * Makefile.in (GTHREAD_FLAGS): Remove. + (ALL_CFLAGS): Remove usage of GTHREAD_FLAGS. + * thr-objc.c: Include config.h. + * configure.ac: Instead of looking at GCC's makefile, figure out if + GTHREAD_FLAGS should be defined by looking at the `thread model' + of the current gcc. + * configure: Regenerate. + * config.h.in: Regenerate. + +2005-02-28 Paolo Bonzini + + PR bootstrap/17383 + * configure.ac: Call GCC_TOPLEV_SUBDIRS. + (Determine CFLAGS for gthread): Use $host_subdir. + * configure: Regenerate. + * Makefile.in (host_subdir): New. + (INCLUDES): Use it. + +2004-12-20 Andrew Pinski + + PR libobjc/12035 + * gc.c: Remove definition of LOGWL, modWORDSZ, and divWORDSZ since + they are not used. + Include limits.h and stdlib.h. + Define BITS_PER_WORD. + +2004-12-12 Alexander Malmberg + + * selector.c (__objc_init_selector_tables): Add missing void to + definition. + +2004-12-02 Richard Sandiford + + * configure.ac: Use TL_AC_GCC_VERSION to set gcc_version. + * configure, aclocal.m4: Regenerate. + +2004-11-29 Kelley Cook + + * configure: Regenerate for libtool change. + +2004-11-25 Kelley Cook + + * configure: Regenerate for libtool reversion. + +2004-11-24 Kelley Cook + + * configure: Regenerate for libtool change. + +2004-11-24 Kelley Cook + + * aclocal.m4, config.h.in: Regenerate. + +2004-10-08 Mike Stump + Andrew Pinski + + * aclocal.m4: Rename to ... + * acinclude.m4: here and also use m4_include instead of sinclude. + * aclocal.m4: Regenerate. + * configure: Regenerate. + * configure.ac: Add AM_MAINTAINER_MODE and AM_PROG_CC_C_O. + * Makefile.in (configure): Add @MAINT@ infront of configure.ac + +2004-10-08 Andrew Pinski + + * archive.c: Fix all the warnings about passing unsigned char* + to char* and the other way too. + +2004-09-16 Andrew Pinski + + PR libobjc/16448 + * exception.c: Include config.h + (objc_exception_throw): Change _GLIBCXX_SJLJ_EXCEPTIONS to + SJLJ_EXCEPTIONS. + * configure.ac: Find out what exception handling code we use. + * configure: Regenerate. + * config.h.in: New file, regenerate. + +2004-09-16 Andrew Pinski + + * encoding.c (ALTIVEC_VECTOR_MODE): Define a bogus macro. + +2004-08-28 Nathanael Nerode + + * configure.ac: Switch from _GCC_TOPLEV_NONCANONICAL_TARGET to + ACX_NONCANONICAL_TARGET. + * configure: Regenerate. + +2004-08-13 Ziemowit Laski + + * objc/sarray.h: Hoist include of assert.h near the top of file, + and mark the remainder of the file 'extern "C"'. + +2004-08-13 Andrew Pinski + + * objc/Object.h: Move includes out of extern "C" blocks. + * objc/encoding.h: Likewise. + * objc/hash.h: Likewise. + * objc/objc-api.h: Likewise. + * objc/runtime.h: Likewise. + * objc/sarray.h: Likewise. + * objc/typedstream.h: Likewise. + +2004-08-12 Ziemowit Laski + + * objc/NXConstStr.h: Update copyright date; bracket with + 'extern "C"' for C++ use; make include syntax consistent + by using <...> instead of "..."; hoist includes + above the 'extern "C"' block. + * objc/Object.h: Likewise. + * objc/Protocol.h: Likewise. + * objc/encoding.h: Likewise. + * objc/hash.h: Likewise. + * objc/runtime.h: Likewise. + * objc/sarray.h: Likewise. + * objc/thr.h: Likewise. + * objc/typedstream.h: Likewise. + * objc/objc-api.h: Add 'extern "C"' block for C++ use. + (objc_static_instances): For C++ case, do away with + zero-sized array. + (objc_method): Hoist definition to file scope. + (_objc_load_callback, _objc_object_alloc, class_get_class_method, + class_get_instance_method, class_create_instance, + class_get_class_name, class_get_instance_size, + class_get_meta_class, class_get_super_class, class_get_version, + class_is_class, class_is_meta_class, class_set_version, + class_get_gc_object_type, class_ivar_set_gcinvisible, + get_imp): Rename 'class' parameter to '_class'. + * objc/objc-list.h: Add 'extern "C"' block for C++ use. + * objc/objc.h: Update copyright date. + (arglist_t): Provide a union tag. + +2004-07-22 Andrew Pinski + + * thr.c (__objc_thread_detach_function): Do not mark as volatile + but instead use the attribute noreturn. + +2004-06-28 Zack Weinberg + + * encoding.c: Rename target_flags with a #define to avoid + conflict with a prior declaration. + +2004-06-24 Andrew Pinski + + * objc/encoding.h: Wrap the functions with extern "C" for C++ + mode. + * objc/hash.h: Likewise. + * objc/objc-api.h: Likewise. + * objc/objc-list.h: Likewise. + * objc/runtime.h: Likewise. + * objc/sarray.h: Likewise. + * objc/thr.h: Likewise. + * objc/typedstream.h: Likewise. + + +2004-06-21 Nick Clifton + + * encoding.c (BITS_PER_UNIT): Define if a definition is not + provided. + +2004-06-20 Alexander Malmberg + + * Makefile.in (exception.lo): Remove $(OBJC_GCFLAGS). + (exception_gc.lo): New. + (OBJS_GC): Add exception_gc.lo. + +2004-06-17 Richard Henderson + + * exception.c: New file. + * Makefile.in (exception.lo): New. + (OBJS): Add it. + +2004-06-14 Andrew Pinski + + * linking.m (_objcInit): New empty function + for Darwin only. + +2004-06-11 Andrew Pinski + + * configure.ac: Support --enable-shared=libobjc. + * configure: Regenerate. + + PR libobjc/15901 + * configure.ac: Do not disable shared by default. + * configure: Regenerate. + +2004-06-03 Nicola Pero + + * Protocol.m ([-isEqual:]): Small optimizations returning + immediately if the argument is equal to self, and accessing + the argument's name directly if it's a protocol. + +2004-06-03 David Ayers + + * Protocol.m ([-isEqual:]): Test the class of the argument. + +2004-05-25 Andrew Pinski + + * configure.ac (includedir): Rename to ... + (includedirname). + * Makefile.in: s/includedir/includedirname/. + + PR target/11572 + * configure.ac (includedir): Set to "include" + except for Darwin. + (libext) Set to empty except for Darwin. + * configure: Regenerate + * Makefile.in: s/libobjc.la/libobjc$(libext).la/g. + s/include/$(includedir)/g. + +2004-05-25 Daniel Jacobowitz + + * Makefile.in: Add .NOEXPORT. + +2004-05-25 Andrew Pinski + + Merge from the libobjc-branch + 2004-02-09 Andrew Pinski + + * Makefile.in (OBJC_H): Change objc-deps.h to objc-decls.h. + + 2004-02-03 Andrew Pinski + + * Makefile.in (OBJC_H): Add objc-deps.h. + + 2004-01-27 Nicola Pero + + * Protocol.m ([-conformsTo:]): If the argument is nil, return NO. + ([-hash], [-isEqual:]): New methods. + + 2004-01-27 Richard Frith-Macdonald + + * sarray.c (sarray_free): Add a better comment. + + 2004-01-27 Adam Fedor + + * hash.c (hash_add): Cast cachep to int. + * selector.c (__sel_register_typed_name): Cast + soffset_decode to int. + + 2004-01-27 Alexander Malmberg + + * selector.c: Rename register_selectors_from_list to + __objc_register_selectors_from_list. Update caller. + (__objc_register_selectors_from_list): Lock __objc_runtime_mutex + while registering selectors. Use __sel_register_typed_name instead + of sel_register_typed_name. Check for NULL method_name:s. + (pool_alloc_selector): New function. + (__sel_register_typed_name): Use pool_alloc_selector to allocate + selector structures. + * sendmsg.c (class_add_method_list): Use + __objc_register_selectors_from_list. + * objc/runtime.h: Add __objc_register_selectors_from_list. + + 2004-01-25 Adam Fedor + Nicola Pero + Andrew Pinski + + * objc/objc-decls.h: New file. + * objc/objc-api.h (_objc_lookup_class): Mark as export. + (_objc_load_callback): Likewise. + (_objc_object_alloc): Likewise. + (_objc_object_copy): Likewise. + (_objc_object_dispose): Likewise. + + 2004-01-25 Andrew Pinski + + * archive.c: s/__inline__/inline + * sendmsg.c: Likewise. + + * encoding.c: Remove FIXME about the warning + about unused variable. + * sendmsg.c: Add a FIXME comment saying that + this should be using libffi. + + * Makefile.in (LIBTOOL): Use @LIBTOOL@ now as it works. + + +2004-05-13 Andrew Pinski + + * archive.c (objc_read_class): Initialize class_name. + (objc_read_selector): Initialize selector_name. + +2004-05-09 Richard Sandiford + + * Makefile.in (toolexecdir): Remove trailing space. + +2004-04-15 Nathanael Nerode + + PR libobjc/14948 + * configure.ac: De-precious CC so multilibs work. + * configure: Regenerate. + +2004-04-14 Nathanael Nerode + + * configure.ac: Restore toolexecdir. + * Makefile.in: Restore toolexecdir. + * configure: Regenerate. + +2004-04-09 Nathanael Nerode + + * configure.ac: Remove (unused) glibcpp_prefixdir. + * configure: Regenerate. + + * configure.in: Rename to configure.ac. + * Makefile.in: Update to match. + + * Makefile.in: Remove toolexecdir, glibcpp_toolexecdir (unused). + Replace glibcpp_toolexeclibdir with toolexeclibdir. + * configure.in: Remove glibcpp_toolexecdir (unused). + Replace glibcpp_toolexeclibdir with toolexeclibdir. Don't generate + config.h or stamp-h (unused). Move one comment to the right place. + * configure: Regenerate. + * config.h.in: Remove (unused). + + * config.h.in: Regenerate with autoheader. + + * Makefile.in: Remove (unused) gcc_version_trigger. + * configure.in: Remove (unused) glibcpp_builddir. Don't AC_SUBST + gcc_version_trigger. + * configure: Regenerate. + + * configure.in: Switch to modern style for AC_INIT, AC_OUTPUT. + Sort file into sections. Remove dnl where appropriate. Fix + other style issues. + * configure: Regenerate. + + * configure.in: Replace old AC_PROG_CC hack with new one. + Define toplevel_srcdir in terms of srcdir, not top_srcdir (there + are no subdirectory output files, so this is fine). Change prereq + to autoconf 2.59. + * aclocal.m4: Include ../config/no-executables.m4. + * configure: Regenerate with autoconf 2.59. + + * configure.in: Improve comments on gthread_cflags. Improve m4 + quotation, and replace 'if test' with 'case', for --enable-objc-gc. + * configure: Regenerate. + + * configure.in: Move PACKAGE and VERSION settings up top. Remove + unused call to AC_PROG_LN_S. Default RANLIB to ':'. Remove + redundant checks for values of RANLIB, AR, INSTALL. + * configure: Regenerate. + + * configure.in: Clean up handling of + --enable-version-specific-runtime-libs and related variables; + replace 'if test' with 'case' where reasonable. Fix comments. + Remove useless libstdcxx_interface. + * configure: Regenerate. + + * configure.in: Use _GCC_TOPLEV_NONCANONICAL_TARGET. + Replace uses of target_alias with target_noncanonical. + * aclocal.m4: Include ../config/acx.m4. + * configure: Regenerate. + * Makefile.in: Replace uses of target_alias with target_noncanonical. + Fix copyright statement. + + * configure.in: Hand-inline bulky, confusing macros from + aclocal.m4. Replace references to "GNU Objective C" with "GCC". + Update copyright notice. Remove stuff for automake, which isn't + used in this directory. Remove emacs local variables. + * aclocal.m4: Remove hand-inlined macros. Update copyright notice. + * configure: Regenerate. + +2004-03-16 Manfred Hollstein + + * Makefile.in, configure.in, configure: Update copyright years. + +2004-03-15 Manfred Hollstein + + * Makefile.in (LIBOBJC_VERSION, LIBOBJC_GC_VERSION): Use + definition from configure.in. + * configure.in (PACKAGE): Add definition. + (VERSION): Add definition; substitute it in output files. + * configure: Re-generate. + +2004-03-05 Ziemowit Laski + + * objc/hash.h (hash_string, compare_strings): + Add type-casts to make Objective-C++ happy. + * objc/typedstream.h (objc_get_stream_class_version): + Rename parameter from 'class' to 'class_name' to make + Objective-C++ happy. + +2004-03-01 Michael Matz + + * Makefile.in (ALL_CFLAGS): Add -fno-strict-aliasing. + +2004-02-06 Ziemowit Laski + + * objc/objc-api.h (objc_super): The 'class' field shall + be named 'super_class' #ifdef __cplusplus. + +2004-01-17 Andrew Pinski + + PR target/10781 + * encoding.c (rs6000_special_round_type_align): Define. + +2004-01-14 Adam Fedor + + PR libobjc/12155 + * selector.c (__objc_register_instance_methods_to_class): Free + new_list if not used. + +2004-01-09 Andrew Ruder + + PR libobjc/11904 + * sarray.c (sarray_free): Free array->is_copy_of latter. + +2003-12-01 Zack Weinberg + + PR 11433 + * Protocol.m (descriptionForInstanceMethod): Don't dereference + instance_methods if it's NULL. + (descriptionForClassMethod): Likewise for class_methods. + +2003-10-24 Rainer Orth + + * Makefile.in (runtime-info.h): Remove -Wp. + +2003-10-21 Rainer Orth + + * Makefile.in (CC1OBJ): Remove. + (runtime-info.h): Invoke $(CC) so all MULTIFLAGS are handled + correctly. + Use .m extension for temporary file. + Remove assembler temp file. + +2003-10-20 Joseph S. Myers + + * objc/hash.h (hash_string): Don't use a cast as an lvalue. + +2003-10-17 Rainer Orth + + * Makefile.in (runtime-info.h): Use MULTIFLAGS. + +2003-09-09 Alan Modra + + * configure: Regenerate. + +2003-08-27 Alexander Malmberg + + * Makefile.in, aclocal.m4: Update to $(libdir)/gcc/ instead of + (libdir)/gcc-lib/ when installing. + * configure: Regenerate. + +Thu Jul 10 10:27:43 2003 Nicola Pero + + libobjc/9969 + * sendmsg.c (get_imp): Fixed rare threading problem. + (__objc_responds_to): Similar fixes. + (objc_msg_lookup): Similar fixes. + (__objc_init_install_dtable): Lock the runtime before checking if the + table is installed. + +2003-05-23 Nathanael Nerode + + * hash.c, init.c, libobjc.def, libobjc_entry.c, linking.m, + makefile.dos, misc.c, nil_method.c, objects.c, sarray.c, + selector.c, sendmsg.c, thr-dce.c, thr-decosf1.c, thr-irix.c, + thr-mach.c, thr-objc.c, thr-os2.c, thr-posix.c, thr-pthreads.c, + thr-rtems.c, thr-single.c, thr-solaris.c, thr-vxworks.c, + thr-win32.c, thr.c: Replace "GNU CC" with "GCC". + * Makefile.in, NXConstStr.m, Object.m, Protocol.m, archive.c, + class.c, encoding.c, gc.c, objc/NXConstStr.h, objc/Object.h, + objc/Protocol.h, objc/encoding.h, objc/hash.h, objc/objc-api.h, + objc/objc-list.h, objc/objc.h, ocjc/runtime.h, objc/sarray.h, + objc/thr.h, objc/typedstream.h: Replace "GNU CC" with "GCC". + +Tue May 13 14:56:03 2003 Richard Frith-Macdonald + Nicola Pero + + libobjc/10742 + * init.c (class_superclass_of_class): New function. + (create_tree_of_subclasses_inherited_from): Use it. + (__objc_tree_insert_class): Likewise. + (class_is_subclass_of_class): Likewise. + +2003-04-11 David Chad + Loren J. Rittle + + libobjc/8562 + * objc/hash.h (hash_string): Constify correctly. + (compare_ptrs): Use direct compare. + * objc/objc-list.h (list_nth): Rename index to indx to avoid shadow. + * objc/sarray.h: Global rename index to indx to avoid shadow. + +2003-03-12 Andreas Schwab + + * aclocal.m4 (GLIBCPP_EXPORT_INSTALL_INFO): Avoid trailing /. in + glibcpp_toolexeclibdir. + * configure: Rebuilt. + +2003-02-20 Alexandre Oliva + + * configure.in: Propagate ORIGINAL_LD_FOR_MULTILIBS to + config.status. + * configure: Rebuilt. + +2003-01-27 Alexandre Oliva + + * aclocal.m4 (glibcpp_toolexeclibdir): Instead of + $(MULTISUBDIR), use `$CC -print-multi-os-directory`, unless + version_specific_libs is enabled. + * configure: Rebuilt. + +2003-01-09 Christian Cornelssen + + * Makefile.in (FLAGS_TO_PASS): Also pass DESTDIR. + (install-libs, install-headers): Prepend $(DESTDIR) to + destination paths in all (un)installation commands. + +2002-12-02 Zack Weinberg + + * thr-objc.c: Include coretypes.h and tm.h. + +2002-12-01 Zack Weinberg + + * encoding.c, sendmsg.c: Include coretypes.h and tm.h. + +2002-11-26 Nathanael Nerode + + * configure.in: Remove skip-this-dir support. + * configure: Regenerate. + +2002-09-22 Kaveh R. Ghazi + + * Makefile.in (all): Fix multilib parallel build. + +Thu Sep 12 12:44:37 2002 Nicola Pero + + * sendmsg.c (nil_method): Declare not to take a variable number of + args. + (objc_msg_lookup): Cast nil_method to IMP before returning it. + (objc_msg_lookup_super): The same. + +2002-09-10 Jan Hubicka + + * nil_method.c (nil_method): No longer defined with variable + arguments. + +2002-07-02 Rodney Brown + + * objc/encoding.h: Fix formatting. + * objc/hash.h: Likewise. + * objc/objc-api.h: Likewise. + * objc/runtime.h: Likewise. + * objc/thr.h: Likewise. + * archive.c: Likewise. + * class.c: Likewise. + * encoding.c: Likewise. + * gc.c: Likewise. + * hash.c: Likewise. + * init.c: Likewise. + * misc.c: Likewise. + * nil_method.c: Likewise. + * objects.c: Likewise. + * sarray.c: Likewise. + * selector.c: Likewise. + * sendmsg.c: Likewise. + * thr-mach.c: Likewise. + * thr.c: Likewise. + +2002-06-25 DJ Delorie + + * aclocal.m4 (GLIBCPP_CONFIGURE): Split out + GLIBCPP_TOPREL_CONFIGURE. + * configure.in: Call it before AC_CANONICAL_SYSTEM. + * configure: Regenerate. + +2002-06-21 Kaveh R. Ghazi + + * Object.m (forward, read, write): Fix unused parameter warnings. + * encoding.c: Include . + (target_flags): Mark with attribute unused. + (atoi): Delete. + * runtime.h (__objc_selector_max_index): Change to unsigned int. + (__objc_generate_gc_type_description): Prototype. + * selector.c (__objc_selector_max_index): Change to unsigned int. + +Mon Jun 17 18:37:42 2002 Nicola Pero + + * sendmsg.c (__objc_get_forward_imp): Fix warning by making sure + we always have a return value: if __objc_msg_forward does not + supply a forwarding implementation, return the default + __builtin_apply based one. + +2002-06-15 Kaveh R. Ghazi + + * Object.m: Fix signed/unsigned warning. + * Protocol.m: Likewise. + * archive.c: Always include stdlib.h. + (objc_read_short, objc_read_unsigned_short, objc_read_int, + objc_read_long, __objc_read_nbyte_uint, __objc_read_nbyte_ulong): + Fix signed/unsigned warning. + (objc_write_type, objc_read_type, objc_write_types, + objc_read_types): Ensure ctype 8-bit safety. + (__objc_no_write, __objc_no_read): Mark unused parameters. + * class.c (class_table_setup): Specify void arg. + * encoding.c (atoi, objc_sizeof_type, objc_alignof_type, + objc_skip_typespec, objc_skip_offset, + objc_layout_structure_next_member): Ensure ctype 8-bit safety. + (objc_layout_structure_next_member): Ensure variables are + initialized. + * gc.c (__objc_generate_gc_type_description, + class_ivar_set_gcinvisible): Mark unused parameters. + * init.c (__objc_send_load, __objc_destroy_class_tree_node): Mark + unused parameters. + (__objc_init_protocols) Fix signed/unsigned warning. + * nil_method.c (nil_method): Mark unused parameters. + * thr.h (objc_thread_callback): Specify void arg. + * sarray.c (sarray_new, sarray_realloc, sarray_free): Fix + signed/unsigned warning. + (sarray_free): Fix formatting. + * selector.c (sel_types_match): Ensure ctype 8-bit safety. + * sendmsg.c (__objc_init_install_dtable) Mark unused parameters. + +2002-06-09 Andreas Jaeger + + * encoding.c (objc_layout_structure_next_member): Remove unused + variable. + +2002-05-20 Kaveh R. Ghazi + + * Makefile.in (SHELL): Set to @SHELL@. + (WARN_CFLAGS): New. + (ALL_CFLAGS): Add $(WARN_CFLAGS). + +2002-05-16 Rainer Orth + + * aclocal.m4: Allow for PWDCMD to override hardcoded pwd. + * configure: Regenerate. + +2002-05-08 Alexandre Oliva + + * configure.in (ORIGINAL_LD_FOR_MULTILIBS): Preserve LD at + script entry, and set LD to it when configuring multilibs. + * configure: Rebuilt. + +2002-04-19 David O'Brien + + * encoding.c (MAX, MIN, ROUNDING): #undef before defining. + +2002-04-09 Hans-Peter Nilsson + + PR objc/6107 + * objc/objc-api.h (struct objc_protocol_list): Change type of + member count from int to size_t. + +2002-02-11 Franz Sirl + + PR libobjc/4039 + * aclocal.m4: Replace with version copied from libstdc++-v3. + * configure.in: Update for changes to aclocal and Makefile. + * configure: Regenerate. + * Makefile.in: Correct install of multilibs and shared libs, use + INSTALL_DATA for include files. + +Mon Dec 17 17:02:12 2001 Nicola Pero + + * init.c (__objc_exec_class): Fixed bug in the loop on unclaimed + categories - when an unclaimed category was found, the loop was + doing two steps forward instead of one, so that in certain cases + it was failing to properly load all the categories. (Reported + with fix by Alexander Malmberg ). + +2001-11-14 Aldy Hernandez + + * encoding.c: Add target_flags. + +2001-11-07 Aldy Hernandez + + * objc/objc-api.h (_C_VECTOR): New. + + * encoding.c (VECTOR_TYPE): New. + +Mon Oct 29 21:29:21 2001 Nicola Pero + + * class.c: Rewritten the class table to use optimized, lock-free + lookup. This more than doubles the speed of class method + invocations. (class_table_setup), (class_table_insert), + (class_table_replace), (class_table_get_safe), + (class_table_next), (class_table_print), + (class_table_print_histogram): New functions. + (__objc_init_class_tables): Use class_table_setup. + (__objc_add_class_to_hash): Use class_table_get_safe and + class_table_insert. (objc_lookup_class), (objc_get_class): Do not + assert the existence of the table; do not lock the runtime; use + class_table_get_safe. (objc_next_class): Use class_table_next. + (__objc_resolve_class_links): Use class_table_next. + (class_pose_as): Use class_table_replace. + +2001-09-10 Ovidiu Predescu + + * gc.c: Removed the DEBUG declaration. + +Wed Jul 18 12:48:56 2001 Nicola Pero + + * thr.c (objc_mutex_lock): Invoke __objc_thread_id directly, + rather than through objc_thread_id, to save a function call. + (objc_mutex_trylock, objc_mutex_unlock, objc_condition_wait): + Ditto. + +Mon Jul 16 12:15:00 2001 Nicola Pero + + * objc/objc-api.h (object_is_class): Fixed - buggy code was trying + to cast an id to a Class, which can not be done. Make the check + by using CLS_ISMETA on the class pointer instead. + (object_is_meta_class): Similar fix. + +2001-06-09 Alexandre Oliva , Stephen L Moshier + + * configure.in (AC_EXEEXT): Work around in case it expands to + nothing, as in autoconf 2.50. + * acinclude.m4: Likewise. + * configure: Rebuilt. + +2001-06-08 Nicola Pero + + * THREADS: Explain that when we compile libobjc inside GCC, we + always use thr-objc.c as a backend, which uses GCC's thread code. + +2001-06-06 Richard Frith-Macdonald + + * init.c (__objc_send_message_in_list): When setting a new entry + in __objc_load_methods use the method IMP as key, but check to see + if the method is in the hashtable by looking at the IMP also. + Also ... call the method after adding it to the hashtable rather + than before ... thus preventing an obscure possibility of infinite + recursion if a +load method itself loads a subclass. + +2001-05-25 Ovidiu Predescu + + * init.c (__objc_send_message_in_list): When setting a new entry + in __objc_load_methods use the method name as key, not the method + IMP (reported by Richard Frith-Macdonald ). + +2001-05-09 Joseph S. Myers + + * objc-features.texi: Move to ../gcc/objc.texi. + * fdl.texi: Remove. + * Makefile.in: Don't generate documentation from + objc-features.texi. + +2001-05-01 Mark Mitchell + + * fdl.texi: New file. + * objc-features.texi: Simplify. + * Makefile.in: Adjust accordingly. + +2001-04-30 Mark Mitchell + + * objc-features.texi: Use the GFDL. + +Wed Mar 21 04:44:58 EST 2001 John Wehle (john@feith.com) + + * encoding.c (REAL_TYPE): Define. + +2001-03-19 David Edelsohn + + * encoding.c (TYPE_MODE): Define. + +2001-03-14 Nicola Pero + + * thr.c (objc_thread_add): New function. + (objc_thread_remove): Ditto. + * objc/thr.h: Declare them. + * libobjc.def: Mention them. + +2001-02-28 Ovidiu Predescu + + * objc-features.texi: Document the @compatibility_alias compiler + directive (description from Nicola Pero ). + +Fri Feb 23 18:12:00 2001 Rainer Orth + + * sendmsg.c (__objc_forward): Delete strlen() declaration. + +2001-02-08 Geoffrey Keating + + * configure.in: Don't run AC_PROG_CC_WORKS or AC_EXEEXT, because + we're not interested in the result and they might fail. + * configure: Regenerated. + +2001-01-12 Joseph S. Myers + + * objc-features.texi: Use @email. + +2001-01-12 Joseph S. Myers + + * sendmsg.c (__objc_print_dtable_stats): Don't use #ifdef inside + printf. + +2000-01-11 Richard Earnshaw + + * encoding.c (STRUCTURE_SIZE_BOUNDARY): Redefine in a way that + determines the value dynamically. + +Wed Jan 3 00:49:10 2001 Ovidiu Predescu + + * sendmsg.c: Added __objc_msg_forward, a hook that allows external + libraries to provide a function that returns the real forwarding + function. This can alleviate problems __builtin_apply() and + friends have on various platforms. (Solution suggested by Helge + Hess.) + + * objc/objc-api.h: Define __objc_msg_forward. + + * sendmsg.c: Define gen_rtx_REG. + +2000-12-06 Ralf Corsepius + + * thr-rtems.c: New file. Stub to compile. + +2000-09-06 Alexandre Oliva + + * configure: Rebuilt with new libtool.m4. + +Tue Aug 15 00:38:56 2000 Ovidiu Predescu + + * configure.in: Create a config.h file. Check for . + * configure: Regenerate. + + * config.h.in: Check for . + +2000-08-14 Zack Weinberg + + * configure: Regenerate after change to ../libtool.m4. + +2000-08-14 Andreas Schwab + + * objc-features.texi (Top): Move @menu at end of node. + +2000-08-11 Manfred Hollstein + + * objc-features.texi: Move @node Top before @menu. + +Sun Aug 6 23:27:49 2000 Ovidiu Predescu + + * objc-features.texi: Documented the new -fconstant-string-class + option. + +Sun Aug 6 22:51:16 2000 Ovidiu Predescu + + * thr-posix.c: Integrated Chris Ball's changes to + improve the Posix thread support for Objective-C. + +2000-08-04 Zack Weinberg + + * aclocal.m4: Replace copy of ../libtool.m4 with + sinclude(../libtool.m4). + +Fri Jul 28 08:58:02 2000 Nicola Pero + + * configure.in: Added libtool support; build shared libraries + if --enable-shared was passed on command line. + * Makefile.in: Modified most compilation commands to use libtool. + * aclocal.m4: New symbolic link to the ../libtool.m4, from the + libtool distribution. + +Sat Jul 29 00:10:21 2000 Ovidiu Predescu + + * sarray.c, Object.m: Removed the explicit prototypes for strlen + and memcpy on 64-bit platforms (Suggested by Rodney Brown + ). + +2000-05-12 H.J. Lu (hjl@gnu.org) + + * Makefile.in (GTHREAD_FLAGS): New. + (ALL_CFLAGS): Add $(GTHREAD_FLAGS). + (OBJC_THREAD_FILE): Changed to thr-objc. + + * configure.in (GTHREAD_FLAGS): New, check and replace it for + Makefile. + (OBJC_THREAD_FILE): Removed. + + * thr-objc.c: New. + +2000-07-13 Kaveh R. Ghazi + + * objc/hash.h: Include string.h. + +2000-04-15 David Edelsohn + + * Object.m (strlen): 64-bit PowerPC is a 64bit platform as well. + +2000-04-12 Jakub Jelinek + + * Object.m (strlen): Provide prototype on all 64bit platforms, + not only alpha. + * sarray.c (memcpy): Likewise. + * encoding.c (objc_layout_finish_structure): Don't use + ROUND_TYPE_ALIGN on sparc. + + * encoding.c (objc_layout_structure_next_member): Do the whole + procedure even for the first member, so that we get correct + alignment. + +2000-03-29 Zack Weinberg + + * objc/Protocol.h, objc/objc-list.h: Change #endif labels to + comments. + +2000-02-23 Zack Weinberg + + * Makefile.in: Add -DIN_TARGET_LIBS to ALL_CFLAGS. + +Thu Sep 23 07:19:12 1999 Chris Ball + + * thr-posix.c (__objc_mutex_deallocate): made deallocate work. + +Tue Sep 21 07:47:10 1999 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (gc.o, gc_gc.o): Do not pass -fgnu-runtime to + the compiler when building C code. + +Fri Aug 6 23:32:29 1999 Daniel Jacobowitz + + * Makefile.in (FLAGS_TO_PASS): Include prefix, exec_prefix, + libdir, libsubdir and tooldir. + +Mon Jun 21 05:40:15 1999 John David Anglin + + * init.c (__objc_force_linking): Make global. + +Thu May 20 03:20:59 1999 Jeffrey A Law (law@cygnus.com) + + * configure.in (AC_EXEEXT): Remove call. + (compiler_name): Explicitly check with no extension and .exe + extension. + * configure: Regenerate. + +Sun Apr 25 01:15:34 1999 Mumit Khan + + * Makefile.in (CC1OBJ): Define in terms of CC. + (runtime-info.h): Use. + +Fri April 8 08:21:07 1999 Ovidiu Predescu + + * objc-features.texi: Updated the URL to Boehm's GC page. + +Fri Mar 26 23:41:07 1999 Ovidiu Predescu + + * archive.c (__objc_code_char, __objc_write_char): Explicitly specify + the char as being signed (patch from Daniel Jacobowitz + ). + +Wed Mar 24 22:41:28 1999 Mumit Khan + + * configure.in (AC_PREREQ): Update to 2.13. + (AC_EXEEXT): Call to find possible file extension. + (compiler_name): Use. + * configure: Regenerate. + +Wed Jan 27 02:31:01 1999 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (ALL_CFLAGS): Add -DIN_GCC. + +Tue Jan 5 01:38:53 1999 Jeffrey A Law (law@cygnus.com) + + * configure.in (thread_file): Correct and simplify code to find + the thread file. + * configure: Rebuilt. + +1998-11-26 Manfred Hollstein + + * configure.in (compiler_name): Add check to detect if this + language's compiler has been built. + * configure: Regenerate. + +Mon Nov 23 16:50:28 1998 Kaveh R. Ghazi + + * configure.in: Use AC_PREREQ(2.12.1). + +Thu Nov 19 20:33:37 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in (runtime-info.h): Avoid GNU make extensions. + +Sun Nov 8 17:46:14 1998 Kaveh R. Ghazi + + * Makefile.in (INCLUDES): Add -I$(srcdir)/$(MULTISRCTOP)../include. + +Thu Oct 22 14:34:06 1998 Kaveh R. Ghazi + + * configure.in: Use AC_CONFIG_AUX_DIR($topsrcdir). + +Sat Oct 17 05:21:31 1998 Ovidiu Predescu + + * objc-features.texi (Top): Changed the email address. + * objc-features.texi (Garbage Collection): Use @uref instead of @url. + +Mon Oct 11 21:25:27 1998 Ovidiu Predescu + + * encoding.c: Redefine get_inner_array_type to get the first entry + in the structure. + +Thu Oct 8 12:21:14 1998 Richard Frith-Macdonald + + * encoding.c (objc_skip_type_qualifiers): Handle _C_BYREF. + (objc_get_type_qualifiers): Similarly. + * objc/encoding.h (_C_BYREF): Define. + (_F_BYREF): Define. + +1998-10-07 David S. Miller + + * objc/sarray.h: Make boffset be an unsigned long when sparc so it + works out on 64-bit systems. + +Tue Oct 6 20:32:06 1998 Alexandre Oliva + + * Makefile.in (INCLUDES): Make it multilib-friendly. + +Fri Oct 2 07:12:14 1998 H.J. Lu (hjl@gnu.org) + + * Makefile.in (INCLUDES): Add -I$(srcdir)/../gcc. + +Thu Oct 1 22:33:03 1998 Robert Lipe + Jeffrey A Law (law@cygnus.com) + + * Makefile.in (INCLUDES): Reference gcc via $MULTIBUILDTOP. + (FLAGS_TO_PASS): Added. + (runtime-info.h): Reference cc1ibj via $MULTIBUILDTOP. + + * archive.c: Change config.h to tconfig.h. + + * configure.in: Find gcc's object directory even for multilibs. + +Wed Sep 30 18:17:17 1998 Robert Lipe + + * configure.in: Escape ^ in grep string. + * configure: Rebuilt. + +Wed Sep 30 09:14:52 1998 Jeffrey A Law (law@cygnus.com) + + * All .h files pushed down into the objc/ subdirectory. + * Makefile.in (copy_headers): Corresponding changes. + * configure.in (AC_INIT): Corresponding changes. + * configure: Rebuilt. + +1998-09-30 Ben Elliston + Jeff Law + + * Makefile.in: Rewrite. + + * configure.in: Likewise. + + * configure: Regenerate. + + * All .c files. Remove "objc" prefix when including objc header + files. Include tconfig.h, not ../tconfig.h. + +Mon Sep 21 23:27:10 1998 Ovidiu Predescu + + * encoding.c (TREE_TYPE, ARRAY_TYPE): Define. + (get_inner_array_type): Define. + +1998-09-21 Ben Elliston + + * New directory. Moved files from ../gcc/objc. diff --git a/contrib/gcc-4.1/libobjc/NXConstStr.m b/contrib/gcc-4.1/libobjc/NXConstStr.m new file mode 100644 index 0000000000..9afe30ae58 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/NXConstStr.m @@ -0,0 +1,42 @@ +/* Implementation of the NXConstantString class for Objective-C. + Copyright (C) 1995 Free Software Foundation, Inc. + Contributed by Pieter J. Schoenmakers + +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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#include "objc/NXConstStr.h" + +@implementation NXConstantString + +-(const char *) cString +{ + return (c_string); +} /* -cString */ + +-(unsigned int) length +{ + return (len); +} /* -length */ + +@end diff --git a/contrib/gcc-4.1/libobjc/Object.m b/contrib/gcc-4.1/libobjc/Object.m new file mode 100644 index 0000000000..3d7d2084b3 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/Object.m @@ -0,0 +1,386 @@ +/* The implementation of class Object for Objective-C. + Copyright (C) 1993, 1994, 1995, 1997, 2002 Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. */ + +#include +#include "objc/Object.h" +#include "objc/Protocol.h" +#include "objc/objc-api.h" + +extern int errno; + +#define MAX_CLASS_NAME_LEN 256 + +@implementation Object + ++ initialize +{ + return self; +} + +- init +{ + return self; +} + ++ new +{ + return [[self alloc] init]; +} + ++ alloc +{ + return class_create_instance(self); +} + +- free +{ + return object_dispose(self); +} + +- copy +{ + return [[self shallowCopy] deepen]; +} + +- shallowCopy +{ + return object_copy(self); +} + +- deepen +{ + return self; +} + +- deepCopy +{ + return [self copy]; +} + +- (Class)class +{ + return object_get_class(self); +} + +- (Class)superClass +{ + return object_get_super_class(self); +} + +- (MetaClass)metaClass +{ + return object_get_meta_class(self); +} + +- (const char *)name +{ + return object_get_class_name(self); +} + +- self +{ + return self; +} + +- (unsigned int)hash +{ + return (size_t)self; +} + +- (BOOL)isEqual:anObject +{ + return self==anObject; +} + +- (int)compare:anotherObject; +{ + if ([self isEqual:anotherObject]) + return 0; + // Ordering objects by their address is pretty useless, + // so subclasses should override this is some useful way. + else if (self > anotherObject) + return 1; + else + return -1; +} + +- (BOOL)isMetaClass +{ + return NO; +} + +- (BOOL)isClass +{ + return object_is_class(self); +} + +- (BOOL)isInstance +{ + return object_is_instance(self); +} + +- (BOOL)isKindOf:(Class)aClassObject +{ + Class class; + + for (class = self->isa; class!=Nil; class = class_get_super_class(class)) + if (class==aClassObject) + return YES; + return NO; +} + +- (BOOL)isMemberOf:(Class)aClassObject +{ + return self->isa==aClassObject; +} + +- (BOOL)isKindOfClassNamed:(const char *)aClassName +{ + Class class; + + if (aClassName!=NULL) + for (class = self->isa; class!=Nil; class = class_get_super_class(class)) + if (!strcmp(class_get_class_name(class), aClassName)) + return YES; + return NO; +} + +- (BOOL)isMemberOfClassNamed:(const char *)aClassName +{ + return ((aClassName!=NULL) + &&!strcmp(class_get_class_name(self->isa), aClassName)); +} + ++ (BOOL)instancesRespondTo:(SEL)aSel +{ + return class_get_instance_method(self, aSel)!=METHOD_NULL; +} + +- (BOOL)respondsTo:(SEL)aSel +{ + return ((object_is_instance(self) + ?class_get_instance_method(self->isa, aSel) + :class_get_class_method(self->isa, aSel))!=METHOD_NULL); +} + ++ (IMP)instanceMethodFor:(SEL)aSel +{ + return method_get_imp(class_get_instance_method(self, aSel)); +} + +// Indicates if the receiving class or instance conforms to the given protocol +// not usually overridden by subclasses +// +// Modified 9/5/94 to always search the class object's protocol list, rather +// than the meta class. + ++ (BOOL) conformsTo: (Protocol*)aProtocol +{ + size_t i; + struct objc_protocol_list* proto_list; + id parent; + + for (proto_list = ((Class)self)->protocols; + proto_list; proto_list = proto_list->next) + { + for (i=0; i < proto_list->count; i++) + { + if ([proto_list->list[i] conformsTo: aProtocol]) + return YES; + } + } + + if ((parent = [self superClass])) + return [parent conformsTo: aProtocol]; + else + return NO; +} + +- (BOOL) conformsTo: (Protocol*)aProtocol +{ + return [[self class] conformsTo:aProtocol]; +} + +- (IMP)methodFor:(SEL)aSel +{ + return (method_get_imp(object_is_instance(self) + ?class_get_instance_method(self->isa, aSel) + :class_get_class_method(self->isa, aSel))); +} + ++ (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel +{ + return ((struct objc_method_description *) + class_get_instance_method(self, aSel)); +} + +- (struct objc_method_description *)descriptionForMethod:(SEL)aSel +{ + return ((struct objc_method_description *) + (object_is_instance(self) + ?class_get_instance_method(self->isa, aSel) + :class_get_class_method(self->isa, aSel))); +} + +- perform:(SEL)aSel +{ + IMP msg = objc_msg_lookup(self, aSel); + if (!msg) + return [self error:"invalid selector passed to %s", sel_get_name(_cmd)]; + return (*msg)(self, aSel); +} + +- perform:(SEL)aSel with:anObject +{ + IMP msg = objc_msg_lookup(self, aSel); + if (!msg) + return [self error:"invalid selector passed to %s", sel_get_name(_cmd)]; + return (*msg)(self, aSel, anObject); +} + +- perform:(SEL)aSel with:anObject1 with:anObject2 +{ + IMP msg = objc_msg_lookup(self, aSel); + if (!msg) + return [self error:"invalid selector passed to %s", sel_get_name(_cmd)]; + return (*msg)(self, aSel, anObject1, anObject2); +} + +- (retval_t)forward:(SEL)aSel :(arglist_t)argFrame +{ + (void) argFrame; /* UNUSED */ + return (retval_t)[self doesNotRecognize: aSel]; +} + +- (retval_t)performv:(SEL)aSel :(arglist_t)argFrame +{ + return objc_msg_sendv(self, aSel, argFrame); +} + ++ poseAs:(Class)aClassObject +{ + return class_pose_as(self, aClassObject); +} + +- (Class)transmuteClassTo:(Class)aClassObject +{ + if (object_is_instance(self)) + if (class_is_class(aClassObject)) + if (class_get_instance_size(aClassObject)==class_get_instance_size(isa)) + if ([self isKindOf:aClassObject]) + { + Class old_isa = isa; + isa = aClassObject; + return old_isa; + } + return nil; +} + +- subclassResponsibility:(SEL)aSel +{ + return [self error:"subclass should override %s", sel_get_name(aSel)]; +} + +- notImplemented:(SEL)aSel +{ + return [self error:"method %s not implemented", sel_get_name(aSel)]; +} + +- shouldNotImplement:(SEL)aSel +{ + return [self error:"%s should not implement %s", + object_get_class_name(self), sel_get_name(aSel)]; +} + +- doesNotRecognize:(SEL)aSel +{ + return [self error:"%s does not recognize %s", + object_get_class_name(self), sel_get_name(aSel)]; +} + +- error:(const char *)aString, ... +{ +#define FMT "error: %s (%s)\n%s\n" + char fmt[(strlen((char*)FMT)+strlen((char*)object_get_class_name(self)) + +((aString!=NULL)?strlen((char*)aString):0)+8)]; + va_list ap; + + sprintf(fmt, FMT, object_get_class_name(self), + object_is_instance(self)?"instance":"class", + (aString!=NULL)?aString:""); + va_start(ap, aString); + objc_verror(self, OBJC_ERR_UNKNOWN, fmt, ap); + va_end(ap); + return nil; +#undef FMT +} + ++ (int)version +{ + return class_get_version(self); +} + ++ setVersion:(int)aVersion +{ + class_set_version(self, aVersion); + return self; +} + ++ (int)streamVersion: (TypedStream*)aStream +{ + if (aStream->mode == OBJC_READONLY) + return objc_get_stream_class_version (aStream, self); + else + return class_get_version (self); +} + +// These are used to write or read the instance variables +// declared in this particular part of the object. Subclasses +// should extend these, by calling [super read/write: aStream] +// before doing their own archiving. These methods are private, in +// the sense that they should only be called from subclasses. + +- read: (TypedStream*)aStream +{ + (void) aStream; /* UNUSED */ + // [super read: aStream]; + return self; +} + +- write: (TypedStream*)aStream +{ + (void) aStream; /* UNUSED */ + // [super write: aStream]; + return self; +} + +- awake +{ + // [super awake]; + return self; +} + +@end diff --git a/contrib/gcc-4.1/libobjc/Protocol.m b/contrib/gcc-4.1/libobjc/Protocol.m new file mode 100644 index 0000000000..645e99114c --- /dev/null +++ b/contrib/gcc-4.1/libobjc/Protocol.m @@ -0,0 +1,182 @@ +/* This file contains the implementation of class Protocol. + Copyright (C) 1993, 2004 Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#include "objc/Protocol.h" +#include "objc/objc-api.h" + +/* Method description list */ +struct objc_method_description_list { + int count; + struct objc_method_description list[1]; +}; + + +@implementation Protocol +{ +@private + char *protocol_name; + struct objc_protocol_list *protocol_list; + struct objc_method_description_list *instance_methods, *class_methods; +} + +/* Obtaining attributes intrinsic to the protocol */ + +- (const char *)name +{ + return protocol_name; +} + +/* Testing protocol conformance */ + +- (BOOL) conformsTo: (Protocol *)aProtocolObject +{ + size_t i; + struct objc_protocol_list* proto_list; + + if (aProtocolObject == nil) + return NO; + + if (!strcmp(aProtocolObject->protocol_name, self->protocol_name)) + return YES; + + for (proto_list = protocol_list; proto_list; proto_list = proto_list->next) + { + for (i=0; i < proto_list->count; i++) + { + if ([proto_list->list[i] conformsTo: aProtocolObject]) + return YES; + } + } + + return NO; +} + +/* Looking up information specific to a protocol */ + +- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel +{ + int i; + struct objc_protocol_list* proto_list; + const char* name = sel_get_name (aSel); + struct objc_method_description *result; + + if (instance_methods) + for (i = 0; i < instance_methods->count; i++) + { + if (!strcmp ((char*)instance_methods->list[i].name, name)) + return &(instance_methods->list[i]); + } + + for (proto_list = protocol_list; proto_list; proto_list = proto_list->next) + { + size_t j; + for (j=0; j < proto_list->count; j++) + { + if ((result = [proto_list->list[j] + descriptionForInstanceMethod: aSel])) + return result; + } + } + + return NULL; +} + +- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel; +{ + int i; + struct objc_protocol_list* proto_list; + const char* name = sel_get_name (aSel); + struct objc_method_description *result; + + if (class_methods) + for (i = 0; i < class_methods->count; i++) + { + if (!strcmp ((char*)class_methods->list[i].name, name)) + return &(class_methods->list[i]); + } + + for (proto_list = protocol_list; proto_list; proto_list = proto_list->next) + { + size_t j; + for (j=0; j < proto_list->count; j++) + { + if ((result = [proto_list->list[j] + descriptionForClassMethod: aSel])) + return result; + } + } + + return NULL; +} + +- (unsigned) hash +{ + /* Compute a hash of the protocol_name; use the same hash algorithm + * that we use for class names; protocol names and class names are + * somewhat similar types of string spaces. + */ + int hash = 0, index; + + for (index = 0; protocol_name[index] != '\0'; index++) + { + hash = (hash << 4) ^ (hash >> 28) ^ protocol_name[index]; + } + + hash = (hash ^ (hash >> 10) ^ (hash >> 20)); + + return hash; +} + +/* + * Equality between formal protocols is only formal (nothing to do + * with actually checking the list of methods they have!). Two formal + * Protocols are equal if and only if they have the same name. + * + * Please note (for comparisons with other implementations) that + * checking the names is equivalent to checking that Protocol A + * conforms to Protocol B and Protocol B conforms to Protocol A, + * because this happens iff they have the same name. If they have + * different names, A conforms to B if and only if A includes B, but + * the situation where A includes B and B includes A is a circular + * dependency between Protocols which is forbidden by the compiler, so + * A conforms to B and B conforms to A with A and B having different + * names is an impossible case. + */ +- (BOOL) isEqual: (id)obj +{ + if (obj == self) + return YES; + + if ([obj isKindOf: [Protocol class]]) + { + if (strcmp (protocol_name, ((Protocol *)obj)->protocol_name) == 0) + return YES; + } + + return NO; +} +@end + diff --git a/contrib/gcc-4.1/libobjc/README b/contrib/gcc-4.1/libobjc/README new file mode 100644 index 0000000000..093116fd59 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/README @@ -0,0 +1,104 @@ + +GNU Objective C notes +********************* + +This document is to explain what has been done, and a little about how +specific features differ from other implementations. The runtime has +been completely rewritten in gcc 2.4. The earlier runtime had several +severe bugs and was rather incomplete. The compiler has had several +new features added as well. + +This is not documentation for Objective C, it is usable to someone +who knows Objective C from somewhere else. + + +Runtime API functions +===================== + +The runtime is modeled after the NeXT Objective C runtime. That is, +most functions have semantics as it is known from the NeXT. The +names, however, have changed. All runtime API functions have names +of lowercase letters and underscores as opposed to the +`traditional' mixed case names. + The runtime api functions are not documented as of now. +Someone offered to write it, and did it, but we were not allowed to +use it by his university (Very sad story). We have started writing +the documentation over again. This will be announced in appropriate +places when it becomes available. + + +Protocols +========= + +Protocols are now fully supported. The semantics is exactly as on the +NeXT. There is a flag to specify how protocols should be typechecked +when adopted to classes. The normal typechecker requires that all +methods in a given protocol must be implemented in the class that +adopts it -- it is not enough to inherit them. The flag +`-Wno-protocol' causes it to allow inherited methods, while +`-Wprotocols' is the default which requires them defined. + + ++load +=========== +This method, if defined, is called for each class and category +implementation when the class is loaded into the runtime. This method +is not inherited, and is thus not called for a subclass that doesn't +define it itself. Thus, each +load method is called exactly once by +the runtime. The runtime invocation of this method is thread safe. + + ++initialize +=========== + +This method, if defined, is called before any other instance or class +methods of that particular class. For the GNU runtime, this method is +not inherited, and is thus not called as initializer for a subclass that +doesn't define it itself. Thus, each +initialize method is called exactly +once by the runtime (or never if no methods of that particular class is +never called). It is wise to guard against multiple invocations anyway +to remain portable with the NeXT runtime. The runtime invocation of +this method is thread safe. + + +Passivation/Activation/Typedstreams +=================================== + +This is supported in the style of NeXT TypedStream's. Consult the +headerfile Typedstreams.h for api functions. I (Kresten) have +rewritten it in Objective C, but this implementation is not part of +2.4, it is available from the GNU Objective C prerelease archive. + There is one difference worth noting concerning objects stored with +objc_write_object_reference (aka NXWriteObjectReference). When these +are read back in, their object is not guaranteed to be available until +the `-awake' method is called in the object that requests that object. +To objc_read_object you must pass a pointer to an id, which is valid +after exit from the function calling it (like e.g. an instance +variable). In general, you should not use objects read in until the +-awake method is called. + + +Acknowledgements +================ + +The GNU Objective C team: Geoffrey Knauth (manager), +Tom Wood (compiler) and Kresten Krab Thorup + (runtime) would like to thank a some people for +participating in the development of the present GNU Objective C. + +Paul Burchard and Andrew McCallum + has been very helpful debugging the +runtime. Eric Herring has been very helpful +cleaning up after the documentation-copyright disaster and is now +helping with the new documentation. + +Steve Naroff and Richard Stallman + has been very helpful with implementation details +in the compiler. + + +Bug Reports +=========== + +Please read the section `Submitting Bugreports' of the gcc manual +before you submit any bugs. diff --git a/contrib/gcc-4.1/libobjc/README.threads b/contrib/gcc-4.1/libobjc/README.threads new file mode 100644 index 0000000000..5f15bd9cb4 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/README.threads @@ -0,0 +1,50 @@ +============================================================================== +README.threads - Wed Nov 29 15:16:24 EST 1995 +------------------------------------------------------------------------------ + +Limited documentation is available in the THREADS file. + +This version has been tested on Sun Solaris, SGI Irix, and Windows NT. +It should also work on any single threaded system. + +Thanks go to the following people for help test and debug the library: + + Scott Christley, scottc@ocbi.com + Andrew McCallum, mccallum@cs.rochester.edu + +galen +gchunt@cs.rochester.edu + +Any questions, bug reports, etc should be directed to: + +Scott Christley, scottc@ocbi.com + +Please do not bug Galen with email as he no longer supports the code. + +============================================================================== +Changes from prior releases (in revered chronological order): +------------------------------------------------------------------------------ + +* Fixed bug in copy part of sarray_realloc. I had an < which should + have been <=. (Bug report from Scott). + +------------------------------------------------------------------------------ + +* Support for DEC OSF/1 is definitely broken. My programs always + seg-fault when I link with libpthreads.a. + +* Thread id's are no longer int's, but are instead of type + _objc_thread_t which is typedef'ed from a void *. An invalid thread + id is denoted by NULL and not -1 as before. + +------------------------------------------------------------------------------ + +* Renamed thread-winnt.c to thread-win32.c to better reflect support + for the API on both Windows NT and Windows 95 platforms. + (Who knows, maybe even Win32s :-). + +* Fixed bugs in Win32 support as per report from Scott Christley. + +* Fixed bug in sarray_get as per report from Scott Christley. + + diff --git a/contrib/gcc-4.1/libobjc/THREADS b/contrib/gcc-4.1/libobjc/THREADS new file mode 100644 index 0000000000..8a436832f6 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/THREADS @@ -0,0 +1,377 @@ +This file describes in little detail the modifications to the +Objective-C runtime needed to make it thread safe. + +First off, kudos to Galen Hunt who is the author of this great work. + +If you have an comments or just want to know where to +send me money to express your undying gratitude for threading the +Objective-C runtime you can reach Galen at: + + gchunt@cs.rochester.edu + +Any questions, comments, bug reports, etc. should send email either to the +GCC bug account or to: + + Scott Christley + +* Sarray Threading: + +The most critical component of the Objective-C runtime is the sparse array +structure (sarray). Sarrays store object selectors and implementations. +Following in the tradition of the Objective-C runtime, my threading +support assumes that fast message dispatching is far more important +than *ANY* and *ALL* other operations. The message dispatching thus +uses *NO* locks on any kind. In fact, if you look in sarray.h, you +will notice that the message dispatching has not been modified. +Instead, I have modified the sarray management functions so that all +updates to the sarray data structure can be made in parallel will +message dispatching. + +To support concurrent message dispatching, no dynamically allocated +sarray data structures are freed while more than one thread is +operational. Sarray data structures that are no longer in use are +kept in a linked list of garbage and are released whenever the program +is operating with a single thread. The programmer can also flush the +garbage list by calling sarray_remove_garbage when the programmer can +ensure that no message dispatching is taking place concurrently. The +amount of un-reclaimed sarray garbage should normally be extremely +small in a real program as sarray structures are freed only when using +the "poseAs" functionality and early in program initialization, which +normally occurs while the program is single threaded. + +****************************************************************************** +* Static Variables: + +The following variables are either statically or globally defined. This list +does not include variables which are internal to implementation dependent +versions of thread-*.c. + +The following threading designations are used: + SAFE : Implicitly thread safe. + SINGLE : Must only be used in single thread mode. + MUTEX : Protected by single global mutex objc_runtime_mutex. + UNUSED : Not used in the runtime. + +Variable Name: Usage: Defined: Also used in: +=========================== ====== ============ ===================== +__objc_class_hash MUTEX class.c +__objc_class_links_resolved UNUSED class.c runtime.h +__objc_class_number MUTEX class.c +__objc_dangling_categories UNUSED init.c +__objc_module_list MUTEX init.c +__objc_selector_array MUTEX selector.c +__objc_selector_hash MUTEX selector.c +__objc_selector_max_index MUTEX selector.c sendmsg.c runtime.h +__objc_selector_names MUTEX selector.c +__objc_thread_exit_status SAFE thread.c +__objc_uninstalled_dtable MUTEX sendmsg.c selector.c +_objc_load_callback SAFE init.c objc-api.h +_objc_lookup_class SAFE class.c objc-api.h +_objc_object_alloc SINGLE objects.c objc-api.h +_objc_object_copy SINGLE objects.c objc-api.h +_objc_object_dispose SINGLE objects.c objc-api.h +frwd_sel SAFE2 sendmsg.c +idxsize MUTEX sarray.c sendmsg.c sarray.h +initialize_sel SAFE2 sendmsg.c +narrays MUTEX sarray.c sendmsg.c sarray.h +nbuckets MUTEX sarray.c sendmsg.c sarray.h +nindices MUTEX sarray.c sarray.h +previous_constructors SAFE1 init.c +proto_class SAFE1 init.c +unclaimed_categories MUTEX init.c +unclaimed_proto_list MUTEX init.c +uninitialized_statics MUTEX init.c + +Notes: +1) Initialized once in unithread mode. +2) Initialized value will always be same, guaranteed by lock on selector + hash table. + + +****************************************************************************** +* Frontend/Backend design: + +The design of the Objective-C runtime thread and mutex functions utilizes a +frontend/backend implementation. + +The frontend, as characterized by the files thr.h and thr.c, is a set +of platform independent structures and functions which represent the +user interface. Objective-C programs should use these structures and +functions for their thread and mutex work if they wish to maintain a +high degree of portability across platforms. + +The backend is composed of a file with the necessary code to map the ObjC +thread and mutex to a platform specific implementation. For example, the +file thr-solaris.c contains the implementation for Solaris. + +If you are compiling libobjc as part of GCC, the thr-objc.c backend is +always used; this backend uses GCC's gthread code. The thread system +is automatically configured when GCC is configured. Important: make +sure you configure GCC using `--enable-threads' if you want threads ! + +If you want to compile libobjc standalone, then you would need to +modify the configure.in and makefiles for it; and you need to pick an +appropriate backend file for the target platform; you make this choice +by assigning the OBJC_THREAD_FILE make variable to the basename of the +backend file. For example, OBJC_THREAD_FILE=thr-posix would indicate +that the generic posix backend file, thr-posix.c, should be compiled +with the ObjC runtime library. If your platform does not support +threads then you should specify the OBJC_THREAD_FILE=thr-single +backend file to compile the ObjC runtime library without thread or +mutex support; note that programs which rely upon the ObjC thread and +mutex functions will compile and link correctly but attempting to +create a thread or mutex will result in an error. + +It is questionable whether it is really necessary to have both a +frontend and backend function for all available functionality. On the +one hand, it provides a clear, consistent differentiation between what +is public and what is private with the downside of having the overhead +of multiple functions calls. For example, the function to have a +thread yield the processor is objc_thread_yield; in the current +implementation this produces a function call set: + +objc_thread_yield() -> __objc_thread_yield() -> system yield function + +This has two extra function calls over calling the platform specific function +explicitly, but the issue is whether only the overhead of a single function +is necessary. + +objc_thread_yield() -> system yield function + +This breaks the public/private dichotomy between the frontend/backend +for the sake of efficiency. It is possible to just use a preprocessor +define so as to eliminate the extra function call: + +#define objc_thread_yield() __objc_thread_yield() + +This has the undesirable effect that if objc_thread_yield is actually +turned into a function based upon future need; then ObjC programs which +access the thread functions would need to be recompiled versus just +being relinked. + +****************************************************************************** +* Threads: + +The thread system attempts to create multiple threads using whatever +operating system or library thread support is available. It does +assume that all system functions are thread safe. Notably this means +that the system implementation of malloc and free must be thread safe. +If a system has multiple processors, the threads are configured for +full parallel processing. + +* Backend initialization functions + +__objc_init_thread_system(void), int + Initialize the thread subsystem. Called once by __objc_exec_class. + Return -1 if error otherwise return 0. + +__objc_close_thread_system(void), int + Closes the thread subsystem, not currently guaranteed to be called. + Return -1 if error otherwise return 0. + +***** +* Frontend thread functions +* User programs should use these functions. + +objc_thread_detach(SEL selector, id object, id argument), objc_thread_t + Creates and detaches a new thread. The new thread starts by + sending the given selector with a single argument to the + given object. + +objc_thread_set_priority(int priority), int + Sets a thread's relative priority within the program. Valid + options are: + + OBJC_THREAD_INTERACTIVE_PRIORITY + OBJC_THREAD_BACKGROUND_PRIORITY + OBJC_THREAD_LOW_PRIORITY + +objc_thread_get_priority(void), int + Query a thread's priority. + +objc_thread_yield(void), void + Yields processor to another thread with equal or higher + priority. It is up to the system scheduler to determine if + the processor is taken or not. + +objc_thread_exit(void), int + Terminates a thread. If this is the last thread executing + then the program will terminate. + +objc_thread_id(void), int + Returns the current thread's id. + +objc_thread_set_data(void *value), int + Set a pointer to the thread's local storage. Local storage is + thread specific. + +objc_thread_get_data(void), void * + Returns the pointer to the thread's local storage. + +***** +* Backend thread functions +* User programs should *NOT* directly call these functions. + +__objc_thread_detach(void (*func)(void *arg), void *arg), objc_thread_t + Spawns a new thread executing func, called by objc_thread_detach. + Return NULL if error otherwise return thread id. + +__objc_thread_set_priority(int priority), int + Set the thread's priority, called by objc_thread_set_priority. + Return -1 if error otherwise return 0. + +__objc_thread_get_priority(void), int + Query a thread's priority, called by objc_thread_get_priority. + Return -1 if error otherwise return the priority. + +__objc_thread_yield(void), void + Yields the processor, called by objc_thread_yield. + +__objc_thread_exit(void), int + Terminates the thread, called by objc_thread_exit. + Return -1 if error otherwise function does not return. + +__objc_thread_id(void), objc_thread_t + Returns the current thread's id, called by objc_thread_id. + Return -1 if error otherwise return thread id. + +__objc_thread_set_data(void *value), int + Set pointer for thread local storage, called by objc_thread_set_data. + Returns -1 if error otherwise return 0. + +__objc_thread_get_data(void), void * + Returns the pointer to the thread's local storage. + Returns NULL if error, called by objc_thread_get_data. + + +****************************************************************************** +* Mutexes: + +Mutexes can be locked recursively. Each locked mutex remembers +its owner (by thread id) and how many times it has been locked. The +last unlock on a mutex removes the system lock and allows other +threads to access the mutex. + +***** +* Frontend mutex functions +* User programs should use these functions. + +objc_mutex_allocate(void), objc_mutex_t + Allocates a new mutex. Mutex is initially unlocked. + Return NULL if error otherwise return mutex pointer. + +objc_mutex_deallocate(objc_mutex_t mutex), int + Free a mutex. Before freeing the mutex, makes sure that no + one else is using it. + Return -1 if error otherwise return 0. + +objc_mutex_lock(objc_mutex_t mutex), int + Locks a mutex. As mentioned earlier, the same thread may call + this routine repeatedly. + Return -1 if error otherwise return 0. + +objc_mutex_trylock(objc_mutex_t mutex), int + Attempts to lock a mutex. If lock on mutex can be acquired + then function operates exactly as objc_mutex_lock. + Return -1 if failed to acquire lock otherwise return 0. + +objc_mutex_unlock(objc_mutex_t mutex), int + Unlocks the mutex by one level. Other threads may not acquire + the mutex until this thread has released all locks on it. + Return -1 if error otherwise return 0. + +***** +* Backend mutex functions +* User programs should *NOT* directly call these functions. + +__objc_mutex_allocate(objc_mutex_t mutex), int + Allocates a new mutex, called by objc_mutex_allocate. + Return -1 if error otherwise return 0. + +__objc_mutex_deallocate(objc_mutex_t mutex), int + Free a mutex, called by objc_mutex_deallocate. + Return -1 if error otherwise return 0. + +__objc_mutex_lock(objc_mutex_t mutex), int + Locks a mutex, called by objc_mutex_lock. + Return -1 if error otherwise return 0. + +__objc_mutex_trylock(objc_mutex_t mutex), int + Attempts to lock a mutex, called by objc_mutex_trylock. + Return -1 if failed to acquire lock or error otherwise return 0. + +__objc_mutex_unlock(objc_mutex_t mutex), int + Unlocks the mutex, called by objc_mutex_unlock. + Return -1 if error otherwise return 0. + +****************************************************************************** +* Condition Mutexes: + +Mutexes can be locked recursively. Each locked mutex remembers +its owner (by thread id) and how many times it has been locked. The +last unlock on a mutex removes the system lock and allows other +threads to access the mutex. + +* +* Frontend condition mutex functions +* User programs should use these functions. +* + +objc_condition_allocate(void), objc_condition_t + Allocate a condition mutex. + Return NULL if error otherwise return condition pointer. + +objc_condition_deallocate(objc_condition_t condition), int + Deallocate a condition. Note that this includes an implicit + condition_broadcast to insure that waiting threads have the + opportunity to wake. It is legal to dealloc a condition only + if no other thread is/will be using it. Does NOT check for + other threads waiting but just wakes them up. + Return -1 if error otherwise return 0. + +objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex), int + Wait on the condition unlocking the mutex until objc_condition_signal() + or objc_condition_broadcast() are called for the same condition. The + given mutex *must* have the depth 1 so that it can be unlocked + here, for someone else can lock it and signal/broadcast the condition. + The mutex is used to lock access to the shared data that make up the + "condition" predicate. + Return -1 if error otherwise return 0. + +objc_condition_broadcast(objc_condition_t condition), int + Wake up all threads waiting on this condition. It is recommended that + the called would lock the same mutex as the threads in + objc_condition_wait before changing the "condition predicate" + and make this call and unlock it right away after this call. + Return -1 if error otherwise return 0. + +objc_condition_signal(objc_condition_t condition), int + Wake up one thread waiting on this condition. + Return -1 if error otherwise return 0. + +* +* Backend condition mutex functions +* User programs should *NOT* directly call these functions. +* + +__objc_condition_allocate(objc_condition_t condition), int + Allocate a condition mutex, called by objc_condition_allocate. + Return -1 if error otherwise return 0. + +__objc_condition_deallocate(objc_condition_t condition), int + Deallocate a condition, called by objc_condition_deallocate. + Return -1 if error otherwise return 0. + +__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex), int + Wait on the condition, called by objc_condition_wait. + Return -1 if error otherwise return 0 when condition is met. + +__objc_condition_broadcast(objc_condition_t condition), int + Wake up all threads waiting on this condition. + Called by objc_condition_broadcast. + Return -1 if error otherwise return 0. + +__objc_condition_signal(objc_condition_t condition), int + Wake up one thread waiting on this condition. + Called by objc_condition_signal. + Return -1 if error otherwise return 0. diff --git a/contrib/gcc-4.1/libobjc/THREADS.MACH b/contrib/gcc-4.1/libobjc/THREADS.MACH new file mode 100644 index 0000000000..55de663786 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/THREADS.MACH @@ -0,0 +1,23 @@ +This readme refers to the file thr-mach.c. + +Under mach, thread priorities are kinda strange-- any given thread has +a MAXIMUM priority and a BASE priority. The BASE priority is the +current priority of the thread and the MAXIMUM is the maximum possible +priority the thread can assume. The developer can lower, but never +raise the maximum priority. + +The gcc concept of thread priorities is that they run at one of three +levels; interactive, background, and low. + +Under mach, this is translated to: + +interactive -- set priority to maximum +background -- set priority to 2/3 of maximum +low -- set priority to 1/3 of maximum + +This means that it is possible for a thread with the priority of +interactive to actually run at a lower priority than another thread +with a background, or even low, priority if the developer has modified +the maximum priority. + + diff --git a/contrib/gcc-4.1/libobjc/archive.c b/contrib/gcc-4.1/libobjc/archive.c new file mode 100644 index 0000000000..992a69600d --- /dev/null +++ b/contrib/gcc-4.1/libobjc/archive.c @@ -0,0 +1,1668 @@ + /* GNU Objective C Runtime archiving + Copyright (C) 1993, 1995, 1996, 1997, 2002, 2004 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +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 2, 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 COPYING. If not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "tconfig.h" +#include "objc/runtime.h" +#include "objc/typedstream.h" +#include "objc/encoding.h" +#include + +extern int fflush (FILE *); + +#define ROUND(V, A) \ + ({ typeof (V) __v = (V); typeof (A) __a = (A); \ + __a * ((__v + __a - 1)/__a); }) + +#define PTR2LONG(P) (((char *) (P))-(char *) 0) +#define LONG2PTR(L) (((char *) 0) + (L)) + +/* Declare some functions... */ + +static int +objc_read_class (struct objc_typed_stream *stream, Class *class); + +int objc_sizeof_type (const char *type); + +static int +objc_write_use_common (struct objc_typed_stream *stream, unsigned long key); + +static int +objc_write_register_common (struct objc_typed_stream *stream, + unsigned long key); + +static int +objc_write_class (struct objc_typed_stream *stream, + struct objc_class *class); + +const char *objc_skip_type (const char *type); + +static void __objc_finish_write_root_object (struct objc_typed_stream *); +static void __objc_finish_read_root_object (struct objc_typed_stream *); + +static inline int +__objc_code_unsigned_char (unsigned char *buf, unsigned char val) +{ + if ((val&_B_VALUE) == val) + { + buf[0] = val|_B_SINT; + return 1; + } + else + { + buf[0] = _B_NINT|0x01; + buf[1] = val; + return 2; + } +} + +int +objc_write_unsigned_char (struct objc_typed_stream *stream, + unsigned char value) +{ + unsigned char buf[sizeof (unsigned char) + 1]; + int len = __objc_code_unsigned_char (buf, value); + return (*stream->write) (stream->physical, (char*)buf, len); +} + +static inline int +__objc_code_char (unsigned char *buf, signed char val) +{ + if (val >= 0) + return __objc_code_unsigned_char (buf, val); + else + { + buf[0] = _B_NINT|_B_SIGN|0x01; + buf[1] = -val; + return 2; + } +} + +int +objc_write_char (struct objc_typed_stream *stream, signed char value) +{ + unsigned char buf[sizeof (char) + 1]; + int len = __objc_code_char (buf, value); + return (*stream->write) (stream->physical, (char*)buf, len); +} + +static inline int +__objc_code_unsigned_short (unsigned char *buf, unsigned short val) +{ + if ((val&_B_VALUE) == val) + { + buf[0] = val|_B_SINT; + return 1; + } + else + { + int c, b; + + buf[0] = _B_NINT; + + for (c = sizeof (short); c != 0; c -= 1) + if (((val >> (8*(c - 1)))%0x100) != 0) + break; + + buf[0] |= c; + + for (b = 1; c != 0; c--, b++) + { + buf[b] = (val >> (8*(c - 1)))%0x100; + } + + return b; + } +} + +int +objc_write_unsigned_short (struct objc_typed_stream *stream, + unsigned short value) +{ + unsigned char buf[sizeof (unsigned short) + 1]; + int len = __objc_code_unsigned_short (buf, value); + return (*stream->write) (stream->physical, (char*)buf, len); +} + +static inline int +__objc_code_short (unsigned char *buf, short val) +{ + int sign = (val < 0); + int size = __objc_code_unsigned_short (buf, sign ? -val : val); + if (sign) + buf[0] |= _B_SIGN; + return size; +} + +int +objc_write_short (struct objc_typed_stream *stream, short value) +{ + unsigned char buf[sizeof (short) + 1]; + int len = __objc_code_short (buf, value); + return (*stream->write) (stream->physical, (char*)buf, len); +} + + +static inline int +__objc_code_unsigned_int (unsigned char *buf, unsigned int val) +{ + if ((val&_B_VALUE) == val) + { + buf[0] = val|_B_SINT; + return 1; + } + else + { + int c, b; + + buf[0] = _B_NINT; + + for (c = sizeof (int); c != 0; c -= 1) + if (((val >> (8*(c - 1)))%0x100) != 0) + break; + + buf[0] |= c; + + for (b = 1; c != 0; c--, b++) + { + buf[b] = (val >> (8*(c-1)))%0x100; + } + + return b; + } +} + +int +objc_write_unsigned_int (struct objc_typed_stream *stream, unsigned int value) +{ + unsigned char buf[sizeof (unsigned int) + 1]; + int len = __objc_code_unsigned_int (buf, value); + return (*stream->write) (stream->physical, (char*)buf, len); +} + +static inline int +__objc_code_int (unsigned char *buf, int val) +{ + int sign = (val < 0); + int size = __objc_code_unsigned_int (buf, sign ? -val : val); + if (sign) + buf[0] |= _B_SIGN; + return size; +} + +int +objc_write_int (struct objc_typed_stream *stream, int value) +{ + unsigned char buf[sizeof (int) + 1]; + int len = __objc_code_int (buf, value); + return (*stream->write) (stream->physical, (char*)buf, len); +} + +static inline int +__objc_code_unsigned_long (unsigned char *buf, unsigned long val) +{ + if ((val&_B_VALUE) == val) + { + buf[0] = val|_B_SINT; + return 1; + } + else + { + int c, b; + + buf[0] = _B_NINT; + + for (c = sizeof (long); c != 0; c -= 1) + if (((val >> (8*(c - 1)))%0x100) != 0) + break; + + buf[0] |= c; + + for (b = 1; c != 0; c--, b++) + { + buf[b] = (val >> (8*(c - 1)))%0x100; + } + + return b; + } +} + +int +objc_write_unsigned_long (struct objc_typed_stream *stream, + unsigned long value) +{ + unsigned char buf[sizeof (unsigned long) + 1]; + int len = __objc_code_unsigned_long (buf, value); + return (*stream->write) (stream->physical, (char*)buf, len); +} + +static inline int +__objc_code_long (unsigned char *buf, long val) +{ + int sign = (val < 0); + int size = __objc_code_unsigned_long (buf, sign ? -val : val); + if (sign) + buf[0] |= _B_SIGN; + return size; +} + +int +objc_write_long (struct objc_typed_stream *stream, long value) +{ + unsigned char buf[sizeof (long) + 1]; + int len = __objc_code_long (buf, value); + return (*stream->write) (stream->physical, (char*)buf, len); +} + + +int +objc_write_string (struct objc_typed_stream *stream, + const unsigned char *string, unsigned int nbytes) +{ + unsigned char buf[sizeof (unsigned int) + 1]; + int len = __objc_code_unsigned_int (buf, nbytes); + + if ((buf[0]&_B_CODE) == _B_SINT) + buf[0] = (buf[0]&_B_VALUE)|_B_SSTR; + + else /* _B_NINT */ + buf[0] = (buf[0]&_B_VALUE)|_B_NSTR; + + if ((*stream->write) (stream->physical, (char*)buf, len) != 0) + return (*stream->write) (stream->physical, (char*)string, nbytes); + else + return 0; +} + +int +objc_write_string_atomic (struct objc_typed_stream *stream, + unsigned char *string, unsigned int nbytes) +{ + unsigned long key; + if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table, string)))) + return objc_write_use_common (stream, key); + else + { + int length; + objc_hash_add (&stream->stream_table, + LONG2PTR(key=PTR2LONG(string)), string); + if ((length = objc_write_register_common (stream, key))) + return objc_write_string (stream, string, nbytes); + return length; + } +} + +static int +objc_write_register_common (struct objc_typed_stream *stream, + unsigned long key) +{ + unsigned char buf[sizeof (unsigned long)+2]; + int len = __objc_code_unsigned_long (buf + 1, key); + if (len == 1) + { + buf[0] = _B_RCOMM|0x01; + buf[1] &= _B_VALUE; + return (*stream->write) (stream->physical, (char*)buf, len + 1); + } + else + { + buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM; + return (*stream->write) (stream->physical, (char*)buf + 1, len); + } +} + +static int +objc_write_use_common (struct objc_typed_stream *stream, unsigned long key) +{ + unsigned char buf[sizeof (unsigned long)+2]; + int len = __objc_code_unsigned_long (buf + 1, key); + if (len == 1) + { + buf[0] = _B_UCOMM|0x01; + buf[1] &= _B_VALUE; + return (*stream->write) (stream->physical, (char*)buf, 2); + } + else + { + buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM; + return (*stream->write) (stream->physical, (char*)buf + 1, len); + } +} + +static inline int +__objc_write_extension (struct objc_typed_stream *stream, unsigned char code) +{ + if (code <= _B_VALUE) + { + unsigned char buf = code|_B_EXT; + return (*stream->write) (stream->physical, (char*)&buf, 1); + } + else + { + objc_error (nil, OBJC_ERR_BAD_OPCODE, + "__objc_write_extension: bad opcode %c\n", code); + return -1; + } +} + +inline int +__objc_write_object (struct objc_typed_stream *stream, id object) +{ + unsigned char buf = '\0'; + SEL write_sel = sel_get_any_uid ("write:"); + if (object) + { + __objc_write_extension (stream, _BX_OBJECT); + objc_write_class (stream, object->class_pointer); + (*objc_msg_lookup (object, write_sel)) (object, write_sel, stream); + return (*stream->write) (stream->physical, (char*)&buf, 1); + } + else + return objc_write_use_common (stream, 0); +} + +int +objc_write_object_reference (struct objc_typed_stream *stream, id object) +{ + unsigned long key; + if ((key = PTR2LONG(objc_hash_value_for_key (stream->object_table, object)))) + return objc_write_use_common (stream, key); + + __objc_write_extension (stream, _BX_OBJREF); + return objc_write_unsigned_long (stream, PTR2LONG (object)); +} + +int +objc_write_root_object (struct objc_typed_stream *stream, id object) +{ + int len = 0; + if (stream->writing_root_p) + objc_error (nil, OBJC_ERR_RECURSE_ROOT, + "objc_write_root_object called recursively"); + else + { + stream->writing_root_p = 1; + __objc_write_extension (stream, _BX_OBJROOT); + if ((len = objc_write_object (stream, object))) + __objc_finish_write_root_object (stream); + stream->writing_root_p = 0; + } + return len; +} + +int +objc_write_object (struct objc_typed_stream *stream, id object) +{ + unsigned long key; + if ((key = PTR2LONG(objc_hash_value_for_key (stream->object_table, object)))) + return objc_write_use_common (stream, key); + + else if (object == nil) + return objc_write_use_common (stream, 0); + + else + { + int length; + objc_hash_add (&stream->object_table, + LONG2PTR(key=PTR2LONG(object)), object); + if ((length = objc_write_register_common (stream, key))) + return __objc_write_object (stream, object); + return length; + } +} + +inline int +__objc_write_class (struct objc_typed_stream *stream, struct objc_class *class) +{ + __objc_write_extension (stream, _BX_CLASS); + objc_write_string_atomic (stream, (unsigned char *) class->name, + strlen ((char *) class->name)); + return objc_write_unsigned_long (stream, class->version); +} + + +static int +objc_write_class (struct objc_typed_stream *stream, + struct objc_class *class) +{ + unsigned long key; + if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table, class)))) + return objc_write_use_common (stream, key); + else + { + int length; + objc_hash_add (&stream->stream_table, + LONG2PTR(key = PTR2LONG(class)), class); + if ((length = objc_write_register_common (stream, key))) + return __objc_write_class (stream, class); + return length; + } +} + + +inline int +__objc_write_selector (struct objc_typed_stream *stream, SEL selector) +{ + const char *sel_name; + __objc_write_extension (stream, _BX_SEL); + /* to handle NULL selectors */ + if ((SEL)0 == selector) + return objc_write_string (stream, (unsigned char*)"", 0); + sel_name = sel_get_name (selector); + return objc_write_string (stream, (unsigned char*)sel_name, strlen ((char*)sel_name)); +} + +int +objc_write_selector (struct objc_typed_stream *stream, SEL selector) +{ + const char *sel_name; + unsigned long key; + + /* to handle NULL selectors */ + if ((SEL)0 == selector) + return __objc_write_selector (stream, selector); + + sel_name = sel_get_name (selector); + if ((key = PTR2LONG(objc_hash_value_for_key (stream->stream_table, + sel_name)))) + return objc_write_use_common (stream, key); + else + { + int length; + objc_hash_add (&stream->stream_table, + LONG2PTR(key = PTR2LONG(sel_name)), (char *) sel_name); + if ((length = objc_write_register_common (stream, key))) + return __objc_write_selector (stream, selector); + return length; + } +} + + + +/* +** Read operations +*/ + +inline int +objc_read_char (struct objc_typed_stream *stream, char *val) +{ + unsigned char buf; + int len; + len = (*stream->read) (stream->physical, (char*)&buf, 1); + if (len != 0) + { + if ((buf & _B_CODE) == _B_SINT) + (*val) = (buf & _B_VALUE); + + else if ((buf & _B_NUMBER) == 1) + { + len = (*stream->read) (stream->physical, val, 1); + if (buf&_B_SIGN) + (*val) = -1 * (*val); + } + + else + objc_error (nil, OBJC_ERR_BAD_DATA, + "expected 8bit signed int, got %dbit int", + (int) (buf&_B_NUMBER)*8); + } + return len; +} + + +inline int +objc_read_unsigned_char (struct objc_typed_stream *stream, unsigned char *val) +{ + unsigned char buf; + int len; + if ((len = (*stream->read) (stream->physical, (char*)&buf, 1))) + { + if ((buf & _B_CODE) == _B_SINT) + (*val) = (buf & _B_VALUE); + + else if ((buf & _B_NUMBER) == 1) + len = (*stream->read) (stream->physical, (char*)val, 1); + + else + objc_error (nil, OBJC_ERR_BAD_DATA, + "expected 8bit unsigned int, got %dbit int", + (int) (buf&_B_NUMBER)*8); + } + return len; +} + +inline int +objc_read_short (struct objc_typed_stream *stream, short *value) +{ + unsigned char buf[sizeof (short) + 1]; + int len; + if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + { + int pos = 1; + int nbytes = buf[0] & _B_NUMBER; + if (nbytes > (int) sizeof (short)) + objc_error (nil, OBJC_ERR_BAD_DATA, + "expected short, got bigger (%dbits)", nbytes*8); + len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes); + (*value) = 0; + while (pos <= nbytes) + (*value) = ((*value)*0x100) + buf[pos++]; + if (buf[0] & _B_SIGN) + (*value) = -(*value); + } + } + return len; +} + +inline int +objc_read_unsigned_short (struct objc_typed_stream *stream, + unsigned short *value) +{ + unsigned char buf[sizeof (unsigned short) + 1]; + int len; + if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + { + int pos = 1; + int nbytes = buf[0] & _B_NUMBER; + if (nbytes > (int) sizeof (short)) + objc_error (nil, OBJC_ERR_BAD_DATA, + "expected short, got int or bigger"); + len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes); + (*value) = 0; + while (pos <= nbytes) + (*value) = ((*value)*0x100) + buf[pos++]; + } + } + return len; +} + + +inline int +objc_read_int (struct objc_typed_stream *stream, int *value) +{ + unsigned char buf[sizeof (int) + 1]; + int len; + if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + { + int pos = 1; + int nbytes = buf[0] & _B_NUMBER; + if (nbytes > (int) sizeof (int)) + objc_error (nil, OBJC_ERR_BAD_DATA, "expected int, got bigger"); + len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes); + (*value) = 0; + while (pos <= nbytes) + (*value) = ((*value)*0x100) + buf[pos++]; + if (buf[0] & _B_SIGN) + (*value) = -(*value); + } + } + return len; +} + +inline int +objc_read_long (struct objc_typed_stream *stream, long *value) +{ + unsigned char buf[sizeof (long) + 1]; + int len; + if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + { + int pos = 1; + int nbytes = buf[0] & _B_NUMBER; + if (nbytes > (int) sizeof (long)) + objc_error (nil, OBJC_ERR_BAD_DATA, "expected long, got bigger"); + len = (*stream->read) (stream->physical, (char*)buf + 1, nbytes); + (*value) = 0; + while (pos <= nbytes) + (*value) = ((*value)*0x100) + buf[pos++]; + if (buf[0] & _B_SIGN) + (*value) = -(*value); + } + } + return len; +} + +inline int +__objc_read_nbyte_uint (struct objc_typed_stream *stream, + unsigned int nbytes, unsigned int *val) +{ + int len; + unsigned int pos = 0; + unsigned char buf[sizeof (unsigned int) + 1]; + + if (nbytes > sizeof (int)) + objc_error (nil, OBJC_ERR_BAD_DATA, "expected int, got bigger"); + + len = (*stream->read) (stream->physical, (char*)buf, nbytes); + (*val) = 0; + while (pos < nbytes) + (*val) = ((*val)*0x100) + buf[pos++]; + return len; +} + + +inline int +objc_read_unsigned_int (struct objc_typed_stream *stream, + unsigned int *value) +{ + unsigned char buf[sizeof (unsigned int) + 1]; + int len; + if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), value); + + } + return len; +} + +int +__objc_read_nbyte_ulong (struct objc_typed_stream *stream, + unsigned int nbytes, unsigned long *val) +{ + int len; + unsigned int pos = 0; + unsigned char buf[sizeof (unsigned long) + 1]; + + if (nbytes > sizeof (long)) + objc_error (nil, OBJC_ERR_BAD_DATA, "expected long, got bigger"); + + len = (*stream->read) (stream->physical, (char*)buf, nbytes); + (*val) = 0; + while (pos < nbytes) + (*val) = ((*val)*0x100) + buf[pos++]; + return len; +} + + +inline int +objc_read_unsigned_long (struct objc_typed_stream *stream, + unsigned long *value) +{ + unsigned char buf[sizeof (unsigned long) + 1]; + int len; + if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), value); + + } + return len; +} + +inline int +objc_read_string (struct objc_typed_stream *stream, + char **string) +{ + unsigned char buf[sizeof (unsigned int) + 1]; + int len; + if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) + { + unsigned long key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ + { + len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); + len = (*stream->read) (stream->physical, (char*)buf, 1); + } + + switch (buf[0]&_B_CODE) { + case _B_SSTR: + { + int length = buf[0]&_B_VALUE; + (*string) = (char*)objc_malloc (length + 1); + if (key) + objc_hash_add (&stream->stream_table, LONG2PTR(key), *string); + len = (*stream->read) (stream->physical, *string, length); + (*string)[length] = '\0'; + } + break; + + case _B_UCOMM: + { + char *tmp; + len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); + tmp = objc_hash_value_for_key (stream->stream_table, LONG2PTR (key)); + *string = objc_malloc (strlen (tmp) + 1); + strcpy (*string, tmp); + } + break; + + case _B_NSTR: + { + unsigned int nbytes = buf[0]&_B_VALUE; + len = __objc_read_nbyte_uint (stream, nbytes, &nbytes); + if (len) { + (*string) = (char*)objc_malloc (nbytes + 1); + if (key) + objc_hash_add (&stream->stream_table, LONG2PTR(key), *string); + len = (*stream->read) (stream->physical, *string, nbytes); + (*string)[nbytes] = '\0'; + } + } + break; + + default: + objc_error (nil, OBJC_ERR_BAD_DATA, + "expected string, got opcode %c\n", (buf[0]&_B_CODE)); + } + } + + return len; +} + + +int +objc_read_object (struct objc_typed_stream *stream, id *object) +{ + unsigned char buf[sizeof (unsigned int)]; + int len; + if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) + { + SEL read_sel = sel_get_any_uid ("read:"); + unsigned long key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register common */ + { + len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); + len = (*stream->read) (stream->physical, (char*)buf, 1); + } + + if (buf[0] == (_B_EXT | _BX_OBJECT)) + { + Class class; + + /* get class */ + len = objc_read_class (stream, &class); + + /* create instance */ + (*object) = class_create_instance (class); + + /* register? */ + if (key) + objc_hash_add (&stream->object_table, LONG2PTR(key), *object); + + /* send -read: */ + if (__objc_responds_to (*object, read_sel)) + (*get_imp (class, read_sel)) (*object, read_sel, stream); + + /* check null-byte */ + len = (*stream->read) (stream->physical, (char*)buf, 1); + if (buf[0] != '\0') + objc_error (nil, OBJC_ERR_BAD_DATA, + "expected null-byte, got opcode %c", buf[0]); + } + + else if ((buf[0]&_B_CODE) == _B_UCOMM) + { + if (key) + objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode..."); + len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); + (*object) = objc_hash_value_for_key (stream->object_table, + LONG2PTR(key)); + } + + else if (buf[0] == (_B_EXT | _BX_OBJREF)) /* a forward reference */ + { + struct objc_list *other; + len = objc_read_unsigned_long (stream, &key); + other + = (struct objc_list *) objc_hash_value_for_key (stream->object_refs, + LONG2PTR(key)); + objc_hash_add (&stream->object_refs, LONG2PTR(key), + (void *)list_cons (object, other)); + } + + else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */ + { + if (key) + objc_error (nil, OBJC_ERR_BAD_KEY, + "cannot register root object..."); + len = objc_read_object (stream, object); + __objc_finish_read_root_object (stream); + } + + else + objc_error (nil, OBJC_ERR_BAD_DATA, + "expected object, got opcode %c", buf[0]); + } + return len; +} + +static int +objc_read_class (struct objc_typed_stream *stream, Class *class) +{ + unsigned char buf[sizeof (unsigned int)]; + int len; + if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) + { + unsigned long key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ + { + len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); + len = (*stream->read) (stream->physical, (char*)buf, 1); + } + + if (buf[0] == (_B_EXT | _BX_CLASS)) + { + char temp[1] = ""; + char *class_name = temp; + unsigned long version; + + /* get class */ + len = objc_read_string (stream, &class_name); + (*class) = objc_get_class (class_name); + objc_free (class_name); + + /* register */ + if (key) + objc_hash_add (&stream->stream_table, LONG2PTR(key), *class); + + objc_read_unsigned_long (stream, &version); + objc_hash_add (&stream->class_table, + (*class)->name, (void *)version); + } + + else if ((buf[0]&_B_CODE) == _B_UCOMM) + { + if (key) + objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode..."); + len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); + *class = objc_hash_value_for_key (stream->stream_table, + LONG2PTR(key)); + if (! *class) + objc_error (nil, OBJC_ERR_BAD_CLASS, + "cannot find class for key %lu", key); + } + + else + objc_error (nil, OBJC_ERR_BAD_DATA, + "expected class, got opcode %c", buf[0]); + } + return len; +} + +int +objc_read_selector (struct objc_typed_stream *stream, SEL* selector) +{ + unsigned char buf[sizeof (unsigned int)]; + int len; + if ((len = (*stream->read) (stream->physical, (char*)buf, 1))) + { + unsigned long key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ + { + len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); + len = (*stream->read) (stream->physical, (char*)buf, 1); + } + + if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */ + { + char temp[1] = ""; + char *selector_name = temp; + + /* get selector */ + len = objc_read_string (stream, &selector_name); + /* To handle NULL selectors */ + if (0 == strlen (selector_name)) + { + (*selector) = (SEL)0; + return 0; + } + else + (*selector) = sel_get_any_uid (selector_name); + objc_free (selector_name); + + /* register */ + if (key) + objc_hash_add (&stream->stream_table, + LONG2PTR(key), (void *) *selector); + } + + else if ((buf[0]&_B_CODE) == _B_UCOMM) + { + if (key) + objc_error (nil, OBJC_ERR_BAD_KEY, "cannot register use upcode..."); + len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), &key); + (*selector) = objc_hash_value_for_key (stream->stream_table, + LONG2PTR(key)); + } + + else + objc_error (nil, OBJC_ERR_BAD_DATA, + "expected selector, got opcode %c", buf[0]); + } + return len; +} + +/* +** USER LEVEL FUNCTIONS +*/ + +/* +** Write one object, encoded in TYPE and pointed to by DATA to the +** typed stream STREAM. +*/ + +int +objc_write_type (TypedStream *stream, const char *type, const void *data) +{ + switch (*type) { + case _C_ID: + return objc_write_object (stream, *(id *) data); + break; + + case _C_CLASS: + return objc_write_class (stream, *(Class *) data); + break; + + case _C_SEL: + return objc_write_selector (stream, *(SEL *) data); + break; + + case _C_CHR: + return objc_write_char (stream, *(signed char *) data); + break; + + case _C_UCHR: + return objc_write_unsigned_char (stream, *(unsigned char *) data); + break; + + case _C_SHT: + return objc_write_short (stream, *(short *) data); + break; + + case _C_USHT: + return objc_write_unsigned_short (stream, *(unsigned short *) data); + break; + + case _C_INT: + return objc_write_int (stream, *(int *) data); + break; + + case _C_UINT: + return objc_write_unsigned_int (stream, *(unsigned int *) data); + break; + + case _C_LNG: + return objc_write_long (stream, *(long *) data); + break; + + case _C_ULNG: + return objc_write_unsigned_long (stream, *(unsigned long *) data); + break; + + case _C_CHARPTR: + return objc_write_string (stream, + *(unsigned char **) data, strlen (*(char **) data)); + break; + + case _C_ATOM: + return objc_write_string_atomic (stream, *(unsigned char **) data, + strlen (*(char **) data)); + break; + + case _C_ARY_B: + { + int len = atoi (type + 1); + while (isdigit ((unsigned char) *++type)) + ; + return objc_write_array (stream, type, len, data); + } + break; + + case _C_STRUCT_B: + { + int acc_size = 0; + int align; + while (*type != _C_STRUCT_E && *type++ != '=') + ; /* skip "=" */ + while (*type != _C_STRUCT_E) + { + align = objc_alignof_type (type); /* padd to alignment */ + acc_size = ROUND (acc_size, align); + objc_write_type (stream, type, ((char *) data) + acc_size); + acc_size += objc_sizeof_type (type); /* add component size */ + type = objc_skip_typespec (type); /* skip component */ + } + return 1; + } + + default: + { + objc_error (nil, OBJC_ERR_BAD_TYPE, + "objc_write_type: cannot parse typespec: %s\n", type); + return 0; + } + } +} + +/* +** Read one object, encoded in TYPE and pointed to by DATA to the +** typed stream STREAM. DATA specifies the address of the types to +** read. Expected type is checked against the type actually present +** on the stream. +*/ + +int +objc_read_type(TypedStream *stream, const char *type, void *data) +{ + char c; + switch (c = *type) { + case _C_ID: + return objc_read_object (stream, (id*)data); + break; + + case _C_CLASS: + return objc_read_class (stream, (Class*)data); + break; + + case _C_SEL: + return objc_read_selector (stream, (SEL*)data); + break; + + case _C_CHR: + return objc_read_char (stream, (char*)data); + break; + + case _C_UCHR: + return objc_read_unsigned_char (stream, (unsigned char*)data); + break; + + case _C_SHT: + return objc_read_short (stream, (short*)data); + break; + + case _C_USHT: + return objc_read_unsigned_short (stream, (unsigned short*)data); + break; + + case _C_INT: + return objc_read_int (stream, (int*)data); + break; + + case _C_UINT: + return objc_read_unsigned_int (stream, (unsigned int*)data); + break; + + case _C_LNG: + return objc_read_long (stream, (long*)data); + break; + + case _C_ULNG: + return objc_read_unsigned_long (stream, (unsigned long*)data); + break; + + case _C_CHARPTR: + case _C_ATOM: + return objc_read_string (stream, (char**)data); + break; + + case _C_ARY_B: + { + int len = atoi (type + 1); + while (isdigit ((unsigned char) *++type)) + ; + return objc_read_array (stream, type, len, data); + } + break; + + case _C_STRUCT_B: + { + int acc_size = 0; + int align; + while (*type != _C_STRUCT_E && *type++ != '=') + ; /* skip "=" */ + while (*type != _C_STRUCT_E) + { + align = objc_alignof_type (type); /* padd to alignment */ + acc_size = ROUND (acc_size, align); + objc_read_type (stream, type, ((char*)data)+acc_size); + acc_size += objc_sizeof_type (type); /* add component size */ + type = objc_skip_typespec (type); /* skip component */ + } + return 1; + } + + default: + { + objc_error (nil, OBJC_ERR_BAD_TYPE, + "objc_read_type: cannot parse typespec: %s\n", type); + return 0; + } + } +} + +/* +** Write the object specified by the template TYPE to STREAM. Last +** arguments specify addresses of values to be written. It might +** seem surprising to specify values by address, but this is extremely +** convenient for copy-paste with objc_read_types calls. A more +** down-to-the-earth cause for this passing of addresses is that values +** of arbitrary size is not well supported in ANSI C for functions with +** variable number of arguments. +*/ + +int +objc_write_types (TypedStream *stream, const char *type, ...) +{ + va_list args; + const char *c; + int res = 0; + + va_start(args, type); + + for (c = type; *c; c = objc_skip_typespec (c)) + { + switch (*c) { + case _C_ID: + res = objc_write_object (stream, *va_arg (args, id*)); + break; + + case _C_CLASS: + res = objc_write_class (stream, *va_arg (args, Class*)); + break; + + case _C_SEL: + res = objc_write_selector (stream, *va_arg (args, SEL*)); + break; + + case _C_CHR: + res = objc_write_char (stream, *va_arg (args, char*)); + break; + + case _C_UCHR: + res = objc_write_unsigned_char (stream, + *va_arg (args, unsigned char*)); + break; + + case _C_SHT: + res = objc_write_short (stream, *va_arg (args, short*)); + break; + + case _C_USHT: + res = objc_write_unsigned_short (stream, + *va_arg (args, unsigned short*)); + break; + + case _C_INT: + res = objc_write_int(stream, *va_arg (args, int*)); + break; + + case _C_UINT: + res = objc_write_unsigned_int(stream, *va_arg (args, unsigned int*)); + break; + + case _C_LNG: + res = objc_write_long(stream, *va_arg (args, long*)); + break; + + case _C_ULNG: + res = objc_write_unsigned_long(stream, *va_arg (args, unsigned long*)); + break; + + case _C_CHARPTR: + { + unsigned char **str = va_arg (args, unsigned char **); + res = objc_write_string (stream, *str, strlen ((char*)*str)); + } + break; + + case _C_ATOM: + { + unsigned char **str = va_arg (args, unsigned char **); + res = objc_write_string_atomic (stream, *str, strlen ((char*)*str)); + } + break; + + case _C_ARY_B: + { + int len = atoi (c + 1); + const char *t = c; + while (isdigit ((unsigned char) *++t)) + ; + res = objc_write_array (stream, t, len, va_arg (args, void *)); + t = objc_skip_typespec (t); + if (*t != _C_ARY_E) + objc_error (nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t); + } + break; + + default: + objc_error (nil, OBJC_ERR_BAD_TYPE, + "objc_write_types: cannot parse typespec: %s\n", type); + } + } + va_end(args); + return res; +} + + +/* +** Last arguments specify addresses of values to be read. Expected +** type is checked against the type actually present on the stream. +*/ + +int +objc_read_types(TypedStream *stream, const char *type, ...) +{ + va_list args; + const char *c; + int res = 0; + + va_start (args, type); + + for (c = type; *c; c = objc_skip_typespec(c)) + { + switch (*c) { + case _C_ID: + res = objc_read_object(stream, va_arg (args, id*)); + break; + + case _C_CLASS: + res = objc_read_class(stream, va_arg (args, Class*)); + break; + + case _C_SEL: + res = objc_read_selector(stream, va_arg (args, SEL*)); + break; + + case _C_CHR: + res = objc_read_char(stream, va_arg (args, char*)); + break; + + case _C_UCHR: + res = objc_read_unsigned_char(stream, va_arg (args, unsigned char*)); + break; + + case _C_SHT: + res = objc_read_short(stream, va_arg (args, short*)); + break; + + case _C_USHT: + res = objc_read_unsigned_short(stream, va_arg (args, unsigned short*)); + break; + + case _C_INT: + res = objc_read_int(stream, va_arg (args, int*)); + break; + + case _C_UINT: + res = objc_read_unsigned_int(stream, va_arg (args, unsigned int*)); + break; + + case _C_LNG: + res = objc_read_long(stream, va_arg (args, long*)); + break; + + case _C_ULNG: + res = objc_read_unsigned_long(stream, va_arg (args, unsigned long*)); + break; + + case _C_CHARPTR: + case _C_ATOM: + { + char **str = va_arg (args, char **); + res = objc_read_string (stream, str); + } + break; + + case _C_ARY_B: + { + int len = atoi (c + 1); + const char *t = c; + while (isdigit ((unsigned char) *++t)) + ; + res = objc_read_array (stream, t, len, va_arg (args, void *)); + t = objc_skip_typespec (t); + if (*t != _C_ARY_E) + objc_error (nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t); + } + break; + + default: + objc_error (nil, OBJC_ERR_BAD_TYPE, + "objc_read_types: cannot parse typespec: %s\n", type); + } + } + va_end (args); + return res; +} + +/* +** Write an array of COUNT elements of TYPE from the memory address DATA. +** This is equivalent of objc_write_type (stream, "[N]", data) +*/ + +int +objc_write_array (TypedStream *stream, const char *type, + int count, const void *data) +{ + int off = objc_sizeof_type(type); + const char *where = data; + + while (count-- > 0) + { + objc_write_type(stream, type, where); + where += off; + } + return 1; +} + +/* +** Read an array of COUNT elements of TYPE into the memory address +** DATA. The memory pointed to by data is supposed to be allocated +** by the callee. This is equivalent of +** objc_read_type (stream, "[N]", data) +*/ + +int +objc_read_array (TypedStream *stream, const char *type, + int count, void *data) +{ + int off = objc_sizeof_type(type); + char *where = (char*)data; + + while (count-- > 0) + { + objc_read_type(stream, type, where); + where += off; + } + return 1; +} + +static int +__objc_fread (FILE *file, char *data, int len) +{ + return fread(data, len, 1, file); +} + +static int +__objc_fwrite (FILE *file, char *data, int len) +{ + return fwrite(data, len, 1, file); +} + +static int +__objc_feof (FILE *file) +{ + return feof(file); +} + +static int +__objc_no_write (FILE *file __attribute__ ((__unused__)), + const char *data __attribute__ ((__unused__)), + int len __attribute__ ((__unused__))) +{ + objc_error (nil, OBJC_ERR_NO_WRITE, "TypedStream not open for writing"); + return 0; +} + +static int +__objc_no_read (FILE *file __attribute__ ((__unused__)), + const char *data __attribute__ ((__unused__)), + int len __attribute__ ((__unused__))) +{ + objc_error (nil, OBJC_ERR_NO_READ, "TypedStream not open for reading"); + return 0; +} + +static int +__objc_read_typed_stream_signature (TypedStream *stream) +{ + char buffer[80]; + int pos = 0; + do + (*stream->read) (stream->physical, buffer+pos, 1); + while (buffer[pos++] != '\0') + ; + sscanf (buffer, "GNU TypedStream %d", &stream->version); + if (stream->version != OBJC_TYPED_STREAM_VERSION) + objc_error (nil, OBJC_ERR_STREAM_VERSION, + "cannot handle TypedStream version %d", stream->version); + return 1; +} + +static int +__objc_write_typed_stream_signature (TypedStream *stream) +{ + char buffer[80]; + sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION); + stream->version = OBJC_TYPED_STREAM_VERSION; + (*stream->write) (stream->physical, buffer, strlen (buffer) + 1); + return 1; +} + +static void __objc_finish_write_root_object(struct objc_typed_stream *stream) +{ + objc_hash_delete (stream->object_table); + stream->object_table = objc_hash_new (64, + (hash_func_type) objc_hash_ptr, + (compare_func_type) objc_compare_ptrs); +} + +static void __objc_finish_read_root_object(struct objc_typed_stream *stream) +{ + node_ptr node; + SEL awake_sel = sel_get_any_uid ("awake"); + cache_ptr free_list = objc_hash_new (64, + (hash_func_type) objc_hash_ptr, + (compare_func_type) objc_compare_ptrs); + + /* resolve object forward references */ + for (node = objc_hash_next (stream->object_refs, NULL); node; + node = objc_hash_next (stream->object_refs, node)) + { + struct objc_list *reflist = node->value; + const void *key = node->key; + id object = objc_hash_value_for_key (stream->object_table, key); + while (reflist) + { + *((id*) reflist->head) = object; + if (objc_hash_value_for_key (free_list,reflist) == NULL) + objc_hash_add (&free_list,reflist,reflist); + + reflist = reflist->tail; + } + } + + /* apply __objc_free to all objects stored in free_list */ + for (node = objc_hash_next (free_list, NULL); node; + node = objc_hash_next (free_list, node)) + objc_free ((void *) node->key); + + objc_hash_delete (free_list); + + /* empty object reference table */ + objc_hash_delete (stream->object_refs); + stream->object_refs = objc_hash_new (8, (hash_func_type) objc_hash_ptr, + (compare_func_type) objc_compare_ptrs); + + /* call -awake for all objects read */ + if (awake_sel) + { + for (node = objc_hash_next (stream->object_table, NULL); node; + node = objc_hash_next (stream->object_table, node)) + { + id object = node->value; + if (__objc_responds_to (object, awake_sel)) + (*objc_msg_lookup (object, awake_sel)) (object, awake_sel); + } + } + + /* empty object table */ + objc_hash_delete (stream->object_table); + stream->object_table = objc_hash_new(64, + (hash_func_type)objc_hash_ptr, + (compare_func_type)objc_compare_ptrs); +} + +/* +** Open the stream PHYSICAL in MODE +*/ + +TypedStream * +objc_open_typed_stream (FILE *physical, int mode) +{ + TypedStream *s = (TypedStream *) objc_malloc (sizeof (TypedStream)); + + s->mode = mode; + s->physical = physical; + s->stream_table = objc_hash_new (64, + (hash_func_type) objc_hash_ptr, + (compare_func_type) objc_compare_ptrs); + s->object_table = objc_hash_new (64, + (hash_func_type) objc_hash_ptr, + (compare_func_type) objc_compare_ptrs); + s->eof = (objc_typed_eof_func) __objc_feof; + s->flush = (objc_typed_flush_func) fflush; + s->writing_root_p = 0; + if (mode == OBJC_READONLY) + { + s->class_table + = objc_hash_new (8, (hash_func_type) objc_hash_string, + (compare_func_type) objc_compare_strings); + s->object_refs = objc_hash_new (8, (hash_func_type) objc_hash_ptr, + (compare_func_type) objc_compare_ptrs); + s->read = (objc_typed_read_func) __objc_fread; + s->write = (objc_typed_write_func) __objc_no_write; + __objc_read_typed_stream_signature (s); + } + else if (mode == OBJC_WRITEONLY) + { + s->class_table = 0; + s->object_refs = 0; + s->read = (objc_typed_read_func) __objc_no_read; + s->write = (objc_typed_write_func) __objc_fwrite; + __objc_write_typed_stream_signature (s); + } + else + { + objc_close_typed_stream (s); + return NULL; + } + s->type = OBJC_FILE_STREAM; + return s; +} + +/* +** Open the file named by FILE_NAME in MODE +*/ + +TypedStream* +objc_open_typed_stream_for_file (const char *file_name, int mode) +{ + FILE *file = NULL; + TypedStream *s; + + if (mode == OBJC_READONLY) + file = fopen (file_name, "r"); + else + file = fopen (file_name, "w"); + + if (file) + { + s = objc_open_typed_stream (file, mode); + if (s) + s->type |= OBJC_MANAGED_STREAM; + return s; + } + else + return NULL; +} + +/* +** Close STREAM freeing the structure it self. If it was opened with +** objc_open_typed_stream_for_file, the file will also be closed. +*/ + +void +objc_close_typed_stream (TypedStream *stream) +{ + if (stream->mode == OBJC_READONLY) + { + __objc_finish_read_root_object (stream); /* Just in case... */ + objc_hash_delete (stream->class_table); + objc_hash_delete (stream->object_refs); + } + + objc_hash_delete (stream->stream_table); + objc_hash_delete (stream->object_table); + + if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM)) + fclose ((FILE *)stream->physical); + + objc_free(stream); +} + +BOOL +objc_end_of_typed_stream (TypedStream *stream) +{ + return (*stream->eof) (stream->physical); +} + +void +objc_flush_typed_stream (TypedStream *stream) +{ + (*stream->flush) (stream->physical); +} + +long +objc_get_stream_class_version (TypedStream *stream, Class class) +{ + if (stream->class_table) + return PTR2LONG(objc_hash_value_for_key (stream->class_table, + class->name)); + else + return class_get_version (class); +} + diff --git a/contrib/gcc-4.1/libobjc/class.c b/contrib/gcc-4.1/libobjc/class.c new file mode 100644 index 0000000000..4374852989 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/class.c @@ -0,0 +1,703 @@ +/* GNU Objective C Runtime class related functions + Copyright (C) 1993, 1995, 1996, 1997, 2001, 2002 + Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup and Dennis Glatting. + + Lock-free class table code designed and written from scratch by + Nicola Pero, 2001. + +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 2, 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 COPYING. If not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +/* + The code in this file critically affects class method invocation + speed. This long preamble comment explains why, and the issues + involved. + + + One of the traditional weaknesses of the GNU Objective-C runtime is + that class method invocations are slow. The reason is that when you + write + + array = [NSArray new]; + + this gets basically compiled into the equivalent of + + array = [(objc_get_class ("NSArray")) new]; + + objc_get_class returns the class pointer corresponding to the string + `NSArray'; and because of the lookup, the operation is more + complicated and slow than a simple instance method invocation. + + Most high performance Objective-C code (using the GNU Objc runtime) + I had the opportunity to read (or write) work around this problem by + caching the class pointer: + + Class arrayClass = [NSArray class]; + + ... later on ... + + array = [arrayClass new]; + array = [arrayClass new]; + array = [arrayClass new]; + + In this case, you always perform a class lookup (the first one), but + then all the [arrayClass new] methods run exactly as fast as an + instance method invocation. It helps if you have many class method + invocations to the same class. + + The long-term solution to this problem would be to modify the + compiler to output tables of class pointers corresponding to all the + class method invocations, and to add code to the runtime to update + these tables - that should in the end allow class method invocations + to perform precisely as fast as instance method invocations, because + no class lookup would be involved. I think the Apple Objective-C + runtime uses this technique. Doing this involves synchronized + modifications in the runtime and in the compiler. + + As a first medicine to the problem, I [NP] have redesigned and + rewritten the way the runtime is performing class lookup. This + doesn't give as much speed as the other (definitive) approach, but + at least a class method invocation now takes approximately 4.5 times + an instance method invocation on my machine (it would take approx 12 + times before the rewriting), which is a lot better. + + One of the main reason the new class lookup is so faster is because + I implemented it in a way that can safely run multithreaded without + using locks - a so-called `lock-free' data structure. The atomic + operation is pointer assignment. The reason why in this problem + lock-free data structures work so well is that you never remove + classes from the table - and the difficult thing with lock-free data + structures is freeing data when is removed from the structures. */ + +#include "objc/runtime.h" /* the kitchen sink */ +#include "objc/sarray.h" + +#include "objc/objc.h" +#include "objc/objc-api.h" +#include "objc/thr.h" + +/* We use a table which maps a class name to the corresponding class + * pointer. The first part of this file defines this table, and + * functions to do basic operations on the table. The second part of + * the file implements some higher level Objective-C functionality for + * classes by using the functions provided in the first part to manage + * the table. */ + +/** + ** Class Table Internals + **/ + +/* A node holding a class */ +typedef struct class_node +{ + struct class_node *next; /* Pointer to next entry on the list. + NULL indicates end of list. */ + + const char *name; /* The class name string */ + int length; /* The class name string length */ + Class pointer; /* The Class pointer */ + +} *class_node_ptr; + +/* A table containing classes is a class_node_ptr (pointing to the + first entry in the table - if it is NULL, then the table is + empty). */ + +/* We have 1024 tables. Each table contains all class names which + have the same hash (which is a number between 0 and 1023). To look + up a class_name, we compute its hash, and get the corresponding + table. Once we have the table, we simply compare strings directly + till we find the one which we want (using the length first). The + number of tables is quite big on purpose (a normal big application + has less than 1000 classes), so that you shouldn't normally get any + collisions, and get away with a single comparison (which we can't + avoid since we need to know that you have got the right thing). */ +#define CLASS_TABLE_SIZE 1024 +#define CLASS_TABLE_MASK 1023 + +static class_node_ptr class_table_array[CLASS_TABLE_SIZE]; + +/* The table writing mutex - we lock on writing to avoid conflicts + between different writers, but we read without locks. That is + possible because we assume pointer assignment to be an atomic + operation. */ +static objc_mutex_t __class_table_lock = NULL; + +/* CLASS_TABLE_HASH is how we compute the hash of a class name. It is + a macro - *not* a function - arguments *are* modified directly. + + INDEX should be a variable holding an int; + HASH should be a variable holding an int; + CLASS_NAME should be a variable holding a (char *) to the class_name. + + After the macro is executed, INDEX contains the length of the + string, and HASH the computed hash of the string; CLASS_NAME is + untouched. */ + +#define CLASS_TABLE_HASH(INDEX, HASH, CLASS_NAME) \ + HASH = 0; \ + for (INDEX = 0; CLASS_NAME[INDEX] != '\0'; INDEX++) \ + { \ + HASH = (HASH << 4) ^ (HASH >> 28) ^ CLASS_NAME[INDEX]; \ + } \ + \ + HASH = (HASH ^ (HASH >> 10) ^ (HASH >> 20)) & CLASS_TABLE_MASK; + +/* Setup the table. */ +static void +class_table_setup (void) +{ + /* Start - nothing in the table. */ + memset (class_table_array, 0, sizeof (class_node_ptr) * CLASS_TABLE_SIZE); + + /* The table writing mutex. */ + __class_table_lock = objc_mutex_allocate (); +} + + +/* Insert a class in the table (used when a new class is registered). */ +static void +class_table_insert (const char *class_name, Class class_pointer) +{ + int hash, length; + class_node_ptr new_node; + + /* Find out the class name's hash and length. */ + CLASS_TABLE_HASH (length, hash, class_name); + + /* Prepare the new node holding the class. */ + new_node = objc_malloc (sizeof (struct class_node)); + new_node->name = class_name; + new_node->length = length; + new_node->pointer = class_pointer; + + /* Lock the table for modifications. */ + objc_mutex_lock (__class_table_lock); + + /* Insert the new node in the table at the beginning of the table at + class_table_array[hash]. */ + new_node->next = class_table_array[hash]; + class_table_array[hash] = new_node; + + objc_mutex_unlock (__class_table_lock); +} + +/* Replace a class in the table (used only by poseAs:). */ +static void +class_table_replace (Class old_class_pointer, Class new_class_pointer) +{ + int hash; + class_node_ptr node; + + objc_mutex_lock (__class_table_lock); + + hash = 0; + node = class_table_array[hash]; + + while (hash < CLASS_TABLE_SIZE) + { + if (node == NULL) + { + hash++; + if (hash < CLASS_TABLE_SIZE) + { + node = class_table_array[hash]; + } + } + else + { + Class class1 = node->pointer; + + if (class1 == old_class_pointer) + { + node->pointer = new_class_pointer; + } + node = node->next; + } + } + + objc_mutex_unlock (__class_table_lock); +} + + +/* Get a class from the table. This does not need mutex protection. + Currently, this function is called each time you call a static + method, this is why it must be very fast. */ +static inline Class +class_table_get_safe (const char *class_name) +{ + class_node_ptr node; + int length, hash; + + /* Compute length and hash. */ + CLASS_TABLE_HASH (length, hash, class_name); + + node = class_table_array[hash]; + + if (node != NULL) + { + do + { + if (node->length == length) + { + /* Compare the class names. */ + int i; + + for (i = 0; i < length; i++) + { + if ((node->name)[i] != class_name[i]) + { + break; + } + } + + if (i == length) + { + /* They are equal! */ + return node->pointer; + } + } + } + while ((node = node->next) != NULL); + } + + return Nil; +} + +/* Enumerate over the class table. */ +struct class_table_enumerator +{ + int hash; + class_node_ptr node; +}; + + +static Class +class_table_next (struct class_table_enumerator **e) +{ + struct class_table_enumerator *enumerator = *e; + class_node_ptr next; + + if (enumerator == NULL) + { + *e = objc_malloc (sizeof (struct class_table_enumerator)); + enumerator = *e; + enumerator->hash = 0; + enumerator->node = NULL; + + next = class_table_array[enumerator->hash]; + } + else + { + next = enumerator->node->next; + } + + if (next != NULL) + { + enumerator->node = next; + return enumerator->node->pointer; + } + else + { + enumerator->hash++; + + while (enumerator->hash < CLASS_TABLE_SIZE) + { + next = class_table_array[enumerator->hash]; + if (next != NULL) + { + enumerator->node = next; + return enumerator->node->pointer; + } + enumerator->hash++; + } + + /* Ok - table finished - done. */ + objc_free (enumerator); + return Nil; + } +} + +#if 0 /* DEBUGGING FUNCTIONS */ +/* Debugging function - print the class table. */ +void +class_table_print (void) +{ + int i; + + for (i = 0; i < CLASS_TABLE_SIZE; i++) + { + class_node_ptr node; + + printf ("%d:\n", i); + node = class_table_array[i]; + + while (node != NULL) + { + printf ("\t%s\n", node->name); + node = node->next; + } + } +} + +/* Debugging function - print an histogram of number of classes in + function of hash key values. Useful to evaluate the hash function + in real cases. */ +void +class_table_print_histogram (void) +{ + int i, j; + int counter = 0; + + for (i = 0; i < CLASS_TABLE_SIZE; i++) + { + class_node_ptr node; + + node = class_table_array[i]; + + while (node != NULL) + { + counter++; + node = node->next; + } + if (((i + 1) % 50) == 0) + { + printf ("%4d:", i + 1); + for (j = 0; j < counter; j++) + { + printf ("X"); + } + printf ("\n"); + counter = 0; + } + } + printf ("%4d:", i + 1); + for (j = 0; j < counter; j++) + { + printf ("X"); + } + printf ("\n"); +} +#endif /* DEBUGGING FUNCTIONS */ + +/** + ** Objective-C runtime functions + **/ + +/* From now on, the only access to the class table data structure + should be via the class_table_* functions. */ + +/* This is a hook which is called by objc_get_class and + objc_lookup_class if the runtime is not able to find the class. + This may e.g. try to load in the class using dynamic loading. */ +Class (*_objc_lookup_class) (const char *name) = 0; /* !T:SAFE */ + + +/* True when class links has been resolved. */ +BOOL __objc_class_links_resolved = NO; /* !T:UNUSED */ + + +void +__objc_init_class_tables (void) +{ + /* Allocate the class hash table. */ + + if (__class_table_lock) + return; + + objc_mutex_lock (__objc_runtime_mutex); + + class_table_setup (); + + objc_mutex_unlock (__objc_runtime_mutex); +} + +/* This function adds a class to the class hash table, and assigns the + class a number, unless it's already known. */ +void +__objc_add_class_to_hash (Class class) +{ + Class h_class; + + objc_mutex_lock (__objc_runtime_mutex); + + /* Make sure the table is there. */ + assert (__class_table_lock); + + /* Make sure it's not a meta class. */ + assert (CLS_ISCLASS (class)); + + /* Check to see if the class is already in the hash table. */ + h_class = class_table_get_safe (class->name); + if (! h_class) + { + /* The class isn't in the hash table. Add the class and assign a class + number. */ + static unsigned int class_number = 1; + + CLS_SETNUMBER (class, class_number); + CLS_SETNUMBER (class->class_pointer, class_number); + + ++class_number; + class_table_insert (class->name, class); + } + + objc_mutex_unlock (__objc_runtime_mutex); +} + +/* Get the class object for the class named NAME. If NAME does not + identify a known class, the hook _objc_lookup_class is called. If + this fails, nil is returned. */ +Class +objc_lookup_class (const char *name) +{ + Class class; + + class = class_table_get_safe (name); + + if (class) + return class; + + if (_objc_lookup_class) + return (*_objc_lookup_class) (name); + else + return 0; +} + +/* Get the class object for the class named NAME. If NAME does not + identify a known class, the hook _objc_lookup_class is called. If + this fails, an error message is issued and the system aborts. */ +Class +objc_get_class (const char *name) +{ + Class class; + + class = class_table_get_safe (name); + + if (class) + return class; + + if (_objc_lookup_class) + class = (*_objc_lookup_class) (name); + + if (class) + return class; + + objc_error (nil, OBJC_ERR_BAD_CLASS, + "objc runtime: cannot find class %s\n", name); + return 0; +} + +MetaClass +objc_get_meta_class (const char *name) +{ + return objc_get_class (name)->class_pointer; +} + +/* This function provides a way to enumerate all the classes in the + executable. Pass *ENUM_STATE == NULL to start the enumeration. The + function will return 0 when there are no more classes. + For example: + id class; + void *es = NULL; + while ((class = objc_next_class (&es))) + ... do something with class; +*/ +Class +objc_next_class (void **enum_state) +{ + Class class; + + objc_mutex_lock (__objc_runtime_mutex); + + /* Make sure the table is there. */ + assert (__class_table_lock); + + class = class_table_next ((struct class_table_enumerator **) enum_state); + + objc_mutex_unlock (__objc_runtime_mutex); + + return class; +} + +/* Resolve super/subclass links for all classes. The only thing we + can be sure of is that the class_pointer for class objects point to + the right meta class objects. */ +void +__objc_resolve_class_links (void) +{ + struct class_table_enumerator *es = NULL; + Class object_class = objc_get_class ("Object"); + Class class1; + + assert (object_class); + + objc_mutex_lock (__objc_runtime_mutex); + + /* Assign subclass links. */ + while ((class1 = class_table_next (&es))) + { + /* Make sure we have what we think we have. */ + assert (CLS_ISCLASS (class1)); + assert (CLS_ISMETA (class1->class_pointer)); + + /* The class_pointer of all meta classes point to Object's meta + class. */ + class1->class_pointer->class_pointer = object_class->class_pointer; + + if (! CLS_ISRESOLV (class1)) + { + CLS_SETRESOLV (class1); + CLS_SETRESOLV (class1->class_pointer); + + if (class1->super_class) + { + Class a_super_class + = objc_get_class ((char *) class1->super_class); + + assert (a_super_class); + + DEBUG_PRINTF ("making class connections for: %s\n", + class1->name); + + /* Assign subclass links for superclass. */ + class1->sibling_class = a_super_class->subclass_list; + a_super_class->subclass_list = class1; + + /* Assign subclass links for meta class of superclass. */ + if (a_super_class->class_pointer) + { + class1->class_pointer->sibling_class + = a_super_class->class_pointer->subclass_list; + a_super_class->class_pointer->subclass_list + = class1->class_pointer; + } + } + else /* A root class, make its meta object be a subclass of + Object. */ + { + class1->class_pointer->sibling_class + = object_class->subclass_list; + object_class->subclass_list = class1->class_pointer; + } + } + } + + /* Assign superclass links. */ + es = NULL; + while ((class1 = class_table_next (&es))) + { + Class sub_class; + for (sub_class = class1->subclass_list; sub_class; + sub_class = sub_class->sibling_class) + { + sub_class->super_class = class1; + if (CLS_ISCLASS (sub_class)) + sub_class->class_pointer->super_class = class1->class_pointer; + } + } + + objc_mutex_unlock (__objc_runtime_mutex); +} + + + +#define CLASSOF(c) ((c)->class_pointer) + +Class +class_pose_as (Class impostor, Class super_class) +{ + if (! CLS_ISRESOLV (impostor)) + __objc_resolve_class_links (); + + /* Preconditions */ + assert (impostor); + assert (super_class); + assert (impostor->super_class == super_class); + assert (CLS_ISCLASS (impostor)); + assert (CLS_ISCLASS (super_class)); + assert (impostor->instance_size == super_class->instance_size); + + { + Class *subclass = &(super_class->subclass_list); + + /* Move subclasses of super_class to impostor. */ + while (*subclass) + { + Class nextSub = (*subclass)->sibling_class; + + if (*subclass != impostor) + { + Class sub = *subclass; + + /* Classes */ + sub->sibling_class = impostor->subclass_list; + sub->super_class = impostor; + impostor->subclass_list = sub; + + /* It will happen that SUB is not a class object if it is + the top of the meta class hierarchy chain (root + meta-class objects inherit their class object). If + that is the case... don't mess with the meta-meta + class. */ + if (CLS_ISCLASS (sub)) + { + /* Meta classes */ + CLASSOF (sub)->sibling_class = + CLASSOF (impostor)->subclass_list; + CLASSOF (sub)->super_class = CLASSOF (impostor); + CLASSOF (impostor)->subclass_list = CLASSOF (sub); + } + } + + *subclass = nextSub; + } + + /* Set subclasses of superclass to be impostor only. */ + super_class->subclass_list = impostor; + CLASSOF (super_class)->subclass_list = CLASSOF (impostor); + + /* Set impostor to have no sibling classes. */ + impostor->sibling_class = 0; + CLASSOF (impostor)->sibling_class = 0; + } + + /* Check relationship of impostor and super_class is kept. */ + assert (impostor->super_class == super_class); + assert (CLASSOF (impostor)->super_class == CLASSOF (super_class)); + + /* This is how to update the lookup table. Regardless of what the + keys of the hashtable is, change all values that are superclass + into impostor. */ + + objc_mutex_lock (__objc_runtime_mutex); + + class_table_replace (super_class, impostor); + + objc_mutex_unlock (__objc_runtime_mutex); + + /* Next, we update the dispatch tables... */ + __objc_update_dispatch_table_for_class (CLASSOF (impostor)); + __objc_update_dispatch_table_for_class (impostor); + + return impostor; +} diff --git a/contrib/gcc-4.1/libobjc/encoding.c b/contrib/gcc-4.1/libobjc/encoding.c new file mode 100644 index 0000000000..efdc2f0a16 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/encoding.c @@ -0,0 +1,960 @@ +/* Encoding of types for Objective C. + Copyright (C) 1993, 1995, 1996, 1997, 1998, 2000, 2002, 2004 + Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + Bitfield support by Ovidiu Predescu + +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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +/* FIXME: This file has no business including tm.h. */ + +#include "tconfig.h" +#include "coretypes.h" +#include "tm.h" +#include "objc/objc-api.h" +#include "objc/encoding.h" +#include + +#undef MAX +#define MAX(X, Y) \ + ({ typeof (X) __x = (X), __y = (Y); \ + (__x > __y ? __x : __y); }) + +#undef MIN +#define MIN(X, Y) \ + ({ typeof (X) __x = (X), __y = (Y); \ + (__x < __y ? __x : __y); }) + +#undef ROUND +#define ROUND(V, A) \ + ({ typeof (V) __v = (V); typeof (A) __a = (A); \ + __a * ((__v+__a - 1)/__a); }) + + +/* Various hacks for objc_layout_record. These are used by the target + macros. */ + +#define TREE_CODE(TYPE) *(TYPE) +#define TREE_TYPE(TREE) (TREE) + +#define RECORD_TYPE _C_STRUCT_B +#define UNION_TYPE _C_UNION_B +#define QUAL_UNION_TYPE _C_UNION_B +#define ARRAY_TYPE _C_ARY_B + +#define REAL_TYPE _C_DBL + +#define VECTOR_TYPE _C_VECTOR + +#define TYPE_FIELDS(TYPE) objc_skip_typespec (TYPE) + +#define DECL_MODE(TYPE) *(TYPE) +#define TYPE_MODE(TYPE) *(TYPE) + +#define DFmode _C_DBL + +#define get_inner_array_type(TYPE) ((TYPE) + 1) + +/* Some ports (eg ARM) allow the structure size boundary to be + selected at compile-time. We override the normal definition with + one that has a constant value for this compilation. */ +#ifndef BITS_PER_UNIT +#define BITS_PER_UNIT 8 +#endif +#undef STRUCTURE_SIZE_BOUNDARY +#define STRUCTURE_SIZE_BOUNDARY (BITS_PER_UNIT * sizeof (struct{char a;})) + +/* Some ROUND_TYPE_ALIGN macros use TARGET_foo, and consequently + target_flags. Define a dummy entry here to so we don't die. + We have to rename it because target_flags may already have been + declared extern. */ +#define target_flags not_target_flags +static int __attribute__ ((__unused__)) not_target_flags = 0; + +/* Some ROUND_TYPE_ALIGN use ALTIVEC_VECTOR_MODE (rs6000 darwin). + Define a dummy ALTIVEC_VECTOR_MODE so it will not die. */ +#undef ALTIVEC_VECTOR_MODE +#define ALTIVEC_VECTOR_MODE(MODE) (0) + + +/* FIXME: while this file has no business including tm.h, this + definitely has no business defining this macro but it + is only way around without really rewritting this file, + should look after the branch of 3.4 to fix this. */ +#define rs6000_special_round_type_align(STRUCT, COMPUTED, SPECIFIED) \ + ((TYPE_FIELDS (STRUCT) != 0 \ + && DECL_MODE (TYPE_FIELDS (STRUCT)) == DFmode) \ + ? MAX (MAX (COMPUTED, SPECIFIED), 64) \ + : MAX (COMPUTED, SPECIFIED)) + +/* + return the size of an object specified by type +*/ + +int +objc_sizeof_type (const char *type) +{ + /* Skip the variable name if any */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + switch (*type) { + case _C_ID: + return sizeof (id); + break; + + case _C_CLASS: + return sizeof (Class); + break; + + case _C_SEL: + return sizeof (SEL); + break; + + case _C_CHR: + return sizeof (char); + break; + + case _C_UCHR: + return sizeof (unsigned char); + break; + + case _C_SHT: + return sizeof (short); + break; + + case _C_USHT: + return sizeof (unsigned short); + break; + + case _C_INT: + return sizeof (int); + break; + + case _C_UINT: + return sizeof (unsigned int); + break; + + case _C_LNG: + return sizeof (long); + break; + + case _C_ULNG: + return sizeof (unsigned long); + break; + + case _C_LNG_LNG: + return sizeof (long long); + break; + + case _C_ULNG_LNG: + return sizeof (unsigned long long); + break; + + case _C_FLT: + return sizeof (float); + break; + + case _C_DBL: + return sizeof (double); + break; + + case _C_VOID: + return sizeof (void); + break; + + case _C_PTR: + case _C_ATOM: + case _C_CHARPTR: + return sizeof (char *); + break; + + case _C_ARY_B: + { + int len = atoi (type + 1); + while (isdigit ((unsigned char)*++type)) + ; + return len * objc_aligned_size (type); + } + break; + + case _C_BFLD: + { + /* The new encoding of bitfields is: b 'position' 'type' 'size' */ + int position, size; + int startByte, endByte; + + position = atoi (type + 1); + while (isdigit ((unsigned char)*++type)) + ; + size = atoi (type + 1); + + startByte = position / BITS_PER_UNIT; + endByte = (position + size) / BITS_PER_UNIT; + return endByte - startByte; + } + + case _C_STRUCT_B: + { + struct objc_struct_layout layout; + unsigned int size; + + objc_layout_structure (type, &layout); + while (objc_layout_structure_next_member (&layout)) + /* do nothing */ ; + objc_layout_finish_structure (&layout, &size, NULL); + + return size; + } + + case _C_UNION_B: + { + int max_size = 0; + while (*type != _C_UNION_E && *type++ != '=') + /* do nothing */; + while (*type != _C_UNION_E) + { + /* Skip the variable name if any */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + max_size = MAX (max_size, objc_sizeof_type (type)); + type = objc_skip_typespec (type); + } + return max_size; + } + + default: + { + objc_error (nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type); + return 0; + } + } +} + + +/* + Return the alignment of an object specified by type +*/ + +int +objc_alignof_type (const char *type) +{ + /* Skip the variable name if any */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + switch (*type) { + case _C_ID: + return __alignof__ (id); + break; + + case _C_CLASS: + return __alignof__ (Class); + break; + + case _C_SEL: + return __alignof__ (SEL); + break; + + case _C_CHR: + return __alignof__ (char); + break; + + case _C_UCHR: + return __alignof__ (unsigned char); + break; + + case _C_SHT: + return __alignof__ (short); + break; + + case _C_USHT: + return __alignof__ (unsigned short); + break; + + case _C_INT: + return __alignof__ (int); + break; + + case _C_UINT: + return __alignof__ (unsigned int); + break; + + case _C_LNG: + return __alignof__ (long); + break; + + case _C_ULNG: + return __alignof__ (unsigned long); + break; + + case _C_LNG_LNG: + return __alignof__ (long long); + break; + + case _C_ULNG_LNG: + return __alignof__ (unsigned long long); + break; + + case _C_FLT: + return __alignof__ (float); + break; + + case _C_DBL: + return __alignof__ (double); + break; + + case _C_PTR: + case _C_ATOM: + case _C_CHARPTR: + return __alignof__ (char *); + break; + + case _C_ARY_B: + while (isdigit ((unsigned char)*++type)) + /* do nothing */; + return objc_alignof_type (type); + + case _C_STRUCT_B: + { + struct objc_struct_layout layout; + unsigned int align; + + objc_layout_structure (type, &layout); + while (objc_layout_structure_next_member (&layout)) + /* do nothing */; + objc_layout_finish_structure (&layout, NULL, &align); + + return align; + } + + case _C_UNION_B: + { + int maxalign = 0; + while (*type != _C_UNION_E && *type++ != '=') + /* do nothing */; + while (*type != _C_UNION_E) + { + /* Skip the variable name if any */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + maxalign = MAX (maxalign, objc_alignof_type (type)); + type = objc_skip_typespec (type); + } + return maxalign; + } + + default: + { + objc_error (nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type); + return 0; + } + } +} + +/* + The aligned size if the size rounded up to the nearest alignment. +*/ + +int +objc_aligned_size (const char *type) +{ + int size, align; + + /* Skip the variable name */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + size = objc_sizeof_type (type); + align = objc_alignof_type (type); + + return ROUND (size, align); +} + +/* + The size rounded up to the nearest integral of the wordsize, taken + to be the size of a void *. +*/ + +int +objc_promoted_size (const char *type) +{ + int size, wordsize; + + /* Skip the variable name */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + size = objc_sizeof_type (type); + wordsize = sizeof (void *); + + return ROUND (size, wordsize); +} + +/* + Skip type qualifiers. These may eventually precede typespecs + occurring in method prototype encodings. +*/ + +inline const char * +objc_skip_type_qualifiers (const char *type) +{ + while (*type == _C_CONST + || *type == _C_IN + || *type == _C_INOUT + || *type == _C_OUT + || *type == _C_BYCOPY + || *type == _C_BYREF + || *type == _C_ONEWAY + || *type == _C_GCINVISIBLE) + { + type += 1; + } + return type; +} + + +/* + Skip one typespec element. If the typespec is prepended by type + qualifiers, these are skipped as well. +*/ + +const char * +objc_skip_typespec (const char *type) +{ + /* Skip the variable name if any */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + type = objc_skip_type_qualifiers (type); + + switch (*type) { + + case _C_ID: + /* An id may be annotated by the actual type if it is known + with the @"ClassName" syntax */ + + if (*++type != '"') + return type; + else + { + while (*++type != '"') + /* do nothing */; + return type + 1; + } + + /* The following are one character type codes */ + case _C_CLASS: + case _C_SEL: + case _C_CHR: + case _C_UCHR: + case _C_CHARPTR: + case _C_ATOM: + case _C_SHT: + case _C_USHT: + case _C_INT: + case _C_UINT: + case _C_LNG: + case _C_ULNG: + case _C_LNG_LNG: + case _C_ULNG_LNG: + case _C_FLT: + case _C_DBL: + case _C_VOID: + case _C_UNDEF: + return ++type; + break; + + case _C_ARY_B: + /* skip digits, typespec and closing ']' */ + + while (isdigit ((unsigned char)*++type)) + ; + type = objc_skip_typespec (type); + if (*type == _C_ARY_E) + return ++type; + else + { + objc_error (nil, OBJC_ERR_BAD_TYPE, "bad array type %s\n", type); + return 0; + } + + case _C_BFLD: + /* The new encoding of bitfields is: b 'position' 'type' 'size' */ + while (isdigit ((unsigned char)*++type)) + ; /* skip position */ + while (isdigit ((unsigned char)*++type)) + ; /* skip type and size */ + return type; + + case _C_STRUCT_B: + /* skip name, and elements until closing '}' */ + + while (*type != _C_STRUCT_E && *type++ != '=') + ; + while (*type != _C_STRUCT_E) + { + type = objc_skip_typespec (type); + } + return ++type; + + case _C_UNION_B: + /* skip name, and elements until closing ')' */ + + while (*type != _C_UNION_E && *type++ != '=') + ; + while (*type != _C_UNION_E) + { + type = objc_skip_typespec (type); + } + return ++type; + + case _C_PTR: + /* Just skip the following typespec */ + + return objc_skip_typespec (++type); + + default: + { + objc_error (nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type); + return 0; + } + } +} + +/* + Skip an offset as part of a method encoding. This is prepended by a + '+' if the argument is passed in registers. +*/ +inline const char * +objc_skip_offset (const char *type) +{ + if (*type == '+') + type++; + while (isdigit ((unsigned char) *++type)) + ; + return type; +} + +/* + Skip an argument specification of a method encoding. +*/ +const char * +objc_skip_argspec (const char *type) +{ + type = objc_skip_typespec (type); + type = objc_skip_offset (type); + return type; +} + +/* + Return the number of arguments that the method MTH expects. + Note that all methods need two implicit arguments `self' and + `_cmd'. +*/ +int +method_get_number_of_arguments (struct objc_method *mth) +{ + int i = 0; + const char *type = mth->method_types; + while (*type) + { + type = objc_skip_argspec (type); + i += 1; + } + return i - 1; +} + +/* + Return the size of the argument block needed on the stack to invoke + the method MTH. This may be zero, if all arguments are passed in + registers. +*/ + +int +method_get_sizeof_arguments (struct objc_method *mth) +{ + const char *type = objc_skip_typespec (mth->method_types); + return atoi (type); +} + +/* + Return a pointer to the next argument of ARGFRAME. type points to + the last argument. Typical use of this look like: + + { + char *datum, *type; + for (datum = method_get_first_argument (method, argframe, &type); + datum; datum = method_get_next_argument (argframe, &type)) + { + unsigned flags = objc_get_type_qualifiers (type); + type = objc_skip_type_qualifiers (type); + if (*type != _C_PTR) + [portal encodeData: datum ofType: type]; + else + { + if ((flags & _F_IN) == _F_IN) + [portal encodeData: *(char **) datum ofType: ++type]; + } + } + } +*/ + +char * +method_get_next_argument (arglist_t argframe, const char **type) +{ + const char *t = objc_skip_argspec (*type); + + if (*t == '\0') + return 0; + + *type = t; + t = objc_skip_typespec (t); + + if (*t == '+') + return argframe->arg_regs + atoi (++t); + else + return argframe->arg_ptr + atoi (t); +} + +/* + Return a pointer to the value of the first argument of the method + described in M with the given argumentframe ARGFRAME. The type + is returned in TYPE. type must be passed to successive calls of + method_get_next_argument. +*/ +char * +method_get_first_argument (struct objc_method *m, + arglist_t argframe, + const char **type) +{ + *type = m->method_types; + return method_get_next_argument (argframe, type); +} + +/* + Return a pointer to the ARGth argument of the method + M from the frame ARGFRAME. The type of the argument + is returned in the value-result argument TYPE +*/ + +char * +method_get_nth_argument (struct objc_method *m, + arglist_t argframe, int arg, + const char **type) +{ + const char *t = objc_skip_argspec (m->method_types); + + if (arg > method_get_number_of_arguments (m)) + return 0; + + while (arg--) + t = objc_skip_argspec (t); + + *type = t; + t = objc_skip_typespec (t); + + if (*t == '+') + return argframe->arg_regs + atoi (++t); + else + return argframe->arg_ptr + atoi (t); +} + +unsigned +objc_get_type_qualifiers (const char *type) +{ + unsigned res = 0; + BOOL flag = YES; + + while (flag) + switch (*type++) + { + case _C_CONST: res |= _F_CONST; break; + case _C_IN: res |= _F_IN; break; + case _C_INOUT: res |= _F_INOUT; break; + case _C_OUT: res |= _F_OUT; break; + case _C_BYCOPY: res |= _F_BYCOPY; break; + case _C_BYREF: res |= _F_BYREF; break; + case _C_ONEWAY: res |= _F_ONEWAY; break; + case _C_GCINVISIBLE: res |= _F_GCINVISIBLE; break; + default: flag = NO; + } + + return res; +} + + +/* The following three functions can be used to determine how a + structure is laid out by the compiler. For example: + + struct objc_struct_layout layout; + int i; + + objc_layout_structure (type, &layout); + while (objc_layout_structure_next_member (&layout)) + { + int position, align; + const char *type; + + objc_layout_structure_get_info (&layout, &position, &align, &type); + printf ("element %d has offset %d, alignment %d\n", + i++, position, align); + } + + These functions are used by objc_sizeof_type and objc_alignof_type + functions to compute the size and alignment of structures. The + previous method of computing the size and alignment of a structure + was not working on some architectures, particulary on AIX, and in + the presence of bitfields inside the structure. */ +void +objc_layout_structure (const char *type, + struct objc_struct_layout *layout) +{ + const char *ntype; + + if (*type++ != _C_STRUCT_B) + { + objc_error (nil, OBJC_ERR_BAD_TYPE, + "record type expected in objc_layout_structure, got %s\n", + type); + } + + layout->original_type = type; + + /* Skip "=" if any. Avoid embedded structures and unions. */ + ntype = type; + while (*ntype != _C_STRUCT_E && *ntype != _C_STRUCT_B && *ntype != _C_UNION_B + && *ntype++ != '=') + /* do nothing */; + + /* If there's a "=", ntype - 1 points to '='; skip the the name */ + if (*(ntype - 1) == '=') + type = ntype; + + layout->type = type; + layout->prev_type = NULL; + layout->record_size = 0; + layout->record_align = BITS_PER_UNIT; + + layout->record_align = MAX (layout->record_align, STRUCTURE_SIZE_BOUNDARY); +} + + +BOOL +objc_layout_structure_next_member (struct objc_struct_layout *layout) +{ + register int desired_align = 0; + + /* The following are used only if the field is a bitfield */ + register const char *bfld_type = 0; + register int bfld_type_size, bfld_type_align = 0, bfld_field_size = 0; + + /* The current type without the type qualifiers */ + const char *type; + + /* Add the size of the previous field to the size of the record. */ + if (layout->prev_type) + { + type = objc_skip_type_qualifiers (layout->prev_type); + + if (*type != _C_BFLD) + layout->record_size += objc_sizeof_type (type) * BITS_PER_UNIT; + else { + /* Get the bitfield's type */ + for (bfld_type = type + 1; + isdigit ((unsigned char)*bfld_type); + bfld_type++) + /* do nothing */; + + bfld_type_size = objc_sizeof_type (bfld_type) * BITS_PER_UNIT; + bfld_type_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT; + bfld_field_size = atoi (objc_skip_typespec (bfld_type)); + layout->record_size += bfld_field_size; + } + } + + if (*layout->type == _C_STRUCT_E) + return NO; + + /* Skip the variable name if any */ + if (*layout->type == '"') + { + for (layout->type++; *layout->type++ != '"';) + /* do nothing */; + } + + type = objc_skip_type_qualifiers (layout->type); + + if (*type != _C_BFLD) + desired_align = objc_alignof_type (type) * BITS_PER_UNIT; + else + { + desired_align = 1; + /* Skip the bitfield's offset */ + for (bfld_type = type + 1; + isdigit ((unsigned char) *bfld_type); + bfld_type++) + /* do nothing */; + + bfld_type_size = objc_sizeof_type (bfld_type) * BITS_PER_UNIT; + bfld_type_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT; + bfld_field_size = atoi (objc_skip_typespec (bfld_type)); + } + +#ifdef BIGGEST_FIELD_ALIGNMENT + desired_align = MIN (desired_align, BIGGEST_FIELD_ALIGNMENT); +#endif +#ifdef ADJUST_FIELD_ALIGN + desired_align = ADJUST_FIELD_ALIGN (type, desired_align); +#endif + + /* Record must have at least as much alignment as any field. + Otherwise, the alignment of the field within the record + is meaningless. */ +#ifndef PCC_BITFIELD_TYPE_MATTERS + layout->record_align = MAX (layout->record_align, desired_align); +#else /* PCC_BITFIELD_TYPE_MATTERS */ + if (*type == _C_BFLD) + { + /* For these machines, a zero-length field does not + affect the alignment of the structure as a whole. + It does, however, affect the alignment of the next field + within the structure. */ + if (bfld_field_size) + layout->record_align = MAX (layout->record_align, desired_align); + else + desired_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT; + + /* A named bit field of declared type `int' + forces the entire structure to have `int' alignment. + Q1: How is encoded this thing and how to check for it? + Q2: How to determine maximum_field_alignment at runtime? */ + +/* if (DECL_NAME (field) != 0) */ + { + int type_align = bfld_type_align; +#if 0 + if (maximum_field_alignment != 0) + type_align = MIN (type_align, maximum_field_alignment); + else if (DECL_PACKED (field)) + type_align = MIN (type_align, BITS_PER_UNIT); +#endif + + layout->record_align = MAX (layout->record_align, type_align); + } + } + else + layout->record_align = MAX (layout->record_align, desired_align); +#endif /* PCC_BITFIELD_TYPE_MATTERS */ + + /* Does this field automatically have alignment it needs + by virtue of the fields that precede it and the record's + own alignment? */ + + if (*type == _C_BFLD) + layout->record_size = atoi (type + 1); + else if (layout->record_size % desired_align != 0) + { + /* No, we need to skip space before this field. + Bump the cumulative size to multiple of field alignment. */ + layout->record_size = ROUND (layout->record_size, desired_align); + } + + /* Jump to the next field in record. */ + + layout->prev_type = layout->type; + layout->type = objc_skip_typespec (layout->type); /* skip component */ + + return YES; +} + + +void objc_layout_finish_structure (struct objc_struct_layout *layout, + unsigned int *size, + unsigned int *align) +{ + if (layout->type && *layout->type == _C_STRUCT_E) + { + /* Work out the alignment of the record as one expression and store + in the record type. Round it up to a multiple of the record's + alignment. */ + +#if defined (ROUND_TYPE_ALIGN) && ! defined (__sparc__) + layout->record_align = ROUND_TYPE_ALIGN (layout->original_type, + 1, + layout->record_align); +#else + layout->record_align = MAX (1, layout->record_align); +#endif + +#ifdef ROUND_TYPE_SIZE + layout->record_size = ROUND_TYPE_SIZE (layout->original_type, + layout->record_size, + layout->record_align); +#else + /* Round the size up to be a multiple of the required alignment */ + layout->record_size = ROUND (layout->record_size, layout->record_align); +#endif + + layout->type = NULL; + } + if (size) + *size = layout->record_size / BITS_PER_UNIT; + if (align) + *align = layout->record_align / BITS_PER_UNIT; +} + + +void objc_layout_structure_get_info (struct objc_struct_layout *layout, + unsigned int *offset, + unsigned int *align, + const char **type) +{ + if (offset) + *offset = layout->record_size / BITS_PER_UNIT; + if (align) + *align = layout->record_align / BITS_PER_UNIT; + if (type) + *type = layout->prev_type; +} diff --git a/contrib/gcc-4.1/libobjc/exception.c b/contrib/gcc-4.1/libobjc/exception.c new file mode 100644 index 0000000000..e1de2ae5af --- /dev/null +++ b/contrib/gcc-4.1/libobjc/exception.c @@ -0,0 +1,376 @@ +/* The implementation of exception handling primitives for Objective-C. + Copyright (C) 2004 Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. */ + +#include +#include "config.h" +#include "objc/objc-api.h" +#include "unwind.h" +#include "unwind-pe.h" + + +/* This is the exception class we report -- "GNUCOBJC". */ +#define __objc_exception_class \ + ((((((((_Unwind_Exception_Class) 'G' \ + << 8 | (_Unwind_Exception_Class) 'N') \ + << 8 | (_Unwind_Exception_Class) 'U') \ + << 8 | (_Unwind_Exception_Class) 'C') \ + << 8 | (_Unwind_Exception_Class) 'O') \ + << 8 | (_Unwind_Exception_Class) 'B') \ + << 8 | (_Unwind_Exception_Class) 'J') \ + << 8 | (_Unwind_Exception_Class) 'C') + +/* This is the object that is passed around by the Objective C runtime + to represent the exception in flight. */ + +struct ObjcException +{ + /* This bit is needed in order to interact with the unwind runtime. */ + struct _Unwind_Exception base; + + /* The actual object we want to throw. */ + id value; + + /* Cache some internal unwind data between phase 1 and phase 2. */ + _Unwind_Ptr landingPad; + int handlerSwitchValue; +}; + + + +struct lsda_header_info +{ + _Unwind_Ptr Start; + _Unwind_Ptr LPStart; + _Unwind_Ptr ttype_base; + const unsigned char *TType; + const unsigned char *action_table; + unsigned char ttype_encoding; + unsigned char call_site_encoding; +}; + +static const unsigned char * +parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, + struct lsda_header_info *info) +{ + _Unwind_Word tmp; + unsigned char lpstart_encoding; + + info->Start = (context ? _Unwind_GetRegionStart (context) : 0); + + /* Find @LPStart, the base to which landing pad offsets are relative. */ + lpstart_encoding = *p++; + if (lpstart_encoding != DW_EH_PE_omit) + p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); + else + info->LPStart = info->Start; + + /* Find @TType, the base of the handler and exception spec type data. */ + info->ttype_encoding = *p++; + if (info->ttype_encoding != DW_EH_PE_omit) + { + p = read_uleb128 (p, &tmp); + info->TType = p + tmp; + } + else + info->TType = 0; + + /* The encoding and length of the call-site table; the action table + immediately follows. */ + info->call_site_encoding = *p++; + p = read_uleb128 (p, &tmp); + info->action_table = p + tmp; + + return p; +} + +static Class +get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i) +{ + _Unwind_Ptr ptr; + + i *= size_of_encoded_value (info->ttype_encoding); + read_encoded_value_with_base (info->ttype_encoding, info->ttype_base, + info->TType - i, &ptr); + + /* NULL ptr means catch-all. */ + if (ptr) + return objc_get_class ((const char *) ptr); + else + return 0; +} + +/* Like unto the method of the same name on Object, but takes an id. */ +/* ??? Does this bork the meta-type system? Can/should we look up an + isKindOf method on the id? */ + +static int +isKindOf (id value, Class target) +{ + Class c; + + /* NULL target is catch-all. */ + if (target == 0) + return 1; + + for (c = value->class_pointer; c; c = class_get_super_class (c)) + if (c == target) + return 1; + return 0; +} + +/* Using a different personality function name causes link failures + when trying to mix code using different exception handling models. */ +#ifdef SJLJ_EXCEPTIONS +#define PERSONALITY_FUNCTION __gnu_objc_personality_sj0 +#define __builtin_eh_return_data_regno(x) x +#else +#define PERSONALITY_FUNCTION __gnu_objc_personality_v0 +#endif + +_Unwind_Reason_Code +PERSONALITY_FUNCTION (int version, + _Unwind_Action actions, + _Unwind_Exception_Class exception_class, + struct _Unwind_Exception *ue_header, + struct _Unwind_Context *context) +{ + struct ObjcException *xh = (struct ObjcException *) ue_header; + + struct lsda_header_info info; + const unsigned char *language_specific_data; + const unsigned char *action_record; + const unsigned char *p; + _Unwind_Ptr landing_pad, ip; + int handler_switch_value; + int saw_cleanup = 0, saw_handler; + void *return_object; + + /* Interface version check. */ + if (version != 1) + return _URC_FATAL_PHASE1_ERROR; + + /* Shortcut for phase 2 found handler for domestic exception. */ + if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) + && exception_class == __objc_exception_class) + { + handler_switch_value = xh->handlerSwitchValue; + landing_pad = xh->landingPad; + goto install_context; + } + + language_specific_data = (const unsigned char *) + _Unwind_GetLanguageSpecificData (context); + + /* If no LSDA, then there are no handlers or cleanups. */ + if (! language_specific_data) + return _URC_CONTINUE_UNWIND; + + /* Parse the LSDA header. */ + p = parse_lsda_header (context, language_specific_data, &info); + info.ttype_base = base_of_encoded_value (info.ttype_encoding, context); + ip = _Unwind_GetIP (context) - 1; + landing_pad = 0; + action_record = 0; + handler_switch_value = 0; + +#ifdef SJLJ_EXCEPTIONS + /* The given "IP" is an index into the call-site table, with two + exceptions -- -1 means no-action, and 0 means terminate. But + since we're using uleb128 values, we've not got random access + to the array. */ + if ((int) ip < 0) + return _URC_CONTINUE_UNWIND; + else + { + _Unwind_Word cs_lp, cs_action; + do + { + p = read_uleb128 (p, &cs_lp); + p = read_uleb128 (p, &cs_action); + } + while (--ip); + + /* Can never have null landing pad for sjlj -- that would have + been indicated by a -1 call site index. */ + landing_pad = cs_lp + 1; + if (cs_action) + action_record = info.action_table + cs_action - 1; + goto found_something; + } +#else + /* Search the call-site table for the action associated with this IP. */ + while (p < info.action_table) + { + _Unwind_Ptr cs_start, cs_len, cs_lp; + _Unwind_Word cs_action; + + /* Note that all call-site encodings are "absolute" displacements. */ + p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); + p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); + p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); + p = read_uleb128 (p, &cs_action); + + /* The table is sorted, so if we've passed the ip, stop. */ + if (ip < info.Start + cs_start) + p = info.action_table; + else if (ip < info.Start + cs_start + cs_len) + { + if (cs_lp) + landing_pad = info.LPStart + cs_lp; + if (cs_action) + action_record = info.action_table + cs_action - 1; + goto found_something; + } + } +#endif /* SJLJ_EXCEPTIONS */ + + /* If ip is not present in the table, C++ would call terminate. */ + /* ??? As with Java, it's perhaps better to tweek the LSDA to + that no-action is mapped to no-entry. */ + return _URC_CONTINUE_UNWIND; + + found_something: + saw_cleanup = 0; + saw_handler = 0; + + if (landing_pad == 0) + { + /* If ip is present, and has a null landing pad, there are + no cleanups or handlers to be run. */ + } + else if (action_record == 0) + { + /* If ip is present, has a non-null landing pad, and a null + action table offset, then there are only cleanups present. + Cleanups use a zero switch value, as set above. */ + saw_cleanup = 1; + } + else + { + /* Otherwise we have a catch handler. */ + _Unwind_Sword ar_filter, ar_disp; + + while (1) + { + p = action_record; + p = read_sleb128 (p, &ar_filter); + read_sleb128 (p, &ar_disp); + + if (ar_filter == 0) + { + /* Zero filter values are cleanups. */ + saw_cleanup = 1; + } + + /* During forced unwinding, we only run cleanups. With a + foreign exception class, we have no class info to match. */ + else if ((actions & _UA_FORCE_UNWIND) + || exception_class != __objc_exception_class) + ; + + else if (ar_filter > 0) + { + /* Positive filter values are handlers. */ + + Class catch_type = get_ttype_entry (&info, ar_filter); + + if (isKindOf (xh->value, catch_type)) + { + handler_switch_value = ar_filter; + saw_handler = 1; + break; + } + } + else + { + /* Negative filter values are exception specifications, + which Objective-C does not use. */ + abort (); + } + + if (ar_disp == 0) + break; + action_record = p + ar_disp; + } + } + + if (! saw_handler && ! saw_cleanup) + return _URC_CONTINUE_UNWIND; + + if (actions & _UA_SEARCH_PHASE) + { + if (!saw_handler) + return _URC_CONTINUE_UNWIND; + + /* For domestic exceptions, we cache data from phase 1 for phase 2. */ + if (exception_class == __objc_exception_class) + { + xh->handlerSwitchValue = handler_switch_value; + xh->landingPad = landing_pad; + } + return _URC_HANDLER_FOUND; + } + + install_context: + if (saw_cleanup == 0) + { + return_object = xh->value; + if (!(actions & _UA_SEARCH_PHASE)) + _Unwind_DeleteException(&xh->base); + } + + _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), + __builtin_extend_pointer (saw_cleanup ? xh : return_object)); + _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), + handler_switch_value); + _Unwind_SetIP (context, landing_pad); + return _URC_INSTALL_CONTEXT; +} + +static void +__objc_exception_cleanup (_Unwind_Reason_Code code __attribute__((unused)), + struct _Unwind_Exception *exc) +{ + free (exc); +} + +void +objc_exception_throw (id value) +{ + struct ObjcException *header = calloc (1, sizeof (*header)); + header->base.exception_class = __objc_exception_class; + header->base.exception_cleanup = __objc_exception_cleanup; + header->value = value; + +#ifdef SJLJ_EXCEPTIONS + _Unwind_SjLj_RaiseException (&header->base); +#else + _Unwind_RaiseException (&header->base); +#endif + + /* Some sort of unwinding error. */ + abort (); +} diff --git a/contrib/gcc-4.1/libobjc/gc.c b/contrib/gcc-4.1/libobjc/gc.c new file mode 100644 index 0000000000..9bb11fc478 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/gc.c @@ -0,0 +1,450 @@ +/* Basic data types for Objective C. + Copyright (C) 1998, 2002 Free Software Foundation, Inc. + Contributed by Ovidiu Predescu. + +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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#include "tconfig.h" +#include "objc/objc.h" +#include "objc/encoding.h" + +#include +#include +#include + +#if OBJC_WITH_GC + +#include +#include + +/* gc_typed.h uses the following but doesn't declare them */ +typedef GC_word word; +typedef GC_signed_word signed_word; +#define BITS_PER_WORD (CHAR_BIT * sizeof (word)) + +#include + +/* The following functions set up in `mask` the corresponding pointers. + The offset is incremented with the size of the type. */ + +#define ROUND(V, A) \ + ({ typeof (V) __v = (V); typeof (A) __a = (A); \ + __a * ((__v+__a - 1)/__a); }) + +#define SET_BIT_FOR_OFFSET(mask, offset) \ + GC_set_bit (mask, offset / sizeof (void *)) + +/* Some prototypes */ +static void +__objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset); +static void +__objc_gc_setup_union (GC_bitmap mask, const char *type, int offset); + + +static void +__objc_gc_setup_array (GC_bitmap mask, const char *type, int offset) +{ + int i, len = atoi (type + 1); + + while (isdigit (*++type)) + /* do nothing */; /* skip the size of the array */ + + switch (*type) { + case _C_ARY_B: + for (i = 0; i < len; i++) + __objc_gc_setup_array (mask, type, offset); + break; + + case _C_STRUCT_B: + for (i = 0; i < len; i++) + __objc_gc_setup_struct (mask, type, offset); + break; + + case _C_UNION_B: + for (i = 0; i < len; i++) + __objc_gc_setup_union (mask, type, offset); + break; + + default: + break; + } +} + +static void +__objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset) +{ + struct objc_struct_layout layout; + unsigned int position; + const char *mtype; + + objc_layout_structure (type, &layout); + + while (objc_layout_structure_next_member (&layout)) + { + BOOL gc_invisible = NO; + + objc_layout_structure_get_info (&layout, &position, NULL, &mtype); + + /* Skip the variable name */ + if (*mtype == '"') + { + for (mtype++; *mtype++ != '"';) + /* do nothing */; + } + + if (*mtype == _C_GCINVISIBLE) + { + gc_invisible = YES; + mtype++; + } + + /* Add to position the offset of this structure */ + position += offset; + + switch (*mtype) { + case _C_ID: + case _C_CLASS: + case _C_SEL: + case _C_PTR: + case _C_CHARPTR: + case _C_ATOM: + if (! gc_invisible) + SET_BIT_FOR_OFFSET (mask, position); + break; + + case _C_ARY_B: + __objc_gc_setup_array (mask, mtype, position); + break; + + case _C_STRUCT_B: + __objc_gc_setup_struct (mask, mtype, position); + break; + + case _C_UNION_B: + __objc_gc_setup_union (mask, mtype, position); + break; + + default: + break; + } + } +} + +static void +__objc_gc_setup_union (GC_bitmap mask, const char *type, int offset) +{ + /* Sub-optimal, quick implementation: assume the union is made of + pointers, set up the mask accordingly. */ + + int i, size, align; + + /* Skip the variable name */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + size = objc_sizeof_type (type); + align = objc_alignof_type (type); + + offset = ROUND (offset, align); + for (i = 0; i < size; i += sizeof (void *)) + { + SET_BIT_FOR_OFFSET (mask, offset); + offset += sizeof (void *); + } +} + + +/* Iterates over the types in the structure that represents the class + encoding and sets the bits in mask according to each ivar type. */ +static void +__objc_gc_type_description_from_type (GC_bitmap mask, const char *type) +{ + struct objc_struct_layout layout; + unsigned int offset, align; + const char *ivar_type; + + objc_layout_structure (type, &layout); + + while (objc_layout_structure_next_member (&layout)) + { + BOOL gc_invisible = NO; + + objc_layout_structure_get_info (&layout, &offset, &align, &ivar_type); + + /* Skip the variable name */ + if (*ivar_type == '"') + { + for (ivar_type++; *ivar_type++ != '"';) + /* do nothing */; + } + + if (*ivar_type == _C_GCINVISIBLE) + { + gc_invisible = YES; + ivar_type++; + } + + switch (*ivar_type) { + case _C_ID: + case _C_CLASS: + case _C_SEL: + case _C_PTR: + case _C_CHARPTR: + if (! gc_invisible) + SET_BIT_FOR_OFFSET (mask, offset); + break; + + case _C_ARY_B: + __objc_gc_setup_array (mask, ivar_type, offset); + break; + + case _C_STRUCT_B: + __objc_gc_setup_struct (mask, ivar_type, offset); + break; + + case _C_UNION_B: + __objc_gc_setup_union (mask, ivar_type, offset); + break; + + default: + break; + } + } +} + +/* Computes in *type the full type encoding of this class including + its super classes. '*size' gives the total number of bytes allocated + into *type, '*current' the number of bytes used so far by the + encoding. */ +static void +__objc_class_structure_encoding (Class class, char **type, int *size, + int *current) +{ + int i, ivar_count; + struct objc_ivar_list *ivars; + + if (! class) + { + strcat (*type, "{"); + *current++; + return; + } + + /* Add the type encodings of the super classes */ + __objc_class_structure_encoding (class->super_class, type, size, current); + + ivars = class->ivars; + if (! ivars) + return; + + ivar_count = ivars->ivar_count; + + for (i = 0; i < ivar_count; i++) + { + struct objc_ivar *ivar = &(ivars->ivar_list[i]); + const char *ivar_type = ivar->ivar_type; + int len = strlen (ivar_type); + + if (*current + len + 1 >= *size) + { + /* Increase the size of the encoding string so that it + contains this ivar's type. */ + *size = ROUND (*current + len + 1, 10); + *type = objc_realloc (*type, *size); + } + strcat (*type + *current, ivar_type); + *current += len; + } +} + + +/* Allocates the memory that will hold the type description for class + and calls the __objc_class_structure_encoding that generates this + value. */ +void +__objc_generate_gc_type_description (Class class) +{ + GC_bitmap mask; + int bits_no, size; + int type_size = 10, current; + char *class_structure_type; + + if (! CLS_ISCLASS (class)) + return; + + /* We have to create a mask in which each bit counts for a pointer member. + We take into consideration all the non-pointer instance variables and we + round them up to the alignment. */ + + /* The number of bits in the mask is the size of an instance in bytes divided + by the size of a pointer. */ + bits_no = (ROUND (class_get_instance_size (class), sizeof (void *)) + / sizeof (void *)); + size = ROUND (bits_no, BITS_PER_WORD) / BITS_PER_WORD; + mask = objc_atomic_malloc (size * sizeof (int)); + memset (mask, 0, size * sizeof (int)); + + class_structure_type = objc_atomic_malloc (type_size); + *class_structure_type = current = 0; + __objc_class_structure_encoding (class, &class_structure_type, + &type_size, ¤t); + if (current + 1 == type_size) + class_structure_type = objc_realloc (class_structure_type, ++type_size); + strcat (class_structure_type + current, "}"); +#ifdef DEBUG + printf ("type description for '%s' is %s\n", class->name, class_structure_type); +#endif + + __objc_gc_type_description_from_type (mask, class_structure_type); + objc_free (class_structure_type); + +#ifdef DEBUG + printf (" mask for '%s', type '%s' (bits %d, mask size %d) is:", + class_structure_type, class->name, bits_no, size); + { + int i; + for (i = 0; i < size; i++) + printf (" %lx", mask[i]); + } + puts (""); +#endif + + class->gc_object_type = (void *) GC_make_descriptor (mask, bits_no); +} + + +/* Returns YES if type denotes a pointer type, NO otherwise */ +static inline BOOL +__objc_ivar_pointer (const char *type) +{ + type = objc_skip_type_qualifiers (type); + + return (*type == _C_ID + || *type == _C_CLASS + || *type == _C_SEL + || *type == _C_PTR + || *type == _C_CHARPTR + || *type == _C_ATOM); +} + + +/* Mark the instance variable whose name is given by ivarname as a + weak pointer (a pointer hidden to the garbage collector) if + gc_invisible is true. If gc_invisible is false it unmarks the + instance variable and makes it a normal pointer, visible to the + garbage collector. + + This operation only makes sense on instance variables that are + pointers. */ +void +class_ivar_set_gcinvisible (Class class, const char *ivarname, + BOOL gc_invisible) +{ + int i, ivar_count; + struct objc_ivar_list *ivars; + + if (! class || ! ivarname) + return; + + ivars = class->ivars; + if (! ivars) + return; + + ivar_count = ivars->ivar_count; + + for (i = 0; i < ivar_count; i++) + { + struct objc_ivar *ivar = &(ivars->ivar_list[i]); + const char *type; + + if (! ivar->ivar_name || strcmp (ivar->ivar_name, ivarname)) + continue; + + assert (ivar->ivar_type); + type = ivar->ivar_type; + + /* Skip the variable name */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + if (*type == _C_GCINVISIBLE) + { + char *new_type; + + if (gc_invisible || ! __objc_ivar_pointer (type)) + return; /* The type of the variable already matches the + requested gc_invisible type */ + + /* The variable is gc_invisible and we have to reverse it */ + new_type = objc_atomic_malloc (strlen (ivar->ivar_type)); + strncpy (new_type, ivar->ivar_type, + (size_t)(type - ivar->ivar_type)); + strcat (new_type, type + 1); + ivar->ivar_type = new_type; + } + else + { + char *new_type; + + if (! gc_invisible || ! __objc_ivar_pointer (type)) + return; /* The type of the variable already matches the + requested gc_invisible type */ + + /* The variable is gc visible and we have to make it gc_invisible */ + new_type = objc_malloc (strlen (ivar->ivar_type) + 2); + strncpy (new_type, ivar->ivar_type, + (size_t)(type - ivar->ivar_type)); + strcat (new_type, "!"); + strcat (new_type, type); + ivar->ivar_type = new_type; + } + + __objc_generate_gc_type_description (class); + return; + } + + /* Search the instance variable in the superclasses */ + class_ivar_set_gcinvisible (class->super_class, ivarname, gc_invisible); +} + +#else /* !OBJC_WITH_GC */ + +void +__objc_generate_gc_type_description (Class class __attribute__ ((__unused__))) +{ +} + +void class_ivar_set_gcinvisible (Class class __attribute__ ((__unused__)), + const char *ivarname __attribute__ ((__unused__)), + BOOL gc_invisible __attribute__ ((__unused__))) +{ +} + +#endif /* OBJC_WITH_GC */ diff --git a/contrib/gcc-4.1/libobjc/hash.c b/contrib/gcc-4.1/libobjc/hash.c new file mode 100644 index 0000000000..969bd45856 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/hash.c @@ -0,0 +1,283 @@ +/* Hash tables for Objective C internal structures + Copyright (C) 1993, 1996, 1997, 2004 Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#include "assert.h" + +#include "objc/hash.h" + +#include "objc/runtime.h" /* for DEBUG_PRINTF */ + +/* These two macros determine when a hash table is full and + by how much it should be expanded respectively. + + These equations are percentages. */ +#define FULLNESS(cache) \ + ((((cache)->size * 75) / 100) <= (cache)->used) +#define EXPANSION(cache) \ + ((cache)->size * 2) + +cache_ptr +objc_hash_new (unsigned int size, hash_func_type hash_func, + compare_func_type compare_func) +{ + cache_ptr cache; + + /* Pass me a value greater than 0 and a power of 2. */ + assert (size); + assert (! (size & (size - 1))); + + /* Allocate the cache structure. calloc insures + its initialization for default values. */ + cache = (cache_ptr) objc_calloc (1, sizeof (struct cache)); + assert (cache); + + /* Allocate the array of buckets for the cache. + calloc initializes all of the pointers to NULL. */ + cache->node_table + = (node_ptr *) objc_calloc (size, sizeof (node_ptr)); + assert (cache->node_table); + + cache->size = size; + + /* This should work for all processor architectures? */ + cache->mask = (size - 1); + + /* Store the hashing function so that codes can be computed. */ + cache->hash_func = hash_func; + + /* Store the function that compares hash keys to + determine if they are equal. */ + cache->compare_func = compare_func; + + return cache; +} + + +void +objc_hash_delete (cache_ptr cache) +{ + node_ptr node; + node_ptr next_node; + unsigned int i; + + /* Purge all key/value pairs from the table. */ + /* Step through the nodes one by one and remove every node WITHOUT + using objc_hash_next. this makes objc_hash_delete much more efficient. */ + for (i = 0;i < cache->size;i++) { + if ((node = cache->node_table[i])) { + /* an entry in the hash table has been found, now step through the + nodes next in the list and free them. */ + while ((next_node = node->next)) { + objc_hash_remove (cache,node->key); + node = next_node; + } + + objc_hash_remove (cache,node->key); + } + } + + /* Release the array of nodes and the cache itself. */ + objc_free(cache->node_table); + objc_free(cache); +} + + +void +objc_hash_add (cache_ptr *cachep, const void *key, void *value) +{ + size_t indx = (*(*cachep)->hash_func)(*cachep, key); + node_ptr node = (node_ptr) objc_calloc (1, sizeof (struct cache_node)); + + + assert (node); + + /* Initialize the new node. */ + node->key = key; + node->value = value; + node->next = (*cachep)->node_table[indx]; + + /* Debugging. + Check the list for another key. */ +#ifdef DEBUG + { node_ptr node1 = (*cachep)->node_table[indx]; + + while (node1) { + + assert (node1->key != key); + node1 = node1->next; + } + } +#endif + + /* Install the node as the first element on the list. */ + (*cachep)->node_table[indx] = node; + + /* Bump the number of entries in the cache. */ + ++(*cachep)->used; + + /* Check the hash table's fullness. We're going + to expand if it is above the fullness level. */ + if (FULLNESS (*cachep)) { + + /* The hash table has reached its fullness level. Time to + expand it. + + I'm using a slow method here but is built on other + primitive functions thereby increasing its + correctness. */ + node_ptr node1 = NULL; + cache_ptr new = objc_hash_new (EXPANSION (*cachep), + (*cachep)->hash_func, + (*cachep)->compare_func); + + DEBUG_PRINTF ("Expanding cache %#x from %d to %d\n", + (int) *cachep, (*cachep)->size, new->size); + + /* Copy the nodes from the first hash table to the new one. */ + while ((node1 = objc_hash_next (*cachep, node1))) + objc_hash_add (&new, node1->key, node1->value); + + /* Trash the old cache. */ + objc_hash_delete (*cachep); + + /* Return a pointer to the new hash table. */ + *cachep = new; + } +} + + +void +objc_hash_remove (cache_ptr cache, const void *key) +{ + size_t indx = (*cache->hash_func)(cache, key); + node_ptr node = cache->node_table[indx]; + + + /* We assume there is an entry in the table. Error if it is not. */ + assert (node); + + /* Special case. First element is the key/value pair to be removed. */ + if ((*cache->compare_func)(node->key, key)) { + cache->node_table[indx] = node->next; + objc_free(node); + } else { + + /* Otherwise, find the hash entry. */ + node_ptr prev = node; + BOOL removed = NO; + + do { + + if ((*cache->compare_func)(node->key, key)) { + prev->next = node->next, removed = YES; + objc_free(node); + } else + prev = node, node = node->next; + } while (! removed && node); + assert (removed); + } + + /* Decrement the number of entries in the hash table. */ + --cache->used; +} + + +node_ptr +objc_hash_next (cache_ptr cache, node_ptr node) +{ + /* If the scan is being started then reset the last node + visitied pointer and bucket index. */ + if (! node) + cache->last_bucket = 0; + + /* If there is a node visited last then check for another + entry in the same bucket; Otherwise step to the next bucket. */ + if (node) { + if (node->next) + /* There is a node which follows the last node + returned. Step to that node and retun it. */ + return node->next; + else + ++cache->last_bucket; + } + + /* If the list isn't exhausted then search the buckets for + other nodes. */ + if (cache->last_bucket < cache->size) { + /* Scan the remainder of the buckets looking for an entry + at the head of the list. Return the first item found. */ + while (cache->last_bucket < cache->size) + if (cache->node_table[cache->last_bucket]) + return cache->node_table[cache->last_bucket]; + else + ++cache->last_bucket; + + /* No further nodes were found in the hash table. */ + return NULL; + } else + return NULL; +} + + +/* Given KEY, return corresponding value for it in CACHE. + Return NULL if the KEY is not recorded. */ + +void * +objc_hash_value_for_key (cache_ptr cache, const void *key) +{ + node_ptr node = cache->node_table[(*cache->hash_func)(cache, key)]; + void *retval = NULL; + + if (node) + do { + if ((*cache->compare_func)(node->key, key)) { + retval = node->value; + break; + } else + node = node->next; + } while (! retval && node); + + return retval; +} + +/* Given KEY, return YES if it exists in the CACHE. + Return NO if it does not */ + +BOOL +objc_hash_is_key_in_hash (cache_ptr cache, const void *key) +{ + node_ptr node = cache->node_table[(*cache->hash_func)(cache, key)]; + + if (node) + do { + if ((*cache->compare_func)(node->key, key)) + return YES; + else + node = node->next; + } while (node); + + return NO; +} diff --git a/contrib/gcc-4.1/libobjc/hash_compat.c b/contrib/gcc-4.1/libobjc/hash_compat.c new file mode 100644 index 0000000000..b04eee6d43 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/hash_compat.c @@ -0,0 +1,97 @@ +/* Binary compatibility hash implementations for Objective C. + Copyright (C) 2005 Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#define OBJC_IGNORE_DEPRECATED_API 1 +#include "objc/hash.h" + +cache_ptr +hash_new (unsigned int size, + hash_func_type hash_func, + compare_func_type compare_func) +{ + return objc_hash_new(size, hash_func, compare_func); +} + +void +hash_delete(cache_ptr cache) +{ + objc_hash_delete(cache); +} + +void +hash_add (cache_ptr *cachep, const void *key, void *value) +{ + objc_hash_add(cachep, key, value); +} + +void +hash_remove (cache_ptr cache, const void *key) +{ + objc_hash_remove (cache, key); +} + +node_ptr +hash_next (cache_ptr cache, node_ptr node) +{ + return objc_hash_next (cache, node); +} + +void * +hash_value_for_key (cache_ptr cache, const void *key) +{ + return objc_hash_value_for_key (cache, key); +} + +BOOL +hash_is_key_in_hash (cache_ptr cache, const void *key) +{ + return objc_hash_is_key_in_hash (cache, key); +} + +unsigned int +hash_ptr (cache_ptr cache, const void *key) +{ + return objc_hash_ptr (cache, key); +} + +unsigned int +hash_string (cache_ptr cache, const void *key) +{ + return objc_hash_string (cache, key); +} + +int +compare_ptrs (const void *k1, const void *k2) +{ + return objc_compare_ptrs (k1, k2); +} + +int +compare_strings (const void *k1, const void *k2) +{ + return objc_compare_strings (k1, k2); +} + diff --git a/contrib/gcc-4.1/libobjc/init.c b/contrib/gcc-4.1/libobjc/init.c new file mode 100644 index 0000000000..fc3d7ff3c0 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/init.c @@ -0,0 +1,894 @@ +/* GNU Objective C Runtime initialization + Copyright (C) 1993, 1995, 1996, 1997, 2002 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +load support contributed by Ovidiu Predescu + +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 2, 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 COPYING. If not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "objc/runtime.h" + +/* The version number of this runtime. This must match the number + defined in gcc (objc-act.c). */ +#define OBJC_VERSION 8 +#define PROTOCOL_VERSION 2 + +/* This list contains all modules currently loaded into the runtime. */ +static struct objc_list *__objc_module_list = 0; /* !T:MUTEX */ + +/* This list contains all proto_list's not yet assigned class links. */ +static struct objc_list *unclaimed_proto_list = 0; /* !T:MUTEX */ + +/* List of unresolved static instances. */ +static struct objc_list *uninitialized_statics = 0; /* !T:MUTEX */ + +/* Global runtime "write" mutex. */ +objc_mutex_t __objc_runtime_mutex = 0; + +/* Number of threads that are alive. */ +int __objc_runtime_threads_alive = 1; /* !T:MUTEX */ + +/* Check compiler vs runtime version. */ +static void init_check_module_version (Module_t); + +/* Assign isa links to protos. */ +static void __objc_init_protocols (struct objc_protocol_list *protos); + +/* Add protocol to class. */ +static void __objc_class_add_protocols (Class, struct objc_protocol_list *); + +/* This is a hook which is called by __objc_exec_class every time a + class or a category is loaded into the runtime. This may e.g. help + a dynamic loader determine the classes that have been loaded when + an object file is dynamically linked in. */ +void (*_objc_load_callback) (Class class, Category *category); /* !T:SAFE */ + +/* Is all categories/classes resolved? */ +BOOL __objc_dangling_categories = NO; /* !T:UNUSED */ + +extern SEL +__sel_register_typed_name (const char *name, const char *types, + struct objc_selector *orig, BOOL is_const); + +/* Sends +load to all classes and categories in certain situations. */ +static void objc_send_load (void); + +/* Inserts all the classes defined in module in a tree of classes that + resembles the class hierarchy. This tree is traversed in preorder + and the classes in its nodes receive the +load message if these + methods were not executed before. The algorithm ensures that when + the +load method of a class is executed all the superclasses have + been already received the +load message. */ +static void __objc_create_classes_tree (Module_t module); + +static void __objc_call_callback (Module_t module); + +/* A special version that works only before the classes are completely + installed in the runtime. */ +static BOOL class_is_subclass_of_class (Class class, Class superclass); + +typedef struct objc_class_tree { + Class class; + struct objc_list *subclasses; /* `head' is pointer to an objc_class_tree */ +} objc_class_tree; + +/* This is a linked list of objc_class_tree trees. The head of these + trees are root classes (their super class is Nil). These different + trees represent different class hierarchies. */ +static struct objc_list *__objc_class_tree_list = NULL; + +/* Keeps the +load methods who have been already executed. This hash + should not be destroyed during the execution of the program. */ +static cache_ptr __objc_load_methods = NULL; + +/* This function is used when building the class tree used to send + ordinately the +load message to all classes needing it. The tree + is really needed so that superclasses will get the message before + subclasses. + + This tree will contain classes which are being loaded (or have just + being loaded), and whose super_class pointers have not yet been + resolved. This implies that their super_class pointers point to a + string with the name of the superclass; when the first message is + sent to the class (/an object of that class) the class links will + be resolved, which will replace the super_class pointers with + pointers to the actual superclasses. + + Unfortunately, the tree might also contain classes which had been + loaded previously, and whose class links have already been + resolved. + + This function returns the superclass of a class in both cases, and + can be used to build the determine the class relationships while + building the tree. +*/ +static Class class_superclass_of_class (Class class) +{ + char *super_class_name; + + /* If the class links have been resolved, use the resolved + * links. */ + if (CLS_ISRESOLV (class)) + return class->super_class; + + /* Else, 'class' has not yet been resolved. This means that its + * super_class pointer is really the name of the super class (rather + * than a pointer to the actual superclass). */ + super_class_name = (char *)class->super_class; + + /* Return Nil for a root class. */ + if (super_class_name == NULL) + return Nil; + + /* Lookup the superclass of non-root classes. */ + return objc_lookup_class (super_class_name); +} + + +/* Creates a tree of classes whose topmost class is directly inherited + from `upper' and the bottom class in this tree is + `bottom_class'. The classes in this tree are super classes of + `bottom_class'. `subclasses' member of each tree node point to the + next subclass tree node. */ + +static objc_class_tree * +create_tree_of_subclasses_inherited_from (Class bottom_class, Class upper) +{ + Class superclass = bottom_class->super_class ? + objc_lookup_class ((char *) bottom_class->super_class) + : Nil; + + objc_class_tree *tree, *prev; + + DEBUG_PRINTF ("create_tree_of_subclasses_inherited_from:"); + DEBUG_PRINTF ("bottom_class = %s, upper = %s\n", + (bottom_class ? bottom_class->name : NULL), + (upper ? upper->name : NULL)); + + tree = prev = objc_calloc (1, sizeof (objc_class_tree)); + prev->class = bottom_class; + + while (superclass != upper) + { + tree = objc_calloc (1, sizeof (objc_class_tree)); + tree->class = superclass; + tree->subclasses = list_cons (prev, tree->subclasses); + superclass = class_superclass_of_class (superclass); + prev = tree; + } + + return tree; +} + +/* Insert the `class' into the proper place in the `tree' class + hierarchy. This function returns a new tree if the class has been + successfully inserted into the tree or NULL if the class is not + part of the classes hierarchy described by `tree'. This function is + private to objc_tree_insert_class (), you should not call it + directly. */ + +static objc_class_tree * +__objc_tree_insert_class (objc_class_tree *tree, Class class) +{ + DEBUG_PRINTF ("__objc_tree_insert_class: tree = %x, class = %s\n", + tree, class->name); + + if (tree == NULL) + return create_tree_of_subclasses_inherited_from (class, NULL); + else if (class == tree->class) + { + /* `class' has been already inserted */ + DEBUG_PRINTF ("1. class %s was previously inserted\n", class->name); + return tree; + } + else if (class_superclass_of_class (class) == tree->class) + { + /* If class is a direct subclass of tree->class then add class to the + list of subclasses. First check to see if it wasn't already + inserted. */ + struct objc_list *list = tree->subclasses; + objc_class_tree *node; + + while (list) + { + /* Class has been already inserted; do nothing just return + the tree. */ + if (((objc_class_tree *) list->head)->class == class) + { + DEBUG_PRINTF ("2. class %s was previously inserted\n", + class->name); + return tree; + } + list = list->tail; + } + + /* Create a new node class and insert it into the list of subclasses */ + node = objc_calloc (1, sizeof (objc_class_tree)); + node->class = class; + tree->subclasses = list_cons (node, tree->subclasses); + DEBUG_PRINTF ("3. class %s inserted\n", class->name); + return tree; + } + else + { + /* The class is not a direct subclass of tree->class. Search for + class's superclasses in the list of subclasses. */ + struct objc_list *subclasses = tree->subclasses; + + /* Precondition: the class must be a subclass of tree->class; + otherwise return NULL to indicate our caller that it must + take the next tree. */ + if (! class_is_subclass_of_class (class, tree->class)) + return NULL; + + for (; subclasses != NULL; subclasses = subclasses->tail) + { + Class aClass = ((objc_class_tree *) (subclasses->head))->class; + + if (class_is_subclass_of_class (class, aClass)) + { + /* If we found one of class's superclasses we insert the + class into its subtree and return the original tree + since nothing has been changed. */ + subclasses->head + = __objc_tree_insert_class (subclasses->head, class); + DEBUG_PRINTF ("4. class %s inserted\n", class->name); + return tree; + } + } + + /* We haven't found a subclass of `class' in the `subclasses' + list. Create a new tree of classes whose topmost class is a + direct subclass of tree->class. */ + { + objc_class_tree *new_tree + = create_tree_of_subclasses_inherited_from (class, tree->class); + tree->subclasses = list_cons (new_tree, tree->subclasses); + DEBUG_PRINTF ("5. class %s inserted\n", class->name); + return tree; + } + } +} + +/* This function inserts `class' in the right tree hierarchy classes. */ + +static void +objc_tree_insert_class (Class class) +{ + struct objc_list *list_node; + objc_class_tree *tree; + + list_node = __objc_class_tree_list; + while (list_node) + { + tree = __objc_tree_insert_class (list_node->head, class); + if (tree) + { + list_node->head = tree; + break; + } + else + list_node = list_node->tail; + } + + /* If the list was finished but the class hasn't been inserted, + insert it here. */ + if (! list_node) + { + __objc_class_tree_list = list_cons (NULL, __objc_class_tree_list); + __objc_class_tree_list->head = __objc_tree_insert_class (NULL, class); + } +} + +/* Traverse tree in preorder. Used to send +load. */ + +static void +objc_preorder_traverse (objc_class_tree *tree, + int level, + void (*function) (objc_class_tree *, int)) +{ + struct objc_list *node; + + (*function) (tree, level); + for (node = tree->subclasses; node; node = node->tail) + objc_preorder_traverse (node->head, level + 1, function); +} + +/* Traverse tree in postorder. Used to destroy a tree. */ + +static void +objc_postorder_traverse (objc_class_tree *tree, + int level, + void (*function) (objc_class_tree *, int)) +{ + struct objc_list *node; + + for (node = tree->subclasses; node; node = node->tail) + objc_postorder_traverse (node->head, level + 1, function); + (*function) (tree, level); +} + +/* Used to print a tree class hierarchy. */ + +#ifdef DEBUG +static void +__objc_tree_print (objc_class_tree *tree, int level) +{ + int i; + + for (i = 0; i < level; i++) + printf (" "); + printf ("%s\n", tree->class->name); +} +#endif + +/* Walks on a linked list of methods in the reverse order and executes + all the methods corresponding to `op' selector. Walking in the + reverse order assures the +load of class is executed first and then + +load of categories because of the way in which categories are + added to the class methods. */ + +static void +__objc_send_message_in_list (MethodList_t method_list, Class class, SEL op) +{ + int i; + + if (! method_list) + return; + + /* First execute the `op' message in the following method lists */ + __objc_send_message_in_list (method_list->method_next, class, op); + + /* Search the method list. */ + for (i = 0; i < method_list->method_count; i++) + { + Method_t mth = &method_list->method_list[i]; + + if (mth->method_name && sel_eq (mth->method_name, op) + && ! objc_hash_is_key_in_hash (__objc_load_methods, mth->method_imp)) + { + /* Add this method into the +load hash table */ + objc_hash_add (&__objc_load_methods, + mth->method_imp, + mth->method_imp); + + DEBUG_PRINTF ("sending +load in class: %s\n", class->name); + + /* The method was found and wasn't previously executed. */ + (*mth->method_imp) ((id)class, mth->method_name); + + break; + } + } +} + +static void +__objc_send_load (objc_class_tree *tree, + int level __attribute__ ((__unused__))) +{ + static SEL load_sel = 0; + Class class = tree->class; + MethodList_t method_list = class->class_pointer->methods; + + if (! load_sel) + load_sel = sel_register_name ("load"); + + __objc_send_message_in_list (method_list, class, load_sel); +} + +static void +__objc_destroy_class_tree_node (objc_class_tree *tree, + int level __attribute__ ((__unused__))) +{ + objc_free (tree); +} + +/* This is used to check if the relationship between two classes + before the runtime completely installs the classes. */ + +static BOOL +class_is_subclass_of_class (Class class, Class superclass) +{ + for (; class != Nil;) + { + if (class == superclass) + return YES; + class = class_superclass_of_class (class); + } + + return NO; +} + +/* This list contains all the classes in the runtime system for whom + their superclasses are not yet known to the runtime. */ +static struct objc_list *unresolved_classes = 0; + +/* Extern function used to reference the Object and NXConstantString + classes. */ + +extern void __objc_force_linking (void); + +void +__objc_force_linking (void) +{ + extern void __objc_linking (void); + __objc_linking (); +} + +/* Run through the statics list, removing modules as soon as all its + statics have been initialized. */ + +static void +objc_init_statics (void) +{ + struct objc_list **cell = &uninitialized_statics; + struct objc_static_instances **statics_in_module; + + objc_mutex_lock (__objc_runtime_mutex); + + while (*cell) + { + int module_initialized = 1; + + for (statics_in_module = (*cell)->head; + *statics_in_module; statics_in_module++) + { + struct objc_static_instances *statics = *statics_in_module; + Class class = objc_lookup_class (statics->class_name); + + if (! class) + module_initialized = 0; + /* Actually, the static's class_pointer will be NULL when we + haven't been here before. However, the comparison is to be + reminded of taking into account class posing and to think about + possible semantics... */ + else if (class != statics->instances[0]->class_pointer) + { + id *inst; + + for (inst = &statics->instances[0]; *inst; inst++) + { + (*inst)->class_pointer = class; + + /* ??? Make sure the object will not be freed. With + refcounting, invoke `-retain'. Without refcounting, do + nothing and hope that `-free' will never be invoked. */ + + /* ??? Send the object an `-initStatic' or something to + that effect now or later on? What are the semantics of + statically allocated instances, besides the trivial + NXConstantString, anyway? */ + } + } + } + if (module_initialized) + { + /* Remove this module from the uninitialized list. */ + struct objc_list *this = *cell; + *cell = this->tail; + objc_free (this); + } + else + cell = &(*cell)->tail; + } + + objc_mutex_unlock (__objc_runtime_mutex); +} /* objc_init_statics */ + +/* This function is called by constructor functions generated for each + module compiled. (_GLOBAL_$I$...) The purpose of this function is + to gather the module pointers so that they may be processed by the + initialization routines as soon as possible. */ + +void +__objc_exec_class (Module_t module) +{ + /* Have we processed any constructors previously? This flag is used to + indicate that some global data structures need to be built. */ + static BOOL previous_constructors = 0; + + static struct objc_list *unclaimed_categories = 0; + + /* The symbol table (defined in objc-api.h) generated by gcc */ + Symtab_t symtab = module->symtab; + + /* The statics in this module */ + struct objc_static_instances **statics + = symtab->defs[symtab->cls_def_cnt + symtab->cat_def_cnt]; + + /* Entry used to traverse hash lists */ + struct objc_list **cell; + + /* The table of selector references for this module */ + SEL selectors = symtab->refs; + + /* dummy counter */ + int i; + + DEBUG_PRINTF ("received module: %s\n", module->name); + + /* check gcc version */ + init_check_module_version (module); + + /* On the first call of this routine, initialize some data structures. */ + if (! previous_constructors) + { + /* Initialize thread-safe system */ + __objc_init_thread_system (); + __objc_runtime_threads_alive = 1; + __objc_runtime_mutex = objc_mutex_allocate (); + + __objc_init_selector_tables (); + __objc_init_class_tables (); + __objc_init_dispatch_tables (); + __objc_class_tree_list = list_cons (NULL, __objc_class_tree_list); + __objc_load_methods = objc_hash_new (128, + (hash_func_type)objc_hash_ptr, + objc_compare_ptrs); + previous_constructors = 1; + } + + /* Save the module pointer for later processing. (not currently used) */ + objc_mutex_lock (__objc_runtime_mutex); + __objc_module_list = list_cons (module, __objc_module_list); + + /* Replace referenced selectors from names to SEL's. */ + if (selectors) + { + for (i = 0; selectors[i].sel_id; ++i) + { + const char *name, *type; + name = (char *) selectors[i].sel_id; + type = (char *) selectors[i].sel_types; + /* Constructors are constant static data so we can safely store + pointers to them in the runtime structures. is_const == YES */ + __sel_register_typed_name (name, type, + (struct objc_selector *) &(selectors[i]), + YES); + } + } + + /* Parse the classes in the load module and gather selector information. */ + DEBUG_PRINTF ("gathering selectors from module: %s\n", module->name); + for (i = 0; i < symtab->cls_def_cnt; ++i) + { + Class class = (Class) symtab->defs[i]; + const char *superclass = (char *) class->super_class; + + /* Make sure we have what we think. */ + assert (CLS_ISCLASS (class)); + assert (CLS_ISMETA (class->class_pointer)); + DEBUG_PRINTF ("phase 1, processing class: %s\n", class->name); + + /* Initialize the subclass list to be NULL. + In some cases it isn't and this crashes the program. */ + class->subclass_list = NULL; + + /* Store the class in the class table and assign class numbers. */ + __objc_add_class_to_hash (class); + + /* Register all of the selectors in the class and meta class. */ + __objc_register_selectors_from_class (class); + __objc_register_selectors_from_class ((Class) class->class_pointer); + + /* Install the fake dispatch tables */ + __objc_install_premature_dtable (class); + __objc_install_premature_dtable (class->class_pointer); + + /* Register the instance methods as class methods, this is + only done for root classes. */ + __objc_register_instance_methods_to_class (class); + + if (class->protocols) + __objc_init_protocols (class->protocols); + + /* Check to see if the superclass is known in this point. If it's not + add the class to the unresolved_classes list. */ + if (superclass && ! objc_lookup_class (superclass)) + unresolved_classes = list_cons (class, unresolved_classes); + } + + /* Process category information from the module. */ + for (i = 0; i < symtab->cat_def_cnt; ++i) + { + Category_t category = symtab->defs[i + symtab->cls_def_cnt]; + Class class = objc_lookup_class (category->class_name); + + /* If the class for the category exists then append its methods. */ + if (class) + { + + DEBUG_PRINTF ("processing categories from (module,object): %s, %s\n", + module->name, + class->name); + + /* Do instance methods. */ + if (category->instance_methods) + class_add_method_list (class, category->instance_methods); + + /* Do class methods. */ + if (category->class_methods) + class_add_method_list ((Class) class->class_pointer, + category->class_methods); + + if (category->protocols) + { + __objc_init_protocols (category->protocols); + __objc_class_add_protocols (class, category->protocols); + } + + /* Register the instance methods as class methods, this is + only done for root classes. */ + __objc_register_instance_methods_to_class (class); + } + else + { + /* The object to which the category methods belong can't be found. + Save the information. */ + unclaimed_categories = list_cons (category, unclaimed_categories); + } + } + + if (statics) + uninitialized_statics = list_cons (statics, uninitialized_statics); + if (uninitialized_statics) + objc_init_statics (); + + /* Scan the unclaimed category hash. Attempt to attach any unclaimed + categories to objects. */ + for (cell = &unclaimed_categories; *cell; ) + { + Category_t category = (*cell)->head; + Class class = objc_lookup_class (category->class_name); + + if (class) + { + DEBUG_PRINTF ("attaching stored categories to object: %s\n", + class->name); + + list_remove_head (cell); + + if (category->instance_methods) + class_add_method_list (class, category->instance_methods); + + if (category->class_methods) + class_add_method_list ((Class) class->class_pointer, + category->class_methods); + + if (category->protocols) + { + __objc_init_protocols (category->protocols); + __objc_class_add_protocols (class, category->protocols); + } + + /* Register the instance methods as class methods, this is + only done for root classes. */ + __objc_register_instance_methods_to_class (class); + } + else + cell = &(*cell)->tail; + } + + if (unclaimed_proto_list && objc_lookup_class ("Protocol")) + { + list_mapcar (unclaimed_proto_list, + (void (*) (void *))__objc_init_protocols); + list_free (unclaimed_proto_list); + unclaimed_proto_list = 0; + } + + objc_send_load (); + + objc_mutex_unlock (__objc_runtime_mutex); +} + +static void +objc_send_load (void) +{ + if (! __objc_module_list) + return; + + /* Try to find out if all the classes loaded so far also have their + superclasses known to the runtime. We suppose that the objects + that are allocated in the +load method are in general of a class + declared in the same module. */ + if (unresolved_classes) + { + Class class = unresolved_classes->head; + + while (objc_lookup_class ((char *) class->super_class)) + { + list_remove_head (&unresolved_classes); + if (unresolved_classes) + class = unresolved_classes->head; + else + break; + } + + /* If we still have classes for whom we don't have yet their + super classes known to the runtime we don't send the +load + messages. */ + if (unresolved_classes) + return; + } + + /* Special check to allow creating and sending messages to constant + strings in +load methods. If these classes are not yet known, + even if all the other classes are known, delay sending of +load. */ + if (! objc_lookup_class ("NXConstantString") || + ! objc_lookup_class ("Object")) + return; + + /* Iterate over all modules in the __objc_module_list and call on + them the __objc_create_classes_tree function. This function + creates a tree of classes that resembles the class hierarchy. */ + list_mapcar (__objc_module_list, + (void (*) (void *)) __objc_create_classes_tree); + + while (__objc_class_tree_list) + { +#ifdef DEBUG + objc_preorder_traverse (__objc_class_tree_list->head, + 0, __objc_tree_print); +#endif + objc_preorder_traverse (__objc_class_tree_list->head, + 0, __objc_send_load); + objc_postorder_traverse (__objc_class_tree_list->head, + 0, __objc_destroy_class_tree_node); + list_remove_head (&__objc_class_tree_list); + } + + list_mapcar (__objc_module_list, (void (*) (void *)) __objc_call_callback); + list_free (__objc_module_list); + __objc_module_list = NULL; +} + +static void +__objc_create_classes_tree (Module_t module) +{ + /* The runtime mutex is locked in this point */ + + Symtab_t symtab = module->symtab; + int i; + + /* Iterate thru classes defined in this module and insert them in + the classes tree hierarchy. */ + for (i = 0; i < symtab->cls_def_cnt; i++) + { + Class class = (Class) symtab->defs[i]; + + objc_tree_insert_class (class); + } +} + +static void +__objc_call_callback (Module_t module) +{ + /* The runtime mutex is locked in this point. */ + + Symtab_t symtab = module->symtab; + int i; + + /* Iterate thru classes defined in this module and call the callback + for each one. */ + for (i = 0; i < symtab->cls_def_cnt; i++) + { + Class class = (Class) symtab->defs[i]; + + /* Call the _objc_load_callback for this class. */ + if (_objc_load_callback) + _objc_load_callback (class, 0); + } + + /* Call the _objc_load_callback for categories. Don't register the + instance methods as class methods for categories to root classes + since they were already added in the class. */ + for (i = 0; i < symtab->cat_def_cnt; i++) + { + Category_t category = symtab->defs[i + symtab->cls_def_cnt]; + Class class = objc_lookup_class (category->class_name); + + if (_objc_load_callback) + _objc_load_callback (class, category); + } +} + +/* Sanity check the version of gcc used to compile `module'. */ + +static void +init_check_module_version (Module_t module) +{ + if ((module->version != OBJC_VERSION) || (module->size != sizeof (Module))) + { + int code; + + if (module->version > OBJC_VERSION) + code = OBJC_ERR_OBJC_VERSION; + else if (module->version < OBJC_VERSION) + code = OBJC_ERR_GCC_VERSION; + else + code = OBJC_ERR_MODULE_SIZE; + + objc_error (nil, code, "Module %s version %d doesn't match runtime %d\n", + module->name, (int)module->version, OBJC_VERSION); + } +} + +static void +__objc_init_protocols (struct objc_protocol_list *protos) +{ + size_t i; + static Class proto_class = 0; + + if (! protos) + return; + + objc_mutex_lock (__objc_runtime_mutex); + + if (! proto_class) + proto_class = objc_lookup_class ("Protocol"); + + if (! proto_class) + { + unclaimed_proto_list = list_cons (protos, unclaimed_proto_list); + objc_mutex_unlock (__objc_runtime_mutex); + return; + } + +#if 0 + assert (protos->next == 0); /* only single ones allowed */ +#endif + + for (i = 0; i < protos->count; i++) + { + struct objc_protocol *aProto = protos->list[i]; + if (((size_t)aProto->class_pointer) == PROTOCOL_VERSION) + { + /* assign class pointer */ + aProto->class_pointer = proto_class; + + /* init super protocols */ + __objc_init_protocols (aProto->protocol_list); + } + else if (protos->list[i]->class_pointer != proto_class) + { + objc_error (nil, OBJC_ERR_PROTOCOL_VERSION, + "Version %d doesn't match runtime protocol version %d\n", + (int) ((char *) protos->list[i]->class_pointer + - (char *) 0), + PROTOCOL_VERSION); + } + } + + objc_mutex_unlock (__objc_runtime_mutex); +} + +static void +__objc_class_add_protocols (Class class, struct objc_protocol_list *protos) +{ + /* Well... */ + if (! protos) + return; + + /* Add it... */ + protos->next = class->protocols; + class->protocols = protos; +} diff --git a/contrib/gcc-4.1/libobjc/libobjc.def b/contrib/gcc-4.1/libobjc/libobjc.def new file mode 100644 index 0000000000..a80fb61558 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/libobjc.def @@ -0,0 +1,170 @@ +; GNU Objective C Runtime DLL Export Definitions +; Copyright (C) 1997 Free Software Foundation, Inc. +; Contributed by Scott Christley +; +; 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 2, 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 COPYING. If not, write to the Free Software +; Foundation, 51 Franklin Street, Fifth Floor, +; Boston, MA 02110-1301, USA. + +LIBRARY libobjc +EXPORTS +search_for_method_in_list +objc_get_uninstalled_dtable +objc_hash_is_key_in_hash +hash_is_key_in_hash +objc_verror +_objc_load_callback +objc_malloc +objc_atomic_malloc +objc_valloc +objc_realloc +objc_calloc +objc_free +__objc_init_thread_system +objc_mutex_allocate +objc_mutex_deallocate +objc_mutex_lock +objc_mutex_trylock +objc_mutex_unlock +objc_thread_detach +objc_thread_exit +objc_thread_get_data +objc_thread_get_priority +objc_thread_id +objc_thread_set_data +objc_thread_set_priority +objc_thread_yield +objc_thread_add +objc_thread_remove +__objc_class_name_Object +__objc_class_name_Protocol +__objc_class_name_NXConstantString +objc_error +__objc_object_alloc +__objc_object_copy +__objc_object_dispose +class_create_instance +object_copy +object_dispose +__objc_init_selector_tables +__objc_register_selectors_from_class +__sel_register_typed_name +sel_get_any_typed_uid +sel_get_any_uid +sel_get_name +sel_get_type +sel_get_typed_uid +sel_get_uid +sel_is_mapped +sel_register_name +sel_register_typed_name +sel_types_match +method_get_first_argument +method_get_next_argument +method_get_nth_argument +method_get_number_of_arguments +method_get_sizeof_arguments +objc_aligned_size +objc_alignof_type +objc_get_type_qualifiers +objc_promoted_size +objc_sizeof_type +objc_skip_argspec +objc_skip_offset +objc_skip_type_qualifiers +objc_skip_typespec +__objc_read_nbyte_uint +__objc_read_nbyte_ulong +__objc_write_class +__objc_write_object +__objc_write_selector +objc_close_typed_stream +objc_end_of_typed_stream +objc_flush_typed_stream +objc_get_stream_class_version +objc_open_typed_stream +objc_open_typed_stream_for_file +objc_read_array +objc_read_char +objc_read_int +objc_read_long +objc_read_object +objc_read_selector +objc_read_short +objc_read_string +objc_read_type +objc_read_types +objc_read_unsigned_char +objc_read_unsigned_int +objc_read_unsigned_long +objc_read_unsigned_short +objc_write_array +objc_write_char +objc_write_int +objc_write_long +objc_write_object +objc_write_object_reference +objc_write_root_object +objc_write_selector +objc_write_short +objc_write_string +objc_write_string_atomic +objc_write_type +objc_write_types +objc_write_unsigned_char +objc_write_unsigned_int +objc_write_unsigned_long +objc_write_unsigned_short +__objc_exec_class +__objc_init_dispatch_tables +__objc_install_premature_dtable +__objc_print_dtable_stats +__objc_responds_to +__objc_update_dispatch_table_for_class +class_add_method_list +class_get_class_method +class_get_instance_method +get_imp +nil_method +objc_msg_lookup +objc_msg_lookup_super +objc_msg_sendv +__objc_add_class_to_hash +__objc_init_class_tables +__objc_resolve_class_links +class_pose_as +objc_get_class +objc_get_meta_class +objc_lookup_class +objc_next_class +sarray_at_put +sarray_at_put_safe +sarray_free +sarray_lazy_copy +sarray_new +sarray_realloc +sarray_remove_garbage +objc_hash_add +hash_add +objc_hash_delete +hash_delete +objc_hash_new +hash_new +objc_hash_next +hash_next +objc_hash_remove +hash_remove +objc_hash_value_for_key +hash_value_for_key diff --git a/contrib/gcc-4.1/libobjc/libobjc_entry.c b/contrib/gcc-4.1/libobjc/libobjc_entry.c new file mode 100644 index 0000000000..205b0eda3b --- /dev/null +++ b/contrib/gcc-4.1/libobjc/libobjc_entry.c @@ -0,0 +1,55 @@ +/* GNU Objective C Runtime DLL Entry + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Scott Christley + +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 2, 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 COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include + +/* + DLL entry function for Objective-C Runtime library + This function gets called everytime a process/thread attaches to DLL + */ +WINBOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, + LPVOID lpReserved) +{ + switch(ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + break; + case DLL_PROCESS_DETACH: + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + } + return TRUE; +} + +/* + This section terminates the list of imports under GCC. If you do not + include this then you will have problems when linking with DLLs. + */ +asm (".section .idata$3\n" ".long 0,0,0,0,0,0,0,0"); diff --git a/contrib/gcc-4.1/libobjc/linking.m b/contrib/gcc-4.1/libobjc/linking.m new file mode 100644 index 0000000000..8c8a0a968b --- /dev/null +++ b/contrib/gcc-4.1/libobjc/linking.m @@ -0,0 +1,40 @@ +/* Force linking of classes required by Objective C runtime. + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Ovidiu Predescu (ovidiu@net-community.com). + +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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include +#include + +/* Generate references to Object and NXConstanstString classes since they are + needed by the runtime system to run correctly. */ + + +void __objc_linking (void) +{ + [Object name]; + [NXConstantString name]; +} + diff --git a/contrib/gcc-4.1/libobjc/misc.c b/contrib/gcc-4.1/libobjc/misc.c new file mode 100644 index 0000000000..972cff1529 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/misc.c @@ -0,0 +1,185 @@ +/* GNU Objective C Runtime Miscellaneous + Copyright (C) 1993, 1994, 1995, 1996, 1997, 2002 + Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +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 2, 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 COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#define __USE_FIXED_PROTOTYPES__ +#include +#include "objc/runtime.h" + +/* +** Error handler function +** NULL so that default is to just print to stderr +*/ +static objc_error_handler _objc_error_handler = NULL; + +/* Trigger an objc error */ +void +objc_error (id object, int code, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + objc_verror (object, code, fmt, ap); + va_end (ap); +} + +/* Trigger an objc error */ +void +objc_verror (id object, int code, const char *fmt, va_list ap) +{ + BOOL result = NO; + + /* Call the error handler if its there + Otherwise print to stderr */ + if (_objc_error_handler) + result = (*_objc_error_handler) (object, code, fmt, ap); + else + vfprintf (stderr, fmt, ap); + + /* Continue if the error handler says its ok + Otherwise abort the program */ + if (result) + return; + else + abort (); +} + +/* Set the error handler */ +objc_error_handler +objc_set_error_handler (objc_error_handler func) +{ + objc_error_handler temp = _objc_error_handler; + _objc_error_handler = func; + return temp; +} + +/* +** Standard functions for memory allocation and disposal. +** Users should use these functions in their ObjC programs so +** that they work properly with garbage collectors as well as +** can take advantage of the exception/error handling available. +*/ + +void * +objc_malloc (size_t size) +{ + void *res = (void *) (*_objc_malloc) (size); + if (! res) + objc_error (nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n"); + return res; +} + +void * +objc_atomic_malloc (size_t size) +{ + void *res = (void *) (*_objc_atomic_malloc) (size); + if (! res) + objc_error (nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n"); + return res; +} + +void * +objc_valloc (size_t size) +{ + void *res = (void *) (*_objc_valloc) (size); + if (! res) + objc_error (nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n"); + return res; +} + +void * +objc_realloc (void *mem, size_t size) +{ + void *res = (void *) (*_objc_realloc) (mem, size); + if (! res) + objc_error (nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n"); + return res; +} + +void * +objc_calloc (size_t nelem, size_t size) +{ + void *res = (void *) (*_objc_calloc) (nelem, size); + if (! res) + objc_error (nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n"); + return res; +} + +void +objc_free (void *mem) +{ + (*_objc_free) (mem); +} + +/* +** Hook functions for memory allocation and disposal. +** This makes it easy to substitute garbage collection systems +** such as Boehm's GC by assigning these function pointers +** to the GC's allocation routines. By default these point +** to the ANSI standard malloc, realloc, free, etc. +** +** Users should call the normal objc routines above for +** memory allocation and disposal within their programs. +*/ + +#if OBJC_WITH_GC +#include + +static void * +GC_calloc (size_t nelem, size_t size) +{ + void *p = GC_malloc (nelem * size); + if (! p) + objc_error (nil, OBJC_ERR_MEMORY, "Virtual memory exhausted!\n"); + + memset (p, 0, nelem * size); + return p; +} + +static void +noFree (void *p) +{ +} + +void *(*_objc_malloc) (size_t) = GC_malloc; +void *(*_objc_atomic_malloc) (size_t) = GC_malloc_atomic; +void *(*_objc_valloc) (size_t) = GC_malloc; +void *(*_objc_realloc) (void *, size_t) = GC_realloc; +void *(*_objc_calloc) (size_t, size_t) = GC_calloc; +void (*_objc_free) (void *) = noFree; + +#else /* !OBJC_WITH_GC */ + +void *(*_objc_malloc) (size_t) = malloc; +void *(*_objc_atomic_malloc) (size_t) = malloc; +void *(*_objc_valloc) (size_t) = malloc; +void *(*_objc_realloc) (void *, size_t) = realloc; +void *(*_objc_calloc) (size_t, size_t) = calloc; +void (*_objc_free) (void *) = free; + + +#endif /* !OBJC_WITH_GC */ diff --git a/contrib/gcc-4.1/libobjc/nil_method.c b/contrib/gcc-4.1/libobjc/nil_method.c new file mode 100644 index 0000000000..268f0e330d --- /dev/null +++ b/contrib/gcc-4.1/libobjc/nil_method.c @@ -0,0 +1,55 @@ +/* GNU Objective C Runtime nil receiver function + Copyright (C) 1993, 1995, 1996, 2002 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +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 2, 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 COPYING. If not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +/* This is the nil method, the function that is called when the receiver + of a method is nil */ + +#include "objc/runtime.h" + +/* When the receiver of a method invocation is nil, the runtime + returns nil_method() as the method implementation. This function + will be casted to whatever function was supposed to be executed to + execute that method (that function will take an id, followed by a + SEL, followed by who knows what arguments, depends on the method), + and executed. + + For this reason, nil_method() should be a function which can be + called in place of any function taking an 'id' argument followed by + a 'SEL' argument, followed by zero, or one, or any number of + arguments (both a fixed number, or a variable number !). + + There is no "proper" implementation of such a nil_method function + in C, however in all existing implementations it does not matter + when extra arguments are present, so we can simply create a function + taking a receiver and a selector, and all other arguments will be + ignored. :-) +*/ + +id +nil_method (id receiver, SEL op __attribute__ ((__unused__))) +{ + return receiver; +} diff --git a/contrib/gcc-4.1/libobjc/objc/NXConstStr.h b/contrib/gcc-4.1/libobjc/objc/NXConstStr.h new file mode 100644 index 0000000000..3f408d3a20 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/objc/NXConstStr.h @@ -0,0 +1,52 @@ +/* Interface for the NXConstantString class for Objective-C. + Copyright (C) 1995, 2004 Free Software Foundation, Inc. + Contributed by Pieter J. Schoenmakers + +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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifndef __nxconstantstring_INCLUDE_GNU +#define __nxconstantstring_INCLUDE_GNU + +#include "Object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +@interface NXConstantString: Object +{ + char *c_string; + unsigned int len; +} + +-(const char *) cString; +-(unsigned int) length; + +@end + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/gcc-4.1/libobjc/objc/Object.h b/contrib/gcc-4.1/libobjc/objc/Object.h new file mode 100644 index 0000000000..7b67f46615 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/objc/Object.h @@ -0,0 +1,132 @@ +/* Interface for the Object class for Objective-C. + Copyright (C) 1993, 1994, 1995 Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. */ + +#ifndef __object_INCLUDE_GNU +#define __object_INCLUDE_GNU + +#include "objc.h" +#include "typedstream.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * All classes are derived from Object. As such, + * this is the overhead tacked onto those objects. + */ +@interface Object +{ + Class isa; /* A pointer to the instance's class structure */ +} + + /* Initializing classes and instances */ ++ initialize; +- init; + + /* Creating, freeing, and copying instances */ ++ new; ++ alloc; +- free; +- copy; +- shallowCopy; +- deepen; +- deepCopy; + + /* Identifying classes */ +- (Class)class; +- (Class)superClass; +- (MetaClass)metaClass; +- (const char *)name; + + /* Identifying and comparing objects */ +- self; +- (unsigned int)hash; +- (BOOL)isEqual:anObject; +- (int)compare:anotherObject; + + /* Testing object type */ +- (BOOL)isMetaClass; +- (BOOL)isClass; +- (BOOL)isInstance; + + /* Testing inheritance relationships */ +- (BOOL)isKindOf:(Class)aClassObject; +- (BOOL)isMemberOf:(Class)aClassObject; +- (BOOL)isKindOfClassNamed:(const char *)aClassName; +- (BOOL)isMemberOfClassNamed:(const char *)aClassName; + + /* Testing class functionality */ ++ (BOOL)instancesRespondTo:(SEL)aSel; +- (BOOL)respondsTo:(SEL)aSel; + + /* Testing protocol conformance */ +- (BOOL)conformsTo:(Protocol*)aProtocol; + + /* Introspection */ ++ (IMP)instanceMethodFor:(SEL)aSel; +- (IMP)methodFor:(SEL)aSel; ++ (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel; +- (struct objc_method_description *)descriptionForMethod:(SEL)aSel; + + /* Sending messages determined at run time */ +- perform:(SEL)aSel; +- perform:(SEL)aSel with:anObject; +- perform:(SEL)aSel with:anObject1 with:anObject2; + + /* Forwarding */ +- (retval_t)forward:(SEL)aSel :(arglist_t)argFrame; +- (retval_t)performv:(SEL)aSel :(arglist_t)argFrame; + + /* Posing */ ++ poseAs:(Class)aClassObject; +- (Class)transmuteClassTo:(Class)aClassObject; + + /* Enforcing intentions */ +- subclassResponsibility:(SEL)aSel; +- notImplemented:(SEL)aSel; +- shouldNotImplement:(SEL)aSel; + + /* Error handling */ +- doesNotRecognize:(SEL)aSel; +- error:(const char *)aString, ...; + + /* Archiving */ ++ (int)version; ++ setVersion:(int)aVersion; ++ (int)streamVersion: (TypedStream*)aStream; + +- read: (TypedStream*)aStream; +- write: (TypedStream*)aStream; +- awake; + +@end + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/gcc-4.1/libobjc/objc/Protocol.h b/contrib/gcc-4.1/libobjc/objc/Protocol.h new file mode 100644 index 0000000000..fe0f28a8eb --- /dev/null +++ b/contrib/gcc-4.1/libobjc/objc/Protocol.h @@ -0,0 +1,63 @@ +/* Declare the class Protocol for Objective C programs. + Copyright (C) 1993, 2004 Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifndef __Protocol_INCLUDE_GNU +#define __Protocol_INCLUDE_GNU + +#include "Object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +@interface Protocol : Object +{ +@private + char *protocol_name; + struct objc_protocol_list *protocol_list; + struct objc_method_description_list *instance_methods, *class_methods; +} + +/* Obtaining attributes intrinsic to the protocol */ + +- (const char *)name; + +/* Testing protocol conformance */ + +- (BOOL) conformsTo: (Protocol *)aProtocolObject; + +/* Looking up information specific to a protocol */ + +- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel; +- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel; + +@end + +#ifdef __cplusplus +} +#endif + +#endif /* not __Protocol_INCLUDE_GNU */ diff --git a/contrib/gcc-4.1/libobjc/objc/encoding.h b/contrib/gcc-4.1/libobjc/objc/encoding.h new file mode 100644 index 0000000000..c432ee93bd --- /dev/null +++ b/contrib/gcc-4.1/libobjc/objc/encoding.h @@ -0,0 +1,107 @@ +/* Encoding of types for Objective C. + Copyright (C) 1993, 1997, 2002, 2004 Free Software Foundation, Inc. + +Author: Kresten Krab Thorup + +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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifndef __encoding_INCLUDE_GNU +#define __encoding_INCLUDE_GNU + +#include "objc-api.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define _C_CONST 'r' +#define _C_IN 'n' +#define _C_INOUT 'N' +#define _C_OUT 'o' +#define _C_BYCOPY 'O' +#define _C_BYREF 'R' +#define _C_ONEWAY 'V' +#define _C_GCINVISIBLE '!' + +#define _F_CONST 0x01 +#define _F_IN 0x01 +#define _F_OUT 0x02 +#define _F_INOUT 0x03 +#define _F_BYCOPY 0x04 +#define _F_BYREF 0x08 +#define _F_ONEWAY 0x10 +#define _F_GCINVISIBLE 0x20 + +int objc_aligned_size (const char *type); +int objc_sizeof_type (const char *type); +int objc_alignof_type (const char *type); +int objc_aligned_size (const char *type); +int objc_promoted_size (const char *type); + +const char *objc_skip_type_qualifiers (const char *type); +const char *objc_skip_typespec (const char *type); +const char *objc_skip_offset (const char *type); +const char *objc_skip_argspec (const char *type); +int method_get_number_of_arguments (struct objc_method *); +int method_get_sizeof_arguments (struct objc_method *); + +char *method_get_first_argument (struct objc_method *, + arglist_t argframe, + const char **type); +char *method_get_next_argument (arglist_t argframe, + const char **type); +char *method_get_nth_argument (struct objc_method *m, + arglist_t argframe, + int arg, + const char **type); + +unsigned objc_get_type_qualifiers (const char *type); + + +struct objc_struct_layout +{ + const char *original_type; + const char *type; + const char *prev_type; + unsigned int record_size; + unsigned int record_align; +}; + +void objc_layout_structure (const char *type, + struct objc_struct_layout *layout); +BOOL objc_layout_structure_next_member (struct objc_struct_layout *layout); +void objc_layout_finish_structure (struct objc_struct_layout *layout, + unsigned int *size, + unsigned int *align); +void objc_layout_structure_get_info (struct objc_struct_layout *layout, + unsigned int *offset, + unsigned int *align, + const char **type); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __encoding_INCLUDE_GNU */ diff --git a/contrib/gcc-4.1/libobjc/objc/hash.h b/contrib/gcc-4.1/libobjc/objc/hash.h new file mode 100644 index 0000000000..2260fad569 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/objc/hash.h @@ -0,0 +1,316 @@ +/* Hash tables for Objective C method dispatch. + Copyright (C) 1993, 1995, 1996, 2004 Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + + +#ifndef __hash_INCLUDE_GNU +#define __hash_INCLUDE_GNU + +#include +#include +#include "objc.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * This data structure is used to hold items + * stored in a hash table. Each node holds + * a key/value pair. + * + * Items in the cache are really of type void *. + */ +typedef struct cache_node +{ + struct cache_node *next; /* Pointer to next entry on the list. + NULL indicates end of list. */ + const void *key; /* Key used to locate the value. Used + to locate value when more than one + key computes the same hash + value. */ + void *value; /* Value stored for the key. */ +} *node_ptr; + + +/* + * This data type is the function that computes a hash code given a key. + * Therefore, the key can be a pointer to anything and the function specific + * to the key type. + * + * Unfortunately there is a mutual data structure reference problem with this + * typedef. Therefore, to remove compiler warnings the functions passed to + * objc_hash_new will have to be casted to this type. + */ +typedef unsigned int (*hash_func_type) (void *, const void *); + +/* + * This data type is the function that compares two hash keys and returns an + * integer greater than, equal to, or less than 0, according as the first + * parameter is lexicographically greater than, equal to, or less than the + * second. + */ + +typedef int (*compare_func_type) (const void *, const void *); + + +/* + * This data structure is the cache. + * + * It must be passed to all of the hashing routines + * (except for new). + */ +typedef struct cache +{ + /* Variables used to implement the hash itself. */ + node_ptr *node_table; /* Pointer to an array of hash nodes. */ + /* Variables used to track the size of the hash table so to determine + when to resize it. */ + unsigned int size; /* Number of buckets allocated for the hash table + (number of array entries allocated for + "node_table"). Must be a power of two. */ + unsigned int used; /* Current number of entries in the hash table. */ + unsigned int mask; /* Precomputed mask. */ + + /* Variables used to implement indexing through the hash table. */ + + unsigned int last_bucket; /* Tracks which entry in the array where + the last value was returned. */ + /* Function used to compute a hash code given a key. + This function is specified when the hash table is created. */ + hash_func_type hash_func; + /* Function used to compare two hash keys to see if they are equal. */ + compare_func_type compare_func; +} *cache_ptr; + + +/* Two important hash tables. */ +extern cache_ptr module_hash_table, class_hash_table; + +/* Allocate and initialize a hash table. */ + +cache_ptr objc_hash_new (unsigned int size, + hash_func_type hash_func, + compare_func_type compare_func); + +/* Deallocate all of the hash nodes and the cache itself. */ + +void objc_hash_delete (cache_ptr cache); + +/* Add the key/value pair to the hash table. If the + hash table reaches a level of fullness then it will be resized. + + assert if the key is already in the hash. */ + +void objc_hash_add (cache_ptr *cachep, const void *key, void *value); + +/* Remove the key/value pair from the hash table. + assert if the key isn't in the table. */ + +void objc_hash_remove (cache_ptr cache, const void *key); + +/* Used to index through the hash table. Start with NULL + to get the first entry. + + Successive calls pass the value returned previously. + ** Don't modify the hash during this operation *** + + Cache nodes are returned such that key or value can + be extracted. */ + +node_ptr objc_hash_next (cache_ptr cache, node_ptr node); + +/* Used to return a value from a hash table using a given key. */ + +void *objc_hash_value_for_key (cache_ptr cache, const void *key); + +/* Used to determine if the given key exists in the hash table */ + +BOOL objc_hash_is_key_in_hash (cache_ptr cache, const void *key); + +/************************************************ + + Useful hashing functions. + + Declared inline for your pleasure. + +************************************************/ + +/* Calculate a hash code by performing some + manipulation of the key pointer. (Use the lowest bits + except for those likely to be 0 due to alignment.) */ + +static inline unsigned int +objc_hash_ptr (cache_ptr cache, const void *key) +{ + return ((size_t)key / sizeof (void *)) & cache->mask; +} + + +/* Calculate a hash code by iterating over a NULL + terminate string. */ +static inline unsigned int +objc_hash_string (cache_ptr cache, const void *key) +{ + unsigned int ret = 0; + unsigned int ctr = 0; + const char *ckey = (const char *) key; + + while (*ckey) { + ret ^= *ckey++ << ctr; + ctr = (ctr + 1) % sizeof (void *); + } + + return ret & cache->mask; +} + + +/* Compare two pointers for equality. */ +static inline int +objc_compare_ptrs (const void *k1, const void *k2) +{ + return (k1 == k2); +} + + +/* Compare two strings. */ +static inline int +objc_compare_strings (const void *k1, const void *k2) +{ + if (k1 == k2) + return 1; + else if (k1 == 0 || k2 == 0) + return 0; + else + return ! strcmp ((const char *) k1, (const char *) k2); +} + +#ifndef OBJC_IGNORE_DEPRECATED_API +/* Deprecated as of 4.0 */ + +static inline cache_ptr +hash_new (unsigned int size, + hash_func_type hash_func, + compare_func_type compare_func) __attribute__ ((deprecated)); +static inline cache_ptr +hash_new (unsigned int size, + hash_func_type hash_func, + compare_func_type compare_func) +{ + return objc_hash_new(size, hash_func, compare_func); +} + +static inline void +hash_delete(cache_ptr cache) __attribute__ ((deprecated)); +static inline void +hash_delete(cache_ptr cache) +{ + objc_hash_delete(cache); +} + +static inline void +hash_add (cache_ptr *cachep, + const void *key, + void *value) __attribute__ ((deprecated)); +static inline void +hash_add (cache_ptr *cachep, const void *key, void *value) +{ + objc_hash_add(cachep, key, value); +} + +static inline void +hash_remove (cache_ptr cache, const void *key) __attribute__ ((deprecated)); +static inline void +hash_remove (cache_ptr cache, const void *key) +{ + objc_hash_remove (cache, key); +} + +static inline node_ptr +hash_next (cache_ptr cache, node_ptr node) __attribute__ ((deprecated)); +static inline node_ptr +hash_next (cache_ptr cache, node_ptr node) +{ + return objc_hash_next (cache, node); +} + +static inline void * +hash_value_for_key (cache_ptr cache, + const void *key) __attribute__ ((deprecated)); +static inline void * +hash_value_for_key (cache_ptr cache, const void *key) +{ + return objc_hash_value_for_key (cache, key); +} + +static inline BOOL +hash_is_key_in_hash (cache_ptr cache, + const void *key) __attribute__ ((deprecated)); +static inline BOOL +hash_is_key_in_hash (cache_ptr cache, const void *key) +{ + return objc_hash_is_key_in_hash (cache, key); +} + +static inline unsigned int +hash_ptr (cache_ptr cache, const void *key) __attribute__ ((deprecated)); +static inline unsigned int +hash_ptr (cache_ptr cache, const void *key) +{ + return objc_hash_ptr (cache, key); +} + +static inline unsigned int +hash_string (cache_ptr cache, const void *key) __attribute__ ((deprecated)); +static inline unsigned int +hash_string (cache_ptr cache, const void *key) +{ + return objc_hash_string (cache, key); +} + +static inline int +compare_ptrs (const void *k1, const void *k2) __attribute__ ((deprecated)); +static inline int +compare_ptrs (const void *k1, const void *k2) +{ + return objc_compare_ptrs (k1, k2); +} + +static inline int +compare_strings (const void *k1, const void *k2) __attribute__ ((deprecated)); +static inline int +compare_strings (const void *k1, const void *k2) +{ + return objc_compare_strings (k1, k2); +} +#endif /* OBJC_IGNORE_DEPRECATED_API */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* not __hash_INCLUDE_GNU */ diff --git a/contrib/gcc-4.1/libobjc/objc/objc-api.h b/contrib/gcc-4.1/libobjc/objc/objc-api.h new file mode 100644 index 0000000000..1f5b5191ff --- /dev/null +++ b/contrib/gcc-4.1/libobjc/objc/objc-api.h @@ -0,0 +1,624 @@ +/* GNU Objective-C Runtime API. + Copyright (C) 1993, 1995, 1996, 1997, 2002, 2004 Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. */ + +#ifndef __objc_api_INCLUDE_GNU +#define __objc_api_INCLUDE_GNU + +#include "objc.h" +#include "hash.h" +#include "thr.h" +#include "objc-decls.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* For functions which return Method_t */ +#define METHOD_NULL (Method_t)0 + /* Boolean typedefs */ +/* +** Method descriptor returned by introspective Object methods. +** This is really just the first part of the more complete objc_method +** structure defined below and used internally by the runtime. +*/ +struct objc_method_description +{ + SEL name; /* this is a selector, not a string */ + char *types; /* type encoding */ +}; + +/* Filer types used to describe Ivars and Methods. */ +#define _C_ID '@' +#define _C_CLASS '#' +#define _C_SEL ':' +#define _C_CHR 'c' +#define _C_UCHR 'C' +#define _C_SHT 's' +#define _C_USHT 'S' +#define _C_INT 'i' +#define _C_UINT 'I' +#define _C_LNG 'l' +#define _C_ULNG 'L' +#define _C_LNG_LNG 'q' +#define _C_ULNG_LNG 'Q' +#define _C_FLT 'f' +#define _C_DBL 'd' +#define _C_BFLD 'b' +#define _C_VOID 'v' +#define _C_UNDEF '?' +#define _C_PTR '^' +#define _C_CHARPTR '*' +#define _C_ATOM '%' +#define _C_ARY_B '[' +#define _C_ARY_E ']' +#define _C_UNION_B '(' +#define _C_UNION_E ')' +#define _C_STRUCT_B '{' +#define _C_STRUCT_E '}' +#define _C_VECTOR '!' + + +/* +** Error handling +** +** Call objc_error() or objc_verror() to record an error; this error +** routine will generally exit the program but not necessarily if the +** user has installed his own error handler. +** +** Call objc_set_error_handler to assign your own function for +** handling errors. The function should return YES if it is ok +** to continue execution, or return NO or just abort if the +** program should be stopped. The default error handler is just to +** print a message on stderr. +** +** The error handler function should be of type objc_error_handler +** The first parameter is an object instance of relevance. +** The second parameter is an error code. +** The third parameter is a format string in the printf style. +** The fourth parameter is a variable list of arguments. +*/ +extern void objc_error(id object, int code, const char* fmt, ...); +extern void objc_verror(id object, int code, const char* fmt, va_list ap); +typedef BOOL (*objc_error_handler)(id, int code, const char *fmt, va_list ap); +extern objc_error_handler objc_set_error_handler(objc_error_handler func); + +/* +** Error codes +** These are used by the runtime library, and your +** error handling may use them to determine if the error is +** hard or soft thus whether execution can continue or abort. +*/ +#define OBJC_ERR_UNKNOWN 0 /* Generic error */ + +#define OBJC_ERR_OBJC_VERSION 1 /* Incorrect runtime version */ +#define OBJC_ERR_GCC_VERSION 2 /* Incorrect compiler version */ +#define OBJC_ERR_MODULE_SIZE 3 /* Bad module size */ +#define OBJC_ERR_PROTOCOL_VERSION 4 /* Incorrect protocol version */ + +#define OBJC_ERR_MEMORY 10 /* Out of memory */ + +#define OBJC_ERR_RECURSE_ROOT 20 /* Attempt to archive the root + object more than once. */ +#define OBJC_ERR_BAD_DATA 21 /* Didn't read expected data */ +#define OBJC_ERR_BAD_KEY 22 /* Bad key for object */ +#define OBJC_ERR_BAD_CLASS 23 /* Unknown class */ +#define OBJC_ERR_BAD_TYPE 24 /* Bad type specification */ +#define OBJC_ERR_NO_READ 25 /* Cannot read stream */ +#define OBJC_ERR_NO_WRITE 26 /* Cannot write stream */ +#define OBJC_ERR_STREAM_VERSION 27 /* Incorrect stream version */ +#define OBJC_ERR_BAD_OPCODE 28 /* Bad opcode */ + +#define OBJC_ERR_UNIMPLEMENTED 30 /* Method is not implemented */ + +#define OBJC_ERR_BAD_STATE 40 /* Bad thread state */ + +/* +** Set this variable nonzero to print a line describing each +** message that is sent. (this is currently disabled) +*/ +extern BOOL objc_trace; + + +/* For every class which happens to have statically allocated instances in + this module, one OBJC_STATIC_INSTANCES is allocated by the compiler. + INSTANCES is NULL terminated and points to all statically allocated + instances of this class. */ +struct objc_static_instances +{ + char *class_name; +#ifdef __cplusplus + id instances[1]; +#else + id instances[0]; +#endif +}; + +/* +** Whereas a Module (defined further down) is the root (typically) of a file, +** a Symtab is the root of the class and category definitions within the +** module. +** +** A Symtab contains a variable length array of pointers to classes and +** categories defined in the module. +*/ +typedef struct objc_symtab { + unsigned long sel_ref_cnt; /* Unknown. */ + SEL refs; /* Unknown. */ + unsigned short cls_def_cnt; /* Number of classes compiled + (defined) in the module. */ + unsigned short cat_def_cnt; /* Number of categories + compiled (defined) in the + module. */ + + void *defs[1]; /* Variable array of pointers. + cls_def_cnt of type Class + followed by cat_def_cnt of + type Category_t, followed + by a NULL terminated array + of objc_static_instances. */ +} Symtab, *Symtab_t; + + +/* +** The compiler generates one of these structures for each module that +** composes the executable (eg main.m). +** +** This data structure is the root of the definition tree for the module. +** +** A collect program runs between ld stages and creates a ObjC ctor array. +** That array holds a pointer to each module structure of the executable. +*/ +typedef struct objc_module { + unsigned long version; /* Compiler revision. */ + unsigned long size; /* sizeof(Module). */ + const char* name; /* Name of the file where the + module was generated. The + name includes the path. */ + + Symtab_t symtab; /* Pointer to the Symtab of + the module. The Symtab + holds an array of + pointers to + the classes and categories + defined in the module. */ +} Module, *Module_t; + + +/* +** The compiler generates one of these structures for a class that has +** instance variables defined in its specification. +*/ +typedef struct objc_ivar { + const char* ivar_name; /* Name of the instance + variable as entered in the + class definition. */ + const char* ivar_type; /* Description of the Ivar's + type. Useful for + debuggers. */ + int ivar_offset; /* Byte offset from the base + address of the instance + structure to the variable. */ +} *Ivar_t; + +typedef struct objc_ivar_list { + int ivar_count; /* Number of structures (Ivar) + contained in the list. One + structure per instance + variable defined in the + class. */ + struct objc_ivar ivar_list[1]; /* Variable length + structure. */ +} IvarList, *IvarList_t; + + +/* +** The compiler generates one (or more) of these structures for a class that +** has methods defined in its specification. +** +** The implementation of a class can be broken into separate pieces in a file +** and categories can break them across modules. To handle this problem is a +** singly linked list of methods. +*/ +typedef struct objc_method { + SEL method_name; /* This variable is the method's + name. It is a char*. + The unique integer passed to + objc_msg_send is a char* too. + It is compared against + method_name using strcmp. */ + const char* method_types; /* Description of the method's + parameter list. Useful for + debuggers. */ + IMP method_imp; /* Address of the method in the + executable. */ +} Method, *Method_t; + +typedef struct objc_method_list { + struct objc_method_list* method_next; /* This variable is used to link + a method list to another. It + is a singly linked list. */ + int method_count; /* Number of methods defined in + this structure. */ + Method method_list[1]; /* Variable length + structure. */ +} MethodList, *MethodList_t; + +struct objc_protocol_list { + struct objc_protocol_list *next; + size_t count; + Protocol *list[1]; +}; + +/* +** This is used to assure consistent access to the info field of +** classes +*/ +#ifndef HOST_BITS_PER_LONG +#define HOST_BITS_PER_LONG (sizeof(long)*8) +#endif + +#define __CLS_INFO(cls) ((cls)->info) +#define __CLS_ISINFO(cls, mask) ((__CLS_INFO(cls)&mask)==mask) +#define __CLS_SETINFO(cls, mask) (__CLS_INFO(cls) |= mask) + +/* The structure is of type MetaClass */ +#define _CLS_META 0x2L +#define CLS_ISMETA(cls) ((cls)&&__CLS_ISINFO(cls, _CLS_META)) + + +/* The structure is of type Class */ +#define _CLS_CLASS 0x1L +#define CLS_ISCLASS(cls) ((cls)&&__CLS_ISINFO(cls, _CLS_CLASS)) + +/* +** The class is initialized within the runtime. This means that +** it has had correct super and sublinks assigned +*/ +#define _CLS_RESOLV 0x8L +#define CLS_ISRESOLV(cls) __CLS_ISINFO(cls, _CLS_RESOLV) +#define CLS_SETRESOLV(cls) __CLS_SETINFO(cls, _CLS_RESOLV) + +/* +** The class has been send a +initialize message or a such is not +** defined for this class +*/ +#define _CLS_INITIALIZED 0x04L +#define CLS_ISINITIALIZED(cls) __CLS_ISINFO(cls, _CLS_INITIALIZED) +#define CLS_SETINITIALIZED(cls) __CLS_SETINFO(cls, _CLS_INITIALIZED) + +/* +** The class number of this class. This must be the same for both the +** class and its meta class object +*/ +#define CLS_GETNUMBER(cls) (__CLS_INFO(cls) >> (HOST_BITS_PER_LONG/2)) +#define CLS_SETNUMBER(cls, num) \ + ({ (cls)->info <<= (HOST_BITS_PER_LONG/2); \ + (cls)->info >>= (HOST_BITS_PER_LONG/2); \ + __CLS_SETINFO(cls, (((unsigned long)num) << (HOST_BITS_PER_LONG/2))); }) + +/* +** The compiler generates one of these structures for each category. A class +** may have many categories and contain both instance and factory methods. +*/ +typedef struct objc_category { + const char* category_name; /* Name of the category. Name + contained in the () of the + category definition. */ + const char* class_name; /* Name of the class to which + the category belongs. */ + MethodList_t instance_methods; /* Linked list of instance + methods defined in the + category. NULL indicates no + instance methods defined. */ + MethodList_t class_methods; /* Linked list of factory + methods defined in the + category. NULL indicates no + class methods defined. */ + struct objc_protocol_list *protocols; /* List of Protocols + conformed to */ +} Category, *Category_t; + +/* +** Structure used when a message is send to a class's super class. The +** compiler generates one of these structures and passes it to +** objc_msg_super. +*/ +typedef struct objc_super { + id self; /* Id of the object sending + the message. */ +#ifdef __cplusplus + Class super_class; +#else + Class class; /* Object's super class. */ +#endif +} Super, *Super_t; + +IMP objc_msg_lookup_super(Super_t super, SEL sel); + +retval_t objc_msg_sendv(id, SEL, arglist_t); + + + +/* +** This is a hook which is called by objc_lookup_class and +** objc_get_class if the runtime is not able to find the class. +** This may e.g. try to load in the class using dynamic loading. +** The function is guaranteed to be passed a non-NULL name string. +*/ +objc_EXPORT Class (*_objc_lookup_class)(const char *name); + +/* +** This is a hook which is called by __objc_exec_class every time a class +** or a category is loaded into the runtime. This may e.g. help a +** dynamic loader determine the classes that have been loaded when +** an object file is dynamically linked in. +*/ +objc_EXPORT void (*_objc_load_callback)(Class _class, Category* category); + +/* +** Hook functions for allocating, copying and disposing of instances +*/ +objc_EXPORT id (*_objc_object_alloc)(Class _class); +objc_EXPORT id (*_objc_object_copy)(id object); +objc_EXPORT id (*_objc_object_dispose)(id object); + +/* +** Standard functions for memory allocation and disposal. +** Users should use these functions in their ObjC programs so +** that they work properly with garbage collectors as well as +** can take advantage of the exception/error handling available. +*/ +void * +objc_malloc(size_t size); + +void * +objc_atomic_malloc(size_t size); + +void * +objc_valloc(size_t size); + +void * +objc_realloc(void *mem, size_t size); + +void * +objc_calloc(size_t nelem, size_t size); + +void +objc_free(void *mem); + +/* +** Hook functions for memory allocation and disposal. +** This makes it easy to substitute garbage collection systems +** such as Boehm's GC by assigning these function pointers +** to the GC's allocation routines. By default these point +** to the ANSI standard malloc, realloc, free, etc. +** +** Users should call the normal objc routines above for +** memory allocation and disposal within their programs. +*/ +objc_EXPORT void *(*_objc_malloc)(size_t); +objc_EXPORT void *(*_objc_atomic_malloc)(size_t); +objc_EXPORT void *(*_objc_valloc)(size_t); +objc_EXPORT void *(*_objc_realloc)(void *, size_t); +objc_EXPORT void *(*_objc_calloc)(size_t, size_t); +objc_EXPORT void (*_objc_free)(void *); + +/* +** Hook for method forwarding. This makes it easy to substitute a +** library, such as ffcall, that implements closures, thereby avoiding +** gcc's __builtin_apply problems. +*/ +objc_EXPORT IMP (*__objc_msg_forward)(SEL); + +Method_t class_get_class_method(MetaClass _class, SEL aSel); + +Method_t class_get_instance_method(Class _class, SEL aSel); + +Class class_pose_as(Class impostor, Class superclass); + +Class objc_get_class(const char *name); + +Class objc_lookup_class(const char *name); + +Class objc_next_class(void **enum_state); + +const char *sel_get_name(SEL selector); + +const char *sel_get_type(SEL selector); + +SEL sel_get_uid(const char *name); + +SEL sel_get_any_uid(const char *name); + +SEL sel_get_any_typed_uid(const char *name); + +SEL sel_get_typed_uid(const char *name, const char*); + +SEL sel_register_name(const char *name); + +SEL sel_register_typed_name(const char *name, const char*type); + + +BOOL sel_is_mapped (SEL aSel); + +extern id class_create_instance(Class _class); + +static inline const char * +class_get_class_name(Class _class) +{ + return CLS_ISCLASS(_class)?_class->name:((_class==Nil)?"Nil":0); +} + +static inline long +class_get_instance_size(Class _class) +{ + return CLS_ISCLASS(_class)?_class->instance_size:0; +} + +static inline MetaClass +class_get_meta_class(Class _class) +{ + return CLS_ISCLASS(_class)?_class->class_pointer:Nil; +} + +static inline Class +class_get_super_class(Class _class) +{ + return CLS_ISCLASS(_class)?_class->super_class:Nil; +} + +static inline int +class_get_version(Class _class) +{ + return CLS_ISCLASS(_class)?_class->version:-1; +} + +static inline BOOL +class_is_class(Class _class) +{ + return CLS_ISCLASS(_class); +} + +static inline BOOL +class_is_meta_class(Class _class) +{ + return CLS_ISMETA(_class); +} + + +static inline void +class_set_version(Class _class, long version) +{ + if (CLS_ISCLASS(_class)) + _class->version = version; +} + +static inline void * +class_get_gc_object_type (Class _class) +{ + return CLS_ISCLASS(_class) ? _class->gc_object_type : NULL; +} + +/* Mark the instance variable as innaccessible to the garbage collector */ +extern void class_ivar_set_gcinvisible (Class _class, + const char* ivarname, + BOOL gcInvisible); + +static inline IMP +method_get_imp(Method_t method) +{ + return (method!=METHOD_NULL)?method->method_imp:(IMP)0; +} + +IMP get_imp (Class _class, SEL sel); + +/* Redefine on NeXTSTEP so as not to conflict with system function */ +#ifdef __NeXT__ +#define object_copy gnu_object_copy +#define object_dispose gnu_object_dispose +#endif + +id object_copy(id object); + +id object_dispose(id object); + +static inline Class +object_get_class(id object) +{ + return ((object!=nil) + ? (CLS_ISCLASS(object->class_pointer) + ? object->class_pointer + : (CLS_ISMETA(object->class_pointer) + ? (Class)object + : Nil)) + : Nil); +} + +static inline const char * +object_get_class_name(id object) +{ + return ((object!=nil)?(CLS_ISCLASS(object->class_pointer) + ?object->class_pointer->name + :((Class)object)->name) + :"Nil"); +} + +static inline MetaClass +object_get_meta_class(id object) +{ + return ((object!=nil)?(CLS_ISCLASS(object->class_pointer) + ?object->class_pointer->class_pointer + :(CLS_ISMETA(object->class_pointer) + ?object->class_pointer + :Nil)) + :Nil); +} + +static inline Class +object_get_super_class +(id object) +{ + return ((object!=nil)?(CLS_ISCLASS(object->class_pointer) + ?object->class_pointer->super_class + :(CLS_ISMETA(object->class_pointer) + ?((Class)object)->super_class + :Nil)) + :Nil); +} + +static inline BOOL +object_is_class (id object) +{ + return ((object != nil) && CLS_ISMETA (object->class_pointer)); +} + +static inline BOOL +object_is_instance (id object) +{ + return ((object != nil) && CLS_ISCLASS (object->class_pointer)); +} + +static inline BOOL +object_is_meta_class (id object) +{ + return ((object != nil) + && !object_is_instance (object) + && !object_is_class (object)); +} + +struct sarray* +objc_get_uninstalled_dtable(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* not __objc_api_INCLUDE_GNU */ + + + diff --git a/contrib/gcc-4.1/libobjc/objc/objc-decls.h b/contrib/gcc-4.1/libobjc/objc/objc-decls.h new file mode 100644 index 0000000000..52938a2381 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/objc/objc-decls.h @@ -0,0 +1,47 @@ +/* GNU Objective-C Extern helpers for Win32. + Copyright (C) 2004 Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. */ + +#ifndef __objc_decls_INCLUDE_GNU +#define __objc_decls_INCLUDE_GNU + +#if defined (_WIN32) || defined (__WIN32__) || defined (WIN32) + +# ifdef DLL_EXPORT /* defined by libtool (if required) */ +# define objc_EXPORT __declspec(dllexport) +# define objc_DECLARE __declspec(dllexport) +#else +# define objc_EXPORT extern __declspec(dllimport) +# define objc_DECLARE extern __declspec(dllimport) +#endif + +#else + +# define objc_EXPORT extern +# define objc_DECLARE + +#endif + +#endif /* __objc_decls_INCLUDE_GNU */ diff --git a/contrib/gcc-4.1/libobjc/objc/objc-list.h b/contrib/gcc-4.1/libobjc/objc/objc-list.h new file mode 100644 index 0000000000..051e1c2c13 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/objc/objc-list.h @@ -0,0 +1,156 @@ +/* Generic single linked list to keep various information + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup. + +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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#ifndef __GNU_OBJC_LIST_H +#define __GNU_OBJC_LIST_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct objc_list { + void *head; + struct objc_list *tail; +}; + +/* Return a cons cell produced from (head . tail) */ + +static inline struct objc_list* +list_cons(void* head, struct objc_list* tail) +{ + struct objc_list* cell; + + cell = (struct objc_list*)objc_malloc(sizeof(struct objc_list)); + cell->head = head; + cell->tail = tail; + return cell; +} + +/* Return the length of a list, list_length(NULL) returns zero */ + +static inline int +list_length(struct objc_list* list) +{ + int i = 0; + while(list) + { + i += 1; + list = list->tail; + } + return i; +} + +/* Return the Nth element of LIST, where N count from zero. If N + larger than the list length, NULL is returned */ + +static inline void* +list_nth(int indx, struct objc_list* list) +{ + while(indx-- != 0) + { + if(list->tail) + list = list->tail; + else + return 0; + } + return list->head; +} + +/* Remove the element at the head by replacing it by its successor */ + +static inline void +list_remove_head(struct objc_list** list) +{ + if ((*list)->tail) + { + struct objc_list* tail = (*list)->tail; /* fetch next */ + *(*list) = *tail; /* copy next to list head */ + objc_free(tail); /* free next */ + } + else /* only one element in list */ + { + objc_free(*list); + (*list) = 0; + } +} + + +/* Remove the element with `car' set to ELEMENT */ + +static inline void +list_remove_elem(struct objc_list** list, void* elem) +{ + while (*list) { + if ((*list)->head == elem) + list_remove_head(list); + list = &((*list)->tail); + } +} + +/* Map FUNCTION over all elements in LIST */ + +static inline void +list_mapcar(struct objc_list* list, void(*function)(void*)) +{ + while(list) + { + (*function)(list->head); + list = list->tail; + } +} + +/* Return element that has ELEM as car */ + +static inline struct objc_list** +list_find(struct objc_list** list, void* elem) +{ + while(*list) + { + if ((*list)->head == elem) + return list; + list = &((*list)->tail); + } + return NULL; +} + +/* Free list (backwards recursive) */ + +static void +list_free(struct objc_list* list) +{ + if(list) + { + list_free(list->tail); + objc_free(list); + } +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* not __GNU_OBJC_LIST_H */ diff --git a/contrib/gcc-4.1/libobjc/objc/objc.h b/contrib/gcc-4.1/libobjc/objc/objc.h new file mode 100644 index 0000000000..ee7612c975 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/objc/objc.h @@ -0,0 +1,165 @@ +/* Basic data types for Objective C. + Copyright (C) 1993, 1995, 1996, 2004 Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifndef __objc_INCLUDE_GNU +#define __objc_INCLUDE_GNU + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* +** Definition of the boolean type. +*/ +#ifdef __vxworks +typedef int BOOL; +#else +typedef unsigned char BOOL; +#endif +#define YES (BOOL)1 +#define NO (BOOL)0 + +/* +** Definition of a selector. Selectors themselves are not unique, but +** the sel_id is a unique identifier. +*/ +typedef const struct objc_selector +{ + void *sel_id; + const char *sel_types; +} *SEL; + +inline static BOOL +sel_eq (SEL s1, SEL s2) +{ + if (s1 == 0 || s2 == 0) + return s1 == s2; + else + return s1->sel_id == s2->sel_id; +} + + +/* +** ObjC uses this typedef for untyped instances. +*/ +typedef struct objc_object { + struct objc_class* class_pointer; +} *id; + +/* +** Definition of method type. When retrieving the implementation of a +** method, this is type of the pointer returned. The idea of the +** definition of IMP is to represent a 'pointer to a general function +** taking an id, a SEL, followed by other unspecified arguments'. You +** must always cast an IMP to a pointer to a function taking the +** appropriate, specific types for that function, before calling it - +** to make sure the appropriate arguments are passed to it. The code +** generated by the compiler to perform method calls automatically +** does this cast inside method calls. +*/ +typedef id (*IMP)(id, SEL, ...); + +/* +** More simple types... +*/ +#define nil (id)0 /* id of Nil instance */ +#define Nil (Class)0 /* id of Nil class */ +typedef char *STR; /* String alias */ + +/* +** The compiler generates one of these structures for each class. +** +** This structure is the definition for classes. +** +** This structure is generated by the compiler in the executable and used by +** the run-time during normal messaging operations. Therefore some members +** change type. The compiler generates "char* const" and places a string in +** the following member variables: super_class. +*/ +typedef struct objc_class *MetaClass; +typedef struct objc_class *Class; +struct objc_class { + MetaClass class_pointer; /* Pointer to the class's + meta class. */ + struct objc_class* super_class; /* Pointer to the super + class. NULL for class + Object. */ + const char* name; /* Name of the class. */ + long version; /* Unknown. */ + unsigned long info; /* Bit mask. See class masks + defined above. */ + long instance_size; /* Size in bytes of the class. + The sum of the class + definition and all super + class definitions. */ + struct objc_ivar_list* ivars; /* Pointer to a structure that + describes the instance + variables in the class + definition. NULL indicates + no instance variables. Does + not include super class + variables. */ + struct objc_method_list* methods; /* Linked list of instance + methods defined for the + class. */ + struct sarray * dtable; /* Pointer to instance + method dispatch table. */ + struct objc_class* subclass_list; /* Subclasses */ + struct objc_class* sibling_class; + + struct objc_protocol_list *protocols; /* Protocols conformed to */ + void* gc_object_type; +}; + +#ifndef __OBJC__ +typedef struct objc_protocol { + struct objc_class* class_pointer; + char *protocol_name; + struct objc_protocol_list *protocol_list; + struct objc_method_description_list *instance_methods, *class_methods; +} Protocol; + +#else /* __OBJC__ */ +@class Protocol; +#endif + +typedef void* retval_t; /* return value */ +typedef void(*apply_t)(void); /* function pointer */ +typedef union arglist { + char *arg_ptr; + char arg_regs[sizeof (char*)]; +} *arglist_t; /* argument frame */ + + +IMP objc_msg_lookup(id receiver, SEL op); + +#ifdef __cplusplus +} +#endif + +#endif /* not __objc_INCLUDE_GNU */ diff --git a/contrib/gcc-4.1/libobjc/objc/runtime.h b/contrib/gcc-4.1/libobjc/objc/runtime.h new file mode 100644 index 0000000000..3582d1d91c --- /dev/null +++ b/contrib/gcc-4.1/libobjc/objc/runtime.h @@ -0,0 +1,96 @@ +/* GNU Objective C Runtime internal declarations + Copyright (C) 1993, 1995, 1996, 1997, 2002, 2004 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +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 2, 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 COPYING. If not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#ifndef __objc_runtime_INCLUDE_GNU +#define __objc_runtime_INCLUDE_GNU + +#include /* for varargs and va_list's */ + +#include +#include + +#include /* so noone else will get system versions */ +#include + +#include "objc.h" /* core data types */ +#include "objc-api.h" /* runtime api functions */ + +#include "thr.h" /* thread and mutex support */ + +#include "hash.h" /* hash structures */ +#include "objc-list.h" /* linear lists */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +extern void __objc_add_class_to_hash(Class); /* (objc-class.c) */ +extern void __objc_init_selector_tables(void); /* (objc-sel.c) */ +extern void __objc_init_class_tables(void); /* (objc-class.c) */ +extern void __objc_init_dispatch_tables(void); /* (objc-dispatch.c) */ +extern void __objc_install_premature_dtable(Class); /* (objc-dispatch.c) */ +extern void __objc_resolve_class_links(void); /* (objc-class.c) */ +extern void __objc_register_selectors_from_class(Class); /* (objc-sel.c) */ +extern void __objc_register_selectors_from_list (MethodList_t); /* (selector.c) */ +extern void __objc_update_dispatch_table_for_class (Class);/* (objc-msg.c) */ + +extern int __objc_init_thread_system(void); /* thread.c */ +extern int __objc_fini_thread_system(void); /* thread.c */ +extern void __objc_print_dtable_stats(void); /* sendmsg.c */ + +extern void class_add_method_list(Class, MethodList_t); + +/* Registering instance methods as class methods for root classes */ +extern void __objc_register_instance_methods_to_class(Class); +extern Method_t search_for_method_in_list(MethodList_t list, SEL op); + +/* True when class links has been resolved */ +extern BOOL __objc_class_links_resolved; + +/* Number of selectors stored in each of the selector tables */ +extern unsigned int __objc_selector_max_index; + +/* Mutex locking __objc_selector_max_index and its arrays. */ +extern objc_mutex_t __objc_runtime_mutex; + +/* Number of threads which are alive. */ +extern int __objc_runtime_threads_alive; + +#ifdef DEBUG +#define DEBUG_PRINTF(format, args...) printf (format, ## args) +#else +#define DEBUG_PRINTF(format, args...) +#endif + +BOOL __objc_responds_to (id object, SEL sel); /* for internal use only! */ +SEL __sel_register_typed_name (const char*, const char*, + struct objc_selector*, BOOL is_const); +extern void __objc_generate_gc_type_description (Class); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* not __objc_runtime_INCLUDE_GNU */ diff --git a/contrib/gcc-4.1/libobjc/objc/sarray.h b/contrib/gcc-4.1/libobjc/objc/sarray.h new file mode 100644 index 0000000000..fe66b2e9a7 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/objc/sarray.h @@ -0,0 +1,244 @@ +/* Sparse Arrays for Objective C dispatch tables + Copyright (C) 1993, 1995, 1996, 2004 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup. + +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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifndef __sarray_INCLUDE_GNU +#define __sarray_INCLUDE_GNU + +#include "thr.h" + +#define OBJC_SPARSE2 /* 2-level sparse array */ +/* #define OBJC_SPARSE3 */ /* 3-level sparse array */ + +#ifdef OBJC_SPARSE2 +extern const char* __objc_sparse2_id; +#endif + +#ifdef OBJC_SPARSE3 +extern const char* __objc_sparse3_id; +#endif + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +extern int nbuckets; /* for stats */ +extern int nindices; +extern int narrays; +extern int idxsize; + +/* An unsigned integer of same size as a pointer */ +#define SIZET_BITS (sizeof(size_t)*8) + +#if defined(__sparc__) || defined(OBJC_SPARSE2) +#define PRECOMPUTE_SELECTORS +#endif + +#ifdef OBJC_SPARSE3 + +/* Buckets are 8 words each */ +#define BUCKET_BITS 3 +#define BUCKET_SIZE (1< + indices[x.off.ioffset]-> + buckets[x.off.boffset]-> + elems[x.off.eoffset]; +#else /* OBJC_SPARSE2 */ + return array->buckets[x.off.boffset]->elems[x.off.eoffset]; +#endif /* OBJC_SPARSE2 */ +#else /* not PRECOMPUTE_SELECTORS */ +#ifdef OBJC_SPARSE3 + return array-> + indices[indx/INDEX_CAPACITY]-> + buckets[(indx/BUCKET_SIZE)%INDEX_SIZE]-> + elems[indx%BUCKET_SIZE]; +#else /* OBJC_SPARSE2 */ + return array->buckets[indx/BUCKET_SIZE]->elems[indx%BUCKET_SIZE]; +#endif /* not OBJC_SPARSE3 */ +#endif /* not PRECOMPUTE_SELECTORS */ +} + +static inline void* sarray_get_safe(struct sarray* array, sidx indx) +{ + if(soffset_decode(indx) < array->capacity) + return sarray_get(array, indx); + else + return (array->empty_bucket->elems[0]); +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __sarray_INCLUDE_GNU */ diff --git a/contrib/gcc-4.1/libobjc/objc/thr.h b/contrib/gcc-4.1/libobjc/objc/thr.h new file mode 100644 index 0000000000..c139926889 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/objc/thr.h @@ -0,0 +1,153 @@ +/* Thread and mutex controls for Objective C. + Copyright (C) 1996, 1997, 2002, 2004 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +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 2, 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. + +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 2, 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 COPYING. If not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + + +#ifndef __thread_INCLUDE_GNU +#define __thread_INCLUDE_GNU + +#include "objc.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/************************************************************************* + * Universal static variables: + */ +extern int __objc_thread_exit_status; /* Global exit status. */ + +/******** + * Thread safe implementation types and functions. + */ + +/* Thread priorities */ +#define OBJC_THREAD_INTERACTIVE_PRIORITY 2 +#define OBJC_THREAD_BACKGROUND_PRIORITY 1 +#define OBJC_THREAD_LOW_PRIORITY 0 + +/* A thread */ +typedef void * objc_thread_t; + +/* This structure represents a single mutual exclusion lock. */ +struct objc_mutex +{ + volatile objc_thread_t owner; /* Id of thread that owns. */ + volatile int depth; /* # of acquires. */ + void * backend; /* Specific to backend */ +}; +typedef struct objc_mutex *objc_mutex_t; + +/* This structure represents a single condition mutex */ +struct objc_condition +{ + void * backend; /* Specific to backend */ +}; +typedef struct objc_condition *objc_condition_t; + +/* Frontend mutex functions */ +objc_mutex_t objc_mutex_allocate (void); +int objc_mutex_deallocate (objc_mutex_t mutex); +int objc_mutex_lock (objc_mutex_t mutex); +int objc_mutex_unlock (objc_mutex_t mutex); +int objc_mutex_trylock (objc_mutex_t mutex); + +/* Frontend condition mutex functions */ +objc_condition_t objc_condition_allocate (void); +int objc_condition_deallocate (objc_condition_t condition); +int objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex); +int objc_condition_signal (objc_condition_t condition); +int objc_condition_broadcast (objc_condition_t condition); + +/* Frontend thread functions */ +objc_thread_t objc_thread_detach (SEL selector, id object, id argument); +void objc_thread_yield (void); +int objc_thread_exit (void); +int objc_thread_set_priority (int priority); +int objc_thread_get_priority (void); +void * objc_thread_get_data (void); +int objc_thread_set_data (void *value); +objc_thread_t objc_thread_id (void); +void objc_thread_add (void); +void objc_thread_remove (void); + +/* + Use this to set the hook function that will be called when the + runtime initially becomes multi threaded. + The hook function is only called once, meaning only when the + 2nd thread is spawned, not for each and every thread. + + It returns the previous hook function or NULL if there is none. + + A program outside of the runtime could set this to some function so + it can be informed; for example, the GNUstep Base Library sets it + so it can implement the NSBecomingMultiThreaded notification. + */ +typedef void (*objc_thread_callback) (void); +objc_thread_callback objc_set_thread_callback (objc_thread_callback func); + +/* Backend initialization functions */ +int __objc_init_thread_system (void); +int __objc_fini_thread_system (void); + +/* Backend mutex functions */ +int __objc_mutex_allocate (objc_mutex_t mutex); +int __objc_mutex_deallocate (objc_mutex_t mutex); +int __objc_mutex_lock (objc_mutex_t mutex); +int __objc_mutex_trylock (objc_mutex_t mutex); +int __objc_mutex_unlock (objc_mutex_t mutex); + +/* Backend condition mutex functions */ +int __objc_condition_allocate (objc_condition_t condition); +int __objc_condition_deallocate (objc_condition_t condition); +int __objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex); +int __objc_condition_broadcast (objc_condition_t condition); +int __objc_condition_signal (objc_condition_t condition); + +/* Backend thread functions */ +objc_thread_t __objc_thread_detach (void (*func) (void *arg), void *arg); +int __objc_thread_set_priority (int priority); +int __objc_thread_get_priority (void); +void __objc_thread_yield (void); +int __objc_thread_exit (void); +objc_thread_t __objc_thread_id (void); +int __objc_thread_set_data (void *value); +void * __objc_thread_get_data (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* not __thread_INCLUDE_GNU */ diff --git a/contrib/gcc-4.1/libobjc/objc/typedstream.h b/contrib/gcc-4.1/libobjc/objc/typedstream.h new file mode 100644 index 0000000000..3a5e0b3b80 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/objc/typedstream.h @@ -0,0 +1,141 @@ +/* GNU Objective-C Typed Streams interface. + Copyright (C) 1993, 1995, 2004 Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. */ + +#ifndef __typedstream_INCLUDE_GNU +#define __typedstream_INCLUDE_GNU + +#include "objc.h" +#include "hash.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef int (*objc_typed_read_func)(void*, char*, int); +typedef int (*objc_typed_write_func)(void*, const char*, int); +typedef int (*objc_typed_flush_func)(void*); +typedef int (*objc_typed_eof_func)(void*); + +#define OBJC_READONLY 0x01 +#define OBJC_WRITEONLY 0x02 + +#define OBJC_MANAGED_STREAM 0x01 +#define OBJC_FILE_STREAM 0x02 +#define OBJC_MEMORY_STREAM 0x04 + +#define OBJC_TYPED_STREAM_VERSION 0x01 + +typedef struct objc_typed_stream { + void* physical; + cache_ptr object_table; /* read/written objects */ + cache_ptr stream_table; /* other read/written but shared things.. */ + cache_ptr class_table; /* class version mapping */ + cache_ptr object_refs; /* forward references */ + int mode; /* OBJC_READONLY or OBJC_WRITEONLY */ + int type; /* MANAGED, FILE, MEMORY etc bit string */ + int version; /* version used when writing */ + int writing_root_p; + objc_typed_read_func read; + objc_typed_write_func write; + objc_typed_eof_func eof; + objc_typed_flush_func flush; +} TypedStream; + +/* opcode masks */ +#define _B_VALUE 0x1fU +#define _B_CODE 0xe0U +#define _B_SIGN 0x10U +#define _B_NUMBER 0x0fU + +/* standard opcodes */ +#define _B_INVALID 0x00U +#define _B_SINT 0x20U +#define _B_NINT 0x40U +#define _B_SSTR 0x60U +#define _B_NSTR 0x80U +#define _B_RCOMM 0xa0U +#define _B_UCOMM 0xc0U +#define _B_EXT 0xe0U + +/* eXtension opcodes */ +#define _BX_OBJECT 0x00U +#define _BX_CLASS 0x01U +#define _BX_SEL 0x02U +#define _BX_OBJREF 0x03U +#define _BX_OBJROOT 0x04U +#define _BX_EXT 0x1fU + +/* +** Read and write objects as specified by TYPE. All the `last' +** arguments are pointers to the objects to read/write. +*/ + +int objc_write_type (TypedStream* stream, const char* type, const void* data); +int objc_read_type (TypedStream* stream, const char* type, void* data); + +int objc_write_types (TypedStream* stream, const char* type, ...); +int objc_read_types (TypedStream* stream, const char* type, ...); + +int objc_write_object_reference (TypedStream* stream, id object); +int objc_write_root_object (TypedStream* stream, id object); + +long objc_get_stream_class_version (TypedStream* stream, Class class_type); + + +/* +** Convenience functions +*/ + +int objc_write_array (TypedStream* stream, const char* type, + int count, const void* data); +int objc_read_array (TypedStream* stream, const char* type, + int count, void* data); + +int objc_write_object (TypedStream* stream, id object); +int objc_read_object (TypedStream* stream, id* object); + + + +/* +** Open a typed stream for reading or writing. MODE may be either of +** OBJC_READONLY or OBJC_WRITEONLY. +*/ + +TypedStream* objc_open_typed_stream (FILE* physical, int mode); +TypedStream* objc_open_typed_stream_for_file (const char* file_name, int mode); + +void objc_close_typed_stream (TypedStream* stream); + +BOOL objc_end_of_typed_stream (TypedStream* stream); +void objc_flush_typed_stream (TypedStream* stream); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* not __typedstream_INCLUDE_GNU */ diff --git a/contrib/gcc-4.1/libobjc/objects.c b/contrib/gcc-4.1/libobjc/objects.c new file mode 100644 index 0000000000..7cc99bfcad --- /dev/null +++ b/contrib/gcc-4.1/libobjc/objects.c @@ -0,0 +1,103 @@ +/* GNU Objective C Runtime class related functions + Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +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 2, 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 COPYING. If not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "tconfig.h" /* include defs of bzero for target */ +#include "objc/objc.h" +#include "objc/runtime.h" /* the kitchen sink */ + +#if OBJC_WITH_GC +# include +#endif + +id __objc_object_alloc (Class); +id __objc_object_dispose (id); +id __objc_object_copy (id); + +id (*_objc_object_alloc) (Class) = __objc_object_alloc; /* !T:SINGLE */ +id (*_objc_object_dispose) (id) = __objc_object_dispose; /* !T:SINGLE */ +id (*_objc_object_copy) (id) = __objc_object_copy; /* !T:SINGLE */ + +id +class_create_instance (Class class) +{ + id new = nil; + +#if OBJC_WITH_GC + if (CLS_ISCLASS (class)) + new = (id) GC_malloc_explicitly_typed (class->instance_size, + class->gc_object_type); +#else + if (CLS_ISCLASS (class)) + new = (*_objc_object_alloc) (class); +#endif + + if (new != nil) + { + memset (new, 0, class->instance_size); + new->class_pointer = class; + } + return new; +} + +id +object_copy (id object) +{ + if ((object != nil) && CLS_ISCLASS (object->class_pointer)) + return (*_objc_object_copy) (object); + else + return nil; +} + +id +object_dispose (id object) +{ + if ((object != nil) && CLS_ISCLASS (object->class_pointer)) + { + if (_objc_object_dispose) + (*_objc_object_dispose) (object); + else + objc_free (object); + } + return nil; +} + +id __objc_object_alloc (Class class) +{ + return (id) objc_malloc (class->instance_size); +} + +id __objc_object_dispose (id object) +{ + objc_free (object); + return 0; +} + +id __objc_object_copy (id object) +{ + id copy = class_create_instance (object->class_pointer); + memcpy (copy, object, object->class_pointer->instance_size); + return copy; +} diff --git a/contrib/gcc-4.1/libobjc/sarray.c b/contrib/gcc-4.1/libobjc/sarray.c new file mode 100644 index 0000000000..b35772b3f5 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/sarray.c @@ -0,0 +1,518 @@ +/* Sparse Arrays for Objective C dispatch tables + Copyright (C) 1993, 1995, 1996, 2002, 2004 Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#include "objc/sarray.h" +#include "objc/runtime.h" +#include +#include "assert.h" + +int nbuckets = 0; /* !T:MUTEX */ +int nindices = 0; /* !T:MUTEX */ +int narrays = 0; /* !T:MUTEX */ +int idxsize = 0; /* !T:MUTEX */ + +static void *first_free_data = NULL; /* !T:MUTEX */ + +#ifdef OBJC_SPARSE2 +const char *__objc_sparse2_id = "2 level sparse indices"; +#endif + +#ifdef OBJC_SPARSE3 +const char *__objc_sparse3_id = "3 level sparse indices"; +#endif + +/* This function removes any structures left over from free operations + that were not safe in a multi-threaded environment. */ +void +sarray_remove_garbage (void) +{ + void **vp; + void *np; + + objc_mutex_lock (__objc_runtime_mutex); + + vp = first_free_data; + first_free_data = NULL; + + while (vp) { + np = *vp; + objc_free (vp); + vp = np; + } + + objc_mutex_unlock (__objc_runtime_mutex); +} + +/* Free a block of dynamically allocated memory. If we are in multi-threaded + mode, it is ok to free it. If not, we add it to the garbage heap to be + freed later. */ + +static void +sarray_free_garbage (void *vp) +{ + objc_mutex_lock (__objc_runtime_mutex); + + if (__objc_runtime_threads_alive == 1) { + objc_free (vp); + if (first_free_data) + sarray_remove_garbage (); + } + else { + *(void **)vp = first_free_data; + first_free_data = vp; + } + + objc_mutex_unlock (__objc_runtime_mutex); +} + +/* sarray_at_put : copies data in such a way as to be thread reader safe. */ +void +sarray_at_put (struct sarray *array, sidx index, void *element) +{ +#ifdef OBJC_SPARSE3 + struct sindex **the_index; + struct sindex *new_index; +#endif + struct sbucket **the_bucket; + struct sbucket *new_bucket; +#ifdef OBJC_SPARSE3 + size_t ioffset; +#endif + size_t boffset; + size_t eoffset; +#ifdef PRECOMPUTE_SELECTORS + union sofftype xx; + xx.idx = index; +#ifdef OBJC_SPARSE3 + ioffset = xx.off.ioffset; +#endif + boffset = xx.off.boffset; + eoffset = xx.off.eoffset; +#else /* not PRECOMPUTE_SELECTORS */ +#ifdef OBJC_SPARSE3 + ioffset = index/INDEX_CAPACITY; + boffset = (index/BUCKET_SIZE)%INDEX_SIZE; + eoffset = index%BUCKET_SIZE; +#else + boffset = index/BUCKET_SIZE; + eoffset = index%BUCKET_SIZE; +#endif +#endif /* not PRECOMPUTE_SELECTORS */ + + assert (soffset_decode (index) < array->capacity); /* Range check */ + +#ifdef OBJC_SPARSE3 + the_index = &(array->indices[ioffset]); + the_bucket = &((*the_index)->buckets[boffset]); +#else + the_bucket = &(array->buckets[boffset]); +#endif + + if ((*the_bucket)->elems[eoffset] == element) + return; /* great! we just avoided a lazy copy */ + +#ifdef OBJC_SPARSE3 + + /* First, perform lazy copy/allocation of index if needed */ + + if ((*the_index) == array->empty_index) { + + /* The index was previously empty, allocate a new */ + new_index = (struct sindex *) objc_malloc (sizeof (struct sindex)); + memcpy (new_index, array->empty_index, sizeof (struct sindex)); + new_index->version.version = array->version.version; + *the_index = new_index; /* Prepared for install. */ + the_bucket = &((*the_index)->buckets[boffset]); + + nindices += 1; + } else if ((*the_index)->version.version != array->version.version) { + + /* This index must be lazy copied */ + struct sindex *old_index = *the_index; + new_index = (struct sindex *) objc_malloc (sizeof (struct sindex)); + memcpy (new_index, old_index, sizeof (struct sindex)); + new_index->version.version = array->version.version; + *the_index = new_index; /* Prepared for install. */ + the_bucket = &((*the_index)->buckets[boffset]); + + nindices += 1; + } + +#endif /* OBJC_SPARSE3 */ + + /* next, perform lazy allocation/copy of the bucket if needed */ + + if ((*the_bucket) == array->empty_bucket) { + + /* The bucket was previously empty (or something like that), */ + /* allocate a new. This is the effect of `lazy' allocation */ + new_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket)); + memcpy ((void *) new_bucket, (const void *) array->empty_bucket, + sizeof (struct sbucket)); + new_bucket->version.version = array->version.version; + *the_bucket = new_bucket; /* Prepared for install. */ + + nbuckets += 1; + + } else if ((*the_bucket)->version.version != array->version.version) { + + /* Perform lazy copy. */ + struct sbucket *old_bucket = *the_bucket; + new_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket)); + memcpy (new_bucket, old_bucket, sizeof (struct sbucket)); + new_bucket->version.version = array->version.version; + *the_bucket = new_bucket; /* Prepared for install. */ + + nbuckets += 1; + + } + (*the_bucket)->elems[eoffset] = element; +} + +void +sarray_at_put_safe (struct sarray *array, sidx index, void *element) +{ + if (soffset_decode (index) >= array->capacity) + sarray_realloc (array, soffset_decode (index) + 1); + sarray_at_put (array, index, element); +} + +struct sarray * +sarray_new (int size, void *default_element) +{ + struct sarray *arr; +#ifdef OBJC_SPARSE3 + size_t num_indices = ((size - 1)/(INDEX_CAPACITY)) + 1; + struct sindex **new_indices; +#else /* OBJC_SPARSE2 */ + size_t num_indices = ((size - 1)/BUCKET_SIZE) + 1; + struct sbucket **new_buckets; +#endif + size_t counter; + + assert (size > 0); + + /* Allocate core array */ + arr = (struct sarray *) objc_malloc (sizeof (struct sarray)); + arr->version.version = 0; + + /* Initialize members */ +#ifdef OBJC_SPARSE3 + arr->capacity = num_indices*INDEX_CAPACITY; + new_indices = (struct sindex **) + objc_malloc (sizeof (struct sindex *) * num_indices); + + arr->empty_index = (struct sindex *) objc_malloc (sizeof (struct sindex)); + arr->empty_index->version.version = 0; + + narrays += 1; + idxsize += num_indices; + nindices += 1; + +#else /* OBJC_SPARSE2 */ + arr->capacity = num_indices*BUCKET_SIZE; + new_buckets = (struct sbucket **) + objc_malloc (sizeof (struct sbucket *) * num_indices); + + narrays += 1; + idxsize += num_indices; + +#endif + + arr->empty_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket)); + arr->empty_bucket->version.version = 0; + + nbuckets += 1; + + arr->ref_count = 1; + arr->is_copy_of = (struct sarray *) 0; + + for (counter = 0; counter < BUCKET_SIZE; counter++) + arr->empty_bucket->elems[counter] = default_element; + +#ifdef OBJC_SPARSE3 + for (counter = 0; counter < INDEX_SIZE; counter++) + arr->empty_index->buckets[counter] = arr->empty_bucket; + + for (counter = 0; counter < num_indices; counter++) + new_indices[counter] = arr->empty_index; + +#else /* OBJC_SPARSE2 */ + + for (counter = 0; counter < num_indices; counter++) + new_buckets[counter] = arr->empty_bucket; + +#endif + +#ifdef OBJC_SPARSE3 + arr->indices = new_indices; +#else /* OBJC_SPARSE2 */ + arr->buckets = new_buckets; +#endif + + return arr; +} + + +/* Reallocate the sparse array to hold `newsize' entries + Note: We really allocate and then free. We have to do this to ensure that + any concurrent readers notice the update. */ + +void +sarray_realloc (struct sarray *array, int newsize) +{ +#ifdef OBJC_SPARSE3 + size_t old_max_index = (array->capacity - 1)/INDEX_CAPACITY; + size_t new_max_index = ((newsize - 1)/INDEX_CAPACITY); + size_t rounded_size = (new_max_index + 1) * INDEX_CAPACITY; + + struct sindex **new_indices; + struct sindex **old_indices; + +#else /* OBJC_SPARSE2 */ + size_t old_max_index = (array->capacity - 1)/BUCKET_SIZE; + size_t new_max_index = ((newsize - 1)/BUCKET_SIZE); + size_t rounded_size = (new_max_index + 1) * BUCKET_SIZE; + + struct sbucket **new_buckets; + struct sbucket **old_buckets; + +#endif + + size_t counter; + + assert (newsize > 0); + + /* The size is the same, just ignore the request */ + if (rounded_size <= array->capacity) + return; + + assert (array->ref_count == 1); /* stop if lazy copied... */ + + /* We are asked to extend the array -- allocate new bucket table, */ + /* and insert empty_bucket in newly allocated places. */ + if (rounded_size > array->capacity) + { + +#ifdef OBJC_SPARSE3 + new_max_index += 4; + rounded_size = (new_max_index + 1) * INDEX_CAPACITY; + +#else /* OBJC_SPARSE2 */ + new_max_index += 4; + rounded_size = (new_max_index + 1) * BUCKET_SIZE; +#endif + + /* update capacity */ + array->capacity = rounded_size; + +#ifdef OBJC_SPARSE3 + /* alloc to force re-read by any concurrent readers. */ + old_indices = array->indices; + new_indices = (struct sindex **) + objc_malloc ((new_max_index + 1) * sizeof (struct sindex *)); +#else /* OBJC_SPARSE2 */ + old_buckets = array->buckets; + new_buckets = (struct sbucket **) + objc_malloc ((new_max_index + 1) * sizeof (struct sbucket *)); +#endif + + /* copy buckets below old_max_index (they are still valid) */ + for (counter = 0; counter <= old_max_index; counter++ ) { +#ifdef OBJC_SPARSE3 + new_indices[counter] = old_indices[counter]; +#else /* OBJC_SPARSE2 */ + new_buckets[counter] = old_buckets[counter]; +#endif + } + +#ifdef OBJC_SPARSE3 + /* reset entries above old_max_index to empty_bucket */ + for (counter = old_max_index + 1; counter <= new_max_index; counter++) + new_indices[counter] = array->empty_index; +#else /* OBJC_SPARSE2 */ + /* reset entries above old_max_index to empty_bucket */ + for (counter = old_max_index + 1; counter <= new_max_index; counter++) + new_buckets[counter] = array->empty_bucket; +#endif + +#ifdef OBJC_SPARSE3 + /* install the new indices */ + array->indices = new_indices; +#else /* OBJC_SPARSE2 */ + array->buckets = new_buckets; +#endif + +#ifdef OBJC_SPARSE3 + /* free the old indices */ + sarray_free_garbage (old_indices); +#else /* OBJC_SPARSE2 */ + sarray_free_garbage (old_buckets); +#endif + + idxsize += (new_max_index-old_max_index); + return; + } +} + + +/* Free a sparse array allocated with sarray_new */ + +void +sarray_free (struct sarray *array) { +#ifdef OBJC_SPARSE3 + size_t old_max_index = (array->capacity - 1)/INDEX_CAPACITY; + struct sindex **old_indices; +#else + size_t old_max_index = (array->capacity - 1)/BUCKET_SIZE; + struct sbucket **old_buckets; +#endif + size_t counter = 0; + + assert (array->ref_count != 0); /* Freed multiple times!!! */ + + if (--(array->ref_count) != 0) /* There exists copies of me */ + return; + +#ifdef OBJC_SPARSE3 + old_indices = array->indices; +#else + old_buckets = array->buckets; +#endif + + /* Free all entries that do not point to empty_bucket */ + for (counter = 0; counter <= old_max_index; counter++ ) { +#ifdef OBJC_SPARSE3 + struct sindex *idx = old_indices[counter]; + if ((idx != array->empty_index) && + (idx->version.version == array->version.version)) { + int c2; + for (c2 = 0; c2 < INDEX_SIZE; c2++) { + struct sbucket *bkt = idx->buckets[c2]; + if ((bkt != array->empty_bucket) && + (bkt->version.version == array->version.version)) + { + sarray_free_garbage (bkt); + nbuckets -= 1; + } + } + sarray_free_garbage (idx); + nindices -= 1; + } +#else /* OBJC_SPARSE2 */ + struct sbucket *bkt = array->buckets[counter]; + if ((bkt != array->empty_bucket) && + (bkt->version.version == array->version.version)) + { + sarray_free_garbage (bkt); + nbuckets -= 1; + } +#endif + } + +#ifdef OBJC_SPARSE3 + /* free empty_index */ + if (array->empty_index->version.version == array->version.version) { + sarray_free_garbage (array->empty_index); + nindices -= 1; + } +#endif + + /* free empty_bucket */ + if (array->empty_bucket->version.version == array->version.version) { + sarray_free_garbage (array->empty_bucket); + nbuckets -= 1; + } + idxsize -= (old_max_index + 1); + narrays -= 1; + +#ifdef OBJC_SPARSE3 + /* free bucket table */ + sarray_free_garbage (array->indices); + +#else + /* free bucket table */ + sarray_free_garbage (array->buckets); + +#endif + + /* If this is a copy of another array, we free it (which might just + * decrement its reference count so it will be freed when no longer in use). + */ + if (array->is_copy_of) + sarray_free (array->is_copy_of); + + /* free array */ + sarray_free_garbage (array); +} + +/* This is a lazy copy. Only the core of the structure is actually */ +/* copied. */ + +struct sarray * +sarray_lazy_copy (struct sarray *oarr) +{ + struct sarray *arr; + +#ifdef OBJC_SPARSE3 + size_t num_indices = ((oarr->capacity - 1)/INDEX_CAPACITY) + 1; + struct sindex **new_indices; +#else /* OBJC_SPARSE2 */ + size_t num_indices = ((oarr->capacity - 1)/BUCKET_SIZE) + 1; + struct sbucket **new_buckets; +#endif + + /* Allocate core array */ + arr = (struct sarray *) objc_malloc (sizeof (struct sarray)); /* !!! */ + arr->version.version = oarr->version.version + 1; +#ifdef OBJC_SPARSE3 + arr->empty_index = oarr->empty_index; +#endif + arr->empty_bucket = oarr->empty_bucket; + arr->ref_count = 1; + oarr->ref_count += 1; + arr->is_copy_of = oarr; + arr->capacity = oarr->capacity; + +#ifdef OBJC_SPARSE3 + /* Copy bucket table */ + new_indices = (struct sindex **) + objc_malloc (sizeof (struct sindex *) * num_indices); + memcpy (new_indices, oarr->indices, sizeof (struct sindex *) * num_indices); + arr->indices = new_indices; +#else + /* Copy bucket table */ + new_buckets = (struct sbucket **) + objc_malloc (sizeof (struct sbucket *) * num_indices); + memcpy (new_buckets, oarr->buckets, sizeof (struct sbucket *) * num_indices); + arr->buckets = new_buckets; +#endif + + idxsize += num_indices; + narrays += 1; + + return arr; +} diff --git a/contrib/gcc-4.1/libobjc/selector.c b/contrib/gcc-4.1/libobjc/selector.c new file mode 100644 index 0000000000..223c7100ef --- /dev/null +++ b/contrib/gcc-4.1/libobjc/selector.c @@ -0,0 +1,490 @@ +/* GNU Objective C Runtime selector related functions + Copyright (C) 1993, 1995, 1996, 1997, 2002, 2004 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +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 2, 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 COPYING. If not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "objc/runtime.h" +#include "objc/sarray.h" +#include "objc/encoding.h" + +/* Initial selector hash table size. Value doesn't matter much */ +#define SELECTOR_HASH_SIZE 128 + +/* Tables mapping selector names to uid and opposite */ +static struct sarray *__objc_selector_array = 0; /* uid -> sel !T:MUTEX */ +static struct sarray *__objc_selector_names = 0; /* uid -> name !T:MUTEX */ +static cache_ptr __objc_selector_hash = 0; /* name -> uid !T:MUTEX */ + +/* Number of selectors stored in each of the above tables */ +unsigned int __objc_selector_max_index = 0; /* !T:MUTEX */ + +void __objc_init_selector_tables (void) +{ + __objc_selector_array = sarray_new (SELECTOR_HASH_SIZE, 0); + __objc_selector_names = sarray_new (SELECTOR_HASH_SIZE, 0); + __objc_selector_hash + = objc_hash_new (SELECTOR_HASH_SIZE, + (hash_func_type) objc_hash_string, + (compare_func_type) objc_compare_strings); +} + +/* This routine is given a class and records all of the methods in its class + structure in the record table. */ +void +__objc_register_selectors_from_class (Class class) +{ + MethodList_t method_list; + + method_list = class->methods; + while (method_list) + { + __objc_register_selectors_from_list (method_list); + method_list = method_list->method_next; + } +} + + +/* This routine is given a list of methods and records each of the methods in + the record table. This is the routine that does the actual recording + work. + + The name and type pointers in the method list must be permanent and + immutable. + */ +void +__objc_register_selectors_from_list (MethodList_t method_list) +{ + int i = 0; + + objc_mutex_lock (__objc_runtime_mutex); + while (i < method_list->method_count) + { + Method_t method = &method_list->method_list[i]; + if (method->method_name) + { + method->method_name + = __sel_register_typed_name ((const char *) method->method_name, + method->method_types, 0, YES); + } + i += 1; + } + objc_mutex_unlock (__objc_runtime_mutex); +} + + +/* Register instance methods as class methods for root classes */ +void __objc_register_instance_methods_to_class (Class class) +{ + MethodList_t method_list; + MethodList_t class_method_list; + int max_methods_no = 16; + MethodList_t new_list; + Method_t curr_method; + + /* Only if a root class. */ + if (class->super_class) + return; + + /* Allocate a method list to hold the new class methods */ + new_list = objc_calloc (sizeof (struct objc_method_list) + + sizeof (struct objc_method[max_methods_no]), 1); + method_list = class->methods; + class_method_list = class->class_pointer->methods; + curr_method = &new_list->method_list[0]; + + /* Iterate through the method lists for the class */ + while (method_list) + { + int i; + + /* Iterate through the methods from this method list */ + for (i = 0; i < method_list->method_count; i++) + { + Method_t mth = &method_list->method_list[i]; + if (mth->method_name + && ! search_for_method_in_list (class_method_list, + mth->method_name)) + { + /* This instance method isn't a class method. + Add it into the new_list. */ + *curr_method = *mth; + + /* Reallocate the method list if necessary */ + if (++new_list->method_count == max_methods_no) + new_list = + objc_realloc (new_list, sizeof (struct objc_method_list) + + sizeof (struct + objc_method[max_methods_no += 16])); + curr_method = &new_list->method_list[new_list->method_count]; + } + } + + method_list = method_list->method_next; + } + + /* If we created any new class methods + then attach the method list to the class */ + if (new_list->method_count) + { + new_list = + objc_realloc (new_list, sizeof (struct objc_method_list) + + sizeof (struct objc_method[new_list->method_count])); + new_list->method_next = class->class_pointer->methods; + class->class_pointer->methods = new_list; + } + else + objc_free(new_list); + + __objc_update_dispatch_table_for_class (class->class_pointer); +} + + +/* Returns YES iff t1 and t2 have same method types, but we ignore + the argframe layout */ +BOOL +sel_types_match (const char *t1, const char *t2) +{ + if (! t1 || ! t2) + return NO; + while (*t1 && *t2) + { + if (*t1 == '+') t1++; + if (*t2 == '+') t2++; + while (isdigit ((unsigned char) *t1)) t1++; + while (isdigit ((unsigned char) *t2)) t2++; + /* xxx Remove these next two lines when qualifiers are put in + all selectors, not just Protocol selectors. */ + t1 = objc_skip_type_qualifiers (t1); + t2 = objc_skip_type_qualifiers (t2); + if (! *t1 && ! *t2) + return YES; + if (*t1 != *t2) + return NO; + t1++; + t2++; + } + return NO; +} + +/* return selector representing name */ +SEL +sel_get_typed_uid (const char *name, const char *types) +{ + struct objc_list *l; + sidx i; + + objc_mutex_lock (__objc_runtime_mutex); + + i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name); + if (i == 0) + { + objc_mutex_unlock (__objc_runtime_mutex); + return 0; + } + + for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i); + l; l = l->tail) + { + SEL s = (SEL) l->head; + if (types == 0 || s->sel_types == 0) + { + if (s->sel_types == types) + { + objc_mutex_unlock (__objc_runtime_mutex); + return s; + } + } + else if (sel_types_match (s->sel_types, types)) + { + objc_mutex_unlock (__objc_runtime_mutex); + return s; + } + } + + objc_mutex_unlock (__objc_runtime_mutex); + return 0; +} + +/* Return selector representing name; prefer a selector with non-NULL type */ +SEL +sel_get_any_typed_uid (const char *name) +{ + struct objc_list *l; + sidx i; + SEL s = NULL; + + objc_mutex_lock (__objc_runtime_mutex); + + i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name); + if (i == 0) + { + objc_mutex_unlock (__objc_runtime_mutex); + return 0; + } + + for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i); + l; l = l->tail) + { + s = (SEL) l->head; + if (s->sel_types) + { + objc_mutex_unlock (__objc_runtime_mutex); + return s; + } + } + + objc_mutex_unlock (__objc_runtime_mutex); + return s; +} + +/* return selector representing name */ +SEL +sel_get_any_uid (const char *name) +{ + struct objc_list *l; + sidx i; + + objc_mutex_lock (__objc_runtime_mutex); + + i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name); + if (soffset_decode (i) == 0) + { + objc_mutex_unlock (__objc_runtime_mutex); + return 0; + } + + l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i); + objc_mutex_unlock (__objc_runtime_mutex); + + if (l == 0) + return 0; + + return (SEL) l->head; +} + +/* return selector representing name */ +SEL +sel_get_uid (const char *name) +{ + return sel_register_typed_name (name, 0); +} + +/* Get name of selector. If selector is unknown, the empty string "" + is returned */ +const char *sel_get_name (SEL selector) +{ + const char *ret; + + objc_mutex_lock (__objc_runtime_mutex); + if ((soffset_decode ((sidx)selector->sel_id) > 0) + && (soffset_decode ((sidx)selector->sel_id) <= __objc_selector_max_index)) + ret = sarray_get_safe (__objc_selector_names, (sidx) selector->sel_id); + else + ret = 0; + objc_mutex_unlock (__objc_runtime_mutex); + return ret; +} + +BOOL +sel_is_mapped (SEL selector) +{ + unsigned int idx = soffset_decode ((sidx)selector->sel_id); + return ((idx > 0) && (idx <= __objc_selector_max_index)); +} + + +const char *sel_get_type (SEL selector) +{ + if (selector) + return selector->sel_types; + else + return 0; +} + +/* The uninstalled dispatch table */ +extern struct sarray *__objc_uninstalled_dtable; + +/* __sel_register_typed_name allocates lots of struct objc_selector:s + of 8 (16, if pointers are 64 bits) bytes at startup. To reduce the number + of malloc calls and memory lost to malloc overhead, we allocate + objc_selector:s in blocks here. This is only called from + __sel_register_typed_name, and __sel_register_typed_name may only be + called when __objc_runtime_mutex is locked. + + Note that the objc_selector:s allocated from __sel_register_typed_name + are never freed. + + 62 because 62 * sizeof (struct objc_selector) = 496 (992). This should + let malloc add some overhead and use a nice, round 512 (1024) byte chunk. + */ +#define SELECTOR_POOL_SIZE 62 +static struct objc_selector *selector_pool; +static int selector_pool_left; + +static struct objc_selector * +pool_alloc_selector(void) +{ + if (!selector_pool_left) + { + selector_pool = objc_malloc (sizeof (struct objc_selector) + * SELECTOR_POOL_SIZE); + selector_pool_left = SELECTOR_POOL_SIZE; + } + return &selector_pool[--selector_pool_left]; +} + +/* Store the passed selector name in the selector record and return its + selector value (value returned by sel_get_uid). + Assumes that the calling function has locked down __objc_runtime_mutex. */ +/* is_const parameter tells us if the name and types parameters + are really constant or not. If YES then they are constant and + we can just store the pointers. If NO then we need to copy + name and types because the pointers may disappear later on. */ +SEL +__sel_register_typed_name (const char *name, const char *types, + struct objc_selector *orig, BOOL is_const) +{ + struct objc_selector *j; + sidx i; + struct objc_list *l; + + i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name); + if (soffset_decode (i) != 0) + { + for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i); + l; l = l->tail) + { + SEL s = (SEL) l->head; + if (types == 0 || s->sel_types == 0) + { + if (s->sel_types == types) + { + if (orig) + { + orig->sel_id = (void *) i; + return orig; + } + else + return s; + } + } + else if (! strcmp (s->sel_types, types)) + { + if (orig) + { + orig->sel_id = (void *) i; + return orig; + } + else + return s; + } + } + if (orig) + j = orig; + else + j = pool_alloc_selector (); + + j->sel_id = (void *) i; + /* Can we use the pointer or must copy types? Don't copy if NULL */ + if ((is_const) || (types == 0)) + j->sel_types = (const char *) types; + else { + j->sel_types = (char *) objc_malloc (strlen (types) + 1); + strcpy ((char *) j->sel_types, types); + } + l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i); + } + else + { + __objc_selector_max_index += 1; + i = soffset_encode (__objc_selector_max_index); + if (orig) + j = orig; + else + j = pool_alloc_selector (); + + j->sel_id = (void *) i; + /* Can we use the pointer or must copy types? Don't copy if NULL */ + if ((is_const) || (types == 0)) + j->sel_types = (const char *) types; + else { + j->sel_types = (char *) objc_malloc (strlen (types) + 1); + strcpy ((char *) j->sel_types, types); + } + l = 0; + } + + DEBUG_PRINTF ("Record selector %s[%s] as: %ld\n", name, types, + (long) soffset_decode (i)); + + { + int is_new = (l == 0); + const char *new_name; + + /* Can we use the pointer or must copy name? Don't copy if NULL */ + if ((is_const) || (name == 0)) + new_name = name; + else { + new_name = (char *) objc_malloc (strlen (name) + 1); + strcpy ((char *) new_name, name); + } + + l = list_cons ((void *) j, l); + sarray_at_put_safe (__objc_selector_names, i, (void *) new_name); + sarray_at_put_safe (__objc_selector_array, i, (void *) l); + if (is_new) + objc_hash_add (&__objc_selector_hash, (void *) new_name, (void *) i); + } + + sarray_realloc (__objc_uninstalled_dtable, __objc_selector_max_index + 1); + + return (SEL) j; +} + +SEL +sel_register_name (const char *name) +{ + SEL ret; + + objc_mutex_lock (__objc_runtime_mutex); + /* Assume that name is not constant static memory and needs to be + copied before put into a runtime structure. is_const == NO */ + ret = __sel_register_typed_name (name, 0, 0, NO); + objc_mutex_unlock (__objc_runtime_mutex); + + return ret; +} + +SEL +sel_register_typed_name (const char *name, const char *type) +{ + SEL ret; + + objc_mutex_lock (__objc_runtime_mutex); + /* Assume that name and type are not constant static memory and need to + be copied before put into a runtime structure. is_const == NO */ + ret = __sel_register_typed_name (name, type, 0, NO); + objc_mutex_unlock (__objc_runtime_mutex); + + return ret; +} diff --git a/contrib/gcc-4.1/libobjc/sendmsg.c b/contrib/gcc-4.1/libobjc/sendmsg.c new file mode 100644 index 0000000000..9453ef3dd4 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/sendmsg.c @@ -0,0 +1,701 @@ +/* GNU Objective C Runtime message lookup + Copyright (C) 1993, 1995, 1996, 1997, 1998, + 2001, 2002, 2004 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +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 2, 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 COPYING. If not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +/* FIXME: This file has no business including tm.h. */ +/* FIXME: This should be using libffi instead of __builtin_apply + and friends. */ + +#include "tconfig.h" +#include "coretypes.h" +#include "tm.h" +#include "objc/runtime.h" +#include "objc/sarray.h" +#include "objc/encoding.h" +#include "runtime-info.h" + +/* This is how we hack STRUCT_VALUE to be 1 or 0. */ +#define gen_rtx(args...) 1 +#define gen_rtx_MEM(args...) 1 +#define gen_rtx_REG(args...) 1 +#define rtx int + +#if ! defined (STRUCT_VALUE) || STRUCT_VALUE == 0 +#define INVISIBLE_STRUCT_RETURN 1 +#else +#define INVISIBLE_STRUCT_RETURN 0 +#endif + +/* The uninstalled dispatch table */ +struct sarray *__objc_uninstalled_dtable = 0; /* !T:MUTEX */ + +/* Hook for method forwarding. If it is set, is invoked to return a + function that performs the real forwarding. Otherwise the libgcc + based functions (__builtin_apply and friends) are used. */ +IMP (*__objc_msg_forward) (SEL) = NULL; + +/* Send +initialize to class */ +static void __objc_send_initialize (Class); + +static void __objc_install_dispatch_table_for_class (Class); + +/* Forward declare some functions */ +static void __objc_init_install_dtable (id, SEL); + +/* Various forwarding functions that are used based upon the + return type for the selector. + __objc_block_forward for structures. + __objc_double_forward for floats/doubles. + __objc_word_forward for pointers or types that fit in registers. + */ +static double __objc_double_forward (id, SEL, ...); +static id __objc_word_forward (id, SEL, ...); +typedef struct { id many[8]; } __big; +#if INVISIBLE_STRUCT_RETURN +static __big +#else +static id +#endif +__objc_block_forward (id, SEL, ...); +static Method_t search_for_method_in_hierarchy (Class class, SEL sel); +Method_t search_for_method_in_list (MethodList_t list, SEL op); +id nil_method (id, SEL); + +/* Given a selector, return the proper forwarding implementation. */ +inline +IMP +__objc_get_forward_imp (SEL sel) +{ + /* If a custom forwarding hook was registered, try getting a forwarding + * function from it. */ + if (__objc_msg_forward) + { + IMP result; + if ((result = __objc_msg_forward (sel)) != NULL) + return result; + } + + /* In all other cases, use the default forwarding functions built using + * __builtin_apply and friends. */ + { + const char *t = sel->sel_types; + + if (t && (*t == '[' || *t == '(' || *t == '{') +#ifdef OBJC_MAX_STRUCT_BY_VALUE + && objc_sizeof_type (t) > OBJC_MAX_STRUCT_BY_VALUE +#endif + ) + return (IMP)__objc_block_forward; + else if (t && (*t == 'f' || *t == 'd')) + return (IMP)__objc_double_forward; + else + return (IMP)__objc_word_forward; + } +} + +/* Given a class and selector, return the selector's implementation. */ +inline +IMP +get_imp (Class class, SEL sel) +{ + /* In a vanilla implementation we would first check if the dispatch + table is installed. Here instead, to get more speed in the + standard case (that the dispatch table is installed) we first try + to get the imp using brute force. Only if that fails, we do what + we should have been doing from the very beginning, that is, check + if the dispatch table needs to be installed, install it if it's + not installed, and retrieve the imp from the table if it's + installed. */ + void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id); + if (res == 0) + { + /* Not a valid method */ + if (class->dtable == __objc_uninstalled_dtable) + { + /* The dispatch table needs to be installed. */ + objc_mutex_lock (__objc_runtime_mutex); + + /* Double-checked locking pattern: Check + __objc_uninstalled_dtable again in case another thread + installed the dtable while we were waiting for the lock + to be released. */ + if (class->dtable == __objc_uninstalled_dtable) + { + __objc_install_dispatch_table_for_class (class); + } + + objc_mutex_unlock (__objc_runtime_mutex); + /* Call ourselves with the installed dispatch table + and get the real method */ + res = get_imp (class, sel); + } + else + { + /* The dispatch table has been installed. */ + + /* Get the method from the dispatch table (we try to get it + again in case another thread has installed the dtable just + after we invoked sarray_get_safe, but before we checked + class->dtable == __objc_uninstalled_dtable). + */ + res = sarray_get_safe (class->dtable, (size_t) sel->sel_id); + if (res == 0) + { + /* The dispatch table has been installed, and the method + is not in the dispatch table. So the method just + doesn't exist for the class. Return the forwarding + implementation. */ + res = __objc_get_forward_imp (sel); + } + } + } + return res; +} + +/* Query if an object can respond to a selector, returns YES if the +object implements the selector otherwise NO. Does not check if the +method can be forwarded. */ +inline +BOOL +__objc_responds_to (id object, SEL sel) +{ + void *res; + + /* Install dispatch table if need be */ + if (object->class_pointer->dtable == __objc_uninstalled_dtable) + { + objc_mutex_lock (__objc_runtime_mutex); + if (object->class_pointer->dtable == __objc_uninstalled_dtable) + { + __objc_install_dispatch_table_for_class (object->class_pointer); + } + objc_mutex_unlock (__objc_runtime_mutex); + } + + /* Get the method from the dispatch table */ + res = sarray_get_safe (object->class_pointer->dtable, (size_t) sel->sel_id); + return (res != 0); +} + +/* This is the lookup function. All entries in the table are either a + valid method *or* zero. If zero then either the dispatch table + needs to be installed or it doesn't exist and forwarding is attempted. */ +inline +IMP +objc_msg_lookup (id receiver, SEL op) +{ + IMP result; + if (receiver) + { + result = sarray_get_safe (receiver->class_pointer->dtable, + (sidx)op->sel_id); + if (result == 0) + { + /* Not a valid method */ + if (receiver->class_pointer->dtable == __objc_uninstalled_dtable) + { + /* The dispatch table needs to be installed. + This happens on the very first method call to the class. */ + __objc_init_install_dtable (receiver, op); + + /* Get real method for this in newly installed dtable */ + result = get_imp (receiver->class_pointer, op); + } + else + { + /* The dispatch table has been installed. Check again + if the method exists (just in case the dispatch table + has been installed by another thread after we did the + previous check that the method exists). + */ + result = sarray_get_safe (receiver->class_pointer->dtable, + (sidx)op->sel_id); + if (result == 0) + { + /* If the method still just doesn't exist for the + class, attempt to forward the method. */ + result = __objc_get_forward_imp (op); + } + } + } + return result; + } + else + return (IMP)nil_method; +} + +IMP +objc_msg_lookup_super (Super_t super, SEL sel) +{ + if (super->self) + return get_imp (super->class, sel); + else + return (IMP)nil_method; +} + +int method_get_sizeof_arguments (Method *); + +retval_t +objc_msg_sendv (id object, SEL op, arglist_t arg_frame) +{ + Method *m = class_get_instance_method (object->class_pointer, op); + const char *type; + *((id *) method_get_first_argument (m, arg_frame, &type)) = object; + *((SEL *) method_get_next_argument (arg_frame, &type)) = op; + return __builtin_apply ((apply_t) m->method_imp, + arg_frame, + method_get_sizeof_arguments (m)); +} + +void +__objc_init_dispatch_tables () +{ + __objc_uninstalled_dtable = sarray_new (200, 0); +} + +/* This function is called by objc_msg_lookup when the + dispatch table needs to be installed; thus it is called once + for each class, namely when the very first message is sent to it. */ +static void +__objc_init_install_dtable (id receiver, SEL op __attribute__ ((__unused__))) +{ + objc_mutex_lock (__objc_runtime_mutex); + + /* This may happen, if the programmer has taken the address of a + method before the dtable was initialized... too bad for him! */ + if (receiver->class_pointer->dtable != __objc_uninstalled_dtable) + { + objc_mutex_unlock (__objc_runtime_mutex); + return; + } + + if (CLS_ISCLASS (receiver->class_pointer)) + { + /* receiver is an ordinary object */ + assert (CLS_ISCLASS (receiver->class_pointer)); + + /* install instance methods table */ + __objc_install_dispatch_table_for_class (receiver->class_pointer); + + /* call +initialize -- this will in turn install the factory + dispatch table if not already done :-) */ + __objc_send_initialize (receiver->class_pointer); + } + else + { + /* receiver is a class object */ + assert (CLS_ISCLASS ((Class)receiver)); + assert (CLS_ISMETA (receiver->class_pointer)); + + /* Install real dtable for factory methods */ + __objc_install_dispatch_table_for_class (receiver->class_pointer); + + __objc_send_initialize ((Class)receiver); + } + objc_mutex_unlock (__objc_runtime_mutex); +} + +/* Install dummy table for class which causes the first message to + that class (or instances hereof) to be initialized properly */ +void +__objc_install_premature_dtable (Class class) +{ + assert (__objc_uninstalled_dtable); + class->dtable = __objc_uninstalled_dtable; +} + +/* Send +initialize to class if not already done */ +static void +__objc_send_initialize (Class class) +{ + /* This *must* be a class object */ + assert (CLS_ISCLASS (class)); + assert (! CLS_ISMETA (class)); + + if (! CLS_ISINITIALIZED (class)) + { + CLS_SETINITIALIZED (class); + CLS_SETINITIALIZED (class->class_pointer); + + /* Create the garbage collector type memory description */ + __objc_generate_gc_type_description (class); + + if (class->super_class) + __objc_send_initialize (class->super_class); + + { + SEL op = sel_register_name ("initialize"); + IMP imp = 0; + MethodList_t method_list = class->class_pointer->methods; + + while (method_list) { + int i; + Method_t method; + + for (i = 0; i < method_list->method_count; i++) { + method = &(method_list->method_list[i]); + if (method->method_name + && method->method_name->sel_id == op->sel_id) { + imp = method->method_imp; + break; + } + } + + if (imp) + break; + + method_list = method_list->method_next; + + } + if (imp) + (*imp) ((id) class, op); + + } + } +} + +/* Walk on the methods list of class and install the methods in the reverse + order of the lists. Since methods added by categories are before the methods + of class in the methods list, this allows categories to substitute methods + declared in class. However if more than one category replaces the same + method nothing is guaranteed about what method will be used. + Assumes that __objc_runtime_mutex is locked down. */ +static void +__objc_install_methods_in_dtable (Class class, MethodList_t method_list) +{ + int i; + + if (! method_list) + return; + + if (method_list->method_next) + __objc_install_methods_in_dtable (class, method_list->method_next); + + for (i = 0; i < method_list->method_count; i++) + { + Method_t method = &(method_list->method_list[i]); + sarray_at_put_safe (class->dtable, + (sidx) method->method_name->sel_id, + method->method_imp); + } +} + +/* Assumes that __objc_runtime_mutex is locked down. */ +static void +__objc_install_dispatch_table_for_class (Class class) +{ + Class super; + + /* If the class has not yet had its class links resolved, we must + re-compute all class links */ + if (! CLS_ISRESOLV (class)) + __objc_resolve_class_links (); + + super = class->super_class; + + if (super != 0 && (super->dtable == __objc_uninstalled_dtable)) + __objc_install_dispatch_table_for_class (super); + + /* Allocate dtable if necessary */ + if (super == 0) + { + objc_mutex_lock (__objc_runtime_mutex); + class->dtable = sarray_new (__objc_selector_max_index, 0); + objc_mutex_unlock (__objc_runtime_mutex); + } + else + class->dtable = sarray_lazy_copy (super->dtable); + + __objc_install_methods_in_dtable (class, class->methods); +} + +void +__objc_update_dispatch_table_for_class (Class class) +{ + Class next; + struct sarray *arr; + + /* not yet installed -- skip it */ + if (class->dtable == __objc_uninstalled_dtable) + return; + + objc_mutex_lock (__objc_runtime_mutex); + + arr = class->dtable; + __objc_install_premature_dtable (class); /* someone might require it... */ + sarray_free (arr); /* release memory */ + + /* could have been lazy... */ + __objc_install_dispatch_table_for_class (class); + + if (class->subclass_list) /* Traverse subclasses */ + for (next = class->subclass_list; next; next = next->sibling_class) + __objc_update_dispatch_table_for_class (next); + + objc_mutex_unlock (__objc_runtime_mutex); +} + + +/* This function adds a method list to a class. This function is + typically called by another function specific to the run-time. As + such this function does not worry about thread safe issues. + + This one is only called for categories. Class objects have their + methods installed right away, and their selectors are made into + SEL's by the function __objc_register_selectors_from_class. */ +void +class_add_method_list (Class class, MethodList_t list) +{ + /* Passing of a linked list is not allowed. Do multiple calls. */ + assert (! list->method_next); + + __objc_register_selectors_from_list(list); + + /* Add the methods to the class's method list. */ + list->method_next = class->methods; + class->methods = list; + + /* Update the dispatch table of class */ + __objc_update_dispatch_table_for_class (class); +} + +Method_t +class_get_instance_method (Class class, SEL op) +{ + return search_for_method_in_hierarchy (class, op); +} + +Method_t +class_get_class_method (MetaClass class, SEL op) +{ + return search_for_method_in_hierarchy (class, op); +} + + +/* Search for a method starting from the current class up its hierarchy. + Return a pointer to the method's method structure if found. NULL + otherwise. */ + +static Method_t +search_for_method_in_hierarchy (Class cls, SEL sel) +{ + Method_t method = NULL; + Class class; + + if (! sel_is_mapped (sel)) + return NULL; + + /* Scan the method list of the class. If the method isn't found in the + list then step to its super class. */ + for (class = cls; ((! method) && class); class = class->super_class) + method = search_for_method_in_list (class->methods, sel); + + return method; +} + + + +/* Given a linked list of method and a method's name. Search for the named + method's method structure. Return a pointer to the method's method + structure if found. NULL otherwise. */ +Method_t +search_for_method_in_list (MethodList_t list, SEL op) +{ + MethodList_t method_list = list; + + if (! sel_is_mapped (op)) + return NULL; + + /* If not found then we'll search the list. */ + while (method_list) + { + int i; + + /* Search the method list. */ + for (i = 0; i < method_list->method_count; ++i) + { + Method_t method = &method_list->method_list[i]; + + if (method->method_name) + if (method->method_name->sel_id == op->sel_id) + return method; + } + + /* The method wasn't found. Follow the link to the next list of + methods. */ + method_list = method_list->method_next; + } + + return NULL; +} + +static retval_t __objc_forward (id object, SEL sel, arglist_t args); + +/* Forwarding pointers/integers through the normal registers */ +static id +__objc_word_forward (id rcv, SEL op, ...) +{ + void *args, *res; + + args = __builtin_apply_args (); + res = __objc_forward (rcv, op, args); + if (res) + __builtin_return (res); + else + return res; +} + +/* Specific routine for forwarding floats/double because of + architectural differences on some processors. i386s for + example which uses a floating point stack versus general + registers for floating point numbers. This forward routine + makes sure that GCC restores the proper return values */ +static double +__objc_double_forward (id rcv, SEL op, ...) +{ + void *args, *res; + + args = __builtin_apply_args (); + res = __objc_forward (rcv, op, args); + __builtin_return (res); +} + +#if INVISIBLE_STRUCT_RETURN +static __big +#else +static id +#endif +__objc_block_forward (id rcv, SEL op, ...) +{ + void *args, *res; + + args = __builtin_apply_args (); + res = __objc_forward (rcv, op, args); + if (res) + __builtin_return (res); + else +#if INVISIBLE_STRUCT_RETURN + return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}}; +#else + return nil; +#endif +} + + +/* This function is installed in the dispatch table for all methods which are + not implemented. Thus, it is called when a selector is not recognized. */ +static retval_t +__objc_forward (id object, SEL sel, arglist_t args) +{ + IMP imp; + static SEL frwd_sel = 0; /* !T:SAFE2 */ + SEL err_sel; + + /* first try if the object understands forward:: */ + if (! frwd_sel) + frwd_sel = sel_get_any_uid ("forward::"); + + if (__objc_responds_to (object, frwd_sel)) + { + imp = get_imp (object->class_pointer, frwd_sel); + return (*imp) (object, frwd_sel, sel, args); + } + + /* If the object recognizes the doesNotRecognize: method then we're going + to send it. */ + err_sel = sel_get_any_uid ("doesNotRecognize:"); + if (__objc_responds_to (object, err_sel)) + { + imp = get_imp (object->class_pointer, err_sel); + return (*imp) (object, err_sel, sel); + } + + /* The object doesn't recognize the method. Check for responding to + error:. If it does then sent it. */ + { + char msg[256 + strlen ((const char *) sel_get_name (sel)) + + strlen ((const char *) object->class_pointer->name)]; + + sprintf (msg, "(%s) %s does not recognize %s", + (CLS_ISMETA (object->class_pointer) + ? "class" + : "instance" ), + object->class_pointer->name, sel_get_name (sel)); + + err_sel = sel_get_any_uid ("error:"); + if (__objc_responds_to (object, err_sel)) + { + imp = get_imp (object->class_pointer, err_sel); + return (*imp) (object, sel_get_any_uid ("error:"), msg); + } + + /* The object doesn't respond to doesNotRecognize: or error:; Therefore, + a default action is taken. */ + objc_error (object, OBJC_ERR_UNIMPLEMENTED, "%s\n", msg); + + return 0; + } +} + +void +__objc_print_dtable_stats () +{ + int total = 0; + + objc_mutex_lock (__objc_runtime_mutex); + +#ifdef OBJC_SPARSE2 + printf ("memory usage: (%s)\n", "2-level sparse arrays"); +#else + printf ("memory usage: (%s)\n", "3-level sparse arrays"); +#endif + + printf ("arrays: %d = %ld bytes\n", narrays, + (long) narrays * sizeof (struct sarray)); + total += narrays * sizeof (struct sarray); + printf ("buckets: %d = %ld bytes\n", nbuckets, + (long) nbuckets * sizeof (struct sbucket)); + total += nbuckets * sizeof (struct sbucket); + + printf ("idxtables: %d = %ld bytes\n", + idxsize, (long) idxsize * sizeof (void *)); + total += idxsize * sizeof (void *); + printf ("-----------------------------------\n"); + printf ("total: %d bytes\n", total); + printf ("===================================\n"); + + objc_mutex_unlock (__objc_runtime_mutex); +} + +/* Returns the uninstalled dispatch table indicator. + If a class' dispatch table points to __objc_uninstalled_dtable + then that means it needs its dispatch table to be installed. */ +inline +struct sarray * +objc_get_uninstalled_dtable () +{ + return __objc_uninstalled_dtable; +} diff --git a/contrib/gcc-4.1/libobjc/thr-dce.c b/contrib/gcc-4.1/libobjc/thr-dce.c new file mode 100644 index 0000000000..b20eacf8c9 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/thr-dce.c @@ -0,0 +1,281 @@ +/* GNU Objective C Runtime Thread Interface + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +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 2, 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 COPYING. If not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include +#include "objc/thr.h" +#include "objc/runtime.h" + +/* Key structure for maintaining thread specific storage */ +static pthread_key_t _objc_thread_storage; + +/* Backend initialization functions */ + +/* Initialize the threads subsystem. */ +int +__objc_init_thread_system(void) +{ + /* Initialize the thread storage key */ + return pthread_keycreate(&_objc_thread_storage, NULL); +} + +/* Close the threads subsystem. */ +int +__objc_close_thread_system(void) +{ + /* Destroy the thread storage key */ + /* Not implemented yet */ + /* return pthread_key_delete(&_objc_thread_storage); */ + return 0; +} + +/* Backend thread functions */ + +/* Create a new thread of execution. */ +objc_thread_t +__objc_thread_detach(void (*func)(void *arg), void *arg) +{ + objc_thread_t thread_id; + pthread_t new_thread_handle; + + if (pthread_create(&new_thread_handle, pthread_attr_default, + (void *)func, arg) == 0) + { + /* ??? May not work! (64bit) */ + thread_id = *(objc_thread_t *)&new_thread_handle; + pthread_detach(&new_thread_handle); /* Fully detach thread. */ + } + else + thread_id = NULL; + + return thread_id; +} + +/* Set the current thread's priority. */ +int +__objc_thread_set_priority(int priority) +{ + int sys_priority = 0; + + switch (priority) + { + case OBJC_THREAD_INTERACTIVE_PRIORITY: + sys_priority = (PRI_FG_MIN_NP + PRI_FG_MAX_NP) / 2; + break; + default: + case OBJC_THREAD_BACKGROUND_PRIORITY: + sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2; + break; + case OBJC_THREAD_LOW_PRIORITY: + sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2; + break; + } + + /* Change the priority. */ + if (pthread_setprio(pthread_self(), sys_priority) >= 0) + return 0; + else + /* Failed */ + return -1; +} + +/* Return the current thread's priority. */ +int +__objc_thread_get_priority(void) +{ + int sys_priority; + + if ((sys_priority = pthread_getprio(pthread_self())) >= 0) { + if (sys_priority >= PRI_FG_MIN_NP && sys_priority <= PRI_FG_MAX_NP) + return OBJC_THREAD_INTERACTIVE_PRIORITY; + if (sys_priority >= PRI_BG_MIN_NP && sys_priority <= PRI_BG_MAX_NP) + return OBJC_THREAD_BACKGROUND_PRIORITY; + return OBJC_THREAD_LOW_PRIORITY; + } + + /* Failed */ + return -1; +} + +/* Yield our process time to another thread. */ +void +__objc_thread_yield(void) +{ + pthread_yield(); +} + +/* Terminate the current thread. */ +int +__objc_thread_exit(void) +{ + /* exit the thread */ + pthread_exit(&__objc_thread_exit_status); + + /* Failed if we reached here */ + return -1; +} + +/* Returns an integer value which uniquely describes a thread. */ +objc_thread_t +__objc_thread_id(void) +{ + pthread_t self = pthread_self(); + + return (objc_thread_t) pthread_getunique_np (&self); +} + +/* Sets the thread's local storage pointer. */ +int +__objc_thread_set_data(void *value) +{ + return pthread_setspecific(_objc_thread_storage, value); +} + +/* Returns the thread's local storage pointer. */ +void * +__objc_thread_get_data(void) +{ + void *value = NULL; + + if ( !(pthread_getspecific(_objc_thread_storage, &value)) ) + return value; + + return NULL; +} + +/* Backend mutex functions */ + +/* Allocate a mutex. */ +int +__objc_mutex_allocate(objc_mutex_t mutex) +{ + if (pthread_mutex_init((pthread_mutex_t *)(&(mutex->backend)), + pthread_mutexattr_default)) + return -1; + else + return 0; +} + +/* Deallocate a mutex. */ +int +__objc_mutex_deallocate(objc_mutex_t mutex) +{ + if (pthread_mutex_destroy((pthread_mutex_t *)(&(mutex->backend)))) + return -1; + else + return 0; +} + +/* Grab a lock on a mutex. */ +int +__objc_mutex_lock(objc_mutex_t mutex) +{ + return pthread_mutex_lock((pthread_mutex_t *)(&(mutex->backend))); +} + +/* Try to grab a lock on a mutex. */ +int +__objc_mutex_trylock(objc_mutex_t mutex) +{ + if (pthread_mutex_trylock((pthread_mutex_t *)(&(mutex->backend))) != 1) + return -1; + else + return 0; +} + +/* Unlock the mutex */ +int +__objc_mutex_unlock(objc_mutex_t mutex) +{ + return pthread_mutex_unlock((pthread_mutex_t *)(&(mutex->backend))); +} + +/* Backend condition mutex functions */ + +/* Allocate a condition. */ +int +__objc_condition_allocate(objc_condition_t condition) +{ + /* Unimplemented. */ + return -1; + + /* + if (pthread_cond_init((pthread_cond_t *)(&(condition->backend)), NULL)) + return -1; + else + return 0; + */ +} + +/* Deallocate a condition. */ +int +__objc_condition_deallocate(objc_condition_t condition) +{ + /* Unimplemented. */ + return -1; + + /* + return pthread_cond_destroy((pthread_cond_t *)(&(condition->backend))); + */ +} + +/* Wait on the condition */ +int +__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex) +{ + /* Unimplemented. */ + return -1; + + /* + return pthread_cond_wait((pthread_cond_t *)(&(condition->backend)), + (pthread_mutex_t *)(&(mutex->backend))); + */ +} + +/* Wake up all threads waiting on this condition. */ +int +__objc_condition_broadcast(objc_condition_t condition) +{ + /* Unimplemented. */ + return -1; + + /* + return pthread_cond_broadcast((pthread_cond_t *)(&(condition->backend))); + */ +} + +/* Wake up one thread waiting on this condition. */ +int +__objc_condition_signal(objc_condition_t condition) +{ + /* Unimplemented. */ + return -1; + + /* + return pthread_cond_signal((pthread_cond_t *)(&(condition->backend))); + */ +} + +/* End of File */ diff --git a/contrib/gcc-4.1/libobjc/thr-objc.c b/contrib/gcc-4.1/libobjc/thr-objc.c new file mode 100644 index 0000000000..7d6375aaa5 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/thr-objc.c @@ -0,0 +1,192 @@ +/* GNU Objective C Runtime Thread Interface. + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005, 2006 + Free Software Foundation, 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#define _LIBOBJC +/* The line below is needed for declarations of functions such as + pthread_mutexattr_settype, without which gthr-posix.h may fail to + compile within libobjc. Unfortunately, this breaks compilation on + Tru64 UNIX V4.0F, so disable it there. */ +#ifndef __osf__ +#define _XOPEN_SOURCE 500 +#endif +#include "config.h" +#include "tconfig.h" +#include "coretypes.h" +#include "tm.h" +#include "defaults.h" +#include "objc/thr.h" +#include "objc/runtime.h" +#include + +/* Backend initialization functions */ + +/* Initialize the threads subsystem. */ +int +__objc_init_thread_system(void) +{ + return __gthread_objc_init_thread_system (); +} + +/* Close the threads subsystem. */ +int +__objc_close_thread_system(void) +{ + return __gthread_objc_close_thread_system (); +} + +/* Backend thread functions */ + +/* Create a new thread of execution. */ +objc_thread_t +__objc_thread_detach(void (*func)(void *), void *arg) +{ + return __gthread_objc_thread_detach (func, arg); +} + +/* Set the current thread's priority. */ +int +__objc_thread_set_priority(int priority) +{ + return __gthread_objc_thread_set_priority (priority); +} + +/* Return the current thread's priority. */ +int +__objc_thread_get_priority(void) +{ + return __gthread_objc_thread_get_priority (); +} + +/* Yield our process time to another thread. */ +void +__objc_thread_yield(void) +{ + __gthread_objc_thread_yield (); +} + +/* Terminate the current thread. */ +int +__objc_thread_exit(void) +{ + return __gthread_objc_thread_exit (); +} + +/* Returns an integer value which uniquely describes a thread. */ +objc_thread_t +__objc_thread_id(void) +{ + return __gthread_objc_thread_id (); +} + +/* Sets the thread's local storage pointer. */ +int +__objc_thread_set_data(void *value) +{ + return __gthread_objc_thread_set_data (value); +} + +/* Returns the thread's local storage pointer. */ +void * +__objc_thread_get_data(void) +{ + return __gthread_objc_thread_get_data (); +} + +/* Backend mutex functions */ + +/* Allocate a mutex. */ +int +__objc_mutex_allocate(objc_mutex_t mutex) +{ + return __gthread_objc_mutex_allocate (mutex); +} + +/* Deallocate a mutex. */ +int +__objc_mutex_deallocate(objc_mutex_t mutex) +{ + return __gthread_objc_mutex_deallocate (mutex); +} + +/* Grab a lock on a mutex. */ +int +__objc_mutex_lock(objc_mutex_t mutex) +{ + return __gthread_objc_mutex_lock (mutex); +} + +/* Try to grab a lock on a mutex. */ +int +__objc_mutex_trylock(objc_mutex_t mutex) +{ + return __gthread_objc_mutex_trylock (mutex); +} + +/* Unlock the mutex */ +int +__objc_mutex_unlock(objc_mutex_t mutex) +{ + return __gthread_objc_mutex_unlock (mutex); +} + +/* Backend condition mutex functions */ + +/* Allocate a condition. */ +int +__objc_condition_allocate(objc_condition_t condition) +{ + return __gthread_objc_condition_allocate (condition); +} + +/* Deallocate a condition. */ +int +__objc_condition_deallocate(objc_condition_t condition) +{ + return __gthread_objc_condition_deallocate (condition); +} + +/* Wait on the condition */ +int +__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex) +{ + return __gthread_objc_condition_wait (condition, mutex); +} + +/* Wake up all threads waiting on this condition. */ +int +__objc_condition_broadcast(objc_condition_t condition) +{ + return __gthread_objc_condition_broadcast (condition); +} + +/* Wake up one thread waiting on this condition. */ +int +__objc_condition_signal(objc_condition_t condition) +{ + return __gthread_objc_condition_signal (condition); +} + +/* End of File */ diff --git a/contrib/gcc-4.1/libobjc/thr-posix.c b/contrib/gcc-4.1/libobjc/thr-posix.c new file mode 100644 index 0000000000..f7010833df --- /dev/null +++ b/contrib/gcc-4.1/libobjc/thr-posix.c @@ -0,0 +1,318 @@ +/* GNU Objective C Runtime Thread Interface for POSIX compliant threads + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + Modified for Linux/Pthreads by Kai-Uwe Sattler (kus@iti.cs.uni-magdeburg.de) + Modified for posix compliance by Chris Ball (cball@fmco.com) + +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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "objc/thr.h" +#include "objc/runtime.h" +#include + +/* Key structure for maintaining thread specific storage */ +static pthread_key_t _objc_thread_storage; +static pthread_attr_t _objc_thread_attribs; + +/* Backend initialization functions */ + +/* Initialize the threads subsystem. */ +int +__objc_init_thread_system(void) +{ + /* Initialize the thread storage key */ + if (pthread_key_create(&_objc_thread_storage, NULL) == 0) + { + /* + * The normal default detach state for threads is PTHREAD_CREATE_JOINABLE + * which causes threads to not die when you think they should. + */ + if (pthread_attr_init(&_objc_thread_attribs) == 0) + { + if (pthread_attr_setdetachstate(&_objc_thread_attribs, + PTHREAD_CREATE_DETACHED) == 0) + return 0; + } + } + + return -1; +} + +/* Close the threads subsystem. */ +int +__objc_close_thread_system(void) +{ + if (pthread_key_delete(_objc_thread_storage) == 0) + { + if (pthread_attr_destroy(&_objc_thread_attribs) == 0) + return 0; + } + + return -1; +} + +/* Backend thread functions */ + +/* Create a new thread of execution. */ +objc_thread_t +__objc_thread_detach(void (*func)(void *arg), void *arg) +{ + objc_thread_t thread_id; + pthread_t new_thread_handle; + + if (!(pthread_create(&new_thread_handle, &_objc_thread_attribs, + (void *)func, arg))) + thread_id = *(objc_thread_t *)&new_thread_handle; + else + thread_id = NULL; + + return thread_id; +} + +/* Set the current thread's priority. + * + * Be aware that the default schedpolicy often disallows thread priorities. + */ +int +__objc_thread_set_priority(int priority) +{ + pthread_t thread_id = pthread_self(); + int policy; + struct sched_param params; + int priority_min, priority_max; + + if (pthread_getschedparam(thread_id, &policy, ¶ms) == 0) + { + if ((priority_max = sched_get_priority_max(policy)) != 0) + return -1; + + if ((priority_min = sched_get_priority_min(policy)) != 0) + return -1; + + if (priority > priority_max) + priority = priority_max; + else if (priority < priority_min) + priority = priority_min; + params.sched_priority = priority; + + /* + * The solaris 7 and several other man pages incorrectly state that + * this should be a pointer to policy but pthread.h is universally + * at odds with this. + */ + if (pthread_setschedparam(thread_id, policy, ¶ms) == 0) + return 0; + } + return -1; +} + +/* Return the current thread's priority. */ +int +__objc_thread_get_priority(void) +{ + int policy; + struct sched_param params; + + if (pthread_getschedparam(pthread_self(), &policy, ¶ms) == 0) + return params.sched_priority; + else + return -1; +} + +/* Yield our process time to another thread. */ +void +__objc_thread_yield(void) +{ + sched_yield(); +} + +/* Terminate the current thread. */ +int +__objc_thread_exit(void) +{ + /* exit the thread */ + pthread_exit(&__objc_thread_exit_status); + + /* Failed if we reached here */ + return -1; +} + +/* Returns an integer value which uniquely describes a thread. */ +objc_thread_t +__objc_thread_id(void) +{ + pthread_t self = pthread_self(); + + return *(objc_thread_t *)&self; +} + +/* Sets the thread's local storage pointer. */ +int +__objc_thread_set_data(void *value) +{ + if (pthread_setspecific(_objc_thread_storage, value) == 0) + return 0; + else + return -1; +} + +/* Returns the thread's local storage pointer. */ +void * +__objc_thread_get_data(void) +{ + return pthread_getspecific(_objc_thread_storage); +} + +/* Backend mutex functions */ + +/* Allocate a mutex. */ +int +__objc_mutex_allocate(objc_mutex_t mutex) +{ + mutex->backend = objc_malloc(sizeof(pthread_mutex_t)); + + if (pthread_mutex_init((pthread_mutex_t *)mutex->backend, NULL)) + { + objc_free(mutex->backend); + mutex->backend = NULL; + return -1; + } + + return 0; +} + +/* Deallocate a mutex. */ +int +__objc_mutex_deallocate(objc_mutex_t mutex) +{ + int count = 1; + + /* + * Posix Threads specifically require that the thread be unlocked for + * pthread_mutex_destroy to work. + */ + + while (count) + { + if ((count = pthread_mutex_unlock((pthread_mutex_t*)mutex->backend)) < 0) + return -1; + } + + if (pthread_mutex_destroy((pthread_mutex_t *)mutex->backend)) + return -1; + + objc_free(mutex->backend); + mutex->backend = NULL; + return 0; +} + +/* Grab a lock on a mutex. */ +int +__objc_mutex_lock(objc_mutex_t mutex) +{ + if (pthread_mutex_lock((pthread_mutex_t *)mutex->backend) == 0) + return 0; + else + return -1; +} + +/* Try to grab a lock on a mutex. */ +int +__objc_mutex_trylock(objc_mutex_t mutex) +{ + if (pthread_mutex_trylock((pthread_mutex_t *)mutex->backend) == 0) + return 0; + else + return -1; +} + +/* Unlock the mutex */ +int +__objc_mutex_unlock(objc_mutex_t mutex) +{ + if (pthread_mutex_unlock((pthread_mutex_t *)mutex->backend) == 0) + return 0; + else + return -1; +} + +/* Backend condition mutex functions */ + +/* Allocate a condition. */ +int +__objc_condition_allocate(objc_condition_t condition) +{ + condition->backend = objc_malloc(sizeof(pthread_cond_t)); + + if (pthread_cond_init((pthread_cond_t *)condition->backend, NULL)) + { + objc_free(condition->backend); + condition->backend = NULL; + return -1; + } + + return 0; +} + +/* Deallocate a condition. */ +int +__objc_condition_deallocate(objc_condition_t condition) +{ + if (pthread_cond_destroy((pthread_cond_t *)condition->backend)) + return -1; + + objc_free(condition->backend); + condition->backend = NULL; + return 0; +} + +/* Wait on the condition */ +int +__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex) +{ + if (pthread_cond_wait((pthread_cond_t *)condition->backend, + (pthread_mutex_t *)mutex->backend) == 0) + return 0; + else + return -1; +} + +/* Wake up all threads waiting on this condition. */ +int +__objc_condition_broadcast(objc_condition_t condition) +{ + if (pthread_cond_broadcast((pthread_cond_t *)condition->backend) == 0) + return 0; + else + return -1; +} + +/* Wake up one thread waiting on this condition. */ +int +__objc_condition_signal(objc_condition_t condition) +{ + if (pthread_cond_signal((pthread_cond_t *)condition->backend) == 0) + return 0; + else + return -1; +} diff --git a/contrib/gcc-4.1/libobjc/thr-pthreads.c b/contrib/gcc-4.1/libobjc/thr-pthreads.c new file mode 100644 index 0000000000..d73db47ad2 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/thr-pthreads.c @@ -0,0 +1,218 @@ +/* GNU Objective C Runtime Thread Implementation for PCThreads under GNU/Linux. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Scott Christley + Condition functions added by: Mircea Oancea + +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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include +#include "objc/thr.h" +#include "objc/runtime.h" + +/* Key structure for maintaining thread specific storage */ +static pthread_key_t _objc_thread_storage; + +/* Backend initialization functions */ + +/* Initialize the threads subsystem. */ +int +__objc_init_thread_system(void) +{ + /* Initialize the thread storage key */ + return pthread_key_create(&_objc_thread_storage, NULL); +} + +/* Close the threads subsystem. */ +int +__objc_close_thread_system(void) +{ + /* Destroy the thread storage key */ + /* Not implemented yet */ + /* return pthread_key_delete(&_objc_thread_storage); */ + return 0; +} + +/* Backend thread functions */ + +/* Create a new thread of execution. */ +objc_thread_t +__objc_thread_detach(void (*func)(void *arg), void *arg) +{ + objc_thread_t thread_id; + pthread_t new_thread_handle; + + if ( !(pthread_create(&new_thread_handle, NULL, (void *)func, arg)) ) + thread_id = *(objc_thread_t *)&new_thread_handle; + else + thread_id = NULL; + + return thread_id; +} + +/* Set the current thread's priority. */ +int +__objc_thread_set_priority(int priority) +{ + /* Not implemented yet */ + return -1; +} + +/* Return the current thread's priority. */ +int +__objc_thread_get_priority(void) +{ + /* Not implemented yet */ + return OBJC_THREAD_INTERACTIVE_PRIORITY; +} + +/* Yield our process time to another thread. */ +void +__objc_thread_yield(void) +{ + pthread_yield(NULL); +} + +/* Terminate the current thread. */ +int +__objc_thread_exit(void) +{ + /* exit the thread */ + pthread_exit(&__objc_thread_exit_status); + + /* Failed if we reached here */ + return -1; +} + +/* Returns an integer value which uniquely describes a thread. */ +objc_thread_t +__objc_thread_id(void) +{ + pthread_t self = pthread_self(); + + return *(objc_thread_t *)&self; +} + +/* Sets the thread's local storage pointer. */ +int +__objc_thread_set_data(void *value) +{ + return pthread_setspecific(_objc_thread_storage, value); +} + +/* Returns the thread's local storage pointer. */ +void * +__objc_thread_get_data(void) +{ + void *value = NULL; + + if ( !(pthread_getspecific(_objc_thread_storage, &value)) ) + return value; + + return NULL; +} + +/* Backend mutex functions */ + +/* Allocate a mutex. */ +int +__objc_mutex_allocate(objc_mutex_t mutex) +{ + if (pthread_mutex_init((pthread_mutex_t *)(&(mutex->backend)), NULL)) + return -1; + else + return 0; +} + +/* Deallocate a mutex. */ +int +__objc_mutex_deallocate(objc_mutex_t mutex) +{ + if (pthread_mutex_destroy((pthread_mutex_t *)(&(mutex->backend)))) + return -1; + else + return 0; +} + +/* Grab a lock on a mutex. */ +int +__objc_mutex_lock(objc_mutex_t mutex) +{ + return pthread_mutex_lock((pthread_mutex_t *)(&(mutex->backend))); +} + +/* Try to grab a lock on a mutex. */ +int +__objc_mutex_trylock(objc_mutex_t mutex) +{ + return pthread_mutex_trylock((pthread_mutex_t *)(&(mutex->backend))); +} + +/* Unlock the mutex */ +int +__objc_mutex_unlock(objc_mutex_t mutex) +{ + return pthread_mutex_unlock((pthread_mutex_t *)(&(mutex->backend))); +} + +/* Backend condition mutex functions */ + +/* Allocate a condition. */ +int +__objc_condition_allocate(objc_condition_t condition) +{ + if (pthread_cond_init((pthread_cond_t *)(&(condition->backend)), NULL)) + return -1; + else + return 0; +} + +/* Deallocate a condition. */ +int +__objc_condition_deallocate(objc_condition_t condition) +{ + return pthread_cond_destroy((pthread_cond_t *)(&(condition->backend))); +} + +/* Wait on the condition */ +int +__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex) +{ + return pthread_cond_wait((pthread_cond_t *)(&(condition->backend)), + (pthread_mutex_t *)(&(mutex->backend))); +} + +/* Wake up all threads waiting on this condition. */ +int +__objc_condition_broadcast(objc_condition_t condition) +{ + return pthread_cond_broadcast((pthread_cond_t *)(&(condition->backend))); +} + +/* Wake up one thread waiting on this condition. */ +int +__objc_condition_signal(objc_condition_t condition) +{ + return pthread_cond_signal((pthread_cond_t *)(&(condition->backend))); +} + +/* End of File */ diff --git a/contrib/gcc-4.1/libobjc/thr-single.c b/contrib/gcc-4.1/libobjc/thr-single.c new file mode 100644 index 0000000000..0407dcf17c --- /dev/null +++ b/contrib/gcc-4.1/libobjc/thr-single.c @@ -0,0 +1,192 @@ +/* GNU Objective C Runtime Thread Implementation + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +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 2, 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 COPYING. If not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "objc/thr.h" +#include "objc/runtime.h" + +/* Thread local storage for a single thread */ +static void *thread_local_storage = NULL; + +/* Backend initialization functions */ + +/* Initialize the threads subsystem. */ +int +__objc_init_thread_system(void) +{ + /* No thread support available */ + return -1; +} + +/* Close the threads subsystem. */ +int +__objc_close_thread_system(void) +{ + /* No thread support available */ + return -1; +} + +/* Backend thread functions */ + +/* Create a new thread of execution. */ +objc_thread_t +__objc_thread_detach(void (*func)(void *arg), void *arg) +{ + /* No thread support available */ + return NULL; +} + +/* Set the current thread's priority. */ +int +__objc_thread_set_priority(int priority) +{ + /* No thread support available */ + return -1; +} + +/* Return the current thread's priority. */ +int +__objc_thread_get_priority(void) +{ + return OBJC_THREAD_INTERACTIVE_PRIORITY; +} + +/* Yield our process time to another thread. */ +void +__objc_thread_yield(void) +{ + return; +} + +/* Terminate the current thread. */ +int +__objc_thread_exit(void) +{ + /* No thread support available */ + /* Should we really exit the program */ + /* exit(&__objc_thread_exit_status); */ + return -1; +} + +/* Returns an integer value which uniquely describes a thread. */ +objc_thread_t +__objc_thread_id(void) +{ + /* No thread support, use 1. */ + return (objc_thread_t)1; +} + +/* Sets the thread's local storage pointer. */ +int +__objc_thread_set_data(void *value) +{ + thread_local_storage = value; + return 0; +} + +/* Returns the thread's local storage pointer. */ +void * +__objc_thread_get_data(void) +{ + return thread_local_storage; +} + +/* Backend mutex functions */ + +/* Allocate a mutex. */ +int +__objc_mutex_allocate(objc_mutex_t mutex) +{ + return 0; +} + +/* Deallocate a mutex. */ +int +__objc_mutex_deallocate(objc_mutex_t mutex) +{ + return 0; +} + +/* Grab a lock on a mutex. */ +int +__objc_mutex_lock(objc_mutex_t mutex) +{ + /* There can only be one thread, so we always get the lock */ + return 0; +} + +/* Try to grab a lock on a mutex. */ +int +__objc_mutex_trylock(objc_mutex_t mutex) +{ + /* There can only be one thread, so we always get the lock */ + return 0; +} + +/* Unlock the mutex */ +int +__objc_mutex_unlock(objc_mutex_t mutex) +{ + return 0; +} + +/* Backend condition mutex functions */ + +/* Allocate a condition. */ +int +__objc_condition_allocate(objc_condition_t condition) +{ + return 0; +} + +/* Deallocate a condition. */ +int +__objc_condition_deallocate(objc_condition_t condition) +{ + return 0; +} + +/* Wait on the condition */ +int +__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex) +{ + return 0; +} + +/* Wake up all threads waiting on this condition. */ +int +__objc_condition_broadcast(objc_condition_t condition) +{ + return 0; +} + +/* Wake up one thread waiting on this condition. */ +int +__objc_condition_signal(objc_condition_t condition) +{ + return 0; +} + +/* End of File */ diff --git a/contrib/gcc-4.1/libobjc/thr.c b/contrib/gcc-4.1/libobjc/thr.c new file mode 100644 index 0000000000..17f6f7e292 --- /dev/null +++ b/contrib/gcc-4.1/libobjc/thr.c @@ -0,0 +1,563 @@ +/* GNU Objective C Runtime Thread Interface + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +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 2, 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 COPYING. If not, write to the Free Software +Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include +#include "objc/runtime.h" + +/* Global exit status. */ +int __objc_thread_exit_status = 0; + +/* Flag which lets us know if we ever became multi threaded */ +int __objc_is_multi_threaded = 0; + +/* The hook function called when the runtime becomes multi threaded */ +objc_thread_callback _objc_became_multi_threaded = NULL; + +/* + Use this to set the hook function that will be called when the + runtime initially becomes multi threaded. + The hook function is only called once, meaning only when the + 2nd thread is spawned, not for each and every thread. + + It returns the previous hook function or NULL if there is none. + + A program outside of the runtime could set this to some function so + it can be informed; for example, the GNUstep Base Library sets it + so it can implement the NSBecomingMultiThreaded notification. + */ +objc_thread_callback objc_set_thread_callback (objc_thread_callback func) +{ + objc_thread_callback temp = _objc_became_multi_threaded; + _objc_became_multi_threaded = func; + return temp; +} + +/* + Private functions + + These functions are utilized by the frontend, but they are not + considered part of the public interface. + */ + +/* + First function called in a thread, starts everything else. + + This function is passed to the backend by objc_thread_detach + as the starting function for a new thread. + */ +struct __objc_thread_start_state +{ + SEL selector; + id object; + id argument; +}; + +static void __attribute__((noreturn)) +__objc_thread_detach_function (struct __objc_thread_start_state *istate) +{ + /* Valid state? */ + if (istate) { + id (*imp) (id, SEL, id); + SEL selector = istate->selector; + id object = istate->object; + id argument = istate->argument; + + /* Don't need anymore so free it */ + objc_free (istate); + + /* Clear out the thread local storage */ + objc_thread_set_data (NULL); + + /* Check to see if we just became multi threaded */ + if (! __objc_is_multi_threaded) + { + __objc_is_multi_threaded = 1; + + /* Call the hook function */ + if (_objc_became_multi_threaded != NULL) + (*_objc_became_multi_threaded) (); + } + + /* Call the method */ + if ((imp = (id (*) (id, SEL, id))objc_msg_lookup (object, selector))) + (*imp) (object, selector, argument); + else + objc_error (object, OBJC_ERR_UNIMPLEMENTED, + "objc_thread_detach called with bad selector.\n"); + } + else + objc_error (nil, OBJC_ERR_BAD_STATE, + "objc_thread_detach called with NULL state.\n"); + + /* Exit the thread */ + objc_thread_exit (); +} + +/* + Frontend functions + + These functions constitute the public interface to the Objective-C thread + and mutex functionality. + */ + +/* Frontend thread functions */ + +/* + Detach a new thread of execution and return its id. Returns NULL if fails. + Thread is started by sending message with selector to object. Message + takes a single argument. + */ +objc_thread_t +objc_thread_detach (SEL selector, id object, id argument) +{ + struct __objc_thread_start_state *istate; + objc_thread_t thread_id = NULL; + + /* Allocate the state structure */ + if (! (istate = (struct __objc_thread_start_state *) + objc_malloc (sizeof (*istate)))) + return NULL; + + /* Initialize the state structure */ + istate->selector = selector; + istate->object = object; + istate->argument = argument; + + /* lock access */ + objc_mutex_lock (__objc_runtime_mutex); + + /* Call the backend to spawn the thread */ + if ((thread_id = __objc_thread_detach ((void *)__objc_thread_detach_function, + istate)) == NULL) + { + /* failed! */ + objc_mutex_unlock (__objc_runtime_mutex); + objc_free (istate); + return NULL; + } + + /* Increment our thread counter */ + __objc_runtime_threads_alive++; + objc_mutex_unlock (__objc_runtime_mutex); + + return thread_id; +} + +/* Set the current thread's priority. */ +int +objc_thread_set_priority (int priority) +{ + /* Call the backend */ + return __objc_thread_set_priority (priority); +} + +/* Return the current thread's priority. */ +int +objc_thread_get_priority (void) +{ + /* Call the backend */ + return __objc_thread_get_priority (); +} + +/* + Yield our process time to another thread. Any BUSY waiting that is done + by a thread should use this function to make sure that other threads can + make progress even on a lazy uniprocessor system. + */ +void +objc_thread_yield (void) +{ + /* Call the backend */ + __objc_thread_yield (); +} + +/* + Terminate the current tread. Doesn't return. + Actually, if it failed returns -1. + */ +int +objc_thread_exit (void) +{ + /* Decrement our counter of the number of threads alive */ + objc_mutex_lock (__objc_runtime_mutex); + __objc_runtime_threads_alive--; + objc_mutex_unlock (__objc_runtime_mutex); + + /* Call the backend to terminate the thread */ + return __objc_thread_exit (); +} + +/* + Returns an integer value which uniquely describes a thread. Must not be + NULL which is reserved as a marker for "no thread". + */ +objc_thread_t +objc_thread_id (void) +{ + /* Call the backend */ + return __objc_thread_id (); +} + +/* + Sets the thread's local storage pointer. + Returns 0 if successful or -1 if failed. + */ +int +objc_thread_set_data (void *value) +{ + /* Call the backend */ + return __objc_thread_set_data (value); +} + +/* + Returns the thread's local storage pointer. Returns NULL on failure. + */ +void * +objc_thread_get_data (void) +{ + /* Call the backend */ + return __objc_thread_get_data (); +} + +/* Frontend mutex functions */ + +/* + Allocate a mutex. Return the mutex pointer if successful or NULL if the + allocation failed for any reason. + */ +objc_mutex_t +objc_mutex_allocate (void) +{ + objc_mutex_t mutex; + + /* Allocate the mutex structure */ + if (! (mutex = (objc_mutex_t)objc_malloc (sizeof (struct objc_mutex)))) + return NULL; + + /* Call backend to create the mutex */ + if (__objc_mutex_allocate (mutex)) + { + /* failed! */ + objc_free (mutex); + return NULL; + } + + /* Initialize mutex */ + mutex->owner = NULL; + mutex->depth = 0; + return mutex; +} + +/* + Deallocate a mutex. Note that this includes an implicit mutex_lock to + insure that no one else is using the lock. It is legal to deallocate + a lock if we have a lock on it, but illegal to deallocate a lock held + by anyone else. + Returns the number of locks on the thread. (1 for deallocate). + */ +int +objc_mutex_deallocate (objc_mutex_t mutex) +{ + int depth; + + /* Valid mutex? */ + if (! mutex) + return -1; + + /* Acquire lock on mutex */ + depth = objc_mutex_lock (mutex); + + /* Call backend to destroy mutex */ + if (__objc_mutex_deallocate (mutex)) + return -1; + + /* Free the mutex structure */ + objc_free (mutex); + + /* Return last depth */ + return depth; +} + +/* + Grab a lock on a mutex. If this thread already has a lock on this mutex + then we increment the lock count. If another thread has a lock on the + mutex we block and wait for the thread to release the lock. + Returns the lock count on the mutex held by this thread. + */ +int +objc_mutex_lock (objc_mutex_t mutex) +{ + objc_thread_t thread_id; + int status; + + /* Valid mutex? */ + if (! mutex) + return -1; + + /* If we already own the lock then increment depth */ + thread_id = __objc_thread_id (); + if (mutex->owner == thread_id) + return ++mutex->depth; + + /* Call the backend to lock the mutex */ + status = __objc_mutex_lock (mutex); + + /* Failed? */ + if (status) + return status; + + /* Successfully locked the thread */ + mutex->owner = thread_id; + return mutex->depth = 1; +} + +/* + Try to grab a lock on a mutex. If this thread already has a lock on + this mutex then we increment the lock count and return it. If another + thread has a lock on the mutex returns -1. + */ +int +objc_mutex_trylock (objc_mutex_t mutex) +{ + objc_thread_t thread_id; + int status; + + /* Valid mutex? */ + if (! mutex) + return -1; + + /* If we already own the lock then increment depth */ + thread_id = __objc_thread_id (); + if (mutex->owner == thread_id) + return ++mutex->depth; + + /* Call the backend to try to lock the mutex */ + status = __objc_mutex_trylock (mutex); + + /* Failed? */ + if (status) + return status; + + /* Successfully locked the thread */ + mutex->owner = thread_id; + return mutex->depth = 1; +} + +/* + Unlocks the mutex by one level. + Decrements the lock count on this mutex by one. + If the lock count reaches zero, release the lock on the mutex. + Returns the lock count on the mutex. + It is an error to attempt to unlock a mutex which this thread + doesn't hold in which case return -1 and the mutex is unaffected. + */ +int +objc_mutex_unlock (objc_mutex_t mutex) +{ + objc_thread_t thread_id; + int status; + + /* Valid mutex? */ + if (! mutex) + return -1; + + /* If another thread owns the lock then abort */ + thread_id = __objc_thread_id (); + if (mutex->owner != thread_id) + return -1; + + /* Decrement depth and return */ + if (mutex->depth > 1) + return --mutex->depth; + + /* Depth down to zero so we are no longer the owner */ + mutex->depth = 0; + mutex->owner = NULL; + + /* Have the backend unlock the mutex */ + status = __objc_mutex_unlock (mutex); + + /* Failed? */ + if (status) + return status; + + return 0; +} + +/* Frontend condition mutex functions */ + +/* + Allocate a condition. Return the condition pointer if successful or NULL + if the allocation failed for any reason. + */ +objc_condition_t +objc_condition_allocate (void) +{ + objc_condition_t condition; + + /* Allocate the condition mutex structure */ + if (! (condition = + (objc_condition_t) objc_malloc (sizeof (struct objc_condition)))) + return NULL; + + /* Call the backend to create the condition mutex */ + if (__objc_condition_allocate (condition)) + { + /* failed! */ + objc_free (condition); + return NULL; + } + + /* Success! */ + return condition; +} + +/* + Deallocate a condition. Note that this includes an implicit + condition_broadcast to insure that waiting threads have the opportunity + to wake. It is legal to dealloc a condition only if no other + thread is/will be using it. Here we do NOT check for other threads + waiting but just wake them up. + */ +int +objc_condition_deallocate (objc_condition_t condition) +{ + /* Broadcast the condition */ + if (objc_condition_broadcast (condition)) + return -1; + + /* Call the backend to destroy */ + if (__objc_condition_deallocate (condition)) + return -1; + + /* Free the condition mutex structure */ + objc_free (condition); + + return 0; +} + +/* + Wait on the condition unlocking the mutex until objc_condition_signal () + or objc_condition_broadcast () are called for the same condition. The + given mutex *must* have the depth set to 1 so that it can be unlocked + here, so that someone else can lock it and signal/broadcast the condition. + The mutex is used to lock access to the shared data that make up the + "condition" predicate. + */ +int +objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex) +{ + objc_thread_t thread_id; + + /* Valid arguments? */ + if (! mutex || ! condition) + return -1; + + /* Make sure we are owner of mutex */ + thread_id = __objc_thread_id (); + if (mutex->owner != thread_id) + return -1; + + /* Cannot be locked more than once */ + if (mutex->depth > 1) + return -1; + + /* Virtually unlock the mutex */ + mutex->depth = 0; + mutex->owner = (objc_thread_t)NULL; + + /* Call the backend to wait */ + __objc_condition_wait (condition, mutex); + + /* Make ourselves owner of the mutex */ + mutex->owner = thread_id; + mutex->depth = 1; + + return 0; +} + +/* + Wake up all threads waiting on this condition. It is recommended that + the called would lock the same mutex as the threads in objc_condition_wait + before changing the "condition predicate" and make this call and unlock it + right away after this call. + */ +int +objc_condition_broadcast (objc_condition_t condition) +{ + /* Valid condition mutex? */ + if (! condition) + return -1; + + return __objc_condition_broadcast (condition); +} + +/* + Wake up one thread waiting on this condition. It is recommended that + the called would lock the same mutex as the threads in objc_condition_wait + before changing the "condition predicate" and make this call and unlock it + right away after this call. + */ +int +objc_condition_signal (objc_condition_t condition) +{ + /* Valid condition mutex? */ + if (! condition) + return -1; + + return __objc_condition_signal (condition); +} + +/* Make the objc thread system aware that a thread which is managed + (started, stopped) by external code could access objc facilities + from now on. This is used when you are interfacing with some + external non-objc-based environment/system - you must call + objc_thread_add () before an alien thread makes any calls to + Objective-C. Do not cause the _objc_became_multi_threaded hook to + be executed. */ +void +objc_thread_add (void) +{ + objc_mutex_lock (__objc_runtime_mutex); + __objc_is_multi_threaded = 1; + __objc_runtime_threads_alive++; + objc_mutex_unlock (__objc_runtime_mutex); +} + +/* Make the objc thread system aware that a thread managed (started, + stopped) by some external code will no longer access objc and thus + can be forgotten by the objc thread system. Call + objc_thread_remove () when your alien thread is done with making + calls to Objective-C. */ +void +objc_thread_remove (void) +{ + objc_mutex_lock (__objc_runtime_mutex); + __objc_runtime_threads_alive--; + objc_mutex_unlock (__objc_runtime_mutex); +} + +/* End of File */