14fee23f9Smrg /* Basic data types for Objective C.
2*b1e83836Smrg Copyright (C) 1998-2022 Free Software Foundation, Inc.
34fee23f9Smrg Contributed by Ovidiu Predescu.
44fee23f9Smrg
54fee23f9Smrg This file is part of GCC.
64fee23f9Smrg
74fee23f9Smrg GCC is free software; you can redistribute it and/or modify
84fee23f9Smrg it under the terms of the GNU General Public License as published by
94fee23f9Smrg the Free Software Foundation; either version 3, or (at your option)
104fee23f9Smrg any later version.
114fee23f9Smrg
124fee23f9Smrg GCC is distributed in the hope that it will be useful,
134fee23f9Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
144fee23f9Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
154fee23f9Smrg GNU General Public License for more details.
164fee23f9Smrg
174fee23f9Smrg Under Section 7 of GPL version 3, you are granted additional
184fee23f9Smrg permissions described in the GCC Runtime Library Exception, version
194fee23f9Smrg 3.1, as published by the Free Software Foundation.
204fee23f9Smrg
214fee23f9Smrg You should have received a copy of the GNU General Public License and
224fee23f9Smrg a copy of the GCC Runtime Library Exception along with this program;
234fee23f9Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
244fee23f9Smrg <http://www.gnu.org/licenses/>. */
254fee23f9Smrg
2648fb7bfaSmrg #include "objc-private/common.h"
274fee23f9Smrg #include "objc/objc.h"
284fee23f9Smrg
294fee23f9Smrg #if OBJC_WITH_GC
304fee23f9Smrg
3148fb7bfaSmrg #include "tconfig.h"
3248fb7bfaSmrg #include <assert.h>
3348fb7bfaSmrg #include <ctype.h> /* For isdigit. */
3448fb7bfaSmrg #include <string.h>
3548fb7bfaSmrg #include <stdlib.h>
3648fb7bfaSmrg #include "objc/runtime.h"
3748fb7bfaSmrg #include "objc-private/module-abi-8.h"
3848fb7bfaSmrg
39b17d1066Smrg #include <gc/gc.h>
404fee23f9Smrg #include <limits.h>
414fee23f9Smrg
424fee23f9Smrg /* gc_typed.h uses the following but doesn't declare them */
434fee23f9Smrg typedef GC_word word;
444fee23f9Smrg typedef GC_signed_word signed_word;
454fee23f9Smrg #define BITS_PER_WORD (CHAR_BIT * sizeof (word))
464fee23f9Smrg
47b17d1066Smrg #include <gc/gc_typed.h>
484fee23f9Smrg
494fee23f9Smrg /* The following functions set up in `mask` the corresponding pointers.
504fee23f9Smrg The offset is incremented with the size of the type. */
514fee23f9Smrg
524fee23f9Smrg #define ROUND(V, A) \
534fee23f9Smrg ({ typeof (V) __v = (V); typeof (A) __a = (A); \
544fee23f9Smrg __a * ((__v+__a - 1)/__a); })
554fee23f9Smrg
564fee23f9Smrg #define SET_BIT_FOR_OFFSET(mask, offset) \
574fee23f9Smrg GC_set_bit (mask, offset / sizeof (void *))
584fee23f9Smrg
594fee23f9Smrg /* Some prototypes */
604fee23f9Smrg static void
614fee23f9Smrg __objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset);
624fee23f9Smrg static void
634fee23f9Smrg __objc_gc_setup_union (GC_bitmap mask, const char *type, int offset);
644fee23f9Smrg
654fee23f9Smrg
664fee23f9Smrg static void
__objc_gc_setup_array(GC_bitmap mask,const char * type,int offset)674fee23f9Smrg __objc_gc_setup_array (GC_bitmap mask, const char *type, int offset)
684fee23f9Smrg {
694fee23f9Smrg int i, len = atoi (type + 1);
704fee23f9Smrg
714fee23f9Smrg while (isdigit (*++type))
724fee23f9Smrg /* do nothing */; /* skip the size of the array */
734fee23f9Smrg
744fee23f9Smrg switch (*type) {
754fee23f9Smrg case _C_ARY_B:
764fee23f9Smrg for (i = 0; i < len; i++)
774fee23f9Smrg __objc_gc_setup_array (mask, type, offset);
784fee23f9Smrg break;
794fee23f9Smrg
804fee23f9Smrg case _C_STRUCT_B:
814fee23f9Smrg for (i = 0; i < len; i++)
824fee23f9Smrg __objc_gc_setup_struct (mask, type, offset);
834fee23f9Smrg break;
844fee23f9Smrg
854fee23f9Smrg case _C_UNION_B:
864fee23f9Smrg for (i = 0; i < len; i++)
874fee23f9Smrg __objc_gc_setup_union (mask, type, offset);
884fee23f9Smrg break;
894fee23f9Smrg
904fee23f9Smrg default:
914fee23f9Smrg break;
924fee23f9Smrg }
934fee23f9Smrg }
944fee23f9Smrg
954fee23f9Smrg static void
__objc_gc_setup_struct(GC_bitmap mask,const char * type,int offset)964fee23f9Smrg __objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset)
974fee23f9Smrg {
984fee23f9Smrg struct objc_struct_layout layout;
994fee23f9Smrg unsigned int position;
1004fee23f9Smrg const char *mtype;
1014fee23f9Smrg
1024fee23f9Smrg objc_layout_structure (type, &layout);
1034fee23f9Smrg
1044fee23f9Smrg while (objc_layout_structure_next_member (&layout))
1054fee23f9Smrg {
1064fee23f9Smrg BOOL gc_invisible = NO;
1074fee23f9Smrg
1084fee23f9Smrg objc_layout_structure_get_info (&layout, &position, NULL, &mtype);
1094fee23f9Smrg
1104fee23f9Smrg /* Skip the variable name */
1114fee23f9Smrg if (*mtype == '"')
1124fee23f9Smrg {
1134fee23f9Smrg for (mtype++; *mtype++ != '"';)
1144fee23f9Smrg /* do nothing */;
1154fee23f9Smrg }
1164fee23f9Smrg
1174fee23f9Smrg if (*mtype == _C_GCINVISIBLE)
1184fee23f9Smrg {
1194fee23f9Smrg gc_invisible = YES;
1204fee23f9Smrg mtype++;
1214fee23f9Smrg }
1224fee23f9Smrg
1234fee23f9Smrg /* Add to position the offset of this structure */
1244fee23f9Smrg position += offset;
1254fee23f9Smrg
1264fee23f9Smrg switch (*mtype) {
1274fee23f9Smrg case _C_ID:
1284fee23f9Smrg case _C_CLASS:
1294fee23f9Smrg case _C_SEL:
1304fee23f9Smrg case _C_PTR:
1314fee23f9Smrg case _C_CHARPTR:
1324fee23f9Smrg case _C_ATOM:
1334fee23f9Smrg if (! gc_invisible)
1344fee23f9Smrg SET_BIT_FOR_OFFSET (mask, position);
1354fee23f9Smrg break;
1364fee23f9Smrg
1374fee23f9Smrg case _C_ARY_B:
1384fee23f9Smrg __objc_gc_setup_array (mask, mtype, position);
1394fee23f9Smrg break;
1404fee23f9Smrg
1414fee23f9Smrg case _C_STRUCT_B:
1424fee23f9Smrg __objc_gc_setup_struct (mask, mtype, position);
1434fee23f9Smrg break;
1444fee23f9Smrg
1454fee23f9Smrg case _C_UNION_B:
1464fee23f9Smrg __objc_gc_setup_union (mask, mtype, position);
1474fee23f9Smrg break;
1484fee23f9Smrg
1494fee23f9Smrg default:
1504fee23f9Smrg break;
1514fee23f9Smrg }
1524fee23f9Smrg }
1534fee23f9Smrg }
1544fee23f9Smrg
1554fee23f9Smrg static void
__objc_gc_setup_union(GC_bitmap mask,const char * type,int offset)1564fee23f9Smrg __objc_gc_setup_union (GC_bitmap mask, const char *type, int offset)
1574fee23f9Smrg {
1584fee23f9Smrg /* Sub-optimal, quick implementation: assume the union is made of
1594fee23f9Smrg pointers, set up the mask accordingly. */
1604fee23f9Smrg
1614fee23f9Smrg int i, size, align;
1624fee23f9Smrg
1634fee23f9Smrg /* Skip the variable name */
1644fee23f9Smrg if (*type == '"')
1654fee23f9Smrg {
1664fee23f9Smrg for (type++; *type++ != '"';)
1674fee23f9Smrg /* do nothing */;
1684fee23f9Smrg }
1694fee23f9Smrg
1704fee23f9Smrg size = objc_sizeof_type (type);
1714fee23f9Smrg align = objc_alignof_type (type);
1724fee23f9Smrg
1734fee23f9Smrg offset = ROUND (offset, align);
1744fee23f9Smrg for (i = 0; i < size; i += sizeof (void *))
1754fee23f9Smrg {
1764fee23f9Smrg SET_BIT_FOR_OFFSET (mask, offset);
1774fee23f9Smrg offset += sizeof (void *);
1784fee23f9Smrg }
1794fee23f9Smrg }
1804fee23f9Smrg
1814fee23f9Smrg
1824fee23f9Smrg /* Iterates over the types in the structure that represents the class
1834fee23f9Smrg encoding and sets the bits in mask according to each ivar type. */
1844fee23f9Smrg static void
__objc_gc_type_description_from_type(GC_bitmap mask,const char * type)1854fee23f9Smrg __objc_gc_type_description_from_type (GC_bitmap mask, const char *type)
1864fee23f9Smrg {
1874fee23f9Smrg struct objc_struct_layout layout;
1884fee23f9Smrg unsigned int offset, align;
1894fee23f9Smrg const char *ivar_type;
1904fee23f9Smrg
1914fee23f9Smrg objc_layout_structure (type, &layout);
1924fee23f9Smrg
1934fee23f9Smrg while (objc_layout_structure_next_member (&layout))
1944fee23f9Smrg {
1954fee23f9Smrg BOOL gc_invisible = NO;
1964fee23f9Smrg
1974fee23f9Smrg objc_layout_structure_get_info (&layout, &offset, &align, &ivar_type);
1984fee23f9Smrg
1994fee23f9Smrg /* Skip the variable name */
2004fee23f9Smrg if (*ivar_type == '"')
2014fee23f9Smrg {
2024fee23f9Smrg for (ivar_type++; *ivar_type++ != '"';)
2034fee23f9Smrg /* do nothing */;
2044fee23f9Smrg }
2054fee23f9Smrg
2064fee23f9Smrg if (*ivar_type == _C_GCINVISIBLE)
2074fee23f9Smrg {
2084fee23f9Smrg gc_invisible = YES;
2094fee23f9Smrg ivar_type++;
2104fee23f9Smrg }
2114fee23f9Smrg
2124fee23f9Smrg switch (*ivar_type) {
2134fee23f9Smrg case _C_ID:
2144fee23f9Smrg case _C_CLASS:
2154fee23f9Smrg case _C_SEL:
2164fee23f9Smrg case _C_PTR:
2174fee23f9Smrg case _C_CHARPTR:
2184fee23f9Smrg if (! gc_invisible)
2194fee23f9Smrg SET_BIT_FOR_OFFSET (mask, offset);
2204fee23f9Smrg break;
2214fee23f9Smrg
2224fee23f9Smrg case _C_ARY_B:
2234fee23f9Smrg __objc_gc_setup_array (mask, ivar_type, offset);
2244fee23f9Smrg break;
2254fee23f9Smrg
2264fee23f9Smrg case _C_STRUCT_B:
2274fee23f9Smrg __objc_gc_setup_struct (mask, ivar_type, offset);
2284fee23f9Smrg break;
2294fee23f9Smrg
2304fee23f9Smrg case _C_UNION_B:
2314fee23f9Smrg __objc_gc_setup_union (mask, ivar_type, offset);
2324fee23f9Smrg break;
2334fee23f9Smrg
2344fee23f9Smrg default:
2354fee23f9Smrg break;
2364fee23f9Smrg }
2374fee23f9Smrg }
2384fee23f9Smrg }
2394fee23f9Smrg
2404fee23f9Smrg /* Computes in *type the full type encoding of this class including
2414fee23f9Smrg its super classes. '*size' gives the total number of bytes allocated
2424fee23f9Smrg into *type, '*current' the number of bytes used so far by the
2434fee23f9Smrg encoding. */
2444fee23f9Smrg static void
__objc_class_structure_encoding(Class class,char ** type,int * size,int * current)2454fee23f9Smrg __objc_class_structure_encoding (Class class, char **type, int *size,
2464fee23f9Smrg int *current)
2474fee23f9Smrg {
2484fee23f9Smrg int i, ivar_count;
2494fee23f9Smrg struct objc_ivar_list *ivars;
2504fee23f9Smrg
2514fee23f9Smrg if (! class)
2524fee23f9Smrg {
2534fee23f9Smrg strcat (*type, "{");
2544fee23f9Smrg (*current)++;
2554fee23f9Smrg return;
2564fee23f9Smrg }
2574fee23f9Smrg
2584fee23f9Smrg /* Add the type encodings of the super classes */
2594fee23f9Smrg __objc_class_structure_encoding (class->super_class, type, size, current);
2604fee23f9Smrg
2614fee23f9Smrg ivars = class->ivars;
2624fee23f9Smrg if (! ivars)
2634fee23f9Smrg return;
2644fee23f9Smrg
2654fee23f9Smrg ivar_count = ivars->ivar_count;
2664fee23f9Smrg
2674fee23f9Smrg for (i = 0; i < ivar_count; i++)
2684fee23f9Smrg {
2694fee23f9Smrg struct objc_ivar *ivar = &(ivars->ivar_list[i]);
2704fee23f9Smrg const char *ivar_type = ivar->ivar_type;
2714fee23f9Smrg int len = strlen (ivar_type);
2724fee23f9Smrg
2734fee23f9Smrg if (*current + len + 1 >= *size)
2744fee23f9Smrg {
2754fee23f9Smrg /* Increase the size of the encoding string so that it
2764fee23f9Smrg contains this ivar's type. */
2774fee23f9Smrg *size = ROUND (*current + len + 1, 10);
2784fee23f9Smrg *type = objc_realloc (*type, *size);
2794fee23f9Smrg }
2804fee23f9Smrg strcat (*type + *current, ivar_type);
2814fee23f9Smrg *current += len;
2824fee23f9Smrg }
2834fee23f9Smrg }
2844fee23f9Smrg
2854fee23f9Smrg
2864fee23f9Smrg /* Allocates the memory that will hold the type description for class
2874fee23f9Smrg and calls the __objc_class_structure_encoding that generates this
2884fee23f9Smrg value. */
2894fee23f9Smrg void
__objc_generate_gc_type_description(Class class)2904fee23f9Smrg __objc_generate_gc_type_description (Class class)
2914fee23f9Smrg {
2924fee23f9Smrg GC_bitmap mask;
2934fee23f9Smrg int bits_no, size;
2944fee23f9Smrg int type_size = 10, current;
2954fee23f9Smrg char *class_structure_type;
2964fee23f9Smrg
2974fee23f9Smrg if (! CLS_ISCLASS (class))
2984fee23f9Smrg return;
2994fee23f9Smrg
3004fee23f9Smrg /* We have to create a mask in which each bit counts for a pointer member.
3014fee23f9Smrg We take into consideration all the non-pointer instance variables and we
3024fee23f9Smrg round them up to the alignment. */
3034fee23f9Smrg
3044fee23f9Smrg /* The number of bits in the mask is the size of an instance in bytes divided
3054fee23f9Smrg by the size of a pointer. */
30648fb7bfaSmrg bits_no = (ROUND (class_getInstanceSize (class), sizeof (void *))
3074fee23f9Smrg / sizeof (void *));
3084fee23f9Smrg size = ROUND (bits_no, BITS_PER_WORD) / BITS_PER_WORD;
3094fee23f9Smrg mask = objc_atomic_malloc (size * sizeof (int));
3104fee23f9Smrg memset (mask, 0, size * sizeof (int));
3114fee23f9Smrg
3124fee23f9Smrg class_structure_type = objc_atomic_malloc (type_size);
3134fee23f9Smrg *class_structure_type = current = 0;
3144fee23f9Smrg __objc_class_structure_encoding (class, &class_structure_type,
3154fee23f9Smrg &type_size, ¤t);
3164fee23f9Smrg if (current + 1 == type_size)
3174fee23f9Smrg class_structure_type = objc_realloc (class_structure_type, ++type_size);
3184fee23f9Smrg strcat (class_structure_type + current, "}");
3194fee23f9Smrg #ifdef DEBUG
3204fee23f9Smrg printf ("type description for '%s' is %s\n", class->name, class_structure_type);
3214fee23f9Smrg #endif
3224fee23f9Smrg
3234fee23f9Smrg __objc_gc_type_description_from_type (mask, class_structure_type);
3244fee23f9Smrg objc_free (class_structure_type);
3254fee23f9Smrg
3264fee23f9Smrg #ifdef DEBUG
3274fee23f9Smrg printf (" mask for '%s', type '%s' (bits %d, mask size %d) is:",
3284fee23f9Smrg class_structure_type, class->name, bits_no, size);
3294fee23f9Smrg {
3304fee23f9Smrg int i;
3314fee23f9Smrg for (i = 0; i < size; i++)
3324fee23f9Smrg printf (" %lx", mask[i]);
3334fee23f9Smrg }
3344fee23f9Smrg puts ("");
3354fee23f9Smrg #endif
3364fee23f9Smrg
3374fee23f9Smrg class->gc_object_type = (void *) GC_make_descriptor (mask, bits_no);
3384fee23f9Smrg }
3394fee23f9Smrg
3404fee23f9Smrg
3414fee23f9Smrg /* Returns YES if type denotes a pointer type, NO otherwise */
3424fee23f9Smrg static inline BOOL
__objc_ivar_pointer(const char * type)3434fee23f9Smrg __objc_ivar_pointer (const char *type)
3444fee23f9Smrg {
3454fee23f9Smrg type = objc_skip_type_qualifiers (type);
3464fee23f9Smrg
3474fee23f9Smrg return (*type == _C_ID
3484fee23f9Smrg || *type == _C_CLASS
3494fee23f9Smrg || *type == _C_SEL
3504fee23f9Smrg || *type == _C_PTR
3514fee23f9Smrg || *type == _C_CHARPTR
3524fee23f9Smrg || *type == _C_ATOM);
3534fee23f9Smrg }
3544fee23f9Smrg
3554fee23f9Smrg
3564fee23f9Smrg /* Mark the instance variable whose name is given by ivarname as a
3574fee23f9Smrg weak pointer (a pointer hidden to the garbage collector) if
3584fee23f9Smrg gc_invisible is true. If gc_invisible is false it unmarks the
3594fee23f9Smrg instance variable and makes it a normal pointer, visible to the
3604fee23f9Smrg garbage collector.
3614fee23f9Smrg
3624fee23f9Smrg This operation only makes sense on instance variables that are
3634fee23f9Smrg pointers. */
3644fee23f9Smrg void
class_ivar_set_gcinvisible(Class class,const char * ivarname,BOOL gc_invisible)3654fee23f9Smrg class_ivar_set_gcinvisible (Class class, const char *ivarname,
3664fee23f9Smrg BOOL gc_invisible)
3674fee23f9Smrg {
3684fee23f9Smrg int i, ivar_count;
3694fee23f9Smrg struct objc_ivar_list *ivars;
3704fee23f9Smrg
3714fee23f9Smrg if (! class || ! ivarname)
3724fee23f9Smrg return;
3734fee23f9Smrg
3744fee23f9Smrg ivars = class->ivars;
3754fee23f9Smrg if (! ivars)
3764fee23f9Smrg return;
3774fee23f9Smrg
3784fee23f9Smrg ivar_count = ivars->ivar_count;
3794fee23f9Smrg
3804fee23f9Smrg for (i = 0; i < ivar_count; i++)
3814fee23f9Smrg {
3824fee23f9Smrg struct objc_ivar *ivar = &(ivars->ivar_list[i]);
3834fee23f9Smrg const char *type;
3844fee23f9Smrg
3854fee23f9Smrg if (! ivar->ivar_name || strcmp (ivar->ivar_name, ivarname))
3864fee23f9Smrg continue;
3874fee23f9Smrg
3884fee23f9Smrg assert (ivar->ivar_type);
3894fee23f9Smrg type = ivar->ivar_type;
3904fee23f9Smrg
3914fee23f9Smrg /* Skip the variable name */
3924fee23f9Smrg if (*type == '"')
3934fee23f9Smrg {
3944fee23f9Smrg for (type++; *type++ != '"';)
3954fee23f9Smrg /* do nothing */;
3964fee23f9Smrg }
3974fee23f9Smrg
3984fee23f9Smrg if (*type == _C_GCINVISIBLE)
3994fee23f9Smrg {
4004fee23f9Smrg char *new_type;
4014fee23f9Smrg size_t len;
4024fee23f9Smrg
4034fee23f9Smrg if (gc_invisible || ! __objc_ivar_pointer (type))
4044fee23f9Smrg return; /* The type of the variable already matches the
4054fee23f9Smrg requested gc_invisible type */
4064fee23f9Smrg
4074fee23f9Smrg /* The variable is gc_invisible so we make it gc visible. */
4084fee23f9Smrg new_type = objc_atomic_malloc (strlen(ivar->ivar_type));
4094fee23f9Smrg len = (type - ivar->ivar_type);
4104fee23f9Smrg memcpy (new_type, ivar->ivar_type, len);
4114fee23f9Smrg new_type[len] = 0;
4124fee23f9Smrg strcat (new_type, type + 1);
4134fee23f9Smrg ivar->ivar_type = new_type;
4144fee23f9Smrg }
4154fee23f9Smrg else
4164fee23f9Smrg {
4174fee23f9Smrg char *new_type;
4184fee23f9Smrg size_t len;
4194fee23f9Smrg
4204fee23f9Smrg if (! gc_invisible || ! __objc_ivar_pointer (type))
4214fee23f9Smrg return; /* The type of the variable already matches the
4224fee23f9Smrg requested gc_invisible type */
4234fee23f9Smrg
4244fee23f9Smrg /* The variable is gc visible so we make it gc_invisible. */
4254fee23f9Smrg new_type = objc_malloc (strlen(ivar->ivar_type) + 2);
42648fb7bfaSmrg
42748fb7bfaSmrg /* Copy the variable name. */
4284fee23f9Smrg len = (type - ivar->ivar_type);
4294fee23f9Smrg memcpy (new_type, ivar->ivar_type, len);
43048fb7bfaSmrg /* Add '!'. */
43148fb7bfaSmrg new_type[len++] = _C_GCINVISIBLE;
43248fb7bfaSmrg /* Copy the original types. */
43348fb7bfaSmrg strcpy (new_type + len, type);
43448fb7bfaSmrg
4354fee23f9Smrg ivar->ivar_type = new_type;
4364fee23f9Smrg }
4374fee23f9Smrg
4384fee23f9Smrg __objc_generate_gc_type_description (class);
4394fee23f9Smrg return;
4404fee23f9Smrg }
4414fee23f9Smrg
4424fee23f9Smrg /* Search the instance variable in the superclasses */
4434fee23f9Smrg class_ivar_set_gcinvisible (class->super_class, ivarname, gc_invisible);
4444fee23f9Smrg }
4454fee23f9Smrg
4464fee23f9Smrg #else /* !OBJC_WITH_GC */
4474fee23f9Smrg
4484fee23f9Smrg void
__objc_generate_gc_type_description(Class class)4494fee23f9Smrg __objc_generate_gc_type_description (Class class __attribute__ ((__unused__)))
4504fee23f9Smrg {
4514fee23f9Smrg }
4524fee23f9Smrg
class_ivar_set_gcinvisible(Class class,const char * ivarname,BOOL gc_invisible)4534fee23f9Smrg void class_ivar_set_gcinvisible (Class class __attribute__ ((__unused__)),
4544fee23f9Smrg const char *ivarname __attribute__ ((__unused__)),
4554fee23f9Smrg BOOL gc_invisible __attribute__ ((__unused__)))
4564fee23f9Smrg {
4574fee23f9Smrg }
4584fee23f9Smrg
4594fee23f9Smrg #endif /* OBJC_WITH_GC */
460