summaryrefslogtreecommitdiff
path: root/gcc/objc/objc-runtime-shared-support.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/objc/objc-runtime-shared-support.c')
-rw-r--r--gcc/objc/objc-runtime-shared-support.c736
1 files changed, 736 insertions, 0 deletions
diff --git a/gcc/objc/objc-runtime-shared-support.c b/gcc/objc/objc-runtime-shared-support.c
new file mode 100644
index 000000000..8dca6ccae
--- /dev/null
+++ b/gcc/objc/objc-runtime-shared-support.c
@@ -0,0 +1,736 @@
+/* Support routines shared by all runtimes.
+ Copyright (C) 2011 Free Software Foundation, Inc.
+ Contributed by Iain Sandoe (partially split from objc-act.c)
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+
+#ifdef OBJCPLUS
+#include "cp-tree.h"
+#else
+#include "c-tree.h"
+#include "c-lang.h"
+#endif
+#include "langhooks.h"
+#include "c-family/c-objc.h"
+#include "objc-act.h"
+
+/* When building Objective-C++, we are not linking against the C front-end
+ and so need to replicate the C tree-construction functions in some way. */
+#ifdef OBJCPLUS
+#define OBJCP_REMAP_FUNCTIONS
+#include "objcp-decl.h"
+#endif /* OBJCPLUS */
+
+#include "obstack.h"
+
+/* These are only used for encoding ivars. */
+extern struct obstack util_obstack;
+extern char *util_firstobj;
+
+/* Hooks for string decls etc. */
+#include "objc-runtime-hooks.h"
+
+#include "objc-runtime-shared-support.h"
+
+/* rt_trees identifiers - shared between NeXT implementations. These allow
+ the FE to tag meta-data in a manner that survives LTO and can be used when
+ the runtime requires that certain meta-data items appear in particular
+ named sections. */
+#include "objc-next-metadata-tags.h"
+extern GTY(()) tree objc_rt_trees[OCTI_RT_META_MAX];
+
+/* Rather than repeatedly looking up the identifiers, we save them here. */
+tree objc_rt_trees[OCTI_RT_META_MAX];
+
+/* For building an objc struct. These might not be used when this file
+ is compiled as part of obj-c++. */
+
+static bool objc_building_struct;
+static struct c_struct_parse_info *objc_struct_info ATTRIBUTE_UNUSED;
+
+/* Start building a struct for objc. */
+
+tree
+objc_start_struct (tree name)
+{
+ gcc_assert (!objc_building_struct);
+ objc_building_struct = true;
+ return start_struct (input_location, RECORD_TYPE, name, &objc_struct_info);
+}
+
+/* Finish building a struct for objc. */
+
+tree
+objc_finish_struct (tree type, tree fieldlist)
+{
+ gcc_assert (objc_building_struct);
+ objc_building_struct = false;
+ return finish_struct (input_location, type, fieldlist, NULL_TREE,
+ objc_struct_info);
+}
+
+tree
+build_sized_array_type (tree base_type, int size)
+{
+ tree index_type = build_index_type (build_int_cst (NULL_TREE, size - 1));
+ return build_array_type (base_type, index_type);
+}
+
+/* Create a declaration for field NAME of a given TYPE. */
+
+static tree
+create_field_decl (tree type, const char *name)
+{
+ return build_decl (input_location,
+ FIELD_DECL, get_identifier (name), type);
+}
+
+tree
+add_field_decl (tree type, const char *name, tree **chain)
+{
+ tree field = create_field_decl (type, name);
+
+ if (*chain != NULL)
+ **chain = field;
+ *chain = &DECL_CHAIN (field);
+
+ return field;
+}
+
+/* Create a global, static declaration for variable NAME of a given TYPE. The
+ finish_var_decl() routine will need to be called on it afterwards. */
+
+tree
+start_var_decl (tree type, const char *name)
+{
+ tree var = build_decl (input_location,
+ VAR_DECL, get_identifier (name), type);
+ TREE_STATIC (var) = 1;
+ DECL_INITIAL (var) = error_mark_node; /* A real initializer is coming... */
+ DECL_IGNORED_P (var) = 1;
+ DECL_ARTIFICIAL (var) = 1;
+ DECL_CONTEXT (var) = NULL_TREE;
+#ifdef OBJCPLUS
+ DECL_THIS_STATIC (var) = 1; /* squash redeclaration errors */
+#endif
+ return var;
+}
+
+/* Finish off the variable declaration created by start_var_decl(). */
+
+void
+finish_var_decl (tree var, tree initializer)
+{
+ finish_decl (var, input_location, initializer, NULL_TREE, NULL_TREE);
+}
+
+/* Just a handy wrapper for add_objc_string. */
+
+tree
+build_selector (tree ident)
+{
+ return convert (objc_selector_type, add_objc_string (ident, meth_var_names));
+}
+
+/* --- templates --- */
+
+/* Set 'objc_super_template' to the data type node for 'struct _objc_super'.
+ This needs to be done just once per compilation. */
+
+/* struct _objc_super {
+ struct _objc_object *self;
+ struct _objc_class *super_class;
+ [or Class cls; for the abi v2]
+ }; */
+
+void
+build_super_template (void)
+{
+ tree decls, *chain = NULL;
+
+ objc_super_template = objc_start_struct (get_identifier (UTAG_SUPER));
+
+ /* struct _objc_object *self; */
+ decls = add_field_decl (objc_object_type, "self", &chain);
+
+ /* struct _objc_class *super_class; */
+ add_field_decl (build_pointer_type (objc_class_template),
+ "super_class", &chain);
+
+ objc_finish_struct (objc_super_template, decls);
+}
+
+/* To accomplish method prototyping without generating all kinds of
+ inane warnings, the definition of the dispatch table entries were
+ changed from:
+
+ struct objc_method { SEL _cmd; ...; id (*_imp)(); };
+ to:
+ struct objc_method { SEL _cmd; ...; void *_imp; }; */
+
+tree
+build_method_template (void)
+{
+ tree _SLT_record;
+ tree decls, *chain = NULL;
+
+ _SLT_record = objc_start_struct (get_identifier (UTAG_METHOD));
+
+ /* SEL _cmd; */
+ decls = add_field_decl (objc_selector_type, "_cmd", &chain);
+
+ /* char *method_types; */
+ add_field_decl (string_type_node, "method_types", &chain);
+
+ /* void *_imp; */
+ add_field_decl (build_pointer_type (void_type_node), "_imp", &chain);
+
+ objc_finish_struct (_SLT_record, decls);
+
+ return _SLT_record;
+}
+
+tree
+build_method_prototype_template (void)
+{
+ tree proto_record;
+ tree decls, *chain = NULL;
+
+ proto_record = objc_start_struct (get_identifier (UTAG_METHOD_PROTOTYPE));
+
+ /* SEL _cmd; */
+ decls = add_field_decl (objc_selector_type, "_cmd", &chain);
+
+ /* char *method_types; */
+ add_field_decl (string_type_node, "method_types", &chain);
+
+ objc_finish_struct (proto_record, decls);
+
+ return proto_record;
+}
+
+/* struct {
+ struct _objc__method_prototype_list *method_next;
+ int method_count;
+ struct objc_method method_list[method_count];
+ }; */
+
+tree
+build_method_list_template (tree list_type, int size)
+{
+ tree objc_ivar_list_record;
+ tree array_type, decls, *chain = NULL;
+
+ objc_ivar_list_record = objc_start_struct (NULL_TREE);
+
+ /* struct _objc__method_prototype_list *method_next; */
+ decls = add_field_decl (objc_method_proto_list_ptr, "method_next", &chain);
+
+ /* int method_count; */
+ add_field_decl (integer_type_node, "method_count", &chain);
+
+ /* struct objc_method method_list[]; */
+ array_type = build_sized_array_type (list_type, size);
+ add_field_decl (array_type, "method_list", &chain);
+
+ objc_finish_struct (objc_ivar_list_record, decls);
+
+ return objc_ivar_list_record;
+}
+
+/* struct objc_method_prototype_list {
+ int count;
+ struct objc_method_prototype {
+ SEL name;
+ char *types;
+ } list[1];
+ }; */
+
+tree
+build_method_prototype_list_template (tree list_type, int size)
+{
+ tree objc_ivar_list_record;
+ tree array_type, decls, *chain = NULL;
+
+ /* Generate an unnamed struct definition. */
+
+ objc_ivar_list_record = objc_start_struct (NULL_TREE);
+
+ /* int method_count; */
+ decls = add_field_decl (integer_type_node, "method_count", &chain);
+
+ /* struct objc_method method_list[]; */
+ array_type = build_sized_array_type (list_type, size);
+ add_field_decl (array_type, "method_list", &chain);
+
+ objc_finish_struct (objc_ivar_list_record, decls);
+
+ return objc_ivar_list_record;
+}
+
+/* --- names, decls entry --- */
+
+/* For each string section we have a chain which maps identifier nodes
+ to decls for the strings. */
+
+static GTY(()) int meth_var_names_idx;
+static GTY(()) int meth_var_types_idx;
+static GTY(()) int property_name_attr_idx;
+
+tree
+add_objc_string (tree ident, string_section section)
+{
+ tree *chain, decl, type;
+ char buf[BUFSIZE];
+
+ switch (section)
+ {
+ case class_names:
+ chain = &class_names_chain;
+ snprintf (buf, BUFSIZE, "_OBJC_ClassName_%s", IDENTIFIER_POINTER (ident));
+ break;
+ case meth_var_names:
+ chain = &meth_var_names_chain;
+ snprintf (buf, BUFSIZE, "_OBJC_METH_VAR_NAME_%d", meth_var_names_idx++);
+ break;
+ case meth_var_types:
+ chain = &meth_var_types_chain;
+ snprintf (buf, BUFSIZE, "_OBJC_METH_VAR_TYPE_%d", meth_var_types_idx++);
+ break;
+ case prop_names_attr:
+ chain = &prop_names_attr_chain;
+ snprintf (buf, BUFSIZE, "_OBJC_PropertyAttributeOrName_%d", property_name_attr_idx++);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ while (*chain)
+ {
+ if (TREE_VALUE (*chain) == ident)
+ return convert (string_type_node,
+ build_unary_op (input_location,
+ ADDR_EXPR, TREE_PURPOSE (*chain), 1));
+
+ chain = &TREE_CHAIN (*chain);
+ }
+
+ type = build_sized_array_type (char_type_node, IDENTIFIER_LENGTH (ident) + 1);
+ /* Get a runtime-specific string decl which will be finish_var()'ed in
+ generate_strings (). */
+ decl = (*runtime.string_decl) (type, buf, section);
+ TREE_CONSTANT (decl) = 1;
+ *chain = tree_cons (decl, ident, NULL_TREE);
+
+ return convert (string_type_node,
+ build_unary_op (input_location, ADDR_EXPR, decl, 1));
+}
+
+/* --- shared metadata routines --- */
+
+tree
+build_descriptor_table_initializer (tree type, tree entries)
+{
+ VEC(constructor_elt,gc) *inits = NULL;
+
+ do
+ {
+ VEC(constructor_elt,gc) *elts = NULL;
+
+ CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+ build_selector (METHOD_SEL_NAME (entries)));
+ CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+ add_objc_string (METHOD_ENCODING (entries),
+ meth_var_types));
+
+ CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE,
+ objc_build_constructor (type, elts));
+
+ entries = DECL_CHAIN (entries);
+ }
+ while (entries);
+
+ return objc_build_constructor (build_array_type (type, 0), inits);
+}
+
+tree
+build_dispatch_table_initializer (tree type, tree entries)
+{
+ VEC(constructor_elt,gc) *inits = NULL;
+
+ do
+ {
+ VEC(constructor_elt,gc) *elems = NULL;
+ tree expr;
+
+ CONSTRUCTOR_APPEND_ELT (elems, NULL_TREE,
+ build_selector (METHOD_SEL_NAME (entries)));
+
+ /* Generate the method encoding if we don't have one already. */
+ if (! METHOD_ENCODING (entries))
+ METHOD_ENCODING (entries) =
+ encode_method_prototype (entries);
+
+ CONSTRUCTOR_APPEND_ELT (elems, NULL_TREE,
+ add_objc_string (METHOD_ENCODING (entries),
+ meth_var_types));
+
+ expr = convert (ptr_type_node,
+ build_unary_op (input_location, ADDR_EXPR,
+ METHOD_DEFINITION (entries), 1));
+ CONSTRUCTOR_APPEND_ELT (elems, NULL_TREE, expr);
+
+ CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE,
+ objc_build_constructor (type, elems));
+
+ entries = DECL_CHAIN (entries);
+ }
+ while (entries);
+
+ return objc_build_constructor (build_array_type (type, 0), inits);
+}
+
+/* Used only by build_*_selector_translation_table (). */
+void
+diagnose_missing_method (tree meth, location_t here)
+{
+ tree method_chain;
+ bool found = false;
+ for (method_chain = meth_var_names_chain;
+ method_chain;
+ method_chain = TREE_CHAIN (method_chain))
+ {
+ if (TREE_VALUE (method_chain) == meth)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ warning_at (here, 0, "creating selector for nonexistent method %qE",
+ meth);
+}
+
+
+static tree
+init_module_descriptor (tree type, long vers)
+{
+ tree expr, ltyp;
+ location_t loc;
+ VEC(constructor_elt,gc) *v = NULL;
+
+ /* No really useful place to point to. */
+ loc = UNKNOWN_LOCATION;
+
+ /* version = { 1, ... } */
+
+ expr = build_int_cst (long_integer_type_node, vers);
+ CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr);
+
+ /* size = { ..., sizeof (struct _objc_module), ... } */
+
+ expr = convert (long_integer_type_node,
+ size_in_bytes (objc_module_template));
+ CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr);
+
+ /* Don't provide any file name for security reasons. */
+ /* name = { ..., "", ... } */
+
+ expr = add_objc_string (get_identifier (""), class_names);
+ CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr);
+
+ /* symtab = { ..., _OBJC_SYMBOLS, ... } */
+
+ ltyp = build_pointer_type (xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_SYMTAB)));
+ if (UOBJC_SYMBOLS_decl)
+ expr = convert (ltyp, build_unary_op (loc,
+ ADDR_EXPR, UOBJC_SYMBOLS_decl, 0));
+ else
+ expr = convert (ltyp, null_pointer_node);
+ CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr);
+
+ return objc_build_constructor (type, v);
+}
+
+/* Write out the data structures to describe Objective C classes defined.
+
+ struct _objc_module { ... } _OBJC_MODULE = { ... }; */
+
+void
+build_module_descriptor (long vers, tree attr)
+{
+ tree decls, *chain = NULL;
+
+#ifdef OBJCPLUS
+ push_lang_context (lang_name_c); /* extern "C" */
+#endif
+
+ objc_module_template = objc_start_struct (get_identifier (UTAG_MODULE));
+
+ /* long version; */
+ decls = add_field_decl (long_integer_type_node, "version", &chain);
+
+ /* long size; */
+ add_field_decl (long_integer_type_node, "size", &chain);
+
+ /* char *name; */
+ add_field_decl (string_type_node, "name", &chain);
+
+ /* struct _objc_symtab *symtab; */
+ add_field_decl (build_pointer_type (xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_SYMTAB))),
+ "symtab", &chain);
+
+ objc_finish_struct (objc_module_template, decls);
+
+ /* Create an instance of "_objc_module". */
+ UOBJC_MODULES_decl = start_var_decl (objc_module_template,
+ /* FIXME - why the conditional
+ if the symbol is the
+ same. */
+ flag_next_runtime ? "_OBJC_Module" : "_OBJC_Module");
+
+ /* This is the root of the metadata for defined classes and categories, it
+ is referenced by the runtime and, therefore, needed. */
+ DECL_PRESERVE_P (UOBJC_MODULES_decl) = 1;
+
+ /* Allow the runtime to mark meta-data such that it can be assigned to target
+ specific sections by the back-end. */
+ if (attr)
+ DECL_ATTRIBUTES (UOBJC_MODULES_decl) = attr;
+
+ finish_var_decl (UOBJC_MODULES_decl,
+ init_module_descriptor (TREE_TYPE (UOBJC_MODULES_decl),
+ vers));
+
+#ifdef OBJCPLUS
+ pop_lang_context ();
+#endif
+}
+
+tree
+build_ivar_list_initializer (tree type, tree field_decl)
+{
+ VEC(constructor_elt,gc) *inits = NULL;
+
+ do
+ {
+ VEC(constructor_elt,gc) *ivar = NULL;
+ tree id;
+
+ /* Set name. */
+ if (DECL_NAME (field_decl))
+ CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE,
+ add_objc_string (DECL_NAME (field_decl),
+ meth_var_names));
+ else
+ /* Unnamed bit-field ivar (yuck). */
+ CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, build_int_cst (NULL_TREE, 0));
+
+ /* Set type. */
+ encode_field_decl (field_decl,
+ obstack_object_size (&util_obstack),
+ OBJC_ENCODE_DONT_INLINE_DEFS);
+
+ /* Null terminate string. */
+ obstack_1grow (&util_obstack, 0);
+ id = add_objc_string (get_identifier (XOBFINISH (&util_obstack, char *)),
+ meth_var_types);
+ CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, id);
+ obstack_free (&util_obstack, util_firstobj);
+
+ /* Set offset. */
+ CONSTRUCTOR_APPEND_ELT (ivar, NULL_TREE, byte_position (field_decl));
+ CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE,
+ objc_build_constructor (type, ivar));
+ do
+ field_decl = DECL_CHAIN (field_decl);
+ while (field_decl && TREE_CODE (field_decl) != FIELD_DECL);
+ }
+ while (field_decl);
+
+ return objc_build_constructor (build_array_type (type, 0), inits);
+}
+
+/* struct {
+ int ivar_count;
+ struct objc_ivar ivar_list[ivar_count];
+ }; */
+
+tree
+build_ivar_list_template (tree list_type, int size)
+{
+ tree objc_ivar_list_record;
+ tree array_type, decls, *chain = NULL;
+
+ objc_ivar_list_record = objc_start_struct (NULL_TREE);
+
+ /* int ivar_count; */
+ decls = add_field_decl (integer_type_node, "ivar_count", &chain);
+
+ /* struct objc_ivar ivar_list[]; */
+ array_type = build_sized_array_type (list_type, size);
+ add_field_decl (array_type, "ivar_list", &chain);
+
+ objc_finish_struct (objc_ivar_list_record, decls);
+
+ return objc_ivar_list_record;
+}
+
+/* struct _objc_ivar {
+ char *ivar_name;
+ char *ivar_type;
+ int ivar_offset;
+ }; */
+
+tree
+build_ivar_template (void)
+{
+ tree objc_ivar_id, objc_ivar_record;
+ tree decls, *chain = NULL;
+
+ objc_ivar_id = get_identifier (UTAG_IVAR);
+ objc_ivar_record = objc_start_struct (objc_ivar_id);
+
+ /* char *ivar_name; */
+ decls = add_field_decl (string_type_node, "ivar_name", &chain);
+
+ /* char *ivar_type; */
+ add_field_decl (string_type_node, "ivar_type", &chain);
+
+ /* int ivar_offset; */
+ add_field_decl (integer_type_node, "ivar_offset", &chain);
+
+ objc_finish_struct (objc_ivar_record, decls);
+
+ return objc_ivar_record;
+}
+
+/* Used by NeXT ABI=0..2 */
+void
+build_next_selector_translation_table (void)
+{
+ tree chain;
+ for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
+ {
+ tree expr;
+ tree decl = TREE_PURPOSE (chain);
+ if (warn_selector)
+ {
+ location_t loc;
+ if (decl)
+ loc = DECL_SOURCE_LOCATION (decl);
+ else
+ loc = UNKNOWN_LOCATION;
+ diagnose_missing_method (TREE_VALUE (chain), loc);
+ }
+
+ expr = build_selector (TREE_VALUE (chain));
+
+ if (decl)
+ {
+ /* Entries of this form are used for references to methods.
+ The runtime re-writes these on start-up, but the compiler can't see
+ that and optimizes it away unless we force it. */
+ DECL_PRESERVE_P (decl) = 1;
+ finish_var_decl (decl, expr);
+ }
+ }
+}
+
+void
+generate_protocol_references (tree plist)
+{
+ tree lproto;
+
+ /* Forward declare protocols referenced. */
+ for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto))
+ {
+ tree proto = TREE_VALUE (lproto);
+
+ if (TREE_CODE (proto) == PROTOCOL_INTERFACE_TYPE
+ && PROTOCOL_NAME (proto))
+ {
+ if (! PROTOCOL_FORWARD_DECL (proto))
+ PROTOCOL_FORWARD_DECL (proto) = (*runtime.protocol_decl) (proto);
+
+ if (PROTOCOL_LIST (proto))
+ generate_protocol_references (PROTOCOL_LIST (proto));
+ }
+ }
+}
+
+/* --- new routines --- */
+
+/* Output all strings. */
+
+/* FIXME: don't use global vars for all this... */
+
+/* This emits all the meta-data string tables (and finalizes each var
+ as it goes). */
+void
+generate_strings (void)
+{
+ tree chain, string_expr;
+ tree string, decl; /* , type;*/
+
+ for (chain = class_names_chain; chain; chain = TREE_CHAIN (chain))
+ {
+ string = TREE_VALUE (chain);
+ decl = TREE_PURPOSE (chain);
+ string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
+ IDENTIFIER_POINTER (string));
+ finish_var_decl (decl, string_expr);
+ }
+
+ for (chain = meth_var_names_chain; chain; chain = TREE_CHAIN (chain))
+ {
+ string = TREE_VALUE (chain);
+ decl = TREE_PURPOSE (chain);
+ string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
+ IDENTIFIER_POINTER (string));
+ finish_var_decl (decl, string_expr);
+ }
+
+ for (chain = meth_var_types_chain; chain; chain = TREE_CHAIN (chain))
+ {
+ string = TREE_VALUE (chain);
+ decl = TREE_PURPOSE (chain);
+ string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
+ IDENTIFIER_POINTER (string));
+ finish_var_decl (decl, string_expr);
+ }
+
+ for (chain = prop_names_attr_chain; chain; chain = TREE_CHAIN (chain))
+ {
+ string = TREE_VALUE (chain);
+ decl = TREE_PURPOSE (chain);
+ string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
+ IDENTIFIER_POINTER (string));
+ finish_var_decl (decl, string_expr);
+ }
+}
+
+#include "gt-objc-objc-runtime-shared-support.h"