/* GNU Objective C Runtime message lookup
Copyright (C) 1993, 1995, 1996, 1997, 1998,
- 2001, 2002 Free Software Foundation, Inc.
+ 2001, 2002, 2004, 2009 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.
+Foundation; either version 3, 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. */
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
-/* 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
- to be covered by the GNU General Public License. This exception does not
- 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 "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
/* 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. */
+/* 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);
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.
- */
+ __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;
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. */
+ 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;
}
/* In all other cases, use the default forwarding functions built using
- * __builtin_apply and friends. */
+ __builtin_apply and friends. */
{
const char *t = sel->sel_types;
}
/* 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 ((id)class, 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 (receiver, op);
+ }
}
}
return result;
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;
#endif
printf ("arrays: %d = %ld bytes\n", narrays,
- (long) narrays * sizeof (struct sarray));
+ (long) ((size_t) narrays * sizeof (struct sarray)));
total += narrays * sizeof (struct sarray);
printf ("buckets: %d = %ld bytes\n", nbuckets,
- (long) nbuckets * sizeof (struct sbucket));
+ (long) ((size_t) nbuckets * sizeof (struct sbucket)));
total += nbuckets * sizeof (struct sbucket);
printf ("idxtables: %d = %ld bytes\n",
- idxsize, (long) idxsize * sizeof (void *));
+ idxsize, (long) ((size_t) idxsize * sizeof (void *)));
total += idxsize * sizeof (void *);
printf ("-----------------------------------\n");
printf ("total: %d bytes\n", total);
/* 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 ()
{