source: trunk/third/gcc/libobjc/gc.c @ 18474

Revision 18474, 11.4 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18473, which included commits to RCS files with non-trunk default branches.
Line 
1/* Basic data types for Objective C.
2   Copyright (C) 1998 Free Software Foundation, Inc.
3   Contributed by Ovidiu Predescu.
4
5This file is part of GNU CC.
6
7GNU CC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU CC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU CC; see the file COPYING.  If not, write to
19the Free Software Foundation, 59 Temple Place - Suite 330,
20Boston, 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 */
40typedef GC_word word;
41typedef 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 */
68static void
69__objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset);
70static void
71__objc_gc_setup_union (GC_bitmap mask, const char *type, int offset);
72
73
74static 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
103static 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
163static 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.  */
192static 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. */
252static 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. */
297void
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 */
350static 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.  */
372void
373class_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
448void
449__objc_generate_gc_type_description (Class class)
450{
451}
452
453void class_ivar_set_gcinvisible (Class class,
454                                 const char* ivarname,
455                                 BOOL gc_invisible)
456{
457}
458
459#endif /* OBJC_WITH_GC */
Note: See TracBrowser for help on using the repository browser.