]>
Commit | Line | Data |
---|---|---|
debfbfee NP |
1 | /* GNU Objective C Runtime protocol related functions. |
2 | Copyright (C) 2010 Free Software Foundation, Inc. | |
3 | Contributed by Nicola Pero | |
4 | ||
5 | This file is part of GCC. | |
6 | ||
7 | GCC is free software; you can redistribute it and/or modify it under the | |
8 | terms of the GNU General Public License as published by the Free Software | |
9 | Foundation; either version 3, or (at your option) any later version. | |
10 | ||
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
13 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |
14 | details. | |
15 | ||
16 | Under Section 7 of GPL version 3, you are granted additional | |
17 | permissions described in the GCC Runtime Library Exception, version | |
18 | 3.1, as published by the Free Software Foundation. | |
19 | ||
20 | You should have received a copy of the GNU General Public License and | |
21 | a copy of the GCC Runtime Library Exception along with this program; | |
22 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | <http://www.gnu.org/licenses/>. */ | |
24 | ||
25 | #include "objc-private/common.h" | |
debfbfee NP |
26 | #include "objc/runtime.h" |
27 | #include "objc-private/module-abi-8.h" /* For runtime structures */ | |
28 | #include "objc/thr.h" | |
29 | #include "objc-private/runtime.h" /* the kitchen sink */ | |
30 | #include "objc-private/hash.h" /* For the hash table of protocols. */ | |
49a35931 NP |
31 | #include "objc-private/protocols.h" /* For __objc_protocols_init() and |
32 | __objc_protocols_add_protocol(). */ | |
33 | #include <stdlib.h> /* For malloc. */ | |
debfbfee NP |
34 | |
35 | /* This is a table that maps a name to a Protocol instance with that | |
36 | name. Because there may be multiple Protocol instances with the | |
37 | same name (no harm in that) the table records only one | |
38 | instance. */ | |
39 | static cache_ptr __protocols_hashtable; | |
40 | ||
41 | /* A mutex protecting the protocol_hashtable. */ | |
42 | static objc_mutex_t __protocols_hashtable_lock = NULL; | |
43 | ||
44 | /* Called at startup by init.c. */ | |
45 | void | |
46 | __objc_protocols_init (void) | |
47 | { | |
48 | __protocols_hashtable_lock = objc_mutex_allocate (); | |
49 | ||
50 | /* The keys in the table are strings, and the values are Protocol | |
51 | objects. */ | |
52 | __protocols_hashtable = objc_hash_new (64, (hash_func_type) objc_hash_string, | |
53 | (compare_func_type) objc_compare_strings); | |
54 | } | |
55 | ||
56 | /* Add a protocol to the hashtable. */ | |
57 | void | |
58 | __objc_protocols_add_protocol (const char *name, Protocol *object) | |
59 | { | |
60 | objc_mutex_lock (__protocols_hashtable_lock); | |
61 | ||
62 | /* If we find a protocol with the same name already in the | |
63 | hashtable, we do not need to add the new one, because it will be | |
64 | identical to it. This in the reasonable assumption that two | |
65 | protocols with the same name are identical, which is expected in | |
66 | any sane program. If we are really paranoid, we would compare | |
67 | the protocols and abort if they are not identical. | |
68 | Unfortunately, this would slow down the startup of all | |
69 | Objective-C programs while trying to catch a problem that has | |
70 | never been seen in practice, so we don't do it. */ | |
71 | if (! objc_hash_is_key_in_hash (__protocols_hashtable, name)) | |
72 | { | |
73 | objc_hash_add (&__protocols_hashtable, name, object); | |
74 | } | |
75 | ||
76 | objc_mutex_unlock (__protocols_hashtable_lock); | |
77 | } | |
78 | ||
79 | Protocol * | |
80 | objc_getProtocol (const char *name) | |
81 | { | |
82 | Protocol *protocol; | |
83 | ||
84 | if (name == NULL) | |
85 | return NULL; | |
86 | ||
87 | objc_mutex_lock (__protocols_hashtable_lock); | |
88 | protocol = (Protocol *)(objc_hash_value_for_key (__protocols_hashtable, name)); | |
89 | objc_mutex_unlock (__protocols_hashtable_lock); | |
90 | ||
91 | return protocol; | |
92 | } | |
93 | ||
94 | Protocol ** | |
95 | objc_copyProtocolList (unsigned int *numberOfReturnedProtocols) | |
96 | { | |
97 | unsigned int count = 0; | |
98 | Protocol **returnValue = NULL; | |
99 | node_ptr node; | |
100 | ||
101 | objc_mutex_lock (__protocols_hashtable_lock); | |
102 | ||
103 | /* Count how many protocols we have. */ | |
104 | node = objc_hash_next (__protocols_hashtable, NULL); | |
105 | while (node) | |
106 | { | |
107 | count++; | |
108 | node = objc_hash_next (__protocols_hashtable, node); | |
109 | } | |
110 | ||
111 | if (count != 0) | |
112 | { | |
113 | unsigned int i = 0; | |
114 | ||
115 | /* Allocate enough memory to hold them. */ | |
116 | returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1))); | |
117 | ||
118 | /* Copy the protocols. */ | |
119 | node = objc_hash_next (__protocols_hashtable, NULL); | |
120 | while (node) | |
121 | { | |
122 | returnValue[i] = node->value; | |
123 | i++; | |
124 | node = objc_hash_next (__protocols_hashtable, node); | |
125 | } | |
126 | ||
127 | returnValue[i] = NULL; | |
128 | } | |
129 | objc_mutex_unlock (__protocols_hashtable_lock); | |
130 | ||
131 | if (numberOfReturnedProtocols) | |
132 | *numberOfReturnedProtocols = count; | |
133 | ||
134 | return returnValue; | |
135 | } | |
136 | ||
137 | BOOL | |
138 | class_addProtocol (Class class_, Protocol *protocol) | |
139 | { | |
140 | struct objc_protocol_list *protocols; | |
141 | ||
142 | if (class_ == Nil || protocol == NULL) | |
143 | return NO; | |
144 | ||
145 | if (class_conformsToProtocol (class_, protocol)) | |
146 | return NO; | |
147 | ||
148 | /* Check that it is a Protocol object before casting it to (struct | |
149 | objc_protocol *). */ | |
150 | if (protocol->class_pointer != objc_lookupClass ("Protocol")) | |
151 | return NO; | |
152 | ||
153 | objc_mutex_lock (__objc_runtime_mutex); | |
154 | ||
155 | /* Create the objc_protocol_list. */ | |
156 | protocols = malloc (sizeof (struct objc_protocol_list)); | |
157 | protocols->count = 1; | |
158 | protocols->list[0] = protocol; | |
159 | ||
160 | /* Attach it to the list of class protocols. */ | |
161 | protocols->next = class_->protocols; | |
162 | class_->protocols = protocols; | |
163 | ||
164 | objc_mutex_unlock (__objc_runtime_mutex); | |
165 | ||
166 | return YES; | |
167 | } | |
168 | ||
169 | BOOL | |
170 | class_conformsToProtocol (Class class_, Protocol *protocol) | |
171 | { | |
172 | struct objc_protocol_list* proto_list; | |
173 | ||
174 | if (class_ == Nil || protocol == NULL) | |
175 | return NO; | |
176 | ||
177 | /* Check that it is a Protocol object before casting it to (struct | |
178 | objc_protocol *). */ | |
179 | if (protocol->class_pointer != objc_lookupClass ("Protocol")) | |
180 | return NO; | |
181 | ||
182 | /* Acquire the runtime lock because the list of protocols for a | |
183 | class may be modified concurrently, for example if another thread | |
184 | calls class_addProtocol(), or dynamically loads from a file a | |
185 | category of the class. */ | |
186 | objc_mutex_lock (__objc_runtime_mutex); | |
187 | proto_list = class_->protocols; | |
188 | ||
189 | while (proto_list) | |
190 | { | |
191 | size_t i; | |
192 | for (i = 0; i < proto_list->count; i++) | |
193 | { | |
194 | if (proto_list->list[i] == protocol | |
195 | || protocol_conformsToProtocol (proto_list->list[i], | |
196 | protocol)) | |
197 | { | |
198 | objc_mutex_unlock (__objc_runtime_mutex); | |
199 | return YES; | |
200 | } | |
201 | } | |
202 | proto_list = proto_list->next; | |
203 | } | |
204 | ||
205 | objc_mutex_unlock (__objc_runtime_mutex); | |
206 | return NO; | |
207 | } | |
208 | ||
209 | Protocol ** | |
210 | class_copyProtocolList (Class class_, unsigned int *numberOfReturnedProtocols) | |
211 | { | |
212 | unsigned int count = 0; | |
213 | Protocol **returnValue = NULL; | |
214 | struct objc_protocol_list* proto_list; | |
215 | ||
ad9eef11 NP |
216 | if (class_ == Nil) |
217 | { | |
218 | if (numberOfReturnedProtocols) | |
219 | *numberOfReturnedProtocols = 0; | |
220 | return NULL; | |
221 | } | |
222 | ||
debfbfee NP |
223 | /* Lock the runtime mutex because the class protocols may be |
224 | concurrently modified. */ | |
225 | objc_mutex_lock (__objc_runtime_mutex); | |
226 | ||
227 | /* Count how many protocols we have. */ | |
228 | proto_list = class_->protocols; | |
229 | ||
230 | while (proto_list) | |
231 | { | |
232 | count = count + proto_list->count; | |
233 | proto_list = proto_list->next; | |
234 | } | |
235 | ||
236 | if (count != 0) | |
237 | { | |
238 | unsigned int i = 0; | |
239 | ||
240 | /* Allocate enough memory to hold them. */ | |
241 | returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1))); | |
242 | ||
243 | /* Copy the protocols. */ | |
244 | proto_list = class_->protocols; | |
245 | ||
246 | while (proto_list) | |
247 | { | |
248 | size_t j; | |
249 | for (j = 0; j < proto_list->count; j++) | |
250 | { | |
251 | returnValue[i] = proto_list->list[j]; | |
252 | i++; | |
253 | } | |
254 | proto_list = proto_list->next; | |
255 | } | |
256 | ||
257 | returnValue[i] = NULL; | |
258 | } | |
259 | objc_mutex_unlock (__objc_runtime_mutex); | |
260 | ||
261 | if (numberOfReturnedProtocols) | |
262 | *numberOfReturnedProtocols = count; | |
263 | ||
264 | return returnValue; | |
265 | } | |
266 | ||
267 | BOOL | |
268 | protocol_conformsToProtocol (Protocol *protocol, Protocol *anotherProtocol) | |
269 | { | |
270 | struct objc_protocol_list* proto_list; | |
271 | ||
272 | if (protocol == NULL || anotherProtocol == NULL) | |
273 | return NO; | |
274 | ||
275 | if (protocol == anotherProtocol) | |
276 | return YES; | |
277 | ||
278 | /* Check that the objects are Protocol objects before casting them | |
279 | to (struct objc_protocol *). */ | |
280 | if (protocol->class_pointer != anotherProtocol->class_pointer) | |
281 | return NO; | |
282 | ||
283 | if (protocol->class_pointer != objc_lookupClass ("Protocol")) | |
284 | return NO; | |
285 | ||
286 | if (strcmp (((struct objc_protocol *)protocol)->protocol_name, | |
287 | ((struct objc_protocol *)anotherProtocol)->protocol_name) == 0) | |
288 | return YES; | |
289 | ||
290 | /* We do not acquire any lock because protocols are currently | |
291 | immutable. We can freely iterate over a protocol structure. */ | |
292 | proto_list = ((struct objc_protocol *)protocol)->protocol_list; | |
293 | while (proto_list) | |
294 | { | |
295 | size_t i; | |
296 | ||
297 | for (i = 0; i < proto_list->count; i++) | |
298 | { | |
299 | if (protocol_conformsToProtocol (proto_list->list[i], anotherProtocol)) | |
300 | return YES; | |
301 | } | |
302 | proto_list = proto_list->next; | |
303 | } | |
304 | ||
305 | return NO; | |
306 | } | |
307 | ||
308 | BOOL | |
309 | protocol_isEqual (Protocol *protocol, Protocol *anotherProtocol) | |
310 | { | |
311 | if (protocol == anotherProtocol) | |
312 | return YES; | |
313 | ||
314 | if (protocol == NULL || anotherProtocol == NULL) | |
315 | return NO; | |
316 | ||
317 | /* Check that the objects are Protocol objects before casting them | |
318 | to (struct objc_protocol *). */ | |
319 | if (protocol->class_pointer != anotherProtocol->class_pointer) | |
320 | return NO; | |
321 | ||
322 | if (protocol->class_pointer != objc_lookupClass ("Protocol")) | |
323 | return NO; | |
324 | ||
325 | /* Equality between formal protocols is only formal (nothing to do | |
326 | with actually checking the list of methods they have!). Two | |
327 | formal Protocols are equal if and only if they have the same | |
328 | name. | |
329 | ||
330 | Please note (for comparisons with other implementations) that | |
331 | checking the names is equivalent to checking that Protocol A | |
332 | conforms to Protocol B and Protocol B conforms to Protocol A, | |
333 | because this happens iff they have the same name. If they have | |
334 | different names, A conforms to B if and only if A includes B, but | |
335 | the situation where A includes B and B includes A is a circular | |
336 | dependency between Protocols which is forbidden by the compiler, | |
337 | so A conforms to B and B conforms to A with A and B having | |
338 | different names is an impossible case. */ | |
339 | if (strcmp (((struct objc_protocol *)protocol)->protocol_name, | |
340 | ((struct objc_protocol *)anotherProtocol)->protocol_name) == 0) | |
341 | return YES; | |
342 | ||
343 | return NO; | |
344 | } | |
345 | ||
346 | const char * | |
347 | protocol_getName (Protocol *protocol) | |
348 | { | |
349 | /* Check that it is a Protocol object before casting it to (struct | |
350 | objc_protocol *). */ | |
351 | if (protocol->class_pointer != objc_lookupClass ("Protocol")) | |
352 | return NULL; | |
353 | ||
354 | return ((struct objc_protocol *)protocol)->protocol_name; | |
355 | } | |
356 | ||
357 | struct objc_method_description protocol_getMethodDescription (Protocol *protocol, | |
358 | SEL selector, | |
359 | BOOL requiredMethod, | |
360 | BOOL instanceMethod) | |
361 | { | |
362 | struct objc_method_description no_result = { NULL, NULL }; | |
debfbfee NP |
363 | struct objc_method_description_list *methods; |
364 | int i; | |
365 | ||
366 | /* TODO: New ABI. */ | |
367 | /* The current ABI does not have any information on optional protocol methods. */ | |
368 | if (! requiredMethod) | |
369 | return no_result; | |
370 | ||
371 | /* Check that it is a Protocol object before casting it to (struct | |
372 | objc_protocol *). */ | |
373 | if (protocol->class_pointer != objc_lookupClass ("Protocol")) | |
374 | return no_result; | |
375 | ||
debfbfee NP |
376 | if (instanceMethod) |
377 | methods = ((struct objc_protocol *)protocol)->instance_methods; | |
378 | else | |
379 | methods = ((struct objc_protocol *)protocol)->class_methods; | |
380 | ||
381 | if (methods) | |
382 | { | |
383 | for (i = 0; i < methods->count; i++) | |
384 | { | |
ae422ccd NP |
385 | if (sel_isEqual (methods->list[i].name, selector)) |
386 | return methods->list[i]; | |
387 | /* | |
f7185d47 | 388 | if (strcmp (sel_getName (methods->list[i].name), selector_name) == 0) |
debfbfee | 389 | return methods->list[i]; |
ae422ccd | 390 | */ |
debfbfee NP |
391 | } |
392 | } | |
393 | ||
394 | return no_result; | |
395 | } | |
396 | ||
397 | struct objc_method_description *protocol_copyMethodDescriptionList (Protocol *protocol, | |
398 | BOOL requiredMethod, | |
399 | BOOL instanceMethod, | |
400 | unsigned int *numberOfReturnedMethods) | |
401 | { | |
402 | struct objc_method_description_list *methods; | |
403 | unsigned int count = 0; | |
404 | struct objc_method_description *returnValue = NULL; | |
405 | ||
406 | /* TODO: New ABI */ | |
407 | /* The current ABI does not have any information on optional protocol methods. */ | |
408 | if (! requiredMethod) | |
409 | { | |
410 | if (numberOfReturnedMethods) | |
411 | *numberOfReturnedMethods = 0; | |
412 | ||
413 | return NULL; | |
414 | } | |
415 | ||
416 | /* Check that it is a Protocol object before casting it to (struct | |
417 | objc_protocol *). */ | |
418 | if (protocol == NULL || protocol->class_pointer != objc_lookupClass ("Protocol")) | |
419 | { | |
420 | if (numberOfReturnedMethods) | |
421 | *numberOfReturnedMethods = 0; | |
422 | ||
423 | return NULL; | |
424 | } | |
425 | ||
426 | /* We do not acquire any lock because protocols are currently | |
427 | immutable. We can freely iterate over a protocol structure. */ | |
428 | ||
429 | if (instanceMethod) | |
430 | methods = ((struct objc_protocol *)protocol)->instance_methods; | |
431 | else | |
432 | methods = ((struct objc_protocol *)protocol)->class_methods; | |
433 | ||
434 | if (methods) | |
435 | { | |
436 | unsigned int i; | |
437 | count = methods->count; | |
438 | ||
439 | /* Allocate enough memory to hold them. */ | |
440 | returnValue = (struct objc_method_description *)(malloc (sizeof (struct objc_method_description) * (count + 1))); | |
441 | ||
442 | /* Copy them. */ | |
443 | for (i = 0; i < count; i++) | |
444 | { | |
445 | returnValue[i].name = methods->list[i].name; | |
446 | returnValue[i].types = methods->list[i].types; | |
447 | } | |
448 | returnValue[i].name = NULL; | |
449 | returnValue[i].types = NULL; | |
450 | } | |
451 | ||
452 | if (numberOfReturnedMethods) | |
453 | *numberOfReturnedMethods = count; | |
454 | ||
455 | return returnValue; | |
456 | } | |
457 | ||
458 | Property protocol_getProperty (Protocol *protocol, const char *propertyName, | |
459 | BOOL requiredProperty, BOOL instanceProperty) | |
460 | { | |
461 | if (protocol == NULL || propertyName == NULL) | |
462 | return NULL; | |
463 | ||
464 | if (!requiredProperty || !instanceProperty) | |
465 | return NULL; | |
466 | ||
467 | /* Check that it is a Protocol object before casting it to (struct | |
468 | objc_protocol *). */ | |
469 | if (protocol->class_pointer != objc_lookupClass ("Protocol")) | |
470 | return NULL; | |
471 | ||
472 | /* TODO: New ABI. */ | |
473 | /* The current ABI does not have any information on protocol properties. */ | |
474 | return NULL; | |
475 | } | |
476 | ||
477 | Property *protocol_copyPropertyList (Protocol *protocol, unsigned int *numberOfReturnedProperties) | |
478 | { | |
479 | unsigned int count = 0; | |
480 | Property *returnValue = NULL; | |
481 | ||
482 | /* Check that it is a Protocol object before casting it to (struct | |
483 | objc_protocol *). */ | |
484 | if (protocol == NULL || protocol->class_pointer != objc_lookupClass ("Protocol")) | |
485 | { | |
486 | if (numberOfReturnedProperties) | |
487 | *numberOfReturnedProperties = 0; | |
488 | ||
489 | return NULL; | |
490 | } | |
491 | ||
492 | /* We do not acquire any lock because protocols are currently | |
493 | immutable. We can freely iterate over a protocol structure. */ | |
494 | ||
495 | /* TODO: New ABI. */ | |
496 | /* The current ABI does not have any information on protocol properties. */ | |
497 | if (numberOfReturnedProperties) | |
498 | *numberOfReturnedProperties = count; | |
499 | ||
500 | return returnValue; | |
501 | } | |
502 | ||
503 | Protocol **protocol_copyProtocolList (Protocol *protocol, unsigned int *numberOfReturnedProtocols) | |
504 | { | |
505 | unsigned int count = 0; | |
506 | Protocol **returnValue = NULL; | |
507 | struct objc_protocol_list* proto_list; | |
508 | ||
509 | /* Check that it is a Protocol object before casting it to (struct | |
510 | objc_protocol *). */ | |
511 | if (protocol == NULL || protocol->class_pointer != objc_lookupClass ("Protocol")) | |
512 | { | |
513 | if (numberOfReturnedProtocols) | |
514 | *numberOfReturnedProtocols = 0; | |
515 | ||
516 | return NULL; | |
517 | } | |
518 | ||
519 | /* We do not acquire any lock because protocols are currently | |
520 | immutable. We can freely iterate over a protocol structure. */ | |
521 | ||
522 | /* Count how many protocols we have. */ | |
523 | proto_list = ((struct objc_protocol *)protocol)->protocol_list; | |
524 | ||
525 | while (proto_list) | |
526 | { | |
527 | count = count + proto_list->count; | |
528 | proto_list = proto_list->next; | |
529 | } | |
530 | ||
531 | if (count != 0) | |
532 | { | |
533 | unsigned int i = 0; | |
534 | ||
535 | /* Allocate enough memory to hold them. */ | |
536 | returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1))); | |
537 | ||
538 | /* Copy the protocols. */ | |
539 | proto_list = ((struct objc_protocol *)protocol)->protocol_list; | |
540 | ||
541 | while (proto_list) | |
542 | { | |
543 | size_t j; | |
544 | for (j = 0; j < proto_list->count; j++) | |
545 | { | |
546 | returnValue[i] = proto_list->list[j]; | |
547 | i++; | |
548 | } | |
549 | proto_list = proto_list->next; | |
550 | } | |
551 | ||
552 | returnValue[i] = NULL; | |
553 | } | |
554 | ||
555 | if (numberOfReturnedProtocols) | |
556 | *numberOfReturnedProtocols = count; | |
557 | ||
558 | return returnValue; | |
559 | } |