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 5This file is part of GCC. 6 7GCC 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 3, or (at your option) 10any later version. 11 12GCC 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 17Under Section 7 of GPL version 3, you are granted additional 18permissions described in the GCC Runtime Library Exception, version 193.1, as published by the Free Software Foundation. 20 21You should have received a copy of the GNU General Public License and 22a copy of the GCC Runtime Library Exception along with this program; 23see 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 */ 40typedef GC_word word; 41typedef 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 */ 57static void 58__objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset); 59static void 60__objc_gc_setup_union (GC_bitmap mask, const char *type, int offset); 61 62 63static 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 92static 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 152static 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. */ 181static 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. */ 241static 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. */ 286void 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, ¤t); 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 */ 339static 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. */ 361void 362class_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 441void 442__objc_generate_gc_type_description (Class class __attribute__ ((__unused__))) 443{ 444} 445 446void 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 */ 453