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