xref: /dflybsd-src/contrib/gcc-4.7/libobjc/sendmsg.c (revision 4baf3da673cf4ccc37972fd7a3a5374f2f949682)
1e4b17023SJohn Marino /* GNU Objective C Runtime message lookup
2e4b17023SJohn Marino    Copyright (C) 1993, 1995, 1996, 1997, 1998,
3e4b17023SJohn Marino    2001, 2002, 2004, 2009, 2010 Free Software Foundation, Inc.
4e4b17023SJohn Marino    Contributed by Kresten Krab Thorup
5e4b17023SJohn Marino 
6e4b17023SJohn Marino This file is part of GCC.
7e4b17023SJohn Marino 
8e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it under the
9e4b17023SJohn Marino terms of the GNU General Public License as published by the Free Software
10e4b17023SJohn Marino Foundation; either version 3, or (at your option) any later version.
11e4b17023SJohn Marino 
12e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13e4b17023SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14e4b17023SJohn Marino FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
15e4b17023SJohn Marino details.
16e4b17023SJohn Marino 
17e4b17023SJohn Marino Under Section 7 of GPL version 3, you are granted additional
18e4b17023SJohn Marino permissions described in the GCC Runtime Library Exception, version
19e4b17023SJohn Marino 3.1, as published by the Free Software Foundation.
20e4b17023SJohn Marino 
21e4b17023SJohn Marino You should have received a copy of the GNU General Public License and
22e4b17023SJohn Marino a copy of the GCC Runtime Library Exception along with this program;
23e4b17023SJohn Marino see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24e4b17023SJohn Marino <http://www.gnu.org/licenses/>.  */
25e4b17023SJohn Marino 
26e4b17023SJohn Marino /* Uncommented the following line to enable debug logging.  Use this
27e4b17023SJohn Marino    only while debugging the runtime.  */
28e4b17023SJohn Marino /* #define DEBUG 1 */
29e4b17023SJohn Marino 
30e4b17023SJohn Marino /* FIXME: This file has no business including tm.h.  */
31e4b17023SJohn Marino /* FIXME: This should be using libffi instead of __builtin_apply
32e4b17023SJohn Marino    and friends.  */
33e4b17023SJohn Marino 
34e4b17023SJohn Marino #include "objc-private/common.h"
35e4b17023SJohn Marino #include "objc-private/error.h"
36e4b17023SJohn Marino #include "tconfig.h"
37e4b17023SJohn Marino #include "coretypes.h"
38e4b17023SJohn Marino #include "tm.h"
39e4b17023SJohn Marino #include "objc/runtime.h"
40e4b17023SJohn Marino #include "objc/message.h"          /* For objc_msg_lookup(), objc_msg_lookup_super().  */
41e4b17023SJohn Marino #include "objc/thr.h"
42e4b17023SJohn Marino #include "objc-private/module-abi-8.h"
43e4b17023SJohn Marino #include "objc-private/runtime.h"
44e4b17023SJohn Marino #include "objc-private/hash.h"
45e4b17023SJohn Marino #include "objc-private/sarray.h"
46e4b17023SJohn Marino #include "objc-private/selector.h" /* For sel_is_mapped() */
47e4b17023SJohn Marino #include "runtime-info.h"
48e4b17023SJohn Marino #include <assert.h> /* For assert */
49e4b17023SJohn Marino #include <string.h> /* For strlen */
50e4b17023SJohn Marino 
51e4b17023SJohn Marino /* This is how we hack STRUCT_VALUE to be 1 or 0.   */
52e4b17023SJohn Marino #define gen_rtx(args...) 1
53e4b17023SJohn Marino #define gen_rtx_MEM(args...) 1
54e4b17023SJohn Marino #define gen_rtx_REG(args...) 1
55e4b17023SJohn Marino /* Already defined in gcc/coretypes.h. So prevent double definition warning.  */
56e4b17023SJohn Marino #undef rtx
57e4b17023SJohn Marino #define rtx int
58e4b17023SJohn Marino 
59e4b17023SJohn Marino #if ! defined (STRUCT_VALUE) || STRUCT_VALUE == 0
60e4b17023SJohn Marino #define INVISIBLE_STRUCT_RETURN 1
61e4b17023SJohn Marino #else
62e4b17023SJohn Marino #define INVISIBLE_STRUCT_RETURN 0
63e4b17023SJohn Marino #endif
64e4b17023SJohn Marino 
65e4b17023SJohn Marino /* The uninstalled dispatch table.  If a class' dispatch table points
66e4b17023SJohn Marino    to __objc_uninstalled_dtable then that means it needs its dispatch
67e4b17023SJohn Marino    table to be installed.  */
68e4b17023SJohn Marino struct sarray *__objc_uninstalled_dtable = 0;   /* !T:MUTEX */
69e4b17023SJohn Marino 
70e4b17023SJohn Marino /* Two hooks for method forwarding. If either is set, it is invoked to
71e4b17023SJohn Marino  * return a function that performs the real forwarding.  If both are
72e4b17023SJohn Marino  * set, the result of __objc_msg_forward2 will be preferred over that
73e4b17023SJohn Marino  * of __objc_msg_forward.  If both return NULL or are unset, the
74e4b17023SJohn Marino  * libgcc based functions (__builtin_apply and friends) are used.  */
75e4b17023SJohn Marino IMP (*__objc_msg_forward) (SEL) = NULL;
76e4b17023SJohn Marino IMP (*__objc_msg_forward2) (id, SEL) = NULL;
77e4b17023SJohn Marino 
78e4b17023SJohn Marino /* Send +initialize to class.  */
79e4b17023SJohn Marino static void __objc_send_initialize (Class);
80e4b17023SJohn Marino 
81e4b17023SJohn Marino /* Forward declare some functions */
82e4b17023SJohn Marino static void __objc_install_dtable_for_class (Class cls);
83e4b17023SJohn Marino static void __objc_prepare_dtable_for_class (Class cls);
84e4b17023SJohn Marino static void __objc_install_prepared_dtable_for_class (Class cls);
85e4b17023SJohn Marino 
86e4b17023SJohn Marino static struct sarray *__objc_prepared_dtable_for_class (Class cls);
87e4b17023SJohn Marino static IMP __objc_get_prepared_imp (Class cls,SEL sel);
88e4b17023SJohn Marino 
89e4b17023SJohn Marino 
90e4b17023SJohn Marino /* Various forwarding functions that are used based upon the
91e4b17023SJohn Marino    return type for the selector.
92e4b17023SJohn Marino    __objc_block_forward for structures.
93e4b17023SJohn Marino    __objc_double_forward for floats/doubles.
94e4b17023SJohn Marino    __objc_word_forward for pointers or types that fit in registers.  */
95e4b17023SJohn Marino static double __objc_double_forward (id, SEL, ...);
96e4b17023SJohn Marino static id __objc_word_forward (id, SEL, ...);
97e4b17023SJohn Marino typedef struct { id many[8]; } __big;
98e4b17023SJohn Marino #if INVISIBLE_STRUCT_RETURN
99e4b17023SJohn Marino static __big
100e4b17023SJohn Marino #else
101e4b17023SJohn Marino static id
102e4b17023SJohn Marino #endif
103e4b17023SJohn Marino __objc_block_forward (id, SEL, ...);
104e4b17023SJohn Marino static struct objc_method * search_for_method_in_hierarchy (Class class, SEL sel);
105e4b17023SJohn Marino struct objc_method * search_for_method_in_list (struct objc_method_list * list, SEL op);
106e4b17023SJohn Marino id nil_method (id, SEL);
107e4b17023SJohn Marino 
108*4baf3da6Szrj /* Make sure this inline function is exported regardless of GNU89 or C99
109*4baf3da6Szrj    inlining semantics as it is part of the libobjc ABI.  */
110*4baf3da6Szrj extern IMP __objc_get_forward_imp (id, SEL);
111*4baf3da6Szrj 
112e4b17023SJohn Marino /* Given a selector, return the proper forwarding implementation.  */
113e4b17023SJohn Marino inline
114e4b17023SJohn Marino IMP
__objc_get_forward_imp(id rcv,SEL sel)115e4b17023SJohn Marino __objc_get_forward_imp (id rcv, SEL sel)
116e4b17023SJohn Marino {
117e4b17023SJohn Marino   /* If a custom forwarding hook was registered, try getting a
118e4b17023SJohn Marino      forwarding function from it. There are two forward routine hooks,
119e4b17023SJohn Marino      one that takes the receiver as an argument and one that does
120e4b17023SJohn Marino      not.  */
121e4b17023SJohn Marino   if (__objc_msg_forward2)
122e4b17023SJohn Marino     {
123e4b17023SJohn Marino       IMP result;
124e4b17023SJohn Marino       if ((result = __objc_msg_forward2 (rcv, sel)) != NULL)
125e4b17023SJohn Marino        return result;
126e4b17023SJohn Marino     }
127e4b17023SJohn Marino   if (__objc_msg_forward)
128e4b17023SJohn Marino     {
129e4b17023SJohn Marino       IMP result;
130e4b17023SJohn Marino       if ((result = __objc_msg_forward (sel)) != NULL)
131e4b17023SJohn Marino 	return result;
132e4b17023SJohn Marino     }
133e4b17023SJohn Marino 
134e4b17023SJohn Marino   /* In all other cases, use the default forwarding functions built
135e4b17023SJohn Marino      using __builtin_apply and friends.  */
136e4b17023SJohn Marino     {
137e4b17023SJohn Marino       const char *t = sel->sel_types;
138e4b17023SJohn Marino 
139e4b17023SJohn Marino       if (t && (*t == '[' || *t == '(' || *t == '{')
140e4b17023SJohn Marino #ifdef OBJC_MAX_STRUCT_BY_VALUE
141e4b17023SJohn Marino           && objc_sizeof_type (t) > OBJC_MAX_STRUCT_BY_VALUE
142e4b17023SJohn Marino #endif
143e4b17023SJohn Marino           )
144e4b17023SJohn Marino         return (IMP)__objc_block_forward;
145e4b17023SJohn Marino       else if (t && (*t == 'f' || *t == 'd'))
146e4b17023SJohn Marino         return (IMP)__objc_double_forward;
147e4b17023SJohn Marino       else
148e4b17023SJohn Marino         return (IMP)__objc_word_forward;
149e4b17023SJohn Marino     }
150e4b17023SJohn Marino }
151e4b17023SJohn Marino 
152e4b17023SJohn Marino /* Selectors for +resolveClassMethod: and +resolveInstanceMethod:.
153e4b17023SJohn Marino    These are set up at startup.  */
154e4b17023SJohn Marino static SEL selector_resolveClassMethod = NULL;
155e4b17023SJohn Marino static SEL selector_resolveInstanceMethod = NULL;
156e4b17023SJohn Marino 
157e4b17023SJohn Marino /* Internal routines use to resolve a class method using
158e4b17023SJohn Marino    +resolveClassMethod:.  'class' is always a non-Nil class (*not* a
159e4b17023SJohn Marino    meta-class), and 'sel' is the selector that we are trying to
160e4b17023SJohn Marino    resolve.  This must be called when class is not Nil, and the
161e4b17023SJohn Marino    dispatch table for class methods has already been installed.
162e4b17023SJohn Marino 
163e4b17023SJohn Marino    This routine tries to call +resolveClassMethod: to give an
164e4b17023SJohn Marino    opportunity to resolve the method.  If +resolveClassMethod: returns
165e4b17023SJohn Marino    YES, it tries looking up the method again, and if found, it returns
166e4b17023SJohn Marino    it.  Else, it returns NULL.  */
167e4b17023SJohn Marino static inline
168e4b17023SJohn Marino IMP
__objc_resolve_class_method(Class class,SEL sel)169e4b17023SJohn Marino __objc_resolve_class_method (Class class, SEL sel)
170e4b17023SJohn Marino {
171e4b17023SJohn Marino   /* We need to lookup +resolveClassMethod:.  */
172e4b17023SJohn Marino   BOOL (*resolveMethodIMP) (id, SEL, SEL);
173e4b17023SJohn Marino 
174e4b17023SJohn Marino   /* The dispatch table for class methods is already installed and we
175e4b17023SJohn Marino      don't want any forwarding to happen when looking up this method,
176e4b17023SJohn Marino      so we just look it up directly.  Note that if 'sel' is precisely
177e4b17023SJohn Marino      +resolveClassMethod:, this would look it up yet again and find
178e4b17023SJohn Marino      nothing.  That's no problem and there's no recursion.  */
179e4b17023SJohn Marino   resolveMethodIMP = (BOOL (*) (id, SEL, SEL))sarray_get_safe
180e4b17023SJohn Marino     (class->class_pointer->dtable, (size_t) selector_resolveClassMethod->sel_id);
181e4b17023SJohn Marino 
182e4b17023SJohn Marino   if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveClassMethod, sel))
183e4b17023SJohn Marino     {
184e4b17023SJohn Marino       /* +resolveClassMethod: returned YES.  Look the method up again.
185e4b17023SJohn Marino 	 We already know the dtable is installed.  */
186e4b17023SJohn Marino 
187e4b17023SJohn Marino       /* TODO: There is the case where +resolveClassMethod: is buggy
188e4b17023SJohn Marino 	 and returned YES without actually adding the method.  We
189e4b17023SJohn Marino 	 could maybe print an error message.  */
190e4b17023SJohn Marino       return sarray_get_safe (class->class_pointer->dtable, (size_t) sel->sel_id);
191e4b17023SJohn Marino     }
192e4b17023SJohn Marino 
193e4b17023SJohn Marino   return NULL;
194e4b17023SJohn Marino }
195e4b17023SJohn Marino 
196e4b17023SJohn Marino /* Internal routines use to resolve a instance method using
197e4b17023SJohn Marino    +resolveInstanceMethod:.  'class' is always a non-Nil class, and
198e4b17023SJohn Marino    'sel' is the selector that we are trying to resolve.  This must be
199e4b17023SJohn Marino    called when class is not Nil, and the dispatch table for instance
200e4b17023SJohn Marino    methods has already been installed.
201e4b17023SJohn Marino 
202e4b17023SJohn Marino    This routine tries to call +resolveInstanceMethod: to give an
203e4b17023SJohn Marino    opportunity to resolve the method.  If +resolveInstanceMethod:
204e4b17023SJohn Marino    returns YES, it tries looking up the method again, and if found, it
205e4b17023SJohn Marino    returns it.  Else, it returns NULL.  */
206e4b17023SJohn Marino static inline
207e4b17023SJohn Marino IMP
__objc_resolve_instance_method(Class class,SEL sel)208e4b17023SJohn Marino __objc_resolve_instance_method (Class class, SEL sel)
209e4b17023SJohn Marino {
210e4b17023SJohn Marino   /* We need to lookup +resolveInstanceMethod:.  */
211e4b17023SJohn Marino   BOOL (*resolveMethodIMP) (id, SEL, SEL);
212e4b17023SJohn Marino 
213e4b17023SJohn Marino   /* The dispatch table for class methods may not be already installed
214e4b17023SJohn Marino      so we have to install it if needed.  */
215e4b17023SJohn Marino   resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable,
216e4b17023SJohn Marino 				      (size_t) selector_resolveInstanceMethod->sel_id);
217e4b17023SJohn Marino   if (resolveMethodIMP == 0)
218e4b17023SJohn Marino     {
219e4b17023SJohn Marino       /* Try again after installing the dtable.  */
220e4b17023SJohn Marino       if (class->class_pointer->dtable == __objc_uninstalled_dtable)
221e4b17023SJohn Marino 	{
222e4b17023SJohn Marino 	  objc_mutex_lock (__objc_runtime_mutex);
223e4b17023SJohn Marino 	  if (class->class_pointer->dtable == __objc_uninstalled_dtable)
224e4b17023SJohn Marino 	    __objc_install_dtable_for_class (class->class_pointer);
225e4b17023SJohn Marino 	  objc_mutex_unlock (__objc_runtime_mutex);
226e4b17023SJohn Marino 	}
227e4b17023SJohn Marino       resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable,
228e4b17023SJohn Marino 					  (size_t) selector_resolveInstanceMethod->sel_id);
229e4b17023SJohn Marino     }
230e4b17023SJohn Marino 
231e4b17023SJohn Marino   if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveInstanceMethod, sel))
232e4b17023SJohn Marino     {
233e4b17023SJohn Marino       /* +resolveInstanceMethod: returned YES.  Look the method up
234e4b17023SJohn Marino 	 again.  We already know the dtable is installed.  */
235e4b17023SJohn Marino 
236e4b17023SJohn Marino       /* TODO: There is the case where +resolveInstanceMethod: is
237e4b17023SJohn Marino 	 buggy and returned YES without actually adding the method.
238e4b17023SJohn Marino 	 We could maybe print an error message.  */
239e4b17023SJohn Marino       return sarray_get_safe (class->dtable, (size_t) sel->sel_id);
240e4b17023SJohn Marino     }
241e4b17023SJohn Marino 
242e4b17023SJohn Marino   return NULL;
243e4b17023SJohn Marino }
244e4b17023SJohn Marino 
245e4b17023SJohn Marino /* Given a CLASS and selector, return the implementation corresponding
246e4b17023SJohn Marino    to the method of the selector.
247e4b17023SJohn Marino 
248e4b17023SJohn Marino    If CLASS is a class, the instance method is returned.
249e4b17023SJohn Marino    If CLASS is a meta class, the class method is returned.
250e4b17023SJohn Marino 
251e4b17023SJohn Marino    Since this requires the dispatch table to be installed, this function
252e4b17023SJohn Marino    will implicitly invoke +initialize for CLASS if it hasn't been
253e4b17023SJohn Marino    invoked yet.  This also insures that +initialize has been invoked
254e4b17023SJohn Marino    when the returned implementation is called directly.
255e4b17023SJohn Marino 
256e4b17023SJohn Marino    The forwarding hooks require the receiver as an argument (if they are to
257e4b17023SJohn Marino    perform dynamic lookup in proxy objects etc), so this function has a
258e4b17023SJohn Marino    receiver argument to be used with those hooks.  */
259e4b17023SJohn Marino static inline
260e4b17023SJohn Marino IMP
get_implementation(id receiver,Class class,SEL sel)261e4b17023SJohn Marino get_implementation (id receiver, Class class, SEL sel)
262e4b17023SJohn Marino {
263e4b17023SJohn Marino   void *res;
264e4b17023SJohn Marino 
265e4b17023SJohn Marino   if (class->dtable == __objc_uninstalled_dtable)
266e4b17023SJohn Marino     {
267e4b17023SJohn Marino       /* The dispatch table needs to be installed.  */
268e4b17023SJohn Marino       objc_mutex_lock (__objc_runtime_mutex);
269e4b17023SJohn Marino 
270e4b17023SJohn Marino       /* Double-checked locking pattern: Check
271e4b17023SJohn Marino 	 __objc_uninstalled_dtable again in case another thread
272e4b17023SJohn Marino 	 installed the dtable while we were waiting for the lock to be
273e4b17023SJohn Marino 	 released.  */
274e4b17023SJohn Marino       if (class->dtable == __objc_uninstalled_dtable)
275e4b17023SJohn Marino 	__objc_install_dtable_for_class (class);
276e4b17023SJohn Marino 
277e4b17023SJohn Marino       /* If the dispatch table is not yet installed, we are still in
278e4b17023SJohn Marino 	 the process of executing +initialize.  But the implementation
279e4b17023SJohn Marino 	 pointer should be available in the prepared ispatch table if
280e4b17023SJohn Marino 	 it exists at all.  */
281e4b17023SJohn Marino       if (class->dtable == __objc_uninstalled_dtable)
282e4b17023SJohn Marino 	{
283e4b17023SJohn Marino 	  assert (__objc_prepared_dtable_for_class (class) != 0);
284e4b17023SJohn Marino 	  res = __objc_get_prepared_imp (class, sel);
285e4b17023SJohn Marino 	}
286e4b17023SJohn Marino       else
287e4b17023SJohn Marino 	res = 0;
288e4b17023SJohn Marino 
289e4b17023SJohn Marino       objc_mutex_unlock (__objc_runtime_mutex);
290e4b17023SJohn Marino       /* Call ourselves with the installed dispatch table and get the
291e4b17023SJohn Marino 	 real method.  */
292e4b17023SJohn Marino       if (!res)
293e4b17023SJohn Marino 	res = get_implementation (receiver, class, sel);
294e4b17023SJohn Marino     }
295e4b17023SJohn Marino   else
296e4b17023SJohn Marino     {
297e4b17023SJohn Marino       /* The dispatch table has been installed.  */
298e4b17023SJohn Marino       res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
299e4b17023SJohn Marino       if (res == 0)
300e4b17023SJohn Marino 	{
301e4b17023SJohn Marino 	  /* The dispatch table has been installed, and the method is
302e4b17023SJohn Marino 	     not in the dispatch table.  So the method just doesn't
303e4b17023SJohn Marino 	     exist for the class.  */
304e4b17023SJohn Marino 
305e4b17023SJohn Marino 	  /* Try going through the +resolveClassMethod: or
306e4b17023SJohn Marino 	     +resolveInstanceMethod: process.  */
307e4b17023SJohn Marino 	  if (CLS_ISMETA (class))
308e4b17023SJohn Marino 	    {
309e4b17023SJohn Marino 	      /* We have the meta class, but we need to invoke the
310e4b17023SJohn Marino 		 +resolveClassMethod: method on the class.  So, we
311e4b17023SJohn Marino 		 need to obtain the class from the meta class, which
312e4b17023SJohn Marino 		 we do using the fact that both the class and the
313e4b17023SJohn Marino 		 meta-class have the same name.  */
314e4b17023SJohn Marino 	      Class realClass = objc_lookUpClass (class->name);
315e4b17023SJohn Marino 	      if (realClass)
316e4b17023SJohn Marino 		res = __objc_resolve_class_method (realClass, sel);
317e4b17023SJohn Marino 	    }
318e4b17023SJohn Marino 	  else
319e4b17023SJohn Marino 	    res = __objc_resolve_instance_method (class, sel);
320e4b17023SJohn Marino 
321e4b17023SJohn Marino 	  if (res == 0)
322e4b17023SJohn Marino 	    res = __objc_get_forward_imp (receiver, sel);
323e4b17023SJohn Marino 	}
324e4b17023SJohn Marino     }
325e4b17023SJohn Marino   return res;
326e4b17023SJohn Marino }
327e4b17023SJohn Marino 
328*4baf3da6Szrj /* Make sure this inline function is exported regardless of GNU89 or C99
329*4baf3da6Szrj    inlining semantics as it is part of the libobjc ABI.  */
330*4baf3da6Szrj extern IMP get_imp (Class, SEL);
331*4baf3da6Szrj 
332e4b17023SJohn Marino inline
333e4b17023SJohn Marino IMP
get_imp(Class class,SEL sel)334e4b17023SJohn Marino get_imp (Class class, SEL sel)
335e4b17023SJohn Marino {
336e4b17023SJohn Marino   /* In a vanilla implementation we would first check if the dispatch
337e4b17023SJohn Marino      table is installed.  Here instead, to get more speed in the
338e4b17023SJohn Marino      standard case (that the dispatch table is installed) we first try
339e4b17023SJohn Marino      to get the imp using brute force.  Only if that fails, we do what
340e4b17023SJohn Marino      we should have been doing from the very beginning, that is, check
341e4b17023SJohn Marino      if the dispatch table needs to be installed, install it if it's
342e4b17023SJohn Marino      not installed, and retrieve the imp from the table if it's
343e4b17023SJohn Marino      installed.  */
344e4b17023SJohn Marino   void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
345e4b17023SJohn Marino   if (res == 0)
346e4b17023SJohn Marino     {
347e4b17023SJohn Marino       res = get_implementation(nil, class, sel);
348e4b17023SJohn Marino     }
349e4b17023SJohn Marino   return res;
350e4b17023SJohn Marino }
351e4b17023SJohn Marino 
352e4b17023SJohn Marino /* The new name of get_imp().  */
353e4b17023SJohn Marino IMP
class_getMethodImplementation(Class class_,SEL selector)354e4b17023SJohn Marino class_getMethodImplementation (Class class_, SEL selector)
355e4b17023SJohn Marino {
356e4b17023SJohn Marino   if (class_ == Nil  ||  selector == NULL)
357e4b17023SJohn Marino     return NULL;
358e4b17023SJohn Marino 
359e4b17023SJohn Marino   /* get_imp is inlined, so we're good.  */
360e4b17023SJohn Marino   return get_imp (class_, selector);
361e4b17023SJohn Marino }
362e4b17023SJohn Marino 
363e4b17023SJohn Marino /* Given a method, return its implementation.  This has been replaced
364e4b17023SJohn Marino    by method_getImplementation() in the modern API.  */
365e4b17023SJohn Marino IMP
method_get_imp(struct objc_method * method)366e4b17023SJohn Marino method_get_imp (struct objc_method * method)
367e4b17023SJohn Marino {
368e4b17023SJohn Marino   return (method != (struct objc_method *)0) ? method->method_imp : (IMP)0;
369e4b17023SJohn Marino }
370e4b17023SJohn Marino 
371e4b17023SJohn Marino /* Query if an object can respond to a selector, returns YES if the
372e4b17023SJohn Marino    object implements the selector otherwise NO.  Does not check if the
373e4b17023SJohn Marino    method can be forwarded.  Since this requires the dispatch table to
374e4b17023SJohn Marino    installed, this function will implicitly invoke +initialize for the
375e4b17023SJohn Marino    class of OBJECT if it hasn't been invoked yet.  */
376e4b17023SJohn Marino inline
377e4b17023SJohn Marino BOOL
__objc_responds_to(id object,SEL sel)378e4b17023SJohn Marino __objc_responds_to (id object, SEL sel)
379e4b17023SJohn Marino {
380e4b17023SJohn Marino   void *res;
381e4b17023SJohn Marino   struct sarray *dtable;
382e4b17023SJohn Marino 
383e4b17023SJohn Marino   /* Install dispatch table if need be */
384e4b17023SJohn Marino   dtable = object->class_pointer->dtable;
385e4b17023SJohn Marino   if (dtable == __objc_uninstalled_dtable)
386e4b17023SJohn Marino     {
387e4b17023SJohn Marino       objc_mutex_lock (__objc_runtime_mutex);
388e4b17023SJohn Marino       if (object->class_pointer->dtable == __objc_uninstalled_dtable)
389e4b17023SJohn Marino         __objc_install_dtable_for_class (object->class_pointer);
390e4b17023SJohn Marino 
391e4b17023SJohn Marino       /* If the dispatch table is not yet installed, we are still in
392e4b17023SJohn Marino          the process of executing +initialize.  Yet the dispatch table
393e4b17023SJohn Marino          should be available.  */
394e4b17023SJohn Marino       if (object->class_pointer->dtable == __objc_uninstalled_dtable)
395e4b17023SJohn Marino         {
396e4b17023SJohn Marino           dtable = __objc_prepared_dtable_for_class (object->class_pointer);
397e4b17023SJohn Marino           assert (dtable);
398e4b17023SJohn Marino         }
399e4b17023SJohn Marino       else
400e4b17023SJohn Marino         dtable = object->class_pointer->dtable;
401e4b17023SJohn Marino 
402e4b17023SJohn Marino       objc_mutex_unlock (__objc_runtime_mutex);
403e4b17023SJohn Marino     }
404e4b17023SJohn Marino 
405e4b17023SJohn Marino   /* Get the method from the dispatch table.  */
406e4b17023SJohn Marino   res = sarray_get_safe (dtable, (size_t) sel->sel_id);
407e4b17023SJohn Marino   return (res != 0) ? YES : NO;
408e4b17023SJohn Marino }
409e4b17023SJohn Marino 
410e4b17023SJohn Marino BOOL
class_respondsToSelector(Class class_,SEL selector)411e4b17023SJohn Marino class_respondsToSelector (Class class_, SEL selector)
412e4b17023SJohn Marino {
413e4b17023SJohn Marino   struct sarray *dtable;
414e4b17023SJohn Marino   void *res;
415e4b17023SJohn Marino 
416e4b17023SJohn Marino   if (class_ == Nil  ||  selector == NULL)
417e4b17023SJohn Marino     return NO;
418e4b17023SJohn Marino 
419e4b17023SJohn Marino   /* Install dispatch table if need be.  */
420e4b17023SJohn Marino   dtable = class_->dtable;
421e4b17023SJohn Marino   if (dtable == __objc_uninstalled_dtable)
422e4b17023SJohn Marino     {
423e4b17023SJohn Marino       objc_mutex_lock (__objc_runtime_mutex);
424e4b17023SJohn Marino       if (class_->dtable == __objc_uninstalled_dtable)
425e4b17023SJohn Marino 	__objc_install_dtable_for_class (class_);
426e4b17023SJohn Marino 
427e4b17023SJohn Marino       /* If the dispatch table is not yet installed,
428e4b17023SJohn Marino          we are still in the process of executing +initialize.
429e4b17023SJohn Marino          Yet the dispatch table should be available.  */
430e4b17023SJohn Marino       if (class_->dtable == __objc_uninstalled_dtable)
431e4b17023SJohn Marino         {
432e4b17023SJohn Marino           dtable = __objc_prepared_dtable_for_class (class_);
433e4b17023SJohn Marino           assert (dtable);
434e4b17023SJohn Marino         }
435e4b17023SJohn Marino       else
436e4b17023SJohn Marino         dtable = class_->dtable;
437e4b17023SJohn Marino 
438e4b17023SJohn Marino       objc_mutex_unlock (__objc_runtime_mutex);
439e4b17023SJohn Marino     }
440e4b17023SJohn Marino 
441e4b17023SJohn Marino   /* Get the method from the dispatch table.  */
442e4b17023SJohn Marino   res = sarray_get_safe (dtable, (size_t) selector->sel_id);
443e4b17023SJohn Marino   return (res != 0) ? YES : NO;
444e4b17023SJohn Marino }
445e4b17023SJohn Marino 
446e4b17023SJohn Marino /* This is the lookup function.  All entries in the table are either a
447e4b17023SJohn Marino    valid method *or* zero.  If zero then either the dispatch table
448e4b17023SJohn Marino    needs to be installed or it doesn't exist and forwarding is
449e4b17023SJohn Marino    attempted.  */
450e4b17023SJohn Marino IMP
objc_msg_lookup(id receiver,SEL op)451e4b17023SJohn Marino objc_msg_lookup (id receiver, SEL op)
452e4b17023SJohn Marino {
453e4b17023SJohn Marino   IMP result;
454e4b17023SJohn Marino   if (receiver)
455e4b17023SJohn Marino     {
456e4b17023SJohn Marino       /* First try a quick lookup assuming the dispatch table exists.  */
457e4b17023SJohn Marino       result = sarray_get_safe (receiver->class_pointer->dtable,
458e4b17023SJohn Marino 				(sidx)op->sel_id);
459e4b17023SJohn Marino       if (result == 0)
460e4b17023SJohn Marino 	{
461e4b17023SJohn Marino 	  /* Not found ... call get_implementation () to install the
462e4b17023SJohn Marino              dispatch table and call +initialize as required,
463e4b17023SJohn Marino              providing the method implementation or a forwarding
464e4b17023SJohn Marino              function.  */
465e4b17023SJohn Marino 	  result = get_implementation (receiver, receiver->class_pointer, op);
466e4b17023SJohn Marino 	}
467e4b17023SJohn Marino       return result;
468e4b17023SJohn Marino     }
469e4b17023SJohn Marino   else
470e4b17023SJohn Marino     return (IMP)nil_method;
471e4b17023SJohn Marino }
472e4b17023SJohn Marino 
473e4b17023SJohn Marino IMP
objc_msg_lookup_super(struct objc_super * super,SEL sel)474e4b17023SJohn Marino objc_msg_lookup_super (struct objc_super *super, SEL sel)
475e4b17023SJohn Marino {
476e4b17023SJohn Marino   if (super->self)
477e4b17023SJohn Marino     return get_imp (super->super_class, sel);
478e4b17023SJohn Marino   else
479e4b17023SJohn Marino     return (IMP)nil_method;
480e4b17023SJohn Marino }
481e4b17023SJohn Marino 
482e4b17023SJohn Marino void
__objc_init_dispatch_tables()483e4b17023SJohn Marino __objc_init_dispatch_tables ()
484e4b17023SJohn Marino {
485e4b17023SJohn Marino   __objc_uninstalled_dtable = sarray_new (200, 0);
486e4b17023SJohn Marino 
487e4b17023SJohn Marino   /* TODO: It would be cool to register typed selectors here.  */
488e4b17023SJohn Marino   selector_resolveClassMethod = sel_registerName ("resolveClassMethod:");
489e4b17023SJohn Marino   selector_resolveInstanceMethod = sel_registerName ("resolveInstanceMethod:");
490e4b17023SJohn Marino }
491e4b17023SJohn Marino 
492e4b17023SJohn Marino 
493e4b17023SJohn Marino /* Install dummy table for class which causes the first message to
494e4b17023SJohn Marino    that class (or instances hereof) to be initialized properly.  */
495e4b17023SJohn Marino void
__objc_install_premature_dtable(Class class)496e4b17023SJohn Marino __objc_install_premature_dtable (Class class)
497e4b17023SJohn Marino {
498e4b17023SJohn Marino   assert (__objc_uninstalled_dtable);
499e4b17023SJohn Marino   class->dtable = __objc_uninstalled_dtable;
500e4b17023SJohn Marino }
501e4b17023SJohn Marino 
502e4b17023SJohn Marino /* Send +initialize to class if not already done.  */
503e4b17023SJohn Marino static void
__objc_send_initialize(Class class)504e4b17023SJohn Marino __objc_send_initialize (Class class)
505e4b17023SJohn Marino {
506e4b17023SJohn Marino   /* This *must* be a class object.  */
507e4b17023SJohn Marino   assert (CLS_ISCLASS (class));
508e4b17023SJohn Marino   assert (! CLS_ISMETA (class));
509e4b17023SJohn Marino 
510e4b17023SJohn Marino   /* class_add_method_list/__objc_update_dispatch_table_for_class may
511e4b17023SJohn Marino      have reset the dispatch table.  The canonical way to insure that
512e4b17023SJohn Marino      we send +initialize just once, is this flag.  */
513e4b17023SJohn Marino   if (! CLS_ISINITIALIZED (class))
514e4b17023SJohn Marino     {
515e4b17023SJohn Marino       DEBUG_PRINTF ("+initialize: need to initialize class '%s'\n", class->name);
516e4b17023SJohn Marino       CLS_SETINITIALIZED (class);
517e4b17023SJohn Marino       CLS_SETINITIALIZED (class->class_pointer);
518e4b17023SJohn Marino 
519e4b17023SJohn Marino       /* Create the garbage collector type memory description.  */
520e4b17023SJohn Marino       __objc_generate_gc_type_description (class);
521e4b17023SJohn Marino 
522e4b17023SJohn Marino       if (class->super_class)
523e4b17023SJohn Marino 	__objc_send_initialize (class->super_class);
524e4b17023SJohn Marino 
525e4b17023SJohn Marino       {
526e4b17023SJohn Marino 	SEL op = sel_registerName ("initialize");
527e4b17023SJohn Marino         struct objc_method *method = search_for_method_in_hierarchy (class->class_pointer,
528e4b17023SJohn Marino 								     op);
529e4b17023SJohn Marino 
530e4b17023SJohn Marino 	if (method)
531e4b17023SJohn Marino 	  {
532e4b17023SJohn Marino 	    DEBUG_PRINTF (" begin of [%s +initialize]\n", class->name);
533e4b17023SJohn Marino 	    (*method->method_imp) ((id)class, op);
534e4b17023SJohn Marino 	    DEBUG_PRINTF (" end of [%s +initialize]\n", class->name);
535e4b17023SJohn Marino 	  }
536e4b17023SJohn Marino #ifdef DEBUG
537e4b17023SJohn Marino 	else
538e4b17023SJohn Marino 	  {
539e4b17023SJohn Marino 	    DEBUG_PRINTF (" class '%s' has no +initialize method\n", class->name);
540e4b17023SJohn Marino 	  }
541e4b17023SJohn Marino #endif
542e4b17023SJohn Marino       }
543e4b17023SJohn Marino     }
544e4b17023SJohn Marino }
545e4b17023SJohn Marino 
546e4b17023SJohn Marino /* Walk on the methods list of class and install the methods in the
547e4b17023SJohn Marino    reverse order of the lists.  Since methods added by categories are
548e4b17023SJohn Marino    before the methods of class in the methods list, this allows
549e4b17023SJohn Marino    categories to substitute methods declared in class.  However if
550e4b17023SJohn Marino    more than one category replaces the same method nothing is
551e4b17023SJohn Marino    guaranteed about what method will be used.  Assumes that
552e4b17023SJohn Marino    __objc_runtime_mutex is locked down.  */
553e4b17023SJohn Marino static void
__objc_install_methods_in_dtable(struct sarray * dtable,struct objc_method_list * method_list)554e4b17023SJohn Marino __objc_install_methods_in_dtable (struct sarray *dtable, struct objc_method_list * method_list)
555e4b17023SJohn Marino {
556e4b17023SJohn Marino   int i;
557e4b17023SJohn Marino 
558e4b17023SJohn Marino   if (! method_list)
559e4b17023SJohn Marino     return;
560e4b17023SJohn Marino 
561e4b17023SJohn Marino   if (method_list->method_next)
562e4b17023SJohn Marino     __objc_install_methods_in_dtable (dtable, method_list->method_next);
563e4b17023SJohn Marino 
564e4b17023SJohn Marino   for (i = 0; i < method_list->method_count; i++)
565e4b17023SJohn Marino     {
566e4b17023SJohn Marino       struct objc_method * method = &(method_list->method_list[i]);
567e4b17023SJohn Marino       sarray_at_put_safe (dtable,
568e4b17023SJohn Marino 			  (sidx) method->method_name->sel_id,
569e4b17023SJohn Marino 			  method->method_imp);
570e4b17023SJohn Marino     }
571e4b17023SJohn Marino }
572e4b17023SJohn Marino 
573e4b17023SJohn Marino void
__objc_update_dispatch_table_for_class(Class class)574e4b17023SJohn Marino __objc_update_dispatch_table_for_class (Class class)
575e4b17023SJohn Marino {
576e4b17023SJohn Marino   Class next;
577e4b17023SJohn Marino   struct sarray *arr;
578e4b17023SJohn Marino 
579e4b17023SJohn Marino   DEBUG_PRINTF (" _objc_update_dtable_for_class (%s)\n", class->name);
580e4b17023SJohn Marino 
581e4b17023SJohn Marino   objc_mutex_lock (__objc_runtime_mutex);
582e4b17023SJohn Marino 
583e4b17023SJohn Marino   /* Not yet installed -- skip it unless in +initialize.  */
584e4b17023SJohn Marino   if (class->dtable == __objc_uninstalled_dtable)
585e4b17023SJohn Marino     {
586e4b17023SJohn Marino       if (__objc_prepared_dtable_for_class (class))
587e4b17023SJohn Marino 	{
588e4b17023SJohn Marino 	  /* There is a prepared table so we must be initialising this
589e4b17023SJohn Marino 	     class ... we must re-do the table preparation.  */
590e4b17023SJohn Marino 	  __objc_prepare_dtable_for_class (class);
591e4b17023SJohn Marino 	}
592e4b17023SJohn Marino       objc_mutex_unlock (__objc_runtime_mutex);
593e4b17023SJohn Marino       return;
594e4b17023SJohn Marino     }
595e4b17023SJohn Marino 
596e4b17023SJohn Marino   arr = class->dtable;
597e4b17023SJohn Marino   __objc_install_premature_dtable (class); /* someone might require it... */
598e4b17023SJohn Marino   sarray_free (arr);			   /* release memory */
599e4b17023SJohn Marino 
600e4b17023SJohn Marino   /* Could have been lazy...  */
601e4b17023SJohn Marino   __objc_install_dtable_for_class (class);
602e4b17023SJohn Marino 
603e4b17023SJohn Marino   if (class->subclass_list)	/* Traverse subclasses.  */
604e4b17023SJohn Marino     for (next = class->subclass_list; next; next = next->sibling_class)
605e4b17023SJohn Marino       __objc_update_dispatch_table_for_class (next);
606e4b17023SJohn Marino 
607e4b17023SJohn Marino   objc_mutex_unlock (__objc_runtime_mutex);
608e4b17023SJohn Marino }
609e4b17023SJohn Marino 
610e4b17023SJohn Marino /* This function adds a method list to a class.  This function is
611e4b17023SJohn Marino    typically called by another function specific to the run-time.  As
612e4b17023SJohn Marino    such this function does not worry about thread safe issues.
613e4b17023SJohn Marino 
614e4b17023SJohn Marino    This one is only called for categories. Class objects have their
615e4b17023SJohn Marino    methods installed right away, and their selectors are made into
616e4b17023SJohn Marino    SEL's by the function __objc_register_selectors_from_class.  */
617e4b17023SJohn Marino void
class_add_method_list(Class class,struct objc_method_list * list)618e4b17023SJohn Marino class_add_method_list (Class class, struct objc_method_list * list)
619e4b17023SJohn Marino {
620e4b17023SJohn Marino   /* Passing of a linked list is not allowed.  Do multiple calls.  */
621e4b17023SJohn Marino   assert (! list->method_next);
622e4b17023SJohn Marino 
623e4b17023SJohn Marino   __objc_register_selectors_from_list(list);
624e4b17023SJohn Marino 
625e4b17023SJohn Marino   /* Add the methods to the class's method list.  */
626e4b17023SJohn Marino   list->method_next = class->methods;
627e4b17023SJohn Marino   class->methods = list;
628e4b17023SJohn Marino 
629e4b17023SJohn Marino   /* Update the dispatch table of class.  */
630e4b17023SJohn Marino   __objc_update_dispatch_table_for_class (class);
631e4b17023SJohn Marino }
632e4b17023SJohn Marino 
633e4b17023SJohn Marino struct objc_method *
class_getInstanceMethod(Class class_,SEL selector)634e4b17023SJohn Marino class_getInstanceMethod (Class class_, SEL selector)
635e4b17023SJohn Marino {
636e4b17023SJohn Marino   struct objc_method *m;
637e4b17023SJohn Marino 
638e4b17023SJohn Marino   if (class_ == Nil  ||  selector == NULL)
639e4b17023SJohn Marino     return NULL;
640e4b17023SJohn Marino 
641e4b17023SJohn Marino   m = search_for_method_in_hierarchy (class_, selector);
642e4b17023SJohn Marino   if (m)
643e4b17023SJohn Marino     return m;
644e4b17023SJohn Marino 
645e4b17023SJohn Marino   /* Try going through +resolveInstanceMethod:, and do the search
646e4b17023SJohn Marino      again if successful.  */
647e4b17023SJohn Marino   if (__objc_resolve_instance_method (class_, selector))
648e4b17023SJohn Marino     return search_for_method_in_hierarchy (class_, selector);
649e4b17023SJohn Marino 
650e4b17023SJohn Marino   return NULL;
651e4b17023SJohn Marino }
652e4b17023SJohn Marino 
653e4b17023SJohn Marino struct objc_method *
class_getClassMethod(Class class_,SEL selector)654e4b17023SJohn Marino class_getClassMethod (Class class_, SEL selector)
655e4b17023SJohn Marino {
656e4b17023SJohn Marino   struct objc_method *m;
657e4b17023SJohn Marino 
658e4b17023SJohn Marino   if (class_ == Nil  ||  selector == NULL)
659e4b17023SJohn Marino     return NULL;
660e4b17023SJohn Marino 
661e4b17023SJohn Marino   m = search_for_method_in_hierarchy (class_->class_pointer,
662e4b17023SJohn Marino 				      selector);
663e4b17023SJohn Marino   if (m)
664e4b17023SJohn Marino     return m;
665e4b17023SJohn Marino 
666e4b17023SJohn Marino   /* Try going through +resolveClassMethod:, and do the search again
667e4b17023SJohn Marino      if successful.  */
668e4b17023SJohn Marino   if (__objc_resolve_class_method (class_, selector))
669e4b17023SJohn Marino     return search_for_method_in_hierarchy (class_->class_pointer,
670e4b17023SJohn Marino 					   selector);
671e4b17023SJohn Marino 
672e4b17023SJohn Marino   return NULL;
673e4b17023SJohn Marino }
674e4b17023SJohn Marino 
675e4b17023SJohn Marino BOOL
class_addMethod(Class class_,SEL selector,IMP implementation,const char * method_types)676e4b17023SJohn Marino class_addMethod (Class class_, SEL selector, IMP implementation,
677e4b17023SJohn Marino 		 const char *method_types)
678e4b17023SJohn Marino {
679e4b17023SJohn Marino   struct objc_method_list *method_list;
680e4b17023SJohn Marino   struct objc_method *method;
681e4b17023SJohn Marino   const char *method_name;
682e4b17023SJohn Marino 
683e4b17023SJohn Marino   if (class_ == Nil  ||  selector == NULL  ||  implementation == NULL
684e4b17023SJohn Marino       || method_types == NULL  || (strcmp (method_types, "") == 0))
685e4b17023SJohn Marino     return NO;
686e4b17023SJohn Marino 
687e4b17023SJohn Marino   method_name = sel_getName (selector);
688e4b17023SJohn Marino   if (method_name == NULL)
689e4b17023SJohn Marino     return NO;
690e4b17023SJohn Marino 
691e4b17023SJohn Marino   /* If the method already exists in the class, return NO.  It is fine
692e4b17023SJohn Marino      if the method already exists in the superclass; in that case, we
693e4b17023SJohn Marino      are overriding it.  */
694e4b17023SJohn Marino   if (CLS_IS_IN_CONSTRUCTION (class_))
695e4b17023SJohn Marino     {
696e4b17023SJohn Marino       /* The class only contains a list of methods; they have not been
697e4b17023SJohn Marino 	 registered yet, ie, the method_name of each of them is still
698e4b17023SJohn Marino 	 a string, not a selector.  Iterate manually over them to
699e4b17023SJohn Marino 	 check if we have already added the method.  */
700e4b17023SJohn Marino       struct objc_method_list * method_list = class_->methods;
701e4b17023SJohn Marino       while (method_list)
702e4b17023SJohn Marino 	{
703e4b17023SJohn Marino 	  int i;
704e4b17023SJohn Marino 
705e4b17023SJohn Marino 	  /* Search the method list.  */
706e4b17023SJohn Marino 	  for (i = 0; i < method_list->method_count; ++i)
707e4b17023SJohn Marino 	    {
708e4b17023SJohn Marino 	      struct objc_method * method = &method_list->method_list[i];
709e4b17023SJohn Marino 
710e4b17023SJohn Marino 	      if (method->method_name
711e4b17023SJohn Marino 		  && strcmp ((char *)method->method_name, method_name) == 0)
712e4b17023SJohn Marino 		return NO;
713e4b17023SJohn Marino 	    }
714e4b17023SJohn Marino 
715e4b17023SJohn Marino 	  /* The method wasn't found.  Follow the link to the next list of
716e4b17023SJohn Marino 	     methods.  */
717e4b17023SJohn Marino 	  method_list = method_list->method_next;
718e4b17023SJohn Marino 	}
719e4b17023SJohn Marino       /* The method wasn't found.  It's a new one.  Go ahead and add
720e4b17023SJohn Marino 	 it.  */
721e4b17023SJohn Marino     }
722e4b17023SJohn Marino   else
723e4b17023SJohn Marino     {
724e4b17023SJohn Marino       /* Do the standard lookup.  This assumes the selectors are
725e4b17023SJohn Marino 	 mapped.  */
726e4b17023SJohn Marino       if (search_for_method_in_list (class_->methods, selector))
727e4b17023SJohn Marino 	return NO;
728e4b17023SJohn Marino     }
729e4b17023SJohn Marino 
730e4b17023SJohn Marino   method_list = (struct objc_method_list *)objc_calloc (1, sizeof (struct objc_method_list));
731e4b17023SJohn Marino   method_list->method_count = 1;
732e4b17023SJohn Marino 
733e4b17023SJohn Marino   method = &(method_list->method_list[0]);
734e4b17023SJohn Marino   method->method_name = objc_malloc (strlen (method_name) + 1);
735e4b17023SJohn Marino   strcpy ((char *)method->method_name, method_name);
736e4b17023SJohn Marino 
737e4b17023SJohn Marino   method->method_types = objc_malloc (strlen (method_types) + 1);
738e4b17023SJohn Marino   strcpy ((char *)method->method_types, method_types);
739e4b17023SJohn Marino 
740e4b17023SJohn Marino   method->method_imp = implementation;
741e4b17023SJohn Marino 
742e4b17023SJohn Marino   if (CLS_IS_IN_CONSTRUCTION (class_))
743e4b17023SJohn Marino     {
744e4b17023SJohn Marino       /* We only need to add the method to the list.  It will be
745e4b17023SJohn Marino 	 registered with the runtime when the class pair is registered
746e4b17023SJohn Marino 	 (if ever).  */
747e4b17023SJohn Marino       method_list->method_next = class_->methods;
748e4b17023SJohn Marino       class_->methods = method_list;
749e4b17023SJohn Marino     }
750e4b17023SJohn Marino   else
751e4b17023SJohn Marino     {
752e4b17023SJohn Marino       /* Add the method to a live class.  */
753e4b17023SJohn Marino       objc_mutex_lock (__objc_runtime_mutex);
754e4b17023SJohn Marino       class_add_method_list (class_, method_list);
755e4b17023SJohn Marino       objc_mutex_unlock (__objc_runtime_mutex);
756e4b17023SJohn Marino     }
757e4b17023SJohn Marino 
758e4b17023SJohn Marino   return YES;
759e4b17023SJohn Marino }
760e4b17023SJohn Marino 
761e4b17023SJohn Marino IMP
class_replaceMethod(Class class_,SEL selector,IMP implementation,const char * method_types)762e4b17023SJohn Marino class_replaceMethod (Class class_, SEL selector, IMP implementation,
763e4b17023SJohn Marino 		     const char *method_types)
764e4b17023SJohn Marino {
765e4b17023SJohn Marino   struct objc_method * method;
766e4b17023SJohn Marino 
767e4b17023SJohn Marino   if (class_ == Nil  ||  selector == NULL  ||  implementation == NULL
768e4b17023SJohn Marino       || method_types == NULL)
769e4b17023SJohn Marino     return NULL;
770e4b17023SJohn Marino 
771e4b17023SJohn Marino   method = search_for_method_in_hierarchy (class_, selector);
772e4b17023SJohn Marino 
773e4b17023SJohn Marino   if (method)
774e4b17023SJohn Marino     {
775e4b17023SJohn Marino       return method_setImplementation (method, implementation);
776e4b17023SJohn Marino     }
777e4b17023SJohn Marino   else
778e4b17023SJohn Marino     {
779e4b17023SJohn Marino       class_addMethod (class_, selector, implementation, method_types);
780e4b17023SJohn Marino       return NULL;
781e4b17023SJohn Marino     }
782e4b17023SJohn Marino }
783e4b17023SJohn Marino 
784e4b17023SJohn Marino /* Search for a method starting from the current class up its
785e4b17023SJohn Marino    hierarchy.  Return a pointer to the method's method structure if
786e4b17023SJohn Marino    found.  NULL otherwise.  */
787e4b17023SJohn Marino static struct objc_method *
search_for_method_in_hierarchy(Class cls,SEL sel)788e4b17023SJohn Marino search_for_method_in_hierarchy (Class cls, SEL sel)
789e4b17023SJohn Marino {
790e4b17023SJohn Marino   struct objc_method * method = NULL;
791e4b17023SJohn Marino   Class class;
792e4b17023SJohn Marino 
793e4b17023SJohn Marino   if (! sel_is_mapped (sel))
794e4b17023SJohn Marino     return NULL;
795e4b17023SJohn Marino 
796e4b17023SJohn Marino   /* Scan the method list of the class.  If the method isn't found in
797e4b17023SJohn Marino      the list then step to its super class.  */
798e4b17023SJohn Marino   for (class = cls; ((! method) && class); class = class->super_class)
799e4b17023SJohn Marino     method = search_for_method_in_list (class->methods, sel);
800e4b17023SJohn Marino 
801e4b17023SJohn Marino   return method;
802e4b17023SJohn Marino }
803e4b17023SJohn Marino 
804e4b17023SJohn Marino 
805e4b17023SJohn Marino 
806e4b17023SJohn Marino /* Given a linked list of method and a method's name.  Search for the
807e4b17023SJohn Marino    named method's method structure.  Return a pointer to the method's
808e4b17023SJohn Marino    method structure if found.  NULL otherwise.  */
809e4b17023SJohn Marino struct objc_method *
search_for_method_in_list(struct objc_method_list * list,SEL op)810e4b17023SJohn Marino search_for_method_in_list (struct objc_method_list * list, SEL op)
811e4b17023SJohn Marino {
812e4b17023SJohn Marino   struct objc_method_list * method_list = list;
813e4b17023SJohn Marino 
814e4b17023SJohn Marino   if (! sel_is_mapped (op))
815e4b17023SJohn Marino     return NULL;
816e4b17023SJohn Marino 
817e4b17023SJohn Marino   /* If not found then we'll search the list.  */
818e4b17023SJohn Marino   while (method_list)
819e4b17023SJohn Marino     {
820e4b17023SJohn Marino       int i;
821e4b17023SJohn Marino 
822e4b17023SJohn Marino       /* Search the method list.  */
823e4b17023SJohn Marino       for (i = 0; i < method_list->method_count; ++i)
824e4b17023SJohn Marino         {
825e4b17023SJohn Marino           struct objc_method * method = &method_list->method_list[i];
826e4b17023SJohn Marino 
827e4b17023SJohn Marino           if (method->method_name)
828e4b17023SJohn Marino             if (method->method_name->sel_id == op->sel_id)
829e4b17023SJohn Marino               return method;
830e4b17023SJohn Marino         }
831e4b17023SJohn Marino 
832e4b17023SJohn Marino       /* The method wasn't found.  Follow the link to the next list of
833e4b17023SJohn Marino          methods.  */
834e4b17023SJohn Marino       method_list = method_list->method_next;
835e4b17023SJohn Marino     }
836e4b17023SJohn Marino 
837e4b17023SJohn Marino   return NULL;
838e4b17023SJohn Marino }
839e4b17023SJohn Marino 
840e4b17023SJohn Marino typedef void * retval_t;
841e4b17023SJohn Marino typedef void * arglist_t;
842e4b17023SJohn Marino 
843e4b17023SJohn Marino static retval_t __objc_forward (id object, SEL sel, arglist_t args);
844e4b17023SJohn Marino 
845e4b17023SJohn Marino /* Forwarding pointers/integers through the normal registers.  */
846e4b17023SJohn Marino static id
__objc_word_forward(id rcv,SEL op,...)847e4b17023SJohn Marino __objc_word_forward (id rcv, SEL op, ...)
848e4b17023SJohn Marino {
849e4b17023SJohn Marino   void *args, *res;
850e4b17023SJohn Marino 
851e4b17023SJohn Marino   args = __builtin_apply_args ();
852e4b17023SJohn Marino   res = __objc_forward (rcv, op, args);
853e4b17023SJohn Marino   if (res)
854e4b17023SJohn Marino     __builtin_return (res);
855e4b17023SJohn Marino   else
856e4b17023SJohn Marino     return res;
857e4b17023SJohn Marino }
858e4b17023SJohn Marino 
859e4b17023SJohn Marino /* Specific routine for forwarding floats/double because of
860e4b17023SJohn Marino    architectural differences on some processors.  i386s for example
861e4b17023SJohn Marino    which uses a floating point stack versus general registers for
862e4b17023SJohn Marino    floating point numbers.  This forward routine makes sure that GCC
863e4b17023SJohn Marino    restores the proper return values.  */
864e4b17023SJohn Marino static double
__objc_double_forward(id rcv,SEL op,...)865e4b17023SJohn Marino __objc_double_forward (id rcv, SEL op, ...)
866e4b17023SJohn Marino {
867e4b17023SJohn Marino   void *args, *res;
868e4b17023SJohn Marino 
869e4b17023SJohn Marino   args = __builtin_apply_args ();
870e4b17023SJohn Marino   res = __objc_forward (rcv, op, args);
871e4b17023SJohn Marino   __builtin_return (res);
872e4b17023SJohn Marino }
873e4b17023SJohn Marino 
874e4b17023SJohn Marino #if INVISIBLE_STRUCT_RETURN
875e4b17023SJohn Marino static __big
876e4b17023SJohn Marino #else
877e4b17023SJohn Marino static id
878e4b17023SJohn Marino #endif
__objc_block_forward(id rcv,SEL op,...)879e4b17023SJohn Marino __objc_block_forward (id rcv, SEL op, ...)
880e4b17023SJohn Marino {
881e4b17023SJohn Marino   void *args, *res;
882e4b17023SJohn Marino 
883e4b17023SJohn Marino   args = __builtin_apply_args ();
884e4b17023SJohn Marino   res = __objc_forward (rcv, op, args);
885e4b17023SJohn Marino   if (res)
886e4b17023SJohn Marino     __builtin_return (res);
887e4b17023SJohn Marino   else
888e4b17023SJohn Marino #if INVISIBLE_STRUCT_RETURN
889e4b17023SJohn Marino     return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}};
890e4b17023SJohn Marino #else
891e4b17023SJohn Marino     return nil;
892e4b17023SJohn Marino #endif
893e4b17023SJohn Marino }
894e4b17023SJohn Marino 
895e4b17023SJohn Marino 
896e4b17023SJohn Marino /* This function is called for methods which are not implemented,
897e4b17023SJohn Marino    unless a custom forwarding routine has been installed.  Please note
898e4b17023SJohn Marino    that most serious users of libobjc (eg, GNUstep base) do install
899e4b17023SJohn Marino    their own forwarding routines, and hence this is never actually
900e4b17023SJohn Marino    used.  But, if no custom forwarding routine is installed, this is
901e4b17023SJohn Marino    called when a selector is not recognized.  */
902e4b17023SJohn Marino static retval_t
__objc_forward(id object,SEL sel,arglist_t args)903e4b17023SJohn Marino __objc_forward (id object, SEL sel, arglist_t args)
904e4b17023SJohn Marino {
905e4b17023SJohn Marino   IMP imp;
906e4b17023SJohn Marino   static SEL frwd_sel = 0;                      /* !T:SAFE2 */
907e4b17023SJohn Marino   SEL err_sel;
908e4b17023SJohn Marino 
909e4b17023SJohn Marino   /* First try if the object understands forward::.  */
910e4b17023SJohn Marino   if (! frwd_sel)
911e4b17023SJohn Marino     frwd_sel = sel_get_any_uid ("forward::");
912e4b17023SJohn Marino 
913e4b17023SJohn Marino   if (__objc_responds_to (object, frwd_sel))
914e4b17023SJohn Marino     {
915e4b17023SJohn Marino       imp = get_implementation (object, object->class_pointer, frwd_sel);
916e4b17023SJohn Marino       return (*imp) (object, frwd_sel, sel, args);
917e4b17023SJohn Marino     }
918e4b17023SJohn Marino 
919e4b17023SJohn Marino   /* If the object recognizes the doesNotRecognize: method then we're
920e4b17023SJohn Marino      going to send it.  */
921e4b17023SJohn Marino   err_sel = sel_get_any_uid ("doesNotRecognize:");
922e4b17023SJohn Marino   if (__objc_responds_to (object, err_sel))
923e4b17023SJohn Marino     {
924e4b17023SJohn Marino       imp = get_implementation (object, object->class_pointer, err_sel);
925e4b17023SJohn Marino       return (*imp) (object, err_sel, sel);
926e4b17023SJohn Marino     }
927e4b17023SJohn Marino 
928e4b17023SJohn Marino   /* The object doesn't recognize the method.  Check for responding to
929e4b17023SJohn Marino      error:.  If it does then sent it.  */
930e4b17023SJohn Marino   {
931e4b17023SJohn Marino     char msg[256 + strlen ((const char *) sel_getName (sel))
932e4b17023SJohn Marino              + strlen ((const char *) object->class_pointer->name)];
933e4b17023SJohn Marino 
934e4b17023SJohn Marino     sprintf (msg, "(%s) %s does not recognize %s",
935e4b17023SJohn Marino 	     (CLS_ISMETA (object->class_pointer)
936e4b17023SJohn Marino 	      ? "class"
937e4b17023SJohn Marino 	      : "instance" ),
938e4b17023SJohn Marino              object->class_pointer->name, sel_getName (sel));
939e4b17023SJohn Marino 
940e4b17023SJohn Marino     /* The object doesn't respond to doesNotRecognize:.  Therefore, a
941e4b17023SJohn Marino        default action is taken.  */
942e4b17023SJohn Marino     _objc_abort ("%s\n", msg);
943e4b17023SJohn Marino 
944e4b17023SJohn Marino     return 0;
945e4b17023SJohn Marino   }
946e4b17023SJohn Marino }
947e4b17023SJohn Marino 
948e4b17023SJohn Marino void
__objc_print_dtable_stats(void)949e4b17023SJohn Marino __objc_print_dtable_stats (void)
950e4b17023SJohn Marino {
951e4b17023SJohn Marino   int total = 0;
952e4b17023SJohn Marino 
953e4b17023SJohn Marino   objc_mutex_lock (__objc_runtime_mutex);
954e4b17023SJohn Marino 
955e4b17023SJohn Marino #ifdef OBJC_SPARSE2
956e4b17023SJohn Marino   printf ("memory usage: (%s)\n", "2-level sparse arrays");
957e4b17023SJohn Marino #else
958e4b17023SJohn Marino   printf ("memory usage: (%s)\n", "3-level sparse arrays");
959e4b17023SJohn Marino #endif
960e4b17023SJohn Marino 
961e4b17023SJohn Marino   printf ("arrays: %d = %ld bytes\n", narrays,
962e4b17023SJohn Marino 	  (long) ((size_t) narrays * sizeof (struct sarray)));
963e4b17023SJohn Marino   total += narrays * sizeof (struct sarray);
964e4b17023SJohn Marino   printf ("buckets: %d = %ld bytes\n", nbuckets,
965e4b17023SJohn Marino 	  (long) ((size_t) nbuckets * sizeof (struct sbucket)));
966e4b17023SJohn Marino   total += nbuckets * sizeof (struct sbucket);
967e4b17023SJohn Marino 
968e4b17023SJohn Marino   printf ("idxtables: %d = %ld bytes\n",
969e4b17023SJohn Marino 	  idxsize, (long) ((size_t) idxsize * sizeof (void *)));
970e4b17023SJohn Marino   total += idxsize * sizeof (void *);
971e4b17023SJohn Marino   printf ("-----------------------------------\n");
972e4b17023SJohn Marino   printf ("total: %d bytes\n", total);
973e4b17023SJohn Marino   printf ("===================================\n");
974e4b17023SJohn Marino 
975e4b17023SJohn Marino   objc_mutex_unlock (__objc_runtime_mutex);
976e4b17023SJohn Marino }
977e4b17023SJohn Marino 
978e4b17023SJohn Marino static cache_ptr prepared_dtable_table = 0;
979e4b17023SJohn Marino 
980e4b17023SJohn Marino /* This function is called by: objc_msg_lookup, get_imp and
981e4b17023SJohn Marino    __objc_responds_to (and the dispatch table installation functions
982e4b17023SJohn Marino    themselves) to install a dispatch table for a class.
983e4b17023SJohn Marino 
984e4b17023SJohn Marino    If CLS is a class, it installs instance methods.
985e4b17023SJohn Marino    If CLS is a meta class, it installs class methods.
986e4b17023SJohn Marino 
987e4b17023SJohn Marino    In either case +initialize is invoked for the corresponding class.
988e4b17023SJohn Marino 
989e4b17023SJohn Marino    The implementation must insure that the dispatch table is not
990e4b17023SJohn Marino    installed until +initialize completes.  Otherwise it opens a
991e4b17023SJohn Marino    potential race since the installation of the dispatch table is used
992e4b17023SJohn Marino    as gate in regular method dispatch and we need to guarantee that
993e4b17023SJohn Marino    +initialize is the first method invoked an that no other thread my
994e4b17023SJohn Marino    dispatch messages to the class before +initialize completes.  */
995e4b17023SJohn Marino static void
__objc_install_dtable_for_class(Class cls)996e4b17023SJohn Marino __objc_install_dtable_for_class (Class cls)
997e4b17023SJohn Marino {
998e4b17023SJohn Marino   /* If the class has not yet had its class links resolved, we must
999e4b17023SJohn Marino      re-compute all class links.  */
1000e4b17023SJohn Marino   if (! CLS_ISRESOLV (cls))
1001e4b17023SJohn Marino     __objc_resolve_class_links ();
1002e4b17023SJohn Marino 
1003e4b17023SJohn Marino   /* Make sure the super class has its dispatch table installed or is
1004e4b17023SJohn Marino      at least preparing.  We do not need to send initialize for the
1005e4b17023SJohn Marino      super class since __objc_send_initialize will insure that.  */
1006e4b17023SJohn Marino   if (cls->super_class
1007e4b17023SJohn Marino       && cls->super_class->dtable == __objc_uninstalled_dtable
1008e4b17023SJohn Marino       && !__objc_prepared_dtable_for_class (cls->super_class))
1009e4b17023SJohn Marino     {
1010e4b17023SJohn Marino       __objc_install_dtable_for_class (cls->super_class);
1011e4b17023SJohn Marino       /* The superclass initialisation may have also initialised the
1012e4b17023SJohn Marino          current class, in which case there is no more to do.  */
1013e4b17023SJohn Marino       if (cls->dtable != __objc_uninstalled_dtable)
1014e4b17023SJohn Marino 	return;
1015e4b17023SJohn Marino     }
1016e4b17023SJohn Marino 
1017e4b17023SJohn Marino   /* We have already been prepared but +initialize hasn't completed.
1018e4b17023SJohn Marino      The +initialize implementation is probably sending 'self'
1019e4b17023SJohn Marino      messages.  We rely on _objc_get_prepared_imp to retrieve the
1020e4b17023SJohn Marino      implementation pointers.  */
1021e4b17023SJohn Marino   if (__objc_prepared_dtable_for_class (cls))
1022e4b17023SJohn Marino     return;
1023e4b17023SJohn Marino 
1024e4b17023SJohn Marino   /* We have this function cache the implementation pointers for
1025e4b17023SJohn Marino      _objc_get_prepared_imp but the dispatch table won't be initilized
1026e4b17023SJohn Marino      until __objc_send_initialize completes.  */
1027e4b17023SJohn Marino   __objc_prepare_dtable_for_class (cls);
1028e4b17023SJohn Marino 
1029e4b17023SJohn Marino   /* We may have already invoked +initialize but
1030e4b17023SJohn Marino      __objc_update_dispatch_table_for_class invoked by
1031e4b17023SJohn Marino      class_add_method_list may have reset dispatch table.  */
1032e4b17023SJohn Marino 
1033e4b17023SJohn Marino   /* Call +initialize.  If we are a real class, we are installing
1034e4b17023SJohn Marino      instance methods.  If we are a meta class, we are installing
1035e4b17023SJohn Marino      class methods.  The __objc_send_initialize itself will insure
1036e4b17023SJohn Marino      that the message is called only once per class.  */
1037e4b17023SJohn Marino   if (CLS_ISCLASS (cls))
1038e4b17023SJohn Marino     __objc_send_initialize (cls);
1039e4b17023SJohn Marino   else
1040e4b17023SJohn Marino     {
1041e4b17023SJohn Marino       /* Retrieve the class from the meta class.  */
1042e4b17023SJohn Marino       Class c = objc_getClass (cls->name);
1043e4b17023SJohn Marino       assert (CLS_ISMETA (cls));
1044e4b17023SJohn Marino       assert (c);
1045e4b17023SJohn Marino       __objc_send_initialize (c);
1046e4b17023SJohn Marino     }
1047e4b17023SJohn Marino 
1048e4b17023SJohn Marino   /* We install the dispatch table correctly when +initialize completed.  */
1049e4b17023SJohn Marino   __objc_install_prepared_dtable_for_class (cls);
1050e4b17023SJohn Marino }
1051e4b17023SJohn Marino 
1052e4b17023SJohn Marino /* Builds the dispatch table for the class CLS and stores it in a
1053e4b17023SJohn Marino    place where it can be retrieved by __objc_get_prepared_imp until
1054e4b17023SJohn Marino    __objc_install_prepared_dtable_for_class installs it into the
1055e4b17023SJohn Marino    class.  The dispatch table should not be installed into the class
1056e4b17023SJohn Marino    until +initialize has completed.  */
1057e4b17023SJohn Marino static void
__objc_prepare_dtable_for_class(Class cls)1058e4b17023SJohn Marino __objc_prepare_dtable_for_class (Class cls)
1059e4b17023SJohn Marino {
1060e4b17023SJohn Marino   struct sarray *dtable;
1061e4b17023SJohn Marino   struct sarray *super_dtable;
1062e4b17023SJohn Marino 
1063e4b17023SJohn Marino   /* This table could be initialized in init.c.  We can not use the
1064e4b17023SJohn Marino      class name since the class maintains the instance methods and the
1065e4b17023SJohn Marino      meta class maintains the the class methods yet both share the
1066e4b17023SJohn Marino      same name.  Classes should be unique in any program.  */
1067e4b17023SJohn Marino   if (! prepared_dtable_table)
1068e4b17023SJohn Marino     prepared_dtable_table
1069e4b17023SJohn Marino       = objc_hash_new (32,
1070e4b17023SJohn Marino 		       (hash_func_type) objc_hash_ptr,
1071e4b17023SJohn Marino 		       (compare_func_type) objc_compare_ptrs);
1072e4b17023SJohn Marino 
1073e4b17023SJohn Marino   /* If the class has not yet had its class links resolved, we must
1074e4b17023SJohn Marino      re-compute all class links.  */
1075e4b17023SJohn Marino   if (! CLS_ISRESOLV (cls))
1076e4b17023SJohn Marino     __objc_resolve_class_links ();
1077e4b17023SJohn Marino 
1078e4b17023SJohn Marino   assert (cls);
1079e4b17023SJohn Marino   assert (cls->dtable == __objc_uninstalled_dtable);
1080e4b17023SJohn Marino 
1081e4b17023SJohn Marino   /* If there is already a prepared dtable for this class, we must
1082e4b17023SJohn Marino      replace it with a new version (since there must have been methods
1083e4b17023SJohn Marino      added to or otherwise modified in the class while executing
1084e4b17023SJohn Marino      +initialize, and the table needs to be recomputed.  */
1085e4b17023SJohn Marino   dtable = __objc_prepared_dtable_for_class (cls);
1086e4b17023SJohn Marino   if (dtable != 0)
1087e4b17023SJohn Marino     {
1088e4b17023SJohn Marino       objc_hash_remove (prepared_dtable_table, cls);
1089e4b17023SJohn Marino       sarray_free (dtable);
1090e4b17023SJohn Marino     }
1091e4b17023SJohn Marino 
1092e4b17023SJohn Marino   /* Now prepare the dtable for population.  */
1093e4b17023SJohn Marino   assert (cls != cls->super_class);
1094e4b17023SJohn Marino   if (cls->super_class)
1095e4b17023SJohn Marino     {
1096e4b17023SJohn Marino       /* Inherit the method list from the super class.  Yet the super
1097e4b17023SJohn Marino          class may still be initializing in the case when a class
1098e4b17023SJohn Marino          cluster sub class initializes its super classes.  */
1099e4b17023SJohn Marino       if (cls->super_class->dtable == __objc_uninstalled_dtable)
1100e4b17023SJohn Marino 	__objc_install_dtable_for_class (cls->super_class);
1101e4b17023SJohn Marino 
1102e4b17023SJohn Marino       super_dtable = cls->super_class->dtable;
1103e4b17023SJohn Marino       /* If the dispatch table is not yet installed, we are still in
1104e4b17023SJohn Marino 	 the process of executing +initialize.  Yet the dispatch table
1105e4b17023SJohn Marino 	 should be available.  */
1106e4b17023SJohn Marino       if (super_dtable == __objc_uninstalled_dtable)
1107e4b17023SJohn Marino 	super_dtable = __objc_prepared_dtable_for_class (cls->super_class);
1108e4b17023SJohn Marino 
1109e4b17023SJohn Marino       assert (super_dtable);
1110e4b17023SJohn Marino       dtable = sarray_lazy_copy (super_dtable);
1111e4b17023SJohn Marino     }
1112e4b17023SJohn Marino   else
1113e4b17023SJohn Marino     dtable = sarray_new (__objc_selector_max_index, 0);
1114e4b17023SJohn Marino 
1115e4b17023SJohn Marino   __objc_install_methods_in_dtable (dtable, cls->methods);
1116e4b17023SJohn Marino 
1117e4b17023SJohn Marino   objc_hash_add (&prepared_dtable_table,
1118e4b17023SJohn Marino 		 cls,
1119e4b17023SJohn Marino 		 dtable);
1120e4b17023SJohn Marino }
1121e4b17023SJohn Marino 
1122e4b17023SJohn Marino /* This wrapper only exists to allow an easy replacement of the lookup
1123e4b17023SJohn Marino    implementation and it is expected that the compiler will optimize
1124e4b17023SJohn Marino    it away.  */
1125e4b17023SJohn Marino static struct sarray *
__objc_prepared_dtable_for_class(Class cls)1126e4b17023SJohn Marino __objc_prepared_dtable_for_class (Class cls)
1127e4b17023SJohn Marino {
1128e4b17023SJohn Marino   struct sarray *dtable = 0;
1129e4b17023SJohn Marino   assert (cls);
1130e4b17023SJohn Marino   if (prepared_dtable_table)
1131e4b17023SJohn Marino     dtable = objc_hash_value_for_key (prepared_dtable_table, cls);
1132e4b17023SJohn Marino   /* dtable my be nil, since we call this to check whether we are
1133e4b17023SJohn Marino      currently preparing before we start preparing.  */
1134e4b17023SJohn Marino   return dtable;
1135e4b17023SJohn Marino }
1136e4b17023SJohn Marino 
1137e4b17023SJohn Marino /* Helper function for messages sent to CLS or implementation pointers
1138e4b17023SJohn Marino    retrieved from CLS during +initialize before the dtable is
1139e4b17023SJohn Marino    installed.  When a class implicitly initializes another class which
1140e4b17023SJohn Marino    in turn implicitly invokes methods in this class, before the
1141e4b17023SJohn Marino    implementation of +initialize of CLS completes, this returns the
1142e4b17023SJohn Marino    expected implementation.  Forwarding remains the responsibility of
1143e4b17023SJohn Marino    objc_msg_lookup.  This function should only be called under the
1144e4b17023SJohn Marino    global lock.  */
1145e4b17023SJohn Marino static IMP
__objc_get_prepared_imp(Class cls,SEL sel)1146e4b17023SJohn Marino __objc_get_prepared_imp (Class cls,SEL sel)
1147e4b17023SJohn Marino {
1148e4b17023SJohn Marino   struct sarray *dtable;
1149e4b17023SJohn Marino   IMP imp;
1150e4b17023SJohn Marino 
1151e4b17023SJohn Marino   assert (cls);
1152e4b17023SJohn Marino   assert (sel);
1153e4b17023SJohn Marino   assert (cls->dtable == __objc_uninstalled_dtable);
1154e4b17023SJohn Marino   dtable = __objc_prepared_dtable_for_class (cls);
1155e4b17023SJohn Marino 
1156e4b17023SJohn Marino   assert (dtable);
1157e4b17023SJohn Marino   assert (dtable != __objc_uninstalled_dtable);
1158e4b17023SJohn Marino   imp = sarray_get_safe (dtable, (size_t) sel->sel_id);
1159e4b17023SJohn Marino 
1160e4b17023SJohn Marino   /* imp may be Nil if the method does not exist and we may fallback
1161e4b17023SJohn Marino      to the forwarding implementation later.  */
1162e4b17023SJohn Marino   return imp;
1163e4b17023SJohn Marino }
1164e4b17023SJohn Marino 
1165e4b17023SJohn Marino /* When this function is called +initialize should be completed.  So
1166e4b17023SJohn Marino    now we are safe to install the dispatch table for the class so that
1167e4b17023SJohn Marino    they become available for other threads that may be waiting in the
1168e4b17023SJohn Marino    lock.  */
1169e4b17023SJohn Marino static void
__objc_install_prepared_dtable_for_class(Class cls)1170e4b17023SJohn Marino __objc_install_prepared_dtable_for_class (Class cls)
1171e4b17023SJohn Marino {
1172e4b17023SJohn Marino   assert (cls);
1173e4b17023SJohn Marino   assert (cls->dtable == __objc_uninstalled_dtable);
1174e4b17023SJohn Marino   cls->dtable = __objc_prepared_dtable_for_class (cls);
1175e4b17023SJohn Marino 
1176e4b17023SJohn Marino   assert (cls->dtable);
1177e4b17023SJohn Marino   assert (cls->dtable != __objc_uninstalled_dtable);
1178e4b17023SJohn Marino   objc_hash_remove (prepared_dtable_table, cls);
1179e4b17023SJohn Marino }
1180