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