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