/* GNU Objective C Runtime message lookup
Copyright (C) 1993, 1995, 1996, 1997, 1998,
- 2001, 2002 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
+GCC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
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 "coretypes.h"
+#include "tm.h"
#include "runtime.h"
#include "sarray.h"
#include "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
__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, ...);
+id nil_method (id, SEL);
/* Given a selector, return the proper forwarding implementation. */
-__inline__
+inline
IMP
__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)
{
+ /* 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)
{
{
/* The dispatch table needs to be installed. */
objc_mutex_lock (__objc_runtime_mutex);
- __objc_install_dispatch_table_for_class (class);
+
+ /* 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 */
}
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 (sel);
+ }
}
}
return res;
/* 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)
{
if (object->class_pointer->dtable == __objc_uninstalled_dtable)
{
objc_mutex_lock (__objc_runtime_mutex);
- __objc_install_dispatch_table_for_class (object->class_pointer);
+ if (object->class_pointer->dtable == __objc_uninstalled_dtable)
+ {
+ __objc_install_dispatch_table_for_class (object->class_pointer);
+ }
objc_mutex_unlock (__objc_runtime_mutex);
}
/* 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)
{
}
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 (op);
+ }
}
}
return result;
}
else
- return nil_method;
+ return (IMP)nil_method;
}
IMP
if (super->self)
return get_imp (super->class, sel);
else
- return nil_method;
+ return (IMP)nil_method;
}
int method_get_sizeof_arguments (Method *);
static void
__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);
-
+ {
+ objc_mutex_unlock (__objc_runtime_mutex);
+ return;
+ }
+
if (CLS_ISCLASS (receiver->class_pointer))
{
/* receiver is an ordinary object */
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);
- /* 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;
/* 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__
+inline
struct sarray *
objc_get_uninstalled_dtable ()
{