source: trunk/src/gcc/libobjc/sarray.c@ 1697

Last change on this file since 1697 was 1392, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

  • 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
RevLine 
[2]1/* Sparse Arrays for Objective C dispatch tables
[1391]2 Copyright (C) 1993, 1995, 1996, 2002 Free Software Foundation, Inc.
[2]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
[1391]37static void *first_free_data = NULL; /* !T:MUTEX */
[2]38
39#ifdef OBJC_SPARSE2
[1391]40const char *__objc_sparse2_id = "2 level sparse indices";
[2]41#endif
42
43#ifdef OBJC_SPARSE3
[1391]44const char *__objc_sparse3_id = "3 level sparse indices";
[2]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
[1391]50sarray_remove_garbage (void)
[2]51{
52 void **vp;
53 void *np;
54
[1391]55 objc_mutex_lock (__objc_runtime_mutex);
[2]56
57 vp = first_free_data;
58 first_free_data = NULL;
59
60 while (vp) {
61 np = *vp;
[1391]62 objc_free (vp);
[2]63 vp = np;
64 }
65
[1391]66 objc_mutex_unlock (__objc_runtime_mutex);
[2]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
[1391]74sarray_free_garbage (void *vp)
[2]75{
[1391]76 objc_mutex_lock (__objc_runtime_mutex);
[2]77
78 if (__objc_runtime_threads_alive == 1) {
[1391]79 objc_free (vp);
[2]80 if (first_free_data)
[1391]81 sarray_remove_garbage ();
[2]82 }
83 else {
84 *(void **)vp = first_free_data;
85 first_free_data = vp;
86 }
87
[1391]88 objc_mutex_unlock (__objc_runtime_mutex);
[2]89}
90
91/* sarray_at_put : copies data in such a way as to be thread reader safe. */
92void
[1391]93sarray_at_put (struct sarray *array, sidx index, void *element)
[2]94{
95#ifdef OBJC_SPARSE3
[1391]96 struct sindex **the_index;
97 struct sindex *new_index;
[2]98#endif
[1391]99 struct sbucket **the_bucket;
100 struct sbucket *new_bucket;
[2]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
[1391]125 assert (soffset_decode (index) < array->capacity); /* Range check */
[2]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 */
[1391]144 new_index = (struct sindex *) objc_malloc (sizeof (struct sindex));
145 memcpy (new_index, array->empty_index, sizeof (struct sindex));
[2]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 */
[1391]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));
[2]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 */
[1391]172 new_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket));
173 memcpy ((void *) new_bucket, (const void *) array->empty_bucket,
174 sizeof (struct sbucket));
[2]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. */
[1391]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));
[2]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
[1391]196sarray_at_put_safe (struct sarray *array, sidx index, void *element)
[2]197{
[1391]198 if (soffset_decode (index) >= array->capacity)
199 sarray_realloc (array, soffset_decode (index) + 1);
200 sarray_at_put (array, index, element);
[2]201}
202
[1391]203struct sarray *
204sarray_new (int size, void *default_element)
[2]205{
[1391]206 struct sarray *arr;
[2]207#ifdef OBJC_SPARSE3
[1391]208 size_t num_indices = ((size - 1)/(INDEX_CAPACITY)) + 1;
209 struct sindex **new_indices;
[2]210#else /* OBJC_SPARSE2 */
[1391]211 size_t num_indices = ((size - 1)/BUCKET_SIZE) + 1;
212 struct sbucket **new_buckets;
[2]213#endif
[1391]214 size_t counter;
[2]215
[1391]216 assert (size > 0);
[2]217
218 /* Allocate core array */
[1391]219 arr = (struct sarray *) objc_malloc (sizeof (struct sarray));
[2]220 arr->version.version = 0;
221
222 /* Initialize members */
223#ifdef OBJC_SPARSE3
224 arr->capacity = num_indices*INDEX_CAPACITY;
[1391]225 new_indices = (struct sindex **)
226 objc_malloc (sizeof (struct sindex *) * num_indices);
[2]227
[1391]228 arr->empty_index = (struct sindex *) objc_malloc (sizeof (struct sindex));
[2]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;
[1391]237 new_buckets = (struct sbucket **)
238 objc_malloc (sizeof (struct sbucket *) * num_indices);
[2]239
240 narrays += 1;
241 idxsize += num_indices;
242
243#endif
244
[1391]245 arr->empty_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket));
[2]246 arr->empty_bucket->version.version = 0;
247
248 nbuckets += 1;
249
250 arr->ref_count = 1;
[1391]251 arr->is_copy_of = (struct sarray *) 0;
[2]252
[1391]253 for (counter = 0; counter < BUCKET_SIZE; counter++)
[2]254 arr->empty_bucket->elems[counter] = default_element;
255
256#ifdef OBJC_SPARSE3
[1391]257 for (counter = 0; counter < INDEX_SIZE; counter++)
[2]258 arr->empty_index->buckets[counter] = arr->empty_bucket;
259
[1391]260 for (counter = 0; counter < num_indices; counter++)
[2]261 new_indices[counter] = arr->empty_index;
262
263#else /* OBJC_SPARSE2 */
264
[1391]265 for (counter = 0; counter < num_indices; counter++)
[2]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
[1391]285void
[2]286sarray_realloc (struct sarray *array, int newsize)
287{
[1391]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);
[2]291 size_t rounded_size = (new_max_index + 1) * INDEX_CAPACITY;
[1391]292
293 struct sindex **new_indices;
[2]294 struct sindex **old_indices;
295
[1391]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);
[2]299 size_t rounded_size = (new_max_index + 1) * BUCKET_SIZE;
[1391]300
301 struct sbucket **new_buckets;
[2]302 struct sbucket **old_buckets;
303
304#endif
[1391]305
[2]306 size_t counter;
[1391]307
[2]308 assert (newsize > 0);
309
[1391]310 /* The size is the same, just ignore the request */
[2]311 if (rounded_size <= array->capacity)
312 return;
[1391]313
[2]314 assert (array->ref_count == 1); /* stop if lazy copied... */
315
316 /* We are asked to extend the array -- allocate new bucket table, */
[1391]317 /* and insert empty_bucket in newly allocated places. */
[2]318 if (rounded_size > array->capacity)
319 {
320
321#ifdef OBJC_SPARSE3
[1391]322 new_max_index += 4;
[2]323 rounded_size = (new_max_index + 1) * INDEX_CAPACITY;
324
325#else /* OBJC_SPARSE2 */
[1391]326 new_max_index += 4;
[2]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. */
[1391]335 old_indices = array->indices;
336 new_indices = (struct sindex **)
[2]337 objc_malloc ((new_max_index + 1) * sizeof (struct sindex *));
338#else /* OBJC_SPARSE2 */
[1391]339 old_buckets = array->buckets;
340 new_buckets = (struct sbucket **)
[2]341 objc_malloc ((new_max_index + 1) * sizeof (struct sbucket *));
342#endif
343
[1391]344 /* copy buckets below old_max_index (they are still valid) */
[2]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
[1391]354 /* reset entries above old_max_index to empty_bucket */
[2]355 for (counter = old_max_index + 1; counter <= new_max_index; counter++)
356 new_indices[counter] = array->empty_index;
357#else /* OBJC_SPARSE2 */
[1391]358 /* reset entries above old_max_index to empty_bucket */
[2]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
[1391]371 /* free the old indices */
[2]372 sarray_free_garbage (old_indices);
[1391]373#else /* OBJC_SPARSE2 */
[2]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 */
[1391]385
[2]386void
[1391]387sarray_free (struct sarray *array) {
388#ifdef OBJC_SPARSE3
[2]389 size_t old_max_index = (array->capacity - 1)/INDEX_CAPACITY;
[1391]390 struct sindex **old_indices;
391#else
[2]392 size_t old_max_index = (array->capacity - 1)/BUCKET_SIZE;
[1391]393 struct sbucket **old_buckets;
[2]394#endif
[1391]395 size_t counter = 0;
[2]396
[1391]397 assert (array->ref_count != 0); /* Freed multiple times!!! */
[2]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;
[1391]406#endif
407
[2]408 if ((array->is_copy_of) && ((array->is_copy_of->ref_count - 1) == 0))
409 sarray_free (array->is_copy_of);
[1391]410
[2]411 /* Free all entries that do not point to empty_bucket */
[1391]412 for (counter = 0; counter <= old_max_index; counter++ ) {
413#ifdef OBJC_SPARSE3
[2]414 struct sindex *idx = old_indices[counter];
415 if ((idx != array->empty_index) &&
[1391]416 (idx->version.version == array->version.version)) {
417 int c2;
418 for (c2 = 0; c2 < INDEX_SIZE; c2++) {
[2]419 struct sbucket *bkt = idx->buckets[c2];
420 if ((bkt != array->empty_bucket) &&
[1391]421 (bkt->version.version == array->version.version))
[2]422 {
423 sarray_free_garbage (bkt);
424 nbuckets -= 1;
[1391]425 }
[2]426 }
427 sarray_free_garbage (idx);
428 nindices -= 1;
[1391]429 }
[2]430#else /* OBJC_SPARSE2 */
431 struct sbucket *bkt = array->buckets[counter];
432 if ((bkt != array->empty_bucket) &&
[1391]433 (bkt->version.version == array->version.version))
[2]434 {
435 sarray_free_garbage (bkt);
436 nbuckets -= 1;
437 }
438#endif
439 }
440
[1391]441#ifdef OBJC_SPARSE3
442 /* free empty_index */
[2]443 if (array->empty_index->version.version == array->version.version) {
444 sarray_free_garbage (array->empty_index);
445 nindices -= 1;
446 }
447#endif
[1391]448
449 /* free empty_bucket */
[2]450 if (array->empty_bucket->version.version == array->version.version) {
451 sarray_free_garbage (array->empty_bucket);
[1391]452 nbuckets -= 1;
[2]453 }
454 idxsize -= (old_max_index + 1);
455 narrays -= 1;
456
[1391]457#ifdef OBJC_SPARSE3
[2]458 /* free bucket table */
459 sarray_free_garbage (array->indices);
460
[1391]461#else
[2]462 /* free bucket table */
463 sarray_free_garbage (array->buckets);
464
465#endif
[1391]466
[2]467 /* free array */
468 sarray_free_garbage (array);
469}
470
471/* This is a lazy copy. Only the core of the structure is actually */
[1391]472/* copied. */
473
[2]474struct sarray *
[1391]475sarray_lazy_copy (struct sarray *oarr)
[2]476{
477 struct sarray *arr;
[1391]478
479#ifdef OBJC_SPARSE3
[2]480 size_t num_indices = ((oarr->capacity - 1)/INDEX_CAPACITY) + 1;
[1391]481 struct sindex **new_indices;
482#else /* OBJC_SPARSE2 */
[2]483 size_t num_indices = ((oarr->capacity - 1)/BUCKET_SIZE) + 1;
484 struct sbucket **new_buckets;
485#endif
[1391]486
[2]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
[1391]499#ifdef OBJC_SPARSE3
500 /* Copy bucket table */
501 new_indices = (struct sindex **)
[2]502 objc_malloc (sizeof (struct sindex *) * num_indices);
503 memcpy (new_indices, oarr->indices, sizeof (struct sindex *) * num_indices);
504 arr->indices = new_indices;
[1391]505#else
506 /* Copy bucket table */
507 new_buckets = (struct sbucket **)
[2]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.