OSDN Git Service

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