1 1.1 mrg /* Sparse Arrays for Objective C dispatch tables 2 1.1.1.12 mrg Copyright (C) 1993-2024 Free Software Foundation, Inc. 3 1.1 mrg 4 1.1 mrg This file is part of GCC. 5 1.1 mrg 6 1.1 mrg GCC is free software; you can redistribute it and/or modify 7 1.1 mrg it under the terms of the GNU General Public License as published by 8 1.1 mrg the Free Software Foundation; either version 3, or (at your option) 9 1.1 mrg any later version. 10 1.1 mrg 11 1.1 mrg GCC is distributed in the hope that it will be useful, 12 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of 13 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 1.1 mrg GNU General Public License for more details. 15 1.1 mrg 16 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 17 1.1 mrg permissions described in the GCC Runtime Library Exception, version 18 1.1 mrg 3.1, as published by the Free Software Foundation. 19 1.1 mrg 20 1.1 mrg You should have received a copy of the GNU General Public License and 21 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 22 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 1.1 mrg <http://www.gnu.org/licenses/>. */ 24 1.1 mrg 25 1.1.1.2 mrg #include "objc-private/common.h" 26 1.1.1.2 mrg #include "objc-private/sarray.h" 27 1.1.1.2 mrg #include "objc/runtime.h" /* For objc_malloc */ 28 1.1.1.2 mrg #include "objc/thr.h" /* For objc_mutex_lock */ 29 1.1.1.2 mrg #include "objc-private/module-abi-8.h" 30 1.1.1.2 mrg #include "objc-private/runtime.h" 31 1.1 mrg #include <stdio.h> 32 1.1.1.2 mrg #include <string.h> /* For memset */ 33 1.1.1.2 mrg #include <assert.h> /* For assert */ 34 1.1 mrg 35 1.1 mrg int nbuckets = 0; /* !T:MUTEX */ 36 1.1 mrg int nindices = 0; /* !T:MUTEX */ 37 1.1 mrg int narrays = 0; /* !T:MUTEX */ 38 1.1 mrg int idxsize = 0; /* !T:MUTEX */ 39 1.1 mrg 40 1.1 mrg static void *first_free_data = NULL; /* !T:MUTEX */ 41 1.1 mrg 42 1.1 mrg #ifdef OBJC_SPARSE2 43 1.1 mrg const char *__objc_sparse2_id = "2 level sparse indices"; 44 1.1 mrg #endif 45 1.1 mrg 46 1.1 mrg #ifdef OBJC_SPARSE3 47 1.1 mrg const char *__objc_sparse3_id = "3 level sparse indices"; 48 1.1 mrg #endif 49 1.1 mrg 50 1.1 mrg /* This function removes any structures left over from free operations 51 1.1 mrg that were not safe in a multi-threaded environment. */ 52 1.1 mrg void 53 1.1 mrg sarray_remove_garbage (void) 54 1.1 mrg { 55 1.1 mrg void **vp; 56 1.1 mrg void *np; 57 1.1 mrg 58 1.1 mrg objc_mutex_lock (__objc_runtime_mutex); 59 1.1 mrg 60 1.1 mrg vp = first_free_data; 61 1.1 mrg first_free_data = NULL; 62 1.1 mrg 63 1.1.1.2 mrg while (vp) 64 1.1.1.2 mrg { 65 1.1.1.2 mrg np = *vp; 66 1.1.1.2 mrg objc_free (vp); 67 1.1.1.2 mrg vp = np; 68 1.1.1.2 mrg } 69 1.1 mrg 70 1.1 mrg objc_mutex_unlock (__objc_runtime_mutex); 71 1.1 mrg } 72 1.1 mrg 73 1.1.1.2 mrg /* Free a block of dynamically allocated memory. If we are in 74 1.1.1.2 mrg multi-threaded mode, it is ok to free it. If not, we add it to the 75 1.1.1.2 mrg garbage heap to be freed later. */ 76 1.1 mrg static void 77 1.1 mrg sarray_free_garbage (void *vp) 78 1.1 mrg { 79 1.1 mrg objc_mutex_lock (__objc_runtime_mutex); 80 1.1 mrg 81 1.1.1.2 mrg if (__objc_runtime_threads_alive == 1) 82 1.1.1.2 mrg { 83 1.1.1.2 mrg objc_free (vp); 84 1.1.1.2 mrg if (first_free_data) 85 1.1.1.2 mrg sarray_remove_garbage (); 86 1.1.1.2 mrg } 87 1.1.1.2 mrg else 88 1.1.1.2 mrg { 89 1.1.1.2 mrg *(void **)vp = first_free_data; 90 1.1.1.2 mrg first_free_data = vp; 91 1.1.1.2 mrg } 92 1.1.1.2 mrg 93 1.1 mrg objc_mutex_unlock (__objc_runtime_mutex); 94 1.1 mrg } 95 1.1 mrg 96 1.1.1.2 mrg /* sarray_at_put copies data in such a way as to be thread reader 97 1.1.1.2 mrg safe. */ 98 1.1 mrg void 99 1.1 mrg sarray_at_put (struct sarray *array, sidx index, void *element) 100 1.1 mrg { 101 1.1 mrg #ifdef OBJC_SPARSE3 102 1.1 mrg struct sindex **the_index; 103 1.1 mrg struct sindex *new_index; 104 1.1 mrg #endif 105 1.1 mrg struct sbucket **the_bucket; 106 1.1 mrg struct sbucket *new_bucket; 107 1.1 mrg #ifdef OBJC_SPARSE3 108 1.1 mrg size_t ioffset; 109 1.1 mrg #endif 110 1.1 mrg size_t boffset; 111 1.1 mrg size_t eoffset; 112 1.1 mrg #ifdef PRECOMPUTE_SELECTORS 113 1.1 mrg union sofftype xx; 114 1.1 mrg xx.idx = index; 115 1.1 mrg #ifdef OBJC_SPARSE3 116 1.1 mrg ioffset = xx.off.ioffset; 117 1.1 mrg #endif 118 1.1 mrg boffset = xx.off.boffset; 119 1.1 mrg eoffset = xx.off.eoffset; 120 1.1 mrg #else /* not PRECOMPUTE_SELECTORS */ 121 1.1 mrg #ifdef OBJC_SPARSE3 122 1.1 mrg ioffset = index/INDEX_CAPACITY; 123 1.1 mrg boffset = (index/BUCKET_SIZE)%INDEX_SIZE; 124 1.1 mrg eoffset = index%BUCKET_SIZE; 125 1.1 mrg #else 126 1.1 mrg boffset = index/BUCKET_SIZE; 127 1.1 mrg eoffset = index%BUCKET_SIZE; 128 1.1 mrg #endif 129 1.1 mrg #endif /* not PRECOMPUTE_SELECTORS */ 130 1.1 mrg 131 1.1 mrg assert (soffset_decode (index) < array->capacity); /* Range check */ 132 1.1 mrg 133 1.1 mrg #ifdef OBJC_SPARSE3 134 1.1 mrg the_index = &(array->indices[ioffset]); 135 1.1 mrg the_bucket = &((*the_index)->buckets[boffset]); 136 1.1 mrg #else 137 1.1 mrg the_bucket = &(array->buckets[boffset]); 138 1.1 mrg #endif 139 1.1 mrg 140 1.1 mrg if ((*the_bucket)->elems[eoffset] == element) 141 1.1.1.2 mrg return; /* Great! we just avoided a lazy copy. */ 142 1.1 mrg 143 1.1 mrg #ifdef OBJC_SPARSE3 144 1.1 mrg 145 1.1.1.2 mrg /* First, perform lazy copy/allocation of index if needed. */ 146 1.1 mrg 147 1.1.1.2 mrg if ((*the_index) == array->empty_index) 148 1.1.1.2 mrg { 149 1.1.1.2 mrg /* The index was previously empty, allocate a new. */ 150 1.1.1.2 mrg new_index = (struct sindex *) objc_malloc (sizeof (struct sindex)); 151 1.1.1.2 mrg memcpy (new_index, array->empty_index, sizeof (struct sindex)); 152 1.1.1.2 mrg new_index->version.version = array->version.version; 153 1.1.1.2 mrg *the_index = new_index; /* Prepared for install. */ 154 1.1.1.2 mrg the_bucket = &((*the_index)->buckets[boffset]); 155 1.1.1.2 mrg 156 1.1.1.2 mrg nindices += 1; 157 1.1.1.2 mrg } 158 1.1.1.2 mrg else if ((*the_index)->version.version != array->version.version) 159 1.1.1.2 mrg { 160 1.1.1.2 mrg /* This index must be lazy copied. */ 161 1.1.1.2 mrg struct sindex *old_index = *the_index; 162 1.1.1.2 mrg new_index = (struct sindex *) objc_malloc (sizeof (struct sindex)); 163 1.1.1.2 mrg memcpy (new_index, old_index, sizeof (struct sindex)); 164 1.1.1.2 mrg new_index->version.version = array->version.version; 165 1.1.1.2 mrg *the_index = new_index; /* Prepared for install. */ 166 1.1.1.2 mrg the_bucket = &((*the_index)->buckets[boffset]); 167 1.1.1.2 mrg 168 1.1.1.2 mrg nindices += 1; 169 1.1.1.2 mrg } 170 1.1.1.2 mrg 171 1.1 mrg #endif /* OBJC_SPARSE3 */ 172 1.1.1.2 mrg 173 1.1.1.2 mrg /* Next, perform lazy allocation/copy of the bucket if needed. */ 174 1.1.1.2 mrg if ((*the_bucket) == array->empty_bucket) 175 1.1.1.2 mrg { 176 1.1.1.2 mrg /* The bucket was previously empty (or something like that), 177 1.1.1.2 mrg allocate a new. This is the effect of `lazy' allocation. */ 178 1.1.1.2 mrg new_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket)); 179 1.1.1.2 mrg memcpy ((void *) new_bucket, (const void *) array->empty_bucket, 180 1.1.1.2 mrg sizeof (struct sbucket)); 181 1.1.1.2 mrg new_bucket->version.version = array->version.version; 182 1.1.1.2 mrg *the_bucket = new_bucket; /* Prepared for install. */ 183 1.1.1.2 mrg 184 1.1.1.2 mrg nbuckets += 1; 185 1.1.1.2 mrg 186 1.1.1.2 mrg } 187 1.1.1.2 mrg else if ((*the_bucket)->version.version != array->version.version) 188 1.1.1.2 mrg { 189 1.1.1.2 mrg /* Perform lazy copy. */ 190 1.1.1.2 mrg struct sbucket *old_bucket = *the_bucket; 191 1.1.1.2 mrg new_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket)); 192 1.1.1.2 mrg memcpy (new_bucket, old_bucket, sizeof (struct sbucket)); 193 1.1.1.2 mrg new_bucket->version.version = array->version.version; 194 1.1.1.2 mrg *the_bucket = new_bucket; /* Prepared for install. */ 195 1.1.1.2 mrg 196 1.1.1.2 mrg nbuckets += 1; 197 1.1.1.2 mrg } 198 1.1 mrg (*the_bucket)->elems[eoffset] = element; 199 1.1 mrg } 200 1.1 mrg 201 1.1 mrg void 202 1.1 mrg sarray_at_put_safe (struct sarray *array, sidx index, void *element) 203 1.1 mrg { 204 1.1 mrg if (soffset_decode (index) >= array->capacity) 205 1.1 mrg sarray_realloc (array, soffset_decode (index) + 1); 206 1.1 mrg sarray_at_put (array, index, element); 207 1.1 mrg } 208 1.1 mrg 209 1.1 mrg struct sarray * 210 1.1 mrg sarray_new (int size, void *default_element) 211 1.1 mrg { 212 1.1 mrg struct sarray *arr; 213 1.1 mrg #ifdef OBJC_SPARSE3 214 1.1 mrg size_t num_indices = ((size - 1)/(INDEX_CAPACITY)) + 1; 215 1.1 mrg struct sindex **new_indices; 216 1.1 mrg #else /* OBJC_SPARSE2 */ 217 1.1 mrg size_t num_indices = ((size - 1)/BUCKET_SIZE) + 1; 218 1.1 mrg struct sbucket **new_buckets; 219 1.1 mrg #endif 220 1.1 mrg size_t counter; 221 1.1 mrg 222 1.1 mrg assert (size > 0); 223 1.1 mrg 224 1.1.1.2 mrg /* Allocate core array. */ 225 1.1 mrg arr = (struct sarray *) objc_malloc (sizeof (struct sarray)); 226 1.1 mrg arr->version.version = 0; 227 1.1 mrg 228 1.1.1.2 mrg /* Initialize members. */ 229 1.1 mrg #ifdef OBJC_SPARSE3 230 1.1 mrg arr->capacity = num_indices*INDEX_CAPACITY; 231 1.1 mrg new_indices = (struct sindex **) 232 1.1 mrg objc_malloc (sizeof (struct sindex *) * num_indices); 233 1.1.1.2 mrg 234 1.1 mrg arr->empty_index = (struct sindex *) objc_malloc (sizeof (struct sindex)); 235 1.1 mrg arr->empty_index->version.version = 0; 236 1.1 mrg 237 1.1 mrg narrays += 1; 238 1.1 mrg idxsize += num_indices; 239 1.1 mrg nindices += 1; 240 1.1 mrg 241 1.1 mrg #else /* OBJC_SPARSE2 */ 242 1.1 mrg arr->capacity = num_indices*BUCKET_SIZE; 243 1.1 mrg new_buckets = (struct sbucket **) 244 1.1 mrg objc_malloc (sizeof (struct sbucket *) * num_indices); 245 1.1 mrg 246 1.1 mrg narrays += 1; 247 1.1 mrg idxsize += num_indices; 248 1.1 mrg 249 1.1 mrg #endif 250 1.1 mrg 251 1.1 mrg arr->empty_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket)); 252 1.1 mrg arr->empty_bucket->version.version = 0; 253 1.1 mrg 254 1.1 mrg nbuckets += 1; 255 1.1 mrg 256 1.1 mrg arr->ref_count = 1; 257 1.1 mrg arr->is_copy_of = (struct sarray *) 0; 258 1.1 mrg 259 1.1 mrg for (counter = 0; counter < BUCKET_SIZE; counter++) 260 1.1 mrg arr->empty_bucket->elems[counter] = default_element; 261 1.1 mrg 262 1.1 mrg #ifdef OBJC_SPARSE3 263 1.1 mrg for (counter = 0; counter < INDEX_SIZE; counter++) 264 1.1 mrg arr->empty_index->buckets[counter] = arr->empty_bucket; 265 1.1 mrg 266 1.1 mrg for (counter = 0; counter < num_indices; counter++) 267 1.1 mrg new_indices[counter] = arr->empty_index; 268 1.1 mrg 269 1.1 mrg #else /* OBJC_SPARSE2 */ 270 1.1 mrg 271 1.1 mrg for (counter = 0; counter < num_indices; counter++) 272 1.1 mrg new_buckets[counter] = arr->empty_bucket; 273 1.1 mrg 274 1.1 mrg #endif 275 1.1 mrg 276 1.1 mrg #ifdef OBJC_SPARSE3 277 1.1 mrg arr->indices = new_indices; 278 1.1 mrg #else /* OBJC_SPARSE2 */ 279 1.1 mrg arr->buckets = new_buckets; 280 1.1 mrg #endif 281 1.1 mrg 282 1.1 mrg return arr; 283 1.1 mrg } 284 1.1 mrg 285 1.1 mrg 287 1.1.1.2 mrg /* Reallocate the sparse array to hold `newsize' entries Note: We 288 1.1.1.2 mrg really allocate and then free. We have to do this to ensure that 289 1.1 mrg any concurrent readers notice the update. */ 290 1.1 mrg void 291 1.1 mrg sarray_realloc (struct sarray *array, int newsize) 292 1.1 mrg { 293 1.1 mrg #ifdef OBJC_SPARSE3 294 1.1 mrg size_t old_max_index = (array->capacity - 1)/INDEX_CAPACITY; 295 1.1 mrg size_t new_max_index = ((newsize - 1)/INDEX_CAPACITY); 296 1.1 mrg size_t rounded_size = (new_max_index + 1) * INDEX_CAPACITY; 297 1.1 mrg 298 1.1 mrg struct sindex **new_indices; 299 1.1 mrg struct sindex **old_indices; 300 1.1 mrg 301 1.1 mrg #else /* OBJC_SPARSE2 */ 302 1.1 mrg size_t old_max_index = (array->capacity - 1)/BUCKET_SIZE; 303 1.1 mrg size_t new_max_index = ((newsize - 1)/BUCKET_SIZE); 304 1.1 mrg size_t rounded_size = (new_max_index + 1) * BUCKET_SIZE; 305 1.1 mrg 306 1.1 mrg struct sbucket **new_buckets; 307 1.1 mrg struct sbucket **old_buckets; 308 1.1 mrg 309 1.1 mrg #endif 310 1.1 mrg 311 1.1 mrg size_t counter; 312 1.1 mrg 313 1.1 mrg assert (newsize > 0); 314 1.1.1.2 mrg 315 1.1 mrg /* The size is the same, just ignore the request. */ 316 1.1 mrg if (rounded_size <= array->capacity) 317 1.1 mrg return; 318 1.1 mrg 319 1.1 mrg assert (array->ref_count == 1); /* stop if lazy copied... */ 320 1.1.1.2 mrg 321 1.1.1.2 mrg /* We are asked to extend the array -- allocate new bucket table, 322 1.1 mrg and insert empty_bucket in newly allocated places. */ 323 1.1 mrg if (rounded_size > array->capacity) 324 1.1 mrg { 325 1.1 mrg #ifdef OBJC_SPARSE3 326 1.1 mrg new_max_index += 4; 327 1.1 mrg rounded_size = (new_max_index + 1) * INDEX_CAPACITY; 328 1.1 mrg #else /* OBJC_SPARSE2 */ 329 1.1 mrg new_max_index += 4; 330 1.1 mrg rounded_size = (new_max_index + 1) * BUCKET_SIZE; 331 1.1 mrg #endif 332 1.1.1.2 mrg 333 1.1 mrg /* Update capacity. */ 334 1.1 mrg array->capacity = rounded_size; 335 1.1 mrg 336 1.1.1.2 mrg #ifdef OBJC_SPARSE3 337 1.1 mrg /* Alloc to force re-read by any concurrent readers. */ 338 1.1 mrg old_indices = array->indices; 339 1.1 mrg new_indices = (struct sindex **) 340 1.1 mrg objc_malloc ((new_max_index + 1) * sizeof (struct sindex *)); 341 1.1 mrg #else /* OBJC_SPARSE2 */ 342 1.1 mrg old_buckets = array->buckets; 343 1.1 mrg new_buckets = (struct sbucket **) 344 1.1 mrg objc_malloc ((new_max_index + 1) * sizeof (struct sbucket *)); 345 1.1 mrg #endif 346 1.1.1.2 mrg 347 1.1.1.2 mrg /* Copy buckets below old_max_index (they are still valid). */ 348 1.1.1.2 mrg for (counter = 0; counter <= old_max_index; counter++ ) 349 1.1 mrg { 350 1.1.1.2 mrg #ifdef OBJC_SPARSE3 351 1.1 mrg new_indices[counter] = old_indices[counter]; 352 1.1.1.2 mrg #else /* OBJC_SPARSE2 */ 353 1.1 mrg new_buckets[counter] = old_buckets[counter]; 354 1.1.1.2 mrg #endif 355 1.1 mrg } 356 1.1 mrg 357 1.1.1.2 mrg #ifdef OBJC_SPARSE3 358 1.1 mrg /* Reset entries above old_max_index to empty_bucket. */ 359 1.1 mrg for (counter = old_max_index + 1; counter <= new_max_index; counter++) 360 1.1 mrg new_indices[counter] = array->empty_index; 361 1.1.1.2 mrg #else /* OBJC_SPARSE2 */ 362 1.1 mrg /* Reset entries above old_max_index to empty_bucket. */ 363 1.1 mrg for (counter = old_max_index + 1; counter <= new_max_index; counter++) 364 1.1 mrg new_buckets[counter] = array->empty_bucket; 365 1.1 mrg #endif 366 1.1 mrg 367 1.1.1.2 mrg #ifdef OBJC_SPARSE3 368 1.1 mrg /* Install the new indices. */ 369 1.1 mrg array->indices = new_indices; 370 1.1 mrg #else /* OBJC_SPARSE2 */ 371 1.1 mrg array->buckets = new_buckets; 372 1.1 mrg #endif 373 1.1 mrg 374 1.1.1.2 mrg #ifdef OBJC_SPARSE3 375 1.1 mrg /* Free the old indices. */ 376 1.1 mrg sarray_free_garbage (old_indices); 377 1.1 mrg #else /* OBJC_SPARSE2 */ 378 1.1 mrg sarray_free_garbage (old_buckets); 379 1.1 mrg #endif 380 1.1 mrg 381 1.1 mrg idxsize += (new_max_index-old_max_index); 382 1.1 mrg return; 383 1.1 mrg } 384 1.1 mrg } 385 1.1 mrg 386 1.1 mrg 388 1.1 mrg /* Free a sparse array allocated with sarray_new */ 389 1.1 mrg void 390 1.1 mrg sarray_free (struct sarray *array) { 391 1.1 mrg #ifdef OBJC_SPARSE3 392 1.1 mrg size_t old_max_index = (array->capacity - 1)/INDEX_CAPACITY; 393 1.1 mrg struct sindex **old_indices; 394 1.1 mrg #else 395 1.1 mrg size_t old_max_index = (array->capacity - 1)/BUCKET_SIZE; 396 1.1 mrg struct sbucket **old_buckets; 397 1.1 mrg #endif 398 1.1 mrg size_t counter = 0; 399 1.1 mrg 400 1.1 mrg assert (array->ref_count != 0); /* Freed multiple times!!! */ 401 1.1 mrg 402 1.1 mrg if (--(array->ref_count) != 0) /* There exists copies of me */ 403 1.1 mrg return; 404 1.1 mrg 405 1.1 mrg #ifdef OBJC_SPARSE3 406 1.1 mrg old_indices = array->indices; 407 1.1 mrg #else 408 1.1 mrg old_buckets = array->buckets; 409 1.1.1.2 mrg #endif 410 1.1.1.2 mrg 411 1.1.1.2 mrg /* Free all entries that do not point to empty_bucket. */ 412 1.1 mrg for (counter = 0; counter <= old_max_index; counter++ ) 413 1.1.1.2 mrg { 414 1.1.1.2 mrg #ifdef OBJC_SPARSE3 415 1.1.1.2 mrg struct sindex *idx = old_indices[counter]; 416 1.1.1.2 mrg if ((idx != array->empty_index) 417 1.1.1.2 mrg && (idx->version.version == array->version.version)) 418 1.1.1.2 mrg { 419 1.1.1.2 mrg int c2; 420 1.1.1.2 mrg for (c2 = 0; c2 < INDEX_SIZE; c2++) 421 1.1.1.2 mrg { 422 1.1.1.2 mrg struct sbucket *bkt = idx->buckets[c2]; 423 1.1.1.2 mrg if ((bkt != array->empty_bucket) 424 1.1.1.2 mrg && (bkt->version.version == array->version.version)) 425 1.1.1.2 mrg { 426 1.1.1.2 mrg sarray_free_garbage (bkt); 427 1.1.1.2 mrg nbuckets -= 1; 428 1.1.1.2 mrg } 429 1.1.1.2 mrg } 430 1.1.1.2 mrg sarray_free_garbage (idx); 431 1.1.1.2 mrg nindices -= 1; 432 1.1.1.2 mrg } 433 1.1.1.2 mrg #else /* OBJC_SPARSE2 */ 434 1.1.1.2 mrg struct sbucket *bkt = old_buckets[counter]; 435 1.1.1.2 mrg if ((bkt != array->empty_bucket) 436 1.1.1.2 mrg && (bkt->version.version == array->version.version)) 437 1.1.1.2 mrg { 438 1.1.1.2 mrg sarray_free_garbage (bkt); 439 1.1 mrg nbuckets -= 1; 440 1.1.1.2 mrg } 441 1.1.1.2 mrg #endif 442 1.1 mrg } 443 1.1.1.2 mrg 444 1.1.1.2 mrg #ifdef OBJC_SPARSE3 445 1.1.1.2 mrg /* Free empty_index. */ 446 1.1.1.2 mrg if (array->empty_index->version.version == array->version.version) 447 1.1.1.2 mrg { 448 1.1.1.2 mrg sarray_free_garbage (array->empty_index); 449 1.1 mrg nindices -= 1; 450 1.1 mrg } 451 1.1.1.2 mrg #endif 452 1.1.1.2 mrg 453 1.1.1.2 mrg /* Free empty_bucket. */ 454 1.1.1.2 mrg if (array->empty_bucket->version.version == array->version.version) 455 1.1.1.2 mrg { 456 1.1.1.2 mrg sarray_free_garbage (array->empty_bucket); 457 1.1 mrg nbuckets -= 1; 458 1.1 mrg } 459 1.1.1.2 mrg idxsize -= (old_max_index + 1); 460 1.1 mrg narrays -= 1; 461 1.1.1.2 mrg 462 1.1 mrg #ifdef OBJC_SPARSE3 463 1.1 mrg /* Free bucket table. */ 464 1.1.1.2 mrg sarray_free_garbage (array->indices); 465 1.1 mrg #else 466 1.1 mrg /* Free bucket table. */ 467 1.1 mrg sarray_free_garbage (array->buckets); 468 1.1 mrg #endif 469 1.1.1.2 mrg 470 1.1.1.2 mrg /* If this is a copy of another array, we free it (which might just 471 1.1 mrg decrement its reference count so it will be freed when no longer 472 1.1 mrg in use). */ 473 1.1 mrg if (array->is_copy_of) 474 1.1.1.2 mrg sarray_free (array->is_copy_of); 475 1.1 mrg 476 1.1 mrg /* Free array. */ 477 1.1 mrg sarray_free_garbage (array); 478 1.1.1.2 mrg } 479 1.1.1.2 mrg 480 1.1 mrg /* This is a lazy copy. Only the core of the structure is actually 481 1.1 mrg copied. */ 482 1.1 mrg struct sarray * 483 1.1 mrg sarray_lazy_copy (struct sarray *oarr) 484 1.1 mrg { 485 1.1 mrg struct sarray *arr; 486 1.1 mrg 487 1.1 mrg #ifdef OBJC_SPARSE3 488 1.1 mrg size_t num_indices = ((oarr->capacity - 1)/INDEX_CAPACITY) + 1; 489 1.1 mrg struct sindex **new_indices; 490 1.1 mrg #else /* OBJC_SPARSE2 */ 491 1.1 mrg size_t num_indices = ((oarr->capacity - 1)/BUCKET_SIZE) + 1; 492 1.1 mrg struct sbucket **new_buckets; 493 1.1.1.2 mrg #endif 494 1.1 mrg 495 1.1 mrg /* Allocate core array. */ 496 1.1 mrg arr = (struct sarray *) objc_malloc (sizeof (struct sarray)); /* !!! */ 497 1.1 mrg arr->version.version = oarr->version.version + 1; 498 1.1 mrg #ifdef OBJC_SPARSE3 499 1.1 mrg arr->empty_index = oarr->empty_index; 500 1.1 mrg #endif 501 1.1 mrg arr->empty_bucket = oarr->empty_bucket; 502 1.1 mrg arr->ref_count = 1; 503 1.1 mrg oarr->ref_count += 1; 504 1.1 mrg arr->is_copy_of = oarr; 505 1.1 mrg arr->capacity = oarr->capacity; 506 1.1.1.2 mrg 507 1.1 mrg #ifdef OBJC_SPARSE3 508 1.1 mrg /* Copy bucket table. */ 509 1.1 mrg new_indices = (struct sindex **) 510 1.1 mrg objc_malloc (sizeof (struct sindex *) * num_indices); 511 1.1 mrg memcpy (new_indices, oarr->indices, sizeof (struct sindex *) * num_indices); 512 1.1.1.2 mrg arr->indices = new_indices; 513 1.1 mrg #else 514 1.1 mrg /* Copy bucket table. */ 515 1.1 mrg new_buckets = (struct sbucket **) 516 1.1 mrg objc_malloc (sizeof (struct sbucket *) * num_indices); 517 1.1 mrg memcpy (new_buckets, oarr->buckets, sizeof (struct sbucket *) * num_indices); 518 1.1 mrg arr->buckets = new_buckets; 519 1.1 mrg #endif 520 1.1 mrg 521 1.1 mrg idxsize += num_indices; 522 1.1 mrg narrays += 1; 523 1.1 mrg 524 return arr; 525 } 526