1/* GNU Objective C Runtime ivar related functions.
2   Copyright (C) 2010-2022 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 <string.h>                    /* For strcmp.  */
31#include <stdlib.h>                    /* For malloc.  */
32
33struct objc_ivar *
34class_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
59struct objc_ivar *
60class_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
78void *
79object_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
88struct objc_ivar *
89object_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
108struct objc_ivar *
109object_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
128id 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
140void 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
152const char * ivar_getName (struct objc_ivar * variable)
153{
154  if (variable == NULL)
155    return NULL;
156
157  return variable->ivar_name;
158}
159
160ptrdiff_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
168const char * ivar_getTypeEncoding (struct objc_ivar * variable)
169{
170  if (variable == NULL)
171    return NULL;
172
173  return variable->ivar_type;
174}
175
176struct 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
213BOOL
214class_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
299const char *
300property_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
310const char *
311property_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
321struct objc_property *
322class_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
333struct objc_property **
334class_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
352const char *
353class_getIvarLayout (Class class_ __attribute__ ((__unused__)))
354{
355  return NULL;
356}
357
358const char *
359class_getWeakIvarLayout (Class class_ __attribute__ ((__unused__)))
360{
361  return NULL;
362}
363
364void
365class_setIvarLayout (Class class_ __attribute__ ((__unused__)),
366		     const char *layout __attribute__ ((__unused__)))
367{
368  return;
369}
370
371void
372class_setWeakIvarLayout (Class class_ __attribute__ ((__unused__)),
373			 const char *layout __attribute__ ((__unused__)))
374{
375  return;
376}
377