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

Last change on this file was 2, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 13.9 KB
Line 
1/* Sparse Arrays for Objective C dispatch tables
2 Copyright (C) 1993, 1995, 1996 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 int 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 int 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
389#ifdef OBJC_SPARSE3
390 size_t old_max_index = (array->capacity-1)/INDEX_CAPACITY;
391 struct sindex ** old_indices;
392#else
393 size_t old_max_index = (array->capacity-1)/BUCKET_SIZE;
394 struct sbucket ** old_buckets;
395#endif
396 int counter = 0;
397
398 assert(array->ref_count != 0); /* Freed multiple times!!! */
399
400 if(--(array->ref_count) != 0) /* There exists copies of me */
401 return;
402
403#ifdef OBJC_SPARSE3
404 old_indices = array->indices;
405#else
406 old_buckets = array->buckets;
407#endif
408
409 if((array->is_copy_of) && ((array->is_copy_of->ref_count - 1) == 0))
410 sarray_free(array->is_copy_of);
411
412 /* Free all entries that do not point to empty_bucket */
413 for(counter = 0; counter <= old_max_index; counter++ ) {
414#ifdef OBJC_SPARSE3
415 struct sindex* idx = old_indices[counter];
416 if((idx != array->empty_index) &&
417 (idx->version.version == array->version.version)) {
418 int c2;
419 for(c2=0; c2<INDEX_SIZE; c2++) {
420 struct sbucket* bkt = idx->buckets[c2];
421 if((bkt != array->empty_bucket) &&
422 (bkt->version.version == array->version.version))
423 {
424 sarray_free_garbage(bkt);
425 nbuckets -= 1;
426 }
427 }
428 sarray_free_garbage(idx);
429 nindices -= 1;
430 }
431#else /* OBJC_SPARSE2 */
432 struct sbucket* bkt = array->buckets[counter];
433 if ((bkt != array->empty_bucket) &&
434 (bkt->version.version == array->version.version))
435 {
436 sarray_free_garbage(bkt);
437 nbuckets -= 1;
438 }
439#endif
440 }
441
442#ifdef OBJC_SPARSE3
443 /* free empty_index */
444 if(array->empty_index->version.version == array->version.version) {
445 sarray_free_garbage(array->empty_index);
446 nindices -= 1;
447 }
448#endif
449
450 /* free empty_bucket */
451 if(array->empty_bucket->version.version == array->version.version) {
452 sarray_free_garbage(array->empty_bucket);
453 nbuckets -= 1;
454 }
455 idxsize -= (old_max_index+1);
456 narrays -= 1;
457
458#ifdef OBJC_SPARSE3
459 /* free bucket table */
460 sarray_free_garbage(array->indices);
461
462#else
463 /* free bucket table */
464 sarray_free_garbage(array->buckets);
465
466#endif
467
468 /* free array */
469 sarray_free_garbage(array);
470}
471
472/* This is a lazy copy. Only the core of the structure is actually */
473/* copied. */
474
475struct sarray*
476sarray_lazy_copy(struct sarray* oarr)
477{
478 struct sarray* arr;
479
480#ifdef OBJC_SPARSE3
481 size_t num_indices = ((oarr->capacity-1)/INDEX_CAPACITY)+1;
482 struct sindex ** new_indices;
483#else /* OBJC_SPARSE2 */
484 size_t num_indices = ((oarr->capacity-1)/BUCKET_SIZE)+1;
485 struct sbucket ** new_buckets;
486#endif
487
488 /* Allocate core array */
489 arr = (struct sarray*) objc_malloc(sizeof(struct sarray)); /* !!! */
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 */
502 new_indices = (struct sindex**)
503 objc_malloc(sizeof(struct sindex*)*num_indices);
504 memcpy( new_indices,oarr->indices,
505 sizeof(struct sindex*)*num_indices);
506 arr->indices = new_indices;
507#else
508 /* Copy bucket table */
509 new_buckets = (struct sbucket**)
510 objc_malloc(sizeof(struct sbucket*)*num_indices);
511 memcpy( new_buckets,oarr->buckets,
512 sizeof(struct sbucket*)*num_indices);
513 arr->buckets = new_buckets;
514#endif
515
516 idxsize += num_indices;
517 narrays += 1;
518
519 return arr;
520}
Note: See TracBrowser for help on using the repository browser.