OSDN Git Service

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