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