#include "input.h"
#include "function.h"
+
/* 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
#include "rtl.h"
#include "c-parse.h"
-#define OBJC_VERSION 5
+#define OBJC_VERSION 6
#define PROTOCOL_VERSION 2
#define NULLT (tree) 0
static tree init_module_descriptor PROTO((tree));
static tree build_objc_method_call PROTO((int, tree, tree, tree, tree, tree));
static void generate_strings PROTO((void));
+static tree get_proto_encoding PROTO((tree));
static void build_selector_translation_table PROTO((void));
static tree build_ivar_chain PROTO((tree, int));
static tree build_method_template PROTO((void));
static tree build_private_template PROTO((tree));
static void build_class_template PROTO((void));
+static void build_selector_template PROTO((void));
static void build_category_template PROTO((void));
static tree build_super_template PROTO((void));
static tree build_category_initializer PROTO((tree, tree, tree, tree, tree, tree));
static void generate_objc_symtab_decl PROTO((void));
static tree build_selector PROTO((tree));
static tree build_msg_pool_reference PROTO((int));
+static tree build_typed_selector_reference PROTO((tree, tree));
static tree build_selector_reference PROTO((tree));
static tree build_class_reference_decl PROTO((tree));
static void add_class_reference PROTO((tree));
#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_PROTOCOL_LIST "_objc_protocol_list"
static int cat_count = 0; /* `@category' */
static tree objc_class_template, objc_category_template, uprivate_record;
-static tree objc_protocol_template;
+static tree objc_protocol_template, objc_selector_template;
static tree ucls_super_ref, uucls_super_ref;
static tree objc_method_template, objc_ivar_template;
/* data imported from tree.c */
extern struct obstack permanent_obstack, *current_obstack, *rtl_obstack;
+extern enum debug_info_type write_symbols;
/* data imported from toplev.c */
int flag_next_runtime = 0;
#endif
+int flag_typed_selectors;
+
/* Open and close the file for outputting class declarations, if requested. */
int flag_gen_declaration = 0;
TAG_MSGSEND = "objc_msg_lookup";
TAG_MSGSENDSUPER = "objc_msg_lookup_super";
TAG_EXECCLASS = "__objc_exec_class";
+ flag_typed_selectors = 1;
}
if (doing_objc_thang)
/* static SEL _OBJC_SELECTOR_TABLE[]; */
- temp_type = build_array_type (selector_type, NULLT);
- layout_type (temp_type);
if (! flag_next_runtime)
- UOBJC_SELECTOR_TABLE_decl
- = create_builtin_decl (VAR_DECL, temp_type,
- "_OBJC_SELECTOR_TABLE");
+ {
+ if (flag_typed_selectors)
+ {
+ /* supress outputting debug symbols, because
+ dbxout_init hasn'r been called yet... */
+ enum debug_info_type save_write_symbols = write_symbols;
+ write_symbols = NO_DEBUG;
+
+ build_selector_template ();
+ temp_type = build_array_type (objc_selector_template, NULLT);
+
+ write_symbols = save_write_symbols;
+ }
+ else
+ temp_type = build_array_type (selector_type, NULLT);
+
+ layout_type (temp_type);
+ UOBJC_SELECTOR_TABLE_decl
+ = create_builtin_decl (VAR_DECL, temp_type,
+ "_OBJC_SELECTOR_TABLE");
+ }
+
generate_forward_declaration_to_string_table ();
function_type);
DECL_EXTERNAL (function_decl) = 1;
TREE_PUBLIC (function_decl) = 1;
+
pushdecl (function_decl);
rest_of_decl_compilation (function_decl, 0, 0, 0);
assemble_external (function_decl);
c_expand_expr_stmt (decelerator);
+ TREE_PUBLIC (current_function_decl) = 1;
+ DECL_EXTERNAL (current_function_decl) = 1;
+
finish_function (0);
/* Return the name of the constructor function. */
tree ident;
{
tree expr = add_objc_string (ident, meth_var_names);
-
- return build_c_cast (selector_type, expr); /* cast! */
+ if (flag_typed_selectors)
+ return expr;
+ else
+ return build_c_cast (selector_type, expr); /* cast! */
}
/* Synthesize the following expr: (char *)&_OBJC_STRINGS[<offset>]
end_temporary_allocation ();
finish_decl (decl, expr, NULLT);
}
- else
- initlist = tree_cons (NULLT, expr, initlist);
+ else
+ {
+ if (flag_typed_selectors)
+ {
+ tree eltlist = NULLT;
+ tree encoding = get_proto_encoding (TREE_PURPOSE (chain));
+ eltlist = tree_cons (NULLT, expr, NULLT);
+ eltlist = tree_cons (NULLT, encoding, eltlist);
+ expr = build_constructor (objc_selector_template,
+ nreverse (eltlist));
+ }
+ initlist = tree_cons (NULLT, expr, initlist);
+
+ }
}
if (! flag_next_runtime)
}
}
+
+static tree
+get_proto_encoding (proto)
+ tree proto;
+{
+ tree encoding;
+ if (proto)
+ {
+ tree tmp_decl;
+
+ if (! METHOD_ENCODING (proto))
+ {
+ tmp_decl = build_tmp_function_decl ();
+ hack_method_prototype (proto, tmp_decl);
+ encoding = encode_method_prototype (proto, tmp_decl);
+ METHOD_ENCODING (proto) = encoding;
+ }
+ else
+ encoding = METHOD_ENCODING (proto);
+
+ return add_objc_string (encoding, meth_var_types);
+ }
+ else
+ return build_int_2 (0, 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 (ident, proto)
+ tree ident, proto;
+{
+ tree *chain = &sel_ref_chain;
+ tree expr;
+ int index = 0;
+
+ while (*chain)
+ {
+ if (TREE_PURPOSE (*chain) == ident && TREE_VALUE (*chain) == proto)
+ goto return_at_index;
+ index++;
+ chain = &TREE_CHAIN (*chain);
+ }
+
+ *chain = perm_tree_cons (proto, ident, NULLT);
+
+ return_at_index:
+ expr = build_unary_op (ADDR_EXPR,
+ build_array_ref (UOBJC_SELECTOR_TABLE_decl,
+ build_int_2 (index, 0)),
+ 1);
+ return build_c_cast (selector_type, expr);
+}
+
static tree
build_selector_reference (ident)
tree ident;
{
tree *chain = &sel_ref_chain;
- tree decl;
+ tree expr;
int index = 0;
while (*chain)
chain = &TREE_CHAIN (*chain);
}
- decl = build_selector_reference_decl (ident);
+ expr = build_selector_reference_decl (ident);
- *chain = perm_tree_cons (decl, ident, NULLT);
+ *chain = perm_tree_cons (expr, ident, NULLT);
return (flag_next_runtime
- ? decl
+ ? expr
: build_array_ref (UOBJC_SELECTOR_TABLE_decl,
build_int_2 (index, 0)));
}
build_tmp_function_decl ()
{
tree decl_specs, expr_decl, parms;
+ static int xxx = 0;
+ char buffer[80];
/* struct objc_object *objc_xxx (id, SEL, ...); */
pushlevel (0);
poplevel (0, 0, 0);
decl_specs = build_tree_list (NULLT, objc_object_reference);
- expr_decl = build_nt (CALL_EXPR, get_identifier ("objc_xxx"), parms, NULLT);
+ sprintf (buffer, "__objc_tmp_%x", xxx++);
+ expr_decl = build_nt (CALL_EXPR, get_identifier (buffer), parms, NULLT);
expr_decl = build1 (INDIRECT_REF, NULLT, expr_decl);
return define_decl (expr_decl, decl_specs);
/* Usually called from store_parm_decls -> init_function_start. */
- init_emit (); /* needed to make assign_parms work (with -O). */
-
DECL_ARGUMENTS (tmp_decl) = TREE_PURPOSE (parms);
+ current_function_decl = tmp_decl;
{
/* Code taken from start_function. */
DECL_RESULT (tmp_decl) = build_decl (RESULT_DECL, 0, restype);
}
+ init_function_start (tmp_decl, "objc-act", 0);
+
/* Typically called from expand_function_start for function definitions. */
assign_parms (tmp_decl, 0);
/* install return type */
TREE_TYPE (TREE_TYPE (tmp_decl)) = groktypename (TREE_TYPE (nst_methods));
+
}
static void
while (nst_methods)
{
- hack_method_prototype (nst_methods, tmp_decl);
- encoding = encode_method_prototype (nst_methods, tmp_decl);
- METHOD_ENCODING (nst_methods) = encoding;
-
+ if (! METHOD_ENCODING (nst_methods))
+ {
+ hack_method_prototype (nst_methods, tmp_decl);
+ encoding = encode_method_prototype (nst_methods, tmp_decl);
+ METHOD_ENCODING (nst_methods) = encoding;
+ }
nst_methods = TREE_CHAIN (nst_methods);
}
while (cls_methods)
{
- hack_method_prototype (cls_methods, tmp_decl);
- encoding = encode_method_prototype (cls_methods, tmp_decl);
- METHOD_ENCODING (cls_methods) = encoding;
+ if (! METHOD_ENCODING (cls_methods))
+ {
+ hack_method_prototype (cls_methods, tmp_decl);
+ encoding = encode_method_prototype (cls_methods, tmp_decl);
+ METHOD_ENCODING (cls_methods) = encoding;
+ }
cls_methods = TREE_CHAIN (cls_methods);
}
finish_struct (objc_category_template, field_decl_chain);
}
+/* struct objc_selector {
+ void *sel_id;
+ char *sel_type;
+ }; */
+
+static void
+build_selector_template ()
+{
+
+ tree decl_specs, field_decl, field_decl_chain;
+
+ objc_selector_template
+ = start_struct (RECORD_TYPE, get_identifier (UTAG_SELECTOR));
+
+ /* void *sel_id; */
+
+ decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_VOID]);
+ field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("sel_id"));
+ field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
+ field_decl_chain = field_decl;
+
+ /* char *sel_type; */
+
+ decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_CHAR]);
+ field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("sel_type"));
+ field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
+ chainon (field_decl_chain, field_decl);
+
+ finish_struct (objc_selector_template, field_decl_chain);
+}
+
/* struct objc_class {
struct objc_class *isa;
struct objc_class *super_class;
/* int method_next; */
- decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_INT]);
- field_decl = get_identifier ("method_next");
-
+ decl_specs = build_tree_list (NULLT,
+ xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_METHOD_PROTOTYPE_LIST)));
+ field_decl = build1 (INDIRECT_REF, NULLT, get_identifier ("method_next"));
field_decl = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
field_decl_chain = field_decl;
else if (TREE_CODE (args) == TREE_LIST)
sel_name = build_keyword_selector (args);
- /* Build the parameters list for looking up the method.
- These are the object itself and the selector. */
-
- selector = build_selector_reference (sel_name);
-
/* Build the parameter list to give to the method. */
method_params = NULLT;
/* Save the selector name for printing error messages. */
building_objc_message_expr = 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, self_object,
selector, method_params);
else if (TREE_CODE (selnamelist) == TREE_LIST)
selname = build_keyword_selector (selnamelist);
- return build_selector_reference (selname);
+ if (flag_typed_selectors)
+ return build_typed_selector_reference (selname, 0);
+ else
+ return build_selector_reference (selname);
}
tree