Commit 5d0f30f7 by Kresten Krab Thorup

objc-act.c (get_proto_encoding, [...]): New fucnctions.

        * objc-act.c (get_proto_encoding, build_typed_selector_reference):
        New fucnctions. (UTAG_PROTOCOL): New define.
        (objc_selector_template, flag_typed_selectors): New variables.
        (objc_init): set flag_typed_selectors if -fgnu-runtime.
        (synth_module_prologue): Change declaration of
        _OBJC_SELECTOR_TABLE when flag_typed_selectors is non-null.
        (build_module_descriptor): Make sure the generated constructor
        function is declared public.
        (build_selector): Only cast to SEL when not doing typed selectors.
        (build_selector_translation_table): Rewrite initialization.
        (build_tmp_function_decl): Make up new name when called, since it
        may now be called multiple times.
        (hack_method_prototype): Use init_function_start to reinit args
        machinery.  Also set current_function_decl before calling
        assign_parms.
        (generate_protocols):  Don't generate encoding twice.
        (build_selector_template): New function.
        (build_method_list_template): Generate (void*)0 as first element,
        not (int)0.
        (build_message_expr): move the call to build_selector_reference
        towards the end, where we have determined the function prototype.

From-SVN: r7620
parent bd4d60ce
...@@ -47,6 +47,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ...@@ -47,6 +47,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "input.h" #include "input.h"
#include "function.h" #include "function.h"
/* This is the default way of generating a method name. */ /* This is the default way of generating a method name. */
/* I am not sure it is really correct. /* I am not sure it is really correct.
Perhaps there's a danger that it will make name conflicts Perhaps there's a danger that it will make name conflicts
...@@ -127,7 +128,7 @@ char *util_firstobj; ...@@ -127,7 +128,7 @@ char *util_firstobj;
#include "rtl.h" #include "rtl.h"
#include "c-parse.h" #include "c-parse.h"
#define OBJC_VERSION 5 #define OBJC_VERSION 6
#define PROTOCOL_VERSION 2 #define PROTOCOL_VERSION 2
#define NULLT (tree) 0 #define NULLT (tree) 0
...@@ -150,6 +151,7 @@ static char *build_module_descriptor PROTO((void)); ...@@ -150,6 +151,7 @@ static char *build_module_descriptor PROTO((void));
static tree init_module_descriptor PROTO((tree)); static tree init_module_descriptor PROTO((tree));
static tree build_objc_method_call PROTO((int, tree, tree, tree, tree, tree)); static tree build_objc_method_call PROTO((int, tree, tree, tree, tree, tree));
static void generate_strings PROTO((void)); static void generate_strings PROTO((void));
static tree get_proto_encoding PROTO((tree));
static void build_selector_translation_table PROTO((void)); static void build_selector_translation_table PROTO((void));
static tree build_ivar_chain PROTO((tree, int)); static tree build_ivar_chain PROTO((tree, int));
...@@ -157,6 +159,7 @@ static tree build_ivar_template PROTO((void)); ...@@ -157,6 +159,7 @@ static tree build_ivar_template PROTO((void));
static tree build_method_template PROTO((void)); static tree build_method_template PROTO((void));
static tree build_private_template PROTO((tree)); static tree build_private_template PROTO((tree));
static void build_class_template PROTO((void)); static void build_class_template PROTO((void));
static void build_selector_template PROTO((void));
static void build_category_template PROTO((void)); static void build_category_template PROTO((void));
static tree build_super_template PROTO((void)); static tree build_super_template PROTO((void));
static tree build_category_initializer PROTO((tree, tree, tree, tree, tree, tree)); static tree build_category_initializer PROTO((tree, tree, tree, tree, tree, tree));
...@@ -263,6 +266,7 @@ static void forward_declare_categories PROTO((void)); ...@@ -263,6 +266,7 @@ static void forward_declare_categories PROTO((void));
static void generate_objc_symtab_decl PROTO((void)); static void generate_objc_symtab_decl PROTO((void));
static tree build_selector PROTO((tree)); static tree build_selector PROTO((tree));
static tree build_msg_pool_reference PROTO((int)); 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_selector_reference PROTO((tree));
static tree build_class_reference_decl PROTO((tree)); static tree build_class_reference_decl PROTO((tree));
static void add_class_reference PROTO((tree)); static void add_class_reference PROTO((tree));
...@@ -319,6 +323,7 @@ static void handle_class_ref PROTO((tree)); ...@@ -319,6 +323,7 @@ static void handle_class_ref PROTO((tree));
#define UTAG_MODULE "_objc_module" #define UTAG_MODULE "_objc_module"
#define UTAG_SYMTAB "_objc_symtab" #define UTAG_SYMTAB "_objc_symtab"
#define UTAG_SUPER "_objc_super" #define UTAG_SUPER "_objc_super"
#define UTAG_SELECTOR "_objc_selector"
#define UTAG_PROTOCOL "_objc_protocol" #define UTAG_PROTOCOL "_objc_protocol"
#define UTAG_PROTOCOL_LIST "_objc_protocol_list" #define UTAG_PROTOCOL_LIST "_objc_protocol_list"
...@@ -414,7 +419,7 @@ static int imp_count = 0; /* `@implementation' */ ...@@ -414,7 +419,7 @@ static int imp_count = 0; /* `@implementation' */
static int cat_count = 0; /* `@category' */ static int cat_count = 0; /* `@category' */
static tree objc_class_template, objc_category_template, uprivate_record; 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 ucls_super_ref, uucls_super_ref;
static tree objc_method_template, objc_ivar_template; static tree objc_method_template, objc_ivar_template;
...@@ -436,6 +441,7 @@ static char *errbuf; /* a buffer for error diagnostics */ ...@@ -436,6 +441,7 @@ static char *errbuf; /* a buffer for error diagnostics */
/* data imported from tree.c */ /* data imported from tree.c */
extern struct obstack permanent_obstack, *current_obstack, *rtl_obstack; extern struct obstack permanent_obstack, *current_obstack, *rtl_obstack;
extern enum debug_info_type write_symbols;
/* data imported from toplev.c */ /* data imported from toplev.c */
...@@ -449,6 +455,8 @@ int flag_next_runtime = 1; ...@@ -449,6 +455,8 @@ int flag_next_runtime = 1;
int flag_next_runtime = 0; int flag_next_runtime = 0;
#endif #endif
int flag_typed_selectors;
/* Open and close the file for outputting class declarations, if requested. */ /* Open and close the file for outputting class declarations, if requested. */
int flag_gen_declaration = 0; int flag_gen_declaration = 0;
...@@ -509,6 +517,7 @@ lang_init () ...@@ -509,6 +517,7 @@ lang_init ()
TAG_MSGSEND = "objc_msg_lookup"; TAG_MSGSEND = "objc_msg_lookup";
TAG_MSGSENDSUPER = "objc_msg_lookup_super"; TAG_MSGSENDSUPER = "objc_msg_lookup_super";
TAG_EXECCLASS = "__objc_exec_class"; TAG_EXECCLASS = "__objc_exec_class";
flag_typed_selectors = 1;
} }
if (doing_objc_thang) if (doing_objc_thang)
...@@ -1086,12 +1095,29 @@ synth_module_prologue () ...@@ -1086,12 +1095,29 @@ synth_module_prologue ()
/* static SEL _OBJC_SELECTOR_TABLE[]; */ /* static SEL _OBJC_SELECTOR_TABLE[]; */
if (! flag_next_runtime)
{
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); temp_type = build_array_type (selector_type, NULLT);
layout_type (temp_type); layout_type (temp_type);
if (! flag_next_runtime)
UOBJC_SELECTOR_TABLE_decl UOBJC_SELECTOR_TABLE_decl
= create_builtin_decl (VAR_DECL, temp_type, = create_builtin_decl (VAR_DECL, temp_type,
"_OBJC_SELECTOR_TABLE"); "_OBJC_SELECTOR_TABLE");
}
generate_forward_declaration_to_string_table (); generate_forward_declaration_to_string_table ();
...@@ -1510,6 +1536,7 @@ build_module_descriptor () ...@@ -1510,6 +1536,7 @@ build_module_descriptor ()
function_type); function_type);
DECL_EXTERNAL (function_decl) = 1; DECL_EXTERNAL (function_decl) = 1;
TREE_PUBLIC (function_decl) = 1; TREE_PUBLIC (function_decl) = 1;
pushdecl (function_decl); pushdecl (function_decl);
rest_of_decl_compilation (function_decl, 0, 0, 0); rest_of_decl_compilation (function_decl, 0, 0, 0);
...@@ -1540,6 +1567,9 @@ build_module_descriptor () ...@@ -1540,6 +1567,9 @@ build_module_descriptor ()
assemble_external (function_decl); assemble_external (function_decl);
c_expand_expr_stmt (decelerator); c_expand_expr_stmt (decelerator);
TREE_PUBLIC (current_function_decl) = 1;
DECL_EXTERNAL (current_function_decl) = 1;
finish_function (0); finish_function (0);
/* Return the name of the constructor function. */ /* Return the name of the constructor function. */
...@@ -1652,7 +1682,9 @@ build_selector (ident) ...@@ -1652,7 +1682,9 @@ build_selector (ident)
tree ident; tree ident;
{ {
tree expr = add_objc_string (ident, meth_var_names); tree expr = add_objc_string (ident, meth_var_names);
if (flag_typed_selectors)
return expr;
else
return build_c_cast (selector_type, expr); /* cast! */ return build_c_cast (selector_type, expr); /* cast! */
} }
...@@ -1730,7 +1762,19 @@ build_selector_translation_table () ...@@ -1730,7 +1762,19 @@ build_selector_translation_table ()
finish_decl (decl, expr, NULLT); finish_decl (decl, expr, NULLT);
} }
else 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); initlist = tree_cons (NULLT, expr, initlist);
}
} }
if (! flag_next_runtime) if (! flag_next_runtime)
...@@ -1747,15 +1791,67 @@ build_selector_translation_table () ...@@ -1747,15 +1791,67 @@ build_selector_translation_table ()
} }
} }
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 /* sel_ref_chain is a list whose "value" fields will be instances of
identifier_node that represent the selector. */ identifier_node that represent the selector. */
static tree 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) build_selector_reference (ident)
tree ident; tree ident;
{ {
tree *chain = &sel_ref_chain; tree *chain = &sel_ref_chain;
tree decl; tree expr;
int index = 0; int index = 0;
while (*chain) while (*chain)
...@@ -1770,12 +1866,12 @@ build_selector_reference (ident) ...@@ -1770,12 +1866,12 @@ build_selector_reference (ident)
chain = &TREE_CHAIN (*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 return (flag_next_runtime
? decl ? expr
: build_array_ref (UOBJC_SELECTOR_TABLE_decl, : build_array_ref (UOBJC_SELECTOR_TABLE_decl,
build_int_2 (index, 0))); build_int_2 (index, 0)));
} }
...@@ -2531,6 +2627,8 @@ static tree ...@@ -2531,6 +2627,8 @@ static tree
build_tmp_function_decl () build_tmp_function_decl ()
{ {
tree decl_specs, expr_decl, parms; tree decl_specs, expr_decl, parms;
static int xxx = 0;
char buffer[80];
/* struct objc_object *objc_xxx (id, SEL, ...); */ /* struct objc_object *objc_xxx (id, SEL, ...); */
pushlevel (0); pushlevel (0);
...@@ -2547,7 +2645,8 @@ build_tmp_function_decl () ...@@ -2547,7 +2645,8 @@ build_tmp_function_decl ()
poplevel (0, 0, 0); poplevel (0, 0, 0);
decl_specs = build_tree_list (NULLT, objc_object_reference); 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); expr_decl = build1 (INDIRECT_REF, NULLT, expr_decl);
return define_decl (expr_decl, decl_specs); return define_decl (expr_decl, decl_specs);
...@@ -2574,9 +2673,8 @@ hack_method_prototype (nst_methods, tmp_decl) ...@@ -2574,9 +2673,8 @@ hack_method_prototype (nst_methods, tmp_decl)
/* Usually called from store_parm_decls -> init_function_start. */ /* 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); DECL_ARGUMENTS (tmp_decl) = TREE_PURPOSE (parms);
current_function_decl = tmp_decl;
{ {
/* Code taken from start_function. */ /* Code taken from start_function. */
...@@ -2588,11 +2686,14 @@ hack_method_prototype (nst_methods, tmp_decl) ...@@ -2588,11 +2686,14 @@ hack_method_prototype (nst_methods, tmp_decl)
DECL_RESULT (tmp_decl) = build_decl (RESULT_DECL, 0, restype); 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. */ /* Typically called from expand_function_start for function definitions. */
assign_parms (tmp_decl, 0); assign_parms (tmp_decl, 0);
/* install return type */ /* install return type */
TREE_TYPE (TREE_TYPE (tmp_decl)) = groktypename (TREE_TYPE (nst_methods)); TREE_TYPE (TREE_TYPE (tmp_decl)) = groktypename (TREE_TYPE (nst_methods));
} }
static void static void
...@@ -2650,18 +2751,23 @@ generate_protocols () ...@@ -2650,18 +2751,23 @@ generate_protocols ()
while (nst_methods) while (nst_methods)
{ {
if (! METHOD_ENCODING (nst_methods))
{
hack_method_prototype (nst_methods, tmp_decl); hack_method_prototype (nst_methods, tmp_decl);
encoding = encode_method_prototype (nst_methods, tmp_decl); encoding = encode_method_prototype (nst_methods, tmp_decl);
METHOD_ENCODING (nst_methods) = encoding; METHOD_ENCODING (nst_methods) = encoding;
}
nst_methods = TREE_CHAIN (nst_methods); nst_methods = TREE_CHAIN (nst_methods);
} }
while (cls_methods) while (cls_methods)
{ {
if (! METHOD_ENCODING (cls_methods))
{
hack_method_prototype (cls_methods, tmp_decl); hack_method_prototype (cls_methods, tmp_decl);
encoding = encode_method_prototype (cls_methods, tmp_decl); encoding = encode_method_prototype (cls_methods, tmp_decl);
METHOD_ENCODING (cls_methods) = encoding; METHOD_ENCODING (cls_methods) = encoding;
}
cls_methods = TREE_CHAIN (cls_methods); cls_methods = TREE_CHAIN (cls_methods);
} }
...@@ -2815,6 +2921,37 @@ build_category_template () ...@@ -2815,6 +2921,37 @@ build_category_template ()
finish_struct (objc_category_template, field_decl_chain); 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 {
struct objc_class *isa; struct objc_class *isa;
struct objc_class *super_class; struct objc_class *super_class;
...@@ -3193,9 +3330,10 @@ build_method_list_template (list_type, size) ...@@ -3193,9 +3330,10 @@ build_method_list_template (list_type, size)
/* int method_next; */ /* int method_next; */
decl_specs = build_tree_list (NULLT, ridpointers[(int) RID_INT]); decl_specs = build_tree_list (NULLT,
field_decl = get_identifier ("method_next"); 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 = grokfield (input_filename, lineno, field_decl, decl_specs, NULLT);
field_decl_chain = field_decl; field_decl_chain = field_decl;
...@@ -4343,11 +4481,6 @@ build_message_expr (mess) ...@@ -4343,11 +4481,6 @@ build_message_expr (mess)
else if (TREE_CODE (args) == TREE_LIST) else if (TREE_CODE (args) == TREE_LIST)
sel_name = build_keyword_selector (args); 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. */ /* Build the parameter list to give to the method. */
method_params = NULLT; method_params = NULLT;
...@@ -4544,6 +4677,14 @@ build_message_expr (mess) ...@@ -4544,6 +4677,14 @@ build_message_expr (mess)
/* Save the selector name for printing error messages. */ /* Save the selector name for printing error messages. */
building_objc_message_expr = sel_name; 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, retval = build_objc_method_call (super, method_prototype,
receiver, self_object, receiver, self_object,
selector, method_params); selector, method_params);
...@@ -4744,6 +4885,9 @@ build_selector_expr (selnamelist) ...@@ -4744,6 +4885,9 @@ build_selector_expr (selnamelist)
else if (TREE_CODE (selnamelist) == TREE_LIST) else if (TREE_CODE (selnamelist) == TREE_LIST)
selname = build_keyword_selector (selnamelist); selname = build_keyword_selector (selnamelist);
if (flag_typed_selectors)
return build_typed_selector_reference (selname, 0);
else
return build_selector_reference (selname); return build_selector_reference (selname);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment