]> git.ipfire.org Git - thirdparty/gcc.git/blame - libobjc/sarray.c
PR fortran/68401 Improve allocation error message
[thirdparty/gcc.git] / libobjc / sarray.c
CommitLineData
8a7d0ecc 1/* Sparse Arrays for Objective C dispatch tables
fbd26352 2 Copyright (C) 1993-2019 Free Software Foundation, Inc.
8a7d0ecc 3
a622d84f 4This file is part of GCC.
8a7d0ecc 5
a622d84f 6GCC is free software; you can redistribute it and/or modify
8a7d0ecc 7it under the terms of the GNU General Public License as published by
6bc9506f 8the Free Software Foundation; either version 3, or (at your option)
8a7d0ecc 9any later version.
10
a622d84f 11GCC is distributed in the hope that it will be useful,
8a7d0ecc 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
6bc9506f 16Under Section 7 of GPL version 3, you are granted additional
17permissions described in the GCC Runtime Library Exception, version
183.1, as published by the Free Software Foundation.
19
20You should have received a copy of the GNU General Public License and
21a copy of the GCC Runtime Library Exception along with this program;
22see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23<http://www.gnu.org/licenses/>. */
8a7d0ecc 24
e58aa1bc 25#include "objc-private/common.h"
54d533d3 26#include "objc-private/sarray.h"
6ee7a276 27#include "objc/runtime.h" /* For objc_malloc */
28#include "objc/thr.h" /* For objc_mutex_lock */
72c46466 29#include "objc-private/module-abi-8.h"
88457013 30#include "objc-private/runtime.h"
8a7d0ecc 31#include <stdio.h>
1a46e3f1 32#include <string.h> /* For memset */
54d533d3 33#include <assert.h> /* For assert */
8a7d0ecc 34
35int nbuckets = 0; /* !T:MUTEX */
36int nindices = 0; /* !T:MUTEX */
37int narrays = 0; /* !T:MUTEX */
38int idxsize = 0; /* !T:MUTEX */
39
61776355 40static void *first_free_data = NULL; /* !T:MUTEX */
8a7d0ecc 41
42#ifdef OBJC_SPARSE2
61776355 43const char *__objc_sparse2_id = "2 level sparse indices";
8a7d0ecc 44#endif
45
46#ifdef OBJC_SPARSE3
61776355 47const char *__objc_sparse3_id = "3 level sparse indices";
8a7d0ecc 48#endif
49
8a7d0ecc 50/* This function removes any structures left over from free operations
51 that were not safe in a multi-threaded environment. */
52void
61776355 53sarray_remove_garbage (void)
8a7d0ecc 54{
55 void **vp;
56 void *np;
57
61776355 58 objc_mutex_lock (__objc_runtime_mutex);
8a7d0ecc 59
60 vp = first_free_data;
61 first_free_data = NULL;
62
2f8eaca5 63 while (vp)
64 {
65 np = *vp;
66 objc_free (vp);
67 vp = np;
68 }
8a7d0ecc 69
61776355 70 objc_mutex_unlock (__objc_runtime_mutex);
8a7d0ecc 71}
72
2f8eaca5 73/* Free a block of dynamically allocated memory. If we are in
74 multi-threaded mode, it is ok to free it. If not, we add it to the
75 garbage heap to be freed later. */
8a7d0ecc 76static void
61776355 77sarray_free_garbage (void *vp)
8a7d0ecc 78{
61776355 79 objc_mutex_lock (__objc_runtime_mutex);
8a7d0ecc 80
2f8eaca5 81 if (__objc_runtime_threads_alive == 1)
82 {
83 objc_free (vp);
84 if (first_free_data)
85 sarray_remove_garbage ();
86 }
87 else
88 {
89 *(void **)vp = first_free_data;
90 first_free_data = vp;
91 }
92
61776355 93 objc_mutex_unlock (__objc_runtime_mutex);
8a7d0ecc 94}
95
2f8eaca5 96/* sarray_at_put copies data in such a way as to be thread reader
97 safe. */
8a7d0ecc 98void
61776355 99sarray_at_put (struct sarray *array, sidx index, void *element)
8a7d0ecc 100{
101#ifdef OBJC_SPARSE3
61776355 102 struct sindex **the_index;
103 struct sindex *new_index;
8a7d0ecc 104#endif
61776355 105 struct sbucket **the_bucket;
106 struct sbucket *new_bucket;
8a7d0ecc 107#ifdef OBJC_SPARSE3
108 size_t ioffset;
109#endif
110 size_t boffset;
111 size_t eoffset;
112#ifdef PRECOMPUTE_SELECTORS
113 union sofftype xx;
114 xx.idx = index;
115#ifdef OBJC_SPARSE3
116 ioffset = xx.off.ioffset;
117#endif
118 boffset = xx.off.boffset;
119 eoffset = xx.off.eoffset;
120#else /* not PRECOMPUTE_SELECTORS */
121#ifdef OBJC_SPARSE3
122 ioffset = index/INDEX_CAPACITY;
123 boffset = (index/BUCKET_SIZE)%INDEX_SIZE;
124 eoffset = index%BUCKET_SIZE;
125#else
126 boffset = index/BUCKET_SIZE;
127 eoffset = index%BUCKET_SIZE;
128#endif
129#endif /* not PRECOMPUTE_SELECTORS */
130
61776355 131 assert (soffset_decode (index) < array->capacity); /* Range check */
8a7d0ecc 132
133#ifdef OBJC_SPARSE3
134 the_index = &(array->indices[ioffset]);
135 the_bucket = &((*the_index)->buckets[boffset]);
136#else
137 the_bucket = &(array->buckets[boffset]);
138#endif
139
140 if ((*the_bucket)->elems[eoffset] == element)
2f8eaca5 141 return; /* Great! we just avoided a lazy copy. */
8a7d0ecc 142
143#ifdef OBJC_SPARSE3
144
2f8eaca5 145 /* First, perform lazy copy/allocation of index if needed. */
8a7d0ecc 146
2f8eaca5 147 if ((*the_index) == array->empty_index)
148 {
149 /* The index was previously empty, allocate a new. */
150 new_index = (struct sindex *) objc_malloc (sizeof (struct sindex));
151 memcpy (new_index, array->empty_index, sizeof (struct sindex));
152 new_index->version.version = array->version.version;
153 *the_index = new_index; /* Prepared for install. */
154 the_bucket = &((*the_index)->buckets[boffset]);
155
156 nindices += 1;
157 }
158 else if ((*the_index)->version.version != array->version.version)
159 {
160 /* This index must be lazy copied. */
161 struct sindex *old_index = *the_index;
162 new_index = (struct sindex *) objc_malloc (sizeof (struct sindex));
163 memcpy (new_index, old_index, sizeof (struct sindex));
164 new_index->version.version = array->version.version;
165 *the_index = new_index; /* Prepared for install. */
166 the_bucket = &((*the_index)->buckets[boffset]);
167
168 nindices += 1;
169 }
170
8a7d0ecc 171#endif /* OBJC_SPARSE3 */
2f8eaca5 172
173 /* Next, perform lazy allocation/copy of the bucket if needed. */
174 if ((*the_bucket) == array->empty_bucket)
175 {
176 /* The bucket was previously empty (or something like that),
177 allocate a new. This is the effect of `lazy' allocation. */
178 new_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket));
179 memcpy ((void *) new_bucket, (const void *) array->empty_bucket,
180 sizeof (struct sbucket));
181 new_bucket->version.version = array->version.version;
182 *the_bucket = new_bucket; /* Prepared for install. */
183
184 nbuckets += 1;
185
186 }
187 else if ((*the_bucket)->version.version != array->version.version)
188 {
189 /* Perform lazy copy. */
190 struct sbucket *old_bucket = *the_bucket;
191 new_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket));
192 memcpy (new_bucket, old_bucket, sizeof (struct sbucket));
193 new_bucket->version.version = array->version.version;
194 *the_bucket = new_bucket; /* Prepared for install. */
195
196 nbuckets += 1;
197 }
8a7d0ecc 198 (*the_bucket)->elems[eoffset] = element;
199}
200
201void
61776355 202sarray_at_put_safe (struct sarray *array, sidx index, void *element)
8a7d0ecc 203{
61776355 204 if (soffset_decode (index) >= array->capacity)
205 sarray_realloc (array, soffset_decode (index) + 1);
206 sarray_at_put (array, index, element);
8a7d0ecc 207}
208
61776355 209struct sarray *
210sarray_new (int size, void *default_element)
8a7d0ecc 211{
61776355 212 struct sarray *arr;
8a7d0ecc 213#ifdef OBJC_SPARSE3
61776355 214 size_t num_indices = ((size - 1)/(INDEX_CAPACITY)) + 1;
215 struct sindex **new_indices;
8a7d0ecc 216#else /* OBJC_SPARSE2 */
61776355 217 size_t num_indices = ((size - 1)/BUCKET_SIZE) + 1;
218 struct sbucket **new_buckets;
8a7d0ecc 219#endif
adff42e6 220 size_t counter;
8a7d0ecc 221
61776355 222 assert (size > 0);
8a7d0ecc 223
2f8eaca5 224 /* Allocate core array. */
61776355 225 arr = (struct sarray *) objc_malloc (sizeof (struct sarray));
8a7d0ecc 226 arr->version.version = 0;
227
2f8eaca5 228 /* Initialize members. */
8a7d0ecc 229#ifdef OBJC_SPARSE3
230 arr->capacity = num_indices*INDEX_CAPACITY;
61776355 231 new_indices = (struct sindex **)
232 objc_malloc (sizeof (struct sindex *) * num_indices);
2f8eaca5 233
61776355 234 arr->empty_index = (struct sindex *) objc_malloc (sizeof (struct sindex));
8a7d0ecc 235 arr->empty_index->version.version = 0;
236
237 narrays += 1;
238 idxsize += num_indices;
239 nindices += 1;
240
241#else /* OBJC_SPARSE2 */
242 arr->capacity = num_indices*BUCKET_SIZE;
61776355 243 new_buckets = (struct sbucket **)
244 objc_malloc (sizeof (struct sbucket *) * num_indices);
8a7d0ecc 245
246 narrays += 1;
247 idxsize += num_indices;
248
249#endif
250
61776355 251 arr->empty_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket));
8a7d0ecc 252 arr->empty_bucket->version.version = 0;
253
254 nbuckets += 1;
255
256 arr->ref_count = 1;
61776355 257 arr->is_copy_of = (struct sarray *) 0;
8a7d0ecc 258
61776355 259 for (counter = 0; counter < BUCKET_SIZE; counter++)
8a7d0ecc 260 arr->empty_bucket->elems[counter] = default_element;
261
262#ifdef OBJC_SPARSE3
61776355 263 for (counter = 0; counter < INDEX_SIZE; counter++)
8a7d0ecc 264 arr->empty_index->buckets[counter] = arr->empty_bucket;
265
61776355 266 for (counter = 0; counter < num_indices; counter++)
8a7d0ecc 267 new_indices[counter] = arr->empty_index;
268
269#else /* OBJC_SPARSE2 */
270
61776355 271 for (counter = 0; counter < num_indices; counter++)
8a7d0ecc 272 new_buckets[counter] = arr->empty_bucket;
273
274#endif
275
276#ifdef OBJC_SPARSE3
277 arr->indices = new_indices;
278#else /* OBJC_SPARSE2 */
279 arr->buckets = new_buckets;
280#endif
281
282 return arr;
283}
284\f
285
2f8eaca5 286/* Reallocate the sparse array to hold `newsize' entries Note: We
287 really allocate and then free. We have to do this to ensure that
288 any concurrent readers notice the update. */
8a7d0ecc 289void
61776355 290sarray_realloc (struct sarray *array, int newsize)
8a7d0ecc 291{
292#ifdef OBJC_SPARSE3
61776355 293 size_t old_max_index = (array->capacity - 1)/INDEX_CAPACITY;
294 size_t new_max_index = ((newsize - 1)/INDEX_CAPACITY);
295 size_t rounded_size = (new_max_index + 1) * INDEX_CAPACITY;
8a7d0ecc 296
61776355 297 struct sindex **new_indices;
298 struct sindex **old_indices;
8a7d0ecc 299
300#else /* OBJC_SPARSE2 */
61776355 301 size_t old_max_index = (array->capacity - 1)/BUCKET_SIZE;
302 size_t new_max_index = ((newsize - 1)/BUCKET_SIZE);
303 size_t rounded_size = (new_max_index + 1) * BUCKET_SIZE;
8a7d0ecc 304
61776355 305 struct sbucket **new_buckets;
306 struct sbucket **old_buckets;
8a7d0ecc 307
308#endif
309
adff42e6 310 size_t counter;
8a7d0ecc 311
61776355 312 assert (newsize > 0);
8a7d0ecc 313
2f8eaca5 314 /* The size is the same, just ignore the request. */
61776355 315 if (rounded_size <= array->capacity)
8a7d0ecc 316 return;
317
61776355 318 assert (array->ref_count == 1); /* stop if lazy copied... */
8a7d0ecc 319
2f8eaca5 320 /* We are asked to extend the array -- allocate new bucket table,
321 and insert empty_bucket in newly allocated places. */
61776355 322 if (rounded_size > array->capacity)
8a7d0ecc 323 {
8a7d0ecc 324#ifdef OBJC_SPARSE3
325 new_max_index += 4;
61776355 326 rounded_size = (new_max_index + 1) * INDEX_CAPACITY;
8a7d0ecc 327#else /* OBJC_SPARSE2 */
328 new_max_index += 4;
61776355 329 rounded_size = (new_max_index + 1) * BUCKET_SIZE;
8a7d0ecc 330#endif
331
2f8eaca5 332 /* Update capacity. */
8a7d0ecc 333 array->capacity = rounded_size;
334
335#ifdef OBJC_SPARSE3
2f8eaca5 336 /* Alloc to force re-read by any concurrent readers. */
8a7d0ecc 337 old_indices = array->indices;
61776355 338 new_indices = (struct sindex **)
339 objc_malloc ((new_max_index + 1) * sizeof (struct sindex *));
8a7d0ecc 340#else /* OBJC_SPARSE2 */
341 old_buckets = array->buckets;
61776355 342 new_buckets = (struct sbucket **)
343 objc_malloc ((new_max_index + 1) * sizeof (struct sbucket *));
8a7d0ecc 344#endif
345
2f8eaca5 346 /* Copy buckets below old_max_index (they are still valid). */
347 for (counter = 0; counter <= old_max_index; counter++ )
348 {
8a7d0ecc 349#ifdef OBJC_SPARSE3
2f8eaca5 350 new_indices[counter] = old_indices[counter];
8a7d0ecc 351#else /* OBJC_SPARSE2 */
2f8eaca5 352 new_buckets[counter] = old_buckets[counter];
8a7d0ecc 353#endif
2f8eaca5 354 }
8a7d0ecc 355
356#ifdef OBJC_SPARSE3
2f8eaca5 357 /* Reset entries above old_max_index to empty_bucket. */
61776355 358 for (counter = old_max_index + 1; counter <= new_max_index; counter++)
8a7d0ecc 359 new_indices[counter] = array->empty_index;
360#else /* OBJC_SPARSE2 */
2f8eaca5 361 /* Reset entries above old_max_index to empty_bucket. */
61776355 362 for (counter = old_max_index + 1; counter <= new_max_index; counter++)
8a7d0ecc 363 new_buckets[counter] = array->empty_bucket;
364#endif
365
366#ifdef OBJC_SPARSE3
2f8eaca5 367 /* Install the new indices. */
8a7d0ecc 368 array->indices = new_indices;
369#else /* OBJC_SPARSE2 */
370 array->buckets = new_buckets;
371#endif
372
373#ifdef OBJC_SPARSE3
2f8eaca5 374 /* Free the old indices. */
61776355 375 sarray_free_garbage (old_indices);
8a7d0ecc 376#else /* OBJC_SPARSE2 */
61776355 377 sarray_free_garbage (old_buckets);
8a7d0ecc 378#endif
379
380 idxsize += (new_max_index-old_max_index);
381 return;
382 }
383}
384\f
385
386/* Free a sparse array allocated with sarray_new */
8a7d0ecc 387void
61776355 388sarray_free (struct sarray *array) {
8a7d0ecc 389#ifdef OBJC_SPARSE3
61776355 390 size_t old_max_index = (array->capacity - 1)/INDEX_CAPACITY;
391 struct sindex **old_indices;
8a7d0ecc 392#else
61776355 393 size_t old_max_index = (array->capacity - 1)/BUCKET_SIZE;
394 struct sbucket **old_buckets;
8a7d0ecc 395#endif
adff42e6 396 size_t counter = 0;
8a7d0ecc 397
61776355 398 assert (array->ref_count != 0); /* Freed multiple times!!! */
8a7d0ecc 399
61776355 400 if (--(array->ref_count) != 0) /* There exists copies of me */
8a7d0ecc 401 return;
402
403#ifdef OBJC_SPARSE3
404 old_indices = array->indices;
405#else
406 old_buckets = array->buckets;
407#endif
8a7d0ecc 408
2f8eaca5 409 /* Free all entries that do not point to empty_bucket. */
410 for (counter = 0; counter <= old_max_index; counter++ )
411 {
8a7d0ecc 412#ifdef OBJC_SPARSE3
2f8eaca5 413 struct sindex *idx = old_indices[counter];
414 if ((idx != array->empty_index)
415 && (idx->version.version == array->version.version))
416 {
417 int c2;
418 for (c2 = 0; c2 < INDEX_SIZE; c2++)
419 {
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 }
8a7d0ecc 431#else /* OBJC_SPARSE2 */
2f8eaca5 432 struct sbucket *bkt = old_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 }
8a7d0ecc 439#endif
2f8eaca5 440 }
441
8a7d0ecc 442#ifdef OBJC_SPARSE3
2f8eaca5 443 /* Free empty_index. */
444 if (array->empty_index->version.version == array->version.version)
445 {
446 sarray_free_garbage (array->empty_index);
447 nindices -= 1;
448 }
8a7d0ecc 449#endif
450
2f8eaca5 451 /* Free empty_bucket. */
452 if (array->empty_bucket->version.version == array->version.version)
453 {
454 sarray_free_garbage (array->empty_bucket);
455 nbuckets -= 1;
456 }
61776355 457 idxsize -= (old_max_index + 1);
8a7d0ecc 458 narrays -= 1;
2f8eaca5 459
8a7d0ecc 460#ifdef OBJC_SPARSE3
2f8eaca5 461 /* Free bucket table. */
61776355 462 sarray_free_garbage (array->indices);
8a7d0ecc 463#else
2f8eaca5 464 /* Free bucket table. */
61776355 465 sarray_free_garbage (array->buckets);
8a7d0ecc 466#endif
467
dd86e3be 468 /* If this is a copy of another array, we free it (which might just
2f8eaca5 469 decrement its reference count so it will be freed when no longer
470 in use). */
4e2e0242 471 if (array->is_copy_of)
472 sarray_free (array->is_copy_of);
473
2f8eaca5 474 /* Free array. */
61776355 475 sarray_free_garbage (array);
8a7d0ecc 476}
477
2f8eaca5 478/* This is a lazy copy. Only the core of the structure is actually
479 copied. */
61776355 480struct sarray *
481sarray_lazy_copy (struct sarray *oarr)
8a7d0ecc 482{
61776355 483 struct sarray *arr;
8a7d0ecc 484
485#ifdef OBJC_SPARSE3
61776355 486 size_t num_indices = ((oarr->capacity - 1)/INDEX_CAPACITY) + 1;
487 struct sindex **new_indices;
8a7d0ecc 488#else /* OBJC_SPARSE2 */
61776355 489 size_t num_indices = ((oarr->capacity - 1)/BUCKET_SIZE) + 1;
490 struct sbucket **new_buckets;
8a7d0ecc 491#endif
492
2f8eaca5 493 /* Allocate core array. */
61776355 494 arr = (struct sarray *) objc_malloc (sizeof (struct sarray)); /* !!! */
8a7d0ecc 495 arr->version.version = oarr->version.version + 1;
496#ifdef OBJC_SPARSE3
497 arr->empty_index = oarr->empty_index;
498#endif
499 arr->empty_bucket = oarr->empty_bucket;
500 arr->ref_count = 1;
501 oarr->ref_count += 1;
502 arr->is_copy_of = oarr;
503 arr->capacity = oarr->capacity;
504
505#ifdef OBJC_SPARSE3
2f8eaca5 506 /* Copy bucket table. */
61776355 507 new_indices = (struct sindex **)
508 objc_malloc (sizeof (struct sindex *) * num_indices);
509 memcpy (new_indices, oarr->indices, sizeof (struct sindex *) * num_indices);
8a7d0ecc 510 arr->indices = new_indices;
511#else
2f8eaca5 512 /* Copy bucket table. */
61776355 513 new_buckets = (struct sbucket **)
514 objc_malloc (sizeof (struct sbucket *) * num_indices);
515 memcpy (new_buckets, oarr->buckets, sizeof (struct sbucket *) * num_indices);
8a7d0ecc 516 arr->buckets = new_buckets;
517#endif
518
519 idxsize += num_indices;
520 narrays += 1;
521
522 return arr;
523}