diff options
author | Marc Espie <espie@cvs.openbsd.org> | 1999-05-26 13:38:57 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 1999-05-26 13:38:57 +0000 |
commit | 0126e157b87f137fc08dc7f46f6c291b9d06ac5d (patch) | |
tree | f8555e3e504eb82b4cd3cba5cec20ae4ce8124ff /gnu/egcs/libobjc/gc.c | |
parent | ff8e9a4356e55ed142306c3a375fa280800abc86 (diff) |
egcs projects compiler system
Exact copy of the snapshot, except for the removal of
texinfo/
gcc/ch/
libchill/
Diffstat (limited to 'gnu/egcs/libobjc/gc.c')
-rw-r--r-- | gnu/egcs/libobjc/gc.c | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/gnu/egcs/libobjc/gc.c b/gnu/egcs/libobjc/gc.c new file mode 100644 index 00000000000..8ca6de8e946 --- /dev/null +++ b/gnu/egcs/libobjc/gc.c @@ -0,0 +1,458 @@ +/* Basic data types for Objective C. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Ovidiu Predescu. + +This file is part of GNU CC. + +GNU CC 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 2, or (at your option) +any later version. + +GNU CC 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. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#include "tconfig.h" +#include "objc.h" +#include "encoding.h" + +#include <assert.h> +#include <string.h> + +#if OBJC_WITH_GC + +#include <gc.h> + +/* gc_typed.h uses the following but doesn't declare them */ +typedef GC_word word; +typedef GC_signed_word signed_word; + +#if BITS_PER_WORD == 32 +# define LOGWL 5 +# define modWORDSZ(n) ((n) & 0x1f) /* n mod size of word */ +#endif + +#if BITS_PER_WORD == 64 +# define LOGWL 6 +# define modWORDSZ(n) ((n) & 0x3f) /* n mod size of word */ +#endif + +#define divWORDSZ(n) ((n) >> LOGWL) /* divide n by size of 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_get_instance_size (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, "}"); +// printf ("type description for '%s' is %s\n", class->name, class_structure_type); + + __objc_gc_type_description_from_type (mask, class_structure_type); + objc_free (class_structure_type); + +#define DEBUG 1 +#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; + + 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 and we have to reverse it */ + new_type = objc_atomic_malloc (strlen (ivar->ivar_type)); + strncpy (new_type, ivar->ivar_type, + (size_t)(type - ivar->ivar_type)); + strcat (new_type, type + 1); + ivar->ivar_type = new_type; + } + else + { + char *new_type; + + 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 and we have to make it gc_invisible */ + new_type = objc_malloc (strlen (ivar->ivar_type) + 2); + strncpy (new_type, ivar->ivar_type, + (size_t)(type - ivar->ivar_type)); + strcat (new_type, "!"); + strcat (new_type, 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) +{ +} + +void class_ivar_set_gcinvisible (Class class, + const char* ivarname, + BOOL gc_invisible) +{ +} + +#endif /* OBJC_WITH_GC */ |