xref: /netbsd-src/external/gpl3/gcc.old/dist/libobjc/gc.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
136ac495dSmrg /* Basic data types for Objective C.
2*8feb0f0bSmrg    Copyright (C) 1998-2020 Free Software Foundation, Inc.
336ac495dSmrg    Contributed by Ovidiu Predescu.
436ac495dSmrg 
536ac495dSmrg This file is part of GCC.
636ac495dSmrg 
736ac495dSmrg GCC is free software; you can redistribute it and/or modify
836ac495dSmrg it under the terms of the GNU General Public License as published by
936ac495dSmrg the Free Software Foundation; either version 3, or (at your option)
1036ac495dSmrg any later version.
1136ac495dSmrg 
1236ac495dSmrg GCC is distributed in the hope that it will be useful,
1336ac495dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
1436ac495dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1536ac495dSmrg GNU General Public License for more details.
1636ac495dSmrg 
1736ac495dSmrg Under Section 7 of GPL version 3, you are granted additional
1836ac495dSmrg permissions described in the GCC Runtime Library Exception, version
1936ac495dSmrg 3.1, as published by the Free Software Foundation.
2036ac495dSmrg 
2136ac495dSmrg You should have received a copy of the GNU General Public License and
2236ac495dSmrg a copy of the GCC Runtime Library Exception along with this program;
2336ac495dSmrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2436ac495dSmrg <http://www.gnu.org/licenses/>.  */
2536ac495dSmrg 
2636ac495dSmrg #include "objc-private/common.h"
2736ac495dSmrg #include "objc/objc.h"
2836ac495dSmrg 
2936ac495dSmrg #if OBJC_WITH_GC
3036ac495dSmrg 
3136ac495dSmrg #include "tconfig.h"
3236ac495dSmrg #include <assert.h>
3336ac495dSmrg #include <ctype.h> /* For isdigit.  */
3436ac495dSmrg #include <string.h>
3536ac495dSmrg #include <stdlib.h>
3636ac495dSmrg #include "objc/runtime.h"
3736ac495dSmrg #include "objc-private/module-abi-8.h"
3836ac495dSmrg 
3936ac495dSmrg #include <gc/gc.h>
4036ac495dSmrg #include <limits.h>
4136ac495dSmrg 
4236ac495dSmrg /* gc_typed.h uses the following but doesn't declare them */
4336ac495dSmrg typedef GC_word word;
4436ac495dSmrg typedef GC_signed_word signed_word;
4536ac495dSmrg #define BITS_PER_WORD (CHAR_BIT * sizeof (word))
4636ac495dSmrg 
4736ac495dSmrg #include <gc/gc_typed.h>
4836ac495dSmrg 
4936ac495dSmrg /* The following functions set up in `mask` the corresponding pointers.
5036ac495dSmrg    The offset is incremented with the size of the type.  */
5136ac495dSmrg 
5236ac495dSmrg #define ROUND(V, A) \
5336ac495dSmrg   ({ typeof (V) __v = (V); typeof (A) __a = (A); \
5436ac495dSmrg      __a * ((__v+__a - 1)/__a); })
5536ac495dSmrg 
5636ac495dSmrg #define SET_BIT_FOR_OFFSET(mask, offset) \
5736ac495dSmrg   GC_set_bit (mask, offset / sizeof (void *))
5836ac495dSmrg 
5936ac495dSmrg /* Some prototypes */
6036ac495dSmrg static void
6136ac495dSmrg __objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset);
6236ac495dSmrg static void
6336ac495dSmrg __objc_gc_setup_union (GC_bitmap mask, const char *type, int offset);
6436ac495dSmrg 
6536ac495dSmrg 
6636ac495dSmrg static void
__objc_gc_setup_array(GC_bitmap mask,const char * type,int offset)6736ac495dSmrg __objc_gc_setup_array (GC_bitmap mask, const char *type, int offset)
6836ac495dSmrg {
6936ac495dSmrg   int i, len = atoi (type + 1);
7036ac495dSmrg 
7136ac495dSmrg   while (isdigit (*++type))
7236ac495dSmrg     /* do nothing */;		/* skip the size of the array */
7336ac495dSmrg 
7436ac495dSmrg   switch (*type) {
7536ac495dSmrg   case _C_ARY_B:
7636ac495dSmrg     for (i = 0; i < len; i++)
7736ac495dSmrg       __objc_gc_setup_array (mask, type, offset);
7836ac495dSmrg     break;
7936ac495dSmrg 
8036ac495dSmrg   case _C_STRUCT_B:
8136ac495dSmrg     for (i = 0; i < len; i++)
8236ac495dSmrg       __objc_gc_setup_struct (mask, type, offset);
8336ac495dSmrg     break;
8436ac495dSmrg 
8536ac495dSmrg   case _C_UNION_B:
8636ac495dSmrg     for (i = 0; i < len; i++)
8736ac495dSmrg       __objc_gc_setup_union (mask, type, offset);
8836ac495dSmrg     break;
8936ac495dSmrg 
9036ac495dSmrg   default:
9136ac495dSmrg     break;
9236ac495dSmrg   }
9336ac495dSmrg }
9436ac495dSmrg 
9536ac495dSmrg static void
__objc_gc_setup_struct(GC_bitmap mask,const char * type,int offset)9636ac495dSmrg __objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset)
9736ac495dSmrg {
9836ac495dSmrg   struct objc_struct_layout layout;
9936ac495dSmrg   unsigned int position;
10036ac495dSmrg   const char *mtype;
10136ac495dSmrg 
10236ac495dSmrg   objc_layout_structure (type, &layout);
10336ac495dSmrg 
10436ac495dSmrg   while (objc_layout_structure_next_member (&layout))
10536ac495dSmrg     {
10636ac495dSmrg       BOOL gc_invisible = NO;
10736ac495dSmrg 
10836ac495dSmrg       objc_layout_structure_get_info (&layout, &position, NULL, &mtype);
10936ac495dSmrg 
11036ac495dSmrg       /* Skip the variable name */
11136ac495dSmrg       if (*mtype == '"')
11236ac495dSmrg 	{
11336ac495dSmrg 	  for (mtype++; *mtype++ != '"';)
11436ac495dSmrg 	    /* do nothing */;
11536ac495dSmrg 	}
11636ac495dSmrg 
11736ac495dSmrg       if (*mtype == _C_GCINVISIBLE)
11836ac495dSmrg 	{
11936ac495dSmrg 	  gc_invisible = YES;
12036ac495dSmrg 	  mtype++;
12136ac495dSmrg 	}
12236ac495dSmrg 
12336ac495dSmrg       /* Add to position the offset of this structure */
12436ac495dSmrg       position += offset;
12536ac495dSmrg 
12636ac495dSmrg       switch (*mtype) {
12736ac495dSmrg       case _C_ID:
12836ac495dSmrg       case _C_CLASS:
12936ac495dSmrg       case _C_SEL:
13036ac495dSmrg       case _C_PTR:
13136ac495dSmrg       case _C_CHARPTR:
13236ac495dSmrg       case _C_ATOM:
13336ac495dSmrg 	if (! gc_invisible)
13436ac495dSmrg 	  SET_BIT_FOR_OFFSET (mask, position);
13536ac495dSmrg 	break;
13636ac495dSmrg 
13736ac495dSmrg       case _C_ARY_B:
13836ac495dSmrg 	__objc_gc_setup_array (mask, mtype, position);
13936ac495dSmrg 	break;
14036ac495dSmrg 
14136ac495dSmrg       case _C_STRUCT_B:
14236ac495dSmrg 	__objc_gc_setup_struct (mask, mtype, position);
14336ac495dSmrg 	break;
14436ac495dSmrg 
14536ac495dSmrg       case _C_UNION_B:
14636ac495dSmrg 	__objc_gc_setup_union (mask, mtype, position);
14736ac495dSmrg 	break;
14836ac495dSmrg 
14936ac495dSmrg       default:
15036ac495dSmrg         break;
15136ac495dSmrg       }
15236ac495dSmrg     }
15336ac495dSmrg }
15436ac495dSmrg 
15536ac495dSmrg static void
__objc_gc_setup_union(GC_bitmap mask,const char * type,int offset)15636ac495dSmrg __objc_gc_setup_union (GC_bitmap mask, const char *type, int offset)
15736ac495dSmrg {
15836ac495dSmrg   /* Sub-optimal, quick implementation: assume the union is made of
15936ac495dSmrg      pointers, set up the mask accordingly. */
16036ac495dSmrg 
16136ac495dSmrg   int i, size, align;
16236ac495dSmrg 
16336ac495dSmrg   /* Skip the variable name */
16436ac495dSmrg   if (*type == '"')
16536ac495dSmrg     {
16636ac495dSmrg       for (type++; *type++ != '"';)
16736ac495dSmrg 	/* do nothing */;
16836ac495dSmrg     }
16936ac495dSmrg 
17036ac495dSmrg   size = objc_sizeof_type (type);
17136ac495dSmrg   align = objc_alignof_type (type);
17236ac495dSmrg 
17336ac495dSmrg   offset = ROUND (offset, align);
17436ac495dSmrg   for (i = 0; i < size; i += sizeof (void *))
17536ac495dSmrg     {
17636ac495dSmrg       SET_BIT_FOR_OFFSET (mask, offset);
17736ac495dSmrg       offset += sizeof (void *);
17836ac495dSmrg     }
17936ac495dSmrg }
18036ac495dSmrg 
18136ac495dSmrg 
18236ac495dSmrg /* Iterates over the types in the structure that represents the class
18336ac495dSmrg    encoding and sets the bits in mask according to each ivar type.  */
18436ac495dSmrg static void
__objc_gc_type_description_from_type(GC_bitmap mask,const char * type)18536ac495dSmrg __objc_gc_type_description_from_type (GC_bitmap mask, const char *type)
18636ac495dSmrg {
18736ac495dSmrg   struct objc_struct_layout layout;
18836ac495dSmrg   unsigned int offset, align;
18936ac495dSmrg   const char *ivar_type;
19036ac495dSmrg 
19136ac495dSmrg   objc_layout_structure (type, &layout);
19236ac495dSmrg 
19336ac495dSmrg   while (objc_layout_structure_next_member (&layout))
19436ac495dSmrg     {
19536ac495dSmrg       BOOL gc_invisible = NO;
19636ac495dSmrg 
19736ac495dSmrg       objc_layout_structure_get_info (&layout, &offset, &align, &ivar_type);
19836ac495dSmrg 
19936ac495dSmrg       /* Skip the variable name */
20036ac495dSmrg       if (*ivar_type == '"')
20136ac495dSmrg 	{
20236ac495dSmrg 	  for (ivar_type++; *ivar_type++ != '"';)
20336ac495dSmrg 	    /* do nothing */;
20436ac495dSmrg 	}
20536ac495dSmrg 
20636ac495dSmrg       if (*ivar_type == _C_GCINVISIBLE)
20736ac495dSmrg 	{
20836ac495dSmrg 	  gc_invisible = YES;
20936ac495dSmrg 	  ivar_type++;
21036ac495dSmrg 	}
21136ac495dSmrg 
21236ac495dSmrg       switch (*ivar_type) {
21336ac495dSmrg       case _C_ID:
21436ac495dSmrg       case _C_CLASS:
21536ac495dSmrg       case _C_SEL:
21636ac495dSmrg       case _C_PTR:
21736ac495dSmrg       case _C_CHARPTR:
21836ac495dSmrg         if (! gc_invisible)
21936ac495dSmrg           SET_BIT_FOR_OFFSET (mask, offset);
22036ac495dSmrg 	break;
22136ac495dSmrg 
22236ac495dSmrg       case _C_ARY_B:
22336ac495dSmrg 	__objc_gc_setup_array (mask, ivar_type, offset);
22436ac495dSmrg 	break;
22536ac495dSmrg 
22636ac495dSmrg       case _C_STRUCT_B:
22736ac495dSmrg 	__objc_gc_setup_struct (mask, ivar_type, offset);
22836ac495dSmrg 	break;
22936ac495dSmrg 
23036ac495dSmrg       case _C_UNION_B:
23136ac495dSmrg 	__objc_gc_setup_union (mask, ivar_type, offset);
23236ac495dSmrg 	break;
23336ac495dSmrg 
23436ac495dSmrg       default:
23536ac495dSmrg         break;
23636ac495dSmrg       }
23736ac495dSmrg     }
23836ac495dSmrg }
23936ac495dSmrg 
24036ac495dSmrg /* Computes in *type the full type encoding of this class including
24136ac495dSmrg    its super classes. '*size' gives the total number of bytes allocated
24236ac495dSmrg    into *type, '*current' the number of bytes used so far by the
24336ac495dSmrg    encoding. */
24436ac495dSmrg static void
__objc_class_structure_encoding(Class class,char ** type,int * size,int * current)24536ac495dSmrg __objc_class_structure_encoding (Class class, char **type, int *size,
24636ac495dSmrg                                  int *current)
24736ac495dSmrg {
24836ac495dSmrg   int i, ivar_count;
24936ac495dSmrg   struct objc_ivar_list *ivars;
25036ac495dSmrg 
25136ac495dSmrg   if (! class)
25236ac495dSmrg     {
25336ac495dSmrg       strcat (*type, "{");
25436ac495dSmrg       (*current)++;
25536ac495dSmrg       return;
25636ac495dSmrg     }
25736ac495dSmrg 
25836ac495dSmrg   /* Add the type encodings of the super classes */
25936ac495dSmrg   __objc_class_structure_encoding (class->super_class, type, size, current);
26036ac495dSmrg 
26136ac495dSmrg   ivars = class->ivars;
26236ac495dSmrg   if (! ivars)
26336ac495dSmrg     return;
26436ac495dSmrg 
26536ac495dSmrg   ivar_count = ivars->ivar_count;
26636ac495dSmrg 
26736ac495dSmrg   for (i = 0; i < ivar_count; i++)
26836ac495dSmrg     {
26936ac495dSmrg       struct objc_ivar *ivar = &(ivars->ivar_list[i]);
27036ac495dSmrg       const char *ivar_type = ivar->ivar_type;
27136ac495dSmrg       int len = strlen (ivar_type);
27236ac495dSmrg 
27336ac495dSmrg       if (*current + len + 1 >= *size)
27436ac495dSmrg         {
27536ac495dSmrg           /* Increase the size of the encoding string so that it
27636ac495dSmrg              contains this ivar's type. */
27736ac495dSmrg           *size = ROUND (*current + len + 1, 10);
27836ac495dSmrg           *type = objc_realloc (*type, *size);
27936ac495dSmrg         }
28036ac495dSmrg       strcat (*type + *current, ivar_type);
28136ac495dSmrg       *current += len;
28236ac495dSmrg     }
28336ac495dSmrg }
28436ac495dSmrg 
28536ac495dSmrg 
28636ac495dSmrg /* Allocates the memory that will hold the type description for class
28736ac495dSmrg    and calls the __objc_class_structure_encoding that generates this
28836ac495dSmrg    value. */
28936ac495dSmrg void
__objc_generate_gc_type_description(Class class)29036ac495dSmrg __objc_generate_gc_type_description (Class class)
29136ac495dSmrg {
29236ac495dSmrg   GC_bitmap mask;
29336ac495dSmrg   int bits_no, size;
29436ac495dSmrg   int type_size = 10, current;
29536ac495dSmrg   char *class_structure_type;
29636ac495dSmrg 
29736ac495dSmrg   if (! CLS_ISCLASS (class))
29836ac495dSmrg     return;
29936ac495dSmrg 
30036ac495dSmrg   /* We have to create a mask in which each bit counts for a pointer member.
30136ac495dSmrg      We take into consideration all the non-pointer instance variables and we
30236ac495dSmrg      round them up to the alignment. */
30336ac495dSmrg 
30436ac495dSmrg   /* The number of bits in the mask is the size of an instance in bytes divided
30536ac495dSmrg      by the size of a pointer. */
30636ac495dSmrg   bits_no = (ROUND (class_getInstanceSize (class), sizeof (void *))
30736ac495dSmrg              / sizeof (void *));
30836ac495dSmrg   size = ROUND (bits_no, BITS_PER_WORD) / BITS_PER_WORD;
30936ac495dSmrg   mask = objc_atomic_malloc (size * sizeof (int));
31036ac495dSmrg   memset (mask, 0, size * sizeof (int));
31136ac495dSmrg 
31236ac495dSmrg   class_structure_type = objc_atomic_malloc (type_size);
31336ac495dSmrg   *class_structure_type = current = 0;
31436ac495dSmrg   __objc_class_structure_encoding (class, &class_structure_type,
31536ac495dSmrg                                    &type_size, &current);
31636ac495dSmrg   if (current + 1 == type_size)
31736ac495dSmrg     class_structure_type = objc_realloc (class_structure_type, ++type_size);
31836ac495dSmrg   strcat (class_structure_type + current, "}");
31936ac495dSmrg #ifdef DEBUG
32036ac495dSmrg   printf ("type description for '%s' is %s\n", class->name, class_structure_type);
32136ac495dSmrg #endif
32236ac495dSmrg 
32336ac495dSmrg   __objc_gc_type_description_from_type (mask, class_structure_type);
32436ac495dSmrg   objc_free (class_structure_type);
32536ac495dSmrg 
32636ac495dSmrg #ifdef DEBUG
32736ac495dSmrg   printf ("  mask for '%s', type '%s' (bits %d, mask size %d) is:",
32836ac495dSmrg 	  class_structure_type, class->name, bits_no, size);
32936ac495dSmrg   {
33036ac495dSmrg     int i;
33136ac495dSmrg     for (i = 0; i < size; i++)
33236ac495dSmrg       printf (" %lx", mask[i]);
33336ac495dSmrg   }
33436ac495dSmrg   puts ("");
33536ac495dSmrg #endif
33636ac495dSmrg 
33736ac495dSmrg   class->gc_object_type = (void *) GC_make_descriptor (mask, bits_no);
33836ac495dSmrg }
33936ac495dSmrg 
34036ac495dSmrg 
34136ac495dSmrg /* Returns YES if type denotes a pointer type, NO otherwise */
34236ac495dSmrg static inline BOOL
__objc_ivar_pointer(const char * type)34336ac495dSmrg __objc_ivar_pointer (const char *type)
34436ac495dSmrg {
34536ac495dSmrg   type = objc_skip_type_qualifiers (type);
34636ac495dSmrg 
34736ac495dSmrg   return (*type == _C_ID
34836ac495dSmrg           || *type == _C_CLASS
34936ac495dSmrg           || *type == _C_SEL
35036ac495dSmrg           || *type == _C_PTR
35136ac495dSmrg           || *type == _C_CHARPTR
35236ac495dSmrg           || *type == _C_ATOM);
35336ac495dSmrg }
35436ac495dSmrg 
35536ac495dSmrg 
35636ac495dSmrg /* Mark the instance variable whose name is given by ivarname as a
35736ac495dSmrg    weak pointer (a pointer hidden to the garbage collector) if
35836ac495dSmrg    gc_invisible is true. If gc_invisible is false it unmarks the
35936ac495dSmrg    instance variable and makes it a normal pointer, visible to the
36036ac495dSmrg    garbage collector.
36136ac495dSmrg 
36236ac495dSmrg    This operation only makes sense on instance variables that are
36336ac495dSmrg    pointers.  */
36436ac495dSmrg void
class_ivar_set_gcinvisible(Class class,const char * ivarname,BOOL gc_invisible)36536ac495dSmrg class_ivar_set_gcinvisible (Class class, const char *ivarname,
36636ac495dSmrg                             BOOL gc_invisible)
36736ac495dSmrg {
36836ac495dSmrg   int i, ivar_count;
36936ac495dSmrg   struct objc_ivar_list *ivars;
37036ac495dSmrg 
37136ac495dSmrg   if (! class || ! ivarname)
37236ac495dSmrg     return;
37336ac495dSmrg 
37436ac495dSmrg   ivars = class->ivars;
37536ac495dSmrg   if (! ivars)
37636ac495dSmrg     return;
37736ac495dSmrg 
37836ac495dSmrg   ivar_count = ivars->ivar_count;
37936ac495dSmrg 
38036ac495dSmrg   for (i = 0; i < ivar_count; i++)
38136ac495dSmrg     {
38236ac495dSmrg       struct objc_ivar *ivar = &(ivars->ivar_list[i]);
38336ac495dSmrg       const char *type;
38436ac495dSmrg 
38536ac495dSmrg       if (! ivar->ivar_name || strcmp (ivar->ivar_name, ivarname))
38636ac495dSmrg 	continue;
38736ac495dSmrg 
38836ac495dSmrg       assert (ivar->ivar_type);
38936ac495dSmrg       type = ivar->ivar_type;
39036ac495dSmrg 
39136ac495dSmrg       /* Skip the variable name */
39236ac495dSmrg       if (*type == '"')
39336ac495dSmrg 	{
39436ac495dSmrg 	  for (type++; *type++ != '"';)
39536ac495dSmrg 	    /* do nothing */;
39636ac495dSmrg 	}
39736ac495dSmrg 
39836ac495dSmrg       if (*type == _C_GCINVISIBLE)
39936ac495dSmrg 	{
40036ac495dSmrg 	  char *new_type;
40136ac495dSmrg 	  size_t len;
40236ac495dSmrg 
40336ac495dSmrg 	  if (gc_invisible || ! __objc_ivar_pointer (type))
40436ac495dSmrg 	    return;	/* The type of the variable already matches the
40536ac495dSmrg 			   requested gc_invisible type */
40636ac495dSmrg 
40736ac495dSmrg 	  /* The variable is gc_invisible so we make it gc visible.  */
40836ac495dSmrg 	  new_type = objc_atomic_malloc (strlen(ivar->ivar_type));
40936ac495dSmrg 	  len = (type - ivar->ivar_type);
41036ac495dSmrg 	  memcpy (new_type, ivar->ivar_type, len);
41136ac495dSmrg 	  new_type[len] = 0;
41236ac495dSmrg 	  strcat (new_type, type + 1);
41336ac495dSmrg 	  ivar->ivar_type = new_type;
41436ac495dSmrg 	}
41536ac495dSmrg       else
41636ac495dSmrg 	{
41736ac495dSmrg 	  char *new_type;
41836ac495dSmrg 	  size_t len;
41936ac495dSmrg 
42036ac495dSmrg 	  if (! gc_invisible || ! __objc_ivar_pointer (type))
42136ac495dSmrg 	    return;	/* The type of the variable already matches the
42236ac495dSmrg 			   requested gc_invisible type */
42336ac495dSmrg 
42436ac495dSmrg 	  /* The variable is gc visible so we make it gc_invisible.  */
42536ac495dSmrg 	  new_type = objc_malloc (strlen(ivar->ivar_type) + 2);
42636ac495dSmrg 
42736ac495dSmrg 	  /* Copy the variable name.  */
42836ac495dSmrg 	  len = (type - ivar->ivar_type);
42936ac495dSmrg 	  memcpy (new_type, ivar->ivar_type, len);
43036ac495dSmrg 	  /* Add '!'.  */
43136ac495dSmrg 	  new_type[len++] = _C_GCINVISIBLE;
43236ac495dSmrg 	  /* Copy the original types.  */
43336ac495dSmrg 	  strcpy (new_type + len, type);
43436ac495dSmrg 
43536ac495dSmrg 	  ivar->ivar_type = new_type;
43636ac495dSmrg 	}
43736ac495dSmrg 
43836ac495dSmrg       __objc_generate_gc_type_description (class);
43936ac495dSmrg       return;
44036ac495dSmrg     }
44136ac495dSmrg 
44236ac495dSmrg   /* Search the instance variable in the superclasses */
44336ac495dSmrg   class_ivar_set_gcinvisible (class->super_class, ivarname, gc_invisible);
44436ac495dSmrg }
44536ac495dSmrg 
44636ac495dSmrg #else /* !OBJC_WITH_GC */
44736ac495dSmrg 
44836ac495dSmrg void
__objc_generate_gc_type_description(Class class)44936ac495dSmrg __objc_generate_gc_type_description (Class class __attribute__ ((__unused__)))
45036ac495dSmrg {
45136ac495dSmrg }
45236ac495dSmrg 
class_ivar_set_gcinvisible(Class class,const char * ivarname,BOOL gc_invisible)45336ac495dSmrg void class_ivar_set_gcinvisible (Class class __attribute__ ((__unused__)),
45436ac495dSmrg 				 const char *ivarname __attribute__ ((__unused__)),
45536ac495dSmrg 				 BOOL gc_invisible __attribute__ ((__unused__)))
45636ac495dSmrg {
45736ac495dSmrg }
45836ac495dSmrg 
45936ac495dSmrg #endif /* OBJC_WITH_GC */
460