source: vendor/gcc/current/libobjc/sarray.c

Last change on this file was 1391, checked in by bird, 21 years ago

GCC v3.3.3 sources.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 14.2 KB
Line 
1/* Sparse Arrays for Objective C dispatch tables
2 Copyright (C) 1993, 1995, 1996, 2002 Free Software Foundation, Inc.
3
4This file is part of GNU CC.
5
6GNU CC is free software; you can redistribute it and/or modify
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
11GNU CC is distributed in the hope that it will be useful,
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
17along with GNU CC; see the file COPYING. If not, write to
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
27#include "sarray.h"
28#include "runtime.h"
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
37static void *first_free_data = NULL; /* !T:MUTEX */
38
39#ifdef OBJC_SPARSE2
40const char *__objc_sparse2_id = "2 level sparse indices";
41#endif
42
43#ifdef OBJC_SPARSE3
44const char *__objc_sparse3_id = "3 level sparse indices";
45#endif
46
47/* This function removes any structures left over from free operations
48 that were not safe in a multi-threaded environment. */
49void
50sarray_remove_garbage (void)
51{
52 void **vp;
53 void *np;
54
55 objc_mutex_lock (__objc_runtime_mutex);
56
57 vp = first_free_data;
58 first_free_data = NULL;
59
60 while (vp) {
61 np = *vp;
62 objc_free (vp);
63 vp = np;
64 }
65
66 objc_mutex_unlock (__objc_runtime_mutex);
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
74sarray_free_garbage (void *vp)
75{
76 objc_mutex_lock (__objc_runtime_mutex);
77
78 if (__objc_runtime_threads_alive == 1) {
79 objc_free (vp);
80 if (first_free_data)
81 sarray_remove_garbage ();
82 }
83 else {
84 *(void **)vp = first_free_data;
85 first_free_data = vp;
86 }
87
88 objc_mutex_unlock (__objc_runtime_mutex);
89}
90
91/* sarray_at_put : copies data in such a way as to be thread reader safe. */
92void
93sarray_at_put (struct sarray *array, sidx index, void *element)
94{
95#ifdef OBJC_SPARSE3
96 struct sindex **the_index;
97 struct sindex *new_index;
98#endif
99 struct sbucket **the_bucket;
100 struct sbucket *new_bucket;
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
125 assert (soffset_decode (index) < array->capacity); /* Range check */
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 */
144 new_index = (struct sindex *) objc_malloc (sizeof (struct sindex));
145 memcpy (new_index, array->empty_index, sizeof (struct sindex));
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 */
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));
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 */
172 new_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket));
173 memcpy ((void *) new_bucket, (const void *) array->empty_bucket,
174 sizeof (struct sbucket));
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. */
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));
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
196sarray_at_put_safe (struct sarray *array, sidx index, void *element)
197{
198 if (soffset_decode (index) >= array->capacity)
199 sarray_realloc (array, soffset_decode (index) + 1);
200 sarray_at_put (array, index, element);
201}
202
203struct sarray *
204sarray_new (int size, void *default_element)
205{
206 struct sarray *arr;
207#ifdef OBJC_SPARSE3
208 size_t num_indices = ((size - 1)/(INDEX_CAPACITY)) + 1;
209 struct sindex **new_indices;
210#else /* OBJC_SPARSE2 */
211 size_t num_indices = ((size - 1)/BUCKET_SIZE) + 1;
212 struct sbucket **new_buckets;
213#endif
214 size_t counter;
215
216 assert (size > 0);
217
218 /* Allocate core array */
219 arr = (struct sarray *) objc_malloc (sizeof (struct sarray));
220 arr->version.version = 0;
221
222 /* Initialize members */
223#ifdef OBJC_SPARSE3
224 arr->capacity = num_indices*INDEX_CAPACITY;
225 new_indices = (struct sindex **)
226 objc_malloc (sizeof (struct sindex *) * num_indices);
227
228 arr->empty_index = (struct sindex *) objc_malloc (sizeof (struct sindex));
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;
237 new_buckets = (struct sbucket **)
238 objc_malloc (sizeof (struct sbucket *) * num_indices);
239
240 narrays += 1;
241 idxsize += num_indices;
242
243#endif
244
245 arr->empty_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket));
246 arr->empty_bucket->version.version = 0;
247
248 nbuckets += 1;
249
250 arr->ref_count = 1;
251 arr->is_copy_of = (struct sarray *) 0;
252
253 for (counter = 0; counter < BUCKET_SIZE; counter++)
254 arr->empty_bucket->elems[counter] = default_element;
255
256#ifdef OBJC_SPARSE3
257 for (counter = 0; counter < INDEX_SIZE; counter++)
258 arr->empty_index->buckets[counter] = arr->empty_bucket;
259
260 for (counter = 0; counter < num_indices; counter++)
261 new_indices[counter] = arr->empty_index;
262
263#else /* OBJC_SPARSE2 */
264
265 for (counter = 0; counter < num_indices; counter++)
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
279
280
281/* Reallocate the sparse array to hold `newsize' entries
282 Note: We really allocate and then free. We have to do this to ensure that
283 any concurrent readers notice the update. */
284
285void
286sarray_realloc (struct sarray *array, int newsize)
287{
288#ifdef OBJC_SPARSE3
289 size_t old_max_index = (array->capacity - 1)/INDEX_CAPACITY;
290 size_t new_max_index = ((newsize - 1)/INDEX_CAPACITY);
291 size_t rounded_size = (new_max_index + 1) * INDEX_CAPACITY;
292
293 struct sindex **new_indices;
294 struct sindex **old_indices;
295
296#else /* OBJC_SPARSE2 */
297 size_t old_max_index = (array->capacity - 1)/BUCKET_SIZE;
298 size_t new_max_index = ((newsize - 1)/BUCKET_SIZE);
299 size_t rounded_size = (new_max_index + 1) * BUCKET_SIZE;
300
301 struct sbucket **new_buckets;
302 struct sbucket **old_buckets;
303
304#endif
305
306 size_t counter;
307
308 assert (newsize > 0);
309
310 /* The size is the same, just ignore the request */
311 if (rounded_size <= array->capacity)
312 return;
313
314 assert (array->ref_count == 1); /* stop if lazy copied... */
315
316 /* We are asked to extend the array -- allocate new bucket table, */
317 /* and insert empty_bucket in newly allocated places. */
318 if (rounded_size > array->capacity)
319 {
320
321#ifdef OBJC_SPARSE3
322 new_max_index += 4;
323 rounded_size = (new_max_index + 1) * INDEX_CAPACITY;
324
325#else /* OBJC_SPARSE2 */
326 new_max_index += 4;
327 rounded_size = (new_max_index + 1) * BUCKET_SIZE;
328#endif
329
330 /* update capacity */
331 array->capacity = rounded_size;
332
333#ifdef OBJC_SPARSE3
334 /* alloc to force re-read by any concurrent readers. */
335 old_indices = array->indices;
336 new_indices = (struct sindex **)
337 objc_malloc ((new_max_index + 1) * sizeof (struct sindex *));
338#else /* OBJC_SPARSE2 */
339 old_buckets = array->buckets;
340 new_buckets = (struct sbucket **)
341 objc_malloc ((new_max_index + 1) * sizeof (struct sbucket *));
342#endif
343
344 /* copy buckets below old_max_index (they are still valid) */
345 for (counter = 0; counter <= old_max_index; counter++ ) {
346#ifdef OBJC_SPARSE3
347 new_indices[counter] = old_indices[counter];
348#else /* OBJC_SPARSE2 */
349 new_buckets[counter] = old_buckets[counter];
350#endif
351 }
352
353#ifdef OBJC_SPARSE3
354 /* reset entries above old_max_index to empty_bucket */
355 for (counter = old_max_index + 1; counter <= new_max_index; counter++)
356 new_indices[counter] = array->empty_index;
357#else /* OBJC_SPARSE2 */
358 /* reset entries above old_max_index to empty_bucket */
359 for (counter = old_max_index + 1; counter <= new_max_index; counter++)
360 new_buckets[counter] = array->empty_bucket;
361#endif
362
363#ifdef OBJC_SPARSE3
364 /* install the new indices */
365 array->indices = new_indices;
366#else /* OBJC_SPARSE2 */
367 array->buckets = new_buckets;
368#endif
369
370#ifdef OBJC_SPARSE3
371 /* free the old indices */
372 sarray_free_garbage (old_indices);
373#else /* OBJC_SPARSE2 */
374 sarray_free_garbage (old_buckets);
375#endif
376
377 idxsize += (new_max_index-old_max_index);
378 return;
379 }
380}
381
382
383
384/* Free a sparse array allocated with sarray_new */
385
386void
387sarray_free (struct sarray *array) {
388#ifdef OBJC_SPARSE3
389 size_t old_max_index = (array->capacity - 1)/INDEX_CAPACITY;
390 struct sindex **old_indices;
391#else
392 size_t old_max_index = (array->capacity - 1)/BUCKET_SIZE;
393 struct sbucket **old_buckets;
394#endif
395 size_t counter = 0;
396
397 assert (array->ref_count != 0); /* Freed multiple times!!! */
398
399 if (--(array->ref_count) != 0) /* There exists copies of me */
400 return;
401
402#ifdef OBJC_SPARSE3
403 old_indices = array->indices;
404#else
405 old_buckets = array->buckets;
406#endif
407
408 if ((array->is_copy_of) && ((array->is_copy_of->ref_count - 1) == 0))
409 sarray_free (array->is_copy_of);
410
411 /* Free all entries that do not point to empty_bucket */
412 for (counter = 0; counter <= old_max_index; counter++ ) {
413#ifdef OBJC_SPARSE3
414 struct sindex *idx = old_indices[counter];
415 if ((idx != array->empty_index) &&
416 (idx->version.version == array->version.version)) {
417 int c2;
418 for (c2 = 0; c2 < INDEX_SIZE; c2++) {
419 struct sbucket *bkt = idx->buckets[c2];
420 if ((bkt != array->empty_bucket) &&
421 (bkt->version.version == array->version.version))
422 {
423 sarray_free_garbage (bkt);
424 nbuckets -= 1;
425 }
426 }
427 sarray_free_garbage (idx);
428 nindices -= 1;
429 }
430#else /* OBJC_SPARSE2 */
431 struct sbucket *bkt = array->buckets[counter];
432 if ((bkt != array->empty_bucket) &&
433 (bkt->version.version == array->version.version))
434 {
435 sarray_free_garbage (bkt);
436 nbuckets -= 1;
437 }
438#endif
439 }
440
441#ifdef OBJC_SPARSE3
442 /* free empty_index */
443 if (array->empty_index->version.version == array->version.version) {
444 sarray_free_garbage (array->empty_index);
445 nindices -= 1;
446 }
447#endif
448
449 /* free empty_bucket */
450 if (array->empty_bucket->version.version == array->version.version) {
451 sarray_free_garbage (array->empty_bucket);
452 nbuckets -= 1;
453 }
454 idxsize -= (old_max_index + 1);
455 narrays -= 1;
456
457#ifdef OBJC_SPARSE3
458 /* free bucket table */
459 sarray_free_garbage (array->indices);
460
461#else
462 /* free bucket table */
463 sarray_free_garbage (array->buckets);
464
465#endif
466
467 /* free array */
468 sarray_free_garbage (array);
469}
470
471/* This is a lazy copy. Only the core of the structure is actually */
472/* copied. */
473
474struct sarray *
475sarray_lazy_copy (struct sarray *oarr)
476{
477 struct sarray *arr;
478
479#ifdef OBJC_SPARSE3
480 size_t num_indices = ((oarr->capacity - 1)/INDEX_CAPACITY) + 1;
481 struct sindex **new_indices;
482#else /* OBJC_SPARSE2 */
483 size_t num_indices = ((oarr->capacity - 1)/BUCKET_SIZE) + 1;
484 struct sbucket **new_buckets;
485#endif
486
487 /* Allocate core array */
488 arr = (struct sarray *) objc_malloc (sizeof (struct sarray)); /* !!! */
489 arr->version.version = oarr->version.version + 1;
490#ifdef OBJC_SPARSE3
491 arr->empty_index = oarr->empty_index;
492#endif
493 arr->empty_bucket = oarr->empty_bucket;
494 arr->ref_count = 1;
495 oarr->ref_count += 1;
496 arr->is_copy_of = oarr;
497 arr->capacity = oarr->capacity;
498
499#ifdef OBJC_SPARSE3
500 /* Copy bucket table */
501 new_indices = (struct sindex **)
502 objc_malloc (sizeof (struct sindex *) * num_indices);
503 memcpy (new_indices, oarr->indices, sizeof (struct sindex *) * num_indices);
504 arr->indices = new_indices;
505#else
506 /* Copy bucket table */
507 new_buckets = (struct sbucket **)
508 objc_malloc (sizeof (struct sbucket *) * num_indices);
509 memcpy (new_buckets, oarr->buckets, sizeof (struct sbucket *) * num_indices);
510 arr->buckets = new_buckets;
511#endif
512
513 idxsize += num_indices;
514 narrays += 1;
515
516 return arr;
517}
Note: See TracBrowser for help on using the repository browser.