Home | History | Annotate | Line # | Download | only in libobjc
      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