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