1/* GNU Objective C Runtime protocol related functions.
2   Copyright (C) 2010-2020 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"
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
32                                          __objc_protocols_add_protocol().  */
33#include <stdlib.h>                    /* For malloc.  */
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, struct objc_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    objc_hash_add (&__protocols_hashtable, name, object);
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] = (struct objc_protocol *)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] == (struct objc_protocol *)protocol
193	      || protocol_conformsToProtocol ((Protocol *)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  if (class_ == Nil)
215    {
216      if (numberOfReturnedProtocols)
217	*numberOfReturnedProtocols = 0;
218      return NULL;
219    }
220
221  /* Lock the runtime mutex because the class protocols may be
222     concurrently modified.  */
223  objc_mutex_lock (__objc_runtime_mutex);
224
225  /* Count how many protocols we have.  */
226  proto_list = class_->protocols;
227
228  while (proto_list)
229    {
230      count = count + proto_list->count;
231      proto_list = proto_list->next;
232    }
233
234  if (count != 0)
235    {
236      unsigned int i = 0;
237
238      /* Allocate enough memory to hold them.  */
239      returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1)));
240
241      /* Copy the protocols.  */
242      proto_list = class_->protocols;
243
244      while (proto_list)
245	{
246	  size_t j;
247	  for (j = 0; j < proto_list->count; j++)
248	    {
249	      returnValue[i] = (Protocol *)proto_list->list[j];
250	      i++;
251	    }
252	  proto_list = proto_list->next;
253	}
254
255      returnValue[i] = NULL;
256    }
257  objc_mutex_unlock (__objc_runtime_mutex);
258
259  if (numberOfReturnedProtocols)
260    *numberOfReturnedProtocols = count;
261
262  return returnValue;
263}
264
265BOOL
266protocol_conformsToProtocol (Protocol *protocol, Protocol *anotherProtocol)
267{
268  struct objc_protocol_list* proto_list;
269
270  if (protocol == NULL  ||  anotherProtocol == NULL)
271    return NO;
272
273  if (protocol == anotherProtocol)
274    return YES;
275
276  /* Check that the objects are Protocol objects before casting them
277     to (struct objc_protocol *).  */
278  if (protocol->class_pointer != anotherProtocol->class_pointer)
279    return NO;
280
281  if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
282    return NO;
283
284  if (strcmp (((struct objc_protocol *)protocol)->protocol_name,
285	      ((struct objc_protocol *)anotherProtocol)->protocol_name) == 0)
286    return YES;
287
288  /* We do not acquire any lock because protocols are currently
289     immutable.  We can freely iterate over a protocol structure.  */
290  proto_list = ((struct objc_protocol *)protocol)->protocol_list;
291  while (proto_list)
292    {
293      size_t i;
294
295      for (i = 0; i < proto_list->count; i++)
296	{
297	  if (protocol_conformsToProtocol ((Protocol *)proto_list->list[i], anotherProtocol))
298	    return YES;
299	}
300      proto_list = proto_list->next;
301    }
302
303  return NO;
304}
305
306BOOL
307protocol_isEqual (Protocol *protocol, Protocol *anotherProtocol)
308{
309  if (protocol == anotherProtocol)
310    return YES;
311
312  if (protocol == NULL  ||  anotherProtocol == NULL)
313    return NO;
314
315  /* Check that the objects are Protocol objects before casting them
316     to (struct objc_protocol *).  */
317  if (protocol->class_pointer != anotherProtocol->class_pointer)
318    return NO;
319
320  if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
321    return NO;
322
323  /* Equality between formal protocols is only formal (nothing to do
324     with actually checking the list of methods they have!).  Two
325     formal Protocols are equal if and only if they have the same
326     name.
327
328     Please note (for comparisons with other implementations) that
329     checking the names is equivalent to checking that Protocol A
330     conforms to Protocol B and Protocol B conforms to Protocol A,
331     because this happens iff they have the same name.  If they have
332     different names, A conforms to B if and only if A includes B, but
333     the situation where A includes B and B includes A is a circular
334     dependency between Protocols which is forbidden by the compiler,
335     so A conforms to B and B conforms to A with A and B having
336     different names is an impossible case.  */
337  if (strcmp (((struct objc_protocol *)protocol)->protocol_name,
338	      ((struct objc_protocol *)anotherProtocol)->protocol_name) == 0)
339    return YES;
340
341  return NO;
342}
343
344const char *
345protocol_getName (Protocol *protocol)
346{
347  /* Check that it is a Protocol object before casting it to (struct
348     objc_protocol *).  */
349  if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
350    return NULL;
351
352  return ((struct objc_protocol *)protocol)->protocol_name;
353}
354
355struct objc_method_description protocol_getMethodDescription (Protocol *protocol,
356							      SEL selector,
357							      BOOL requiredMethod,
358							      BOOL instanceMethod)
359{
360  struct objc_method_description no_result = { NULL, NULL };
361  struct objc_method_description_list *methods;
362  int i;
363
364  /* TODO: New ABI.  */
365  /* The current ABI does not have any information on optional protocol methods.  */
366  if (! requiredMethod)
367    return no_result;
368
369  /* Check that it is a Protocol object before casting it to (struct
370     objc_protocol *).  */
371  if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
372    return no_result;
373
374  if (instanceMethod)
375    methods = ((struct objc_protocol *)protocol)->instance_methods;
376  else
377    methods = ((struct objc_protocol *)protocol)->class_methods;
378
379  if (methods)
380    {
381      for (i = 0; i < methods->count; i++)
382	{
383	  if (sel_isEqual (methods->list[i].name, selector))
384	    return methods->list[i];
385	  /*
386	  if (strcmp (sel_getName (methods->list[i].name), selector_name) == 0)
387	    return methods->list[i];
388	  */
389	}
390    }
391
392  return no_result;
393}
394
395struct objc_method_description *protocol_copyMethodDescriptionList (Protocol *protocol,
396								    BOOL requiredMethod,
397								    BOOL instanceMethod,
398								    unsigned int *numberOfReturnedMethods)
399{
400  struct objc_method_description_list *methods;
401  unsigned int count = 0;
402  struct objc_method_description *returnValue = NULL;
403
404  /* TODO: New ABI */
405  /* The current ABI does not have any information on optional protocol methods.  */
406  if (! requiredMethod)
407    {
408      if (numberOfReturnedMethods)
409	*numberOfReturnedMethods = 0;
410
411      return NULL;
412    }
413
414  /* Check that it is a Protocol object before casting it to (struct
415     objc_protocol *).  */
416  if (protocol == NULL  ||  protocol->class_pointer != objc_lookUpClass ("Protocol"))
417    {
418      if (numberOfReturnedMethods)
419	*numberOfReturnedMethods = 0;
420
421      return NULL;
422    }
423
424  /* We do not acquire any lock because protocols are currently
425     immutable.  We can freely iterate over a protocol structure.  */
426
427  if (instanceMethod)
428    methods = ((struct objc_protocol *)protocol)->instance_methods;
429  else
430    methods = ((struct objc_protocol *)protocol)->class_methods;
431
432  if (methods)
433    {
434      unsigned int i;
435      count = methods->count;
436
437      /* Allocate enough memory to hold them.  */
438      returnValue = (struct objc_method_description *)(malloc (sizeof (struct objc_method_description) * (count + 1)));
439
440      /* Copy them.  */
441      for (i = 0; i < count; i++)
442	{
443	  returnValue[i].name = methods->list[i].name;
444	  returnValue[i].types = methods->list[i].types;
445	}
446      returnValue[i].name = NULL;
447      returnValue[i].types = NULL;
448    }
449
450  if (numberOfReturnedMethods)
451    *numberOfReturnedMethods = count;
452
453  return returnValue;
454}
455
456Property protocol_getProperty (Protocol *protocol, const char *propertyName,
457			       BOOL requiredProperty, BOOL instanceProperty)
458{
459  if (protocol == NULL  ||  propertyName == NULL)
460    return NULL;
461
462  if (!requiredProperty  ||  !instanceProperty)
463    return NULL;
464
465  /* Check that it is a Protocol object before casting it to (struct
466     objc_protocol *).  */
467  if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
468    return NULL;
469
470  /* TODO: New ABI.  */
471  /* The current ABI does not have any information on protocol properties.  */
472  return NULL;
473}
474
475Property *protocol_copyPropertyList (Protocol *protocol, unsigned int *numberOfReturnedProperties)
476{
477  unsigned int count = 0;
478  Property *returnValue = NULL;
479
480  /* Check that it is a Protocol object before casting it to (struct
481     objc_protocol *).  */
482  if (protocol == NULL  ||  protocol->class_pointer != objc_lookUpClass ("Protocol"))
483    {
484      if (numberOfReturnedProperties)
485	*numberOfReturnedProperties = 0;
486
487      return NULL;
488    }
489
490  /* We do not acquire any lock because protocols are currently
491     immutable.  We can freely iterate over a protocol structure.  */
492
493  /* TODO: New ABI.  */
494  /* The current ABI does not have any information on protocol properties.  */
495  if (numberOfReturnedProperties)
496    *numberOfReturnedProperties = count;
497
498  return returnValue;
499}
500
501Protocol **protocol_copyProtocolList (Protocol *protocol, unsigned int *numberOfReturnedProtocols)
502{
503  unsigned int count = 0;
504  Protocol **returnValue = NULL;
505  struct objc_protocol_list* proto_list;
506
507  /* Check that it is a Protocol object before casting it to (struct
508     objc_protocol *).  */
509  if (protocol == NULL  ||  protocol->class_pointer != objc_lookUpClass ("Protocol"))
510    {
511      if (numberOfReturnedProtocols)
512	*numberOfReturnedProtocols = 0;
513
514      return NULL;
515    }
516
517  /* We do not acquire any lock because protocols are currently
518     immutable.  We can freely iterate over a protocol structure.  */
519
520  /* Count how many protocols we have.  */
521  proto_list = ((struct objc_protocol *)protocol)->protocol_list;
522
523  while (proto_list)
524    {
525      count = count + proto_list->count;
526      proto_list = proto_list->next;
527    }
528
529  if (count != 0)
530    {
531      unsigned int i = 0;
532
533      /* Allocate enough memory to hold them.  */
534      returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1)));
535
536      /* Copy the protocols.  */
537      proto_list = ((struct objc_protocol *)protocol)->protocol_list;
538
539      while (proto_list)
540	{
541	  size_t j;
542	  for (j = 0; j < proto_list->count; j++)
543	    {
544	      returnValue[i] = (Protocol *)proto_list->list[j];
545	      i++;
546	    }
547	  proto_list = proto_list->next;
548	}
549
550      returnValue[i] = NULL;
551    }
552
553  if (numberOfReturnedProtocols)
554    *numberOfReturnedProtocols = count;
555
556  return returnValue;
557}
558