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