(root)/
gcc-13.2.0/
libobjc/
protocols.c
       1  /* GNU Objective C Runtime protocol related functions.
       2     Copyright (C) 2010-2023 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/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.  */
      39  static cache_ptr __protocols_hashtable;
      40  
      41  /* A mutex protecting the protocol_hashtable.  */
      42  static objc_mutex_t __protocols_hashtable_lock = NULL;
      43  
      44  /* Called at startup by init.c.  */
      45  void
      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.  */
      57  void
      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  
      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] = (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  
     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] == (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  
     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    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  
     265  BOOL 
     266  protocol_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  
     306  BOOL 
     307  protocol_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  
     344  const char *
     345  protocol_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  
     355  struct 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  
     395  struct 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  
     456  Property 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  
     475  Property *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  
     501  Protocol **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  }