aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.7/libobjc/sendmsg.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.7/libobjc/sendmsg.c')
-rw-r--r--gcc-4.7/libobjc/sendmsg.c1171
1 files changed, 0 insertions, 1171 deletions
diff --git a/gcc-4.7/libobjc/sendmsg.c b/gcc-4.7/libobjc/sendmsg.c
deleted file mode 100644
index ea8ea9702..000000000
--- a/gcc-4.7/libobjc/sendmsg.c
+++ /dev/null
@@ -1,1171 +0,0 @@
-/* GNU Objective C Runtime message lookup
- Copyright (C) 1993, 1995, 1996, 1997, 1998,
- 2001, 2002, 2004, 2009, 2010 Free Software Foundation, Inc.
- Contributed by Kresten Krab Thorup
-
-This file is part of GCC.
-
-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 3, or (at your option) any later version.
-
-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.
-
-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/>. */
-
-/* Uncommented the following line to enable debug logging. Use this
- only while debugging the runtime. */
-/* #define DEBUG 1 */
-
-/* FIXME: This file has no business including tm.h. */
-/* FIXME: This should be using libffi instead of __builtin_apply
- and friends. */
-
-#include "objc-private/common.h"
-#include "objc-private/error.h"
-#include "tconfig.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "objc/runtime.h"
-#include "objc/message.h" /* For objc_msg_lookup(), objc_msg_lookup_super(). */
-#include "objc/thr.h"
-#include "objc-private/module-abi-8.h"
-#include "objc-private/runtime.h"
-#include "objc-private/hash.h"
-#include "objc-private/sarray.h"
-#include "objc-private/selector.h" /* For sel_is_mapped() */
-#include "runtime-info.h"
-#include <assert.h> /* For assert */
-#include <string.h> /* For strlen */
-
-/* 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
-/* Already defined in gcc/coretypes.h. So prevent double definition warning. */
-#undef rtx
-#define rtx int
-
-#if ! defined (STRUCT_VALUE) || STRUCT_VALUE == 0
-#define INVISIBLE_STRUCT_RETURN 1
-#else
-#define INVISIBLE_STRUCT_RETURN 0
-#endif
-
-/* The uninstalled dispatch table. If a class' dispatch table points
- to __objc_uninstalled_dtable then that means it needs its dispatch
- table to be installed. */
-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);
-
-/* Forward declare some functions */
-static void __objc_install_dtable_for_class (Class cls);
-static void __objc_prepare_dtable_for_class (Class cls);
-static void __objc_install_prepared_dtable_for_class (Class cls);
-
-static struct sarray *__objc_prepared_dtable_for_class (Class cls);
-static IMP __objc_get_prepared_imp (Class cls,SEL 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, ...);
-typedef struct { id many[8]; } __big;
-#if INVISIBLE_STRUCT_RETURN
-static __big
-#else
-static id
-#endif
-__objc_block_forward (id, SEL, ...);
-static struct objc_method * search_for_method_in_hierarchy (Class class, SEL sel);
-struct objc_method * search_for_method_in_list (struct objc_method_list * list, SEL op);
-id nil_method (id, SEL);
-
-/* Given a selector, return the proper forwarding implementation. */
-inline
-IMP
-__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)) != NULL)
- return result;
- }
-
- /* 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
-#endif
- )
- return (IMP)__objc_block_forward;
- else if (t && (*t == 'f' || *t == 'd'))
- return (IMP)__objc_double_forward;
- else
- return (IMP)__objc_word_forward;
- }
-}
-
-/* Selectors for +resolveClassMethod: and +resolveInstanceMethod:.
- These are set up at startup. */
-static SEL selector_resolveClassMethod = NULL;
-static SEL selector_resolveInstanceMethod = NULL;
-
-/* Internal routines use to resolve a class method using
- +resolveClassMethod:. 'class' is always a non-Nil class (*not* a
- meta-class), and 'sel' is the selector that we are trying to
- resolve. This must be called when class is not Nil, and the
- dispatch table for class methods has already been installed.
-
- This routine tries to call +resolveClassMethod: to give an
- opportunity to resolve the method. If +resolveClassMethod: returns
- YES, it tries looking up the method again, and if found, it returns
- it. Else, it returns NULL. */
-static inline
-IMP
-__objc_resolve_class_method (Class class, SEL sel)
-{
- /* We need to lookup +resolveClassMethod:. */
- BOOL (*resolveMethodIMP) (id, SEL, SEL);
-
- /* The dispatch table for class methods is already installed and we
- don't want any forwarding to happen when looking up this method,
- so we just look it up directly. Note that if 'sel' is precisely
- +resolveClassMethod:, this would look it up yet again and find
- nothing. That's no problem and there's no recursion. */
- resolveMethodIMP = (BOOL (*) (id, SEL, SEL))sarray_get_safe
- (class->class_pointer->dtable, (size_t) selector_resolveClassMethod->sel_id);
-
- if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveClassMethod, sel))
- {
- /* +resolveClassMethod: returned YES. Look the method up again.
- We already know the dtable is installed. */
-
- /* TODO: There is the case where +resolveClassMethod: is buggy
- and returned YES without actually adding the method. We
- could maybe print an error message. */
- return sarray_get_safe (class->class_pointer->dtable, (size_t) sel->sel_id);
- }
-
- return NULL;
-}
-
-/* Internal routines use to resolve a instance method using
- +resolveInstanceMethod:. 'class' is always a non-Nil class, and
- 'sel' is the selector that we are trying to resolve. This must be
- called when class is not Nil, and the dispatch table for instance
- methods has already been installed.
-
- This routine tries to call +resolveInstanceMethod: to give an
- opportunity to resolve the method. If +resolveInstanceMethod:
- returns YES, it tries looking up the method again, and if found, it
- returns it. Else, it returns NULL. */
-static inline
-IMP
-__objc_resolve_instance_method (Class class, SEL sel)
-{
- /* We need to lookup +resolveInstanceMethod:. */
- BOOL (*resolveMethodIMP) (id, SEL, SEL);
-
- /* The dispatch table for class methods may not be already installed
- so we have to install it if needed. */
- resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable,
- (size_t) selector_resolveInstanceMethod->sel_id);
- if (resolveMethodIMP == 0)
- {
- /* Try again after installing the dtable. */
- if (class->class_pointer->dtable == __objc_uninstalled_dtable)
- {
- objc_mutex_lock (__objc_runtime_mutex);
- if (class->class_pointer->dtable == __objc_uninstalled_dtable)
- __objc_install_dtable_for_class (class->class_pointer);
- objc_mutex_unlock (__objc_runtime_mutex);
- }
- resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable,
- (size_t) selector_resolveInstanceMethod->sel_id);
- }
-
- if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveInstanceMethod, sel))
- {
- /* +resolveInstanceMethod: returned YES. Look the method up
- again. We already know the dtable is installed. */
-
- /* TODO: There is the case where +resolveInstanceMethod: is
- buggy and returned YES without actually adding the method.
- We could maybe print an error message. */
- return sarray_get_safe (class->dtable, (size_t) sel->sel_id);
- }
-
- return NULL;
-}
-
-/* Given a CLASS and selector, return the implementation corresponding
- to the method of the selector.
-
- If CLASS is a class, the instance method is returned.
- If CLASS is a meta class, the class method is returned.
-
- Since this requires the dispatch table to be installed, this function
- will implicitly invoke +initialize for CLASS if it hasn't been
- invoked yet. This also insures that +initialize has been invoked
- when the returned implementation is called directly.
-
- The forwarding hooks require the receiver as an argument (if they are to
- perform dynamic lookup in proxy objects etc), so this function has a
- receiver argument to be used with those hooks. */
-static inline
-IMP
-get_implementation (id receiver, Class class, SEL sel)
-{
- void *res;
-
- if (class->dtable == __objc_uninstalled_dtable)
- {
- /* The dispatch table needs to be installed. */
- 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_dtable_for_class (class);
-
- /* If the dispatch table is not yet installed, we are still in
- the process of executing +initialize. But the implementation
- pointer should be available in the prepared ispatch table if
- it exists at all. */
- if (class->dtable == __objc_uninstalled_dtable)
- {
- assert (__objc_prepared_dtable_for_class (class) != 0);
- res = __objc_get_prepared_imp (class, sel);
- }
- else
- res = 0;
-
- objc_mutex_unlock (__objc_runtime_mutex);
- /* Call ourselves with the installed dispatch table and get the
- real method. */
- if (!res)
- res = get_implementation (receiver, class, sel);
- }
- else
- {
- /* The dispatch table has been installed. */
- 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. */
-
- /* Try going through the +resolveClassMethod: or
- +resolveInstanceMethod: process. */
- if (CLS_ISMETA (class))
- {
- /* We have the meta class, but we need to invoke the
- +resolveClassMethod: method on the class. So, we
- need to obtain the class from the meta class, which
- we do using the fact that both the class and the
- meta-class have the same name. */
- Class realClass = objc_lookUpClass (class->name);
- if (realClass)
- res = __objc_resolve_class_method (realClass, sel);
- }
- else
- res = __objc_resolve_instance_method (class, sel);
-
- if (res == 0)
- res = __objc_get_forward_imp (receiver, sel);
- }
- }
- return res;
-}
-
-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)
- {
- res = get_implementation(nil, class, sel);
- }
- return res;
-}
-
-/* The new name of get_imp(). */
-IMP
-class_getMethodImplementation (Class class_, SEL selector)
-{
- if (class_ == Nil || selector == NULL)
- return NULL;
-
- /* get_imp is inlined, so we're good. */
- return get_imp (class_, selector);
-}
-
-/* Given a method, return its implementation. This has been replaced
- by method_getImplementation() in the modern API. */
-IMP
-method_get_imp (struct objc_method * method)
-{
- return (method != (struct objc_method *)0) ? method->method_imp : (IMP)0;
-}
-
-/* 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. Since this requires the dispatch table to
- installed, this function will implicitly invoke +initialize for the
- class of OBJECT if it hasn't been invoked yet. */
-inline
-BOOL
-__objc_responds_to (id object, SEL sel)
-{
- void *res;
- struct sarray *dtable;
-
- /* Install dispatch table if need be */
- dtable = object->class_pointer->dtable;
- if (dtable == __objc_uninstalled_dtable)
- {
- objc_mutex_lock (__objc_runtime_mutex);
- if (object->class_pointer->dtable == __objc_uninstalled_dtable)
- __objc_install_dtable_for_class (object->class_pointer);
-
- /* If the dispatch table is not yet installed, we are still in
- the process of executing +initialize. Yet the dispatch table
- should be available. */
- if (object->class_pointer->dtable == __objc_uninstalled_dtable)
- {
- dtable = __objc_prepared_dtable_for_class (object->class_pointer);
- assert (dtable);
- }
- else
- dtable = object->class_pointer->dtable;
-
- objc_mutex_unlock (__objc_runtime_mutex);
- }
-
- /* Get the method from the dispatch table. */
- res = sarray_get_safe (dtable, (size_t) sel->sel_id);
- return (res != 0) ? YES : NO;
-}
-
-BOOL
-class_respondsToSelector (Class class_, SEL selector)
-{
- struct sarray *dtable;
- void *res;
-
- if (class_ == Nil || selector == NULL)
- return NO;
-
- /* Install dispatch table if need be. */
- dtable = class_->dtable;
- if (dtable == __objc_uninstalled_dtable)
- {
- objc_mutex_lock (__objc_runtime_mutex);
- if (class_->dtable == __objc_uninstalled_dtable)
- __objc_install_dtable_for_class (class_);
-
- /* If the dispatch table is not yet installed,
- we are still in the process of executing +initialize.
- Yet the dispatch table should be available. */
- if (class_->dtable == __objc_uninstalled_dtable)
- {
- dtable = __objc_prepared_dtable_for_class (class_);
- assert (dtable);
- }
- else
- dtable = class_->dtable;
-
- objc_mutex_unlock (__objc_runtime_mutex);
- }
-
- /* Get the method from the dispatch table. */
- res = sarray_get_safe (dtable, (size_t) selector->sel_id);
- return (res != 0) ? YES : NO;
-}
-
-/* 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. */
-IMP
-objc_msg_lookup (id receiver, SEL op)
-{
- IMP result;
- if (receiver)
- {
- /* First try a quick lookup assuming the dispatch table exists. */
- result = sarray_get_safe (receiver->class_pointer->dtable,
- (sidx)op->sel_id);
- if (result == 0)
- {
- /* Not found ... call get_implementation () to install the
- dispatch table and call +initialize as required,
- providing the method implementation or a forwarding
- function. */
- result = get_implementation (receiver, receiver->class_pointer, op);
- }
- return result;
- }
- else
- return (IMP)nil_method;
-}
-
-IMP
-objc_msg_lookup_super (struct objc_super *super, SEL sel)
-{
- if (super->self)
- return get_imp (super->super_class, sel);
- else
- return (IMP)nil_method;
-}
-
-void
-__objc_init_dispatch_tables ()
-{
- __objc_uninstalled_dtable = sarray_new (200, 0);
-
- /* TODO: It would be cool to register typed selectors here. */
- selector_resolveClassMethod = sel_registerName ("resolveClassMethod:");
- selector_resolveInstanceMethod = sel_registerName ("resolveInstanceMethod:");
-}
-
-
-/* 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)
-{
- assert (__objc_uninstalled_dtable);
- class->dtable = __objc_uninstalled_dtable;
-}
-
-/* Send +initialize to class if not already done. */
-static void
-__objc_send_initialize (Class class)
-{
- /* This *must* be a class object. */
- assert (CLS_ISCLASS (class));
- assert (! CLS_ISMETA (class));
-
- /* class_add_method_list/__objc_update_dispatch_table_for_class may
- have reset the dispatch table. The canonical way to insure that
- we send +initialize just once, is this flag. */
- if (! CLS_ISINITIALIZED (class))
- {
- DEBUG_PRINTF ("+initialize: need to initialize class '%s'\n", class->name);
- 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);
-
- {
- SEL op = sel_registerName ("initialize");
- struct objc_method *method = search_for_method_in_hierarchy (class->class_pointer,
- op);
-
- if (method)
- {
- DEBUG_PRINTF (" begin of [%s +initialize]\n", class->name);
- (*method->method_imp) ((id)class, op);
- DEBUG_PRINTF (" end of [%s +initialize]\n", class->name);
- }
-#ifdef DEBUG
- else
- {
- DEBUG_PRINTF (" class '%s' has no +initialize method\n", class->name);
- }
-#endif
- }
- }
-}
-
-/* Walk on the methods list of class and install the methods in the
- reverse order of the lists. Since methods added by categories are
- before the methods of class in the methods list, this allows
- categories to substitute methods declared in class. However if
- more than one category replaces the same method nothing is
- guaranteed about what method will be used. Assumes that
- __objc_runtime_mutex is locked down. */
-static void
-__objc_install_methods_in_dtable (struct sarray *dtable, struct objc_method_list * method_list)
-{
- int i;
-
- if (! method_list)
- return;
-
- if (method_list->method_next)
- __objc_install_methods_in_dtable (dtable, method_list->method_next);
-
- for (i = 0; i < method_list->method_count; i++)
- {
- struct objc_method * method = &(method_list->method_list[i]);
- sarray_at_put_safe (dtable,
- (sidx) method->method_name->sel_id,
- method->method_imp);
- }
-}
-
-void
-__objc_update_dispatch_table_for_class (Class class)
-{
- Class next;
- struct sarray *arr;
-
- DEBUG_PRINTF (" _objc_update_dtable_for_class (%s)\n", class->name);
-
- objc_mutex_lock (__objc_runtime_mutex);
-
- /* Not yet installed -- skip it unless in +initialize. */
- if (class->dtable == __objc_uninstalled_dtable)
- {
- if (__objc_prepared_dtable_for_class (class))
- {
- /* There is a prepared table so we must be initialising this
- class ... we must re-do the table preparation. */
- __objc_prepare_dtable_for_class (class);
- }
- objc_mutex_unlock (__objc_runtime_mutex);
- return;
- }
-
- arr = class->dtable;
- __objc_install_premature_dtable (class); /* someone might require it... */
- sarray_free (arr); /* release memory */
-
- /* Could have been lazy... */
- __objc_install_dtable_for_class (class);
-
- if (class->subclass_list) /* Traverse subclasses. */
- for (next = class->subclass_list; next; next = next->sibling_class)
- __objc_update_dispatch_table_for_class (next);
-
- objc_mutex_unlock (__objc_runtime_mutex);
-}
-
-/* This function adds a method list to a class. This function is
- typically called by another function specific to the run-time. As
- such this function does not worry about thread safe issues.
-
- 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. */
-void
-class_add_method_list (Class class, struct objc_method_list * list)
-{
- /* Passing of a linked list is not allowed. Do multiple calls. */
- assert (! list->method_next);
-
- __objc_register_selectors_from_list(list);
-
- /* Add the methods to the class's method list. */
- list->method_next = class->methods;
- class->methods = list;
-
- /* Update the dispatch table of class. */
- __objc_update_dispatch_table_for_class (class);
-}
-
-struct objc_method *
-class_getInstanceMethod (Class class_, SEL selector)
-{
- struct objc_method *m;
-
- if (class_ == Nil || selector == NULL)
- return NULL;
-
- m = search_for_method_in_hierarchy (class_, selector);
- if (m)
- return m;
-
- /* Try going through +resolveInstanceMethod:, and do the search
- again if successful. */
- if (__objc_resolve_instance_method (class_, selector))
- return search_for_method_in_hierarchy (class_, selector);
-
- return NULL;
-}
-
-struct objc_method *
-class_getClassMethod (Class class_, SEL selector)
-{
- struct objc_method *m;
-
- if (class_ == Nil || selector == NULL)
- return NULL;
-
- m = search_for_method_in_hierarchy (class_->class_pointer,
- selector);
- if (m)
- return m;
-
- /* Try going through +resolveClassMethod:, and do the search again
- if successful. */
- if (__objc_resolve_class_method (class_, selector))
- return search_for_method_in_hierarchy (class_->class_pointer,
- selector);
-
- return NULL;
-}
-
-BOOL
-class_addMethod (Class class_, SEL selector, IMP implementation,
- const char *method_types)
-{
- struct objc_method_list *method_list;
- struct objc_method *method;
- const char *method_name;
-
- if (class_ == Nil || selector == NULL || implementation == NULL
- || method_types == NULL || (strcmp (method_types, "") == 0))
- return NO;
-
- method_name = sel_getName (selector);
- if (method_name == NULL)
- return NO;
-
- /* If the method already exists in the class, return NO. It is fine
- if the method already exists in the superclass; in that case, we
- are overriding it. */
- if (CLS_IS_IN_CONSTRUCTION (class_))
- {
- /* The class only contains a list of methods; they have not been
- registered yet, ie, the method_name of each of them is still
- a string, not a selector. Iterate manually over them to
- check if we have already added the method. */
- struct objc_method_list * method_list = class_->methods;
- while (method_list)
- {
- int i;
-
- /* Search the method list. */
- for (i = 0; i < method_list->method_count; ++i)
- {
- struct objc_method * method = &method_list->method_list[i];
-
- if (method->method_name
- && strcmp ((char *)method->method_name, method_name) == 0)
- return NO;
- }
-
- /* The method wasn't found. Follow the link to the next list of
- methods. */
- method_list = method_list->method_next;
- }
- /* The method wasn't found. It's a new one. Go ahead and add
- it. */
- }
- else
- {
- /* Do the standard lookup. This assumes the selectors are
- mapped. */
- if (search_for_method_in_list (class_->methods, selector))
- return NO;
- }
-
- method_list = (struct objc_method_list *)objc_calloc (1, sizeof (struct objc_method_list));
- method_list->method_count = 1;
-
- method = &(method_list->method_list[0]);
- method->method_name = objc_malloc (strlen (method_name) + 1);
- strcpy ((char *)method->method_name, method_name);
-
- method->method_types = objc_malloc (strlen (method_types) + 1);
- strcpy ((char *)method->method_types, method_types);
-
- method->method_imp = implementation;
-
- if (CLS_IS_IN_CONSTRUCTION (class_))
- {
- /* We only need to add the method to the list. It will be
- registered with the runtime when the class pair is registered
- (if ever). */
- method_list->method_next = class_->methods;
- class_->methods = method_list;
- }
- else
- {
- /* Add the method to a live class. */
- objc_mutex_lock (__objc_runtime_mutex);
- class_add_method_list (class_, method_list);
- objc_mutex_unlock (__objc_runtime_mutex);
- }
-
- return YES;
-}
-
-IMP
-class_replaceMethod (Class class_, SEL selector, IMP implementation,
- const char *method_types)
-{
- struct objc_method * method;
-
- if (class_ == Nil || selector == NULL || implementation == NULL
- || method_types == NULL)
- return NULL;
-
- method = search_for_method_in_hierarchy (class_, selector);
-
- if (method)
- {
- return method_setImplementation (method, implementation);
- }
- else
- {
- class_addMethod (class_, selector, implementation, method_types);
- return NULL;
- }
-}
-
-/* Search for a method starting from the current class up its
- hierarchy. Return a pointer to the method's method structure if
- found. NULL otherwise. */
-static struct objc_method *
-search_for_method_in_hierarchy (Class cls, SEL sel)
-{
- struct objc_method * method = NULL;
- Class class;
-
- if (! sel_is_mapped (sel))
- return NULL;
-
- /* Scan the method list of the class. If the method isn't found in
- the list then step to its super class. */
- for (class = cls; ((! method) && class); class = class->super_class)
- method = search_for_method_in_list (class->methods, sel);
-
- return method;
-}
-
-
-
-/* Given a linked list of method and a method's name. Search for the
- named method's method structure. Return a pointer to the method's
- method structure if found. NULL otherwise. */
-struct objc_method *
-search_for_method_in_list (struct objc_method_list * list, SEL op)
-{
- struct objc_method_list * method_list = list;
-
- if (! sel_is_mapped (op))
- return NULL;
-
- /* If not found then we'll search the list. */
- while (method_list)
- {
- int i;
-
- /* Search the method list. */
- for (i = 0; i < method_list->method_count; ++i)
- {
- struct objc_method * method = &method_list->method_list[i];
-
- if (method->method_name)
- if (method->method_name->sel_id == op->sel_id)
- return method;
- }
-
- /* The method wasn't found. Follow the link to the next list of
- methods. */
- method_list = method_list->method_next;
- }
-
- return NULL;
-}
-
-typedef void * retval_t;
-typedef void * arglist_t;
-
-static retval_t __objc_forward (id object, SEL sel, arglist_t args);
-
-/* Forwarding pointers/integers through the normal registers. */
-static id
-__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;
-}
-
-/* Specific routine for forwarding floats/double because of
- architectural differences on some processors. i386s for example
- which uses a floating point stack versus general registers for
- floating point numbers. This forward routine makes sure that GCC
- restores the proper return values. */
-static double
-__objc_double_forward (id rcv, SEL op, ...)
-{
- void *args, *res;
-
- args = __builtin_apply_args ();
- res = __objc_forward (rcv, op, args);
- __builtin_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);
- else
-#if INVISIBLE_STRUCT_RETURN
- return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}};
-#else
- return nil;
-#endif
-}
-
-
-/* This function is called for methods which are not implemented,
- unless a custom forwarding routine has been installed. Please note
- that most serious users of libobjc (eg, GNUstep base) do install
- their own forwarding routines, and hence this is never actually
- used. But, if no custom forwarding routine is installed, this is
- called when a selector is not recognized. */
-static retval_t
-__objc_forward (id object, SEL sel, arglist_t args)
-{
- IMP imp;
- static SEL frwd_sel = 0; /* !T:SAFE2 */
- SEL err_sel;
-
- /* First try if the object understands forward::. */
- if (! frwd_sel)
- frwd_sel = sel_get_any_uid ("forward::");
-
- if (__objc_responds_to (object, frwd_sel))
- {
- imp = get_implementation (object, 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_any_uid ("doesNotRecognize:");
- if (__objc_responds_to (object, err_sel))
- {
- imp = get_implementation (object, 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 ((const char *) sel_getName (sel))
- + strlen ((const char *) object->class_pointer->name)];
-
- sprintf (msg, "(%s) %s does not recognize %s",
- (CLS_ISMETA (object->class_pointer)
- ? "class"
- : "instance" ),
- object->class_pointer->name, sel_getName (sel));
-
- /* The object doesn't respond to doesNotRecognize:. Therefore, a
- default action is taken. */
- _objc_abort ("%s\n", msg);
-
- return 0;
- }
-}
-
-void
-__objc_print_dtable_stats (void)
-{
- int total = 0;
-
- objc_mutex_lock (__objc_runtime_mutex);
-
-#ifdef OBJC_SPARSE2
- printf ("memory usage: (%s)\n", "2-level sparse arrays");
-#else
- printf ("memory usage: (%s)\n", "3-level sparse arrays");
-#endif
-
- 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);
-}
-
-static cache_ptr prepared_dtable_table = 0;
-
-/* This function is called by: objc_msg_lookup, get_imp and
- __objc_responds_to (and the dispatch table installation functions
- themselves) to install a dispatch table for a class.
-
- If CLS is a class, it installs instance methods.
- If CLS is a meta class, it installs class methods.
-
- In either case +initialize is invoked for the corresponding class.
-
- The implementation must insure that the dispatch table is not
- installed until +initialize completes. Otherwise it opens a
- potential race since the installation of the dispatch table is used
- as gate in regular method dispatch and we need to guarantee that
- +initialize is the first method invoked an that no other thread my
- dispatch messages to the class before +initialize completes. */
-static void
-__objc_install_dtable_for_class (Class cls)
-{
- /* If the class has not yet had its class links resolved, we must
- re-compute all class links. */
- if (! CLS_ISRESOLV (cls))
- __objc_resolve_class_links ();
-
- /* Make sure the super class has its dispatch table installed or is
- at least preparing. We do not need to send initialize for the
- super class since __objc_send_initialize will insure that. */
- if (cls->super_class
- && cls->super_class->dtable == __objc_uninstalled_dtable
- && !__objc_prepared_dtable_for_class (cls->super_class))
- {
- __objc_install_dtable_for_class (cls->super_class);
- /* The superclass initialisation may have also initialised the
- current class, in which case there is no more to do. */
- if (cls->dtable != __objc_uninstalled_dtable)
- return;
- }
-
- /* We have already been prepared but +initialize hasn't completed.
- The +initialize implementation is probably sending 'self'
- messages. We rely on _objc_get_prepared_imp to retrieve the
- implementation pointers. */
- if (__objc_prepared_dtable_for_class (cls))
- return;
-
- /* We have this function cache the implementation pointers for
- _objc_get_prepared_imp but the dispatch table won't be initilized
- until __objc_send_initialize completes. */
- __objc_prepare_dtable_for_class (cls);
-
- /* We may have already invoked +initialize but
- __objc_update_dispatch_table_for_class invoked by
- class_add_method_list may have reset dispatch table. */
-
- /* Call +initialize. If we are a real class, we are installing
- instance methods. If we are a meta class, we are installing
- class methods. The __objc_send_initialize itself will insure
- that the message is called only once per class. */
- if (CLS_ISCLASS (cls))
- __objc_send_initialize (cls);
- else
- {
- /* Retrieve the class from the meta class. */
- Class c = objc_getClass (cls->name);
- assert (CLS_ISMETA (cls));
- assert (c);
- __objc_send_initialize (c);
- }
-
- /* We install the dispatch table correctly when +initialize completed. */
- __objc_install_prepared_dtable_for_class (cls);
-}
-
-/* Builds the dispatch table for the class CLS and stores it in a
- place where it can be retrieved by __objc_get_prepared_imp until
- __objc_install_prepared_dtable_for_class installs it into the
- class. The dispatch table should not be installed into the class
- until +initialize has completed. */
-static void
-__objc_prepare_dtable_for_class (Class cls)
-{
- struct sarray *dtable;
- struct sarray *super_dtable;
-
- /* This table could be initialized in init.c. We can not use the
- class name since the class maintains the instance methods and the
- meta class maintains the the class methods yet both share the
- same name. Classes should be unique in any program. */
- if (! prepared_dtable_table)
- prepared_dtable_table
- = objc_hash_new (32,
- (hash_func_type) objc_hash_ptr,
- (compare_func_type) objc_compare_ptrs);
-
- /* If the class has not yet had its class links resolved, we must
- re-compute all class links. */
- if (! CLS_ISRESOLV (cls))
- __objc_resolve_class_links ();
-
- assert (cls);
- assert (cls->dtable == __objc_uninstalled_dtable);
-
- /* If there is already a prepared dtable for this class, we must
- replace it with a new version (since there must have been methods
- added to or otherwise modified in the class while executing
- +initialize, and the table needs to be recomputed. */
- dtable = __objc_prepared_dtable_for_class (cls);
- if (dtable != 0)
- {
- objc_hash_remove (prepared_dtable_table, cls);
- sarray_free (dtable);
- }
-
- /* Now prepare the dtable for population. */
- assert (cls != cls->super_class);
- if (cls->super_class)
- {
- /* Inherit the method list from the super class. Yet the super
- class may still be initializing in the case when a class
- cluster sub class initializes its super classes. */
- if (cls->super_class->dtable == __objc_uninstalled_dtable)
- __objc_install_dtable_for_class (cls->super_class);
-
- super_dtable = cls->super_class->dtable;
- /* If the dispatch table is not yet installed, we are still in
- the process of executing +initialize. Yet the dispatch table
- should be available. */
- if (super_dtable == __objc_uninstalled_dtable)
- super_dtable = __objc_prepared_dtable_for_class (cls->super_class);
-
- assert (super_dtable);
- dtable = sarray_lazy_copy (super_dtable);
- }
- else
- dtable = sarray_new (__objc_selector_max_index, 0);
-
- __objc_install_methods_in_dtable (dtable, cls->methods);
-
- objc_hash_add (&prepared_dtable_table,
- cls,
- dtable);
-}
-
-/* This wrapper only exists to allow an easy replacement of the lookup
- implementation and it is expected that the compiler will optimize
- it away. */
-static struct sarray *
-__objc_prepared_dtable_for_class (Class cls)
-{
- struct sarray *dtable = 0;
- assert (cls);
- if (prepared_dtable_table)
- dtable = objc_hash_value_for_key (prepared_dtable_table, cls);
- /* dtable my be nil, since we call this to check whether we are
- currently preparing before we start preparing. */
- return dtable;
-}
-
-/* Helper function for messages sent to CLS or implementation pointers
- retrieved from CLS during +initialize before the dtable is
- installed. When a class implicitly initializes another class which
- in turn implicitly invokes methods in this class, before the
- implementation of +initialize of CLS completes, this returns the
- expected implementation. Forwarding remains the responsibility of
- objc_msg_lookup. This function should only be called under the
- global lock. */
-static IMP
-__objc_get_prepared_imp (Class cls,SEL sel)
-{
- struct sarray *dtable;
- IMP imp;
-
- assert (cls);
- assert (sel);
- assert (cls->dtable == __objc_uninstalled_dtable);
- dtable = __objc_prepared_dtable_for_class (cls);
-
- assert (dtable);
- assert (dtable != __objc_uninstalled_dtable);
- imp = sarray_get_safe (dtable, (size_t) sel->sel_id);
-
- /* imp may be Nil if the method does not exist and we may fallback
- to the forwarding implementation later. */
- return imp;
-}
-
-/* When this function is called +initialize should be completed. So
- now we are safe to install the dispatch table for the class so that
- they become available for other threads that may be waiting in the
- lock. */
-static void
-__objc_install_prepared_dtable_for_class (Class cls)
-{
- assert (cls);
- assert (cls->dtable == __objc_uninstalled_dtable);
- cls->dtable = __objc_prepared_dtable_for_class (cls);
-
- assert (cls->dtable);
- assert (cls->dtable != __objc_uninstalled_dtable);
- objc_hash_remove (prepared_dtable_table, cls);
-}