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