mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			460 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			460 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
| /* Basic data types for Objective C.
 | |
|    Copyright (C) 1998-2014 Free Software Foundation, Inc.
 | |
|    Contributed by Ovidiu Predescu.
 | |
| 
 | |
| This file is part of GCC.
 | |
| 
 | |
| GCC is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 3, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GCC is distributed in the hope that it will be useful,
 | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| GNU General Public License for more details.
 | |
| 
 | |
| Under Section 7 of GPL version 3, you are granted additional
 | |
| permissions described in the GCC Runtime Library Exception, version
 | |
| 3.1, as published by the Free Software Foundation.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License and
 | |
| a copy of the GCC Runtime Library Exception along with this program;
 | |
| see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 | |
| <http://www.gnu.org/licenses/>.  */
 | |
| 
 | |
| #include "objc-private/common.h"
 | |
| #include "objc/objc.h"
 | |
| 
 | |
| #if OBJC_WITH_GC
 | |
| 
 | |
| #include "tconfig.h"
 | |
| #include <assert.h>
 | |
| #include <ctype.h> /* For isdigit.  */
 | |
| #include <string.h>
 | |
| #include <stdlib.h>
 | |
| #include "objc/runtime.h"
 | |
| #include "objc-private/module-abi-8.h"
 | |
| 
 | |
| #include <gc.h>
 | |
| #include <limits.h>
 | |
| 
 | |
| /* gc_typed.h uses the following but doesn't declare them */
 | |
| typedef GC_word word;
 | |
| typedef GC_signed_word signed_word;
 | |
| #define BITS_PER_WORD (CHAR_BIT * sizeof (word))
 | |
| 
 | |
| #include <gc_typed.h>
 | |
| 
 | |
| /* The following functions set up in `mask` the corresponding pointers.
 | |
|    The offset is incremented with the size of the type.  */
 | |
| 
 | |
| #define ROUND(V, A) \
 | |
|   ({ typeof (V) __v = (V); typeof (A) __a = (A); \
 | |
|      __a * ((__v+__a - 1)/__a); })
 | |
| 
 | |
| #define SET_BIT_FOR_OFFSET(mask, offset) \
 | |
|   GC_set_bit (mask, offset / sizeof (void *))
 | |
| 
 | |
| /* Some prototypes */
 | |
| static void
 | |
| __objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset);
 | |
| static void
 | |
| __objc_gc_setup_union (GC_bitmap mask, const char *type, int offset);
 | |
| 
 | |
| 
 | |
| static void
 | |
| __objc_gc_setup_array (GC_bitmap mask, const char *type, int offset)
 | |
| {
 | |
|   int i, len = atoi (type + 1);
 | |
| 
 | |
|   while (isdigit (*++type))
 | |
|     /* do nothing */;		/* skip the size of the array */
 | |
| 
 | |
|   switch (*type) {
 | |
|   case _C_ARY_B:
 | |
|     for (i = 0; i < len; i++)
 | |
|       __objc_gc_setup_array (mask, type, offset);
 | |
|     break;
 | |
| 
 | |
|   case _C_STRUCT_B:
 | |
|     for (i = 0; i < len; i++)
 | |
|       __objc_gc_setup_struct (mask, type, offset);
 | |
|     break;
 | |
| 
 | |
|   case _C_UNION_B:
 | |
|     for (i = 0; i < len; i++)
 | |
|       __objc_gc_setup_union (mask, type, offset);
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void
 | |
| __objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset)
 | |
| {
 | |
|   struct objc_struct_layout layout;
 | |
|   unsigned int position;
 | |
|   const char *mtype;
 | |
| 
 | |
|   objc_layout_structure (type, &layout);
 | |
| 
 | |
|   while (objc_layout_structure_next_member (&layout))
 | |
|     {
 | |
|       BOOL gc_invisible = NO;
 | |
| 
 | |
|       objc_layout_structure_get_info (&layout, &position, NULL, &mtype);
 | |
| 
 | |
|       /* Skip the variable name */
 | |
|       if (*mtype == '"')
 | |
| 	{
 | |
| 	  for (mtype++; *mtype++ != '"';)
 | |
| 	    /* do nothing */;
 | |
| 	}
 | |
| 
 | |
|       if (*mtype == _C_GCINVISIBLE)
 | |
| 	{
 | |
| 	  gc_invisible = YES;
 | |
| 	  mtype++;
 | |
| 	}
 | |
| 
 | |
|       /* Add to position the offset of this structure */
 | |
|       position += offset;
 | |
| 
 | |
|       switch (*mtype) {
 | |
|       case _C_ID:
 | |
|       case _C_CLASS:
 | |
|       case _C_SEL:
 | |
|       case _C_PTR:
 | |
|       case _C_CHARPTR:
 | |
|       case _C_ATOM:
 | |
| 	if (! gc_invisible)
 | |
| 	  SET_BIT_FOR_OFFSET (mask, position);
 | |
| 	break;
 | |
| 
 | |
|       case _C_ARY_B:
 | |
| 	__objc_gc_setup_array (mask, mtype, position);
 | |
| 	break;
 | |
| 
 | |
|       case _C_STRUCT_B:
 | |
| 	__objc_gc_setup_struct (mask, mtype, position);
 | |
| 	break;
 | |
| 
 | |
|       case _C_UNION_B:
 | |
| 	__objc_gc_setup_union (mask, mtype, position);
 | |
| 	break;
 | |
| 
 | |
|       default:
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| __objc_gc_setup_union (GC_bitmap mask, const char *type, int offset)
 | |
| {
 | |
|   /* Sub-optimal, quick implementation: assume the union is made of
 | |
|      pointers, set up the mask accordingly. */
 | |
| 
 | |
|   int i, size, align;
 | |
| 
 | |
|   /* Skip the variable name */
 | |
|   if (*type == '"')
 | |
|     {
 | |
|       for (type++; *type++ != '"';)
 | |
| 	/* do nothing */;
 | |
|     }
 | |
| 
 | |
|   size = objc_sizeof_type (type);
 | |
|   align = objc_alignof_type (type);
 | |
| 
 | |
|   offset = ROUND (offset, align);
 | |
|   for (i = 0; i < size; i += sizeof (void *))
 | |
|     {
 | |
|       SET_BIT_FOR_OFFSET (mask, offset);
 | |
|       offset += sizeof (void *);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Iterates over the types in the structure that represents the class
 | |
|    encoding and sets the bits in mask according to each ivar type.  */
 | |
| static void
 | |
| __objc_gc_type_description_from_type (GC_bitmap mask, const char *type)
 | |
| {
 | |
|   struct objc_struct_layout layout;
 | |
|   unsigned int offset, align;
 | |
|   const char *ivar_type;
 | |
| 
 | |
|   objc_layout_structure (type, &layout);
 | |
| 
 | |
|   while (objc_layout_structure_next_member (&layout))
 | |
|     {
 | |
|       BOOL gc_invisible = NO;
 | |
| 
 | |
|       objc_layout_structure_get_info (&layout, &offset, &align, &ivar_type);
 | |
| 
 | |
|       /* Skip the variable name */
 | |
|       if (*ivar_type == '"')
 | |
| 	{
 | |
| 	  for (ivar_type++; *ivar_type++ != '"';)
 | |
| 	    /* do nothing */;
 | |
| 	}
 | |
| 
 | |
|       if (*ivar_type == _C_GCINVISIBLE)
 | |
| 	{
 | |
| 	  gc_invisible = YES;
 | |
| 	  ivar_type++;
 | |
| 	}
 | |
| 
 | |
|       switch (*ivar_type) {
 | |
|       case _C_ID:
 | |
|       case _C_CLASS:
 | |
|       case _C_SEL:
 | |
|       case _C_PTR:
 | |
|       case _C_CHARPTR:
 | |
|         if (! gc_invisible)
 | |
|           SET_BIT_FOR_OFFSET (mask, offset);
 | |
| 	break;
 | |
| 
 | |
|       case _C_ARY_B:
 | |
| 	__objc_gc_setup_array (mask, ivar_type, offset);
 | |
| 	break;
 | |
| 
 | |
|       case _C_STRUCT_B:
 | |
| 	__objc_gc_setup_struct (mask, ivar_type, offset);
 | |
| 	break;
 | |
| 
 | |
|       case _C_UNION_B:
 | |
| 	__objc_gc_setup_union (mask, ivar_type, offset);
 | |
| 	break;
 | |
| 
 | |
|       default:
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Computes in *type the full type encoding of this class including
 | |
|    its super classes. '*size' gives the total number of bytes allocated
 | |
|    into *type, '*current' the number of bytes used so far by the
 | |
|    encoding. */
 | |
| static void
 | |
| __objc_class_structure_encoding (Class class, char **type, int *size,
 | |
|                                  int *current)
 | |
| {
 | |
|   int i, ivar_count;
 | |
|   struct objc_ivar_list *ivars;
 | |
| 
 | |
|   if (! class)
 | |
|     {
 | |
|       strcat (*type, "{");
 | |
|       (*current)++;
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   /* Add the type encodings of the super classes */
 | |
|   __objc_class_structure_encoding (class->super_class, type, size, current);
 | |
| 
 | |
|   ivars = class->ivars;
 | |
|   if (! ivars)
 | |
|     return;
 | |
| 
 | |
|   ivar_count = ivars->ivar_count;
 | |
| 
 | |
|   for (i = 0; i < ivar_count; i++)
 | |
|     {
 | |
|       struct objc_ivar *ivar = &(ivars->ivar_list[i]);
 | |
|       const char *ivar_type = ivar->ivar_type;
 | |
|       int len = strlen (ivar_type);
 | |
| 
 | |
|       if (*current + len + 1 >= *size)
 | |
|         {
 | |
|           /* Increase the size of the encoding string so that it
 | |
|              contains this ivar's type. */
 | |
|           *size = ROUND (*current + len + 1, 10);
 | |
|           *type = objc_realloc (*type, *size);
 | |
|         }
 | |
|       strcat (*type + *current, ivar_type);
 | |
|       *current += len;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Allocates the memory that will hold the type description for class
 | |
|    and calls the __objc_class_structure_encoding that generates this
 | |
|    value. */
 | |
| void
 | |
| __objc_generate_gc_type_description (Class class)
 | |
| {
 | |
|   GC_bitmap mask;
 | |
|   int bits_no, size;
 | |
|   int type_size = 10, current;
 | |
|   char *class_structure_type;
 | |
| 
 | |
|   if (! CLS_ISCLASS (class))
 | |
|     return;
 | |
| 
 | |
|   /* We have to create a mask in which each bit counts for a pointer member.
 | |
|      We take into consideration all the non-pointer instance variables and we
 | |
|      round them up to the alignment. */
 | |
| 
 | |
|   /* The number of bits in the mask is the size of an instance in bytes divided
 | |
|      by the size of a pointer. */
 | |
|   bits_no = (ROUND (class_getInstanceSize (class), sizeof (void *))
 | |
|              / sizeof (void *));
 | |
|   size = ROUND (bits_no, BITS_PER_WORD) / BITS_PER_WORD;
 | |
|   mask = objc_atomic_malloc (size * sizeof (int));
 | |
|   memset (mask, 0, size * sizeof (int));
 | |
| 
 | |
|   class_structure_type = objc_atomic_malloc (type_size);
 | |
|   *class_structure_type = current = 0;
 | |
|   __objc_class_structure_encoding (class, &class_structure_type,
 | |
|                                    &type_size, ¤t);
 | |
|   if (current + 1 == type_size)
 | |
|     class_structure_type = objc_realloc (class_structure_type, ++type_size);
 | |
|   strcat (class_structure_type + current, "}");
 | |
| #ifdef DEBUG
 | |
|   printf ("type description for '%s' is %s\n", class->name, class_structure_type);
 | |
| #endif
 | |
|   
 | |
|   __objc_gc_type_description_from_type (mask, class_structure_type);
 | |
|   objc_free (class_structure_type);
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   printf ("  mask for '%s', type '%s' (bits %d, mask size %d) is:",
 | |
| 	  class_structure_type, class->name, bits_no, size);
 | |
|   {
 | |
|     int i;
 | |
|     for (i = 0; i < size; i++)
 | |
|       printf (" %lx", mask[i]);
 | |
|   }
 | |
|   puts ("");
 | |
| #endif
 | |
| 
 | |
|   class->gc_object_type = (void *) GC_make_descriptor (mask, bits_no);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Returns YES if type denotes a pointer type, NO otherwise */
 | |
| static inline BOOL
 | |
| __objc_ivar_pointer (const char *type)
 | |
| {
 | |
|   type = objc_skip_type_qualifiers (type);
 | |
| 
 | |
|   return (*type == _C_ID
 | |
|           || *type == _C_CLASS
 | |
|           || *type == _C_SEL
 | |
|           || *type == _C_PTR
 | |
|           || *type == _C_CHARPTR
 | |
|           || *type == _C_ATOM);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Mark the instance variable whose name is given by ivarname as a
 | |
|    weak pointer (a pointer hidden to the garbage collector) if
 | |
|    gc_invisible is true. If gc_invisible is false it unmarks the
 | |
|    instance variable and makes it a normal pointer, visible to the
 | |
|    garbage collector.
 | |
| 
 | |
|    This operation only makes sense on instance variables that are
 | |
|    pointers.  */
 | |
| void
 | |
| class_ivar_set_gcinvisible (Class class, const char *ivarname,
 | |
|                             BOOL gc_invisible)
 | |
| {
 | |
|   int i, ivar_count;
 | |
|   struct objc_ivar_list *ivars;
 | |
| 
 | |
|   if (! class || ! ivarname)
 | |
|     return;
 | |
| 
 | |
|   ivars = class->ivars;
 | |
|   if (! ivars)
 | |
|     return;
 | |
| 
 | |
|   ivar_count = ivars->ivar_count;
 | |
| 
 | |
|   for (i = 0; i < ivar_count; i++)
 | |
|     {
 | |
|       struct objc_ivar *ivar = &(ivars->ivar_list[i]);
 | |
|       const char *type;
 | |
| 
 | |
|       if (! ivar->ivar_name || strcmp (ivar->ivar_name, ivarname))
 | |
| 	continue;
 | |
| 
 | |
|       assert (ivar->ivar_type);
 | |
|       type = ivar->ivar_type;
 | |
| 
 | |
|       /* Skip the variable name */
 | |
|       if (*type == '"')
 | |
| 	{
 | |
| 	  for (type++; *type++ != '"';)
 | |
| 	    /* do nothing */;
 | |
| 	}
 | |
| 
 | |
|       if (*type == _C_GCINVISIBLE)
 | |
| 	{
 | |
| 	  char *new_type;
 | |
| 	  size_t len;
 | |
| 
 | |
| 	  if (gc_invisible || ! __objc_ivar_pointer (type))
 | |
| 	    return;	/* The type of the variable already matches the
 | |
| 			   requested gc_invisible type */
 | |
| 
 | |
| 	  /* The variable is gc_invisible so we make it gc visible.  */
 | |
| 	  new_type = objc_atomic_malloc (strlen(ivar->ivar_type));
 | |
| 	  len = (type - ivar->ivar_type);
 | |
| 	  memcpy (new_type, ivar->ivar_type, len);
 | |
| 	  new_type[len] = 0;
 | |
| 	  strcat (new_type, type + 1);
 | |
| 	  ivar->ivar_type = new_type;
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  char *new_type;
 | |
| 	  size_t len;
 | |
| 
 | |
| 	  if (! gc_invisible || ! __objc_ivar_pointer (type))
 | |
| 	    return;	/* The type of the variable already matches the
 | |
| 			   requested gc_invisible type */
 | |
| 
 | |
| 	  /* The variable is gc visible so we make it gc_invisible.  */
 | |
| 	  new_type = objc_malloc (strlen(ivar->ivar_type) + 2);
 | |
| 
 | |
| 	  /* Copy the variable name.  */
 | |
| 	  len = (type - ivar->ivar_type);
 | |
| 	  memcpy (new_type, ivar->ivar_type, len);
 | |
| 	  /* Add '!'.  */
 | |
| 	  new_type[len++] = _C_GCINVISIBLE;
 | |
| 	  /* Copy the original types.  */
 | |
| 	  strcpy (new_type + len, type);
 | |
| 
 | |
| 	  ivar->ivar_type = new_type;
 | |
| 	}
 | |
| 
 | |
|       __objc_generate_gc_type_description (class);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   /* Search the instance variable in the superclasses */
 | |
|   class_ivar_set_gcinvisible (class->super_class, ivarname, gc_invisible);
 | |
| }
 | |
| 
 | |
| #else /* !OBJC_WITH_GC */
 | |
| 
 | |
| void
 | |
| __objc_generate_gc_type_description (Class class __attribute__ ((__unused__)))
 | |
| {
 | |
| }
 | |
| 
 | |
| void class_ivar_set_gcinvisible (Class class __attribute__ ((__unused__)),
 | |
| 				 const char *ivarname __attribute__ ((__unused__)),
 | |
| 				 BOOL gc_invisible __attribute__ ((__unused__)))
 | |
| {
 | |
| }
 | |
| 
 | |
| #endif /* OBJC_WITH_GC */
 |