xref: /netbsd-src/external/gpl3/gcc.old/dist/libobjc/gc.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
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 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11 
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
20 
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see 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 */
40 typedef GC_word word;
41 typedef 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 */
57 static void
58 __objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset);
59 static void
60 __objc_gc_setup_union (GC_bitmap mask, const char *type, int offset);
61 
62 
63 static 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 
92 static 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 
152 static 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.  */
181 static 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. */
241 static 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. */
286 void
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 */
339 static 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.  */
361 void
362 class_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 
441 void
442 __objc_generate_gc_type_description (Class class __attribute__ ((__unused__)))
443 {
444 }
445 
446 void 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