From 87b388040539290dbaf1c8592fcd1e300d2a89f4 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 15 Apr 2014 16:35:34 +0100 Subject: [PATCH] New generic function landsize returns the total size of ranges in a land (if the land supports it). implement it for all land classes. The MVFF pool class doesn't have to maintain its free size any more: it can just call LandSize. Move re-entrancy protection from CBS to Land. This allows us to remove some CBS functions. (But requires some adjustment in failoverDelete.) In MVFF, do more checking of mvff->total. Copied from Perforce Change: 185569 ServerID: perforce.ravenbrook.com --- mps/code/cbs.c | 158 ++++++++++++++------------------------------ mps/code/failover.c | 23 ++++++- mps/code/freelist.c | 24 ++++++- mps/code/land.c | 138 +++++++++++++++++++++++++++----------- mps/code/mpm.h | 4 +- mps/code/mpmst.h | 6 +- mps/code/mpmtypes.h | 1 + mps/code/poolmvff.c | 19 ++++-- mps/design/land.txt | 5 ++ 9 files changed, 218 insertions(+), 160 deletions(-) diff --git a/mps/code/cbs.c b/mps/code/cbs.c index 8aa21f87ca7..177388bc0cb 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -40,43 +40,20 @@ SRCID(cbs, "$Id$"); #define cbsBlockPool(cbs) RVALUE((cbs)->blockPool) -/* cbsEnter, cbsLeave -- Avoid re-entrance - * - * .enter-leave: The callbacks are restricted in what they may call. - * These functions enforce this. - * - * .enter-leave.simple: Simple queries may be called from callbacks. - */ - -static void cbsEnter(CBS cbs) -{ - /* Don't need to check as always called from interface function. */ - AVER(!cbs->inCBS); - cbs->inCBS = TRUE; - return; -} - -static void cbsLeave(CBS cbs) -{ - /* Don't need to check as always called from interface function. */ - AVER(cbs->inCBS); - cbs->inCBS = FALSE; - return; -} - - /* CBSCheck -- Check CBS */ Bool CBSCheck(CBS cbs) { /* See .enter-leave.simple. */ + Land land; CHECKS(CBS, cbs); - CHECKD(Land, cbsLand(cbs)); + land = cbsLand(cbs); + CHECKD(Land, land); CHECKD(SplayTree, cbsSplay(cbs)); - /* nothing to check about treeSize */ CHECKD(Pool, cbs->blockPool); - CHECKL(BoolCheck(cbs->inCBS)); CHECKL(BoolCheck(cbs->ownPool)); + CHECKL(SizeIsAligned(cbs->size, LandAlignment(land))); + CHECKL((cbs->size == 0) == (cbs->treeSize == 0)); return TRUE; } @@ -84,7 +61,6 @@ Bool CBSCheck(CBS cbs) static Bool CBSBlockCheck(CBSBlock block) { - /* See .enter-leave.simple. */ UNUSED(block); /* Required because there is no signature */ CHECKL(block != NULL); /* Can't use CHECKD_NOSIG because TreeEMPTY is NULL. */ @@ -277,16 +253,15 @@ static Res cbsInitComm(Land land, ArgList args, SplayUpdateNodeMethod update, cbs->ownPool = TRUE; } cbs->treeSize = 0; + cbs->size = 0; cbs->blockStructSize = blockStructSize; - cbs->inCBS = TRUE; METER_INIT(cbs->treeSearch, "size of tree", (void *)cbs); cbs->sig = CBSSig; AVERT(CBS, cbs); - cbsLeave(cbs); return ResOK; } @@ -309,7 +284,7 @@ static Res cbsInitZoned(Land land, ArgList args) } -/* CBSFinish -- Finish a CBS structure +/* cbsFinish -- Finish a CBS structure * * See . */ @@ -321,7 +296,6 @@ static void cbsFinish(Land land) AVERT(Land, land); cbs = cbsOfLand(land); AVERT(CBS, cbs); - cbsEnter(cbs); METER_EMIT(&cbs->treeSearch); @@ -333,6 +307,23 @@ static void cbsFinish(Land land) } +/* cbsSize -- total size of ranges in CBS + * + * See . + */ + +static Size cbsSize(Land land) +{ + CBS cbs; + + AVERT(Land, land); + cbs = cbsOfLand(land); + AVERT(CBS, cbs); + + return cbs->size; +} + + /* Node change operators * * These four functions are called whenever blocks are created, @@ -343,14 +334,18 @@ static void cbsFinish(Land land) static void cbsBlockDelete(CBS cbs, CBSBlock block) { Bool b; + Size size; AVERT(CBS, cbs); AVERT(CBSBlock, block); + size = CBSBlockSize(block); METER_ACC(cbs->treeSearch, cbs->treeSize); b = SplayTreeDelete(cbsSplay(cbs), cbsBlockTree(block)); AVER(b); /* expect block to be in the tree */ STATISTIC(--cbs->treeSize); + AVER(cbs->size >= size); + cbs->size -= size; /* make invalid */ block->limit = block->base; @@ -367,8 +362,10 @@ static void cbsBlockShrunk(CBS cbs, CBSBlock block, Size oldSize) newSize = CBSBlockSize(block); AVER(oldSize > newSize); + AVER(cbs->size >= oldSize - newSize); SplayNodeRefresh(cbsSplay(cbs), cbsBlockTree(block)); + cbs->size -= oldSize - newSize; } static void cbsBlockGrew(CBS cbs, CBSBlock block, Size oldSize) @@ -382,6 +379,7 @@ static void cbsBlockGrew(CBS cbs, CBSBlock block, Size oldSize) AVER(oldSize < newSize); SplayNodeRefresh(cbsSplay(cbs), cbsBlockTree(block)); + cbs->size += newSize - oldSize; } /* cbsBlockAlloc -- allocate a new block and set its base and limit, @@ -431,12 +429,19 @@ static void cbsBlockInsert(CBS cbs, CBSBlock block) b = SplayTreeInsert(cbsSplay(cbs), cbsBlockTree(block)); AVER(b); STATISTIC(++cbs->treeSize); + cbs->size += CBSBlockSize(block); } -/* cbsInsertIntoTree -- Insert a range into the tree */ +/* cbsInsert -- Insert a range into the CBS + * + * See . + * + * .insert.alloc: Will only allocate a block if the range does not + * abut an existing range. + */ -static Res cbsInsertIntoTree(Range rangeReturn, Land land, Range range) +static Res cbsInsert(Range rangeReturn, Land land, Range range) { CBS cbs; Bool b; @@ -533,38 +538,15 @@ fail: } -/* cbsInsert -- Insert a range into the CBS +/* cbsDelete -- Remove a range from a CBS * - * See . + * See . * - * .insert.alloc: Will only allocate a block if the range does not - * abut an existing range. + * .delete.alloc: Will only allocate a block if the range splits + * an existing range. */ -static Res cbsInsert(Range rangeReturn, Land land, Range range) -{ - CBS cbs; - Res res; - - AVERT(Land, land); - cbs = cbsOfLand(land); - AVERT(CBS, cbs); - cbsEnter(cbs); - - AVER(rangeReturn != NULL); - AVERT(Range, range); - AVER(RangeIsAligned(range, LandAlignment(land))); - - res = cbsInsertIntoTree(rangeReturn, land, range); - - cbsLeave(cbs); - return res; -} - - -/* cbsDeleteFromTree -- delete blocks from the tree */ - -static Res cbsDeleteFromTree(Range rangeReturn, Land land, Range range) +static Res cbsDelete(Range rangeReturn, Land land, Range range) { CBS cbs; Res res; @@ -642,35 +624,6 @@ failSplayTreeSearch: } -/* cbsDelete -- Remove a range from a CBS - * - * See . - * - * .delete.alloc: Will only allocate a block if the range splits - * an existing range. - */ - -static Res cbsDelete(Range rangeReturn, Land land, Range range) -{ - CBS cbs; - Res res; - - AVERT(Land, land); - cbs = cbsOfLand(land); - AVERT(CBS, cbs); - cbsEnter(cbs); - - AVER(rangeReturn != NULL); - AVERT(Range, range); - AVER(RangeIsAligned(range, LandAlignment(land))); - - res = cbsDeleteFromTree(rangeReturn, land, range); - - cbsLeave(cbs); - return res; -} - - static Res cbsBlockDescribe(CBSBlock block, mps_lib_FILE *stream) { Res res; @@ -813,7 +766,6 @@ static void cbsIterate(Land land, LandVisitor visitor, AVERT(Land, land); cbs = cbsOfLand(land); AVERT(CBS, cbs); - cbsEnter(cbs); AVER(FUNCHECK(visitor)); splay = cbsSplay(cbs); @@ -827,9 +779,6 @@ static void cbsIterate(Land land, LandVisitor visitor, closure.closureS = closureS; (void)TreeTraverse(SplayTreeRoot(splay), splay->compare, splay->nodeKey, cbsIterateVisit, &closure, 0); - - cbsLeave(cbs); - return; } @@ -882,10 +831,10 @@ static void cbsFindDeleteRange(Range rangeReturn, Range oldRangeReturn, if (callDelete) { Res res; - res = cbsDeleteFromTree(oldRangeReturn, land, rangeReturn); + res = cbsDelete(oldRangeReturn, land, rangeReturn); /* Can't have run out of memory, because all our callers pass in blocks that were just found in the tree, and we only - deleted from one end of the block, so cbsDeleteFromTree did not + deleted from one end of the block, so cbsDelete did not need to allocate a new block. */ AVER(res == ResOK); } @@ -905,7 +854,6 @@ static Bool cbsFindFirst(Range rangeReturn, Range oldRangeReturn, cbs = cbsOfLand(land); AVERT(CBS, cbs); AVER(IsLandSubclass(cbsLand(cbs), CBSFastLandClass)); - cbsEnter(cbs); AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); @@ -927,7 +875,6 @@ static Bool cbsFindFirst(Range rangeReturn, Range oldRangeReturn, size, findDelete); } - cbsLeave(cbs); return found; } @@ -992,7 +939,6 @@ static Bool cbsFindLast(Range rangeReturn, Range oldRangeReturn, cbs = cbsOfLand(land); AVERT(CBS, cbs); AVER(IsLandSubclass(cbsLand(cbs), CBSFastLandClass)); - cbsEnter(cbs); AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); @@ -1014,7 +960,6 @@ static Bool cbsFindLast(Range rangeReturn, Range oldRangeReturn, size, findDelete); } - cbsLeave(cbs); return found; } @@ -1031,7 +976,6 @@ static Bool cbsFindLargest(Range rangeReturn, Range oldRangeReturn, cbs = cbsOfLand(land); AVERT(CBS, cbs); AVER(IsLandSubclass(cbsLand(cbs), CBSFastLandClass)); - cbsEnter(cbs); AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); @@ -1058,7 +1002,6 @@ static Bool cbsFindLargest(Range rangeReturn, Range oldRangeReturn, } } - cbsLeave(cbs); return found; } @@ -1101,8 +1044,6 @@ static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn, /* It would be nice if there were a neat way to eliminate all runs of zones in zoneSet too small for size.*/ - cbsEnter(cbs); - closure.arena = LandArena(land); closure.zoneSet = zoneSet; closure.size = size; @@ -1123,7 +1064,7 @@ static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn, RangeInit(&rangeStruct, closure.base, AddrAdd(closure.base, size)); else RangeInit(&rangeStruct, AddrSub(closure.limit, size), closure.limit); - res = cbsDeleteFromTree(&oldRangeStruct, land, &rangeStruct); + res = cbsDelete(&oldRangeStruct, land, &rangeStruct); if (res == ResOK) { /* enough memory to split block */ RangeCopy(rangeReturn, &rangeStruct); RangeCopy(oldRangeReturn, &oldRangeStruct); @@ -1131,7 +1072,6 @@ static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn, } else res = ResFAIL; - cbsLeave(cbs); return res; } @@ -1158,7 +1098,6 @@ static Res cbsDescribe(Land land, mps_lib_FILE *stream) res = WriteF(stream, "CBS $P {\n", (WriteFP)cbs, " blockPool: $P\n", (WriteFP)cbsBlockPool(cbs), - " inCBS: $U\n", (WriteFU)cbs->inCBS, " ownPool: $U\n", (WriteFU)cbs->ownPool, " treeSize: $U\n", (WriteFU)cbs->treeSize, NULL); @@ -1187,6 +1126,7 @@ DEFINE_LAND_CLASS(CBSLandClass, class) class->size = sizeof(CBSStruct); class->init = cbsInit; class->finish = cbsFinish; + class->sizeMethod = cbsSize; class->insert = cbsInsert; class->delete = cbsDelete; class->iterate = cbsIterate; diff --git a/mps/code/failover.c b/mps/code/failover.c index 3f633acd34d..e8a0dbc7dae 100644 --- a/mps/code/failover.c +++ b/mps/code/failover.c @@ -70,6 +70,18 @@ static void failoverFinish(Land land) } +static Size failoverSize(Land land) +{ + Failover fo; + + AVERT(Land, land); + fo = failoverOfLand(land); + AVERT(Failover, fo); + + return LandSize(fo->primary) + LandSize(fo->secondary); +} + + static Res failoverInsert(Range rangeReturn, Land land, Range range) { Failover fo; @@ -129,12 +141,18 @@ static Res failoverDelete(Range rangeReturn, Land land, Range range) AVER(RangesEqual(&oldRange, &dummyRange)); RangeInit(&left, RangeBase(&oldRange), RangeBase(range)); if (!RangeIsEmpty(&left)) { - res = LandInsert(&dummyRange, land, &left); + /* Don't call LandInsert(..., land, ...) here: that would be + * re-entrant and fail the landEnter check. */ + res = LandInsert(&dummyRange, fo->primary, &left); + if (res != ResOK && res != ResFAIL) + res = LandInsert(&dummyRange, fo->secondary, &left); AVER(res == ResOK); } RangeInit(&right, RangeLimit(range), RangeLimit(&oldRange)); if (!RangeIsEmpty(&right)) { - res = LandInsert(&dummyRange, land, &right); + res = LandInsert(&dummyRange, fo->primary, &right); + if (res != ResOK && res != ResFAIL) + res = LandInsert(&dummyRange, fo->secondary, &right); AVER(res == ResOK); } } @@ -266,6 +284,7 @@ DEFINE_LAND_CLASS(FailoverLandClass, class) class->size = sizeof(FailoverStruct); class->init = failoverInit; class->finish = failoverFinish; + class->sizeMethod = failoverSize; class->insert = failoverInsert; class->delete = failoverDelete; class->iterate = failoverIterate; diff --git a/mps/code/freelist.c b/mps/code/freelist.c index 5b586a82e6a..13f83bd4aad 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -168,8 +168,11 @@ Bool FreelistCheck(Freelist fl) land = &fl->landStruct; CHECKD(Land, land); /* See */ - CHECKL(AlignIsAligned(LandAlignment(land), freelistMinimumAlignment)); + CHECKL(AlignIsAligned(freelistAlignment(fl), freelistMinimumAlignment)); CHECKL((fl->list == NULL) == (fl->listSize == 0)); + CHECKL((fl->list == NULL) == (fl->size == 0)); + CHECKL(SizeIsAligned(fl->size, freelistAlignment(fl))); + return TRUE; } @@ -192,6 +195,7 @@ static Res freelistInit(Land land, ArgList args) fl = freelistOfLand(land); fl->list = NULL; fl->listSize = 0; + fl->size = 0; fl->sig = FreelistSig; AVERT(Freelist, fl); @@ -211,6 +215,17 @@ static void freelistFinish(Land land) } +static Size freelistSize(Land land) +{ + Freelist fl; + + AVERT(Land, land); + fl = freelistOfLand(land); + AVERT(Freelist, fl); + return fl->size; +} + + /* freelistBlockSetPrevNext -- update list of blocks * * If prev and next are both NULL, make the block list empty. @@ -303,6 +318,7 @@ static Res freelistInsert(Range rangeReturn, Land land, Range range) freelistBlockSetPrevNext(fl, prev, new, +1); } + fl->size += RangeSize(range); RangeInit(rangeReturn, base, limit); return ResOK; } @@ -360,6 +376,8 @@ static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl, freelistBlockSetPrevNext(fl, block, new, +1); } + AVER(fl->size >= RangeSize(range)); + fl->size -= RangeSize(range); RangeInit(rangeReturn, blockBase, blockLimit); } @@ -426,7 +444,10 @@ static void freelistIterate(Land land, LandVisitor visitor, cont = (*visitor)(&delete, land, &range, closureP, closureS); next = FreelistBlockNext(cur); if (delete) { + Size size = FreelistBlockSize(fl, cur); freelistBlockSetPrevNext(fl, prev, next, -1); + AVER(fl->size >= size); + fl->size -= size; } else { prev = cur; } @@ -726,6 +747,7 @@ DEFINE_LAND_CLASS(FreelistLandClass, class) class->size = sizeof(FreelistStruct); class->init = freelistInit; class->finish = freelistFinish; + class->sizeMethod = freelistSize; class->insert = freelistInsert; class->delete = freelistDelete; class->iterate = freelistIterate; diff --git a/mps/code/land.c b/mps/code/land.c index 6c59cb193a6..9ff8257151c 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -26,16 +26,41 @@ Bool FindDeleteCheck(FindDelete findDelete) } +/* landEnter, landLeave -- Avoid re-entrance + * + * .enter-leave: The visitor function passed to LandIterate is not + * allowed to call methods of that land. These functions enforce this. + * + * .enter-leave.simple: Some simple queries are fine to call from + * visitor functions. These are marked with the tag of this comment. + */ + +static void landEnter(Land land) +{ + /* Don't need to check as always called from interface function. */ + AVER(!land->inLand); + land->inLand = TRUE; + return; +} + +static void landLeave(Land land) +{ + /* Don't need to check as always called from interface function. */ + AVER(land->inLand); + land->inLand = FALSE; + return; +} + + /* LandCheck -- check land */ Bool LandCheck(Land land) { + /* .enter-leave.simple */ CHECKS(Land, land); CHECKD(LandClass, land->class); CHECKU(Arena, land->arena); CHECKL(AlignCheck(land->alignment)); - CHECKL(SizeIsAligned(land->size, land->alignment)); - /* too expensive to check land->size against contents */ return TRUE; } @@ -53,7 +78,7 @@ Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *own AVERT(LandClass, class); AVERT(Align, alignment); - land->size = 0; + land->inLand = TRUE; land->alignment = alignment; land->arena = arena; land->class = class; @@ -66,6 +91,7 @@ Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *own goto failInit; EVENT2(LandInit, land, owner); + landLeave(land); return ResOK; failInit: @@ -136,6 +162,7 @@ void LandDestroy(Land land) void LandFinish(Land land) { AVERT(Land, land); + landEnter(land); (*land->class->finish)(land); @@ -143,6 +170,20 @@ void LandFinish(Land land) } +/* LandSize -- return the total size of ranges in land + * + * See + */ + +Size LandSize(Land land) +{ + /* .enter-leave.simple */ + AVERT(Land, land); + + return (*land->class->sizeMethod)(land); +} + + /* LandInsert -- insert range of addresses into land * * See @@ -151,19 +192,16 @@ void LandFinish(Land land) Res LandInsert(Range rangeReturn, Land land, Range range) { Res res; - Size size; AVER(rangeReturn != NULL); AVERT(Land, land); AVERT(Range, range); AVER(RangeIsAligned(range, land->alignment)); + landEnter(land); - /* rangeReturn is allowed to alias with range, so take size first. - * See */ - size = RangeSize(range); res = (*land->class->insert)(rangeReturn, land, range); - if (res == ResOK) - land->size += size; + + landLeave(land); return res; } @@ -176,20 +214,16 @@ Res LandInsert(Range rangeReturn, Land land, Range range) Res LandDelete(Range rangeReturn, Land land, Range range) { Res res; - Size size; AVER(rangeReturn != NULL); AVERT(Land, land); AVERT(Range, range); AVER(RangeIsAligned(range, land->alignment)); + landEnter(land); - /* rangeReturn is allowed to alias with range, so take size first. - * See */ - size = RangeSize(range); - AVER(land->size >= size); res = (*land->class->delete)(rangeReturn, land, range); - if (res == ResOK) - land->size -= size; + + landLeave(land); return res; } @@ -203,8 +237,11 @@ void LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) { AVERT(Land, land); AVER(FUNCHECK(visitor)); + landEnter(land); (*land->class->iterate)(land, visitor, closureP, closureS); + + landLeave(land); } @@ -222,14 +259,12 @@ Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); AVER(FindDeleteCheck(findDelete)); + landEnter(land); res = (*land->class->findFirst)(rangeReturn, oldRangeReturn, land, size, findDelete); - if (res && findDelete != FindDeleteNONE) { - AVER(RangeIsAligned(rangeReturn, land->alignment)); - AVER(land->size >= RangeSize(rangeReturn)); - land->size -= RangeSize(rangeReturn); - } + + landLeave(land); return res; } @@ -248,14 +283,12 @@ Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); AVER(FindDeleteCheck(findDelete)); + landEnter(land); res = (*land->class->findLast)(rangeReturn, oldRangeReturn, land, size, findDelete); - if (res && findDelete != FindDeleteNONE) { - AVER(RangeIsAligned(rangeReturn, land->alignment)); - AVER(land->size >= RangeSize(rangeReturn)); - land->size -= RangeSize(rangeReturn); - } + + landLeave(land); return res; } @@ -274,14 +307,12 @@ Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size si AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); AVER(FindDeleteCheck(findDelete)); + landEnter(land); res = (*land->class->findLargest)(rangeReturn, oldRangeReturn, land, size, findDelete); - if (res && findDelete != FindDeleteNONE) { - AVER(RangeIsAligned(rangeReturn, land->alignment)); - AVER(land->size >= RangeSize(rangeReturn)); - land->size -= RangeSize(rangeReturn); - } + + landLeave(land); return res; } @@ -301,14 +332,12 @@ Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size siz AVER(SizeIsAligned(size, land->alignment)); /* AVER(ZoneSet, zoneSet); */ AVERT(Bool, high); + landEnter(land); res = (*land->class->findInZones)(rangeReturn, oldRangeReturn, land, size, zoneSet, high); - if (res == ResOK) { - AVER(RangeIsAligned(rangeReturn, land->alignment)); - AVER(land->size >= RangeSize(rangeReturn)); - land->size -= RangeSize(rangeReturn); - } + + landLeave(land); return res; } @@ -331,7 +360,7 @@ Res LandDescribe(Land land, mps_lib_FILE *stream) " (\"$S\")\n", land->class->name, " arena $P\n", (WriteFP)land->arena, " align $U\n", (WriteFU)land->alignment, - " align $U\n", (WriteFU)land->size, + " inLand: $U\n", (WriteFU)land->inLand, NULL); if (res != ResOK) return res; @@ -424,6 +453,40 @@ static void landTrivFinish(Land land) NOOP; } +static Size landNoSize(Land land) +{ + UNUSED(land); + NOTREACHED; + return 0; +} + +/* LandSlowSize -- generic size method but slow */ + +static Bool landSizeVisitor(Bool *deleteReturn, Land land, Range range, + void *closureP, Size closureS) +{ + Size *size; + + AVER(deleteReturn != NULL); + AVERT(Land, land); + AVERT(Range, range); + AVER(closureP != NULL); + UNUSED(closureS); + + size = closureP; + *size += RangeSize(range); + *deleteReturn = FALSE; + + return TRUE; +} + +Size LandSlowSize(Land land) +{ + Size size = 0; + LandIterate(land, landSizeVisitor, &size, 0); + return size; +} + static Res landNoInsert(Range rangeReturn, Land land, Range range) { AVER(rangeReturn != NULL); @@ -486,6 +549,7 @@ DEFINE_CLASS(LandClass, class) class->name = "LAND"; class->size = sizeof(LandStruct); class->init = landTrivInit; + class->sizeMethod = landNoSize; class->finish = landTrivFinish; class->insert = landNoInsert; class->delete = landNoDelete; diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 406aaf7c107..070d749bb80 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -1002,8 +1002,7 @@ extern Size VMMapped(VM vm); extern Bool LandCheck(Land land); #define LandArena(land) ((land)->arena) #define LandAlignment(land) ((land)->alignment) -#define LandSize(land) ((land)->size) - +extern Size LandSize(Land land); extern Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *owner, ArgList args); extern Res LandCreate(Land *landReturn, Arena arena, LandClass class, Align alignment, void *owner, ArgList args); extern void LandDestroy(Land land); @@ -1018,6 +1017,7 @@ extern Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, S extern Res LandDescribe(Land land, mps_lib_FILE *stream); extern void LandFlush(Land dest, Land src); +extern Size LandSlowSize(Land land); extern Bool LandClassCheck(LandClass class); extern LandClass LandClassGet(void); #define LAND_SUPERCLASS(className) ((LandClass)SUPERCLASS(className)) diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 7f355ed4ec8..8ce4d14f01a 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -615,6 +615,7 @@ typedef struct LandClassStruct { ProtocolClassStruct protocol; const char *name; /* class name string */ size_t size; /* size of outer structure */ + LandSizeMethod sizeMethod; /* total size of ranges in land */ LandInitMethod init; /* initialize the land */ LandFinishMethod finish; /* finish the land */ LandInsertMethod insert; /* insert a range into the land */ @@ -641,7 +642,7 @@ typedef struct LandStruct { LandClass class; /* land class structure */ Arena arena; /* owning arena */ Align alignment; /* alignment of addresses */ - Size size; /* total size of ranges in land */ + Bool inLand; /* prevent reentrance */ } LandStruct; @@ -661,8 +662,8 @@ typedef struct CBSStruct { STATISTIC_DECL(Count treeSize); Pool blockPool; /* pool that manages blocks */ Size blockStructSize; /* size of block structure */ - Bool inCBS; /* prevent reentrance */ Bool ownPool; /* did we create blockPool? */ + Size size; /* total size of ranges in CBS */ /* meters for sizes of search structures at each op */ METER_DECL(treeSearch); Sig sig; /* .class.end-sig */ @@ -703,6 +704,7 @@ typedef struct FreelistStruct { LandStruct landStruct; /* superclass fields come first */ FreelistBlock list; /* first block in list or NULL if empty */ Count listSize; /* number of blocks in list */ + Size size; /* total size of ranges in list */ Sig sig; /* .class.end-sig */ } FreelistStruct; diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index d8eebb7bcd6..04f73a7e42d 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -268,6 +268,7 @@ typedef struct TraceMessageStruct *TraceMessage; /* trace end */ typedef Res (*LandInitMethod)(Land land, ArgList args); typedef void (*LandFinishMethod)(Land land); +typedef Size (*LandSizeMethod)(Land land); typedef Res (*LandInsertMethod)(Range rangeReturn, Land land, Range range); typedef Res (*LandDeleteMethod)(Range rangeReturn, Land land, Range range); typedef Bool (*LandVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS); diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 73bb4ff19eb..4fb5c5ce724 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -141,6 +141,7 @@ static void MVFFFreeSegs(MVFF mvff, Range range) * that needs to be read in order to update the Freelist. */ SegFree(seg); + AVER(mvff->total >= RangeSize(&delRange)); mvff->total -= RangeSize(&delRange); } @@ -502,7 +503,8 @@ static Res MVFFInit(Pool pool, ArgList args) mvff->total = 0; - res = LandInit(FreelistOfMVFF(mvff), FreelistLandClassGet(), arena, align, mvff, mps_args_none); + res = LandInit(FreelistOfMVFF(mvff), FreelistLandClassGet(), arena, align, + mvff, mps_args_none); if (res != ResOK) goto failFreelistInit; @@ -514,7 +516,8 @@ static Res MVFFInit(Pool pool, ArgList args) MPS_ARGS_BEGIN(foArgs) { MPS_ARGS_ADD(foArgs, FailoverPrimary, CBSOfMVFF(mvff)); MPS_ARGS_ADD(foArgs, FailoverSecondary, FreelistOfMVFF(mvff)); - res = LandInit(FailoverOfMVFF(mvff), FailoverLandClassGet(), arena, align, mvff, foArgs); + res = LandInit(FailoverOfMVFF(mvff), FailoverLandClassGet(), arena, align, + mvff, foArgs); } MPS_ARGS_END(foArgs); if (res != ResOK) goto failFailoverInit; @@ -541,7 +544,6 @@ static void MVFFFinish(Pool pool) { MVFF mvff; Arena arena; - Seg seg; Ring ring, node, nextNode; AVERT(Pool, pool); @@ -550,14 +552,17 @@ static void MVFFFinish(Pool pool) ring = PoolSegRing(pool); RING_FOR(node, ring, nextNode) { + Size size; + Seg seg; seg = SegOfPoolRing(node); AVER(SegPool(seg) == pool); + size = AddrOffset(SegBase(seg), SegLimit(seg)); + AVER(size <= mvff->total); + mvff->total -= size; SegFree(seg); } - /* Could maintain mvff->total here and check it falls to zero, */ - /* but that would just make the function slow. If only we had */ - /* a way to do operations only if AVERs are turned on. */ + AVER(mvff->total == 0); arena = PoolArena(pool); ControlFree(arena, mvff->segPref, sizeof(SegPrefStruct)); @@ -719,11 +724,11 @@ static Bool MVFFCheck(MVFF mvff) CHECKL(mvff->minSegSize >= ArenaAlign(PoolArena(MVFF2Pool(mvff)))); CHECKL(mvff->avgSize > 0); /* see .arg.check */ CHECKL(mvff->avgSize <= mvff->extendBy); /* see .arg.check */ - CHECKL(mvff->total >= LandSize(FailoverOfMVFF(mvff))); CHECKL(SizeIsAligned(mvff->total, ArenaAlign(PoolArena(MVFF2Pool(mvff))))); CHECKD(CBS, &mvff->cbsStruct); CHECKD(Freelist, &mvff->flStruct); CHECKD(Failover, &mvff->foStruct); + CHECKL(mvff->total >= LandSize(FailoverOfMVFF(mvff))); CHECKL(BoolCheck(mvff->slotHigh)); CHECKL(BoolCheck(mvff->firstFit)); return TRUE; diff --git a/mps/design/land.txt b/mps/design/land.txt index 3a4b81abc08..11f192fa6ff 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -117,6 +117,11 @@ finish the land structure, and then frees its memory. _`.function.finish`: ``LandFinish()`` finishes the land structure and discards any other resources associated with the land. +``void LandSize(Land land)`` + +_`.function.size`: ``LandSize()`` returns the total size of the ranges +stored in the land. + ``Res LandInsert(Range rangeReturn, Land land, Range range)`` _`.function.insert`: If any part of ``range`` is already in the