diff --git a/mps/code/cbs.c b/mps/code/cbs.c index 966c4babbc0..44ba821316b 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -13,6 +13,7 @@ */ #include "cbs.h" +#include "range.h" #include "splay.h" #include "meter.h" #include "poolmfs.h" @@ -21,9 +22,12 @@ SRCID(cbs, "$Id$"); -#define CBSBlockBase(block) ((block)->base) -#define CBSBlockLimit(block) ((block)->limit) -#define CBSBlockSize(block) AddrOffset((block)->base, (block)->limit) +#define CBSBlockRange(block) (&(block)->rangeStruct) +#define CBSBlockBase(block) RangeBase(CBSBlockRange(block)) +#define CBSBlockLimit(block) RangeLimit(CBSBlockRange(block)) +#define CBSBlockSetBase(block, addr) RangeSetBase(CBSBlockRange(block), addr) +#define CBSBlockSetLimit(block, addr) RangeSetLimit(CBSBlockRange(block), addr) +#define CBSBlockSize(block) RangeSize(CBSBlockRange(block)) #define cbsOfLand(land) PARENT(CBSStruct, landStruct, land) @@ -41,7 +45,7 @@ SRCID(cbs, "$Id$"); Addr can be encoded, and possibly breaking . On an exotic platform where this isn't true, pass the address of base. i.e. add an & */ -#define cbsBlockKey(block) ((TreeKey)(block)->base) +#define cbsBlockKey(block) ((TreeKey)CBSBlockBase(block)) #define keyOfBaseVar(baseVar) ((TreeKey)(baseVar)) #define baseOfKey(key) ((Addr)(key)) @@ -98,8 +102,8 @@ static Compare cbsCompare(Tree tree, TreeKey key) base1 = baseOfKey(key); cbsBlock = cbsBlockOfTree(tree); - base2 = cbsBlock->base; - limit2 = cbsBlock->limit; + base2 = CBSBlockBase(cbsBlock); + limit2 = CBSBlockLimit(cbsBlock); if (base1 < base2) return CompareLESS; @@ -334,8 +338,7 @@ static void cbsBlockDestroy(CBS cbs, CBSBlock block) AVER(cbs->size >= size); cbs->size -= size; - /* make invalid */ - block->limit = block->base; + RangeFinish(CBSBlockRange(block)); PoolFree(cbsBlockPool(cbs), (Addr)block, cbs->blockStructSize); } @@ -408,8 +411,7 @@ static Res cbsBlockAlloc(CBSBlock *blockReturn, CBS cbs, Range range) block = (CBSBlock)p; TreeInit(cbsBlockTree(block)); - block->base = RangeBase(range); - block->limit = RangeLimit(range); + RangeCopy(CBSBlockRange(block), range); SplayNodeInit(cbsSplay(cbs), cbsBlockTree(block)); @@ -454,7 +456,7 @@ static Res cbsInsert(Range rangeReturn, Land land, Range range) Res res; Addr base, limit, newBase, newLimit; Tree leftSplay, rightSplay; - CBSBlock leftCBS, rightCBS; + CBSBlock leftBlock, rightBlock; Bool leftMerge, rightMerge; Size oldSize; @@ -468,61 +470,64 @@ static Res cbsInsert(Range rangeReturn, Land land, Range range) limit = RangeLimit(range); METER_ACC(cbs->treeSearch, cbs->treeSize); - b = SplayTreeNeighbours(&leftSplay, &rightSplay, cbsSplay(cbs), keyOfBaseVar(base)); + b = SplayTreeNeighbours(&leftSplay, &rightSplay, + cbsSplay(cbs), keyOfBaseVar(base)); if (!b) { res = ResFAIL; goto fail; } - /* The two cases below are not quite symmetrical, because base was - * passed into the call to SplayTreeNeighbours(), but limit was not. - * So we know that if there is a left neighbour, then leftCBS->limit - * <= base (this is ensured by cbsCompare, which is the - * comparison method on the tree). But if there is a right - * neighbour, all we know is that base < rightCBS->base. But for the - * range to fit, we need limit <= rightCBS->base too. Hence the extra - * check and the possibility of failure in the second case. - */ + /* .insert.overlap: The two cases below are not quite symmetrical, + because base was passed into the call to SplayTreeNeighbours(), + but limit was not. So we know that if there is a left neighbour, + then leftBlock's limit <= base (this is ensured by cbsCompare, + which is the comparison method on the tree). But if there is a + right neighbour, all we know is that base < rightBlock's + base. But for the range to fit, we need limit <= rightBlock's + base too. Hence the extra check and the possibility of failure in + the second case. */ + if (leftSplay == TreeEMPTY) { - leftCBS = NULL; + leftBlock = NULL; leftMerge = FALSE; } else { - leftCBS = cbsBlockOfTree(leftSplay); - AVER(leftCBS->limit <= base); - leftMerge = leftCBS->limit == base; + leftBlock = cbsBlockOfTree(leftSplay); + AVER(CBSBlockLimit(leftBlock) <= base); + leftMerge = CBSBlockLimit(leftBlock) == base; } if (rightSplay == TreeEMPTY) { - rightCBS = NULL; + rightBlock = NULL; rightMerge = FALSE; } else { - rightCBS = cbsBlockOfTree(rightSplay); - if (rightCBS != NULL && limit > CBSBlockLimit(rightCBS)) { + rightBlock = cbsBlockOfTree(rightSplay); + if (rightBlock != NULL && limit > CBSBlockLimit(rightBlock)) { + /* .insert.overlap */ res = ResFAIL; goto fail; } - rightMerge = rightCBS->base == limit; + rightMerge = CBSBlockBase(rightBlock) == limit; } - newBase = leftMerge ? CBSBlockBase(leftCBS) : base; - newLimit = rightMerge ? CBSBlockLimit(rightCBS) : limit; + newBase = leftMerge ? CBSBlockBase(leftBlock) : base; + newLimit = rightMerge ? CBSBlockLimit(rightBlock) : limit; if (leftMerge && rightMerge) { - Size oldLeftSize = CBSBlockSize(leftCBS); - Addr rightLimit = CBSBlockLimit(rightCBS); - cbsBlockDelete(cbs, rightCBS); - leftCBS->limit = rightLimit; - cbsBlockGrew(cbs, leftCBS, oldLeftSize); + Size oldLeftSize = CBSBlockSize(leftBlock); + Addr rightLimit = CBSBlockLimit(rightBlock); + cbsBlockDelete(cbs, rightBlock); + CBSBlockSetLimit(leftBlock, rightLimit); + cbsBlockGrew(cbs, leftBlock, oldLeftSize); } else if (leftMerge) { - oldSize = CBSBlockSize(leftCBS); - leftCBS->limit = limit; - cbsBlockGrew(cbs, leftCBS, oldSize); + oldSize = CBSBlockSize(leftBlock); + CBSBlockSetLimit(leftBlock, limit); + cbsBlockGrew(cbs, leftBlock, oldSize); } else if (rightMerge) { - oldSize = CBSBlockSize(rightCBS); - rightCBS->base = base; - cbsBlockGrew(cbs, rightCBS, oldSize); + oldSize = CBSBlockSize(rightBlock); + CBSBlockSetBase(rightBlock, base); + cbsBlockGrew(cbs, rightBlock, oldSize); } else { CBSBlock block; @@ -577,13 +582,13 @@ static Res cbsDelete(Range rangeReturn, Land land, Range range) } cbsBlock = cbsBlockOfTree(tree); - if (limit > cbsBlock->limit) { + if (limit > CBSBlockLimit(cbsBlock)) { res = ResFAIL; goto failLimitCheck; } - oldBase = cbsBlock->base; - oldLimit = cbsBlock->limit; + oldBase = CBSBlockBase(cbsBlock); + oldLimit = CBSBlockLimit(cbsBlock); oldSize = CBSBlockSize(cbsBlock); RangeInit(rangeReturn, oldBase, oldLimit); @@ -594,13 +599,13 @@ static Res cbsDelete(Range rangeReturn, Land land, Range range) } else if (base == oldBase) { /* remaining fragment at right */ AVER(limit < oldLimit); - cbsBlock->base = limit; + CBSBlockSetBase(cbsBlock, limit); cbsBlockShrunk(cbs, cbsBlock, oldSize); } else if (limit == oldLimit) { /* remaining fragment at left */ AVER(base > oldBase); - cbsBlock->limit = base; + CBSBlockSetLimit(cbsBlock, base); cbsBlockShrunk(cbs, cbsBlock, oldSize); } else { @@ -615,7 +620,7 @@ static Res cbsDelete(Range rangeReturn, Land land, Range range) if (res != ResOK) { goto failAlloc; } - cbsBlock->limit = base; + CBSBlockSetLimit(cbsBlock, base); cbsBlockShrunk(cbs, cbsBlock, oldSize); cbsBlockInsert(cbs, newBlock); } @@ -639,8 +644,8 @@ static Res cbsBlockDescribe(CBSBlock block, mps_lib_FILE *stream) res = WriteF(stream, 0, "[$P,$P)", - (WriteFP)block->base, - (WriteFP)block->limit, + (WriteFP)CBSBlockBase(block), + (WriteFP)CBSBlockLimit(block), NULL); return res; } @@ -667,8 +672,8 @@ static Res cbsFastBlockDescribe(CBSFastBlock block, mps_lib_FILE *stream) res = WriteF(stream, 0, "[$P,$P) {$U}", - (WriteFP)block->cbsBlockStruct.base, - (WriteFP)block->cbsBlockStruct.limit, + (WriteFP)CBSBlockBase(&block->cbsBlockStruct), + (WriteFP)CBSBlockLimit(&block->cbsBlockStruct), (WriteFU)block->maxSize, NULL); return res; @@ -696,8 +701,8 @@ static Res cbsZonedBlockDescribe(CBSZonedBlock block, mps_lib_FILE *stream) res = WriteF(stream, 0, "[$P,$P) {$U, $B}", - (WriteFP)block->cbsFastBlockStruct.cbsBlockStruct.base, - (WriteFP)block->cbsFastBlockStruct.cbsBlockStruct.limit, + (WriteFP)CBSBlockBase(&block->cbsFastBlockStruct.cbsBlockStruct), + (WriteFP)CBSBlockLimit(&block->cbsFastBlockStruct.cbsBlockStruct), (WriteFU)block->cbsFastBlockStruct.maxSize, (WriteFB)block->zones, NULL); @@ -918,9 +923,12 @@ static Bool cbsFindFirst(Range rangeReturn, Range oldRangeReturn, return found; } -/* cbsFindInZones -- find a block of at least the given size that lies - * entirely within a zone set. (The first such block, if high is - * FALSE, or the last, if high is TRUE.) + +/* cbsFindInZones -- find a block within a zone set + * + * Fins a block of at least the given size that lies entirely within a + * zone set. (The first such block, if high is FALSE, or the last, if + * high is TRUE.) */ typedef struct cbsTestNodeInZonesClosureStruct { diff --git a/mps/code/cbs.h b/mps/code/cbs.h index a1496b3f771..9b060d3709b 100644 --- a/mps/code/cbs.h +++ b/mps/code/cbs.h @@ -18,8 +18,7 @@ typedef struct CBSBlockStruct *CBSBlock; typedef struct CBSBlockStruct { TreeStruct treeStruct; - Addr base; - Addr limit; + RangeStruct rangeStruct; } CBSBlockStruct; typedef struct CBSFastBlockStruct *CBSFastBlock; diff --git a/mps/code/range.c b/mps/code/range.c index 8b8f1c8bf8a..f535fed85f7 100644 --- a/mps/code/range.c +++ b/mps/code/range.c @@ -39,6 +39,9 @@ void RangeInitSize(Range range, Addr base, Size size) void RangeFinish(Range range) { AVERT(Range, range); + /* Make range invalid and recognisably so. */ + range->limit = (Addr)0; + range->base = (Addr)0xF191583D; } Res RangeDescribe(Range range, mps_lib_FILE *stream, Count depth) diff --git a/mps/code/range.h b/mps/code/range.h index ac262c98c1a..5ef6371ad8f 100644 --- a/mps/code/range.h +++ b/mps/code/range.h @@ -18,6 +18,8 @@ #define RangeBase(range) ((range)->base) #define RangeLimit(range) ((range)->limit) +#define RangeSetBase(range, addr) BEGIN ((range)->base = (addr)); END +#define RangeSetLimit(range, addr) BEGIN ((range)->limit = (addr)); END #define RangeSize(range) (AddrOffset(RangeBase(range), RangeLimit(range))) #define RangeContains(range, addr) ((range)->base <= (addr) && (addr) < (range)->limit) #define RangeIsEmpty(range) (RangeSize(range) == 0) diff --git a/mps/design/cbs.txt b/mps/design/cbs.txt index f004eedd90a..6471434f0e0 100644 --- a/mps/design/cbs.txt +++ b/mps/design/cbs.txt @@ -111,7 +111,7 @@ following optional keyword arguments: the block descriptor pool automatically extends itself when out of space; if ``FALSE``, the pool returns ``ResLIMIT`` in this case. (This feature is used by the arena to bootstrap its own CBS of free - memory.) + memory. See design.mps.bootstrap.land.sol.pool.) Limitations