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