136ac495dSmrg /* Sparse Arrays for Objective C dispatch tables
2*8feb0f0bSmrg Copyright (C) 1993-2020 Free Software Foundation, Inc.
336ac495dSmrg Contributed by Kresten Krab Thorup.
436ac495dSmrg
536ac495dSmrg This file is part of GCC.
636ac495dSmrg
736ac495dSmrg GCC is free software; you can redistribute it and/or modify
836ac495dSmrg it under the terms of the GNU General Public License as published by
936ac495dSmrg the Free Software Foundation; either version 3, or (at your option)
1036ac495dSmrg any later version.
1136ac495dSmrg
1236ac495dSmrg GCC is distributed in the hope that it will be useful,
1336ac495dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
1436ac495dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1536ac495dSmrg GNU General Public License for more details.
1636ac495dSmrg
1736ac495dSmrg Under Section 7 of GPL version 3, you are granted additional
1836ac495dSmrg permissions described in the GCC Runtime Library Exception, version
1936ac495dSmrg 3.1, as published by the Free Software Foundation.
2036ac495dSmrg
2136ac495dSmrg You should have received a copy of the GNU General Public License and
2236ac495dSmrg a copy of the GCC Runtime Library Exception along with this program;
2336ac495dSmrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
2436ac495dSmrg <http://www.gnu.org/licenses/>. */
2536ac495dSmrg
2636ac495dSmrg #ifndef __sarray_INCLUDE_GNU
2736ac495dSmrg #define __sarray_INCLUDE_GNU
2836ac495dSmrg
2936ac495dSmrg #define OBJC_SPARSE2 /* 2-level sparse array. */
3036ac495dSmrg /* #define OBJC_SPARSE3 */ /* 3-level sparse array. */
3136ac495dSmrg
3236ac495dSmrg #ifdef OBJC_SPARSE2
3336ac495dSmrg extern const char* __objc_sparse2_id;
3436ac495dSmrg #endif
3536ac495dSmrg
3636ac495dSmrg #ifdef OBJC_SPARSE3
3736ac495dSmrg extern const char* __objc_sparse3_id;
3836ac495dSmrg #endif
3936ac495dSmrg
4036ac495dSmrg #include <stddef.h>
4136ac495dSmrg
4236ac495dSmrg extern int nbuckets; /* for stats */
4336ac495dSmrg extern int nindices;
4436ac495dSmrg extern int narrays;
4536ac495dSmrg extern int idxsize;
4636ac495dSmrg
4736ac495dSmrg /* An unsigned integer of same size as a pointer. */
4836ac495dSmrg #define SIZET_BITS (sizeof (size_t) * 8)
4936ac495dSmrg
5036ac495dSmrg #if defined (__sparc__) || defined (OBJC_SPARSE2)
5136ac495dSmrg #define PRECOMPUTE_SELECTORS
5236ac495dSmrg #endif
5336ac495dSmrg
5436ac495dSmrg #ifdef OBJC_SPARSE3
5536ac495dSmrg
5636ac495dSmrg /* Buckets are 8 words each. */
5736ac495dSmrg #define BUCKET_BITS 3
5836ac495dSmrg #define BUCKET_SIZE (1 << BUCKET_BITS)
5936ac495dSmrg #define BUCKET_MASK (BUCKET_SIZE - 1)
6036ac495dSmrg
6136ac495dSmrg /* Indices are 16 words each. */
6236ac495dSmrg #define INDEX_BITS 4
6336ac495dSmrg #define INDEX_SIZE (1 << INDEX_BITS)
6436ac495dSmrg #define INDEX_MASK (INDEX_SIZE - 1)
6536ac495dSmrg
6636ac495dSmrg #define INDEX_CAPACITY (BUCKET_SIZE * INDEX_SIZE)
6736ac495dSmrg
6836ac495dSmrg #else /* OBJC_SPARSE2 */
6936ac495dSmrg
7036ac495dSmrg /* Buckets are 32 words each. */
7136ac495dSmrg #define BUCKET_BITS 5
7236ac495dSmrg #define BUCKET_SIZE (1 << BUCKET_BITS)
7336ac495dSmrg #define BUCKET_MASK (BUCKET_SIZE - 1)
7436ac495dSmrg
7536ac495dSmrg #endif /* OBJC_SPARSE2 */
7636ac495dSmrg
7736ac495dSmrg typedef size_t sidx;
7836ac495dSmrg
7936ac495dSmrg #ifdef PRECOMPUTE_SELECTORS
8036ac495dSmrg
8136ac495dSmrg struct soffset
8236ac495dSmrg {
8336ac495dSmrg #ifdef OBJC_SPARSE3
8436ac495dSmrg unsigned int unused : SIZET_BITS / 4;
8536ac495dSmrg unsigned int eoffset : SIZET_BITS / 4;
8636ac495dSmrg unsigned int boffset : SIZET_BITS / 4;
8736ac495dSmrg unsigned int ioffset : SIZET_BITS / 4;
8836ac495dSmrg #else /* OBJC_SPARSE2 */
8936ac495dSmrg #ifdef __sparc__
9036ac495dSmrg unsigned long boffset : (SIZET_BITS - 2) - BUCKET_BITS;
9136ac495dSmrg unsigned int eoffset : BUCKET_BITS;
9236ac495dSmrg unsigned int unused : 2;
9336ac495dSmrg #else
9436ac495dSmrg unsigned int boffset : SIZET_BITS / 2;
9536ac495dSmrg unsigned int eoffset : SIZET_BITS / 2;
9636ac495dSmrg #endif
9736ac495dSmrg #endif /* OBJC_SPARSE2 */
9836ac495dSmrg };
9936ac495dSmrg
10036ac495dSmrg union sofftype
10136ac495dSmrg {
10236ac495dSmrg struct soffset off;
10336ac495dSmrg sidx idx;
10436ac495dSmrg };
10536ac495dSmrg
10636ac495dSmrg #endif /* not PRECOMPUTE_SELECTORS */
10736ac495dSmrg
10836ac495dSmrg union sversion
10936ac495dSmrg {
11036ac495dSmrg int version;
11136ac495dSmrg void *next_free;
11236ac495dSmrg };
11336ac495dSmrg
11436ac495dSmrg struct sbucket
11536ac495dSmrg {
11636ac495dSmrg /* Elements stored in array. */
11736ac495dSmrg void* elems[BUCKET_SIZE];
11836ac495dSmrg
11936ac495dSmrg /* Used for copy-on-write. */
12036ac495dSmrg union sversion version;
12136ac495dSmrg };
12236ac495dSmrg
12336ac495dSmrg #ifdef OBJC_SPARSE3
12436ac495dSmrg
12536ac495dSmrg struct sindex
12636ac495dSmrg {
12736ac495dSmrg struct sbucket* buckets[INDEX_SIZE];
12836ac495dSmrg
12936ac495dSmrg /* Used for copy-on-write. */
13036ac495dSmrg union sversion version;
13136ac495dSmrg };
13236ac495dSmrg
13336ac495dSmrg #endif /* OBJC_SPARSE3 */
13436ac495dSmrg
13536ac495dSmrg struct sarray
13636ac495dSmrg {
13736ac495dSmrg #ifdef OBJC_SPARSE3
13836ac495dSmrg struct sindex** indices;
13936ac495dSmrg struct sindex* empty_index;
14036ac495dSmrg #else /* OBJC_SPARSE2 */
14136ac495dSmrg struct sbucket** buckets;
14236ac495dSmrg #endif /* OBJC_SPARSE2 */
14336ac495dSmrg struct sbucket* empty_bucket;
14436ac495dSmrg
14536ac495dSmrg /* Used for copy-on-write. */
14636ac495dSmrg union sversion version;
14736ac495dSmrg
14836ac495dSmrg short ref_count;
14936ac495dSmrg struct sarray* is_copy_of;
15036ac495dSmrg size_t capacity;
15136ac495dSmrg };
15236ac495dSmrg
15336ac495dSmrg struct sarray* sarray_new (int, void* default_element);
15436ac495dSmrg void sarray_free (struct sarray*);
15536ac495dSmrg struct sarray* sarray_lazy_copy (struct sarray*);
15636ac495dSmrg void sarray_realloc (struct sarray*, int new_size);
15736ac495dSmrg void sarray_at_put (struct sarray*, sidx indx, void* elem);
15836ac495dSmrg void sarray_at_put_safe (struct sarray*, sidx indx, void* elem);
15936ac495dSmrg
16036ac495dSmrg struct sarray* sarray_hard_copy (struct sarray*); /* ... like the name ? */
16136ac495dSmrg void sarray_remove_garbage (void);
16236ac495dSmrg
16336ac495dSmrg
16436ac495dSmrg #ifdef PRECOMPUTE_SELECTORS
16536ac495dSmrg /* Transform soffset values to ints and vice versa. */
16636ac495dSmrg static inline unsigned int
soffset_decode(sidx indx)16736ac495dSmrg soffset_decode (sidx indx)
16836ac495dSmrg {
16936ac495dSmrg union sofftype x;
17036ac495dSmrg x.idx = indx;
17136ac495dSmrg #ifdef OBJC_SPARSE3
17236ac495dSmrg return x.off.eoffset
17336ac495dSmrg + (x.off.boffset * BUCKET_SIZE)
17436ac495dSmrg + (x.off.ioffset * INDEX_CAPACITY);
17536ac495dSmrg #else /* OBJC_SPARSE2 */
17636ac495dSmrg return x.off.eoffset + (x.off.boffset * BUCKET_SIZE);
17736ac495dSmrg #endif /* OBJC_SPARSE2 */
17836ac495dSmrg }
17936ac495dSmrg
18036ac495dSmrg static inline sidx
soffset_encode(size_t offset)18136ac495dSmrg soffset_encode (size_t offset)
18236ac495dSmrg {
18336ac495dSmrg union sofftype x;
18436ac495dSmrg x.off.eoffset = offset % BUCKET_SIZE;
18536ac495dSmrg #ifdef OBJC_SPARSE3
18636ac495dSmrg x.off.boffset = (offset / BUCKET_SIZE) % INDEX_SIZE;
18736ac495dSmrg x.off.ioffset = offset / INDEX_CAPACITY;
18836ac495dSmrg #else /* OBJC_SPARSE2 */
18936ac495dSmrg x.off.boffset = offset / BUCKET_SIZE;
19036ac495dSmrg #endif
19136ac495dSmrg return (sidx)x.idx;
19236ac495dSmrg }
19336ac495dSmrg
19436ac495dSmrg #else /* not PRECOMPUTE_SELECTORS */
19536ac495dSmrg
19636ac495dSmrg static inline size_t
soffset_decode(sidx indx)19736ac495dSmrg soffset_decode (sidx indx)
19836ac495dSmrg {
19936ac495dSmrg return indx;
20036ac495dSmrg }
20136ac495dSmrg
20236ac495dSmrg static inline sidx
soffset_encode(size_t offset)20336ac495dSmrg soffset_encode (size_t offset)
20436ac495dSmrg {
20536ac495dSmrg return offset;
20636ac495dSmrg }
20736ac495dSmrg #endif /* not PRECOMPUTE_SELECTORS */
20836ac495dSmrg
20936ac495dSmrg /* Get element from the Sparse array `array' at offset `indx'. */
sarray_get(struct sarray * array,sidx indx)21036ac495dSmrg static inline void* sarray_get (struct sarray* array, sidx indx)
21136ac495dSmrg {
21236ac495dSmrg #ifdef PRECOMPUTE_SELECTORS
21336ac495dSmrg union sofftype x;
21436ac495dSmrg x.idx = indx;
21536ac495dSmrg #ifdef OBJC_SPARSE3
21636ac495dSmrg return array->
21736ac495dSmrg indices[x.off.ioffset]->
21836ac495dSmrg buckets[x.off.boffset]->
21936ac495dSmrg elems[x.off.eoffset];
22036ac495dSmrg #else /* OBJC_SPARSE2 */
22136ac495dSmrg return array->buckets[x.off.boffset]->elems[x.off.eoffset];
22236ac495dSmrg #endif /* OBJC_SPARSE2 */
22336ac495dSmrg #else /* not PRECOMPUTE_SELECTORS */
22436ac495dSmrg #ifdef OBJC_SPARSE3
22536ac495dSmrg return array->
22636ac495dSmrg indices[indx / INDEX_CAPACITY]->
22736ac495dSmrg buckets[(indx / BUCKET_SIZE) % INDEX_SIZE]->
22836ac495dSmrg elems[indx % BUCKET_SIZE];
22936ac495dSmrg #else /* OBJC_SPARSE2 */
23036ac495dSmrg return array->buckets[indx / BUCKET_SIZE]->elems[indx % BUCKET_SIZE];
23136ac495dSmrg #endif /* not OBJC_SPARSE3 */
23236ac495dSmrg #endif /* not PRECOMPUTE_SELECTORS */
23336ac495dSmrg }
23436ac495dSmrg
sarray_get_safe(struct sarray * array,sidx indx)23536ac495dSmrg static inline void* sarray_get_safe (struct sarray* array, sidx indx)
23636ac495dSmrg {
23736ac495dSmrg if (soffset_decode (indx) < array->capacity)
23836ac495dSmrg return sarray_get (array, indx);
23936ac495dSmrg else
24036ac495dSmrg return (array->empty_bucket->elems[0]);
24136ac495dSmrg }
24236ac495dSmrg
24336ac495dSmrg #endif /* __sarray_INCLUDE_GNU */
244