source: trunk/third/gcc/libobjc/sarray.c @ 21199

Revision 21199, 14.2 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21198, which included commits to RCS files with non-trunk default branches.
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 GCC.
5
6GCC 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
11GCC 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 GCC; 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/* 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
285sarray_realloc (struct sarray *array, int newsize)
286{
287#ifdef OBJC_SPARSE3
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;
291
292  struct sindex **new_indices;
293  struct sindex **old_indices;
294 
295#else /* OBJC_SPARSE2 */
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;
299
300  struct sbucket **new_buckets;
301  struct sbucket **old_buckets;
302 
303#endif
304
305  size_t counter;
306
307  assert (newsize > 0);
308
309  /* The size is the same, just ignore the request */
310  if (rounded_size <= array->capacity)
311    return;
312
313  assert (array->ref_count == 1);       /* stop if lazy copied... */
314
315  /* We are asked to extend the array -- allocate new bucket table, */
316  /* and insert empty_bucket in newly allocated places. */
317  if (rounded_size > array->capacity)
318    {
319
320#ifdef OBJC_SPARSE3
321      new_max_index += 4;
322      rounded_size = (new_max_index + 1) * INDEX_CAPACITY;
323     
324#else /* OBJC_SPARSE2 */
325      new_max_index += 4;
326      rounded_size = (new_max_index + 1) * BUCKET_SIZE;
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;
335      new_indices = (struct sindex **)
336        objc_malloc ((new_max_index + 1) * sizeof (struct sindex *));
337#else /* OBJC_SPARSE2 */
338      old_buckets = array->buckets;
339      new_buckets = (struct sbucket **)
340        objc_malloc ((new_max_index + 1) * sizeof (struct sbucket *));
341#endif
342
343      /* copy buckets below old_max_index (they are still valid) */
344      for (counter = 0; counter <= old_max_index; counter++ ) {
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 */
354      for (counter = old_max_index + 1; counter <= new_max_index; counter++)
355        new_indices[counter] = array->empty_index;
356#else /* OBJC_SPARSE2 */
357      /* reset entries above old_max_index to empty_bucket */
358      for (counter = old_max_index + 1; counter <= new_max_index; counter++)
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 */
371      sarray_free_garbage (old_indices);
372#else /* OBJC_SPARSE2 */
373      sarray_free_garbage (old_buckets);
374#endif
375     
376      idxsize += (new_max_index-old_max_index);
377      return;
378    }
379}
380
381
382/* Free a sparse array allocated with sarray_new */
383
384void
385sarray_free (struct sarray *array) {
386#ifdef OBJC_SPARSE3
387  size_t old_max_index = (array->capacity - 1)/INDEX_CAPACITY;
388  struct sindex **old_indices;
389#else
390  size_t old_max_index = (array->capacity - 1)/BUCKET_SIZE;
391  struct sbucket **old_buckets;
392#endif
393  size_t counter = 0;
394
395  assert (array->ref_count != 0);       /* Freed multiple times!!! */
396
397  if (--(array->ref_count) != 0)        /* There exists copies of me */
398    return;
399
400#ifdef OBJC_SPARSE3
401  old_indices = array->indices;
402#else
403  old_buckets = array->buckets;
404#endif
405
406  /* Free all entries that do not point to empty_bucket */
407  for (counter = 0; counter <= old_max_index; counter++ ) {
408#ifdef OBJC_SPARSE3
409    struct sindex *idx = old_indices[counter];
410    if ((idx != array->empty_index) &&
411       (idx->version.version == array->version.version)) {
412      int c2;
413      for (c2 = 0; c2 < INDEX_SIZE; c2++) {
414        struct sbucket *bkt = idx->buckets[c2];
415        if ((bkt != array->empty_bucket) &&
416           (bkt->version.version == array->version.version))
417          {
418            sarray_free_garbage (bkt);
419            nbuckets -= 1;
420          }
421      }
422      sarray_free_garbage (idx);
423      nindices -= 1;
424    }
425#else /* OBJC_SPARSE2 */
426    struct sbucket *bkt = array->buckets[counter];
427    if ((bkt != array->empty_bucket) &&
428        (bkt->version.version == array->version.version))
429      {
430        sarray_free_garbage (bkt);
431        nbuckets -= 1;
432      }
433#endif
434  }
435       
436#ifdef OBJC_SPARSE3 
437  /* free empty_index */
438  if (array->empty_index->version.version == array->version.version) {
439    sarray_free_garbage (array->empty_index);
440    nindices -= 1;
441  }
442#endif
443
444  /* free empty_bucket */
445  if (array->empty_bucket->version.version == array->version.version) {
446    sarray_free_garbage (array->empty_bucket);
447    nbuckets -= 1;
448  }
449  idxsize -= (old_max_index + 1);
450  narrays -= 1;
451
452#ifdef OBJC_SPARSE3
453  /* free bucket table */
454  sarray_free_garbage (array->indices);
455
456#else
457  /* free bucket table */
458  sarray_free_garbage (array->buckets);
459
460#endif
461 
462  /* If this is a copy, go ahead and decrement/deallocate the original */
463  if (array->is_copy_of)
464    sarray_free (array->is_copy_of);
465
466  /* free array */
467  sarray_free_garbage (array);
468}
469
470/* This is a lazy copy.  Only the core of the structure is actually */
471/* copied.   */
472
473struct sarray *
474sarray_lazy_copy (struct sarray *oarr)
475{
476  struct sarray *arr;
477
478#ifdef OBJC_SPARSE3
479  size_t num_indices = ((oarr->capacity - 1)/INDEX_CAPACITY) + 1;
480  struct sindex **new_indices;
481#else /* OBJC_SPARSE2 */
482  size_t num_indices = ((oarr->capacity - 1)/BUCKET_SIZE) + 1;
483  struct sbucket **new_buckets;
484#endif
485
486  /* Allocate core array */
487  arr = (struct sarray *) objc_malloc (sizeof (struct sarray)); /* !!! */
488  arr->version.version = oarr->version.version + 1;
489#ifdef OBJC_SPARSE3
490  arr->empty_index = oarr->empty_index;
491#endif
492  arr->empty_bucket = oarr->empty_bucket;
493  arr->ref_count = 1;
494  oarr->ref_count += 1;
495  arr->is_copy_of = oarr;
496  arr->capacity = oarr->capacity;
497 
498#ifdef OBJC_SPARSE3
499  /* Copy bucket table */
500  new_indices = (struct sindex **)
501    objc_malloc (sizeof (struct sindex *) * num_indices);
502  memcpy (new_indices, oarr->indices, sizeof (struct sindex *) * num_indices);
503  arr->indices = new_indices;
504#else
505  /* Copy bucket table */
506  new_buckets = (struct sbucket **)
507    objc_malloc (sizeof (struct sbucket *) * num_indices);
508  memcpy (new_buckets, oarr->buckets, sizeof (struct sbucket *) * num_indices);
509  arr->buckets = new_buckets;
510#endif
511
512  idxsize += num_indices;
513  narrays += 1;
514 
515  return arr;
516}
Note: See TracBrowser for help on using the repository browser.