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