1/* Basic data types for Objective C.
2   Copyright (C) 1998, 2002, 2004, 2005, 2006, 2009 Free Software Foundation, Inc.
3   Contributed by Ovidiu Predescu.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17Under Section 7 of GPL version 3, you are granted additional
18permissions described in the GCC Runtime Library Exception, version
193.1, as published by the Free Software Foundation.
20
21You should have received a copy of the GNU General Public License and
22a copy of the GCC Runtime Library Exception along with this program;
23see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24<http://www.gnu.org/licenses/>.  */
25
26#include "tconfig.h"
27#include "objc/objc.h"
28#include "objc/encoding.h"
29
30#include <assert.h>
31#include <string.h>
32#include <stdlib.h>
33
34#if OBJC_WITH_GC
35
36#include <gc.h>
37#include <limits.h>
38
39/* gc_typed.h uses the following but doesn't declare them */
40typedef GC_word word;
41typedef GC_signed_word signed_word;
42#define BITS_PER_WORD (CHAR_BIT * sizeof (word))
43
44#include <gc_typed.h>
45
46/* The following functions set up in `mask` the corresponding pointers.
47   The offset is incremented with the size of the type.  */
48
49#define ROUND(V, A) \
50  ({ typeof (V) __v = (V); typeof (A) __a = (A); \
51     __a * ((__v+__a - 1)/__a); })
52
53#define SET_BIT_FOR_OFFSET(mask, offset) \
54  GC_set_bit (mask, offset / sizeof (void *))
55
56/* Some prototypes */
57static void
58__objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset);
59static void
60__objc_gc_setup_union (GC_bitmap mask, const char *type, int offset);
61
62
63static void
64__objc_gc_setup_array (GC_bitmap mask, const char *type, int offset)
65{
66  int i, len = atoi (type + 1);
67
68  while (isdigit (*++type))
69    /* do nothing */;		/* skip the size of the array */
70
71  switch (*type) {
72  case _C_ARY_B:
73    for (i = 0; i < len; i++)
74      __objc_gc_setup_array (mask, type, offset);
75    break;
76
77  case _C_STRUCT_B:
78    for (i = 0; i < len; i++)
79      __objc_gc_setup_struct (mask, type, offset);
80    break;
81
82  case _C_UNION_B:
83    for (i = 0; i < len; i++)
84      __objc_gc_setup_union (mask, type, offset);
85    break;
86
87  default:
88    break;
89  }
90}
91
92static void
93__objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset)
94{
95  struct objc_struct_layout layout;
96  unsigned int position;
97  const char *mtype;
98
99  objc_layout_structure (type, &layout);
100
101  while (objc_layout_structure_next_member (&layout))
102    {
103      BOOL gc_invisible = NO;
104
105      objc_layout_structure_get_info (&layout, &position, NULL, &mtype);
106
107      /* Skip the variable name */
108      if (*mtype == '"')
109	{
110	  for (mtype++; *mtype++ != '"';)
111	    /* do nothing */;
112	}
113
114      if (*mtype == _C_GCINVISIBLE)
115	{
116	  gc_invisible = YES;
117	  mtype++;
118	}
119
120      /* Add to position the offset of this structure */
121      position += offset;
122
123      switch (*mtype) {
124      case _C_ID:
125      case _C_CLASS:
126      case _C_SEL:
127      case _C_PTR:
128      case _C_CHARPTR:
129      case _C_ATOM:
130	if (! gc_invisible)
131	  SET_BIT_FOR_OFFSET (mask, position);
132	break;
133
134      case _C_ARY_B:
135	__objc_gc_setup_array (mask, mtype, position);
136	break;
137
138      case _C_STRUCT_B:
139	__objc_gc_setup_struct (mask, mtype, position);
140	break;
141
142      case _C_UNION_B:
143	__objc_gc_setup_union (mask, mtype, position);
144	break;
145
146      default:
147        break;
148      }
149    }
150}
151
152static void
153__objc_gc_setup_union (GC_bitmap mask, const char *type, int offset)
154{
155  /* Sub-optimal, quick implementation: assume the union is made of
156     pointers, set up the mask accordingly. */
157
158  int i, size, align;
159
160  /* Skip the variable name */
161  if (*type == '"')
162    {
163      for (type++; *type++ != '"';)
164	/* do nothing */;
165    }
166
167  size = objc_sizeof_type (type);
168  align = objc_alignof_type (type);
169
170  offset = ROUND (offset, align);
171  for (i = 0; i < size; i += sizeof (void *))
172    {
173      SET_BIT_FOR_OFFSET (mask, offset);
174      offset += sizeof (void *);
175    }
176}
177
178
179/* Iterates over the types in the structure that represents the class
180   encoding and sets the bits in mask according to each ivar type.  */
181static void
182__objc_gc_type_description_from_type (GC_bitmap mask, const char *type)
183{
184  struct objc_struct_layout layout;
185  unsigned int offset, align;
186  const char *ivar_type;
187
188  objc_layout_structure (type, &layout);
189
190  while (objc_layout_structure_next_member (&layout))
191    {
192      BOOL gc_invisible = NO;
193
194      objc_layout_structure_get_info (&layout, &offset, &align, &ivar_type);
195
196      /* Skip the variable name */
197      if (*ivar_type == '"')
198	{
199	  for (ivar_type++; *ivar_type++ != '"';)
200	    /* do nothing */;
201	}
202
203      if (*ivar_type == _C_GCINVISIBLE)
204	{
205	  gc_invisible = YES;
206	  ivar_type++;
207	}
208
209      switch (*ivar_type) {
210      case _C_ID:
211      case _C_CLASS:
212      case _C_SEL:
213      case _C_PTR:
214      case _C_CHARPTR:
215        if (! gc_invisible)
216          SET_BIT_FOR_OFFSET (mask, offset);
217	break;
218
219      case _C_ARY_B:
220	__objc_gc_setup_array (mask, ivar_type, offset);
221	break;
222
223      case _C_STRUCT_B:
224	__objc_gc_setup_struct (mask, ivar_type, offset);
225	break;
226
227      case _C_UNION_B:
228	__objc_gc_setup_union (mask, ivar_type, offset);
229	break;
230
231      default:
232        break;
233      }
234    }
235}
236
237/* Computes in *type the full type encoding of this class including
238   its super classes. '*size' gives the total number of bytes allocated
239   into *type, '*current' the number of bytes used so far by the
240   encoding. */
241static void
242__objc_class_structure_encoding (Class class, char **type, int *size,
243                                 int *current)
244{
245  int i, ivar_count;
246  struct objc_ivar_list *ivars;
247
248  if (! class)
249    {
250      strcat (*type, "{");
251      (*current)++;
252      return;
253    }
254
255  /* Add the type encodings of the super classes */
256  __objc_class_structure_encoding (class->super_class, type, size, current);
257
258  ivars = class->ivars;
259  if (! ivars)
260    return;
261
262  ivar_count = ivars->ivar_count;
263
264  for (i = 0; i < ivar_count; i++)
265    {
266      struct objc_ivar *ivar = &(ivars->ivar_list[i]);
267      const char *ivar_type = ivar->ivar_type;
268      int len = strlen (ivar_type);
269
270      if (*current + len + 1 >= *size)
271        {
272          /* Increase the size of the encoding string so that it
273             contains this ivar's type. */
274          *size = ROUND (*current + len + 1, 10);
275          *type = objc_realloc (*type, *size);
276        }
277      strcat (*type + *current, ivar_type);
278      *current += len;
279    }
280}
281
282
283/* Allocates the memory that will hold the type description for class
284   and calls the __objc_class_structure_encoding that generates this
285   value. */
286void
287__objc_generate_gc_type_description (Class class)
288{
289  GC_bitmap mask;
290  int bits_no, size;
291  int type_size = 10, current;
292  char *class_structure_type;
293
294  if (! CLS_ISCLASS (class))
295    return;
296
297  /* We have to create a mask in which each bit counts for a pointer member.
298     We take into consideration all the non-pointer instance variables and we
299     round them up to the alignment. */
300
301  /* The number of bits in the mask is the size of an instance in bytes divided
302     by the size of a pointer. */
303  bits_no = (ROUND (class_get_instance_size (class), sizeof (void *))
304             / sizeof (void *));
305  size = ROUND (bits_no, BITS_PER_WORD) / BITS_PER_WORD;
306  mask = objc_atomic_malloc (size * sizeof (int));
307  memset (mask, 0, size * sizeof (int));
308
309  class_structure_type = objc_atomic_malloc (type_size);
310  *class_structure_type = current = 0;
311  __objc_class_structure_encoding (class, &class_structure_type,
312                                   &type_size, &current);
313  if (current + 1 == type_size)
314    class_structure_type = objc_realloc (class_structure_type, ++type_size);
315  strcat (class_structure_type + current, "}");
316#ifdef DEBUG
317  printf ("type description for '%s' is %s\n", class->name, class_structure_type);
318#endif
319
320  __objc_gc_type_description_from_type (mask, class_structure_type);
321  objc_free (class_structure_type);
322
323#ifdef DEBUG
324  printf ("  mask for '%s', type '%s' (bits %d, mask size %d) is:",
325	  class_structure_type, class->name, bits_no, size);
326  {
327    int i;
328    for (i = 0; i < size; i++)
329      printf (" %lx", mask[i]);
330  }
331  puts ("");
332#endif
333
334  class->gc_object_type = (void *) GC_make_descriptor (mask, bits_no);
335}
336
337
338/* Returns YES if type denotes a pointer type, NO otherwise */
339static inline BOOL
340__objc_ivar_pointer (const char *type)
341{
342  type = objc_skip_type_qualifiers (type);
343
344  return (*type == _C_ID
345          || *type == _C_CLASS
346          || *type == _C_SEL
347          || *type == _C_PTR
348          || *type == _C_CHARPTR
349          || *type == _C_ATOM);
350}
351
352
353/* Mark the instance variable whose name is given by ivarname as a
354   weak pointer (a pointer hidden to the garbage collector) if
355   gc_invisible is true. If gc_invisible is false it unmarks the
356   instance variable and makes it a normal pointer, visible to the
357   garbage collector.
358
359   This operation only makes sense on instance variables that are
360   pointers.  */
361void
362class_ivar_set_gcinvisible (Class class, const char *ivarname,
363                            BOOL gc_invisible)
364{
365  int i, ivar_count;
366  struct objc_ivar_list *ivars;
367
368  if (! class || ! ivarname)
369    return;
370
371  ivars = class->ivars;
372  if (! ivars)
373    return;
374
375  ivar_count = ivars->ivar_count;
376
377  for (i = 0; i < ivar_count; i++)
378    {
379      struct objc_ivar *ivar = &(ivars->ivar_list[i]);
380      const char *type;
381
382      if (! ivar->ivar_name || strcmp (ivar->ivar_name, ivarname))
383	continue;
384
385      assert (ivar->ivar_type);
386      type = ivar->ivar_type;
387
388      /* Skip the variable name */
389      if (*type == '"')
390	{
391	  for (type++; *type++ != '"';)
392	    /* do nothing */;
393	}
394
395      if (*type == _C_GCINVISIBLE)
396	{
397	  char *new_type;
398	  size_t len;
399
400	  if (gc_invisible || ! __objc_ivar_pointer (type))
401	    return;	/* The type of the variable already matches the
402			   requested gc_invisible type */
403
404	  /* The variable is gc_invisible so we make it gc visible.  */
405	  new_type = objc_atomic_malloc (strlen(ivar->ivar_type));
406	  len = (type - ivar->ivar_type);
407	  memcpy (new_type, ivar->ivar_type, len);
408	  new_type[len] = 0;
409	  strcat (new_type, type + 1);
410	  ivar->ivar_type = new_type;
411	}
412      else
413	{
414	  char *new_type;
415	  size_t len;
416
417	  if (! gc_invisible || ! __objc_ivar_pointer (type))
418	    return;	/* The type of the variable already matches the
419			   requested gc_invisible type */
420
421	  /* The variable is gc visible so we make it gc_invisible.  */
422	  new_type = objc_malloc (strlen(ivar->ivar_type) + 2);
423	  len = (type - ivar->ivar_type);
424	  memcpy (new_type, ivar->ivar_type, len);
425	  new_type[len] = 0;
426	  strcat (new_type, "!");
427	  strcat (new_type, type);
428	  ivar->ivar_type = new_type;
429	}
430
431      __objc_generate_gc_type_description (class);
432      return;
433    }
434
435  /* Search the instance variable in the superclasses */
436  class_ivar_set_gcinvisible (class->super_class, ivarname, gc_invisible);
437}
438
439#else /* !OBJC_WITH_GC */
440
441void
442__objc_generate_gc_type_description (Class class __attribute__ ((__unused__)))
443{
444}
445
446void class_ivar_set_gcinvisible (Class class __attribute__ ((__unused__)),
447				 const char *ivarname __attribute__ ((__unused__)),
448				 BOOL gc_invisible __attribute__ ((__unused__)))
449{
450}
451
452#endif /* OBJC_WITH_GC */
453