| 1 | /* Sparse Arrays for Objective C dispatch tables | 
|---|
| 2 | Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc. | 
|---|
| 3 | Contributed by Kresten Krab Thorup. | 
|---|
| 4 |  | 
|---|
| 5 | This file is part of GNU CC. | 
|---|
| 6 |  | 
|---|
| 7 | GNU CC is free software; you can redistribute it and/or modify | 
|---|
| 8 | it under the terms of the GNU General Public License as published by | 
|---|
| 9 | the Free Software Foundation; either version 2, or (at your option) | 
|---|
| 10 | any later version. | 
|---|
| 11 |  | 
|---|
| 12 | GNU CC is distributed in the hope that it will be useful, | 
|---|
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
| 15 | GNU General Public License for more details. | 
|---|
| 16 |  | 
|---|
| 17 | You should have received a copy of the GNU General Public License | 
|---|
| 18 | along with GNU CC; see the file COPYING.  If not, write to | 
|---|
| 19 | the Free Software Foundation, 59 Temple Place - Suite 330, | 
|---|
| 20 | Boston, MA 02111-1307, USA.  */ | 
|---|
| 21 |  | 
|---|
| 22 | /* As a special exception, if you link this library with files | 
|---|
| 23 | compiled with GCC to produce an executable, this does not cause | 
|---|
| 24 | the resulting executable to be covered by the GNU General Public License. | 
|---|
| 25 | This exception does not however invalidate any other reasons why | 
|---|
| 26 | the executable file might be covered by the GNU General Public License.  */ | 
|---|
| 27 |  | 
|---|
| 28 | #ifndef __sarray_INCLUDE_GNU | 
|---|
| 29 | #define __sarray_INCLUDE_GNU | 
|---|
| 30 |  | 
|---|
| 31 | #define OBJC_SPARSE2            /* 2-level sparse array */ | 
|---|
| 32 | /* #define OBJC_SPARSE3 */      /* 3-level sparse array */ | 
|---|
| 33 |  | 
|---|
| 34 | #ifdef OBJC_SPARSE2 | 
|---|
| 35 | extern const char* __objc_sparse2_id; | 
|---|
| 36 | #endif | 
|---|
| 37 |  | 
|---|
| 38 | #ifdef OBJC_SPARSE3 | 
|---|
| 39 | extern const char* __objc_sparse3_id; | 
|---|
| 40 | #endif | 
|---|
| 41 |  | 
|---|
| 42 | #include <stddef.h> | 
|---|
| 43 |  | 
|---|
| 44 | #include "objc/thr.h" | 
|---|
| 45 |  | 
|---|
| 46 | extern int nbuckets;            /* for stats */ | 
|---|
| 47 | extern int nindices; | 
|---|
| 48 | extern int narrays; | 
|---|
| 49 | extern int idxsize; | 
|---|
| 50 |  | 
|---|
| 51 | #include <assert.h> | 
|---|
| 52 |  | 
|---|
| 53 | /* An unsigned integer of same size as a pointer */ | 
|---|
| 54 | #define SIZET_BITS (sizeof(size_t)*8) | 
|---|
| 55 |  | 
|---|
| 56 | #if defined(__sparc__) || defined(OBJC_SPARSE2) | 
|---|
| 57 | #define PRECOMPUTE_SELECTORS | 
|---|
| 58 | #endif | 
|---|
| 59 |  | 
|---|
| 60 | #ifdef OBJC_SPARSE3 | 
|---|
| 61 |  | 
|---|
| 62 | /* Buckets are 8 words each */ | 
|---|
| 63 | #define BUCKET_BITS 3 | 
|---|
| 64 | #define BUCKET_SIZE (1<<BUCKET_BITS) | 
|---|
| 65 | #define BUCKET_MASK (BUCKET_SIZE-1) | 
|---|
| 66 |  | 
|---|
| 67 | /* Indices are 16 words each */ | 
|---|
| 68 | #define INDEX_BITS 4 | 
|---|
| 69 | #define INDEX_SIZE (1<<INDEX_BITS) | 
|---|
| 70 | #define INDEX_MASK (INDEX_SIZE-1) | 
|---|
| 71 |  | 
|---|
| 72 | #define INDEX_CAPACITY (BUCKET_SIZE*INDEX_SIZE) | 
|---|
| 73 |  | 
|---|
| 74 | #else /* OBJC_SPARSE2 */ | 
|---|
| 75 |  | 
|---|
| 76 | /* Buckets are 32 words each */ | 
|---|
| 77 | #define BUCKET_BITS 5 | 
|---|
| 78 | #define BUCKET_SIZE (1<<BUCKET_BITS) | 
|---|
| 79 | #define BUCKET_MASK (BUCKET_SIZE-1) | 
|---|
| 80 |  | 
|---|
| 81 | #endif /* OBJC_SPARSE2 */ | 
|---|
| 82 |  | 
|---|
| 83 | typedef size_t sidx; | 
|---|
| 84 |  | 
|---|
| 85 | #ifdef PRECOMPUTE_SELECTORS | 
|---|
| 86 |  | 
|---|
| 87 | struct soffset { | 
|---|
| 88 | #ifdef OBJC_SPARSE3 | 
|---|
| 89 | unsigned int unused : SIZET_BITS/4; | 
|---|
| 90 | unsigned int eoffset : SIZET_BITS/4; | 
|---|
| 91 | unsigned int boffset : SIZET_BITS/4; | 
|---|
| 92 | unsigned int ioffset : SIZET_BITS/4; | 
|---|
| 93 | #else /* OBJC_SPARSE2 */ | 
|---|
| 94 | #ifdef __sparc__ | 
|---|
| 95 | unsigned long boffset : (SIZET_BITS - 2) - BUCKET_BITS; | 
|---|
| 96 | unsigned int eoffset : BUCKET_BITS; | 
|---|
| 97 | unsigned int unused  : 2; | 
|---|
| 98 | #else | 
|---|
| 99 | unsigned int boffset : SIZET_BITS/2; | 
|---|
| 100 | unsigned int eoffset : SIZET_BITS/2; | 
|---|
| 101 | #endif | 
|---|
| 102 | #endif /* OBJC_SPARSE2 */ | 
|---|
| 103 | }; | 
|---|
| 104 |  | 
|---|
| 105 | union sofftype { | 
|---|
| 106 | struct soffset off; | 
|---|
| 107 | sidx idx; | 
|---|
| 108 | }; | 
|---|
| 109 |  | 
|---|
| 110 | #endif /* not PRECOMPUTE_SELECTORS */ | 
|---|
| 111 |  | 
|---|
| 112 | union sversion { | 
|---|
| 113 | int   version; | 
|---|
| 114 | void *next_free; | 
|---|
| 115 | }; | 
|---|
| 116 |  | 
|---|
| 117 | struct sbucket { | 
|---|
| 118 | void* elems[BUCKET_SIZE];     /* elements stored in array */ | 
|---|
| 119 | union sversion        version;                /* used for copy-on-write */ | 
|---|
| 120 | }; | 
|---|
| 121 |  | 
|---|
| 122 | #ifdef OBJC_SPARSE3 | 
|---|
| 123 |  | 
|---|
| 124 | struct sindex { | 
|---|
| 125 | struct sbucket* buckets[INDEX_SIZE]; | 
|---|
| 126 | union sversion        version;                /* used for copy-on-write */ | 
|---|
| 127 | }; | 
|---|
| 128 |  | 
|---|
| 129 | #endif /* OBJC_SPARSE3 */ | 
|---|
| 130 |  | 
|---|
| 131 | struct sarray { | 
|---|
| 132 | #ifdef OBJC_SPARSE3 | 
|---|
| 133 | struct sindex** indices; | 
|---|
| 134 | struct sindex* empty_index; | 
|---|
| 135 | #else /* OBJC_SPARSE2 */ | 
|---|
| 136 | struct sbucket** buckets; | 
|---|
| 137 | #endif  /* OBJC_SPARSE2 */ | 
|---|
| 138 | struct sbucket* empty_bucket; | 
|---|
| 139 | union sversion        version;                /* used for copy-on-write */ | 
|---|
| 140 | short ref_count; | 
|---|
| 141 | struct sarray* is_copy_of; | 
|---|
| 142 | size_t capacity; | 
|---|
| 143 | }; | 
|---|
| 144 |  | 
|---|
| 145 | struct sarray* sarray_new(int, void* default_element); | 
|---|
| 146 | void sarray_free(struct sarray*); | 
|---|
| 147 | struct sarray* sarray_lazy_copy(struct sarray*); | 
|---|
| 148 | void sarray_realloc(struct sarray*, int new_size); | 
|---|
| 149 | void sarray_at_put(struct sarray*, sidx index, void* elem); | 
|---|
| 150 | void sarray_at_put_safe(struct sarray*, sidx index, void* elem); | 
|---|
| 151 |  | 
|---|
| 152 | struct sarray* sarray_hard_copy(struct sarray*); /* ... like the name? */ | 
|---|
| 153 | void sarray_remove_garbage(void); | 
|---|
| 154 |  | 
|---|
| 155 |  | 
|---|
| 156 |  | 
|---|
| 157 | #ifdef PRECOMPUTE_SELECTORS | 
|---|
| 158 | /* Transform soffset values to ints and vica verca */ | 
|---|
| 159 | static inline unsigned int | 
|---|
| 160 | soffset_decode(sidx index) | 
|---|
| 161 | { | 
|---|
| 162 | union sofftype x; | 
|---|
| 163 | x.idx = index; | 
|---|
| 164 | #ifdef OBJC_SPARSE3 | 
|---|
| 165 | return x.off.eoffset | 
|---|
| 166 | + (x.off.boffset*BUCKET_SIZE) | 
|---|
| 167 | + (x.off.ioffset*INDEX_CAPACITY); | 
|---|
| 168 | #else /* OBJC_SPARSE2 */ | 
|---|
| 169 | return x.off.eoffset + (x.off.boffset*BUCKET_SIZE); | 
|---|
| 170 | #endif /* OBJC_SPARSE2 */ | 
|---|
| 171 | } | 
|---|
| 172 |  | 
|---|
| 173 | static inline sidx | 
|---|
| 174 | soffset_encode(size_t offset) | 
|---|
| 175 | { | 
|---|
| 176 | union sofftype x; | 
|---|
| 177 | x.off.eoffset = offset%BUCKET_SIZE; | 
|---|
| 178 | #ifdef OBJC_SPARSE3 | 
|---|
| 179 | x.off.boffset = (offset/BUCKET_SIZE)%INDEX_SIZE; | 
|---|
| 180 | x.off.ioffset = offset/INDEX_CAPACITY; | 
|---|
| 181 | #else /* OBJC_SPARSE2 */ | 
|---|
| 182 | x.off.boffset = offset/BUCKET_SIZE; | 
|---|
| 183 | #endif | 
|---|
| 184 | return (sidx)x.idx; | 
|---|
| 185 | } | 
|---|
| 186 |  | 
|---|
| 187 | #else /* not PRECOMPUTE_SELECTORS */ | 
|---|
| 188 |  | 
|---|
| 189 | static inline size_t | 
|---|
| 190 | soffset_decode(sidx index) | 
|---|
| 191 | { | 
|---|
| 192 | return index; | 
|---|
| 193 | } | 
|---|
| 194 |  | 
|---|
| 195 | static inline sidx | 
|---|
| 196 | soffset_encode(size_t offset) | 
|---|
| 197 | { | 
|---|
| 198 | return offset; | 
|---|
| 199 | } | 
|---|
| 200 | #endif /* not PRECOMPUTE_SELECTORS */ | 
|---|
| 201 |  | 
|---|
| 202 | /* Get element from the Sparse array `array' at offset `index' */ | 
|---|
| 203 |  | 
|---|
| 204 | static inline void* sarray_get(struct sarray* array, sidx index) | 
|---|
| 205 | { | 
|---|
| 206 | #ifdef PRECOMPUTE_SELECTORS | 
|---|
| 207 | union sofftype x; | 
|---|
| 208 | x.idx = index; | 
|---|
| 209 | #ifdef OBJC_SPARSE3 | 
|---|
| 210 | return | 
|---|
| 211 | array-> | 
|---|
| 212 | indices[x.off.ioffset]-> | 
|---|
| 213 | buckets[x.off.boffset]-> | 
|---|
| 214 | elems[x.off.eoffset]; | 
|---|
| 215 | #else /* OBJC_SPARSE2 */ | 
|---|
| 216 | return array->buckets[x.off.boffset]->elems[x.off.eoffset]; | 
|---|
| 217 | #endif /* OBJC_SPARSE2 */ | 
|---|
| 218 | #else /* not PRECOMPUTE_SELECTORS */ | 
|---|
| 219 | #ifdef OBJC_SPARSE3 | 
|---|
| 220 | return array-> | 
|---|
| 221 | indices[index/INDEX_CAPACITY]-> | 
|---|
| 222 | buckets[(index/BUCKET_SIZE)%INDEX_SIZE]-> | 
|---|
| 223 | elems[index%BUCKET_SIZE]; | 
|---|
| 224 | #else /* OBJC_SPARSE2 */ | 
|---|
| 225 | return array->buckets[index/BUCKET_SIZE]->elems[index%BUCKET_SIZE]; | 
|---|
| 226 | #endif /* not OBJC_SPARSE3 */ | 
|---|
| 227 | #endif /* not PRECOMPUTE_SELECTORS */ | 
|---|
| 228 | } | 
|---|
| 229 |  | 
|---|
| 230 | static inline void* sarray_get_safe(struct sarray* array, sidx index) | 
|---|
| 231 | { | 
|---|
| 232 | if(soffset_decode(index) < array->capacity) | 
|---|
| 233 | return sarray_get(array, index); | 
|---|
| 234 | else | 
|---|
| 235 | return (array->empty_bucket->elems[0]); | 
|---|
| 236 | } | 
|---|
| 237 |  | 
|---|
| 238 | #endif /* __sarray_INCLUDE_GNU */ | 
|---|