148fb7bfaSmrg /* Sparse Arrays for Objective C dispatch tables
2*b1e83836Smrg Copyright (C) 1993-2022 Free Software Foundation, Inc.
348fb7bfaSmrg Contributed by Kresten Krab Thorup.
448fb7bfaSmrg
548fb7bfaSmrg This file is part of GCC.
648fb7bfaSmrg
748fb7bfaSmrg GCC is free software; you can redistribute it and/or modify
848fb7bfaSmrg it under the terms of the GNU General Public License as published by
948fb7bfaSmrg the Free Software Foundation; either version 3, or (at your option)
1048fb7bfaSmrg any later version.
1148fb7bfaSmrg
1248fb7bfaSmrg GCC is distributed in the hope that it will be useful,
1348fb7bfaSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
1448fb7bfaSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1548fb7bfaSmrg GNU General Public License for more details.
1648fb7bfaSmrg
1748fb7bfaSmrg Under Section 7 of GPL version 3, you are granted additional
1848fb7bfaSmrg permissions described in the GCC Runtime Library Exception, version
1948fb7bfaSmrg 3.1, as published by the Free Software Foundation.
2048fb7bfaSmrg
2148fb7bfaSmrg You should have received a copy of the GNU General Public License and
2248fb7bfaSmrg a copy of the GCC Runtime Library Exception along with this program;
2348fb7bfaSmrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
2448fb7bfaSmrg <http://www.gnu.org/licenses/>. */
2548fb7bfaSmrg
2648fb7bfaSmrg #ifndef __sarray_INCLUDE_GNU
2748fb7bfaSmrg #define __sarray_INCLUDE_GNU
2848fb7bfaSmrg
2948fb7bfaSmrg #define OBJC_SPARSE2 /* 2-level sparse array. */
3048fb7bfaSmrg /* #define OBJC_SPARSE3 */ /* 3-level sparse array. */
3148fb7bfaSmrg
3248fb7bfaSmrg #ifdef OBJC_SPARSE2
3348fb7bfaSmrg extern const char* __objc_sparse2_id;
3448fb7bfaSmrg #endif
3548fb7bfaSmrg
3648fb7bfaSmrg #ifdef OBJC_SPARSE3
3748fb7bfaSmrg extern const char* __objc_sparse3_id;
3848fb7bfaSmrg #endif
3948fb7bfaSmrg
4048fb7bfaSmrg #include <stddef.h>
4148fb7bfaSmrg
4248fb7bfaSmrg extern int nbuckets; /* for stats */
4348fb7bfaSmrg extern int nindices;
4448fb7bfaSmrg extern int narrays;
4548fb7bfaSmrg extern int idxsize;
4648fb7bfaSmrg
4748fb7bfaSmrg /* An unsigned integer of same size as a pointer. */
4848fb7bfaSmrg #define SIZET_BITS (sizeof (size_t) * 8)
4948fb7bfaSmrg
5048fb7bfaSmrg #if defined (__sparc__) || defined (OBJC_SPARSE2)
5148fb7bfaSmrg #define PRECOMPUTE_SELECTORS
5248fb7bfaSmrg #endif
5348fb7bfaSmrg
5448fb7bfaSmrg #ifdef OBJC_SPARSE3
5548fb7bfaSmrg
5648fb7bfaSmrg /* Buckets are 8 words each. */
5748fb7bfaSmrg #define BUCKET_BITS 3
5848fb7bfaSmrg #define BUCKET_SIZE (1 << BUCKET_BITS)
5948fb7bfaSmrg #define BUCKET_MASK (BUCKET_SIZE - 1)
6048fb7bfaSmrg
6148fb7bfaSmrg /* Indices are 16 words each. */
6248fb7bfaSmrg #define INDEX_BITS 4
6348fb7bfaSmrg #define INDEX_SIZE (1 << INDEX_BITS)
6448fb7bfaSmrg #define INDEX_MASK (INDEX_SIZE - 1)
6548fb7bfaSmrg
6648fb7bfaSmrg #define INDEX_CAPACITY (BUCKET_SIZE * INDEX_SIZE)
6748fb7bfaSmrg
6848fb7bfaSmrg #else /* OBJC_SPARSE2 */
6948fb7bfaSmrg
7048fb7bfaSmrg /* Buckets are 32 words each. */
7148fb7bfaSmrg #define BUCKET_BITS 5
7248fb7bfaSmrg #define BUCKET_SIZE (1 << BUCKET_BITS)
7348fb7bfaSmrg #define BUCKET_MASK (BUCKET_SIZE - 1)
7448fb7bfaSmrg
7548fb7bfaSmrg #endif /* OBJC_SPARSE2 */
7648fb7bfaSmrg
7748fb7bfaSmrg typedef size_t sidx;
7848fb7bfaSmrg
7948fb7bfaSmrg #ifdef PRECOMPUTE_SELECTORS
8048fb7bfaSmrg
8148fb7bfaSmrg struct soffset
8248fb7bfaSmrg {
8348fb7bfaSmrg #ifdef OBJC_SPARSE3
8448fb7bfaSmrg unsigned int unused : SIZET_BITS / 4;
8548fb7bfaSmrg unsigned int eoffset : SIZET_BITS / 4;
8648fb7bfaSmrg unsigned int boffset : SIZET_BITS / 4;
8748fb7bfaSmrg unsigned int ioffset : SIZET_BITS / 4;
8848fb7bfaSmrg #else /* OBJC_SPARSE2 */
8948fb7bfaSmrg #ifdef __sparc__
9048fb7bfaSmrg unsigned long boffset : (SIZET_BITS - 2) - BUCKET_BITS;
9148fb7bfaSmrg unsigned int eoffset : BUCKET_BITS;
9248fb7bfaSmrg unsigned int unused : 2;
9348fb7bfaSmrg #else
9448fb7bfaSmrg unsigned int boffset : SIZET_BITS / 2;
9548fb7bfaSmrg unsigned int eoffset : SIZET_BITS / 2;
9648fb7bfaSmrg #endif
9748fb7bfaSmrg #endif /* OBJC_SPARSE2 */
9848fb7bfaSmrg };
9948fb7bfaSmrg
10048fb7bfaSmrg union sofftype
10148fb7bfaSmrg {
10248fb7bfaSmrg struct soffset off;
10348fb7bfaSmrg sidx idx;
10448fb7bfaSmrg };
10548fb7bfaSmrg
10648fb7bfaSmrg #endif /* not PRECOMPUTE_SELECTORS */
10748fb7bfaSmrg
10848fb7bfaSmrg union sversion
10948fb7bfaSmrg {
11048fb7bfaSmrg int version;
11148fb7bfaSmrg void *next_free;
11248fb7bfaSmrg };
11348fb7bfaSmrg
11448fb7bfaSmrg struct sbucket
11548fb7bfaSmrg {
11648fb7bfaSmrg /* Elements stored in array. */
11748fb7bfaSmrg void* elems[BUCKET_SIZE];
11848fb7bfaSmrg
11948fb7bfaSmrg /* Used for copy-on-write. */
12048fb7bfaSmrg union sversion version;
12148fb7bfaSmrg };
12248fb7bfaSmrg
12348fb7bfaSmrg #ifdef OBJC_SPARSE3
12448fb7bfaSmrg
12548fb7bfaSmrg struct sindex
12648fb7bfaSmrg {
12748fb7bfaSmrg struct sbucket* buckets[INDEX_SIZE];
12848fb7bfaSmrg
12948fb7bfaSmrg /* Used for copy-on-write. */
13048fb7bfaSmrg union sversion version;
13148fb7bfaSmrg };
13248fb7bfaSmrg
13348fb7bfaSmrg #endif /* OBJC_SPARSE3 */
13448fb7bfaSmrg
13548fb7bfaSmrg struct sarray
13648fb7bfaSmrg {
13748fb7bfaSmrg #ifdef OBJC_SPARSE3
13848fb7bfaSmrg struct sindex** indices;
13948fb7bfaSmrg struct sindex* empty_index;
14048fb7bfaSmrg #else /* OBJC_SPARSE2 */
14148fb7bfaSmrg struct sbucket** buckets;
14248fb7bfaSmrg #endif /* OBJC_SPARSE2 */
14348fb7bfaSmrg struct sbucket* empty_bucket;
14448fb7bfaSmrg
14548fb7bfaSmrg /* Used for copy-on-write. */
14648fb7bfaSmrg union sversion version;
14748fb7bfaSmrg
14848fb7bfaSmrg short ref_count;
14948fb7bfaSmrg struct sarray* is_copy_of;
15048fb7bfaSmrg size_t capacity;
15148fb7bfaSmrg };
15248fb7bfaSmrg
15348fb7bfaSmrg struct sarray* sarray_new (int, void* default_element);
15448fb7bfaSmrg void sarray_free (struct sarray*);
15548fb7bfaSmrg struct sarray* sarray_lazy_copy (struct sarray*);
15648fb7bfaSmrg void sarray_realloc (struct sarray*, int new_size);
15748fb7bfaSmrg void sarray_at_put (struct sarray*, sidx indx, void* elem);
15848fb7bfaSmrg void sarray_at_put_safe (struct sarray*, sidx indx, void* elem);
15948fb7bfaSmrg
16048fb7bfaSmrg struct sarray* sarray_hard_copy (struct sarray*); /* ... like the name ? */
16148fb7bfaSmrg void sarray_remove_garbage (void);
16248fb7bfaSmrg
16348fb7bfaSmrg
16448fb7bfaSmrg #ifdef PRECOMPUTE_SELECTORS
16548fb7bfaSmrg /* Transform soffset values to ints and vice versa. */
16648fb7bfaSmrg static inline unsigned int
soffset_decode(sidx indx)16748fb7bfaSmrg soffset_decode (sidx indx)
16848fb7bfaSmrg {
16948fb7bfaSmrg union sofftype x;
17048fb7bfaSmrg x.idx = indx;
17148fb7bfaSmrg #ifdef OBJC_SPARSE3
17248fb7bfaSmrg return x.off.eoffset
17348fb7bfaSmrg + (x.off.boffset * BUCKET_SIZE)
17448fb7bfaSmrg + (x.off.ioffset * INDEX_CAPACITY);
17548fb7bfaSmrg #else /* OBJC_SPARSE2 */
17648fb7bfaSmrg return x.off.eoffset + (x.off.boffset * BUCKET_SIZE);
17748fb7bfaSmrg #endif /* OBJC_SPARSE2 */
17848fb7bfaSmrg }
17948fb7bfaSmrg
18048fb7bfaSmrg static inline sidx
soffset_encode(size_t offset)18148fb7bfaSmrg soffset_encode (size_t offset)
18248fb7bfaSmrg {
18348fb7bfaSmrg union sofftype x;
18448fb7bfaSmrg x.off.eoffset = offset % BUCKET_SIZE;
18548fb7bfaSmrg #ifdef OBJC_SPARSE3
18648fb7bfaSmrg x.off.boffset = (offset / BUCKET_SIZE) % INDEX_SIZE;
18748fb7bfaSmrg x.off.ioffset = offset / INDEX_CAPACITY;
18848fb7bfaSmrg #else /* OBJC_SPARSE2 */
18948fb7bfaSmrg x.off.boffset = offset / BUCKET_SIZE;
19048fb7bfaSmrg #endif
19148fb7bfaSmrg return (sidx)x.idx;
19248fb7bfaSmrg }
19348fb7bfaSmrg
19448fb7bfaSmrg #else /* not PRECOMPUTE_SELECTORS */
19548fb7bfaSmrg
19648fb7bfaSmrg static inline size_t
soffset_decode(sidx indx)19748fb7bfaSmrg soffset_decode (sidx indx)
19848fb7bfaSmrg {
19948fb7bfaSmrg return indx;
20048fb7bfaSmrg }
20148fb7bfaSmrg
20248fb7bfaSmrg static inline sidx
soffset_encode(size_t offset)20348fb7bfaSmrg soffset_encode (size_t offset)
20448fb7bfaSmrg {
20548fb7bfaSmrg return offset;
20648fb7bfaSmrg }
20748fb7bfaSmrg #endif /* not PRECOMPUTE_SELECTORS */
20848fb7bfaSmrg
20948fb7bfaSmrg /* Get element from the Sparse array `array' at offset `indx'. */
sarray_get(struct sarray * array,sidx indx)21048fb7bfaSmrg static inline void* sarray_get (struct sarray* array, sidx indx)
21148fb7bfaSmrg {
21248fb7bfaSmrg #ifdef PRECOMPUTE_SELECTORS
21348fb7bfaSmrg union sofftype x;
21448fb7bfaSmrg x.idx = indx;
21548fb7bfaSmrg #ifdef OBJC_SPARSE3
21648fb7bfaSmrg return array->
21748fb7bfaSmrg indices[x.off.ioffset]->
21848fb7bfaSmrg buckets[x.off.boffset]->
21948fb7bfaSmrg elems[x.off.eoffset];
22048fb7bfaSmrg #else /* OBJC_SPARSE2 */
22148fb7bfaSmrg return array->buckets[x.off.boffset]->elems[x.off.eoffset];
22248fb7bfaSmrg #endif /* OBJC_SPARSE2 */
22348fb7bfaSmrg #else /* not PRECOMPUTE_SELECTORS */
22448fb7bfaSmrg #ifdef OBJC_SPARSE3
22548fb7bfaSmrg return array->
22648fb7bfaSmrg indices[indx / INDEX_CAPACITY]->
22748fb7bfaSmrg buckets[(indx / BUCKET_SIZE) % INDEX_SIZE]->
22848fb7bfaSmrg elems[indx % BUCKET_SIZE];
22948fb7bfaSmrg #else /* OBJC_SPARSE2 */
23048fb7bfaSmrg return array->buckets[indx / BUCKET_SIZE]->elems[indx % BUCKET_SIZE];
23148fb7bfaSmrg #endif /* not OBJC_SPARSE3 */
23248fb7bfaSmrg #endif /* not PRECOMPUTE_SELECTORS */
23348fb7bfaSmrg }
23448fb7bfaSmrg
sarray_get_safe(struct sarray * array,sidx indx)23548fb7bfaSmrg static inline void* sarray_get_safe (struct sarray* array, sidx indx)
23648fb7bfaSmrg {
23748fb7bfaSmrg if (soffset_decode (indx) < array->capacity)
23848fb7bfaSmrg return sarray_get (array, indx);
23948fb7bfaSmrg else
24048fb7bfaSmrg return (array->empty_bucket->elems[0]);
24148fb7bfaSmrg }
24248fb7bfaSmrg
24348fb7bfaSmrg #endif /* __sarray_INCLUDE_GNU */
244