1  /* GNU Objective C Runtime ivar 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 <string.h>                    /* For strcmp.  */
      31  #include <stdlib.h>                    /* For malloc.  */
      32  
      33  struct objc_ivar *
      34  class_getInstanceVariable (Class class_, const char *name)
      35  {
      36    if (class_ != Nil  &&  name != NULL  &&  ! CLS_IS_IN_CONSTRUCTION (class_))
      37      {
      38        while (class_ != Nil)
      39  	{
      40  	  struct objc_ivar_list *ivars = class_->ivars;
      41  	  if (ivars != NULL)
      42  	    {
      43  	      int i;
      44  	      
      45  	      for (i = 0; i < ivars->ivar_count; i++)
      46  		{
      47  		  struct objc_ivar *ivar = &(ivars->ivar_list[i]);
      48  		  
      49  		  if (!strcmp (ivar->ivar_name, name))
      50  		    return ivar;
      51  		}
      52  	    }
      53  	  class_ = class_getSuperclass (class_);
      54  	}
      55      }
      56    return NULL;
      57  }
      58  
      59  struct objc_ivar *
      60  class_getClassVariable (Class class_, const char *name)
      61  {
      62    if (class_ == Nil)
      63      return NULL;
      64  
      65    /* Logically, since a class is an instance of its meta-class, and
      66       since its class methods are the instance methods of the
      67       meta-class, class variables should be instance variables of the
      68       meta-class.  That is different from the normal use of having
      69       'static' variables in the class implementation file, because
      70       every class would have its own variables.
      71  
      72       Anyway, it is all speculative at this stage, but if we get class
      73       variables in Objective-C, it is conceivable that this
      74       implementation should work.  */
      75    return class_getInstanceVariable (class_->class_pointer, name);
      76  }
      77  
      78  void *
      79  object_getIndexedIvars (id object)
      80  {
      81    if (object == nil)
      82      return NULL;
      83    else
      84      return (void *)(((char *)object) 
      85  		    + object->class_pointer->instance_size);
      86  }
      87  
      88  struct objc_ivar *
      89  object_getInstanceVariable (id object, const char *name, void **returnValue)
      90  {
      91    if (object == nil  ||  name == NULL)
      92      return NULL;
      93    else
      94      {
      95        struct objc_ivar * variable = class_getInstanceVariable (object->class_pointer, name);
      96  
      97        if (variable != NULL  &&  returnValue != NULL)
      98  	{
      99  	  char *location = (char *)object + variable->ivar_offset;
     100  	 
     101  	  *returnValue = *((id *)location);
     102  	}
     103  
     104        return variable;
     105      }
     106  }
     107  
     108  struct objc_ivar *
     109  object_setInstanceVariable (id object, const char *name, void *newValue)
     110  {
     111    if (object == nil  ||  name == NULL)
     112      return NULL;
     113    else
     114      {
     115        struct objc_ivar * variable = class_getInstanceVariable (object->class_pointer, name);
     116  
     117        if (variable != NULL)
     118  	{
     119  	  char *location = (char *)object + variable->ivar_offset;
     120  	  
     121  	  *((id *)location) = (id)newValue;
     122  	}
     123  
     124        return variable;
     125      }
     126  }
     127  
     128  id object_getIvar (id object, struct objc_ivar * variable)
     129  {
     130    if (object == nil  ||  variable == NULL)
     131      return nil;
     132    else
     133      {
     134        char *location = (char *)object + variable->ivar_offset;
     135  
     136        return *((id *)location);
     137      }
     138  }
     139  
     140  void object_setIvar (id object, struct objc_ivar * variable, id value)
     141  {
     142    if (object == nil  ||  variable == NULL)
     143      return;
     144    else
     145      {
     146        char *location = (char *)object + variable->ivar_offset;
     147  
     148        *((id *)location) = value;
     149      }
     150  }
     151  
     152  const char * ivar_getName (struct objc_ivar * variable)
     153  {
     154    if (variable == NULL)
     155      return NULL;
     156  
     157    return variable->ivar_name;
     158  }
     159  
     160  ptrdiff_t ivar_getOffset (struct objc_ivar * variable)
     161  {
     162    if (variable == NULL)
     163      return 0;
     164  
     165    return (ptrdiff_t)(variable->ivar_offset);
     166  }
     167  
     168  const char * ivar_getTypeEncoding (struct objc_ivar * variable)
     169  {
     170    if (variable == NULL)
     171      return NULL;
     172  
     173    return variable->ivar_type;
     174  }
     175  
     176  struct objc_ivar ** class_copyIvarList (Class class_, unsigned int *numberOfReturnedIvars)
     177  {
     178    unsigned int count = 0;
     179    struct objc_ivar **returnValue = NULL;
     180    struct objc_ivar_list* ivar_list;
     181  
     182    if (class_ == Nil  ||  CLS_IS_IN_CONSTRUCTION (class_) || !class_->ivars)
     183      {
     184        if (numberOfReturnedIvars)
     185  	*numberOfReturnedIvars = 0;
     186        return NULL;
     187      }
     188      
     189    /* Count how many ivars we have.  */
     190    ivar_list = class_->ivars;
     191    count = ivar_list->ivar_count;
     192  
     193    if (count != 0)
     194      {
     195        unsigned int i = 0;
     196        
     197        /* Allocate enough memory to hold them.  */
     198        returnValue = (struct objc_ivar **)(malloc (sizeof (struct objc_ivar *) * (count + 1)));
     199        
     200        /* Copy the ivars.  */
     201        for (i = 0; i < count; i++)
     202  	returnValue[i] = &(ivar_list->ivar_list[i]);
     203        
     204        returnValue[i] = NULL;
     205      }
     206    
     207    if (numberOfReturnedIvars)
     208      *numberOfReturnedIvars = count;
     209  
     210    return returnValue;
     211  }
     212  
     213  BOOL
     214  class_addIvar (Class class_, const char * ivar_name, size_t size,
     215  	       unsigned char log_2_of_alignment, const char *type)
     216  {
     217    struct objc_ivar_list *ivars;
     218  
     219    if (class_ == Nil
     220        || (! CLS_IS_IN_CONSTRUCTION (class_))  
     221        || ivar_name == NULL  
     222        || (strcmp (ivar_name, "") == 0)
     223        || size == 0
     224        || type == NULL)
     225      return NO;
     226  
     227    /* Check if the class has an instance variable with that name
     228       already.  */
     229    ivars = class_->ivars;
     230  
     231    if (ivars != NULL)
     232      {
     233        int i;
     234        
     235        for (i = 0; i < ivars->ivar_count; i++)
     236  	{
     237  	  struct objc_ivar *ivar = &(ivars->ivar_list[i]);
     238  	  
     239  	  if (strcmp (ivar->ivar_name, ivar_name) == 0)
     240  	    return NO;
     241  	}
     242      }
     243  
     244    /* Ok, no direct ivars.  Check superclasses.  */
     245    if (class_getInstanceVariable (objc_getClass ((char *)(class_->super_class)),
     246  				 ivar_name))
     247      return NO;
     248  
     249    /* Good.  Create space for the new instance variable.  */
     250    if (ivars)
     251      {
     252        int ivar_count = ivars->ivar_count + 1;
     253        int new_size = sizeof (struct objc_ivar_list) 
     254  	+ (ivar_count - 1) * sizeof (struct objc_ivar);
     255        
     256        ivars = (struct objc_ivar_list*) objc_realloc (ivars, new_size);
     257        ivars->ivar_count = ivar_count;
     258        class_->ivars = ivars;
     259      }
     260    else
     261      {
     262        int new_size = sizeof (struct objc_ivar_list);
     263        
     264        ivars = (struct objc_ivar_list*) objc_malloc (new_size);
     265        ivars->ivar_count = 1;
     266        class_->ivars = ivars;
     267      }
     268      
     269    /* Now ivars is set to a list of instance variables of the right
     270       size. */
     271    {
     272      struct objc_ivar *ivar = &(ivars->ivar_list[ivars->ivar_count - 1]);
     273      unsigned int alignment = 1 << log_2_of_alignment;
     274      int misalignment;
     275      
     276      ivar->ivar_name = objc_malloc (strlen (ivar_name) + 1);
     277      strcpy ((char *)ivar->ivar_name, ivar_name);
     278  
     279      ivar->ivar_type = objc_malloc (strlen (type) + 1);
     280      strcpy ((char *)ivar->ivar_type, type);
     281  
     282      /* The new instance variable is placed at the end of the existing
     283         instance_size, at the first byte that is aligned with
     284         alignment.  */
     285      misalignment = class_->instance_size % alignment;
     286      
     287      if (misalignment == 0)
     288        ivar->ivar_offset = class_->instance_size;
     289      else
     290        ivar->ivar_offset = class_->instance_size - misalignment + alignment;
     291      
     292      class_->instance_size = ivar->ivar_offset + size;
     293    }
     294    
     295    return YES;
     296  }
     297  
     298  
     299  const char *
     300  property_getName (struct objc_property * property __attribute__ ((__unused__)))
     301  {
     302    if (property == NULL)
     303      return NULL;
     304  
     305    /* TODO: New ABI.  */
     306    /* The current ABI does not have any information on properties.  */
     307    return NULL;
     308  }
     309  
     310  const char *
     311  property_getAttributes (struct objc_property * property __attribute__ ((__unused__)))
     312  {
     313    if (property == NULL)
     314      return NULL;
     315  
     316    /* TODO: New ABI.  */
     317    /* The current ABI does not have any information on properties.  */
     318    return NULL;
     319  }
     320  
     321  struct objc_property *
     322  class_getProperty (Class class_ __attribute__ ((__unused__)),
     323  		   const char *propertyName __attribute__ ((__unused__)))
     324  {
     325    if (class_ == NULL  ||  propertyName == NULL)
     326      return NULL;
     327  
     328    /* TODO: New ABI.  */
     329    /* The current ABI does not have any information on class properties.  */
     330    return NULL;
     331  }
     332  
     333  struct objc_property ** 
     334  class_copyPropertyList (Class class_ __attribute__ ((__unused__)), 
     335  			unsigned int *numberOfReturnedProperties __attribute__ ((__unused__)))
     336  {
     337    if (class_ == Nil)
     338      {
     339        if (numberOfReturnedProperties)
     340  	*numberOfReturnedProperties = 0;
     341        return NULL;
     342      }
     343  
     344    /* TODO: New ABI.  */
     345    /* The current ABI does not have any information on class properties.  */
     346    if (numberOfReturnedProperties)
     347      *numberOfReturnedProperties = 0;
     348  
     349    return NULL;
     350  }
     351  
     352  const char *
     353  class_getIvarLayout (Class class_ __attribute__ ((__unused__)))
     354  {
     355    return NULL;
     356  }
     357  
     358  const char *
     359  class_getWeakIvarLayout (Class class_ __attribute__ ((__unused__)))
     360  {
     361    return NULL;
     362  }
     363  
     364  void
     365  class_setIvarLayout (Class class_ __attribute__ ((__unused__)),
     366  		     const char *layout __attribute__ ((__unused__)))
     367  {
     368    return;
     369  }
     370  
     371  void
     372  class_setWeakIvarLayout (Class class_ __attribute__ ((__unused__)),
     373  			 const char *layout __attribute__ ((__unused__)))
     374  {
     375    return;
     376  }