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, ¤t);
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