annotate libobjc/sendmsg.c @ 158:494b0b89df80 default tip

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