X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=libobjc%2Fsendmsg.c;h=42d3e02af9fc62c6c4060c00488893ee05b495c1;hb=a5095f658307b9a28644862f860fb4ecfe4a69b3;hp=61fa28833b3099f7c2ea397c0fb2b637fcb9f018;hpb=899d0712f77e63feb5450a6ec29bc0659c798a5a;p=pf3gnuchains%2Fgcc-fork.git diff --git a/libobjc/sendmsg.c b/libobjc/sendmsg.c index 61fa28833b3..42d3e02af9f 100644 --- a/libobjc/sendmsg.c +++ b/libobjc/sendmsg.c @@ -1,23 +1,23 @@ /* GNU Objective C Runtime message lookup Copyright (C) 1993, 1995, 1996, 1997, 1998, - 2001 Free Software Foundation, Inc. + 2001, 2002, 2004 Free Software Foundation, Inc. Contributed by Kresten Krab Thorup -This file is part of GNU CC. +This file is part of GCC. -GNU CC is free software; you can redistribute it and/or modify it under the +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. -GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +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 -GNU CC; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +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 @@ -25,77 +25,100 @@ Boston, MA 02111-1307, USA. */ 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 "runtime.h" -#include "sarray.h" -#include "encoding.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 */ +/* 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 +/* Alread defined in gcc/coretypes.h. So prevent double definition warning. */ +#undef rtx #define rtx int -#if !defined(STRUCT_VALUE) || STRUCT_VALUE == 0 +#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; +struct sarray *__objc_uninstalled_dtable = 0; /* !T:MUTEX */ + +/* Two hooks for method forwarding. If either is set, it is invoked + * to return a function that performs the real forwarding. If both + * are set, the result of __objc_msg_forward2 will be preferred over + * that of __objc_msg_forward. If both return NULL or are unset, + * the libgcc based functions (__builtin_apply and friends) are + * used. + */ +IMP (*__objc_msg_forward) (SEL) = NULL; +IMP (*__objc_msg_forward2) (id, SEL) = NULL; /* 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); /* Forward declare some functions */ -static void __objc_init_install_dtable(id, SEL); +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, ...); + __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, ...); +__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, ...); +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__ +inline IMP -__objc_get_forward_imp (SEL sel) +__objc_get_forward_imp (id rcv, SEL sel) { + /* If a custom forwarding hook was registered, try getting a forwarding + function from it. There are two forward routine hooks, one that + takes the receiver as an argument and one that does not. */ + if (__objc_msg_forward2) + { + IMP result; + if ((result = __objc_msg_forward2 (rcv, sel)) != NULL) + return result; + } if (__objc_msg_forward) { IMP result; - if ((result = __objc_msg_forward (sel))) + if ((result = __objc_msg_forward (sel)) != NULL) return result; } - else + + /* 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 + && objc_sizeof_type (t) > OBJC_MAX_STRUCT_BY_VALUE #endif ) return (IMP)__objc_block_forward; @@ -107,30 +130,59 @@ __objc_get_forward_imp (SEL sel) } /* Given a class and selector, return the selector's implementation. */ -__inline__ +inline IMP get_imp (Class class, SEL sel) { - void* res = sarray_get_safe (class->dtable, (size_t) sel->sel_id); + /* 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) + if (class->dtable == __objc_uninstalled_dtable) { /* The dispatch table needs to be installed. */ - objc_mutex_lock(__objc_runtime_mutex); - __objc_install_dispatch_table_for_class (class); - objc_mutex_unlock(__objc_runtime_mutex); + 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); + res = get_imp (class, sel); } else { - /* The dispatch table has been installed so the - method just doesn't exist for the class. - Return the forwarding implementation. */ - res = __objc_get_forward_imp(sel); + /* 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 ((id)class, sel); + } } } return res; @@ -139,18 +191,21 @@ get_imp (Class class, SEL sel) /* 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__ +inline BOOL __objc_responds_to (id object, SEL sel) { - void* res; + void *res; /* Install dispatch table if need be */ if (object->class_pointer->dtable == __objc_uninstalled_dtable) { - objc_mutex_lock(__objc_runtime_mutex); - __objc_install_dispatch_table_for_class (object->class_pointer); - objc_mutex_unlock(__objc_runtime_mutex); + 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 */ @@ -161,39 +216,48 @@ __objc_responds_to (id object, SEL sel) /* 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__ +inline IMP -objc_msg_lookup(id receiver, SEL op) +objc_msg_lookup (id receiver, SEL op) { IMP result; - if(receiver) + 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) + 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); + __objc_init_install_dtable (receiver, op); /* Get real method for this in newly installed dtable */ - result = get_imp(receiver->class_pointer, op); + result = get_imp (receiver->class_pointer, op); } else { - /* The dispatch table has been installed so the - method just doesn't exist for the class. - Attempt to forward the method. */ - result = __objc_get_forward_imp(op); + /* 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 (receiver, op); + } } } return result; } else - return nil_method; + return (IMP)nil_method; } IMP @@ -202,96 +266,98 @@ objc_msg_lookup_super (Super_t super, SEL sel) if (super->self) return get_imp (super->class, sel); else - return nil_method; + return (IMP)nil_method; } -int method_get_sizeof_arguments (Method*); +int method_get_sizeof_arguments (Method *); retval_t -objc_msg_sendv(id object, SEL op, arglist_t arg_frame) +objc_msg_sendv (id object, SEL op, arglist_t arg_frame) { - Method* m = class_get_instance_method(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, - method_get_sizeof_arguments (m)); + *((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_init_dispatch_tables () { - __objc_uninstalled_dtable - = sarray_new(200, 0); + __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) +__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) - return; - - objc_mutex_lock(__objc_runtime_mutex); - - if(CLS_ISCLASS(receiver->class_pointer)) + 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)); + 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); + __objc_send_initialize (receiver->class_pointer); } else { /* receiver is a class object */ - assert(CLS_ISCLASS((Class)receiver)); - assert(CLS_ISMETA(receiver->class_pointer)); + 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_send_initialize ((Class)receiver); } - objc_mutex_unlock(__objc_runtime_mutex); + 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) +__objc_install_premature_dtable (Class class) { - assert(__objc_uninstalled_dtable); + assert (__objc_uninstalled_dtable); class->dtable = __objc_uninstalled_dtable; } /* Send +initialize to class if not already done */ static void -__objc_send_initialize(Class class) +__objc_send_initialize (Class class) { /* This *must* be a class object */ - assert(CLS_ISCLASS(class)); - assert(!CLS_ISMETA(class)); + assert (CLS_ISCLASS (class)); + assert (! CLS_ISMETA (class)); - if (!CLS_ISINITIALIZED(class)) + if (! CLS_ISINITIALIZED (class)) { - CLS_SETINITIALIZED(class); - CLS_SETINITIALIZED(class->class_pointer); + 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); + if (class->super_class) + __objc_send_initialize (class->super_class); { SEL op = sel_register_name ("initialize"); @@ -302,7 +368,7 @@ __objc_send_initialize(Class class) int i; Method_t method; - for (i = 0; i< method_list->method_count; i++) { + 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) { @@ -318,7 +384,7 @@ __objc_send_initialize(Class class) } if (imp) - (*imp)((id)class, op); + (*imp) ((id) class, op); } } @@ -335,7 +401,7 @@ __objc_install_methods_in_dtable (Class class, MethodList_t method_list) { int i; - if (!method_list) + if (! method_list) return; if (method_list->method_next) @@ -358,8 +424,8 @@ __objc_install_dispatch_table_for_class (Class class) /* 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(); + if (! CLS_ISRESOLV (class)) + __objc_resolve_class_links (); super = class->super_class; @@ -369,9 +435,9 @@ __objc_install_dispatch_table_for_class (Class class) /* Allocate dtable if necessary */ if (super == 0) { - objc_mutex_lock(__objc_runtime_mutex); + objc_mutex_lock (__objc_runtime_mutex); class->dtable = sarray_new (__objc_selector_max_index, 0); - objc_mutex_unlock(__objc_runtime_mutex); + objc_mutex_unlock (__objc_runtime_mutex); } else class->dtable = sarray_lazy_copy (super->dtable); @@ -389,7 +455,7 @@ __objc_update_dispatch_table_for_class (Class class) if (class->dtable == __objc_uninstalled_dtable) return; - objc_mutex_lock(__objc_runtime_mutex); + objc_mutex_lock (__objc_runtime_mutex); arr = class->dtable; __objc_install_premature_dtable (class); /* someone might require it... */ @@ -402,7 +468,7 @@ __objc_update_dispatch_table_for_class (Class class) for (next = class->subclass_list; next; next = next->sibling_class) __objc_update_dispatch_table_for_class (next); - objc_mutex_unlock(__objc_runtime_mutex); + objc_mutex_unlock (__objc_runtime_mutex); } @@ -412,28 +478,14 @@ __objc_update_dispatch_table_for_class (Class class) 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. */ + SEL's by the function __objc_register_selectors_from_class. */ void class_add_method_list (Class class, MethodList_t list) { - int i; - /* Passing of a linked list is not allowed. Do multiple calls. */ - assert (!list->method_next); + assert (! list->method_next); - /* Check for duplicates. */ - for (i = 0; i < list->method_count; ++i) - { - Method_t method = &list->method_list[i]; - - if (method->method_name) /* Sometimes these are NULL */ - { - /* 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); - } - } + __objc_register_selectors_from_list(list); /* Add the methods to the class's method list. */ list->method_next = class->methods; @@ -444,15 +496,15 @@ class_add_method_list (Class class, MethodList_t list) } 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); + 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); + return search_for_method_in_hierarchy (class, op); } @@ -576,13 +628,13 @@ __objc_forward (id object, SEL sel, arglist_t args) SEL err_sel; /* first try if the object understands forward:: */ - if (!frwd_sel) - frwd_sel = sel_get_any_uid("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); + 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 @@ -597,11 +649,11 @@ __objc_forward (id object, SEL sel, arglist_t args) /* 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)]; + 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) + (CLS_ISMETA (object->class_pointer) ? "class" : "instance" ), object->class_pointer->name, sel_get_name (sel)); @@ -622,40 +674,41 @@ __objc_forward (id object, SEL sel, arglist_t args) } void -__objc_print_dtable_stats() +__objc_print_dtable_stats () { int total = 0; - objc_mutex_lock(__objc_runtime_mutex); + objc_mutex_lock (__objc_runtime_mutex); #ifdef OBJC_SPARSE2 - printf("memory usage: (%s)\n", "2-level sparse arrays"); + printf ("memory usage: (%s)\n", "2-level sparse arrays"); #else - printf("memory usage: (%s)\n", "3-level sparse arrays"); + 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); + printf ("arrays: %d = %ld bytes\n", narrays, + (long) ((size_t) narrays * sizeof (struct sarray))); + total += narrays * sizeof (struct sarray); + printf ("buckets: %d = %ld bytes\n", nbuckets, + (long) ((size_t) nbuckets * sizeof (struct sbucket))); + total += nbuckets * sizeof (struct sbucket); + + printf ("idxtables: %d = %ld bytes\n", + idxsize, (long) ((size_t) 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() +inline +struct sarray * +objc_get_uninstalled_dtable () { return __objc_uninstalled_dtable; }