]> git.ipfire.org Git - thirdparty/gcc.git/blame - libobjc/protocols.c
archive.c: Do not include objc/objc.h.
[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. */
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. */
37static cache_ptr __protocols_hashtable;
38
39/* A mutex protecting the protocol_hashtable. */
40static objc_mutex_t __protocols_hashtable_lock = NULL;
41
42/* Called at startup by init.c. */
43void
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. */
55void
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
77Protocol *
78objc_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
92Protocol **
93objc_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
135BOOL
136class_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
167BOOL
168class_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
207Protocol **
208class_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
258BOOL
259protocol_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
299BOOL
300protocol_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
337const char *
338protocol_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
348struct 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
387struct 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
448Property 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
467Property *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
493Protocol **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}