aboutsummaryrefslogtreecommitdiffstats
path: root/mps/code
diff options
context:
space:
mode:
authorGareth Rees2013-05-31 13:41:36 +0100
committerGareth Rees2013-05-31 13:41:36 +0100
commit83aff660e27fe56ba6f5c4b898aa00da206c6c9e (patch)
tree8a324c5520c20c8a824c979291d4fbf8602b2faa /mps/code
parent915a41123cdc078220b43fed8d9d44b0845c9493 (diff)
downloademacs-83aff660e27fe56ba6f5c4b898aa00da206c6c9e.tar.gz
emacs-83aff660e27fe56ba6f5c4b898aa00da206c6c9e.zip
Use a tag in the bottom bit to distinguish grains and blocks in the free list. this results in much simplification of the code.
Copied from Perforce Change: 182362 ServerID: perforce.ravenbrook.com
Diffstat (limited to 'mps/code')
-rw-r--r--mps/code/freelist.c611
-rw-r--r--mps/code/freelist.h8
2 files changed, 161 insertions, 458 deletions
diff --git a/mps/code/freelist.c b/mps/code/freelist.c
index 79d10409469..f6e86ddf958 100644
--- a/mps/code/freelist.c
+++ b/mps/code/freelist.c
@@ -15,83 +15,78 @@ SRCID(freelist, "$Id$");
15/* See <design/freelist/#impl.grain.align> */ 15/* See <design/freelist/#impl.grain.align> */
16#define freelistMinimumAlignment ((Align)sizeof(void *)) 16#define freelistMinimumAlignment ((Align)sizeof(void *))
17 17
18#define FreelistBlock(addr) ((Addr *)(addr))
18 19
19/* See <design/freelist/#impl.grain> */ 20#define FreelistTag(addr) ((Word)(addr) & 1)
20typedef struct FreelistGrainStruct { 21#define FreelistTagSet(addr) ((Addr)((Word)(addr) | 1))
21 Addr next; 22#define FreelistTagReset(addr) ((Addr)((Word)(addr) & ~1))
22} FreelistGrainStruct; 23#define FreelistTagCopy(to, from) ((Addr)((Word)(to) | FreelistTag(from)))
23 24
24
25/* FreelistGrain* -- Getters and setters for grains
26 *
27 * See <design/freelist/#impl.grain>.
28 */
29#define FreelistGrainBase(grain) ((Addr)(grain))
30#define FreelistGrainLimit(fl, grain) \
31 AddrAdd(FreelistGrainBase(grain), FreelistGrainSize(fl))
32#define FreelistGrainSize(fl) ((fl)->alignment) 25#define FreelistGrainSize(fl) ((fl)->alignment)
33#define FreelistGrainNext(grain) \
34 ((FreelistGrain)(((FreelistGrain)(grain))->next))
35#define FreelistGrainSetNext(grain, _next) \
36 BEGIN ((FreelistGrain)(grain))->next = (void *)(_next); END
37 26
38 27
39/* FreelistGrainInit -- return grain for the range [base, limit). */ 28/* FreelistBlockLimit -- return the limit of a block. */
40 29
41static FreelistGrain FreelistGrainInit(Freelist fl, Addr base, Addr limit) 30static Addr FreelistBlockLimit(Freelist fl, Addr addr)
42{ 31{
43 FreelistGrain grain = (FreelistGrain)base; 32 Addr *block = FreelistBlock(addr);
44 AVER(AddrOffset(base, limit) == FreelistGrainSize(fl)); 33 if (FreelistTag(block[0])) {
45 FreelistGrainSetNext(grain, NULL); 34 return AddrAdd(addr, FreelistGrainSize(fl));
46 return grain; 35 } else {
36 return block[1];
37 }
47} 38}
48 39
49 40
50/* See <design/freelist/#impl.block> */ 41/* FreelistBlockNext -- return the next block in the list, or NULL if
51typedef struct FreelistBlockStruct { 42 * there are no more blocks.
52 Addr next; 43 */
53 Addr limit; 44static Addr FreelistBlockNext(Freelist fl, Addr addr)
54} FreelistBlockStruct; 45{
46 Addr *block = FreelistBlock(addr);
47 return FreelistTagReset(block[0]);
48}
55 49
56 50
57/* FreelistBlock* -- Getters and setters for blocks 51/* FreelistBlockSize -- return the size of a block. */
58 * 52
59 * See <design/freelist/#impl.block>. 53#define FreelistBlockSize(fl, block) \
60 */ 54 AddrOffset(block, FreelistBlockLimit(fl, block))
61#define FreelistBlockBase(block) ((Addr)(block)) 55
62#define FreelistBlockLimit(block) (((FreelistBlock)(block))->limit) 56
63#define FreelistBlockSize(block) \ 57/* FreelistBlockSetNext -- update the next block in the list */
64 AddrOffset(FreelistBlockBase(block), FreelistBlockLimit(block)) 58
65#define FreelistBlockNext(block) \ 59static void FreelistBlockSetNext(Freelist fl, Addr addr, Addr next)
66 ((FreelistBlock)(((FreelistBlock)(block))->next))
67#define FreelistBlockSetNext(block, _next) \
68 BEGIN ((FreelistBlock)(block))->next = (void *)(_next); END
69#define FreelistBlockSetLimit(block, _limit) \
70 BEGIN { \
71 AVER(AddrOffset(block, _limit) >= sizeof(FreelistBlockStruct)); \
72 ((FreelistBlock)(block))->limit = (void *)(_limit); \
73 } END
74
75
76/* FreelistBlockCheck -- check block. */
77
78static Bool FreelistBlockCheck(FreelistBlock block)
79{ 60{
80 CHECKL(FreelistBlockBase(block) < FreelistBlockLimit(block)); 61 Addr *block = FreelistBlock(addr);
81 return TRUE; 62 block[0] = FreelistTagCopy(next, block[0]);
63}
64
65
66/* FreelistBlockSetLimit -- update the limit of a block */
67
68static void FreelistBlockSetLimit(Freelist fl, Addr addr, Addr limit)
69{
70 Addr *block = FreelistBlock(addr);
71 Size size = size;
72 if (size > FreelistGrainSize(fl)) {
73 block[0] = FreelistTagReset(block[0]);
74 block[1] = limit;
75 } else {
76 AVER(size == FreelistGrainSize(fl));
77 block[0] = FreelistTagSet(block[0]);
78 }
82} 79}
83 80
84 81
85/* FreelistBlockInit -- return block for the range [base, limit). */ 82/* FreelistBlockInit -- return block for the range [base, limit). */
86 83
87static FreelistBlock FreelistBlockInit(Addr base, Addr limit) 84static Addr FreelistBlockInit(Freelist fl, Addr base, Addr limit)
88{ 85{
89 FreelistBlock block; 86 Addr *block = FreelistBlock(base);
90 AVER(AddrOffset(base, limit) >= sizeof(FreelistBlockStruct)); 87 block[0] = NULL;
91 block = (FreelistBlock)base; 88 FreelistBlockSetLimit(fl, base, limit);
92 FreelistBlockSetNext(block, NULL); 89 return base;
93 FreelistBlockSetLimit(block, limit);
94 return block;
95} 90}
96 91
97 92
@@ -100,24 +95,20 @@ Bool FreelistCheck(Freelist fl)
100 CHECKS(Freelist, fl); 95 CHECKS(Freelist, fl);
101 /* See <design/freelist/#impl.grain.align> */ 96 /* See <design/freelist/#impl.grain.align> */
102 CHECKL(AlignIsAligned(fl->alignment, freelistMinimumAlignment)); 97 CHECKL(AlignIsAligned(fl->alignment, freelistMinimumAlignment));
103 /* can't check blockList or grainList more */ 98 /* can't check list or listSize */
104 /* Checking blockListSize and grainListSize is too laborious without
105 a List ADT */
106 return TRUE; 99 return TRUE;
107} 100}
108 101
109 102
110Res FreelistInit(Freelist fl, Align alignment) 103Res FreelistInit(Freelist fl, Align alignment)
111{ 104{
112 /* See <design/freelist/#impl.grain.align> */ 105 /* See <design/freelist/#impl.grain> */
113 if (!AlignIsAligned(alignment, freelistMinimumAlignment)) 106 if (!AlignIsAligned(alignment, freelistMinimumAlignment))
114 return ResPARAM; 107 return ResPARAM;
115 108
116 fl->alignment = alignment; 109 fl->alignment = alignment;
117 fl->blockList = NULL; 110 fl->list = NULL;
118 fl->blockListSize = 0; 111 fl->listSize = 0;
119 fl->grainList = NULL;
120 fl->grainListSize = 0;
121 112
122 fl->sig = FreelistSig; 113 fl->sig = FreelistSig;
123 AVERT(Freelist, fl); 114 AVERT(Freelist, fl);
@@ -129,27 +120,7 @@ void FreelistFinish(Freelist fl)
129{ 120{
130 AVERT(Freelist, fl); 121 AVERT(Freelist, fl);
131 fl->sig = SigInvalid; 122 fl->sig = SigInvalid;
132 123 fl->list = NULL;
133 fl->blockList = NULL;
134 fl->grainList = NULL;
135}
136
137
138/* freelistGrainSetPrevNext -- make 'next' be the next grain in the
139 * list after 'prev', or make it the first grain in the list if 'prev'
140 * is NULL. Update the count of grains by 'delta'.
141 */
142static void freelistGrainSetPrevNext(Freelist fl, FreelistGrain prev,
143 FreelistGrain next, int delta)
144{
145 if (prev) {
146 FreelistGrainSetNext(prev, next);
147 } else {
148 fl->grainList = next;
149 }
150 if (delta < 0)
151 AVER(fl->grainListSize >= -delta);
152 fl->grainListSize += delta;
153} 124}
154 125
155 126
@@ -157,26 +128,24 @@ static void freelistGrainSetPrevNext(Freelist fl, FreelistGrain prev,
157 * list after 'prev', or make it the first block in the list if 'prev' 128 * list after 'prev', or make it the first block in the list if 'prev'
158 * is NULL. Update the count of blocks by 'delta'. 129 * is NULL. Update the count of blocks by 'delta'.
159 */ 130 */
160static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev, 131static void freelistBlockSetPrevNext(Freelist fl, Addr prev,
161 FreelistBlock next, int delta) 132 Addr next, int delta)
162{ 133{
163 if (prev) { 134 if (prev) {
164 FreelistBlockSetNext(prev, next); 135 FreelistBlockSetNext(fl, prev, next);
165 } else { 136 } else {
166 fl->blockList = next; 137 fl->list = next;
167 } 138 }
168 if (delta < 0) 139 if (delta < 0)
169 AVER(fl->blockListSize >= -delta); 140 AVER(fl->listSize >= -delta);
170 fl->blockListSize += delta; 141 fl->listSize += delta;
171} 142}
172 143
173 144
174Res FreelistInsert(Range rangeReturn, Freelist fl, Range range) 145Res FreelistInsert(Range rangeReturn, Freelist fl, Range range)
175{ 146{
176 FreelistGrain grainPrev, grainCur, grainNext, grainNew; 147 Addr prev, cur, next, new;
177 FreelistBlock blockPrev, blockCur, blockNext, blockNew;
178 Addr base, limit; 148 Addr base, limit;
179 Size size;
180 Bool coalesceLeft, coalesceRight; 149 Bool coalesceLeft, coalesceRight;
181 Res res = ResOK; 150 Res res = ResOK;
182 151
@@ -184,115 +153,53 @@ Res FreelistInsert(Range rangeReturn, Freelist fl, Range range)
184 AVERT(Freelist, fl); 153 AVERT(Freelist, fl);
185 AVERT(Range, range); 154 AVERT(Range, range);
186 AVER(RangeIsAligned(range, fl->alignment)); 155 AVER(RangeIsAligned(range, fl->alignment));
156 AVER(RangeSize(range) >= FreelistGrainSize(fl));
187 157
188 size = RangeSize(range);
189 AVER(size >= FreelistGrainSize(fl));
190 base = RangeBase(range); 158 base = RangeBase(range);
191 limit = RangeLimit(range); 159 limit = RangeLimit(range);
192 160
193 /* In order to correctly detect erroneous input (that is, range 161 prev = NULL;
194 * overlapping with some existing block or grain), we must check for 162 cur = fl->list;
195 * overlap with both the block list and the grain list *before* 163 while (cur) {
196 * trying to coalesce with either, lest we find ourselves in the 164 if (base < FreelistBlockLimit(fl, cur) && cur < limit)
197 * embarrassing position of having coalesced the range with a block 165 return ResFAIL; /* range overlaps with cur */
198 * only to find that it overlaps with a grain (or vice versa). 166 if (limit <= cur)
199 */
200 grainPrev = NULL;
201 grainCur = fl->grainList;
202 grainNext = NULL;
203 while (grainCur) {
204 if (base < FreelistGrainLimit(fl, grainCur)
205 && FreelistGrainBase(grainCur) < limit)
206 return ResFAIL; /* range overlaps with grainCur */
207 if (limit <= FreelistGrainBase(grainCur))
208 break;
209 /* The following test is a special case for grains. In the block
210 * case we can safely wait until the next time around the loop
211 * because if range coalesces on the left with blockPrev then
212 * blockPrev->limit can be adjusted. But in the grain case if we
213 * coalesce we remove the grain from the grain list, so we have to
214 * ensure that we retain a pointer to the previous grain so that
215 * we can update grainPrev->next.
216 */
217 if (base == FreelistGrainLimit(fl, grainCur))
218 break;
219 grainNext = FreelistGrainNext(grainCur);
220 if (grainNext)
221 AVER(FreelistGrainLimit(fl, grainCur) < FreelistGrainBase(grainNext));
222 grainPrev = grainCur;
223 grainCur = grainNext;
224 }
225
226 blockPrev = NULL;
227 blockCur = fl->blockList;
228 while (blockCur) {
229 AVERT(FreelistBlock, blockCur);
230 if (base < FreelistBlockLimit(blockCur)
231 && FreelistBlockBase(blockCur) < limit)
232 return ResFAIL; /* range overlaps with blockCur */
233 if (limit <= FreelistBlockBase(blockCur))
234 break; 167 break;
235 blockNext = FreelistBlockNext(blockCur); 168 next = FreelistBlockNext(fl, cur);
236 if (blockNext) 169 if (next)
237 AVER(FreelistBlockLimit(blockCur) < FreelistBlockBase(blockNext)); 170 /* Isolated range invariant (design.mps.freelist.impl.invariant). */
238 blockPrev = blockCur; 171 AVER(FreelistBlockLimit(fl, cur) < next);
239 blockCur = blockNext; 172 prev = cur;
173 cur = next;
240 } 174 }
241 175
242 /* Now we know that range does not overlap with any block or grain, 176 /* Now we know that range does not overlap with any block, and if it
243 * and if it coalesces then it does so with blockPrev on the left, 177 * coalesces then it does so with prev on the left, and cur on the
244 * with blockCur on the right, with grainCur on either side, and/or 178 * right.
245 * with grainNext on the right. Try the grains first.
246 */ 179 */
247 if (grainCur && limit == FreelistGrainBase(grainCur)) { 180 coalesceLeft = (prev && base == FreelistBlockLimit(fl, prev));
248 /* Coalesce with grainCur on the right and delete grainCur */ 181 coalesceRight = (cur && limit == cur);
249 limit = FreelistGrainLimit(fl, grainCur);
250 freelistGrainSetPrevNext(fl, grainPrev, grainNext, -1);
251
252 } else if (grainCur && base == FreelistGrainLimit(fl, grainCur)
253 && grainNext && limit == FreelistGrainBase(grainNext)) {
254 /* Coalesce with grainCur on the left and grainNext on the right
255 * and delete both grains. */
256 base = FreelistGrainBase(grainCur);
257 limit = FreelistGrainLimit(fl, grainNext);
258 freelistGrainSetPrevNext(fl, grainPrev, FreelistGrainNext(grainNext), -2);
259
260 } else if (grainCur && base == FreelistGrainLimit(fl, grainCur)) {
261 /* Coalesce with grainCur on the left and delete grainCur */
262 base = FreelistGrainBase(grainCur);
263 freelistGrainSetPrevNext(fl, grainPrev, grainNext, -1);
264 }
265
266 /* now try to coalesce with blocks */
267 coalesceLeft = (blockPrev && base == FreelistBlockLimit(blockPrev));
268 coalesceRight = (blockCur && limit == FreelistBlockBase(blockCur));
269 182
270 if (coalesceLeft && coalesceRight) { 183 if (coalesceLeft && coalesceRight) {
271 base = FreelistBlockBase(blockPrev); 184 base = prev;
272 limit = FreelistBlockLimit(blockCur); 185 limit = FreelistBlockLimit(fl, cur);
273 FreelistBlockSetLimit(blockPrev, limit); 186 FreelistBlockSetLimit(fl, prev, limit);
274 freelistBlockSetPrevNext(fl, blockPrev, blockNext, -1); 187 freelistBlockSetPrevNext(fl, prev, next, -1);
275 188
276 } else if (coalesceLeft) { 189 } else if (coalesceLeft) {
277 base = FreelistBlockBase(blockPrev); 190 base = prev;
278 FreelistBlockSetLimit(blockPrev, limit); 191 FreelistBlockSetLimit(fl, prev, limit);
279 192
280 } else if (coalesceRight) { 193 } else if (coalesceRight) {
281 limit = FreelistBlockLimit(blockCur); 194 limit = FreelistBlockLimit(fl, cur);
282 blockCur = FreelistBlockInit(base, limit); 195 cur = FreelistBlockInit(fl, base, limit);
283 FreelistBlockSetNext(blockCur, blockNext); 196 FreelistBlockSetNext(fl, cur, next);
284
285 } else if (size > FreelistGrainSize(fl)) {
286 /* failed to coalesce: add new block */
287 blockNew = FreelistBlockInit(base, limit);
288 FreelistBlockSetNext(blockNew, blockCur);
289 freelistBlockSetPrevNext(fl, blockPrev, blockNew, +1);
290 197
291 } else { 198 } else {
292 /* failed to coalesce: add new grain */ 199 /* failed to coalesce: add new block */
293 grainNew = FreelistGrainInit(fl, base, limit); 200 new = FreelistBlockInit(fl, base, limit);
294 FreelistGrainSetNext(grainNew, grainNext); 201 FreelistBlockSetNext(fl, new, cur);
295 freelistGrainSetPrevNext(fl, grainPrev, grainNew, +1); 202 freelistBlockSetPrevNext(fl, prev, new, +1);
296 } 203 }
297 204
298 RangeInit(rangeReturn, base, limit); 205 RangeInit(rangeReturn, base, limit);
@@ -300,34 +207,6 @@ Res FreelistInsert(Range rangeReturn, Freelist fl, Range range)
300} 207}
301 208
302 209
303/* freelistInsertGrain -- Insert a grain (that is known to be isolated
304 * from all blocks and grains) into the free list.
305 */
306static void freelistInsertGrain(Freelist fl, FreelistGrain grain)
307{
308 FreelistGrain prev, cur, next;
309
310 prev = NULL;
311 cur = fl->grainList;
312 while (cur) {
313 if (prev)
314 AVER(FreelistGrainLimit(fl, prev) < FreelistGrainBase(cur));
315 if ((prev == NULL
316 || FreelistGrainLimit(fl, prev) < FreelistGrainBase(grain))
317 && FreelistGrainLimit(fl, grain) < FreelistGrainBase(cur))
318 break;
319 AVER(FreelistGrainLimit(fl, grain) != FreelistGrainBase(cur));
320 AVER(FreelistGrainBase(grain) != FreelistGrainLimit(fl, cur));
321 next = FreelistGrainNext(cur);
322 prev = cur;
323 cur = next;
324 }
325
326 FreelistGrainSetNext(grain, cur);
327 freelistGrainSetPrevNext(fl, prev, grain, +1);
328}
329
330
331/* freelistDeleteFromBlock -- delete 'range' from 'block' (it is known 210/* freelistDeleteFromBlock -- delete 'range' from 'block' (it is known
332 * to be a subset of that block); update 'rangeReturn' to the original 211 * to be a subset of that block); update 'rangeReturn' to the original
333 * range of 'block' and update the block list accordingly: 'prev' is 212 * range of 'block' and update the block list accordingly: 'prev' is
@@ -335,103 +214,57 @@ static void freelistInsertGrain(Freelist fl, FreelistGrain grain)
335 * the first block on the list. 214 * the first block on the list.
336 */ 215 */
337static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl, 216static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl,
338 Range range, FreelistBlock prev, 217 Range range, Addr prev, Addr block)
339 FreelistBlock block)
340{ 218{
341 FreelistBlock next, blockNew; 219 Addr next, new;
342 Addr base, limit, blockBase, blockLimit; 220 Addr base, limit, blockBase, blockLimit;
343 221
344 AVER(rangeReturn != NULL); 222 AVER(rangeReturn != NULL);
345 AVERT(Freelist, fl); 223 AVERT(Freelist, fl);
346 AVERT(Range, range); 224 AVERT(Range, range);
347 AVER(RangeIsAligned(range, fl->alignment)); 225 AVER(RangeIsAligned(range, fl->alignment));
348 AVER(prev == NULL || FreelistBlockNext(prev) == block); 226 AVER(prev == NULL || FreelistBlockNext(fl, prev) == block);
349 AVER(block != NULL); 227 AVER(block != NULL);
350 228
351 AVER(FreelistBlockBase(block) <= RangeBase(range)); 229 AVER(block <= RangeBase(range));
352 AVER(RangeLimit(range) <= FreelistBlockLimit(block)); 230 AVER(RangeLimit(range) <= FreelistBlockLimit(fl, block));
353 231
354 base = RangeBase(range); 232 base = RangeBase(range);
355 limit = RangeLimit(range); 233 limit = RangeLimit(range);
356 blockBase = FreelistBlockBase(block); 234 blockBase = block;
357 blockLimit = FreelistBlockLimit(block); 235 blockLimit = FreelistBlockLimit(fl, block);
358 next = FreelistBlockNext(block); 236 next = FreelistBlockNext(fl, block);
359
360 /* There are NINE (count 'em!) cases here, because on both sides
361 * the deletion might leave no fragment, a grain, or a block. */
362 237
363 if (base == blockBase && limit == blockLimit) { 238 if (base == blockBase && limit == blockLimit) {
364 /* No fragment at left; no fragment at right. */ 239 /* No fragment at left; no fragment at right. */
365 freelistBlockSetPrevNext(fl, prev, next, -1); 240 freelistBlockSetPrevNext(fl, prev, next, -1);
366 241
367 } else if (base == blockBase
368 && FreelistGrainLimit(fl, limit) == blockLimit)
369 {
370 /* No fragment at left; grain at right. */
371 freelistBlockSetPrevNext(fl, prev, next, -1);
372 freelistInsertGrain(fl, FreelistGrainInit(fl, limit, blockLimit));
373
374 } else if (base == blockBase) { 242 } else if (base == blockBase) {
375 /* No fragment at left; block at right. */ 243 /* No fragment at left; block at right. */
376 block = FreelistBlockInit(limit, blockLimit); 244 block = FreelistBlockInit(fl, limit, blockLimit);
377 FreelistBlockSetNext(block, next); 245 FreelistBlockSetNext(fl, block, next);
378 freelistBlockSetPrevNext(fl, prev, block, 0); 246 freelistBlockSetPrevNext(fl, prev, block, 0);
379 247
380 } else if (FreelistGrainLimit(fl, blockBase) == base
381 && limit == blockLimit)
382 {
383 /* Grain at left; no fragment at right. */
384 freelistBlockSetPrevNext(fl, prev, next, -1);
385 freelistInsertGrain(fl, FreelistGrainInit(fl, blockBase, base));
386
387 } else if (limit == blockLimit) { 248 } else if (limit == blockLimit) {
388 /* Block at left; no frament at right. */ 249 /* Block at left; no fragment at right. */
389 FreelistBlockSetLimit(block, base); 250 FreelistBlockSetLimit(fl, block, base);
390
391 } else if (FreelistGrainLimit(fl, blockBase) == base
392 && FreelistGrainLimit(fl, limit) == blockLimit)
393 {
394 /* Grain at left; grain at right. */
395 freelistBlockSetPrevNext(fl, prev, next, -1);
396 freelistInsertGrain(fl, FreelistGrainInit(fl, blockBase, base));
397 freelistInsertGrain(fl, FreelistGrainInit(fl, limit, blockLimit));
398
399 } else if (FreelistGrainLimit(fl, blockBase) == base) {
400 /* Grain at left; block at right. */
401 block = FreelistBlockInit(limit, blockLimit);
402 FreelistBlockSetNext(block, next);
403 freelistBlockSetPrevNext(fl, prev, block, 0);
404 freelistInsertGrain(fl, FreelistGrainInit(fl, blockBase, base));
405
406 } else if (FreelistGrainLimit(fl, limit) == blockLimit) {
407 /* Block at left; grain at right. */
408 AVER(FreelistGrainLimit(fl, blockBase) < base);
409 FreelistBlockSetLimit(block, base);
410 freelistInsertGrain(fl, FreelistGrainInit(fl, limit, blockLimit));
411 251
412 } else { 252 } else {
413 /* Block at left; block at right. */ 253 /* Block at left; block at right. */
414 FreelistBlockSetLimit(block, base); 254 FreelistBlockSetLimit(fl, block, base);
415 blockNew = FreelistBlockInit(limit, blockLimit); 255 new = FreelistBlockInit(fl, limit, blockLimit);
416 FreelistBlockSetNext(blockNew, next); 256 FreelistBlockSetNext(fl, new, next);
417 freelistBlockSetPrevNext(fl, block, blockNew, +1); 257 freelistBlockSetPrevNext(fl, block, new, +1);
418 } 258 }
419 259
420 RangeInit(rangeReturn, blockBase, blockLimit); 260 RangeInit(rangeReturn, blockBase, blockLimit);
421} 261}
422 262
423 263
424/* freelistDeleteFromBlockList -- if 'range' is found in the block 264Res FreelistDelete(Range rangeReturn, Freelist fl, Range range)
425 * list, delete it, update 'rangeReturn' to the range of the block
426 * that contained 'range' and return ResOK. Otherwise, return ResFAIL.
427 * (This might mean that the range was not found at all in the block
428 * list, or that it was only partially found.)
429 */
430static Res freelistDeleteFromBlockList(Range rangeReturn, Freelist fl,
431 Range range)
432{ 265{
433 Res res; 266 Res res;
434 FreelistBlock prev, cur, next, blockNew; 267 Addr prev, cur, next, new;
435 Addr base, limit; 268 Addr base, limit;
436 269
437 AVER(rangeReturn != NULL); 270 AVER(rangeReturn != NULL);
@@ -442,12 +275,11 @@ static Res freelistDeleteFromBlockList(Range rangeReturn, Freelist fl,
442 limit = RangeLimit(range); 275 limit = RangeLimit(range);
443 276
444 prev = NULL; 277 prev = NULL;
445 cur = fl->blockList; 278 cur = fl->list;
446 while (cur) { 279 while (cur) {
447 Addr blockBase, blockLimit; 280 Addr blockBase, blockLimit;
448 AVERT(FreelistBlock, cur); 281 blockBase = cur;
449 blockBase = FreelistBlockBase(cur); 282 blockLimit = FreelistBlockLimit(fl, cur);
450 blockLimit = FreelistBlockLimit(cur);
451 283
452 if (limit <= blockBase) 284 if (limit <= blockBase)
453 return ResFAIL; /* not found */ 285 return ResFAIL; /* not found */
@@ -458,7 +290,7 @@ static Res freelistDeleteFromBlockList(Range rangeReturn, Freelist fl,
458 return ResOK; 290 return ResOK;
459 } 291 }
460 292
461 next = FreelistBlockNext(cur); 293 next = FreelistBlockNext(fl, cur);
462 prev = cur; 294 prev = cur;
463 cur = next; 295 cur = next;
464 } 296 }
@@ -468,118 +300,29 @@ static Res freelistDeleteFromBlockList(Range rangeReturn, Freelist fl,
468} 300}
469 301
470 302
471/* freelistDeleteFromGrainList -- if 'range' is found in the grain
472 * list, delete it, update 'rangeReturn' to the range of the grain
473 * that contained 'range' and return ResOK. Otherwise, return ResFAIL.
474 */
475static Res freelistDeleteFromGrainList(Range rangeReturn, Freelist fl,
476 Range range)
477{
478 Addr base, limit;
479 FreelistGrain prev, cur, next;
480
481 AVER(rangeReturn != NULL);
482 AVERT(Freelist, fl);
483 AVERT(Range, range);
484
485 if (RangeSize(range) != FreelistGrainSize(fl))
486 return ResFAIL;
487
488 base = RangeBase(range);
489 limit = RangeLimit(range);
490
491 prev = NULL;
492 cur = fl->grainList;
493 while (cur) {
494 Addr grainBase, grainLimit;
495 grainBase = FreelistGrainBase(cur);
496 grainLimit = FreelistGrainLimit(fl, cur);
497 next = FreelistGrainNext(cur);
498
499 if (prev != NULL)
500 AVER(FreelistGrainLimit(fl, prev) < grainBase);
501 if (limit <= grainBase)
502 return ResFAIL; /* not found */
503 if (base == grainBase && limit == grainLimit) {
504 freelistGrainSetPrevNext(fl, prev, next, -1);
505 RangeInit(rangeReturn, grainBase, grainLimit);
506 return ResOK;
507 }
508 /* Partial overlap can't happen if everything's aligned. */
509 AVER(base >= grainLimit);
510
511 prev = cur;
512 cur = next;
513 }
514
515 return ResFAIL; /* not found */
516}
517
518
519Res FreelistDelete(Range rangeReturn, Freelist fl, Range range)
520{
521 Res res;
522
523 AVER(rangeReturn != NULL);
524 AVERT(Freelist, fl);
525 AVERT(Range, range);
526 AVER(RangeIsAligned(range, fl->alignment));
527
528 if (RangeSize(range) == FreelistGrainSize(fl)) {
529 res = freelistDeleteFromGrainList(rangeReturn, fl, range);
530 } else {
531 res = freelistDeleteFromBlockList(rangeReturn, fl, range);
532 }
533 return res;
534}
535
536
537void FreelistIterate(Freelist fl, FreelistIterateMethod iterate, 303void FreelistIterate(Freelist fl, FreelistIterateMethod iterate,
538 void *closureP, Size closureS) 304 void *closureP, Size closureS)
539{ 305{
540 FreelistBlock blockPrev, blockCur, blockNext; 306 Addr prev, cur, next;
541 FreelistGrain grainPrev, grainCur, grainNext;
542 307
543 AVERT(Freelist, fl); 308 AVERT(Freelist, fl);
544 AVER(FUNCHECK(iterate)); 309 AVER(FUNCHECK(iterate));
545 310
546 blockPrev = NULL; 311 prev = NULL;
547 blockCur = fl->blockList; 312 cur = fl->list;
548 grainPrev = NULL; 313 while (cur) {
549 grainCur = fl->grainList;
550 while (blockCur || grainCur) {
551 Bool delete = FALSE; 314 Bool delete = FALSE;
552 RangeStruct range; 315 RangeStruct range;
553 Bool cont; 316 Bool cont;
554 if (blockCur == NULL || (void *)grainCur < (void *)blockCur) { 317 RangeInit(&range, cur, FreelistBlockLimit(fl, cur));
555 AVER(grainCur); 318 cont = (*iterate)(&delete, &range, closureP, closureS);
556 RangeInit(&range, FreelistGrainBase(grainCur), 319 next = FreelistBlockNext(fl, cur);
557 FreelistGrainLimit(fl, grainCur)); 320 if (delete) {
558 cont = (*iterate)(&delete, &range, closureP, closureS); 321 freelistBlockSetPrevNext(fl, prev, next, -1);
559 AVERT(Bool, cont);
560 AVERT(Bool, delete);
561 grainNext = FreelistGrainNext(grainCur);
562 if (delete) {
563 freelistGrainSetPrevNext(fl, grainPrev, grainNext, -1);
564 } else {
565 grainPrev = grainCur;
566 }
567 grainCur = grainNext;
568 } else { 322 } else {
569 AVER(blockCur); 323 prev = cur;
570 RangeInit(&range, FreelistBlockBase(blockCur),
571 FreelistBlockLimit(blockCur));
572 cont = (*iterate)(&delete, &range, closureP, closureS);
573 AVERT(Bool, cont);
574 AVERT(Bool, delete);
575 blockNext = FreelistBlockNext(blockCur);
576 if (delete) {
577 freelistBlockSetPrevNext(fl, blockPrev, blockNext, -1);
578 } else {
579 blockPrev = blockCur;
580 }
581 blockCur = blockNext;
582 } 324 }
325 cur = next;
583 if (!cont) 326 if (!cont)
584 break; 327 break;
585 } 328 }
@@ -597,22 +340,22 @@ void FreelistIterate(Freelist fl, FreelistIterateMethod iterate,
597static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn, 340static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn,
598 Freelist fl, Size size, 341 Freelist fl, Size size,
599 FindDelete findDelete, 342 FindDelete findDelete,
600 FreelistBlock prev, FreelistBlock block) 343 Addr prev, Addr block)
601{ 344{
602 Bool callDelete = TRUE; 345 Bool callDelete = TRUE;
603 Addr base, limit; 346 Addr base, limit;
604 347
605 AVER(rangeReturn != NULL); 348 AVER(rangeReturn != NULL);
606 AVER(oldRangeReturn != NULL); 349 AVER(oldRangeReturn != NULL);
607 AVER(SizeIsAligned(size, fl->alignment));
608 AVERT(Freelist, fl); 350 AVERT(Freelist, fl);
351 AVER(SizeIsAligned(size, fl->alignment));
609 AVERT(FindDelete, findDelete); 352 AVERT(FindDelete, findDelete);
610 AVER(prev == NULL || FreelistBlockNext(prev) == block); 353 AVER(prev == NULL || FreelistBlockNext(fl, prev) == block);
611 AVER(block != NULL); 354 AVER(block != NULL);
612 AVER(FreelistBlockSize(block) >= size); 355 AVER(FreelistBlockSize(fl, block) >= size);
613 356
614 base = FreelistBlockBase(block); 357 base = block;
615 limit = FreelistBlockLimit(block); 358 limit = FreelistBlockLimit(fl, block);
616 359
617 switch (findDelete) { 360 switch (findDelete) {
618 case FindDeleteNONE: 361 case FindDeleteNONE:
@@ -645,42 +388,11 @@ static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn,
645} 388}
646 389
647 390
648/* freelistTakeGrain -- If there are any grains in the free list, find
649 * the first grain; return its range in 'rangeReturn' and
650 * 'oldRangeReturn'; possibly delete it from the list according to the
651 * instruction in 'findDelete'; and return TRUE. If the grain list is
652 * empty, return FALSE.
653 */
654static Bool freelistTakeGrain(Range rangeReturn, Range oldRangeReturn,
655 Freelist fl, FindDelete findDelete)
656{
657 FreelistGrain grain;
658
659 AVER(rangeReturn != NULL);
660 AVER(oldRangeReturn != NULL);
661 AVERT(Freelist, fl);
662 AVERT(FindDelete, findDelete);
663
664 grain = fl->grainList;
665 if (grain) {
666 RangeInit(rangeReturn, FreelistGrainBase(grain),
667 FreelistGrainLimit(fl, grain));
668 RangeInit(oldRangeReturn, FreelistGrainBase(grain),
669 FreelistGrainLimit(fl, grain));
670 if (findDelete != FindDeleteNONE)
671 freelistGrainSetPrevNext(fl, NULL, FreelistGrainNext(grain), -1);
672 return TRUE;
673 }
674
675 return FALSE;
676}
677
678
679Bool FreelistFind(Range rangeReturn, Range oldRangeReturn, 391Bool FreelistFind(Range rangeReturn, Range oldRangeReturn,
680 Freelist fl, Size size, FindDelete findDelete) 392 Freelist fl, Size size, FindDelete findDelete)
681{ 393{
682 Res res; 394 Res res;
683 FreelistBlock blockPrev, blockCur, blockNext; 395 Addr prev, cur, next;
684 396
685 AVER(rangeReturn != NULL); 397 AVER(rangeReturn != NULL);
686 AVER(oldRangeReturn != NULL); 398 AVER(oldRangeReturn != NULL);
@@ -688,20 +400,17 @@ Bool FreelistFind(Range rangeReturn, Range oldRangeReturn,
688 AVER(SizeIsAligned(size, fl->alignment)); 400 AVER(SizeIsAligned(size, fl->alignment));
689 AVERT(FindDelete, findDelete); 401 AVERT(FindDelete, findDelete);
690 402
691 if (size == FreelistGrainSize(fl)) 403 prev = NULL;
692 return freelistTakeGrain(rangeReturn, oldRangeReturn, fl, findDelete); 404 cur = fl->list;
693 405 while (cur) {
694 blockPrev = NULL; 406 if (FreelistBlockSize(fl, cur) >= size) {
695 blockCur = fl->blockList;
696 while (blockCur) {
697 if (FreelistBlockSize(blockCur) >= size) {
698 freelistFindDeleteFromBlock(rangeReturn, oldRangeReturn, fl, size, 407 freelistFindDeleteFromBlock(rangeReturn, oldRangeReturn, fl, size,
699 findDelete, blockPrev, blockCur); 408 findDelete, prev, cur);
700 return TRUE; 409 return TRUE;
701 } 410 }
702 blockNext = FreelistBlockNext(blockCur); 411 next = FreelistBlockNext(fl, cur);
703 blockPrev = blockCur; 412 prev = cur;
704 blockCur = blockNext; 413 cur = next;
705 } 414 }
706 415
707 return FALSE; 416 return FALSE;
@@ -713,36 +422,35 @@ Bool FreelistFindLargest(Range rangeReturn, Range oldRangeReturn,
713{ 422{
714 Bool found = FALSE; 423 Bool found = FALSE;
715 Size size = 0; 424 Size size = 0;
716 FreelistBlock blockPrev, blockCur, blockNext; 425 Addr prev, cur, next;
717 FreelistBlock bestBlockPrev, bestBlockCur; 426 Addr bestPrev, bestCur;
718 427
719 AVER(rangeReturn != NULL); 428 AVER(rangeReturn != NULL);
720 AVER(oldRangeReturn != NULL); 429 AVER(oldRangeReturn != NULL);
721 AVERT(Freelist, fl); 430 AVERT(Freelist, fl);
722 AVERT(FindDelete, findDelete); 431 AVERT(FindDelete, findDelete);
723 432
724 blockPrev = NULL; 433 prev = NULL;
725 blockCur = fl->blockList; 434 cur = fl->list;
726 while (blockCur) { 435 while (cur) {
727 if (FreelistBlockSize(blockCur) > size) { 436 if (FreelistBlockSize(fl, cur) > size) {
728 found = TRUE; 437 found = TRUE;
729 size = FreelistBlockSize(blockCur); 438 size = FreelistBlockSize(fl, cur);
730 bestBlockPrev = blockPrev; 439 bestPrev = prev;
731 bestBlockCur = blockCur; 440 bestCur = cur;
732 } 441 }
733 blockNext = FreelistBlockNext(blockCur); 442 next = FreelistBlockNext(fl, cur);
734 blockPrev = blockCur; 443 prev = cur;
735 blockCur = blockNext; 444 cur = next;
736 } 445 }
737 446
738 if (found) { 447 if (found) {
739 /* No need to search the grain list. */
740 freelistFindDeleteFromBlock(rangeReturn, oldRangeReturn, fl, size, 448 freelistFindDeleteFromBlock(rangeReturn, oldRangeReturn, fl, size,
741 findDelete, bestBlockPrev, bestBlockCur); 449 findDelete, bestPrev, bestCur);
742 return TRUE; 450 return TRUE;
743 } 451 }
744 452
745 return freelistTakeGrain(rangeReturn, oldRangeReturn, fl, findDelete); 453 return FALSE;
746} 454}
747 455
748 456
@@ -780,8 +488,7 @@ Res FreelistDescribe(Freelist fl, mps_lib_FILE *stream)
780 res = WriteF(stream, 488 res = WriteF(stream,
781 "Freelist $P {\n", (WriteFP)fl, 489 "Freelist $P {\n", (WriteFP)fl,
782 " alignment = $U\n", (WriteFU)fl->alignment, 490 " alignment = $U\n", (WriteFU)fl->alignment,
783 " blockListSize = $U\n", (WriteFU)fl->blockListSize, 491 " listSize = $U\n", (WriteFU)fl->listSize,
784 " grainListSize = $U\n", (WriteFU)fl->grainListSize,
785 NULL); 492 NULL);
786 493
787 FreelistIterate(fl, freelistDescribeIterateMethod, stream, 0); 494 FreelistIterate(fl, freelistDescribeIterateMethod, stream, 0);
diff --git a/mps/code/freelist.h b/mps/code/freelist.h
index b0f047840a3..467ed80f3c2 100644
--- a/mps/code/freelist.h
+++ b/mps/code/freelist.h
@@ -15,8 +15,6 @@
15#define FreelistSig ((Sig)0x519F6331) /* SIGnature FREEL */ 15#define FreelistSig ((Sig)0x519F6331) /* SIGnature FREEL */
16 16
17typedef struct FreelistStruct *Freelist; 17typedef struct FreelistStruct *Freelist;
18typedef struct FreelistBlockStruct *FreelistBlock;
19typedef struct FreelistGrainStruct *FreelistGrain;
20 18
21typedef Bool (*FreelistIterateMethod)(Bool *deleteReturn, Range range, 19typedef Bool (*FreelistIterateMethod)(Bool *deleteReturn, Range range,
22 void *closureP, Size closureS); 20 void *closureP, Size closureS);
@@ -24,10 +22,8 @@ typedef Bool (*FreelistIterateMethod)(Bool *deleteReturn, Range range,
24typedef struct FreelistStruct { 22typedef struct FreelistStruct {
25 Sig sig; 23 Sig sig;
26 Align alignment; 24 Align alignment;
27 FreelistBlock blockList; 25 Addr list;
28 Count blockListSize; 26 Count listSize;
29 FreelistGrain grainList;
30 Count grainListSize;
31} FreelistStruct; 27} FreelistStruct;
32 28
33extern Bool FreelistCheck(Freelist fl); 29extern Bool FreelistCheck(Freelist fl);