OSDN Git Service

Licensing changes to GPLv3 resp. GPLv3 with GCC Runtime Exception.
[pf3gnuchains/gcc-fork.git] / libobjc / gc.c
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 */