]> git.ipfire.org Git - thirdparty/gcc.git/blame - libobjc/protocols.c
update_web_docs_svn (MANUALS): Add libquadmath.
[thirdparty/gcc.git] / libobjc / protocols.c
CommitLineData
debfbfee
NP
1/* GNU Objective C Runtime protocol related functions.
2 Copyright (C) 2010 Free Software Foundation, Inc.
3 Contributed by Nicola Pero
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under the
8terms of the GNU General Public License as published by the Free Software
9Foundation; either version 3, or (at your option) any later version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14details.
15
16Under Section 7 of GPL version 3, you are granted additional
17permissions described in the GCC Runtime Library Exception, version
183.1, as published by the Free Software Foundation.
19
20You should have received a copy of the GNU General Public License and
21a copy of the GCC Runtime Library Exception along with this program;
22see 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. */
39static cache_ptr __protocols_hashtable;
40
41/* A mutex protecting the protocol_hashtable. */
42static objc_mutex_t __protocols_hashtable_lock = NULL;
43
44/* Called at startup by init.c. */
45void
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. */
57void
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
79Protocol *
80objc_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
94Protocol **
95objc_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
137BOOL
138class_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
169BOOL
170class_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
209Protocol **
210class_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
267BOOL
268protocol_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
308BOOL
309protocol_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
346const char *
347protocol_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
357struct 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
397struct 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
458Property 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
477Property *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
503Protocol **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}