aarch64: Fix sve/acle/general/ldff1_8.c failures
[gcc.git] / libphobos / libdruntime / core / internal / gc / pooltable.d
blobf9ec3d2a22b64f53a6cce708cdbb82457b9d9766
1 /**
2 * A sorted array to quickly lookup pools.
4 * Copyright: D Language Foundation 2001 - 2021
5 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6 * Authors: Walter Bright, David Friedman, Sean Kelly, Martin Nowak
7 */
8 module core.internal.gc.pooltable;
10 static import cstdlib=core.stdc.stdlib;
12 struct PoolTable(Pool)
14 import core.stdc.string : memmove;
16 void Dtor() nothrow @nogc
18 cstdlib.free(pools);
19 pools = null;
20 npools = 0;
23 bool insert(Pool* pool) nothrow @nogc
25 auto newpools = cast(Pool **)cstdlib.realloc(pools, (npools + 1) * pools[0].sizeof);
26 if (!newpools)
27 return false;
29 pools = newpools;
31 // Sort pool into newpooltable[]
32 size_t i;
33 for (; i < npools; ++i)
35 if (pool.baseAddr < pools[i].baseAddr)
36 break;
38 if (i != npools)
39 memmove(pools + i + 1, pools + i, (npools - i) * pools[0].sizeof);
40 pools[i] = pool;
42 ++npools;
44 foreach (idx; i .. npools)
45 pools[idx].ptIndex = idx;
47 _minAddr = pools[0].baseAddr;
48 _maxAddr = pools[npools - 1].topAddr;
50 return true;
53 @property size_t length() const scope @safe pure nothrow @nogc
55 return npools;
58 ref inout(Pool*) opIndex(size_t idx) inout return @trusted pure nothrow @nogc
59 in { assert(idx < length); }
62 return pools[idx];
65 inout(Pool*)[] opSlice(size_t a, size_t b) inout return @trusted pure nothrow @nogc
66 in { assert(a <= length && b <= length); }
69 return pools[a .. b];
72 /// Returns: A slice over all pools in this `PoolTable`
73 inout(Pool*)[] opSlice() inout return @trusted pure nothrow @nogc
75 return this.pools[0 .. this.length];
78 alias opDollar = length;
80 /**
81 * Find Pool that pointer is in.
82 * Return null if not in a Pool.
83 * Assume pooltable[] is sorted.
85 Pool *findPool(void *p) nothrow @nogc
87 if (p >= minAddr && p < maxAddr)
89 assert(npools);
91 // let dmd allocate a register for this.pools
92 auto pools = this.pools;
94 if (npools == 1)
95 return pools[0];
97 /* The pooltable[] is sorted by address, so do a binary search
99 size_t low = 0;
100 size_t high = npools - 1;
101 while (low <= high)
103 size_t mid = (low + high) >> 1;
104 auto pool = pools[mid];
105 if (p < pool.baseAddr)
106 high = mid - 1;
107 else if (p >= pool.topAddr)
108 low = mid + 1;
109 else
110 return pool;
113 return null;
116 // semi-stable partition, returns right half for which pred is false
117 Pool*[] minimize() pure nothrow @nogc
119 static void swap(ref Pool* a, ref Pool* b)
121 auto c = a; a = b; b = c;
124 size_t i;
125 // find first bad entry
126 for (; i < npools; ++i)
127 if (pools[i].isFree) break;
129 // move good in front of bad entries
130 size_t j = i + 1;
131 for (; j < npools; ++j)
133 if (!pools[j].isFree) // keep
135 swap(pools[i], pools[j]);
136 pools[i].ptIndex = i;
137 ++i;
140 // npooltable[0 .. i] => used pools
141 // npooltable[i .. npools] => free pools
143 if (i)
145 _minAddr = pools[0].baseAddr;
146 _maxAddr = pools[i - 1].topAddr;
148 else
150 _minAddr = _maxAddr = null;
153 immutable len = npools;
154 npools = i;
155 // return freed pools to the caller
156 return pools[npools .. len];
159 void Invariant() const nothrow @nogc
161 if (!npools) return;
163 foreach (i; 0 .. npools)
164 assert(pools[i].ptIndex == i);
166 foreach (i, pool; pools[0 .. npools - 1])
167 assert(pool.baseAddr < pools[i + 1].baseAddr);
169 assert(_minAddr == pools[0].baseAddr);
170 assert(_maxAddr == pools[npools - 1].topAddr);
173 @property const(void)* minAddr() const @safe pure nothrow @nogc { return _minAddr; }
174 @property const(void)* maxAddr() const @safe pure nothrow @nogc { return _maxAddr; }
176 package:
177 Pool** pools;
178 size_t npools;
179 void* _minAddr, _maxAddr;
182 unittest
184 import core.internal.gc.impl.conservative.gc : PAGESIZE;
186 enum NPOOLS = 6;
187 enum NPAGES = 10;
189 static struct MockPool
191 byte* baseAddr, topAddr;
192 size_t freepages, npages, ptIndex;
193 @property bool isFree() const scope pure nothrow @nogc { return freepages == npages; }
195 PoolTable!MockPool pooltable;
197 void reset()
199 foreach (ref pool; pooltable[0 .. $])
200 pool.freepages = pool.npages;
201 pooltable.minimize();
202 assert(pooltable.length == 0);
204 foreach (i; 0 .. NPOOLS)
206 auto pool = cast(MockPool*)cstdlib.malloc(MockPool.sizeof);
207 *pool = MockPool.init;
208 assert(pooltable.insert(pool));
212 void usePools()
214 foreach (pool; pooltable[0 .. $])
216 pool.npages = NPAGES;
217 pool.freepages = NPAGES / 2;
221 // all pools are free
222 reset();
223 assert(pooltable.length == NPOOLS);
224 auto freed = pooltable.minimize();
225 assert(freed.length == NPOOLS);
226 assert(pooltable.length == 0);
228 // all pools used
229 reset();
230 usePools();
231 assert(pooltable.length == NPOOLS);
232 freed = pooltable.minimize();
233 assert(freed.length == 0);
234 assert(pooltable.length == NPOOLS);
236 // preserves order of used pools
237 reset();
238 usePools();
241 MockPool*[NPOOLS] opools = pooltable[0 .. NPOOLS];
242 // make the 2nd pool free
243 pooltable[2].freepages = NPAGES;
245 pooltable.minimize();
246 assert(pooltable.length == NPOOLS - 1);
247 assert(pooltable[0] == opools[0]);
248 assert(pooltable[1] == opools[1]);
249 assert(pooltable[2] == opools[3]);
252 // test that PoolTable reduces min/max address span
253 reset();
254 usePools();
256 byte* base, top;
259 // fill with fake addresses
260 size_t i;
261 foreach (pool; pooltable[0 .. NPOOLS])
263 pool.baseAddr = cast(byte*)(i++ * NPAGES * PAGESIZE);
264 pool.topAddr = pool.baseAddr + NPAGES * PAGESIZE;
266 base = pooltable[0].baseAddr;
267 top = pooltable[NPOOLS - 1].topAddr;
270 freed = pooltable.minimize();
271 assert(freed.length == 0);
272 assert(pooltable.length == NPOOLS);
273 assert(pooltable.minAddr == base);
274 assert(pooltable.maxAddr == top);
276 pooltable[NPOOLS - 1].freepages = NPAGES;
277 pooltable[NPOOLS - 2].freepages = NPAGES;
279 freed = pooltable.minimize();
280 assert(freed.length == 2);
281 assert(pooltable.length == NPOOLS - 2);
282 assert(pooltable.minAddr == base);
283 assert(pooltable.maxAddr == pooltable[NPOOLS - 3].topAddr);
285 pooltable[0].freepages = NPAGES;
287 freed = pooltable.minimize();
288 assert(freed.length == 1);
289 assert(pooltable.length == NPOOLS - 3);
290 assert(pooltable.minAddr != base);
291 assert(pooltable.minAddr == pooltable[0].baseAddr);
292 assert(pooltable.maxAddr == pooltable[NPOOLS - 4].topAddr);
294 // free all
295 foreach (pool; pooltable[0 .. $])
296 pool.freepages = NPAGES;
297 freed = pooltable.minimize();
298 assert(freed.length == NPOOLS - 3);
299 assert(pooltable.length == 0);
300 pooltable.Dtor();