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