OSDN Git Service

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