--- gcc/objc/sendmsg.c 2018/04/24 18:10:14 1.1.1.1 +++ gcc/objc/sendmsg.c 2018/04/24 18:26:42 1.1.1.4 @@ -1,22 +1,22 @@ /* GNU Objective C Runtime message lookup - Copyright (C) 1993 Free Software Foundation, Inc. - -Author: Kresten Krab Thorup + Copyright (C) 1993, 1995 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup This file is part of GNU CC. GNU CC 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. +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. GNU CC 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. +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 - GNU CC; see the file COPYING. If not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 @@ -24,21 +24,40 @@ You should have received a copy of the G however invalidate any other reasons why the executable file might be covered by the GNU General Public License. */ +#include "../tconfig.h" #include "runtime.h" #include "sarray.h" +#include "encoding.h" + +/* this is how we hack STRUCT_VALUE to be 1 or 0 */ +#define gen_rtx(args...) 1 +#define rtx int + +#if 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; /* Send +initialize to class */ -static void __objc_send_initialize(Class*); +static void __objc_send_initialize(Class); -static void __objc_install_dispatch_table_for_class (Class*); +static void __objc_install_dispatch_table_for_class (Class); /* Forward declare some functions */ static void __objc_init_install_dtable(id, SEL); -static id __objc_missing_method(id, SEL, ...); -static Method_t search_for_method_in_hierarchy (Class* class, SEL 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); static Method_t search_for_method_in_list(MethodList_t list, SEL op); id nil_method(id, SEL, ...); @@ -49,19 +68,38 @@ nil_method(id receiver, SEL op, ...) } /* Given a class and selector, return the selector's implementation. */ -__inline__ IMP -get_imp (Class* class, SEL sel) +__inline__ +IMP +get_imp (Class class, SEL sel) { - void* res = sarray_get (class->dtable, (size_t) sel); + IMP impl; + void* res = sarray_get (class->dtable, (size_t) sel->sel_id); if(res == __objc_init_install_dtable) - __objc_install_dispatch_table_for_class (class); - return sarray_get (class->dtable, (size_t) sel); + { + __objc_install_dispatch_table_for_class (class); + res = sarray_get (class->dtable, (size_t) sel->sel_id); + } + if (res == 0) + { + const char *t = sel->sel_types; + if (t && (*t == '[' || *t == '(' || *t == '{')) + res = (IMP)__objc_block_forward; + else + res = (IMP)__objc_word_forward; + } + return res; } __inline__ BOOL __objc_responds_to (id object, SEL sel) { - return get_imp (object->class_pointer, sel) != __objc_missing_method; + void* res = sarray_get (object->class_pointer->dtable, (size_t) sel->sel_id); + if(res == __objc_init_install_dtable) + { + __objc_install_dispatch_table_for_class (object->class_pointer); + res = sarray_get (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 @@ -71,8 +109,20 @@ __objc_responds_to (id object, SEL sel) __inline__ IMP objc_msg_lookup(id receiver, SEL op) { + IMP result; if(receiver) - return sarray_get(receiver->class_pointer->dtable, (sidx)op); + { + result = sarray_get(receiver->class_pointer->dtable, (sidx)op->sel_id); + if (result == 0) + { + const char *t = op->sel_types; + if (t && (*t == '[' || *t == '(' || *t == '{')) + result = (IMP)__objc_block_forward; + else + result = (IMP)__objc_word_forward; + } + return result; + } else return nil_method; } @@ -86,21 +136,18 @@ objc_msg_lookup_super (Super_t super, SE return nil_method; } +int method_get_sizeof_arguments (Method*); + retval_t -objc_msg_sendv(id object, SEL op, size_t frame_size, arglist_t arg_frame) +objc_msg_sendv(id object, SEL op, arglist_t arg_frame) { -#ifdef __objc_frame_receiver - __objc_frame_receiver(arg_frame) = object; - __objc_frame_selector(arg_frame) = op; - return __builtin_apply((apply_t)get_imp(object->class_pointer, op), + 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, - frame_size); -#else -#warning performv:: will not work - va_list nothing; - (*_objc_error)(object, "objc_msg_sendv (performv::) not supported\n", nothing); - return 0; -#endif + method_get_sizeof_arguments (m)); } void __objc_init_dispatch_tables() @@ -115,7 +162,7 @@ void __objc_init_dispatch_tables() static void __objc_init_install_dtable(id receiver, SEL op) { - __label__ allready_initialized; + __label__ already_initialized; IMP imp; void* args; void* result; @@ -123,7 +170,7 @@ static void __objc_init_install_dtable(i /* 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) - goto allready_initialized; + goto already_initialized; if(CLS_ISCLASS(receiver->class_pointer)) { @@ -140,42 +187,43 @@ static void __objc_init_install_dtable(i else { /* receiver is a class object */ - assert(CLS_ISCLASS((Class*)receiver)); + 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); - - if(op != sel_get_uid ("initialize")) - __objc_send_initialize((Class*)receiver); + + if (strcmp (sel_get_name (op), "initialize")) + __objc_send_initialize((Class)receiver); else - CLS_SETINITIALIZED((Class*)receiver); + CLS_SETINITIALIZED((Class)receiver); } -allready_initialized: +already_initialized: /* Get real method for this in newly installed dtable */ imp = get_imp(receiver->class_pointer, op); args = __builtin_apply_args(); result = __builtin_apply((apply_t)imp, args, 96); - __builtin_return (result); + if (result) + __builtin_return (result); + else + return; } /* 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) +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) +static void __objc_send_initialize(Class class) { - Method_t m; - /* This *must* be a class object */ assert(CLS_ISCLASS(class)); assert(!CLS_ISMETA(class)); @@ -189,36 +237,42 @@ static void __objc_send_initialize(Class __objc_send_initialize(class->super_class); { - MethodList_t method_list = class->class_pointer->methods; - SEL op = sel_register_name ("initialize"); + SEL op = sel_register_name ("initialize"); + Class tmpclass = class; + IMP imp = 0; - /* If not found then we'll search the list. */ - while (method_list) - { + while (!imp && tmpclass) { + MethodList_t method_list = tmpclass->class_pointer->methods; + + while(!imp && method_list) { int i; + Method_t method; - /* 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 == op) - (*method->method_imp)((id) class, op); + for (i=0;imethod_count;i++) { + method = &(method_list->method_list[i]); + if (method->method_name->sel_id == op->sel_id) { + imp = method->method_imp; + break; } + } - /* The method wasn't found. Follow the link to the next list of - methods. */ method_list = method_list->method_next; + } + + tmpclass = tmpclass->super_class; + } + if (imp) + (*imp)((id)class, op); + } } } static void -__objc_install_dispatch_table_for_class (Class* class) +__objc_install_dispatch_table_for_class (Class class) { - Class* super; + Class super; MethodList_t mlist; int counter; @@ -232,11 +286,10 @@ __objc_install_dispatch_table_for_class if (super != 0 && (super->dtable == __objc_uninstalled_dtable)) __objc_install_dispatch_table_for_class (super); - /* Allocate dtable if nessecary */ + /* Allocate dtable if necessary */ if (super == 0) { - class->dtable = sarray_new (__objc_selector_max_index, - __objc_missing_method); + class->dtable = sarray_new (__objc_selector_max_index, 0); } else class->dtable = sarray_lazy_copy (super->dtable); @@ -247,31 +300,30 @@ __objc_install_dispatch_table_for_class while (counter >= 0) { Method_t method = &(mlist->method_list[counter]); - sarray_at_put (class->dtable, - (sidx) method->method_name, - method->method_imp); + sarray_at_put_safe (class->dtable, + (sidx) method->method_name->sel_id, + method->method_imp); counter -= 1; } } } -void __objc_update_dispatch_table_for_class (Class* class) +void __objc_update_dispatch_table_for_class (Class class) { - Class* next; - struct sarray* save; + Class next; /* not yet installed -- skip it */ if (class->dtable == __objc_uninstalled_dtable) return; - save = class->dtable; - __objc_install_premature_dtable (class); - sarray_free (save); - + sarray_free (class->dtable); /* release memory */ + __objc_install_premature_dtable (class); /* someone might require it... */ + __objc_install_dispatch_table_for_class (class); /* could have been lazy... */ if (class->subclass_list) /* Traverse subclasses */ for (next = class->subclass_list; next; next = next->sibling_class) __objc_update_dispatch_table_for_class (next); + } @@ -280,10 +332,10 @@ void __objc_update_dispatch_table_for_cl such this function does not worry about thread safe issued. This one is only called for categories. Class objects have their - methods installed rightaway, and their selectors are made into + 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) +class_add_method_list (Class class, MethodList_t list) { int i; static SEL initialize_sel = 0; @@ -300,11 +352,13 @@ class_add_method_list (Class* class, Met if (method->method_name) /* Sometimes these are NULL */ { - /* This is where selector names are transmogriffed to SEL's */ - method->method_name = sel_register_name ((char*)method->method_name); + /* This is where selector names are transmogrified to SEL's */ + method->method_name = + sel_register_typed_name ((const char*)method->method_name, + method->method_types); if (search_for_method_in_list (class->methods, method->method_name) - && method->method_name != initialize_sel) + && method->method_name->sel_id != initialize_sel->sel_id) { /* Duplication. Print a error message an change the method name to NULL. */ @@ -322,13 +376,13 @@ class_add_method_list (Class* class, Met Method_t -class_get_instance_method(Class* class, SEL op) +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) +class_get_class_method(MetaClass class, SEL op) { return search_for_method_in_hierarchy(class, op); } @@ -339,10 +393,10 @@ class_get_class_method(MetaClass* class, otherwise. */ static Method_t -search_for_method_in_hierarchy (Class* cls, SEL sel) +search_for_method_in_hierarchy (Class cls, SEL sel) { Method_t method = NULL; - Class* class; + Class class; if (! sel_is_mapped (sel)) return NULL; @@ -379,7 +433,7 @@ search_for_method_in_list (MethodList_t Method_t method = &method_list->method_list[i]; if (method->method_name) - if (method->method_name == op) + if (method->method_name->sel_id == op->sel_id) return method; } @@ -391,40 +445,71 @@ search_for_method_in_list (MethodList_t return NULL; } +static retval_t __objc_forward (id object, SEL sel, arglist_t args); -/* This fuction is installed in the dispatch table for all methods which are - not implemented. Thus, it is called when a selector is not recognized. */ static id -__objc_missing_method (id object, SEL sel, ...) +__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; +} + +#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); +} + + +/* 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; - SEL frwd_sel; + static SEL frwd_sel = 0; SEL err_sel; /* first try if the object understands forward:: */ - frwd_sel = sel_get_uid("forward::"); - imp = get_imp(object->class_pointer, frwd_sel); - if(imp != __objc_missing_method) - { - void *result, *args = __builtin_apply_args(); - result = (*imp)(object, frwd_sel, sel, args); - __builtin_return(result); + 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_uid ("doesNotRecognize:"); - imp = get_imp (object->class_pointer, err_sel); - if (imp != __objc_missing_method) + 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 ((char*)sel_get_name (sel)) - + strlen ((char*)object->class_pointer->name)]; + size_t strlen (const char*); + 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) @@ -432,10 +517,12 @@ __objc_missing_method (id object, SEL se : "instance" ), object->class_pointer->name, sel_get_name (sel)); - err_sel = sel_get_uid ("error:"); - imp = get_imp (object->class_pointer, err_sel); - if (imp != __objc_missing_method) - return (*imp) (object, sel_get_uid ("error:"), msg); + 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. */ @@ -455,12 +542,12 @@ void __objc_print_dtable_stats() #endif ); - printf("arrays: %d = %d bytes\n", narrays, narrays*sizeof(struct sarray)); + printf("arrays: %d = %ld bytes\n", narrays, (int)narrays*sizeof(struct sarray)); total += narrays*sizeof(struct sarray); - printf("buckets: %d = %d bytes\n", nbuckets, nbuckets*sizeof(struct sbucket)); + printf("buckets: %d = %ld bytes\n", nbuckets, (int)nbuckets*sizeof(struct sbucket)); total += nbuckets*sizeof(struct sbucket); - printf("idxtables: %d = %d bytes\n", idxsize, idxsize*sizeof(void*)); + printf("idxtables: %d = %ld bytes\n", idxsize, (int)idxsize*sizeof(void*)); total += idxsize*sizeof(void*); printf("-----------------------------------\n"); printf("total: %d bytes\n", total);