*/
ReservoirSetLimit(ArenaReservoir(arena), 0);
- arena->poolReady = FALSE;
ControlFinish(arena);
- /* We must tear down the freeLand before the chunks, because pages
- containing CBS blocks might be allocated in those chunks. */
- AVER(arena->hasFreeLand);
- arena->hasFreeLand = FALSE;
- LandFinish(ArenaFreeLand(arena));
-
- /* The CBS block pool can't free its own memory via ArenaFree because
- that would use the freeLand. */
- MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor,
- UNUSED_POINTER, UNUSED_SIZE);
+ /* We must tear down the free land before the chunks, because pages
+ * containing CBS blocks might be allocated in those chunks. */
+ arenaFreeLandFinish(arena);
/* Call class-specific finishing. This will call ArenaFinish. */
(*arena->class->finish)(arena);
@@ -427,6 +455,7 @@ Res ControlInit(Arena arena)
Res res;
AVERT(Arena, arena);
+ AVER(!arena->poolReady);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, CONTROL_EXTEND_BY);
res = PoolInit(MVPool(&arena->controlPoolStruct), arena,
@@ -444,6 +473,7 @@ Res ControlInit(Arena arena)
void ControlFinish(Arena arena)
{
AVERT(Arena, arena);
+ AVER(arena->poolReady);
arena->poolReady = FALSE;
PoolFinish(MVPool(&arena->controlPoolStruct));
}
@@ -454,7 +484,6 @@ void ControlFinish(Arena arena)
Res ArenaDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
{
Res res;
- Size reserved;
if (!TESTT(Arena, arena))
return ResFAIL;
@@ -476,20 +505,9 @@ Res ArenaDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
return res;
}
- /* Note: this Describe clause calls a function */
- reserved = ArenaReserved(arena);
res = WriteF(stream, depth + 2,
- "reserved $W <-- "
- "total size of address-space reserved\n",
- (WriteFW)reserved,
- NULL);
- if (res != ResOK)
- return res;
-
- res = WriteF(stream, depth + 2,
- "committed $W <-- "
- "total bytes currently stored (in RAM or swap)\n",
- (WriteFW)arena->committed,
+ "reserved $W\n", (WriteFW)arena->reserved,
+ "committed $W\n", (WriteFW)arena->committed,
"commitLimit $W\n", (WriteFW)arena->commitLimit,
"spareCommitted $W\n", (WriteFW)arena->spareCommitted,
"spareCommitLimit $W\n", (WriteFW)arena->spareCommitLimit,
@@ -669,7 +687,10 @@ Res ControlDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
}
-/* ArenaChunkInsert -- insert chunk into arena's chunk tree and ring */
+/* ArenaChunkInsert -- insert chunk into arena's chunk tree and ring,
+ * update the total reserved address space, and set the primary chunk
+ * if not already set.
+ */
void ArenaChunkInsert(Arena arena, Chunk chunk) {
Bool inserted;
@@ -687,6 +708,8 @@ void ArenaChunkInsert(Arena arena, Chunk chunk) {
arena->chunkTree = updatedTree;
RingAppend(&arena->chunkRing, &chunk->arenaRing);
+ arena->reserved += ChunkReserved(chunk);
+
/* As part of the bootstrap, the first created chunk becomes the primary
chunk. This step allows ArenaFreeLandInsert to allocate pages. */
if (arena->primary == NULL)
@@ -694,6 +717,31 @@ void ArenaChunkInsert(Arena arena, Chunk chunk) {
}
+/* ArenaChunkRemoved -- chunk was removed from the arena and is being
+ * finished, so update the total reserved address space, and unset the
+ * primary chunk if necessary.
+ */
+
+void ArenaChunkRemoved(Arena arena, Chunk chunk)
+{
+ Size size;
+
+ AVERT(Arena, arena);
+ AVERT(Chunk, chunk);
+
+ size = ChunkReserved(chunk);
+ AVER(arena->reserved >= size);
+ arena->reserved -= size;
+
+ if (chunk == arena->primary) {
+ /* The primary chunk must be the last chunk to be removed. */
+ AVER(RingIsSingle(&arena->chunkRing));
+ AVER(arena->reserved == 0);
+ arena->primary = NULL;
+ }
+}
+
+
/* arenaAllocPage -- allocate one page from the arena
*
* This is a primitive allocator used to allocate pages for the arena
@@ -781,7 +829,7 @@ static Res arenaExtendCBSBlockPool(Range pageRangeReturn, Arena arena)
return res;
MFSExtend(ArenaCBSBlockPool(arena), pageBase, ArenaGrainSize(arena));
- RangeInit(pageRangeReturn, pageBase, AddrAdd(pageBase, ArenaGrainSize(arena)));
+ RangeInitSize(pageRangeReturn, pageBase, ArenaGrainSize(arena));
return ResOK;
}
@@ -801,15 +849,19 @@ static void arenaExcludePage(Arena arena, Range pageRange)
}
-/* arenaLandInsert -- add range to arena's land, maybe extending block pool
+/* arenaFreeLandInsertExtend -- add range to arena's free land, maybe
+ * extending block pool
*
- * The arena's land can't get memory in the usual way because it is
- * used in the basic allocator, so we allocate pages specially.
+ * The arena's free land can't get memory for its block pool in the
+ * usual way (via ArenaAlloc), because it is the mechanism behind
+ * ArenaAlloc! So we extend the block pool via a back door (see
+ * arenaExtendCBSBlockPool).
*
* Only fails if it can't get a page for the block pool.
*/
-static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range)
+static Res arenaFreeLandInsertExtend(Range rangeReturn, Arena arena,
+ Range range)
{
Res res;
@@ -835,16 +887,18 @@ static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range)
}
-/* ArenaFreeLandInsert -- add range to arena's land, maybe stealing memory
+/* arenaFreeLandInsertSteal -- add range to arena's free land, maybe
+ * stealing memory
*
- * See arenaLandInsert. This function may only be applied to mapped
- * pages and may steal them to store Land nodes if it's unable to
- * allocate space for CBS blocks.
+ * See arenaFreeLandInsertExtend. This function may only be applied to
+ * mapped pages and may steal them to store Land nodes if it's unable
+ * to allocate space for CBS blocks.
*
* IMPORTANT: May update rangeIO.
*/
-static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO)
+static void arenaFreeLandInsertSteal(Range rangeReturn, Arena arena,
+ Range rangeIO)
{
Res res;
@@ -852,7 +906,7 @@ static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO)
AVERT(Arena, arena);
AVERT(Range, rangeIO);
- res = arenaLandInsert(rangeReturn, arena, rangeIO);
+ res = arenaFreeLandInsertExtend(rangeReturn, arena, rangeIO);
if (res != ResOK) {
Addr pageBase;
@@ -881,7 +935,8 @@ static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO)
}
-/* ArenaFreeLandInsert -- add range to arena's land, maybe extending block pool
+/* ArenaFreeLandInsert -- add range to arena's free land, maybe extending
+ * block pool
*
* The inserted block of address space may not abut any existing block.
* This restriction ensures that we don't coalesce chunks and allocate
@@ -896,7 +951,7 @@ Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit)
AVERT(Arena, arena);
RangeInit(&range, base, limit);
- res = arenaLandInsert(&oldRange, arena, &range);
+ res = arenaFreeLandInsertExtend(&oldRange, arena, &range);
if (res != ResOK)
return res;
@@ -911,7 +966,8 @@ Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit)
}
-/* ArenaFreeLandDelete -- remove range from arena's land, maybe extending block pool
+/* ArenaFreeLandDelete -- remove range from arena's free land, maybe
+ * extending block pool
*
* This is called from ChunkFinish in order to remove address space from
* the arena.
@@ -1003,7 +1059,7 @@ static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high,
failMark:
{
- Res insertRes = arenaLandInsert(&oldRange, arena, &range);
+ Res insertRes = arenaFreeLandInsertExtend(&oldRange, arena, &range);
AVER(insertRes == ResOK); /* We only just deleted it. */
/* If the insert does fail, we lose some address space permanently. */
}
@@ -1215,7 +1271,7 @@ void ArenaFree(Addr base, Size size, Pool pool)
RangeInit(&range, base, limit);
- arenaLandInsertSteal(&oldRange, arena, &range); /* may update range */
+ arenaFreeLandInsertSteal(&oldRange, arena, &range); /* may update range */
(*arena->class->free)(RangeBase(&range), RangeSize(&range), pool);
@@ -1231,7 +1287,7 @@ allDeposited:
Size ArenaReserved(Arena arena)
{
AVERT(Arena, arena);
- return (*arena->class->reserved)(arena);
+ return arena->reserved;
}
Size ArenaCommitted(Arena arena)
diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c
index e535ad770cc..cd5c24fe46a 100644
--- a/mps/code/arenacl.c
+++ b/mps/code/arenacl.c
@@ -81,8 +81,15 @@ static Bool ClientChunkCheck(ClientChunk clChunk)
ATTRIBUTE_UNUSED
static Bool ClientArenaCheck(ClientArena clientArena)
{
+ Arena arena;
+
CHECKS(ClientArena, clientArena);
- CHECKD(Arena, ClientArena2Arena(clientArena));
+ arena = ClientArena2Arena(clientArena);
+ CHECKD(Arena, arena);
+ /* See */
+ CHECKL(arena->committed <= arena->reserved);
+ CHECKL(arena->spareCommitted == 0);
+
return TRUE;
}
@@ -121,15 +128,17 @@ static Res clientChunkCreate(Chunk *chunkReturn, ClientArena clientArena,
res = BootAlloc(&p, boot, sizeof(ClientChunkStruct), MPS_PF_ALIGN);
if (res != ResOK)
goto failChunkAlloc;
- clChunk = p; chunk = ClientChunk2Chunk(clChunk);
+ clChunk = p;
+ chunk = ClientChunk2Chunk(clChunk);
res = ChunkInit(chunk, arena, alignedBase,
- AddrAlignDown(limit, ArenaGrainSize(arena)), boot);
+ AddrAlignDown(limit, ArenaGrainSize(arena)),
+ AddrOffset(base, limit), boot);
if (res != ResOK)
goto failChunkInit;
- ClientArena2Arena(clientArena)->committed +=
- AddrOffset(base, PageIndexBase(chunk, chunk->allocBase));
+ arena->committed += ChunkPagesToSize(chunk, chunk->allocBase);
+
BootBlockFinish(boot);
clChunk->sig = ClientChunkSig;
@@ -155,7 +164,6 @@ static Res ClientChunkInit(Chunk chunk, BootBlock boot)
/* chunk is supposed to be uninitialized, so don't check it. */
clChunk = Chunk2ClientChunk(chunk);
AVERT(BootBlock, boot);
- UNUSED(boot);
/* TODO: An old comment claimed this is too large.
Does it fail to exclude the page table or something? */
@@ -176,8 +184,10 @@ static Res ClientChunkInit(Chunk chunk, BootBlock boot)
static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS)
{
+ Arena arena;
Chunk chunk;
ClientChunk clChunk;
+ Size size;
AVERT(Tree, tree);
AVER(closureP == UNUSED_POINTER);
@@ -187,8 +197,15 @@ static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS)
chunk = ChunkOfTree(tree);
AVERT(Chunk, chunk);
+ arena = ChunkArena(chunk);
+ AVERT(Arena, arena);
clChunk = Chunk2ClientChunk(chunk);
AVERT(ClientChunk, clChunk);
+ AVER(chunk->pages == clChunk->freePages);
+
+ size = ChunkPagesToSize(chunk, chunk->allocBase);
+ AVER(arena->committed >= size);
+ arena->committed -= size;
clChunk->sig = SigInvalid;
ChunkFinish(chunk);
@@ -202,7 +219,7 @@ static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS)
static void ClientChunkFinish(Chunk chunk)
{
/* Can't check chunk as it's not valid anymore. */
- UNUSED(chunk); NOOP;
+ UNUSED(chunk);
}
@@ -227,7 +244,7 @@ static void ClientArenaVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs)
* to do the generic part of init.
*/
-ARG_DEFINE_KEY(arena_cl_addr, Addr);
+ARG_DEFINE_KEY(ARENA_CL_BASE, Addr);
static Res ClientArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
{
@@ -257,6 +274,10 @@ static Res ClientArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
AVER(base != (Addr)0);
AVERT(ArenaGrainSize, grainSize);
+ if (size < grainSize * MPS_WORD_WIDTH)
+ /* Not enough room for a full complement of zones. */
+ return ResMEMORY;
+
clArenaSize = SizeAlignUp(sizeof(ClientArenaStruct), MPS_PF_ALIGN);
if (size < clArenaSize)
return ResMEMORY;
@@ -320,6 +341,10 @@ static void ClientArenaFinish(Arena arena)
clientArena->sig = SigInvalid;
+ /* Destroying the chunks should leave nothing behind. */
+ AVER(arena->reserved == 0);
+ AVER(arena->committed == 0);
+
ArenaFinish(arena); /* */
}
@@ -344,27 +369,6 @@ static Res ClientArenaExtend(Arena arena, Addr base, Size size)
}
-/* ClientArenaReserved -- return the amount of reserved address space */
-
-static Size ClientArenaReserved(Arena arena)
-{
- Size size;
- Ring node, nextNode;
-
- AVERT(Arena, arena);
-
- size = 0;
- /* .req.extend.slow */
- RING_FOR(node, &arena->chunkRing, nextNode) {
- Chunk chunk = RING_ELT(Chunk, arenaRing, node);
- AVERT(Chunk, chunk);
- size += ChunkSize(chunk);
- }
-
- return size;
-}
-
-
/* ClientArenaPagesMarkAllocated -- Mark the pages allocated */
static Res ClientArenaPagesMarkAllocated(Arena arena, Chunk chunk,
@@ -372,9 +376,12 @@ static Res ClientArenaPagesMarkAllocated(Arena arena, Chunk chunk,
Pool pool)
{
Index i;
+ ClientChunk clChunk;
AVERT(Arena, arena);
AVERT(Chunk, chunk);
+ clChunk = Chunk2ClientChunk(chunk);
+ AVERT(ClientChunk, clChunk);
AVER(chunk->allocBase <= baseIndex);
AVER(pages > 0);
AVER(baseIndex + pages <= chunk->pages);
@@ -383,15 +390,17 @@ static Res ClientArenaPagesMarkAllocated(Arena arena, Chunk chunk,
for (i = 0; i < pages; ++i)
PageAlloc(chunk, baseIndex + i, pool);
- Chunk2ClientChunk(chunk)->freePages -= pages;
+ arena->committed += ChunkPagesToSize(chunk, pages);
+ AVER(clChunk->freePages >= pages);
+ clChunk->freePages -= pages;
return ResOK;
}
-/* ClientFree - free a region in the arena */
+/* ClientArenaFree - free a region in the arena */
-static void ClientFree(Addr base, Size size, Pool pool)
+static void ClientArenaFree(Addr base, Size size, Pool pool)
{
Arena arena;
Chunk chunk = NULL; /* suppress "may be used uninitialized" */
@@ -432,6 +441,8 @@ static void ClientFree(Addr base, Size size, Pool pool)
AVER(BTIsSetRange(chunk->allocTable, baseIndex, limitIndex));
BTResRange(chunk->allocTable, baseIndex, limitIndex);
+ AVER(arena->committed >= size);
+ arena->committed -= size;
clChunk->freePages += pages;
}
@@ -447,10 +458,9 @@ DEFINE_ARENA_CLASS(ClientArenaClass, this)
this->varargs = ClientArenaVarargs;
this->init = ClientArenaInit;
this->finish = ClientArenaFinish;
- this->reserved = ClientArenaReserved;
this->extend = ClientArenaExtend;
this->pagesMarkAllocated = ClientArenaPagesMarkAllocated;
- this->free = ClientFree;
+ this->free = ClientArenaFree;
this->chunkInit = ClientChunkInit;
this->chunkFinish = ClientChunkFinish;
AVERT(ArenaClass, this);
diff --git a/mps/code/arenacv.c b/mps/code/arenacv.c
index 469cfc86956..7b02c11bcc2 100644
--- a/mps/code/arenacv.c
+++ b/mps/code/arenacv.c
@@ -397,7 +397,7 @@ static void testAllocAndIterate(Arena arena, Pool pool,
allocator->free(&offsetRegion);
}
}
- LocusPrefExpress(&pref, LocusPrefZoneSet, &zone);
+ LocusPrefExpress(&pref, LocusPrefZONESET, &zone);
}
}
diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c
index 97d2efe3e95..ba34a7c70ef 100644
--- a/mps/code/arenavm.c
+++ b/mps/code/arenavm.c
@@ -323,7 +323,8 @@ static Res VMChunkCreate(Chunk *chunkReturn, VMArena vmArena, Size size)
/* Copy VM descriptor into its place in the chunk. */
VMCopy(VMChunkVM(vmChunk), vm);
- res = ChunkInit(VMChunk2Chunk(vmChunk), arena, base, limit, boot);
+ res = ChunkInit(VMChunk2Chunk(vmChunk), arena, base, limit,
+ VMReserved(VMChunkVM(vmChunk)), boot);
if (res != ResOK)
goto failChunkInit;
@@ -507,6 +508,7 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
{
Size size = VM_ARENA_SIZE_DEFAULT; /* initial arena size */
Align grainSize = MPS_PF_ALIGN; /* arena grain size */
+ Size pageSize = PageSize(); /* operating system page size */
Size chunkSize; /* size actually created */
Size vmArenaSize; /* aligned size of VMArenaStruct */
Res res;
@@ -522,14 +524,19 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
AVER(class == VMArenaClassGet());
AVERT(ArgList, args);
- if (ArgPick(&arg, args, MPS_KEY_ARENA_SIZE))
- size = arg.val.size;
if (ArgPick(&arg, args, MPS_KEY_ARENA_GRAIN_SIZE))
grainSize = arg.val.size;
- grainSize = SizeAlignUp(grainSize, PageSize());
-
- AVER(size > 0);
+ if (grainSize < pageSize)
+ /* Make it easier to write portable programs by rounding up. */
+ grainSize = pageSize;
AVERT(ArenaGrainSize, grainSize);
+
+ if (ArgPick(&arg, args, MPS_KEY_ARENA_SIZE))
+ size = arg.val.size;
+ if (size < grainSize * MPS_WORD_WIDTH)
+ /* There has to be enough room in the chunk for a full complement of
+ zones. Make it easier to write portable programs by rounding up. */
+ size = grainSize * MPS_WORD_WIDTH;
/* Parse remaining arguments, if any, into VM parameters. We must do
this into some stack-allocated memory for the moment, since we
@@ -554,6 +561,7 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
res = ArenaInit(arena, class, grainSize, args);
if (res != ResOK)
goto failArenaInit;
+ arena->reserved = VMReserved(vm);
arena->committed = VMMapped(vm);
/* Copy VM descriptor into its place in the arena. */
@@ -634,6 +642,7 @@ static void VMArenaFinish(Arena arena)
RingFinish(&vmArena->spareRing);
/* Destroying the chunks should leave only the arena's own VM. */
+ AVER(arena->reserved == VMReserved(VMArenaVM(vmArena)));
AVER(arena->committed == VMMapped(VMArenaVM(vmArena)));
vmArena->sig = SigInvalid;
@@ -648,25 +657,6 @@ static void VMArenaFinish(Arena arena)
}
-/* VMArenaReserved -- return the amount of reserved address space
- *
- * Add up the reserved space from all the chunks.
- */
-
-static Size VMArenaReserved(Arena arena)
-{
- Size reserved;
- Ring node, next;
-
- reserved = 0;
- RING_FOR(node, &arena->chunkRing, next) {
- VMChunk vmChunk = Chunk2VMChunk(RING_ELT(Chunk, arenaRing, node));
- reserved += VMReserved(VMChunkVM(vmChunk));
- }
- return reserved;
-}
-
-
/* vmArenaChunkSize -- choose chunk size for arena extension
*
* .vmchunk.overhead: This code still lacks a proper estimate of
@@ -717,7 +707,7 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
chunkSize = vmArenaChunkSize(vmArena, size);
EVENT3(vmArenaExtendStart, size, chunkSize,
- VMArenaReserved(VMArena2Arena(vmArena)));
+ ArenaReserved(VMArena2Arena(vmArena)));
/* .chunk-create.fail: If we fail, try again with a smaller size */
{
@@ -731,17 +721,17 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
if (chunkSize < chunkMin)
chunkSize = chunkMin;
+ res = ResRESOURCE;
for(;; chunkSize = chunkHalf) {
chunkHalf = chunkSize / 2;
sliceSize = chunkHalf / fidelity;
AVER(sliceSize > 0);
/* remove slices, down to chunkHalf but no further */
- res = ResRESOURCE;
for(; chunkSize > chunkHalf; chunkSize -= sliceSize) {
if(chunkSize < chunkMin) {
EVENT2(vmArenaExtendFail, chunkMin,
- VMArenaReserved(VMArena2Arena(vmArena)));
+ ArenaReserved(VMArena2Arena(vmArena)));
return res;
}
res = VMChunkCreate(&newChunk, vmArena, chunkSize);
@@ -752,7 +742,7 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
}
vmArenaGrow_Done:
- EVENT2(vmArenaExtendDone, chunkSize, VMArenaReserved(VMArena2Arena(vmArena)));
+ EVENT2(vmArenaExtendDone, chunkSize, ArenaReserved(VMArena2Arena(vmArena)));
vmArena->extended(VMArena2Arena(vmArena),
newChunk->base,
AddrOffset(newChunk->base, newChunk->limit));
@@ -800,16 +790,23 @@ static Res pageDescMap(VMChunk vmChunk, Index basePI, Index limitPI)
Size before = VMMapped(VMChunkVM(vmChunk));
Arena arena = VMArena2Arena(VMChunkVMArena(vmChunk));
Res res = SparseArrayMap(&vmChunk->pages, basePI, limitPI);
- arena->committed += VMMapped(VMChunkVM(vmChunk)) - before;
+ Size after = VMMapped(VMChunkVM(vmChunk));
+ AVER(before <= after);
+ arena->committed += after - before;
return res;
}
static void pageDescUnmap(VMChunk vmChunk, Index basePI, Index limitPI)
{
+ Size size, after;
Size before = VMMapped(VMChunkVM(vmChunk));
Arena arena = VMArena2Arena(VMChunkVMArena(vmChunk));
SparseArrayUnmap(&vmChunk->pages, basePI, limitPI);
- arena->committed += VMMapped(VMChunkVM(vmChunk)) - before;
+ after = VMMapped(VMChunkVM(vmChunk));
+ AVER(after <= before);
+ size = before - after;
+ AVER(arena->committed >= size);
+ arena->committed -= size;
}
@@ -1117,8 +1114,10 @@ static Bool vmChunkCompact(Tree tree, void *closureP, Size closureS)
{
Addr base = chunk->base;
Size size = ChunkSize(chunk);
+ /* Callback before destroying the chunk, as the arena is (briefly)
+ invalid afterwards. See job003893. */
+ (*vmArena->contracted)(arena, base, size);
vmChunkDestroy(tree, UNUSED_POINTER, UNUSED_SIZE);
- vmArena->contracted(arena, base, size);
return TRUE;
} else {
/* Keep this chunk. */
@@ -1136,7 +1135,7 @@ static void VMCompact(Arena arena, Trace trace)
AVERT(VMArena, vmArena);
AVERT(Trace, trace);
- vmem1 = VMArenaReserved(arena);
+ vmem1 = ArenaReserved(arena);
/* Destroy chunks that are completely free, but not the primary
* chunk. See
@@ -1146,7 +1145,7 @@ static void VMCompact(Arena arena, Trace trace)
{
Size vmem0 = trace->preTraceArenaReserved;
- Size vmem2 = VMArenaReserved(arena);
+ Size vmem2 = ArenaReserved(arena);
/* VMCompact event: emit for all client-requested collections, */
/* plus any others where chunks were gained or lost during the */
@@ -1196,7 +1195,6 @@ DEFINE_ARENA_CLASS(VMArenaClass, this)
this->varargs = VMArenaVarargs;
this->init = VMArenaInit;
this->finish = VMArenaFinish;
- this->reserved = VMArenaReserved;
this->purgeSpare = VMPurgeSpare;
this->grow = VMArenaGrow;
this->free = VMFree;
diff --git a/mps/code/arg.c b/mps/code/arg.c
index 784a7e57f30..4721c415ccb 100644
--- a/mps/code/arg.c
+++ b/mps/code/arg.c
@@ -105,7 +105,7 @@ Bool ArgCheckPool(Arg arg) {
}
-ARG_DEFINE_KEY(args_end, Shouldnt);
+ARG_DEFINE_KEY(ARGS_END, Shouldnt);
ArgStruct mps_args_none[] = {{MPS_KEY_ARGS_END, {0}}};
@@ -174,9 +174,8 @@ found:
/* ArgRequire -- take a required argument out of the argument list by keyword */
void ArgRequire(ArgStruct *argOut, ArgList args, Key key) {
- if (ArgPick(argOut, args, key))
- return;
- NOTREACHED;
+ Bool b = ArgPick(argOut, args, key);
+ ASSERT(b, key->name);
}
diff --git a/mps/code/arg.h b/mps/code/arg.h
index bb184dddad9..2b5b3fbb31a 100644
--- a/mps/code/arg.h
+++ b/mps/code/arg.h
@@ -29,7 +29,7 @@ typedef struct mps_key_s {
#define ARG_DEFINE_KEY(id, type) \
extern const KeyStruct _mps_key_##id; \
- const KeyStruct _mps_key_##id = {KeySig, #id, ArgCheck##type}
+ const KeyStruct _mps_key_##id = {KeySig, "MPS_KEY_" #id, ArgCheck##type}
#define argsNone mps_args_none
diff --git a/mps/code/buffer.c b/mps/code/buffer.c
index 2e2ed0bc458..edef611c217 100644
--- a/mps/code/buffer.c
+++ b/mps/code/buffer.c
@@ -19,10 +19,8 @@
*
* TRANSGRESSIONS
*
- * .trans.mod: There are several instances where pool structures are
- * directly accessed by this module because does not provide
- * an adequate (or adequately documented) interface. They bear this
- * tag.
+ * .trans.mod: pool->bufferSerial is directly accessed by this module
+ * because does not provide an interface.
*/
#include "mpm.h"
@@ -221,7 +219,7 @@ static Res BufferInit(Buffer buffer, BufferClass class,
}
buffer->fillSize = 0.0;
buffer->emptySize = 0.0;
- buffer->alignment = pool->alignment; /* .trans.mod */
+ buffer->alignment = PoolAlignment(pool);
buffer->base = (Addr)0;
buffer->initAtFlip = (Addr)0;
/* In the next three assignments we really mean zero, not NULL, because
@@ -328,12 +326,10 @@ void BufferDetach(Buffer buffer, Pool pool)
spare = AddrOffset(init, limit);
buffer->emptySize += spare;
if (buffer->isMutator) {
- buffer->pool->emptyMutatorSize += spare;
ArenaGlobals(buffer->arena)->emptyMutatorSize += spare;
ArenaGlobals(buffer->arena)->allocMutatorSize +=
AddrOffset(buffer->base, init);
} else {
- buffer->pool->emptyInternalSize += spare;
ArenaGlobals(buffer->arena)->emptyInternalSize += spare;
}
@@ -657,10 +653,8 @@ void BufferAttach(Buffer buffer, Addr base, Addr limit,
Size prealloc = AddrOffset(base, init);
ArenaGlobals(buffer->arena)->allocMutatorSize -= prealloc;
}
- buffer->pool->fillMutatorSize += filled;
ArenaGlobals(buffer->arena)->fillMutatorSize += filled;
} else {
- buffer->pool->fillInternalSize += filled;
ArenaGlobals(buffer->arena)->fillInternalSize += filled;
}
diff --git a/mps/code/cbs.c b/mps/code/cbs.c
index 7e4340f1929..0b30b68acb1 100644
--- a/mps/code/cbs.c
+++ b/mps/code/cbs.c
@@ -1,7 +1,7 @@
/* cbs.c: COALESCING BLOCK STRUCTURE IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
* .intro: This is a portable implementation of coalescing block
* structures.
@@ -215,7 +215,7 @@ static void cbsUpdateZonedNode(SplayTree splay, Tree tree)
ARG_DEFINE_KEY(cbs_block_pool, Pool);
-static Res cbsInitComm(Land land, ArgList args, SplayUpdateNodeMethod update,
+static Res cbsInitComm(Land land, ArgList args, SplayUpdateNodeFunction update,
Size blockStructSize)
{
CBS cbs;
@@ -1058,7 +1058,7 @@ static Res cbsFindInZones(Bool *foundReturn, Range rangeReturn,
cbsTestNodeInZonesClosureStruct closure;
Res res;
LandFindMethod landFind;
- SplayFindMethod splayFind;
+ SplayFindFunction splayFind;
RangeStruct rangeStruct, oldRangeStruct;
AVER(foundReturn != NULL);
@@ -1069,7 +1069,7 @@ static Res cbsFindInZones(Bool *foundReturn, Range rangeReturn,
AVERT(CBS, cbs);
AVER(IsLandSubclass(CBSLand(cbs), CBSZonedLandClass));
/* AVERT(ZoneSet, zoneSet); */
- AVER(BoolCheck(high));
+ AVERT(Bool, high);
landFind = high ? cbsFindLast : cbsFindFirst;
splayFind = high ? SplayFindLast : SplayFindFirst;
@@ -1208,7 +1208,7 @@ DEFINE_LAND_CLASS(CBSZonedLandClass, class)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk
index ba2065c5ce1..c82caa4576e 100644
--- a/mps/code/comm.gmk
+++ b/mps/code/comm.gmk
@@ -36,7 +36,6 @@
# NOISY if defined and non-empty, causes commands to be emitted
# MPMPF platform-dependent C sources for the "mpm" part
# MPMS assembler sources for the "mpm" part (.s files)
-# MPMPS pre-processor assembler sources for the "mpm" part (.S files)
#
# %%PART: When adding a new part, add a new parameter above for the
# files included in the part.
@@ -213,7 +212,8 @@ MPMCOMMON = \
version.c \
vm.c \
walk.c
-MPM = $(MPMCOMMON) $(MPMPF) $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(PLINTH)
+POOLS = $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(SNC)
+MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH)
# These map the source file lists onto object files and dependency files
@@ -308,12 +308,12 @@ all: $(ALL_TARGETS)
# testci = continuous integration tests, must be known good
# testall = all test cases, for ensuring quality of a release
# testansi = tests that run on the generic ("ANSI") platform
-# testpoll = tests that run on the generic platform with CONFIG_POLL_NONE
+# testpollnone = tests that run on the generic platform with CONFIG_POLL_NONE
-TEST_SUITES=testrun testci testall testansi testpoll
+TEST_SUITES=testrun testci testall testansi testpollnone
$(addprefix $(PFM)/$(VARIETY)/,$(TEST_SUITES)): $(TEST_TARGETS)
- ../tool/testrun.sh "$(PFM)/$(VARIETY)" "$(notdir $@)"
+ ../tool/testrun.sh -s "$(notdir $@)" "$(PFM)/$(VARIETY)"
# These convenience targets allow one to type "make foo" to build target
diff --git a/mps/code/commpost.nmk b/mps/code/comm.nmk
similarity index 54%
rename from mps/code/commpost.nmk
rename to mps/code/comm.nmk
index ffb6b6a9efb..a59132ff354 100644
--- a/mps/code/commpost.nmk
+++ b/mps/code/comm.nmk
@@ -1,11 +1,330 @@
-# commpost.nmk: SECOND COMMON FRAGMENT FOR PLATFORMS USING NMAKE -*- makefile -*-
+# -*- makefile -*-
+#
+# comm.nmk: COMMON NMAKE FRAGMENT
#
# $Id$
# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
#
# DESCRIPTION
#
-# Second common makefile fragment for w3*mv.nmk. See commpre.nmk
+# This makefile fragment is included in more specific makefiles for
+# platforms which use nmake.
+#
+# %%PART: When adding a new part, add a new parameter for the files included
+# in the part
+# Parameters:
+# PFM platform code, e.g. "w3i3mv"
+# PFMDEFS /D options to define platforms preprocessor symbols
+# to the compiler. Avoid using this if possible, as it
+# prevents the MPS being built with a simple command like
+# "cl mps.c".
+# MPMCOMMON list of sources which make up the "mpm" part for all
+# platforms. Each source is stripped of its .c extension
+# and surrounded with [brackets].
+# MPMPF as above for the current platform.
+# PLINTH as above for the "plinth" part
+# AMC as above for the "amc" part
+# AMS as above for the "ams" part
+# LO as above for the "lo" part
+# POOLN as above for the "pooln" part
+# SNC as above for the "snc" part
+# POOLS as above for all pools included in the target
+# MPM as above for the MPMCOMMON + MPMPF + PLINTH + POOLS
+# DW as above for the "dw" part
+# FMTTEST as above for the "fmttest" part
+# FMTSCHEME as above for the "fmtscheme" part
+# TESTLIB as above for the "testlib" part
+# TESTTHR as above for the "testthr" part
+# NOISY if defined, causes command to be emitted
+#
+#
+# EDITING
+#
+# To add new targets. varieties, and parts:
+# Search for the string "%%TARGET", "%%VARIETY", or "%%PART" in this makefile
+# and follow the instructions.
+#
+
+
+# TARGETS
+#
+#
+# %%TARGET: When adding a new target, add it to one of the variables
+# in this section. Library components go in LIB_TARGETS.
+
+LIB_TARGETS=mps.lib
+
+# Test cases go in TEST_TARGETS.
+
+TEST_TARGETS=\
+ abqtest.exe \
+ airtest.exe \
+ amcss.exe \
+ amcsshe.exe \
+ amcssth.exe \
+ amsss.exe \
+ amssshe.exe \
+ apss.exe \
+ arenacv.exe \
+ awlut.exe \
+ awluthe.exe \
+ awlutth.exe \
+ btcv.exe \
+ bttest.exe \
+ djbench.exe \
+ exposet0.exe \
+ expt825.exe \
+ finalcv.exe \
+ finaltest.exe \
+ fotest.exe \
+ gcbench.exe \
+ landtest.exe \
+ locbwcss.exe \
+ lockcov.exe \
+ lockut.exe \
+ locusss.exe \
+ locv.exe \
+ messtest.exe \
+ mpmss.exe \
+ mpsicv.exe \
+ mv2test.exe \
+ nailboardtest.exe \
+ poolncv.exe \
+ qs.exe \
+ sacss.exe \
+ segsmss.exe \
+ steptest.exe \
+ teletest.exe \
+ walkt0.exe \
+ zcoll.exe \
+ zmess.exe
+
+# Stand-alone programs go in EXTRA_TARGETS if they should always be
+# built, or in OPTIONAL_TARGETS if they should only be built if
+
+EXTRA_TARGETS=mpseventcnv.exe mpseventtxt.exe
+OPTIONAL_TARGETS=mpseventsql.exe
+
+# This target records programs that we were once able to build but
+# can't at the moment:
+#
+# replay -- depends on the EPVM pool.
+
+UNBUILDABLE_TARGETS=replay.exe
+
+ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS)
+
+
+# PARAMETERS
+#
+#
+# %%PART: When adding a new part, add the sources for the new part here.
+
+MPMCOMMON=\
+ [abq] \
+ [arena] \
+ [arenacl] \
+ [arenavm] \
+ [arg] \
+ [boot] \
+ [bt] \
+ [buffer] \
+ [cbs] \
+ [dbgpool] \
+ [dbgpooli] \
+ [event] \
+ [failover] \
+ [format] \
+ [freelist] \
+ [global] \
+ [land] \
+ [ld] \
+ [locus] \
+ [message] \
+ [meter] \
+ [mpm] \
+ [mpsi] \
+ [nailboard] \
+ [pool] \
+ [poolabs] \
+ [poolmfs] \
+ [poolmrg] \
+ [poolmv2] \
+ [poolmv] \
+ [protocol] \
+ [range] \
+ [ref] \
+ [reserv] \
+ [ring] \
+ [root] \
+ [sa] \
+ [sac] \
+ [seg] \
+ [shield] \
+ [splay] \
+ [ss] \
+ [table] \
+ [trace] \
+ [traceanc] \
+ [tract] \
+ [tree] \
+ [version] \
+ [vm] \
+ [walk]
+PLINTH = [mpsliban] [mpsioan]
+AMC = [poolamc]
+AMS = [poolams] [poolamsi]
+AWL = [poolawl]
+LO = [poollo]
+MVFF = [poolmvff]
+POOLN = [pooln]
+SNC = [poolsnc]
+FMTDY = [fmtdy] [fmtno]
+FMTTEST = [fmthe] [fmtdy] [fmtno] [fmtdytst]
+FMTSCHEME = [fmtscheme]
+TESTLIB = [testlib] [getoptl]
+TESTTHR = [testthrw3]
+POOLS = $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(SNC)
+MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH)
+
+
+# CHECK PARAMETERS
+#
+#
+# %%PART: When adding a new part, add checks for the parameter with the
+# sources for the new part.
+
+!IFNDEF PFM
+!ERROR comm.nmk: PFM not defined
+!ENDIF
+!IFNDEF MPM
+!ERROR comm.nmk: MPM not defined
+!ENDIF
+!IFNDEF MPMCOMMON
+!ERROR comm.nmk: MPMCOMMON not defined
+!ENDIF
+!IFNDEF MPMPF
+!ERROR comm.nmk: MPMPF not defined
+!ENDIF
+!IFNDEF PLINTH
+!ERROR comm.nmk: PLINTH not defined
+!ENDIF
+!IFNDEF LO
+!ERROR comm.nmk: LO not defined
+!ENDIF
+!IFNDEF AMC
+!ERROR comm.nmk: AMC not defined
+!ENDIF
+!IFNDEF AMS
+!ERROR comm.nmk: AMS not defined
+!ENDIF
+!IFNDEF POOLN
+!ERROR comm.nmk: POOLN not defined
+!ENDIF
+!IFNDEF SNC
+!ERROR comm.nmk: SNC not defined
+!ENDIF
+!IFNDEF FMTDY
+!ERROR comm.nmk: FMTDY not defined
+!ENDIF
+!IFNDEF FMTTEST
+!ERROR comm.nmk: FMTTEST not defined
+!ENDIF
+!IFNDEF FMTSCHEME
+!ERROR comm.nmk: FMTSCHEME not defined
+!ENDIF
+!IFNDEF TESTLIB
+!ERROR comm.nmk: TESTLIB not defined
+!ENDIF
+!IFNDEF TESTTHR
+!ERROR comm.nmk: TESTTHR not defined
+!ENDIF
+
+
+# DECLARATIONS
+
+
+!IFDEF NOISY
+ECHO = rem
+!ELSE
+.SILENT:
+ECHO = echo
+!ENDIF
+
+
+# C FLAGS
+
+CFLAGSTARGETPRE =
+CFLAGSTARGETPOST =
+CRTFLAGSHOT =
+CRTFLAGSCOOL =
+LINKFLAGSHOT =
+LINKFLAGSCOOL =
+
+CFLAGSSQLPRE = /nologo $(PFMDEFS)
+CFLAGSCOMMONPRE = /nologo $(PFMDEFS) $(CFLAGSTARGETPRE)
+CFLAGSSQLPOST =
+CFLAGSCOMMONPOST = $(CFLAGSTARGETPOST)
+
+# Flags for use in the variety combinations
+CFLAGSHOT = /O2
+# (above /O2 (maximise speed) used to be set to /Ox
+# (maximise optimisations) in for tool versions before VS 9)
+# We used to have /GZ here (stack probe).
+# Note that GZ is specific to version 12 of the cl tool. drj 2003-11-04
+# It is ignored on earlier versions of the cl tool.
+# /GZ here generates a dependency on the C library and when we are
+# building a DLL, mpsdy.dll, the linker step will fail (error LNK2001:
+# unresolved external symbol __chkesp). See
+# http://support.microsoft.com/kb/q191669/
+CFLAGSCOOL =
+CFLAGSINTERNAL = /Zi
+CFLAGSEXTERNAL =
+
+# The combinations of variety
+# %%VARIETY: When adding a new variety, define a macro containing the set
+# of flags for the new variety.
+CFRASH = /DCONFIG_VAR_RASH $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSEXTERNAL)
+CFHOT = /DCONFIG_VAR_HOT $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL)
+CFCOOL = /DCONFIG_VAR_COOL $(CRTFLAGSCOOL) $(CFLAGSCOOL) $(CFLAGSINTERNAL)
+
+# Microsoft documentation is not very clear on the point of using both
+# optimization and debug information
+
+# LINKER FLAGS
+# %%VARIETY: When adding a new variety, define a macro containing the flags
+# for the new variety
+LINKER = link
+LINKFLAGSCOMMON = /nologo /LARGEADDRESSAWARE
+LINKFLAGSINTERNAL = /DEBUG
+# ( Internal flags used to be set to /DEBUG:full )
+LINKFLAGSEXTERNAL = /RELEASE
+
+LFRASH = $(LINKFLAGSHOT) $(LINKFLAGSEXTERNAL)
+LFHOT = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL)
+LFCOOL = $(LINKFLAGSCOOL) $(LINKFLAGSINTERNAL)
+
+#LFCV = /PROFILE /DEBUG:full /DEBUGTYPE:cv
+
+# Library manager
+# %%VARIETY: When adding a new variety, define a macro containing the flags
+# for the new variety
+LIBMAN = lib # can't call this LIB - it screws the environment
+LIBFLAGSCOMMON =
+
+LIBFLAGSRASH =
+LIBFLAGSHOT =
+LIBFLAGSCOOL =
+
+# Browser database manager [not used at present]
+#BSC = bscmake
+#BSCFLAGS = /nologo /n
+
+
+# == Common definitions ==
+# %%PART: When adding a new part, add it here, unless it's platform-specific
+# [It is not possible use a macro, like $(PFM), in a substitution,
+# hence all parts end up being platform-specific.]
# == Pseudo-targets ==
@@ -56,10 +375,10 @@ variety: $(PFM)\$(VARIETY)\$(TARGET)
!ENDIF
!ENDIF
-# testrun testci testall testansi testpoll
+# testrun testci testall testansi testpollnone
# Runs automated test cases.
-testrun testci testall testansi testpoll: $(TEST_TARGETS)
+testrun testci testall testansi testpollnone: $(TEST_TARGETS)
!IFDEF VARIETY
..\tool\testrun.bat $(PFM) $(VARIETY) $@
!ELSE
@@ -68,6 +387,69 @@ testrun testci testall testansi testpoll: $(TEST_TARGETS)
!ENDIF
+# FLAGS AMALGAMATION
+#
+# %%VARIETY: When adding a new variety, add the following macros that
+# expand to sets of flags that the variety should use:
+#
+# CFLAGS -- when compiling C;
+# CFLAGSSQL -- when compiling mpseventsql;
+# LINKFLAGS -- when building executables;
+# LIBFLAGS -- when building libraries.
+
+!IF "$(VARIETY)" == "hot"
+CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST)
+CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST)
+LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT)
+LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT)
+
+!ELSEIF "$(VARIETY)" == "cool"
+CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST)
+CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST)
+LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL)
+LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL)
+
+!ELSEIF "$(VARIETY)" == "rash"
+CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST)
+CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST)
+LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH)
+LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH)
+
+!ENDIF
+
+
+# SOURCE TO OBJECT FILE MAPPINGS
+#
+# %%PART: When adding a new part, add new macros which expand to the object
+# files included in the part
+#
+# Note: nmake doesn't expand variables within a string replacement
+# operation. We work around this by writing out a temporary makefile
+# and including it.
+
+TEMPMAKE=$(TEMP)\mps.nmk
+!IF [echo MPMOBJ0 = $$(MPM:[=$(PFM)\$(VARIETY)\) > $(TEMPMAKE)] == 0 \
+ && [echo FMTDYOBJ0 = $$(FMTDY:[=$(PFM)\$(VARIETY)\) >> $(TEMPMAKE)] == 0 \
+ && [echo FMTTESTOBJ0 = $$(FMTTEST:[=$(PFM)\$(VARIETY)\) >> $(TEMPMAKE)] == 0 \
+ && [echo FMTSCHEMEOBJ0 = $$(FMTSCHEME:[=$(PFM)\$(VARIETY)\) >> $(TEMPMAKE)] == 0 \
+ && [echo POOLNOBJ0 = $$(POOLN:[=$(PFM)\$(VARIETY)\) >> $(TEMPMAKE)] == 0 \
+ && [echo TESTLIBOBJ0 = $$(TESTLIB:[=$(PFM)\$(VARIETY)\) >> $(TEMPMAKE)] == 0 \
+ && [echo TESTTHROBJ0 = $$(TESTTHR:[=$(PFM)\$(VARIETY)\) >> $(TEMPMAKE)] == 0
+!INCLUDE $(TEMPMAKE)
+!IF [del $(TEMPMAKE)] != 0
+!ERROR Failed to delete $(TEMPMAKE)
+!ENDIF
+!ENDIF
+
+MPMOBJ = $(MPMOBJ0:]=.obj)
+FMTDYOBJ = $(FMTDYOBJ0:]=.obj)
+FMTTESTOBJ = $(FMTTESTOBJ0:]=.obj)
+FMTSCHEMEOBJ = $(FMTSCHEMEOBJ0:]=.obj)
+POOLNOBJ = $(POOLNOBJ0:]=.obj)
+TESTLIBOBJ = $(TESTLIBOBJ0:]=.obj)
+TESTTHROBJ = $(TESTTHROBJ0:]=.obj)
+
+
# THE MPS LIBRARY
#
# The MPS library is built in two ways:
@@ -319,18 +701,18 @@ $(PFM)\$(VARIETY)\sqlite3.obj:
# Copyright (C) 2001-2014 Ravenbrook Limited .
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
-#
+#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
-#
+#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
-#
+#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
-#
+#
# 3. Redistributions in any form must be accompanied by information on how
# to obtain complete source code for this software and any accompanying
# software that uses this software. The source code must either be
@@ -341,7 +723,7 @@ $(PFM)\$(VARIETY)\sqlite3.obj:
# include source code for modules or files that typically accompany the
# major components of the operating system on which the executable file
# runs.
-#
+#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk
deleted file mode 100644
index 45b16cdb2a2..00000000000
--- a/mps/code/commpre.nmk
+++ /dev/null
@@ -1,368 +0,0 @@
-# commpre.nmk: FIRST COMMON FRAGMENT FOR PLATFORMS USING NMAKE -*- makefile -*-1
-#
-# $Id$
-# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
-#
-# DESCRIPTION
-#
-# .description: This makefile fragment is included in more specific
-# makefiles for platforms which use the "mv" builder. This is
-# the first of two common makefile fragements (the other is commpost.nmk).
-# Alas, due to shortcomings in nmake, it is not possible to use only one
-# common fragment.
-#
-# %%PART: When adding a new part, add a new parameter for the files included
-# in the part
-# Parameters:
-# PFM platform code, e.g. "w3i3mv"
-# PFMDEFS /D options to define platforms preprocessor symbols
-# to the compiler. Eg "/DOS_NT /DARCH_386 /DBUILD_MVC"
-# MPMCOMMON list of sources which make up the "mpm" part for all
-# platforms. Each source is stripped of its .c extension
-# and surrounded in angle brackets (<>)
-# MPM as above, plus sources for the "mpm" part for the current
-# platform.
-# PLINTH as above for the "plinth" part
-# AMC as above for the "amc" part
-# AMS as above for the "ams" part
-# LO as above for the "lo" part
-# POOLN as above for the "pooln" part
-# SNC as above for the "snc" part
-# DW as above for the "dw" part
-# FMTTEST as above for the "fmttest" part
-# FMTSCHEME as above for the "fmtscheme" part
-# TESTLIB as above for the "testlib" part
-# TESTTHR as above for the "testthr" part
-# NOISY if defined, causes command to be emitted
-#
-#
-# EDITING
-#
-# To add new targets. varieties, and parts:
-# Search for the string "%%TARGET", "%%VARIETY", or "%%PART" in this makefile
-# and follow the instructions.
-#
-
-
-# TARGETS
-#
-#
-# %%TARGET: When adding a new target, add it to one of the variables
-# in this section. Library components go in LIB_TARGETS.
-
-LIB_TARGETS=mps.lib
-
-# Test cases go in TEST_TARGETS.
-
-TEST_TARGETS=\
- abqtest.exe \
- airtest.exe \
- amcss.exe \
- amcsshe.exe \
- amcssth.exe \
- amsss.exe \
- amssshe.exe \
- apss.exe \
- arenacv.exe \
- awlut.exe \
- awluthe.exe \
- awlutth.exe \
- btcv.exe \
- bttest.exe \
- djbench.exe \
- exposet0.exe \
- expt825.exe \
- finalcv.exe \
- finaltest.exe \
- fotest.exe \
- gcbench.exe \
- landtest.exe \
- locbwcss.exe \
- lockcov.exe \
- lockut.exe \
- locusss.exe \
- locv.exe \
- messtest.exe \
- mpmss.exe \
- mpsicv.exe \
- mv2test.exe \
- nailboardtest.exe \
- poolncv.exe \
- qs.exe \
- sacss.exe \
- segsmss.exe \
- steptest.exe \
- teletest.exe \
- walkt0.exe \
- zcoll.exe \
- zmess.exe
-
-# Stand-alone programs go in EXTRA_TARGETS if they should always be
-# built, or in OPTIONAL_TARGETS if they should only be built if
-
-EXTRA_TARGETS=mpseventcnv.exe mpseventtxt.exe
-OPTIONAL_TARGETS=mpseventsql.exe
-
-# This target records programs that we were once able to build but
-# can't at the moment:
-#
-# replay -- depends on the EPVM pool.
-
-UNBUILDABLE_TARGETS=replay.exe
-
-ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS)
-
-
-# PARAMETERS
-#
-#
-# %%PART: When adding a new part, add the sources for the new part here.
-
-MPMCOMMON=\
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
- \
-
-PLINTH =
-AMC =
-AMS =
-AWL =
-LO =
-MVFF =
-POOLN =
-SNC =
-FMTDY =
-FMTTEST =
-FMTSCHEME =
-TESTLIB =
-TESTTHR =
-MPM = $(MPMCOMMON) $(MPMPF) $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(PLINTH)
-
-
-# CHECK PARAMETERS
-#
-#
-# %%PART: When adding a new part, add checks for the parameter with the
-# sources for the new part.
-
-!IFNDEF PFM
-!ERROR commpre.nmk: PFM not defined
-!ENDIF
-!IFNDEF PFMDEFS
-!ERROR commpre.nmk: PFMDEFS not defined
-!ENDIF
-!IFNDEF MPM
-!ERROR commpre.nmk: MPM not defined
-!ENDIF
-!IFNDEF MPMCOMMON
-!ERROR commpre.nmk: MPMCOMMON not defined
-!ENDIF
-!IFNDEF MPMPF
-!ERROR commpre.nmk: MPMPF not defined
-!ENDIF
-!IFNDEF PLINTH
-!ERROR commpre.nmk: PLINTH not defined
-!ENDIF
-!IFNDEF LO
-!ERROR commpre.nmk: LO not defined
-!ENDIF
-!IFNDEF AMC
-!ERROR commpre.nmk: AMC not defined
-!ENDIF
-!IFNDEF AMS
-!ERROR commpre.nmk: AMS not defined
-!ENDIF
-!IFNDEF POOLN
-!ERROR commpre.nmk: POOLN not defined
-!ENDIF
-!IFNDEF SNC
-!ERROR commpre.nmk: SNC not defined
-!ENDIF
-!IFNDEF FMTDY
-!ERROR commpre.nmk: FMTDY not defined
-!ENDIF
-!IFNDEF FMTTEST
-!ERROR commpre.nmk: FMTTEST not defined
-!ENDIF
-!IFNDEF FMTSCHEME
-!ERROR commpre.nmk: FMTSCHEME not defined
-!ENDIF
-!IFNDEF TESTLIB
-!ERROR commpre.nmk: TESTLIB not defined
-!ENDIF
-!IFNDEF TESTTHR
-!ERROR commpre.nmk: TESTTHR not defined
-!ENDIF
-
-
-# DECLARATIONS
-
-
-!IFDEF NOISY
-ECHO = rem
-!ELSE
-.SILENT:
-ECHO = echo
-!ENDIF
-
-
-# C FLAGS
-
-CFLAGSTARGETPRE =
-CFLAGSTARGETPOST =
-CRTFLAGSHOT =
-CRTFLAGSCOOL =
-LINKFLAGSHOT =
-LINKFLAGSCOOL =
-
-CFLAGSSQLPRE = /nologo $(PFMDEFS)
-CFLAGSCOMMONPRE = /nologo $(PFMDEFS) $(CFLAGSTARGETPRE)
-CFLAGSSQLPOST =
-CFLAGSCOMMONPOST = $(CFLAGSTARGETPOST)
-
-# Flags for use in the variety combinations
-CFLAGSHOT = /O2
-# (above /O2 (maximise speed) used to be set to /Ox
-# (maximise optimisations) in for tool versions before VS 9)
-# We used to have /GZ here (stack probe).
-# Note that GZ is specific to version 12 of the cl tool. drj 2003-11-04
-# It is ignored on earlier versions of the cl tool.
-# /GZ here generates a dependency on the C library and when we are
-# building a DLL, mpsdy.dll, the linker step will fail (error LNK2001:
-# unresolved external symbol __chkesp). See
-# http://support.microsoft.com/kb/q191669/
-CFLAGSCOOL =
-CFLAGSINTERNAL = /Zi
-CFLAGSEXTERNAL =
-
-# The combinations of variety
-# %%VARIETY: When adding a new variety, define a macro containing the set
-# of flags for the new variety.
-CFRASH = /DCONFIG_VAR_RASH $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSEXTERNAL)
-CFHOT = /DCONFIG_VAR_HOT $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL)
-CFCOOL = /DCONFIG_VAR_COOL $(CRTFLAGSCOOL) $(CFLAGSCOOL) $(CFLAGSINTERNAL)
-
-# Microsoft documentation is not very clear on the point of using both
-# optimization and debug information
-
-# LINKER FLAGS
-# %%VARIETY: When adding a new variety, define a macro containing the flags
-# for the new variety
-LINKER = link
-LINKFLAGSCOMMON = /nologo /LARGEADDRESSAWARE
-LINKFLAGSINTERNAL = /DEBUG
-# ( Internal flags used to be set to /DEBUG:full )
-LINKFLAGSEXTERNAL = /RELEASE
-
-LFRASH = $(LINKFLAGSHOT) $(LINKFLAGSEXTERNAL)
-LFHOT = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL)
-LFCOOL = $(LINKFLAGSCOOL) $(LINKFLAGSINTERNAL)
-
-#LFCV = /PROFILE /DEBUG:full /DEBUGTYPE:cv
-
-# Library manager
-# %%VARIETY: When adding a new variety, define a macro containing the flags
-# for the new variety
-LIBMAN = lib # can't call this LIB - it screws the environment
-LIBFLAGSCOMMON =
-
-LIBFLAGSRASH =
-LIBFLAGSHOT =
-LIBFLAGSCOOL =
-
-# Browser database manager [not used at present]
-#BSC = bscmake
-#BSCFLAGS = /nologo /n
-
-
-# == Common definitions ==
-# %%PART: When adding a new part, add it here, unless it's platform-specific
-# [It is not possible use a macro, like $(PFM), in a substitution,
-# hence all parts end up being platform-specific.]
-
-
-# C. COPYRIGHT AND LICENSE
-#
-# Copyright (C) 2001-2014 Ravenbrook Limited .
-# All rights reserved. This is an open source license. Contact
-# Ravenbrook for commercial licensing options.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# 3. Redistributions in any form must be accompanied by information on how
-# to obtain complete source code for this software and any accompanying
-# software that uses this software. The source code must either be
-# included in the distribution or be available for no more than the cost
-# of distribution plus a nominal fee, and must be freely redistributable
-# under reasonable conditions. For an executable file, complete source
-# code means the source code for all modules it contains. It does not
-# include source code for modules or files that typically accompany the
-# major components of the operating system on which the executable file
-# runs.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
-# COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/mps/code/config.h b/mps/code/config.h
index 396fbdb5532..8fbd251a220 100644
--- a/mps/code/config.h
+++ b/mps/code/config.h
@@ -427,14 +427,11 @@
#define VM_ARENA_SIZE_DEFAULT ((Size)1 << 28)
-/* Stack configuration */
+/* Stack configuration -- see */
/* Currently StackProbe has a useful implementation only on Windows. */
-#if defined(PLATFORM_ANSI)
-#define StackProbeDEPTH ((Size)0)
-#elif defined(MPS_OS_W3) && defined(MPS_ARCH_I3)
-#define StackProbeDEPTH ((Size)500)
-#elif defined(MPS_OS_W3) && defined(MPS_ARCH_I6)
+#if defined(MPS_OS_W3)
+/* See for a justification of this value. */
#define StackProbeDEPTH ((Size)500)
#else
#define StackProbeDEPTH ((Size)0)
diff --git a/mps/code/dbgpool.c b/mps/code/dbgpool.c
index bef5cbbe991..6a8417595f7 100644
--- a/mps/code/dbgpool.c
+++ b/mps/code/dbgpool.c
@@ -121,7 +121,7 @@ Bool PoolDebugOptionsCheck(PoolDebugOptions opt)
* Someday, this could be split into fence and tag init methods.
*/
-ARG_DEFINE_KEY(pool_debug_options, PoolDebugOptions);
+ARG_DEFINE_KEY(POOL_DEBUG_OPTIONS, PoolDebugOptions);
static PoolDebugOptionsStruct debugPoolOptionsDefault = {
"POST", 4, "DEAD", 4,
@@ -132,7 +132,7 @@ static Res DebugPoolInit(Pool pool, ArgList args)
Res res;
PoolDebugOptions options = &debugPoolOptionsDefault;
PoolDebugMixin debug;
- TagInitMethod tagInit;
+ TagInitFunction tagInit;
Size tagSize;
ArgStruct arg;
@@ -648,19 +648,16 @@ static void DebugPoolFree(Pool pool, Addr old, Size size)
/* TagWalk -- walk all objects in the pool using tags */
-typedef void (*ObjectsStepMethod)(Addr addr, Size size, Format fmt,
- Pool pool, void *tagData, void *p);
+typedef void (*ObjectsVisitor)(Addr addr, Size size, Format fmt,
+ Pool pool, void *tagData, void *p);
-#define ObjectsStepMethodCheck(f) \
- ((f) != NULL) /* that's the best we can do */
-
-static void TagWalk(Pool pool, ObjectsStepMethod step, void *p)
+static void TagWalk(Pool pool, ObjectsVisitor visitor, void *p)
{
Tree node;
PoolDebugMixin debug;
AVERT(Pool, pool);
- AVERT(ObjectsStepMethod, step);
+ AVER(FUNCHECK(visitor));
/* Can't check p */
debug = DebugPoolDebugMixin(pool);
@@ -671,7 +668,7 @@ static void TagWalk(Pool pool, ObjectsStepMethod step, void *p)
while (node != TreeEMPTY) {
Tag tag = TagOfTree(node);
- step(tag->addr, tag->size, NULL, pool, &tag->userdata, p);
+ (*visitor)(tag->addr, tag->size, NULL, pool, &tag->userdata, p);
node = SplayTreeNext(&debug->index, &tag->addr);
}
}
diff --git a/mps/code/dbgpool.h b/mps/code/dbgpool.h
index e00cfe19ab8..e01d8c3b650 100644
--- a/mps/code/dbgpool.h
+++ b/mps/code/dbgpool.h
@@ -3,7 +3,7 @@
* See .
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*/
@@ -15,9 +15,9 @@
#include
-/* tag init methods: copying the user-supplied data into the tag */
+/* tag init function: copies the user-supplied data into the tag */
-typedef void (*TagInitMethod)(void* tag, va_list args);
+typedef void (*TagInitFunction)(void *tag, va_list args);
/* PoolDebugOptions -- option structure for debug pool init
@@ -30,7 +30,7 @@ typedef struct PoolDebugOptionsStruct {
Size fenceSize;
const void *freeTemplate;
Size freeSize;
- /* TagInitMethod tagInit; */
+ /* TagInitFunction tagInit; */
/* Size tagSize; */
} PoolDebugOptionsStruct;
@@ -47,7 +47,7 @@ typedef struct PoolDebugMixinStruct {
Size fenceSize;
const struct AddrStruct *freeTemplate;
Size freeSize;
- TagInitMethod tagInit;
+ TagInitFunction tagInit;
Size tagSize;
Pool tagPool;
Count missingTags;
@@ -73,7 +73,7 @@ extern void DebugPoolFreeCheck(Pool pool, Addr base, Addr limit);
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/djbench.c b/mps/code/djbench.c
index 33cf1d4bdb9..fbc6dcabc1c 100644
--- a/mps/code/djbench.c
+++ b/mps/code/djbench.c
@@ -13,10 +13,15 @@
#include "mps.c"
-#include "getopt.h"
#include "testlib.h"
#include "testthr.h"
+#ifdef MPS_OS_W3
+#include "getopt.h"
+#else
+#include
+#endif
+
#include /* fprintf, stderr */
#include /* alloca, exit, EXIT_SUCCESS, EXIT_FAILURE */
#include /* CLOCKS_PER_SEC, clock */
diff --git a/mps/code/format.c b/mps/code/format.c
index 763682a0a50..07a8319082a 100644
--- a/mps/code/format.c
+++ b/mps/code/format.c
@@ -88,14 +88,14 @@ static mps_addr_t FormatDefaultClass(mps_addr_t object)
/* FormatCreate -- create a format */
-ARG_DEFINE_KEY(fmt_align, Align);
-ARG_DEFINE_KEY(fmt_scan, Fun);
-ARG_DEFINE_KEY(fmt_skip, Fun);
-ARG_DEFINE_KEY(fmt_fwd, Fun);
-ARG_DEFINE_KEY(fmt_isfwd, Fun);
-ARG_DEFINE_KEY(fmt_pad, Fun);
-ARG_DEFINE_KEY(fmt_header_size, Size);
-ARG_DEFINE_KEY(fmt_class, Fun);
+ARG_DEFINE_KEY(FMT_ALIGN, Align);
+ARG_DEFINE_KEY(FMT_SCAN, Fun);
+ARG_DEFINE_KEY(FMT_SKIP, Fun);
+ARG_DEFINE_KEY(FMT_FWD, Fun);
+ARG_DEFINE_KEY(FMT_ISFWD, Fun);
+ARG_DEFINE_KEY(FMT_PAD, Fun);
+ARG_DEFINE_KEY(FMT_HEADER_SIZE, Size);
+ARG_DEFINE_KEY(FMT_CLASS, Fun);
Res FormatCreate(Format *formatReturn, Arena arena, ArgList args)
{
@@ -181,12 +181,11 @@ void FormatDestroy(Format format)
/* FormatArena -- find the arena of a format
*
- * Must be thread-safe. See . */
+ * Must be thread-safe. See . */
Arena FormatArena(Format format)
{
- /* Can't AVER format as that would not be thread-safe */
- /* AVERT(Format, format); */
+ AVER(TESTT(Format, format));
return format->arena;
}
diff --git a/mps/code/freelist.c b/mps/code/freelist.c
index a9e482550f3..6eddc3dff83 100644
--- a/mps/code/freelist.c
+++ b/mps/code/freelist.c
@@ -1,7 +1,7 @@
/* freelist.c: FREE LIST ALLOCATOR IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2013-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2013-2015 Ravenbrook Limited. See end of file for license.
*
* .sources: .
*/
@@ -18,11 +18,11 @@ SRCID(freelist, "$Id$");
typedef union FreelistBlockUnion {
- struct {
+ struct FreelistBlockSmall {
FreelistBlock next; /* tagged with low bit 1 */
/* limit is (char *)this + freelistAlignment(fl) */
} small;
- struct {
+ struct FreelistBlockLarge {
FreelistBlock next; /* not tagged (low bit 0) */
Addr limit;
} large;
@@ -101,6 +101,9 @@ static Bool FreelistBlockCheck(FreelistBlock block)
CHECKL(freelistBlockNext(block) == freelistEND
|| block < freelistBlockNext(block));
CHECKL(freelistBlockIsSmall(block) || (Addr)block < block->large.limit);
+ /* Would like to CHECKL(!freelistBlockIsSmall(block) ||
+ * freelistBlockSize(fl, block) == freelistAlignment(fl)) but we
+ * don't have 'fl' here. This is checked in freelistBlockSetLimit. */
return TRUE;
}
@@ -139,6 +142,7 @@ static void freelistBlockSetLimit(Freelist fl, FreelistBlock block, Addr limit)
} else {
AVER(size >= sizeof(block->small));
block->small.next = freelistTagSet(block->small.next);
+ AVER(freelistBlockSize(fl, block) == freelistAlignment(fl));
}
AVER(freelistBlockLimit(fl, block) == limit);
}
@@ -170,6 +174,9 @@ Bool FreelistCheck(Freelist fl)
CHECKS(Freelist, fl);
land = FreelistLand(fl);
CHECKD(Land, land);
+ CHECKL(AlignCheck(FreelistMinimumAlignment));
+ CHECKL(sizeof(struct FreelistBlockSmall) < sizeof(struct FreelistBlockLarge));
+ CHECKL(sizeof(struct FreelistBlockSmall) <= freelistAlignment(fl));
/* See */
CHECKL(AlignIsAligned(freelistAlignment(fl), FreelistMinimumAlignment));
CHECKL((fl->list == freelistEND) == (fl->listSize == 0));
@@ -236,12 +243,14 @@ static Size freelistSize(Land land)
* Otherwise, if next is freelistEND, make prev the last block in the list.
* Otherwise, make next follow prev in the list.
* Update the count of blocks by 'delta'.
-
+ *
* It is tempting to try to simplify this code by putting a
* FreelistBlockUnion into the FreelistStruct and so avoiding the
* special case on prev. But the problem with that idea is that we
* can't guarantee that such a sentinel would respect the isolated
- * range invariant, and so it would still have to be special-cases.
+ * range invariant (it would have to be at a lower address than the
+ * first block in the free list, which the MPS has no mechanism to
+ * enforce), and so it would still have to be special-cased.
*/
static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev,
@@ -781,6 +790,7 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream, Count depth)
res = WriteF(stream, depth,
"Freelist $P {\n", (WriteFP)fl,
" listSize = $U\n", (WriteFU)fl->listSize,
+ " size = $U\n", (WriteFU)fl->size,
NULL);
b = LandIterate(land, freelistDescribeVisitor, stream, depth + 2);
@@ -815,7 +825,7 @@ DEFINE_LAND_CLASS(FreelistLandClass, class)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2013-2014 Ravenbrook Limited .
+ * Copyright (C) 2013-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/fri3gc.gmk b/mps/code/fri3gc.gmk
index dd7f92d0748..99d455e51fa 100644
--- a/mps/code/fri3gc.gmk
+++ b/mps/code/fri3gc.gmk
@@ -3,33 +3,36 @@
# fri3gc.gmk: BUILD FOR FreeBSD/i386/GCC PLATFORM
#
# $Id$
-# Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license.
+# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
PFM = fri3gc
-MPMPF = lockix.c thix.c pthrdext.c vmix.c \
- protix.c protsgix.c prmcan.c prmci3fr.c ssixi3.c span.c
+MPMPF = \
+ lockix.c \
+ prmcan.c \
+ prmci3fr.c \
+ protix.c \
+ protsgix.c \
+ pthrdext.c \
+ span.c \
+ ssixi3.c \
+ thix.c \
+ vmix.c
LIBS = -lm -pthread
include gc.gmk
-# FIXME: We pun types through the MPS interface, setting off this warning.
-# Can we avoid this? The puns might indeed be dangerous.
-CFLAGSCOMPILER += -Wno-strict-aliasing
-
# For SQLite3.
LINKFLAGS += -L/usr/local/lib
CFLAGSCOMPILER += -I/usr/local/include
-CC = cc
-
include comm.gmk
# C. COPYRIGHT AND LICENSE
#
-# Copyright (C) 2001-2013 Ravenbrook Limited .
+# Copyright (C) 2001-2014 Ravenbrook Limited .
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#
diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c
index 2ae97104930..6d7f3339667 100644
--- a/mps/code/gcbench.c
+++ b/mps/code/gcbench.c
@@ -7,13 +7,18 @@
*/
#include "mps.c"
-#include "getopt.h"
#include "testlib.h"
#include "testthr.h"
#include "fmtdy.h"
#include "fmtdytst.h"
#include "mpm.h"
+#ifdef MPS_OS_W3
+#include "getopt.h"
+#else
+#include
+#endif
+
#include /* fprintf, printf, putchars, sscanf, stderr, stdout */
#include /* alloca, exit, EXIT_FAILURE, EXIT_SUCCESS, strtoul */
#include /* clock, CLOCKS_PER_SEC */
diff --git a/mps/code/global.c b/mps/code/global.c
index efffd564ad4..65948706928 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -153,6 +153,7 @@ Bool GlobalsCheck(Globals arenaGlobals)
}
CHECKD_NOSIG(Ring, &arena->threadRing);
+ CHECKD_NOSIG(Ring, &arena->deadRing);
CHECKL(BoolCheck(arena->insideShield));
CHECKL(arena->shCacheLimit <= ShieldCacheSIZE);
@@ -185,7 +186,7 @@ Bool GlobalsCheck(Globals arenaGlobals)
CHECKL(TraceIdMessagesCheck(arena, ti));
TRACE_SET_ITER_END(ti, trace, TraceSetUNIV, arena);
- for(rank = 0; rank < RankLIMIT; ++rank)
+ for(rank = RankMIN; rank < RankLIMIT; ++rank)
CHECKD_NOSIG(Ring, &arena->greyRing[rank]);
CHECKD_NOSIG(Ring, &arena->chainRing);
@@ -277,6 +278,7 @@ Res GlobalsInit(Globals arenaGlobals)
arenaGlobals->rememberedSummaryIndex = 0;
RingInit(&arena->threadRing);
+ RingInit(&arena->deadRing);
arena->threadSerial = (Serial)0;
RingInit(&arena->formatRing);
arena->formatSerial = (Serial)0;
@@ -308,7 +310,7 @@ Res GlobalsInit(Globals arenaGlobals)
arena->tMessage[ti] = NULL;
}
- for(rank = 0; rank < RankLIMIT; ++rank)
+ for(rank = RankMIN; rank < RankLIMIT; ++rank)
RingInit(&arena->greyRing[rank]);
STATISTIC(arena->writeBarrierHitCount = 0);
RingInit(&arena->chainRing);
@@ -405,7 +407,8 @@ void GlobalsFinish(Globals arenaGlobals)
RingFinish(&arena->chainRing);
RingFinish(&arena->messageRing);
RingFinish(&arena->threadRing);
- for(rank = 0; rank < RankLIMIT; ++rank)
+ RingFinish(&arena->deadRing);
+ for(rank = RankMIN; rank < RankLIMIT; ++rank)
RingFinish(&arena->greyRing[rank]);
RingFinish(&arenaGlobals->rootRing);
RingFinish(&arenaGlobals->poolRing);
@@ -438,7 +441,7 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals)
arenaGlobals->defaultChain = NULL;
ChainDestroy(defaultChain);
- LockReleaseMPM(arenaGlobals->lock);
+ LockRelease(arenaGlobals->lock);
/* Theoretically, another thread could grab the lock here, but it's */
/* not worth worrying about, since an attempt after the lock has been */
/* destroyed would lead to a crash just the same. */
@@ -495,8 +498,9 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals)
AVER(RingIsSingle(&arena->chainRing));
AVER(RingIsSingle(&arena->messageRing));
AVER(RingIsSingle(&arena->threadRing));
+ AVER(RingIsSingle(&arena->deadRing));
AVER(RingIsSingle(&arenaGlobals->rootRing));
- for(rank = 0; rank < RankLIMIT; ++rank)
+ for(rank = RankMIN; rank < RankLIMIT; ++rank)
AVER(RingIsSingle(&arena->greyRing[rank]));
/* At this point the following pools still exist:
@@ -548,7 +552,7 @@ void ArenaEnterLock(Arena arena, Bool recursive)
} else {
LockClaim(lock);
}
- AVERT(Arena, arena); /* can't AVER it until we've got the lock */
+ AVERT(Arena, arena); /* can't AVERT it until we've got the lock */
if(recursive) {
/* already in shield */
} else {
@@ -591,7 +595,7 @@ void ArenaLeaveLock(Arena arena, Bool recursive)
if(recursive) {
LockReleaseRecursive(lock);
} else {
- LockReleaseMPM(lock);
+ LockRelease(lock);
}
return;
}
@@ -653,7 +657,8 @@ Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context)
res = PoolAccess(SegPool(seg), seg, addr, mode, context);
AVER(res == ResOK); /* Mutator can't continue unless this succeeds */
} else {
- /* Protection was already cleared: nothing to do now. */
+ /* Protection was already cleared, for example by another thread
+ or a fault in a nested exception handler: nothing to do now. */
}
EVENT4(ArenaAccess, arena, count, addr, mode);
ArenaLeave(arena);
diff --git a/mps/code/land.c b/mps/code/land.c
index 7dbc7845b5b..18d446288f8 100644
--- a/mps/code/land.c
+++ b/mps/code/land.c
@@ -1,7 +1,7 @@
/* land.c: LAND (COLLECTION OF ADDRESS RANGES) IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2014-2015 Ravenbrook Limited. See end of file for license.
*
* .design:
*/
@@ -282,7 +282,7 @@ Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size
AVER(oldRangeReturn != NULL);
AVERT(Land, land);
AVER(SizeIsAligned(size, land->alignment));
- AVER(FindDeleteCheck(findDelete));
+ AVERT(FindDelete, findDelete);
landEnter(land);
b = (*land->class->findFirst)(rangeReturn, oldRangeReturn, land, size,
@@ -306,7 +306,7 @@ Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size,
AVER(oldRangeReturn != NULL);
AVERT(Land, land);
AVER(SizeIsAligned(size, land->alignment));
- AVER(FindDeleteCheck(findDelete));
+ AVERT(FindDelete, findDelete);
landEnter(land);
b = (*land->class->findLast)(rangeReturn, oldRangeReturn, land, size,
@@ -330,7 +330,7 @@ Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size si
AVER(oldRangeReturn != NULL);
AVERT(Land, land);
AVER(SizeIsAligned(size, land->alignment));
- AVER(FindDeleteCheck(findDelete));
+ AVERT(FindDelete, findDelete);
landEnter(land);
b = (*land->class->findLargest)(rangeReturn, oldRangeReturn, land, size,
@@ -470,7 +470,7 @@ Bool LandClassCheck(LandClass class)
static Res landTrivInit(Land land, ArgList args)
{
AVERT(Land, land);
- AVER(ArgListCheck(args));
+ AVERT(ArgList, args);
UNUSED(args);
return ResOK;
}
@@ -555,7 +555,7 @@ static Bool landNoFind(Range rangeReturn, Range oldRangeReturn, Land land, Size
AVER(oldRangeReturn != NULL);
AVERT(Land, land);
UNUSED(size);
- AVER(FindDeleteCheck(findDelete));
+ AVERT(FindDelete, findDelete);
return ResUNIMPL;
}
@@ -567,7 +567,7 @@ static Res landNoFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRang
AVERT(Land, land);
UNUSED(size);
UNUSED(zoneSet);
- AVER(BoolCheck(high));
+ AVERT(Bool, high);
return ResUNIMPL;
}
@@ -606,7 +606,7 @@ DEFINE_CLASS(LandClass, class)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2014 Ravenbrook Limited .
+ * Copyright (C) 2014-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/landtest.c b/mps/code/landtest.c
index aa561fb3d6d..eb4229f65e8 100644
--- a/mps/code/landtest.c
+++ b/mps/code/landtest.c
@@ -500,7 +500,6 @@ extern int main(int argc, char *argv[])
MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSFastBlockStruct));
MPS_ARGS_ADD(piArgs, MPS_KEY_EXTEND_BY, ArenaGrainSize(arena));
MPS_ARGS_ADD(piArgs, MFSExtendSelf, i);
- MPS_ARGS_DONE(piArgs);
die(PoolInit(mfs, arena, PoolClassMFS(), piArgs), "PoolInit");
} MPS_ARGS_END(piArgs);
diff --git a/mps/code/ld.c b/mps/code/ld.c
index e34479c629b..c9e79f8a762 100644
--- a/mps/code/ld.c
+++ b/mps/code/ld.c
@@ -1,7 +1,7 @@
/* ld.c: LOCATION DEPENDENCY IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
* .def: A location dependency records the fact that the bit-patterns
* of some references will be used directly (most likely for
@@ -92,11 +92,21 @@ void LDReset(mps_ld_t ld, Arena arena)
* occured since the epoch recorded in the dependency. If the location
* were used first only the new location of the reference would end up
* in the set.
+ *
+ * .add.no-arena-check: Add does not check that the address belongs to
+ * the arena because this would require taking the arena lock. We
+ * would rather that this function be lock-free even if some errors
+ * are not detected.
+ *
+ * .add.no-align-check: Add does not check that the address is
+ * aligned, for the same reason as .add.check: it can't find out which
+ * pool the address belongs to without taking the lock.
*/
void LDAdd(mps_ld_t ld, Arena arena, Addr addr)
{
+ AVER(ld != NULL);
+ AVER(TESTT(Arena, arena)); /* see .add.lock-free */
AVER(ld->_epoch <= arena->epoch);
- /* AVERT(Arena, arena) -- see .add.lock-free */
ld->_rs = RefSetAdd(arena, ld->_rs, addr);
}
@@ -126,8 +136,9 @@ Bool LDIsStaleAny(mps_ld_t ld, Arena arena)
{
RefSet rs;
+ AVER(ld != NULL);
+ AVER(TESTT(Arena, arena)); /* .stale.thread-safe */
AVER(ld->_epoch <= arena->epoch);
- /* AVERT(Arena, arena) -- .stale.thread-safe */
if (arena->epoch == ld->_epoch) /* .stale.current */
return FALSE;
@@ -151,6 +162,10 @@ Bool LDIsStaleAny(mps_ld_t ld, Arena arena)
* .stale.conservative: In fact we just ignore the address and test if
* any dependency is stale. This is conservatively correct (no false
* negatives) but provides a hook for future improvement.
+ *
+ * .stale.no-arena-check: See .add.no-arena-check.
+ *
+ * .stale.no-align-check: See .add.no-align-check.
*/
Bool LDIsStale(mps_ld_t ld, Arena arena, Addr addr)
{
@@ -204,8 +219,8 @@ void LDAge(Arena arena, RefSet rs)
*/
void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from)
{
- /* AVERT(Arena, arena); -- .merge.lock-free */
AVER(ld != NULL);
+ AVER(TESTT(Arena, arena)); /* .merge.lock-free */
AVER(ld->_epoch <= arena->epoch);
AVER(from != NULL);
AVER(from->_epoch <= arena->epoch);
@@ -223,7 +238,7 @@ void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2013 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/lii3gc.gmk b/mps/code/lii3gc.gmk
index b205028358a..00be40c673c 100644
--- a/mps/code/lii3gc.gmk
+++ b/mps/code/lii3gc.gmk
@@ -1,30 +1,33 @@
# -*- makefile -*-
#
-# lii3gc.gmk: BUILD FOR LINUX/INTEL/GCC PLATFORM
+# lii3gc.gmk: BUILD FOR LINUX/x86/GCC PLATFORM
#
# $Id$
-# Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
PFM = lii3gc
-THREADSRC = lockli.c thix.c pthrdext.c
-THREADLIB = -lpthread
+MPMPF = \
+ lockli.c \
+ prmci3li.c \
+ proti3.c \
+ protix.c \
+ protli.c \
+ pthrdext.c \
+ span.c \
+ ssixi3.c \
+ thix.c \
+ vmix.c
-MPMPF = ${THREADSRC} vmix.c \
- protix.c protli.c proti3.c prmci3li.c ssixi3.c span.c
-
-LIBS = -lm ${THREADLIB}
+LIBS = -lm -lpthread
include gc.gmk
-
-CC = cc
-
include comm.gmk
# C. COPYRIGHT AND LICENSE
#
-# Copyright (C) 2001-2002 Ravenbrook Limited .
+# Copyright (C) 2001-2014 Ravenbrook Limited .
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#
diff --git a/mps/code/lii6gc.gmk b/mps/code/lii6gc.gmk
index b913578a893..91f8f5d9066 100644
--- a/mps/code/lii6gc.gmk
+++ b/mps/code/lii6gc.gmk
@@ -3,28 +3,31 @@
# lii6gc.gmk: BUILD FOR LINUX/x64/GCC PLATFORM
#
# $Id$
-# Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
PFM = lii6gc
-THREADSRC = lockli.c thix.c pthrdext.c
-THREADLIB = -lpthread
+MPMPF = \
+ lockli.c \
+ prmci6li.c \
+ proti6.c \
+ protix.c \
+ protli.c \
+ pthrdext.c \
+ span.c \
+ ssixi6.c \
+ thix.c \
+ vmix.c
-MPMPF = ${THREADSRC} vmix.c \
- protix.c protli.c proti6.c prmci6li.c ssixi6.c span.c
-
-LIBS = -lm ${THREADLIB}
+LIBS = -lm -lpthread
include gc.gmk
-
-CC = cc
-
include comm.gmk
# C. COPYRIGHT AND LICENSE
#
-# Copyright (C) 2001-2002 Ravenbrook Limited .
+# Copyright (C) 2001-2014 Ravenbrook Limited .
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#
diff --git a/mps/code/lii6ll.gmk b/mps/code/lii6ll.gmk
index 75b298b156e..5988b0c0b17 100644
--- a/mps/code/lii6ll.gmk
+++ b/mps/code/lii6ll.gmk
@@ -3,17 +3,23 @@
# lii6ll.gmk: BUILD FOR LINUX/x64/Clang PLATFORM
#
# $Id$
-# Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license.
+# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
PFM = lii6ll
-THREADSRC = lockli.c thix.c pthrdext.c
-THREADLIB = -lpthread
+MPMPF = \
+ lockli.c \
+ prmci6li.c \
+ proti6.c \
+ protix.c \
+ protli.c \
+ pthrdext.c \
+ span.c \
+ ssixi6.c \
+ thix.c \
+ vmix.c
-MPMPF = ${THREADSRC} vmix.c \
- protix.c protli.c proti6.c prmci6li.c ssixi6.c span.c
-
-LIBS = -lm ${THREADLIB}
+LIBS = -lm -lpthread
include ll.gmk
include comm.gmk
@@ -21,7 +27,7 @@ include comm.gmk
# C. COPYRIGHT AND LICENSE
#
-# Copyright (C) 2001-2013 Ravenbrook Limited .
+# Copyright (C) 2001-2014 Ravenbrook Limited .
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#
diff --git a/mps/code/lock.h b/mps/code/lock.h
index 4fcd591a0f2..35d0ed6db41 100644
--- a/mps/code/lock.h
+++ b/mps/code/lock.h
@@ -1,79 +1,7 @@
/* lock.h: RECURSIVE LOCKS
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
- *
- * .description: [@@@@ Should be combined with ]
- * This defines the type Lock, which supports simple recursive
- * locking. Locking ensures that only a single thread may be running
- * with a lock held. By claiming a lock in some code, this ensures
- * that only one thread can be running in that code at a time. This
- * in turn can be used to protect different threads from trying to
- * read or update data structures which are in a transitional state.
- *
- * At most one thread may own a lock at a time. A lock is initialised
- * without an owner. A lock should not have an owner when it is
- * finished. Claiming the lock will wait until the lock is not owned
- * by another thread and then cause the current thread to become the
- * owner. Releasing the the lock will relinquish ownership if the
- * number of releases matches the number of claims.
- *
- * To use a lock a structure of type LockStruct must be allocated.
- * This is defined in . Sources which allocate such a
- * structure will need to include "lockst.h". A lock of type Lock is
- * a pointer to such an allocated structure.
- *
- * A lock must be Inited before use and should be Finished after use,
- * using LockInit and LockFinish.
- *
- * LockClaimRecursive & LockReleaseRecursive are for claiming and
- * releasing the lock. These may be used recursively.
- *
- * There is a limit on the number of recursive claims which
- * depends on the implementation. See issue.lock-claim-limit.
- *
- * LockClaim and LockReleaseMPM are the same as the Recursive versions,
- * except that LockClaim may only be used by a thread that doesn't
- * already own the lock, and LockReleaseMPM may only be used to release
- * a lock with one claim. LockClaim and LockReleaseMPM if used, must
- * be used symmetrically in pairs.
- *
- * There are two intended uses. Here is an example:
- * #include "lock.h"
- * #include "lockst.h"
- * static LockStruct lockStruct;
- * binaryUse()
- * { ;; lock not owned by this thread.
- * LockClaim(&lockStruct);
- * ;; lock owned by this thread.
- * ;; Cannot call binaryUse() at this point.
- * ;; only one thread at a time may be at this point.
- * LockReleaseMPM(&lockStruct);
- * ;; lock not owned by this thread.
- * }
- *
- * recursiveUse()
- * { ;; lock may already be owned by this thread.
- * LockClaimRecursive(&lockStruct);
- * ;; lock held by this thread.
- * ;; only one thread at a time may be at this point.
- * LockReleaseRecursive(&lockStruct);
- * ;; lock owned by this thread if it was before.
- * }
- * LockInit(&lockStruct) must be called before calling binaryUse()
- * or recursiveUse().
- * LockFinish(&lockStruct) should be called when lock is no longer
- * needed.
- * recursiveUse() may be called by both functions.
- * binaryUse() may only be called where lock is known not to be
- * already owned by this thread. In particular, it may not be
- * called by recursiveUse().
- *
- * LockClaimGlobalRecursive & LockReleaseGlobalRecursive are
- * similar to LockClaimRecursive & LockReleaseRecursive
- * except that they lock an implicit global lock. This may be
- * used for locking access to data structures which are global,
- * such as class objects.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*/
#ifndef lock_h
@@ -129,20 +57,20 @@ extern void LockReleaseRecursive(Lock lock);
* This may only be used when the lock is not already owned by
* the calling thread.
* When used it behaves like LockClaimRecursive, but must be
- * matched by a call to LockReleaseMPM.
+ * matched by a call to LockRelease.
*/
extern void LockClaim(Lock lock);
-/* LockReleaseMPM
+/* LockRelease
*
* This must only be used to release a Lock symmetrically
* with LockClaim. It therefore should only be called with
* a single claim.
*/
-extern void LockReleaseMPM(Lock lock);
+extern void LockRelease(Lock lock);
/* LockCheck -- Validation */
@@ -204,7 +132,7 @@ extern void LockReleaseGlobal(void);
#define LockClaimRecursive(lock) UNUSED(lock)
#define LockReleaseRecursive(lock) UNUSED(lock)
#define LockClaim(lock) UNUSED(lock)
-#define LockReleaseMPM(lock) UNUSED(lock)
+#define LockRelease(lock) UNUSED(lock)
#define LockCheck(lock) ((void)lock, TRUE)
#define LockClaimGlobalRecursive()
#define LockReleaseGlobalRecursive()
@@ -220,7 +148,7 @@ extern void LockReleaseGlobal(void);
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/lockan.c b/mps/code/lockan.c
index f720e22755d..fe5082a6ebf 100644
--- a/mps/code/lockan.c
+++ b/mps/code/lockan.c
@@ -1,7 +1,7 @@
/* lockan.c: ANSI RECURSIVE LOCKS
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* .purpose: This is a trivial implementation of recursive locks
* that assumes we are not running in a multi-threaded environment.
@@ -58,7 +58,7 @@ void (LockClaim)(Lock lock)
lock->claims = 1;
}
-void (LockReleaseMPM)(Lock lock)
+void (LockRelease)(Lock lock)
{
AVERT(Lock, lock);
AVER(lock->claims == 1);
@@ -118,13 +118,13 @@ void (LockClaimGlobal)(void)
void (LockReleaseGlobal)(void)
{
- LockReleaseMPM(globalLock);
+ LockRelease(globalLock);
}
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/lockcov.c b/mps/code/lockcov.c
index 75ded6f202a..84866046d82 100644
--- a/mps/code/lockcov.c
+++ b/mps/code/lockcov.c
@@ -46,7 +46,7 @@ int main(int argc, char *argv[])
LockClaimGlobalRecursive();
LockReleaseGlobal();
LockClaimGlobal();
- LockReleaseMPM(a);
+ LockRelease(a);
LockClaimGlobalRecursive();
LockReleaseGlobal();
LockClaimRecursive(b);
@@ -59,7 +59,7 @@ int main(int argc, char *argv[])
LockClaimRecursive(a);
LockReleaseGlobalRecursive();
LockReleaseRecursive(a);
- LockReleaseMPM(a);
+ LockRelease(a);
LockFinish(a);
LockReleaseGlobalRecursive();
diff --git a/mps/code/lockix.c b/mps/code/lockix.c
index 2afd294246e..c982bf0cb17 100644
--- a/mps/code/lockix.c
+++ b/mps/code/lockix.c
@@ -1,7 +1,7 @@
/* lockix.c: RECURSIVE LOCKS FOR POSIX SYSTEMS
*
* $Id$
- * Copyright (c) 2001,2007 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* .posix: The implementation uses a POSIX interface, and should be reusable
* for many Unix-like operating systems.
@@ -131,9 +131,9 @@ void (LockClaim)(Lock lock)
}
-/* LockReleaseMPM -- release a lock (non-recursive) */
+/* LockRelease -- release a lock (non-recursive) */
-void (LockReleaseMPM)(Lock lock)
+void (LockRelease)(Lock lock)
{
int res;
@@ -239,13 +239,13 @@ void (LockClaimGlobal)(void)
void (LockReleaseGlobal)(void)
{
- LockReleaseMPM(globalLock);
+ LockRelease(globalLock);
}
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/lockli.c b/mps/code/lockli.c
index 89e8f4f0653..0dc98fb8a25 100644
--- a/mps/code/lockli.c
+++ b/mps/code/lockli.c
@@ -1,7 +1,7 @@
/* lockli.c: RECURSIVE LOCKS FOR POSIX SYSTEMS
*
* $Id$
- * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* .linux: This implementation currently just supports LinuxThreads
* (platform MPS_OS_LI), Single Unix i/f.
@@ -145,9 +145,9 @@ void (LockClaim)(Lock lock)
}
-/* LockReleaseMPM -- release a lock (non-recursive) */
+/* LockRelease -- release a lock (non-recursive) */
-void (LockReleaseMPM)(Lock lock)
+void (LockRelease)(Lock lock)
{
int res;
@@ -253,13 +253,13 @@ void (LockClaimGlobal)(void)
void (LockReleaseGlobal)(void)
{
- LockReleaseMPM(globalLock);
+ LockRelease(globalLock);
}
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2013 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/lockut.c b/mps/code/lockut.c
index e93bdea6815..a6e592988f1 100644
--- a/mps/code/lockut.c
+++ b/mps/code/lockut.c
@@ -49,7 +49,7 @@ static void inc(unsigned long i)
tmp = shared;
shared = tmp+1;
i--;
- LockReleaseMPM(lock);
+ LockRelease(lock);
}
}
diff --git a/mps/code/lockw3.c b/mps/code/lockw3.c
index 2fdc2800032..53da970aed2 100644
--- a/mps/code/lockw3.c
+++ b/mps/code/lockw3.c
@@ -1,7 +1,7 @@
/* lockw3.c: RECURSIVE LOCKS IN WIN32
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* .design: These are implemented using critical sections.
* See the section titled "Synchronization functions" in the Groups
@@ -79,7 +79,7 @@ void (LockClaim)(Lock lock)
lock->claims = 1;
}
-void (LockReleaseMPM)(Lock lock)
+void (LockRelease)(Lock lock)
{
AVERT(Lock, lock);
AVER(lock->claims == 1); /* The lock should only be held once */
@@ -152,13 +152,13 @@ void (LockClaimGlobal)(void)
void (LockReleaseGlobal)(void)
{
AVER(globalLockInit);
- LockReleaseMPM(globalLock);
+ LockRelease(globalLock);
}
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/locus.c b/mps/code/locus.c
index 0c5bacb86b5..d6df60633cb 100644
--- a/mps/code/locus.c
+++ b/mps/code/locus.c
@@ -56,17 +56,17 @@ void LocusPrefExpress(LocusPref pref, LocusPrefKind kind, void *p)
AVER(pref != &locusPrefDefault);
switch(kind) {
- case LocusPrefHigh:
+ case LocusPrefHIGH:
AVER(p == NULL);
pref->high = TRUE;
break;
- case LocusPrefLow:
+ case LocusPrefLOW:
AVER(p == NULL);
pref->high = FALSE;
break;
- case LocusPrefZoneSet:
+ case LocusPrefZONESET:
AVER(p != NULL);
pref->zones = *(ZoneSet *)p;
break;
diff --git a/mps/code/mpm.c b/mps/code/mpm.c
index 97b752be498..aba1ac2f5cb 100644
--- a/mps/code/mpm.c
+++ b/mps/code/mpm.c
@@ -1,7 +1,7 @@
/* mpm.c: GENERAL MPM SUPPORT
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
* .purpose: Miscellaneous support for the implementation of the MPM
* and pool classes.
@@ -84,7 +84,11 @@ Bool MPMCheck(void)
* arena grain). */
CHECKL(PageSize() % ProtGranularity() == 0);
- return TRUE;
+ /* StackProbe mustn't skip over the stack guard page. See
+ * . */
+ CHECKL(StackProbeDEPTH * sizeof(Word) < PageSize());
+
+ return TRUE;
}
@@ -133,6 +137,16 @@ Bool AlignCheck(Align align)
}
+/* AccessSetCheck -- check that an access set is valid */
+
+Bool AccessSetCheck(AccessSet mode)
+{
+ CHECKL(mode < ((ULongest)1 << AccessLIMIT));
+ UNUSED(mode); /* see .check.unused */
+ return TRUE;
+}
+
+
#endif /* defined(AVER_AND_CHECK) */
@@ -634,7 +648,7 @@ Bool StringEqual(const char *s1, const char *s2)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index f1ed6812886..af2cde97ff1 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -1,7 +1,7 @@
/* mpm.h: MEMORY POOL MANAGER DEFINITIONS
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
* .trans.bufferinit: The Buffer data structure has an Init field and
@@ -18,6 +18,8 @@
#include "event.h"
#include "lock.h"
+#include "prot.h"
+#include "sp.h"
#include "th.h"
#include "ss.h"
#include "mpslib.h"
@@ -44,6 +46,7 @@ extern Bool FunCheck(Fun f);
extern Bool ShiftCheck(Shift shift);
extern Bool AttrCheck(Attr attr);
extern Bool RootVarCheck(RootVar rootVar);
+extern Bool AccessSetCheck(AccessSet mode);
/* Address/Size Interface -- see */
@@ -222,9 +225,9 @@ extern Res PoolFixEmergency(Pool pool, ScanState ss, Seg seg, Addr *refIO);
extern void PoolReclaim(Pool pool, Trace trace, Seg seg);
extern void PoolTraceEnd(Pool pool, Trace trace);
extern Res PoolAddrObject(Addr *pReturn, Pool pool, Seg seg, Addr addr);
-extern void PoolWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f,
+extern void PoolWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
void *v, size_t s);
-extern void PoolFreeWalk(Pool pool, FreeBlockStepMethod f, void *p);
+extern void PoolFreeWalk(Pool pool, FreeBlockVisitor f, void *p);
extern Size PoolTotalSize(Pool pool);
extern Size PoolFreeSize(Pool pool);
@@ -276,9 +279,9 @@ extern Res PoolTrivFramePop(Pool pool, Buffer buf, AllocFrame frame);
extern void PoolNoFramePopPending(Pool pool, Buffer buf, AllocFrame frame);
extern void PoolTrivFramePopPending(Pool pool, Buffer buf, AllocFrame frame);
extern Res PoolNoAddrObject(Addr *pReturn, Pool pool, Seg seg, Addr addr);
-extern void PoolNoWalk(Pool pool, Seg seg, FormattedObjectsStepMethod step,
+extern void PoolNoWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
void *p, size_t s);
-extern void PoolTrivFreeWalk(Pool pool, FreeBlockStepMethod f, void *p);
+extern void PoolTrivFreeWalk(Pool pool, FreeBlockVisitor f, void *p);
extern PoolDebugMixin PoolNoDebugMixin(Pool pool);
extern BufferClass PoolNoBufferClass(void);
extern Size PoolNoSize(Pool pool);
@@ -518,6 +521,7 @@ extern Ring GlobalsRememberedSummaryRing(Globals);
#define GlobalsArena(glob) PARENT(ArenaStruct, globals, glob)
#define ArenaThreadRing(arena) (&(arena)->threadRing)
+#define ArenaDeadRing(arena) (&(arena)->deadRing)
#define ArenaEpoch(arena) ((arena)->epoch) /* .epoch.ts */
#define ArenaTrace(arena, ti) (&(arena)->trace[ti])
#define ArenaZoneShift(arena) ((arena)->zoneShift)
@@ -559,13 +563,14 @@ extern Bool (ArenaStep)(Globals globals, double interval, double multiplier);
extern void ArenaClamp(Globals globals);
extern void ArenaRelease(Globals globals);
extern void ArenaPark(Globals globals);
-extern void ArenaExposeRemember(Globals globals, int remember);
+extern void ArenaExposeRemember(Globals globals, Bool remember);
extern void ArenaRestoreProtection(Globals globals);
extern Res ArenaStartCollect(Globals globals, int why);
extern Res ArenaCollect(Globals globals, int why);
extern Bool ArenaHasAddr(Arena arena, Addr addr);
extern Res ArenaAddrObject(Addr *pReturn, Arena arena, Addr addr);
extern void ArenaChunkInsert(Arena arena, Chunk chunk);
+extern void ArenaChunkRemoved(Arena arena, Chunk chunk);
extern void ArenaSetEmergency(Arena arena, Bool emergency);
extern Bool ArenaEmergency(Arena arean);
@@ -931,30 +936,6 @@ extern void (ShieldFlush)(Arena arena);
#endif /* SHIELD */
-/* Protection Interface
- *
- * See for the design of the generic interface including
- * the contracts for these functions.
- *
- * This interface has several different implementations, typically one
- * per platform, see * for the various implementations, and
- * * for the corresponding designs. */
-
-extern void ProtSetup(void);
-
-extern Size ProtGranularity(void);
-extern void ProtSet(Addr base, Addr limit, AccessSet mode);
-extern void ProtSync(Arena arena);
-extern Bool ProtCanStepInstruction(MutatorFaultContext context);
-extern Res ProtStepInstruction(MutatorFaultContext context);
-
-
-/* Mutator Fault Context */
-
-extern Addr MutatorFaultContextSP(MutatorFaultContext mfc);
-extern Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc);
-
-
/* Location Dependency -- see */
extern void LDReset(mps_ld_t ld, Arena arena);
@@ -1033,11 +1014,6 @@ extern LandClass LandClassGet(void);
IsSubclassPoly((land)->class, className ## Get())
-/* Stack Probe */
-
-extern void StackProbe(Size depth);
-
-
/* STATISTIC -- gather statistics (in some varieties)
*
* The argument of STATISTIC is an expression; the expansion followed by
@@ -1078,7 +1054,7 @@ extern void StackProbe(Size depth);
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/mpmss.c b/mps/code/mpmss.c
index f4688cb5a81..2c746b7e34d 100644
--- a/mps/code/mpmss.c
+++ b/mps/code/mpmss.c
@@ -172,6 +172,7 @@ static void testInArena(mps_arena_class_t arena_class, mps_arg_s *arena_args,
MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE);
MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE);
MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE);
+ MPS_ARGS_ADD(args, MPS_KEY_SPARE, rnd_double());
die(stress(arena, NULL, randomSize8, align, "MVFF",
mps_class_mvff(), args), "stress MVFF");
} MPS_ARGS_END(args);
@@ -182,6 +183,7 @@ static void testInArena(mps_arena_class_t arena_class, mps_arg_s *arena_args,
MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE);
MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE);
MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE);
+ MPS_ARGS_ADD(args, MPS_KEY_SPARE, rnd_double());
MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options);
die(stress(arena, options, randomSize8, align, "MVFF debug",
mps_class_mvff_debug(), args), "stress MVFF debug");
diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h
index ac59492bea5..a798cc71fc4 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -111,10 +111,6 @@ typedef struct mps_pool_s { /* generic structure */
Align alignment; /* alignment for units */
Format format; /* format only if class->attr&AttrFMT */
PoolFixMethod fix; /* fix method */
- double fillMutatorSize; /* bytes filled, mutator buffers */
- double emptyMutatorSize; /* bytes emptied, mutator buffers */
- double fillInternalSize; /* bytes filled, internal buffers */
- double emptyInternalSize; /* bytes emptied, internal buffers */
} PoolStruct;
@@ -530,7 +526,6 @@ typedef struct mps_arena_class_s {
ArenaVarargsMethod varargs;
ArenaInitMethod init;
ArenaFinishMethod finish;
- ArenaReservedMethod reserved;
ArenaPurgeSpareMethod purgeSpare;
ArenaExtendMethod extend;
ArenaGrowMethod grow;
@@ -718,7 +713,8 @@ typedef struct mps_arena_s {
ReservoirStruct reservoirStruct; /* */
- Size committed; /* amount of committed RAM */
+ Size reserved; /* total reserved address space */
+ Size committed; /* total committed memory */
Size commitLimit; /* client-configurable commit limit */
Size spareCommitted; /* Amount of memory in hysteresis fund */
@@ -759,6 +755,7 @@ typedef struct mps_arena_s {
/* thread fields () */
RingStruct threadRing; /* ring of attached threads */
+ RingStruct deadRing; /* ring of dead threads */
Serial threadSerial; /* serial of next thread */
/* shield fields () */
diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h
index 4c0b6bd9c87..a6030e4c1e5 100644
--- a/mps/code/mpmtypes.h
+++ b/mps/code/mpmtypes.h
@@ -120,7 +120,6 @@ typedef void (*ArenaVarargsMethod)(ArgStruct args[], va_list varargs);
typedef Res (*ArenaInitMethod)(Arena *arenaReturn,
ArenaClass class, ArgList args);
typedef void (*ArenaFinishMethod)(Arena arena);
-typedef Size (*ArenaReservedMethod)(Arena arena);
typedef Size (*ArenaPurgeSpareMethod)(Arena arena, Size size);
typedef Res (*ArenaExtendMethod)(Arena arena, Addr base, Size size);
typedef Res (*ArenaGrowMethod)(Arena arena, LocusPref pref, Size size);
@@ -148,11 +147,11 @@ typedef Res (*TraceFixMethod)(ScanState ss, Ref *refIO);
/* Heap Walker */
/* This type is used by the PoolClass method Walk */
-typedef void (*FormattedObjectsStepMethod)(Addr obj, Format fmt, Pool pool,
+typedef void (*FormattedObjectsVisitor)(Addr obj, Format fmt, Pool pool,
void *v, size_t s);
/* This type is used by the PoolClass method Walk */
-typedef void (*FreeBlockStepMethod)(Addr base, Addr limit, Pool pool, void *p);
+typedef void (*FreeBlockVisitor)(Addr base, Addr limit, Pool pool, void *p);
/* Seg*Method -- see */
@@ -230,10 +229,9 @@ typedef void (*PoolFramePopPendingMethod)(Pool pool, Buffer buf,
AllocFrame frame);
typedef Res (*PoolAddrObjectMethod)(Addr *pReturn,
Pool pool, Seg seg, Addr addr);
-typedef void (*PoolWalkMethod)(Pool pool, Seg seg,
- FormattedObjectsStepMethod f,
+typedef void (*PoolWalkMethod)(Pool pool, Seg seg, FormattedObjectsVisitor f,
void *v, size_t s);
-typedef void (*PoolFreeWalkMethod)(Pool pool, FreeBlockStepMethod f, void *p);
+typedef void (*PoolFreeWalkMethod)(Pool pool, FreeBlockVisitor f, void *p);
typedef BufferClass (*PoolBufferClassMethod)(void);
typedef Res (*PoolDescribeMethod)(Pool pool, mps_lib_FILE *stream, Count depth);
typedef PoolDebugMixin (*PoolDebugMixinMethod)(Pool pool);
@@ -308,9 +306,9 @@ typedef Res (*LandDescribeMethod)(Land land, mps_lib_FILE *stream, Count depth);
/* Locus preferences */
enum {
- LocusPrefHigh = 1,
- LocusPrefLow,
- LocusPrefZoneSet,
+ LocusPrefHIGH = 1,
+ LocusPrefLOW,
+ LocusPrefZONESET,
LocusPrefLIMIT
};
@@ -335,6 +333,7 @@ enum {
/* This is checked by . */
enum {
+ RankMIN = 0,
RankAMBIG = 0,
RankEXACT = 1,
RankFINAL = 2,
diff --git a/mps/code/mps.c b/mps/code/mps.c
index d31a1f60a0a..95919d9680c 100644
--- a/mps/code/mps.c
+++ b/mps/code/mps.c
@@ -214,7 +214,6 @@
#include "mpsiw3.c" /* Windows interface layer extras */
/* Windows on 64-bit Intel with Microsoft Visual Studio */
-/* ssw3i6.asm is also required, but can't be included here */
#elif defined(MPS_PF_W3I6MV)
diff --git a/mps/code/mps.h b/mps/code/mps.h
index 78f46640f49..4e75d49b73a 100644
--- a/mps/code/mps.h
+++ b/mps/code/mps.h
@@ -151,84 +151,84 @@ typedef struct mps_arg_s {
} val;
} mps_arg_s;
-extern const struct mps_key_s _mps_key_args_end;
-#define MPS_KEY_ARGS_END (&_mps_key_args_end)
+extern const struct mps_key_s _mps_key_ARGS_END;
+#define MPS_KEY_ARGS_END (&_mps_key_ARGS_END)
extern mps_arg_s mps_args_none[];
-extern const struct mps_key_s _mps_key_arena_size;
-#define MPS_KEY_ARENA_SIZE (&_mps_key_arena_size)
+extern const struct mps_key_s _mps_key_ARENA_SIZE;
+#define MPS_KEY_ARENA_SIZE (&_mps_key_ARENA_SIZE)
#define MPS_KEY_ARENA_SIZE_FIELD size
-extern const struct mps_key_s _mps_key_arena_grain_size;
-#define MPS_KEY_ARENA_GRAIN_SIZE (&_mps_key_arena_grain_size)
+extern const struct mps_key_s _mps_key_ARENA_GRAIN_SIZE;
+#define MPS_KEY_ARENA_GRAIN_SIZE (&_mps_key_ARENA_GRAIN_SIZE)
#define MPS_KEY_ARENA_GRAIN_SIZE_FIELD size
-extern const struct mps_key_s _mps_key_arena_zoned;
-#define MPS_KEY_ARENA_ZONED (&_mps_key_arena_zoned)
+extern const struct mps_key_s _mps_key_ARENA_ZONED;
+#define MPS_KEY_ARENA_ZONED (&_mps_key_ARENA_ZONED)
#define MPS_KEY_ARENA_ZONED_FIELD b
-extern const struct mps_key_s _mps_key_format;
-#define MPS_KEY_FORMAT (&_mps_key_format)
+extern const struct mps_key_s _mps_key_FORMAT;
+#define MPS_KEY_FORMAT (&_mps_key_FORMAT)
#define MPS_KEY_FORMAT_FIELD format
-extern const struct mps_key_s _mps_key_chain;
-#define MPS_KEY_CHAIN (&_mps_key_chain)
+extern const struct mps_key_s _mps_key_CHAIN;
+#define MPS_KEY_CHAIN (&_mps_key_CHAIN)
#define MPS_KEY_CHAIN_FIELD chain
-extern const struct mps_key_s _mps_key_gen;
-#define MPS_KEY_GEN (&_mps_key_gen)
+extern const struct mps_key_s _mps_key_GEN;
+#define MPS_KEY_GEN (&_mps_key_GEN)
#define MPS_KEY_GEN_FIELD u
-extern const struct mps_key_s _mps_key_rank;
-#define MPS_KEY_RANK (&_mps_key_rank)
+extern const struct mps_key_s _mps_key_RANK;
+#define MPS_KEY_RANK (&_mps_key_RANK)
#define MPS_KEY_RANK_FIELD rank
-extern const struct mps_key_s _mps_key_extend_by;
-#define MPS_KEY_EXTEND_BY (&_mps_key_extend_by)
+extern const struct mps_key_s _mps_key_EXTEND_BY;
+#define MPS_KEY_EXTEND_BY (&_mps_key_EXTEND_BY)
#define MPS_KEY_EXTEND_BY_FIELD size
-extern const struct mps_key_s _mps_key_large_size;
-#define MPS_KEY_LARGE_SIZE (&_mps_key_large_size)
+extern const struct mps_key_s _mps_key_LARGE_SIZE;
+#define MPS_KEY_LARGE_SIZE (&_mps_key_LARGE_SIZE)
#define MPS_KEY_LARGE_SIZE_FIELD size
-extern const struct mps_key_s _mps_key_min_size;
-#define MPS_KEY_MIN_SIZE (&_mps_key_min_size)
+extern const struct mps_key_s _mps_key_MIN_SIZE;
+#define MPS_KEY_MIN_SIZE (&_mps_key_MIN_SIZE)
#define MPS_KEY_MIN_SIZE_FIELD size
-extern const struct mps_key_s _mps_key_mean_size;
-#define MPS_KEY_MEAN_SIZE (&_mps_key_mean_size)
+extern const struct mps_key_s _mps_key_MEAN_SIZE;
+#define MPS_KEY_MEAN_SIZE (&_mps_key_MEAN_SIZE)
#define MPS_KEY_MEAN_SIZE_FIELD size
-extern const struct mps_key_s _mps_key_max_size;
-#define MPS_KEY_MAX_SIZE (&_mps_key_max_size)
+extern const struct mps_key_s _mps_key_MAX_SIZE;
+#define MPS_KEY_MAX_SIZE (&_mps_key_MAX_SIZE)
#define MPS_KEY_MAX_SIZE_FIELD size
-extern const struct mps_key_s _mps_key_align;
-#define MPS_KEY_ALIGN (&_mps_key_align)
+extern const struct mps_key_s _mps_key_ALIGN;
+#define MPS_KEY_ALIGN (&_mps_key_ALIGN)
#define MPS_KEY_ALIGN_FIELD align
-extern const struct mps_key_s _mps_key_spare;
-#define MPS_KEY_SPARE (&_mps_key_spare)
-#define MPS_KEY_SPARE_FIELD double
-extern const struct mps_key_s _mps_key_interior;
-#define MPS_KEY_INTERIOR (&_mps_key_interior)
+extern const struct mps_key_s _mps_key_SPARE;
+#define MPS_KEY_SPARE (&_mps_key_SPARE)
+#define MPS_KEY_SPARE_FIELD d
+extern const struct mps_key_s _mps_key_INTERIOR;
+#define MPS_KEY_INTERIOR (&_mps_key_INTERIOR)
#define MPS_KEY_INTERIOR_FIELD b
-extern const struct mps_key_s _mps_key_vmw3_top_down;
-#define MPS_KEY_VMW3_TOP_DOWN (&_mps_key_vmw3_top_down)
+extern const struct mps_key_s _mps_key_VMW3_TOP_DOWN;
+#define MPS_KEY_VMW3_TOP_DOWN (&_mps_key_VMW3_TOP_DOWN)
#define MPS_KEY_VMW3_TOP_DOWN_FIELD b
-extern const struct mps_key_s _mps_key_fmt_align;
-#define MPS_KEY_FMT_ALIGN (&_mps_key_fmt_align)
+extern const struct mps_key_s _mps_key_FMT_ALIGN;
+#define MPS_KEY_FMT_ALIGN (&_mps_key_FMT_ALIGN)
#define MPS_KEY_FMT_ALIGN_FIELD align
-extern const struct mps_key_s _mps_key_fmt_header_size;
-#define MPS_KEY_FMT_HEADER_SIZE (&_mps_key_fmt_header_size)
+extern const struct mps_key_s _mps_key_FMT_HEADER_SIZE;
+#define MPS_KEY_FMT_HEADER_SIZE (&_mps_key_FMT_HEADER_SIZE)
#define MPS_KEY_FMT_HEADER_SIZE_FIELD size
-extern const struct mps_key_s _mps_key_fmt_scan;
-#define MPS_KEY_FMT_SCAN (&_mps_key_fmt_scan)
+extern const struct mps_key_s _mps_key_FMT_SCAN;
+#define MPS_KEY_FMT_SCAN (&_mps_key_FMT_SCAN)
#define MPS_KEY_FMT_SCAN_FIELD fmt_scan
-extern const struct mps_key_s _mps_key_fmt_skip;
-#define MPS_KEY_FMT_SKIP (&_mps_key_fmt_skip)
+extern const struct mps_key_s _mps_key_FMT_SKIP;
+#define MPS_KEY_FMT_SKIP (&_mps_key_FMT_SKIP)
#define MPS_KEY_FMT_SKIP_FIELD fmt_skip
-extern const struct mps_key_s _mps_key_fmt_fwd;
-#define MPS_KEY_FMT_FWD (&_mps_key_fmt_fwd)
+extern const struct mps_key_s _mps_key_FMT_FWD;
+#define MPS_KEY_FMT_FWD (&_mps_key_FMT_FWD)
#define MPS_KEY_FMT_FWD_FIELD fmt_fwd
-extern const struct mps_key_s _mps_key_fmt_isfwd;
-#define MPS_KEY_FMT_ISFWD (&_mps_key_fmt_isfwd)
+extern const struct mps_key_s _mps_key_FMT_ISFWD;
+#define MPS_KEY_FMT_ISFWD (&_mps_key_FMT_ISFWD)
#define MPS_KEY_FMT_ISFWD_FIELD fmt_isfwd
-extern const struct mps_key_s _mps_key_fmt_pad;
-#define MPS_KEY_FMT_PAD (&_mps_key_fmt_pad)
+extern const struct mps_key_s _mps_key_FMT_PAD;
+#define MPS_KEY_FMT_PAD (&_mps_key_FMT_PAD)
#define MPS_KEY_FMT_PAD_FIELD fmt_pad
-extern const struct mps_key_s _mps_key_fmt_class;
-#define MPS_KEY_FMT_CLASS (&_mps_key_fmt_class)
+extern const struct mps_key_s _mps_key_FMT_CLASS;
+#define MPS_KEY_FMT_CLASS (&_mps_key_FMT_CLASS)
#define MPS_KEY_FMT_CLASS_FIELD fmt_class
/* Maximum length of a keyword argument list. */
@@ -294,12 +294,12 @@ extern mps_rank_t mps_rank_weak(void);
/* Root Modes */
/* .rm: Keep in sync with */
-#define MPS_RM_CONST (((mps_rm_t)1<<0))
-#define MPS_RM_PROT (((mps_rm_t)1<<1))
+#define MPS_RM_CONST (((mps_rm_t)1<<0))
+#define MPS_RM_PROT (((mps_rm_t)1<<1))
+#define MPS_RM_PROT_INNER (((mps_rm_t)1<<1))
/* Allocation Point */
-/* .ap: Keep in sync with . */
typedef struct mps_ap_s { /* allocation point descriptor */
mps_addr_t init; /* limit of initialized memory */
@@ -775,8 +775,8 @@ typedef struct mps_pool_debug_option_s {
size_t free_size;
} mps_pool_debug_option_s;
-extern const struct mps_key_s _mps_key_pool_debug_options;
-#define MPS_KEY_POOL_DEBUG_OPTIONS (&_mps_key_pool_debug_options)
+extern const struct mps_key_s _mps_key_POOL_DEBUG_OPTIONS;
+#define MPS_KEY_POOL_DEBUG_OPTIONS (&_mps_key_POOL_DEBUG_OPTIONS)
#define MPS_KEY_POOL_DEBUG_OPTIONS_FIELD pool_debug_options
extern void mps_pool_check_fenceposts(mps_pool_t);
diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj
index c83a1026d6e..30aad557d3b 100644
--- a/mps/code/mps.xcodeproj/project.pbxproj
+++ b/mps/code/mps.xcodeproj/project.pbxproj
@@ -43,16 +43,16 @@
name = testall;
productName = testrun;
};
- 2215A9C1192A47D500E9E2CE /* testpoll */ = {
+ 2215A9C1192A47D500E9E2CE /* testpollnone */ = {
isa = PBXAggregateTarget;
- buildConfigurationList = 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpoll" */;
+ buildConfigurationList = 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpollnone" */;
buildPhases = (
2215A9C4192A47D500E9E2CE /* ShellScript */,
);
dependencies = (
2215A9C2192A47D500E9E2CE /* PBXTargetDependency */,
);
- name = testpoll;
+ name = testpollnone;
productName = testrun;
};
22CDE8EF16E9E97D00366D0A /* testrun */ = {
@@ -285,7 +285,6 @@
3124CAFB156BE82000753214 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
3124CAFC156BE82900753214 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
3150AE53156ABA2500A6E22A /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
- 318DA8D21892B13B0089718C /* getoptl.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8D11892B13B0089718C /* getoptl.c */; };
318DA8D31892B27E0089718C /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
31A47BA4156C1E130039B1C2 /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; };
31D60007156D3C6200337B26 /* segsmss.c in Sources */ = {isa = PBXBuildFile; fileRef = 31D60006156D3C5F00337B26 /* segsmss.c */; };
@@ -327,7 +326,6 @@
31FCAE161769244F008C034C /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; };
31FCAE19176924D4008C034C /* scheme.c in Sources */ = {isa = PBXBuildFile; fileRef = 31FCAE18176924D4008C034C /* scheme.c */; };
6313D46918A400B200EB03EF /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
- 6313D46A18A400B200EB03EF /* getoptl.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8D11892B13B0089718C /* getoptl.c */; };
6313D47318A4028E00EB03EF /* djbench.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8CE1892B1210089718C /* djbench.c */; };
6313D47418A4029200EB03EF /* gcbench.c in Sources */ = {isa = PBXBuildFile; fileRef = 6313D46618A3FDC900EB03EF /* gcbench.c */; };
6313D47518A40C6300EB03EF /* fmtdytst.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAC7156BE48D00753214 /* fmtdytst.c */; };
@@ -1635,8 +1633,6 @@
317B3C2A1731830100F9A469 /* arg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arg.c; sourceTree = ""; };
318DA8CD1892B0F30089718C /* djbench */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = djbench; sourceTree = BUILT_PRODUCTS_DIR; };
318DA8CE1892B1210089718C /* djbench.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = djbench.c; sourceTree = ""; };
- 318DA8D01892B13B0089718C /* getopt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = getopt.h; sourceTree = ""; };
- 318DA8D11892B13B0089718C /* getoptl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = getoptl.c; sourceTree = ""; };
31A47BA3156C1E130039B1C2 /* mps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mps.c; sourceTree = ""; };
31A47BA5156C1E5E0039B1C2 /* ssixi3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ssixi3.c; sourceTree = ""; };
31C83ADD1786281C0031A0DB /* protxc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = protxc.h; sourceTree = ""; };
@@ -2267,8 +2263,6 @@
318DA8C21892B0B20089718C /* Benchmarks */ = {
isa = PBXGroup;
children = (
- 318DA8D01892B13B0089718C /* getopt.h */,
- 318DA8D11892B13B0089718C /* getoptl.c */,
318DA8CE1892B1210089718C /* djbench.c */,
6313D46618A3FDC900EB03EF /* gcbench.c */,
);
@@ -3403,7 +3397,7 @@
2215A9B9192A47CE00E9E2CE /* testall */,
2215A9B1192A47C500E9E2CE /* testansi */,
2215A9A9192A47BB00E9E2CE /* testci */,
- 2215A9C1192A47D500E9E2CE /* testpoll */,
+ 2215A9C1192A47D500E9E2CE /* testpollnone */,
22CDE8EF16E9E97D00366D0A /* testrun */,
31EEABFA156AAF9D00714D05 /* mps */,
3114A632156E94DB001E0AA3 /* abqtest */,
@@ -3468,7 +3462,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n";
+ shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n";
showEnvVarsInLog = 0;
};
2215A9B4192A47C500E9E2CE /* ShellScript */ = {
@@ -3482,7 +3476,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n";
+ shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n";
showEnvVarsInLog = 0;
};
2215A9BC192A47CE00E9E2CE /* ShellScript */ = {
@@ -3496,7 +3490,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n";
+ shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n";
showEnvVarsInLog = 0;
};
2215A9C4192A47D500E9E2CE /* ShellScript */ = {
@@ -3510,7 +3504,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n";
+ shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n";
showEnvVarsInLog = 0;
};
22CDE8F416E9E9D400366D0A /* ShellScript */ = {
@@ -3524,7 +3518,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n";
+ shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@@ -3909,7 +3903,6 @@
files = (
318DA8D31892B27E0089718C /* testlib.c in Sources */,
6313D47318A4028E00EB03EF /* djbench.c in Sources */,
- 318DA8D21892B13B0089718C /* getoptl.c in Sources */,
22561A9A18F426BB00372C66 /* testthrix.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -4018,7 +4011,6 @@
6313D47418A4029200EB03EF /* gcbench.c in Sources */,
6313D47518A40C6300EB03EF /* fmtdytst.c in Sources */,
6313D47618A40C7B00EB03EF /* fmtdy.c in Sources */,
- 6313D46A18A400B200EB03EF /* getoptl.c in Sources */,
22561A9B18F426F300372C66 /* testthrix.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -5810,7 +5802,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpoll" */ = {
+ 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpollnone" */ = {
isa = XCConfigurationList;
buildConfigurations = (
2215A9C6192A47D500E9E2CE /* Debug */,
diff --git a/mps/code/mpsacl.h b/mps/code/mpsacl.h
index b9fc2913f63..85536ef4ed7 100644
--- a/mps/code/mpsacl.h
+++ b/mps/code/mpsacl.h
@@ -1,7 +1,7 @@
/* mpsacl.h: MEMORY POOL SYSTEM ARENA CLASS "CL"
*
* $Id$
- * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*/
#ifndef mpsacl_h
@@ -10,8 +10,8 @@
#include "mps.h"
/* Client arena base address argument */
-extern const struct mps_key_s _mps_key_arena_cl_addr;
-#define MPS_KEY_ARENA_CL_BASE (&_mps_key_arena_cl_addr)
+extern const struct mps_key_s _mps_key_ARENA_CL_BASE;
+#define MPS_KEY_ARENA_CL_BASE (&_mps_key_ARENA_CL_BASE)
#define MPS_KEY_ARENA_CL_BASE_FIELD addr
extern mps_arena_class_t mps_arena_class_cl(void);
@@ -22,7 +22,7 @@ extern mps_arena_class_t mps_arena_class_cl(void);
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2013 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/mpscams.h b/mps/code/mpscams.h
index dc5d9fdf688..49a3de484c9 100644
--- a/mps/code/mpscams.h
+++ b/mps/code/mpscams.h
@@ -10,8 +10,8 @@
#include "mps.h"
-extern const struct mps_key_s _mps_key_ams_support_ambiguous;
-#define MPS_KEY_AMS_SUPPORT_AMBIGUOUS (&_mps_key_ams_support_ambiguous)
+extern const struct mps_key_s _mps_key_AMS_SUPPORT_AMBIGUOUS;
+#define MPS_KEY_AMS_SUPPORT_AMBIGUOUS (&_mps_key_AMS_SUPPORT_AMBIGUOUS)
#define MPS_KEY_AMS_SUPPORT_AMBIGUOUS_FIELD b
extern mps_pool_class_t mps_class_ams(void);
diff --git a/mps/code/mpscawl.h b/mps/code/mpscawl.h
index a449d0ecd26..087e927bf7c 100644
--- a/mps/code/mpscawl.h
+++ b/mps/code/mpscawl.h
@@ -9,8 +9,8 @@
#include "mps.h"
-extern const struct mps_key_s _mps_key_awl_find_dependent;
-#define MPS_KEY_AWL_FIND_DEPENDENT (&_mps_key_awl_find_dependent)
+extern const struct mps_key_s _mps_key_AWL_FIND_DEPENDENT;
+#define MPS_KEY_AWL_FIND_DEPENDENT (&_mps_key_AWL_FIND_DEPENDENT)
#define MPS_KEY_AWL_FIND_DEPENDENT_FIELD addr_method
extern mps_pool_class_t mps_class_awl(void);
diff --git a/mps/code/mpscmfs.h b/mps/code/mpscmfs.h
index 1a2dd875522..bb3b1013cf2 100644
--- a/mps/code/mpscmfs.h
+++ b/mps/code/mpscmfs.h
@@ -9,8 +9,8 @@
#include "mps.h"
-extern const struct mps_key_s _mps_key_mfs_unit_size;
-#define MPS_KEY_MFS_UNIT_SIZE (&_mps_key_mfs_unit_size)
+extern const struct mps_key_s _mps_key_MFS_UNIT_SIZE;
+#define MPS_KEY_MFS_UNIT_SIZE (&_mps_key_MFS_UNIT_SIZE)
#define MPS_KEY_MFS_UNIT_SIZE_FIELD size
extern mps_pool_class_t mps_class_mfs(void);
diff --git a/mps/code/mpscmvff.h b/mps/code/mpscmvff.h
index 3dfb9b5687c..2f468c5e483 100644
--- a/mps/code/mpscmvff.h
+++ b/mps/code/mpscmvff.h
@@ -9,14 +9,14 @@
#include "mps.h"
-extern const struct mps_key_s _mps_key_mvff_slot_high;
-#define MPS_KEY_MVFF_SLOT_HIGH (&_mps_key_mvff_slot_high)
+extern const struct mps_key_s _mps_key_MVFF_SLOT_HIGH;
+#define MPS_KEY_MVFF_SLOT_HIGH (&_mps_key_MVFF_SLOT_HIGH)
#define MPS_KEY_MVFF_SLOT_HIGH_FIELD b
-extern const struct mps_key_s _mps_key_mvff_arena_high;
-#define MPS_KEY_MVFF_ARENA_HIGH (&_mps_key_mvff_arena_high)
+extern const struct mps_key_s _mps_key_MVFF_ARENA_HIGH;
+#define MPS_KEY_MVFF_ARENA_HIGH (&_mps_key_MVFF_ARENA_HIGH)
#define MPS_KEY_MVFF_ARENA_HIGH_FIELD b
-extern const struct mps_key_s _mps_key_mvff_first_fit;
-#define MPS_KEY_MVFF_FIRST_FIT (&_mps_key_mvff_first_fit)
+extern const struct mps_key_s _mps_key_MVFF_FIRST_FIT;
+#define MPS_KEY_MVFF_FIRST_FIT (&_mps_key_MVFF_FIRST_FIT)
#define MPS_KEY_MVFF_FIRST_FIT_FIELD b
#define mps_mvff_free_size mps_pool_free_size
diff --git a/mps/code/mpscmvt.h b/mps/code/mpscmvt.h
index 943a97e6f6f..b3a62734684 100644
--- a/mps/code/mpscmvt.h
+++ b/mps/code/mpscmvt.h
@@ -9,11 +9,11 @@
#include "mps.h"
-extern const struct mps_key_s _mps_key_mvt_reserve_depth;
-#define MPS_KEY_MVT_RESERVE_DEPTH (&_mps_key_mvt_reserve_depth)
+extern const struct mps_key_s _mps_key_MVT_RESERVE_DEPTH;
+#define MPS_KEY_MVT_RESERVE_DEPTH (&_mps_key_MVT_RESERVE_DEPTH)
#define MPS_KEY_MVT_RESERVE_DEPTH_FIELD count
-extern const struct mps_key_s _mps_key_mvt_frag_limit;
-#define MPS_KEY_MVT_FRAG_LIMIT (&_mps_key_mvt_frag_limit)
+extern const struct mps_key_s _mps_key_MVT_FRAG_LIMIT;
+#define MPS_KEY_MVT_FRAG_LIMIT (&_mps_key_MVT_FRAG_LIMIT)
#define MPS_KEY_MVT_FRAG_LIMIT_FIELD d
extern mps_pool_class_t mps_class_mvt(void);
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index 69e072a3d7b..283fbc6123e 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -1,14 +1,14 @@
/* mpsi.c: MEMORY POOL SYSTEM C INTERFACE LAYER
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
* Portions copyright (c) 2002 Global Graphics Software.
*
* .purpose: This code bridges between the MPS interface to C,
* , and the internal MPM interfaces, as defined by
* . .purpose.check: It performs checking of the C client's
* usage of the MPS Interface. .purpose.thread: It excludes multiple
- * threads from the MPM by locking the Arena (see .thread-safety).
+ * threads from the MPM by locking the Arena (see ).
*
* .design:
*
@@ -19,6 +19,11 @@
* (between ArenaEnter and ArenaLeave) as this will leave the Arena in
* an unsuitable state for re-entry.
*
+ * .note.avert: Use AVERT only when "inside" the Arena (between
+ * ArenaEnter and ArenaLeave), as it's not thread-safe in all
+ * varieties. Use AVER(TESTT) otherwise. See
+ * .
+ *
*
* TRANSGRESSIONS (rule.impl.trans)
*
@@ -243,7 +248,7 @@ void mps_arena_park(mps_arena_t arena)
void mps_arena_expose(mps_arena_t arena)
{
ArenaEnter(arena);
- ArenaExposeRemember(ArenaGlobals(arena), 0);
+ ArenaExposeRemember(ArenaGlobals(arena), FALSE);
ArenaLeave(arena);
}
@@ -251,7 +256,7 @@ void mps_arena_expose(mps_arena_t arena)
void mps_arena_unsafe_expose_remember_protection(mps_arena_t arena)
{
ArenaEnter(arena);
- ArenaExposeRemember(ArenaGlobals(arena), 1);
+ ArenaExposeRemember(ArenaGlobals(arena), TRUE);
ArenaLeave(arena);
}
@@ -314,7 +319,7 @@ mps_res_t mps_arena_create_v(mps_arena_t *mps_arena_o,
va_list varargs)
{
mps_arg_s args[MPS_ARGS_MAX];
- AVERT(ArenaClass, arena_class);
+ AVER(TESTT(ArenaClass, arena_class));
arena_class->varargs(args, varargs);
return mps_arena_create_k(mps_arena_o, arena_class, args);
}
@@ -642,7 +647,7 @@ mps_res_t mps_pool_create_v(mps_pool_t *mps_pool_o, mps_arena_t arena,
mps_pool_class_t pool_class, va_list varargs)
{
mps_arg_s args[MPS_ARGS_MAX];
- AVERT(PoolClass, pool_class);
+ AVER(TESTT(PoolClass, pool_class));
pool_class->varargs(args, varargs);
return mps_pool_create_k(mps_pool_o, arena, pool_class, args);
}
@@ -923,7 +928,7 @@ mps_bool_t (mps_commit)(mps_ap_t mps_ap, mps_addr_t p, size_t size)
AVER(p != NULL);
AVER(size > 0);
AVER(p == mps_ap->init);
- AVER((void *)((char *)mps_ap->init + size) == mps_ap->alloc);
+ AVER(PointerAdd(mps_ap->init, size) == mps_ap->alloc);
return mps_commit(mps_ap, p, size);
}
@@ -1379,6 +1384,7 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena,
AVER(mps_reg_scan != NULL);
AVER(mps_reg_scan == mps_stack_scan_ambig); /* .reg.scan */
AVER(reg_scan_p != NULL); /* stackBot */
+ AVER(AddrIsAligned(reg_scan_p, sizeof(Word)));
AVER(rank == mps_rank_ambig());
AVER(mps_rm == (mps_rm_t)0);
@@ -2000,7 +2006,7 @@ void _mps_args_set_key(mps_arg_s args[MPS_ARGS_MAX], unsigned i,
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/mpsliban.c b/mps/code/mpsliban.c
index 092c1d3543a..2e391596e03 100644
--- a/mps/code/mpsliban.c
+++ b/mps/code/mpsliban.c
@@ -111,9 +111,6 @@ int (mps_lib_memcmp)(const void *s1, const void *s2, size_t n)
}
-/* @@@@ Platform specific conversion? */
-/* See http://devworld.apple.com/dev/techsupport/insidemac/OSUtilities/OSUtilities-94.html#MARKER-9-32 */
-
/* If your platform has a low-resolution clock(), and there are
* higher-resolution clocks readily available, then using one of those
* will improve MPS scheduling decisions and the quality of telemetry
diff --git a/mps/code/mv.nmk b/mps/code/mv.nmk
index d0759bad532..6abd37d810e 100644
--- a/mps/code/mv.nmk
+++ b/mps/code/mv.nmk
@@ -7,7 +7,7 @@
#
# This file is included by platform nmake files that use the Microsoft
# Visual C/C+ compiler. It defines the compiler-specific variables
-# that the common nmake file fragment () requires.
+# that the common nmake fragment (comm.nmk) requires.
CC = cl
LIBMAN = lib
diff --git a/mps/code/pc.nmk b/mps/code/pc.nmk
index e52addfba4c..fdcf1235d37 100644
--- a/mps/code/pc.nmk
+++ b/mps/code/pc.nmk
@@ -7,7 +7,7 @@
#
# This file is included by platform nmake files that use the Pelles C
# compiler. It defines the compiler-specific variables that the common
-# nmake file fragment () requires.
+# nmake fragment (comm.nmk) requires.
CC = pocc
LIBMAN = polib
diff --git a/mps/code/pool.c b/mps/code/pool.c
index 6d656f86b20..f939bca84e9 100644
--- a/mps/code/pool.c
+++ b/mps/code/pool.c
@@ -1,7 +1,7 @@
/* pool.c: POOL IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2001 Global Graphics Software.
*
* DESIGN
@@ -97,28 +97,24 @@ Bool PoolCheck(Pool pool)
/* normally pool->format iff PoolHasAttr(pool, AttrFMT), but during
* pool initialization pool->format may not yet be set. */
CHECKL(pool->format == NULL || PoolHasAttr(pool, AttrFMT));
- CHECKL(pool->fillMutatorSize >= 0.0);
- CHECKL(pool->emptyMutatorSize >= 0.0);
- CHECKL(pool->fillInternalSize >= 0.0);
- CHECKL(pool->emptyInternalSize >= 0.0);
return TRUE;
}
/* Common keywords to PoolInit */
-ARG_DEFINE_KEY(format, Format);
-ARG_DEFINE_KEY(chain, Chain);
-ARG_DEFINE_KEY(gen, Cant);
-ARG_DEFINE_KEY(rank, Rank);
-ARG_DEFINE_KEY(extend_by, Size);
-ARG_DEFINE_KEY(large_size, Size);
-ARG_DEFINE_KEY(min_size, Size);
-ARG_DEFINE_KEY(mean_size, Size);
-ARG_DEFINE_KEY(max_size, Size);
-ARG_DEFINE_KEY(align, Align);
-ARG_DEFINE_KEY(spare, double);
-ARG_DEFINE_KEY(interior, Bool);
+ARG_DEFINE_KEY(FORMAT, Format);
+ARG_DEFINE_KEY(CHAIN, Chain);
+ARG_DEFINE_KEY(GEN, Cant);
+ARG_DEFINE_KEY(RANK, Rank);
+ARG_DEFINE_KEY(EXTEND_BY, Size);
+ARG_DEFINE_KEY(LARGE_SIZE, Size);
+ARG_DEFINE_KEY(MIN_SIZE, Size);
+ARG_DEFINE_KEY(MEAN_SIZE, Size);
+ARG_DEFINE_KEY(MAX_SIZE, Size);
+ARG_DEFINE_KEY(ALIGN, Align);
+ARG_DEFINE_KEY(SPARE, double);
+ARG_DEFINE_KEY(INTERIOR, Bool);
/* PoolInit -- initialize a pool
@@ -157,10 +153,6 @@ Res PoolInit(Pool pool, Arena arena, PoolClass class, ArgList args)
pool->alignment = MPS_PF_ALIGN;
pool->format = NULL;
pool->fix = class->fix;
- pool->fillMutatorSize = 0.0;
- pool->emptyMutatorSize = 0.0;
- pool->fillInternalSize = 0.0;
- pool->emptyInternalSize = 0.0;
/* Initialise signature last; see */
pool->sig = PoolSig;
@@ -304,7 +296,6 @@ Res PoolAlloc(Addr *pReturn, Pool pool, Size size,
/* All PoolAllocs should advance the allocation clock, so we count */
/* it all in the fillMutatorSize field. */
- pool->fillMutatorSize += size;
ArenaGlobals(PoolArena(pool))->fillMutatorSize += size;
EVENT3(PoolAlloc, pool, *pReturn, size);
@@ -321,6 +312,7 @@ void PoolFree(Pool pool, Addr old, Size size)
AVER(old != NULL);
/* The pool methods should check that old is in pool. */
AVER(size > 0);
+ AVER(AddrIsAligned(old, pool->alignment));
AVER(PoolHasRange(pool, old, AddrAdd(old, size)));
(*pool->class->free)(pool, old, size);
@@ -336,7 +328,7 @@ Res PoolAccess(Pool pool, Seg seg, Addr addr,
AVERT(Seg, seg);
AVER(SegBase(seg) <= addr);
AVER(addr < SegLimit(seg));
- /* Can't check mode as there is no check method */
+ AVERT(AccessSet, mode);
/* Can't check MutatorFaultContext as there is no check method */
return (*pool->class->access)(pool, seg, addr, mode, context);
@@ -495,8 +487,7 @@ Res PoolAddrObject(Addr *pReturn, Pool pool, Seg seg, Addr addr)
/* PoolWalk -- walk objects in this segment */
-void PoolWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f,
- void *p, size_t s)
+void PoolWalk(Pool pool, Seg seg, FormattedObjectsVisitor f, void *p, size_t s)
{
AVERT(Pool, pool);
AVERT(Seg, seg);
@@ -512,7 +503,7 @@ void PoolWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f,
* PoolFreeWalk is not required to find all free blocks.
*/
-void PoolFreeWalk(Pool pool, FreeBlockStepMethod f, void *p)
+void PoolFreeWalk(Pool pool, FreeBlockVisitor f, void *p)
{
AVERT(Pool, pool);
AVER(FUNCHECK(f));
@@ -569,18 +560,6 @@ Res PoolDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
if (res != ResOK)
return res;
}
- res = WriteF(stream, depth + 2,
- "fillMutatorSize $UKb\n",
- (WriteFU)(pool->fillMutatorSize / 1024),
- "emptyMutatorSize $UKb\n",
- (WriteFU)(pool->emptyMutatorSize / 1024),
- "fillInternalSize $UKb\n",
- (WriteFU)(pool->fillInternalSize / 1024),
- "emptyInternalSize $UKb\n",
- (WriteFU)(pool->emptyInternalSize / 1024),
- NULL);
- if (res != ResOK)
- return res;
res = (*pool->class->describe)(pool, stream, depth + 2);
if (res != ResOK)
@@ -715,7 +694,7 @@ Bool PoolHasRange(Pool pool, Addr base, Addr limit)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/poolabs.c b/mps/code/poolabs.c
index 89da02abb38..30f5d0f999e 100644
--- a/mps/code/poolabs.c
+++ b/mps/code/poolabs.c
@@ -1,7 +1,7 @@
/* poolabs.c: ABSTRACT POOL CLASSES
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
* PURPOSE
@@ -334,7 +334,7 @@ Res PoolNoAccess(Pool pool, Seg seg, Addr addr,
AVERT(Seg, seg);
AVER(SegBase(seg) <= addr);
AVER(addr < SegLimit(seg));
- /* can't check AccessSet as there is no Check method */
+ AVERT(AccessSet, mode);
/* can't check context as there is no Check method */
UNUSED(mode);
UNUSED(context);
@@ -360,7 +360,7 @@ Res PoolSegAccess(Pool pool, Seg seg, Addr addr,
AVER(SegBase(seg) <= addr);
AVER(addr < SegLimit(seg));
AVER(SegPool(seg) == pool);
- /* can't check AccessSet as there is no Check method */
+ AVERT(AccessSet, mode);
/* can't check context as there is no Check method */
UNUSED(addr);
@@ -396,7 +396,7 @@ Res PoolSingleAccess(Pool pool, Seg seg, Addr addr,
AVER(SegBase(seg) <= addr);
AVER(addr < SegLimit(seg));
AVER(SegPool(seg) == pool);
- /* can't check AccessSet as there is no Check method */
+ AVERT(AccessSet, mode);
/* can't check context as there is no Check method */
arena = PoolArena(pool);
@@ -648,8 +648,8 @@ Res PoolNoAddrObject(Addr *pReturn, Pool pool, Seg seg, Addr addr)
return ResUNIMPL;
}
-void PoolNoWalk(Pool pool, Seg seg,
- FormattedObjectsStepMethod f, void *p, size_t s)
+void PoolNoWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
+ void *p, size_t s)
{
AVERT(Pool, pool);
AVERT(Seg, seg);
@@ -662,7 +662,7 @@ void PoolNoWalk(Pool pool, Seg seg,
}
-void PoolTrivFreeWalk(Pool pool, FreeBlockStepMethod f, void *p)
+void PoolTrivFreeWalk(Pool pool, FreeBlockVisitor f, void *p)
{
AVERT(Pool, pool);
AVER(FUNCHECK(f));
@@ -691,7 +691,7 @@ Size PoolNoSize(Pool pool)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c
index e6d4ddac154..dfe3cfc37d9 100644
--- a/mps/code/poolamc.c
+++ b/mps/code/poolamc.c
@@ -22,7 +22,7 @@ typedef struct AMCStruct *AMC;
typedef struct amcGenStruct *amcGen;
/* Function returning TRUE if block in nailboarded segment is pinned. */
-typedef Bool (*amcPinnedMethod)(AMC amc, Nailboard board, Addr base, Addr limit);
+typedef Bool (*amcPinnedFunction)(AMC amc, Nailboard board, Addr base, Addr limit);
/* forward declarations */
@@ -31,7 +31,6 @@ static Bool amcSegHasNailboard(Seg seg);
static Nailboard amcSegNailboard(Seg seg);
static Bool AMCCheck(AMC amc);
static Res AMCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO);
-static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO);
extern PoolClass AMCZPoolClassGet(void);
extern BufferClass amcBufClassGet(void);
extern SegClass amcSegClassGet(void);
@@ -71,7 +70,7 @@ enum {
/* amcSegStruct -- AMC-specific fields appended to GCSegStruct
*
- * .seq.old: The "old" flag is FALSE if the segment has never been
+ * .seg.old: The "old" flag is FALSE if the segment has never been
* collected, and so its size is accounted against the pool
* generation's newSize; it is TRUE if the segment has been collected
* at least once, and so its size is accounted against the pool
@@ -394,71 +393,6 @@ static amcGen amcSegGen(Seg seg)
#define AMCSig ((Sig)0x519A3C99) /* SIGnature AMC */
-typedef struct PageRetStruct {
- Count pCond; /* pages Condemned */
- Count pRet; /* pages Retained (in place) */
- /* Small */
- Count pCS; /* pages Condemned in Small segments */
- Count pRS; /* pages Retained in Small segments */
- /* Medium */
- Count sCM; /* segments Condemned: Medium */
- /* ...= upper bound of how many extra pages it */
- /* would have cost, had we chosen to LSP-pad */
- /* all these segments. */
- Count pCM; /* pages Condemned in Medium segments */
- Count sRM; /* segments Retained: Medium */
- Count pRM; /* pages Retained in Medium segments: */
- Count pRM1; /* ...because obj 1 was preserved in place */
- /* ...because a rest obj was pip, causing: */
- Count pRMrr; /* ...retained rest pages (page where rest obj is) */
- Count pRMr1; /* ...retained obj 1 pages (purely NMR pad) */
- /* Large */
- Count sCL; /* segments Condemned: Large */
- /* ...= upper bound of how many extra pages it */
- /* has cost to LSP-pad all these segments. */
- Count pCL; /* pages Condemned in Large segments */
- Count sRL; /* segments Retained: Large */
- Count pRL; /* pages Retained in Large segments */
- Count pRLr; /* ...because a rest obj (actually LSP) was pip */
-
- /* The interesting things about this report are:
- * - How many pages are actually being retained? (pRet)
- * - Percentage? (pRet/pCond)
- * - Is the major contribution from Small, Medium, or Large segs?
- *
- * Generally, pages retained because obj 1 needed to be preserved in
- * place are ok (because no alternative placement could have retained
- * fewer pages), but pages retained by a rest obj are unfortunate
- * (better placement, putting the small rest objs in their own seg,
- * would have retained fewer pages). In particular:
- *
- * The LSP threshold is a payoff between the wasted space from
- * LSP-padding, versus the risk of increased page-retention (due to
- * rest objs) from not LSP-padding.
- *
- * For Medium segs, where we do not do LSP-padding:
- * - LSP would have required at most sCM extra pages;
- * - the extra retention incurred by not LSP-padding is pRMr1.
- * A high pRMr1 => lots of Medium segs getting retained by the rest
- * objs tacked on after obj 1. Consider lowering LSP-threshold.
- *
- * For Large segs we do LSP padding. This has a cost; upper bound is
- * sCL extra pages. But the benefit should be greatly reduced ambig
- * refs to rest objs. With LSP, the only rest obj is the LSP pad
- * itself. We expect that ambig refs to this are rare, so currently
- * we do not implement .large.lsp-no-retain. But we do record the
- * occurrence of pages retained by a ref to an LSP pad: pPLr. A high
- * pRLr => perhaps .large.lsp-no-retain should be implemented?
- *
- * If the mutator is causing a lot of page retention, then sRM/pRM
- * and sRL/pRL should give some picture of the number of retained
- * objects and their average size.
- */
-} PageRetStruct;
-
-/* static => init'd to zero */
-static struct PageRetStruct pageretstruct_Zero;
-
typedef struct AMCStruct { /* */
PoolStruct poolStruct; /* generic pool structure */
RankSet rankSet; /* rankSet for entire pool */
@@ -471,13 +405,9 @@ typedef struct AMCStruct { /* */
amcGen afterRampGen; /* the generation after rampGen */
unsigned rampCount; /* */
int rampMode; /* */
- amcPinnedMethod pinned; /* function determining if block is pinned */
+ amcPinnedFunction pinned; /* function determining if block is pinned */
Size extendBy; /* segment size to extend pool by */
Size largeSize; /* min size of "large" segments */
-
- /* page retention in an in-progress trace */
- STATISTIC_DECL(PageRetStruct pageretstruct[TraceLIMIT]);
-
Sig sig; /* */
} AMCStruct;
@@ -804,8 +734,6 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args)
AMC amc;
Res res;
Arena arena;
- TraceId ti;
- Trace trace;
Index i;
size_t genArraySize;
size_t genCount;
@@ -815,16 +743,6 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args)
Size largeSize = AMC_LARGE_SIZE_DEFAULT;
ArgStruct arg;
- /* Suppress a warning about this structure not being used when there
- are no statistics. Note that simply making the declaration conditional
- does not work, because we carefully reference expressions inside
- STATISTICS to prevent such warnings on parameters and local variables.
- It's just that clang 4.0 on Mac OS X does some sort of extra check
- that produces a special warnings about static variables. */
-#if !defined(STATISTICS)
- UNUSED(pageretstruct_Zero);
-#endif
-
AVER(pool != NULL);
amc = PoolAMC(pool);
@@ -844,7 +762,9 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args)
largeSize = arg.val.size;
AVERT(Format, pool->format);
+ AVER(FormatArena(pool->format) == arena);
AVERT(Chain, chain);
+ AVER(chain->arena == arena);
AVER(extendBy > 0);
AVER(largeSize > 0);
/* TODO: it would be nice to be able to manage large objects that
@@ -853,6 +773,7 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args)
* assertion catches this bad case. */
AVER(largeSize >= extendBy);
pool->alignment = pool->format->alignment;
+ pool->fix = AMCFix;
amc->rankSet = rankSet;
RingInit(&amc->genRing);
@@ -867,16 +788,6 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args)
amc->rampCount = 0;
amc->rampMode = RampOUTSIDE;
- TRACE_SET_ITER(ti, trace, TraceSetUNIV, arena)
- STATISTIC(amc->pageretstruct[ti] = pageretstruct_Zero);
- TRACE_SET_ITER_END(ti, trace, TraceSetUNIV, arena);
-
- if(pool->format->headerSize == 0) {
- pool->fix = AMCFix;
- } else {
- pool->fix = AMCHeaderFix;
- }
-
if (interior) {
amc->pinned = amcPinnedInterior;
} else {
@@ -1308,24 +1219,6 @@ static Res AMCWhiten(Pool pool, Trace trace, Seg seg)
amc = PoolAMC(pool);
AVERT(AMC, amc);
- STATISTIC_STAT( {
- Count pages;
- Size size = SegSize(seg);
- AVER(SizeIsArenaGrains(size, pool->arena));
- pages = size / ArenaGrainSize(pool->arena);
- AVER(pages != 0);
- amc->pageretstruct[trace->ti].pCond += pages;
- if(pages == 1) {
- amc->pageretstruct[trace->ti].pCS += pages;
- } else if(size < amc->largeSize) {
- amc->pageretstruct[trace->ti].sCM += 1;
- amc->pageretstruct[trace->ti].pCM += pages;
- } else {
- amc->pageretstruct[trace->ti].sCL += 1;
- amc->pageretstruct[trace->ti].pCL += pages;
- }
- } );
-
gen = amcSegGen(seg);
AVERT(amcGen, gen);
if (!amcseg->old) {
@@ -1649,155 +1542,6 @@ fixInPlace: /* see .Nailboard.emergency */
* See .
*/
static Res AMCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
-{
- Arena arena;
- AMC amc;
- Res res;
- Format format; /* cache of pool->format */
- Ref ref; /* reference to be fixed */
- Ref newRef; /* new location, if moved */
- Size length; /* length of object to be relocated */
- Buffer buffer; /* buffer to allocate new copy into */
- amcGen gen; /* generation of old copy of object */
- TraceSet grey; /* greyness of object being relocated */
- Seg toSeg; /* segment to which object is being relocated */
-
- /* */
- AVERT_CRITICAL(Pool, pool);
- AVERT_CRITICAL(ScanState, ss);
- AVERT_CRITICAL(Seg, seg);
- AVER_CRITICAL(refIO != NULL);
- EVENT0(AMCFix);
-
- /* For the moment, assume that the object was already marked. */
- /* (See .) */
- ss->wasMarked = TRUE;
-
- /* If the reference is ambiguous, set up the datastructures for */
- /* managing a nailed segment. This involves marking the segment */
- /* as nailed, and setting up a per-word mark table */
- if(ss->rank == RankAMBIG) {
- /* .nail.new: Check to see whether we need a Nailboard for */
- /* this seg. We use "SegNailed(seg) == TraceSetEMPTY" */
- /* rather than "!amcSegHasNailboard(seg)" because this avoids */
- /* setting up a new nailboard when the segment was nailed, but */
- /* had no nailboard. This must be avoided because otherwise */
- /* assumptions in AMCFixEmergency will be wrong (essentially */
- /* we will lose some pointer fixes because we introduced a */
- /* nailboard). */
- if(SegNailed(seg) == TraceSetEMPTY) {
- res = amcSegCreateNailboard(seg, pool);
- if(res != ResOK)
- return res;
- ++ss->nailCount;
- SegSetNailed(seg, TraceSetUnion(SegNailed(seg), ss->traces));
- }
- amcFixInPlace(pool, seg, ss, refIO);
- return ResOK;
- }
-
- amc = PoolAMC(pool);
- AVERT_CRITICAL(AMC, amc);
- format = pool->format;
- ref = *refIO;
- AVER_CRITICAL(SegBase(seg) <= ref);
- AVER_CRITICAL(ref < SegLimit(seg));
- arena = pool->arena;
-
- /* .exposed.seg: Statements tagged ".exposed.seg" below require */
- /* that "seg" (that is: the 'from' seg) has been ShieldExposed. */
- ShieldExpose(arena, seg);
- newRef = (*format->isMoved)(ref); /* .exposed.seg */
-
- if(newRef == (Addr)0) {
- Addr clientQ;
- clientQ = (*format->skip)(ref);
-
- /* If object is nailed already then we mustn't copy it: */
- if (SegNailed(seg) != TraceSetEMPTY
- && !(amcSegHasNailboard(seg)
- && !(*amc->pinned)(amc, amcSegNailboard(seg), ref, clientQ)))
- {
- /* Segment only needs greying if there are new traces for */
- /* which we are nailing. */
- if(!TraceSetSub(ss->traces, SegNailed(seg))) {
- if(SegRankSet(seg) != RankSetEMPTY) /* not for AMCZ */
- SegSetGrey(seg, TraceSetUnion(SegGrey(seg), ss->traces));
- SegSetNailed(seg, TraceSetUnion(SegNailed(seg), ss->traces));
- }
- res = ResOK;
- goto returnRes;
- } else if(ss->rank == RankWEAK) {
- /* Object is not preserved (neither moved, nor nailed) */
- /* hence, reference should be splatted. */
- goto updateReference;
- }
- /* Object is not preserved yet (neither moved, nor nailed) */
- /* so should be preserved by forwarding. */
-
- /* */
- ss->wasMarked = FALSE;
-
- /* Get the forwarding buffer from the object's generation. */
- gen = amcSegGen(seg);
- buffer = gen->forward;
- AVER_CRITICAL(buffer != NULL);
-
- length = AddrOffset(ref, clientQ); /* .exposed.seg */
- STATISTIC_STAT(++ss->forwardedCount);
- ss->forwardedSize += length;
- do {
- res = BUFFER_RESERVE(&newRef, buffer, length, FALSE);
- if(res != ResOK)
- goto returnRes;
-
- toSeg = BufferSeg(buffer);
- ShieldExpose(arena, toSeg);
-
- /* Since we're moving an object from one segment to another, */
- /* union the greyness and the summaries together. */
- grey = SegGrey(seg);
- if(SegRankSet(seg) != RankSetEMPTY) { /* not for AMCZ */
- grey = TraceSetUnion(grey, ss->traces);
- SegSetSummary(toSeg, RefSetUnion(SegSummary(toSeg), SegSummary(seg)));
- } else {
- AVER(SegRankSet(toSeg) == RankSetEMPTY);
- }
- SegSetGrey(toSeg, TraceSetUnion(SegGrey(toSeg), grey));
-
- /* */
- (void)AddrCopy(newRef, ref, length); /* .exposed.seg */
-
- ShieldCover(arena, toSeg);
- } while(!BUFFER_COMMIT(buffer, newRef, length));
- ss->copiedSize += length;
-
- (*format->move)(ref, newRef); /* .exposed.seg */
-
- EVENT1(AMCFixForward, newRef);
- } else {
- /* reference to broken heart (which should be snapped out -- */
- /* consider adding to (non-existant) snap-out cache here) */
- STATISTIC_STAT(++ss->snapCount);
- }
-
- /* .fix.update: update the reference to whatever the above code */
- /* decided it should be */
-updateReference:
- *refIO = newRef;
- res = ResOK;
-
-returnRes:
- ShieldCover(arena, seg); /* .exposed.seg */
- return res;
-}
-
-
-/* AMCHeaderFix -- fix a reference to the pool, with headers
- *
- * See .
- */
-static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
{
Arena arena;
AMC amc;
@@ -1805,6 +1549,7 @@ static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
Format format; /* cache of pool->format */
Size headerSize; /* cache of pool->format->headerSize */
Ref ref; /* reference to be fixed */
+ Addr base; /* base address of reference */
Ref newRef; /* new location, if moved */
Addr newBase; /* base address of new copy */
Size length; /* length of object to be relocated */
@@ -1853,6 +1598,8 @@ static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
headerSize = format->headerSize;
ref = *refIO;
AVER_CRITICAL(AddrAdd(SegBase(seg), headerSize) <= ref);
+ base = AddrSub(ref, headerSize);
+ AVER_CRITICAL(AddrIsAligned(base, PoolAlignment(pool)));
AVER_CRITICAL(ref < SegLimit(seg)); /* see .ref-limit */
arena = pool->arena;
@@ -1919,7 +1666,7 @@ static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
SegSetGrey(toSeg, TraceSetUnion(SegGrey(toSeg), grey));
/* */
- (void)AddrCopy(newBase, AddrSub(ref, headerSize), length); /* .exposed.seg */
+ (void)AddrCopy(newBase, base, length); /* .exposed.seg */
ShieldCover(arena, toSeg);
} while (!BUFFER_COMMIT(buffer, newBase, length));
@@ -1958,8 +1705,6 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg)
Size preservedInPlaceSize = (Size)0;
AMC amc;
Size headerSize;
- Addr p1; /* first obj in seg */
- Bool obj1pip = FALSE; /* first obj was preserved in place */
Addr padBase; /* base of next padding object */
Size padLength; /* length of next padding object */
@@ -1981,7 +1726,6 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg)
} else {
limit = SegLimit(seg);
}
- p1 = p;
padBase = p;
padLength = 0;
while(p < limit) {
@@ -2003,8 +1747,6 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg)
if(preserve) {
++preservedInPlaceCount;
preservedInPlaceSize += length;
- if(p == p1)
- obj1pip = TRUE;
if (padLength > 0) {
/* Replace run of forwarding pointers and unreachable objects
* with a padding object. */
@@ -2053,38 +1795,6 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg)
AVER(SegBuffer(seg) == NULL);
PoolGenFree(&gen->pgen, seg, 0, SegSize(seg), 0, Seg2amcSeg(seg)->deferred);
- } else {
- /* Seg retained */
- STATISTIC_STAT( {
- Count pages;
- Size size = SegSize(seg);
- AVER(SizeIsArenaGrains(size, pool->arena));
- pages = size / ArenaGrainSize(pool->arena);
- AVER(pages != 0);
- amc->pageretstruct[trace->ti].pRet += pages;
- if(pages == 1) {
- amc->pageretstruct[trace->ti].pRS += pages;
- } else if(size < amc->largeSize) {
- amc->pageretstruct[trace->ti].sRM += 1;
- amc->pageretstruct[trace->ti].pRM += pages;
- if(obj1pip) {
- amc->pageretstruct[trace->ti].pRM1 += pages;
- } else {
- /* Seg retained by a rest obj. Cost: one rest page, */
- /* plus pages-1 pages of pure padding. */
- amc->pageretstruct[trace->ti].pRMrr += 1;
- amc->pageretstruct[trace->ti].pRMr1 += pages - 1;
- }
- } else {
- amc->pageretstruct[trace->ti].sRL += 1;
- amc->pageretstruct[trace->ti].pRL += pages;
- if(!obj1pip) {
- /* Seg retained by a rest obj */
- amc->pageretstruct[trace->ti].pRLr += pages;
- }
- }
- } );
-
}
}
@@ -2135,40 +1845,9 @@ static void AMCReclaim(Pool pool, Trace trace, Seg seg)
}
-/* AMCTraceEnd -- emit end-of-trace event */
-
-static void AMCTraceEnd(Pool pool, Trace trace)
-{
- AMC amc;
- TraceId ti;
-
- AVERT(Pool, pool);
- AVERT(Trace, trace);
-
- amc = PoolAMC(pool);
- AVERT(AMC, amc);
- ti = trace->ti;
- AVERT(TraceId, ti);
-
- STATISTIC_STAT ({
- Count pRetMin = 100;
- PageRetStruct *pr = &amc->pageretstruct[ti];
- if(pr->pRet >= pRetMin) {
- EVENT21(AMCTraceEnd, ArenaEpoch(pool->arena), (EventFU)trace->why,
- ArenaGrainSize(pool->arena), amc->largeSize, pRetMin, pr->pCond,
-
- pr->pRet, pr->pCS, pr->pRS, pr->sCM, pr->pCM, pr->sRM, pr->pRM,
- pr->pRM1, pr->pRMrr, pr->pRMr1, pr->sCL, pr->pCL, pr->sRL,
- pr->pRL, pr->pRLr);
- }
- *pr = pageretstruct_Zero;
- });
-}
-
-
/* AMCWalk -- Apply function to (black) objects in segment */
-static void AMCWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f,
+static void AMCWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
void *p, size_t s)
{
Addr object, nextObject, limit;
@@ -2218,8 +1897,7 @@ static void AMCWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f,
/* amcWalkAll -- Apply a function to all (black) objects in a pool */
-static void amcWalkAll(Pool pool, FormattedObjectsStepMethod f,
- void *p, size_t s)
+static void amcWalkAll(Pool pool, FormattedObjectsVisitor f, void *p, size_t s)
{
Arena arena;
Ring ring, next, node;
@@ -2453,7 +2131,6 @@ DEFINE_POOL_CLASS(AMCZPoolClass, this)
this->fix = AMCFix;
this->fixEmergency = AMCFixEmergency;
this->reclaim = AMCReclaim;
- this->traceEnd = AMCTraceEnd;
this->rampBegin = AMCRampBegin;
this->rampEnd = AMCRampEnd;
this->addrObject = AMCAddrObject;
@@ -2574,7 +2251,6 @@ static Bool AMCCheck(AMC amc)
/* if BEGIN or RAMPING, count must not be zero. */
CHECKL((amc->rampCount != 0) || ((amc->rampMode != RampBEGIN) &&
(amc->rampMode != RampRAMPING)));
- /* pageretstruct[ti] is statistics only, currently unchecked */
return TRUE;
}
diff --git a/mps/code/poolams.c b/mps/code/poolams.c
index b93375e4e0c..3f7f170ddbc 100644
--- a/mps/code/poolams.c
+++ b/mps/code/poolams.c
@@ -85,7 +85,7 @@ Bool AMSSegCheck(AMSSeg amsseg)
/* AMSSegFreeWalk -- walk the free space in a segment */
-void AMSSegFreeWalk(AMSSeg amsseg, FreeBlockStepMethod f, void *p)
+void AMSSegFreeWalk(AMSSeg amsseg, FreeBlockVisitor f, void *p)
{
Pool pool;
Seg seg;
@@ -785,7 +785,7 @@ static void AMSDebugVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs)
* allocated in the pool. See .
*/
-ARG_DEFINE_KEY(ams_support_ambiguous, Bool);
+ARG_DEFINE_KEY(AMS_SUPPORT_AMBIGUOUS, Bool);
static Res AMSInit(Pool pool, ArgList args)
{
@@ -831,13 +831,15 @@ Res AMSInitInternal(AMS ams, Format format, Chain chain, unsigned gen,
Res res;
/* Can't check ams, it's not initialized. */
- AVERT(Format, format);
- AVERT(Chain, chain);
- AVER(gen <= ChainGens(chain));
-
pool = AMSPool(ams);
AVERT(Pool, pool);
+ AVERT(Format, format);
+ AVER(FormatArena(format) == PoolArena(pool));
pool->format = format;
+ AVERT(Chain, chain);
+ AVER(gen <= ChainGens(chain));
+ AVER(chain->arena == PoolArena(pool));
+
pool->alignment = pool->format->alignment;
ams->grainShift = SizeLog2(PoolAlignment(pool));
@@ -1653,7 +1655,7 @@ static void AMSReclaim(Pool pool, Trace trace, Seg seg)
/* AMSFreeWalk -- free block walking method of the pool class */
-static void AMSFreeWalk(Pool pool, FreeBlockStepMethod f, void *p)
+static void AMSFreeWalk(Pool pool, FreeBlockVisitor f, void *p)
{
AMS ams;
Ring node, ring, nextNode; /* for iterating over the segments */
diff --git a/mps/code/poolams.h b/mps/code/poolams.h
index a69926e2354..8617063fc80 100644
--- a/mps/code/poolams.h
+++ b/mps/code/poolams.h
@@ -1,7 +1,7 @@
/* poolams.h: AUTOMATIC MARK & SWEEP POOL CLASS INTERFACE
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
* .purpose: Internal interface to AMS functionality. */
@@ -175,7 +175,7 @@ extern Res AMSScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg);
#define AMSChain(ams) ((ams)->chain)
-extern void AMSSegFreeWalk(AMSSeg amsseg, FreeBlockStepMethod f, void *p);
+extern void AMSSegFreeWalk(AMSSeg amsseg, FreeBlockVisitor f, void *p);
extern void AMSSegFreeCheck(AMSSeg amsseg);
@@ -198,7 +198,7 @@ extern AMSPoolClass AMSDebugPoolClassGet(void);
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c
index b00d9129c75..5bb0e6b9025 100644
--- a/mps/code/poolawl.c
+++ b/mps/code/poolawl.c
@@ -1,7 +1,7 @@
/* poolawl.c: AUTOMATIC WEAK LINKED POOL CLASS
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
*
* DESIGN
@@ -74,7 +74,7 @@ typedef struct awlStatTotalStruct {
/* the type of a function to find an object's dependent object */
-typedef Addr (*FindDependentMethod)(Addr object);
+typedef Addr (*FindDependentFunction)(Addr object);
/* AWLStruct -- AWL pool structure
*
@@ -86,7 +86,7 @@ typedef struct AWLStruct {
Shift alignShift;
PoolGenStruct pgen; /* generation representing the pool */
Count succAccesses; /* number of successive single accesses */
- FindDependentMethod findDependent; /* to find a dependent object */
+ FindDependentFunction findDependent; /* to find a dependent object */
awlStatTotalStruct stats;
Sig sig;
} AWLStruct, *AWL;
@@ -544,13 +544,13 @@ static Addr awlNoDependent(Addr addr)
/* AWLInit -- initialize an AWL pool */
-ARG_DEFINE_KEY(awl_find_dependent, Fun);
+ARG_DEFINE_KEY(AWL_FIND_DEPENDENT, Fun);
static Res AWLInit(Pool pool, ArgList args)
{
AWL awl;
Format format;
- FindDependentMethod findDependent = awlNoDependent;
+ FindDependentFunction findDependent = awlNoDependent;
Chain chain;
Res res;
ArgStruct arg;
@@ -564,7 +564,7 @@ static Res AWLInit(Pool pool, ArgList args)
ArgRequire(&arg, args, MPS_KEY_FORMAT);
format = arg.val.format;
if (ArgPick(&arg, args, MPS_KEY_AWL_FIND_DEPENDENT))
- findDependent = (FindDependentMethod)arg.val.addr_method;
+ findDependent = (FindDependentFunction)arg.val.addr_method;
if (ArgPick(&arg, args, MPS_KEY_CHAIN))
chain = arg.val.chain;
else {
@@ -575,6 +575,7 @@ static Res AWLInit(Pool pool, ArgList args)
gen = arg.val.u;
AVERT(Format, format);
+ AVER(FormatArena(format) == PoolArena(pool));
pool->format = format;
pool->alignment = format->alignment;
@@ -583,6 +584,7 @@ static Res AWLInit(Pool pool, ArgList args)
AVERT(Chain, chain);
AVER(gen <= ChainGens(chain));
+ AVER(chain->arena == PoolArena(pool));
res = PoolGenInit(&awl->pgen, ChainGen(chain, gen), pool);
if (res != ResOK)
@@ -1204,6 +1206,7 @@ static Res AWLAccess(Pool pool, Seg seg, Addr addr,
AVER(SegBase(seg) <= addr);
AVER(addr < SegLimit(seg));
AVER(SegPool(seg) == pool);
+ AVERT(AccessSet, mode);
/* Attempt scanning a single reference if permitted */
if(AWLCanTrySingleAccess(PoolArena(pool), awl, seg, addr)) {
@@ -1232,7 +1235,7 @@ static Res AWLAccess(Pool pool, Seg seg, Addr addr,
/* AWLWalk -- walk all objects */
-static void AWLWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f,
+static void AWLWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
void *p, size_t s)
{
AWL awl;
@@ -1373,7 +1376,7 @@ static Bool AWLCheck(AWL awl)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/poollo.c b/mps/code/poollo.c
index b60ae06ea02..a1a3f328468 100644
--- a/mps/code/poollo.c
+++ b/mps/code/poollo.c
@@ -401,8 +401,7 @@ static void loSegReclaim(LOSeg loseg, Trace trace)
/* This walks over _all_ objects in the heap, whether they are */
/* black or white, they are still validly formatted as this is */
/* a leaf pool, so there can't be any dangling references */
-static void LOWalk(Pool pool, Seg seg,
- FormattedObjectsStepMethod f,
+static void LOWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
void *p, size_t s)
{
Addr base;
@@ -505,8 +504,10 @@ static Res LOInit(Pool pool, ArgList args)
gen = arg.val.u;
AVERT(Format, pool->format);
+ AVER(FormatArena(pool->format) == arena);
AVERT(Chain, chain);
AVER(gen <= ChainGens(chain));
+ AVER(chain->arena == arena);
pool->alignment = pool->format->alignment;
lo->alignShift = SizeLog2((Size)PoolAlignment(pool));
diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c
index aaa780d238b..ed1c0343aba 100644
--- a/mps/code/poolmfs.c
+++ b/mps/code/poolmfs.c
@@ -72,7 +72,7 @@ static void MFSVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs)
AVERT(ArgList, args);
}
-ARG_DEFINE_KEY(mfs_unit_size, Size);
+ARG_DEFINE_KEY(MFS_UNIT_SIZE, Size);
ARG_DEFINE_KEY(MFSExtendSelf, Bool);
static Res MFSInit(Pool pool, ArgList args)
@@ -94,6 +94,8 @@ static Res MFSInit(Pool pool, ArgList args)
if (ArgPick(&arg, args, MFSExtendSelf))
extendSelf = arg.val.b;
+ AVER(unitSize > 0);
+ AVER(extendBy > 0);
AVERT(Bool, extendSelf);
mfs = PoolPoolMFS(pool);
diff --git a/mps/code/poolmv.c b/mps/code/poolmv.c
index 709dfb6bf7b..19b3c2bb443 100644
--- a/mps/code/poolmv.c
+++ b/mps/code/poolmv.c
@@ -1,7 +1,7 @@
/* poolmv.c: MANUAL VARIABLE POOL
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
* **** RESTRICTION: This pool may not allocate from the arena control
@@ -260,7 +260,7 @@ static Res MVInit(Pool pool, ArgList args)
res = PoolInit(mvBlockPool(mv), arena, PoolClassMFS(), piArgs);
} MPS_ARGS_END(piArgs);
if(res != ResOK)
- return res;
+ goto failBlockPoolInit;
spanExtendBy = sizeof(MVSpanStruct) * (maxSize/extendBy);
@@ -270,7 +270,7 @@ static Res MVInit(Pool pool, ArgList args)
res = PoolInit(mvSpanPool(mv), arena, PoolClassMFS(), piArgs);
} MPS_ARGS_END(piArgs);
if(res != ResOK)
- return res;
+ goto failSpanPoolInit;
mv->extendBy = extendBy;
mv->avgSize = avgSize;
@@ -284,6 +284,11 @@ static Res MVInit(Pool pool, ArgList args)
AVERT(MV, mv);
EVENT5(PoolInitMV, pool, arena, extendBy, avgSize, maxSize);
return ResOK;
+
+failSpanPoolInit:
+ PoolFinish(mvBlockPool(mv));
+failBlockPoolInit:
+ return res;
}
@@ -913,7 +918,7 @@ Bool MVCheck(MV mv)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c
index a54e004aae0..95c3e9ecc9a 100644
--- a/mps/code/poolmv2.c
+++ b/mps/code/poolmv2.c
@@ -215,11 +215,11 @@ static void MVTVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs)
* minSize, meanSize, maxSize, reserveDepth, fragLimit
*/
-ARG_DEFINE_KEY(mvt_min_size, Size);
-ARG_DEFINE_KEY(mvt_mean_size, Size);
-ARG_DEFINE_KEY(mvt_max_size, Size);
-ARG_DEFINE_KEY(mvt_reserve_depth, Count);
-ARG_DEFINE_KEY(mvt_frag_limit, double);
+ARG_DEFINE_KEY(MVT_MIN_SIZE, Size);
+ARG_DEFINE_KEY(MVT_MEAN_SIZE, Size);
+ARG_DEFINE_KEY(MVT_MAX_SIZE, Size);
+ARG_DEFINE_KEY(MVT_RESERVE_DEPTH, Count);
+ARG_DEFINE_KEY(MVT_FRAG_LIMIT, double);
static Res MVTInit(Pool pool, ArgList args)
{
diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c
index eaf2c5e116d..22b6d004f68 100644
--- a/mps/code/poolmvff.c
+++ b/mps/code/poolmvff.c
@@ -122,7 +122,7 @@ static void MVFFReduce(MVFF mvff)
targetFree = freeLimit / 2;
/* Each time around this loop we either break, or we free at least
- one page back to the arena, thus ensuring that eventually the
+ one grain back to the arena, thus ensuring that eventually the
loop will terminate */
/* NOTE: If this code becomes very hot, then the test of whether there's
@@ -133,7 +133,7 @@ static void MVFFReduce(MVFF mvff)
&& LandFindLargest(&freeRange, &oldFreeRange, MVFFFreeLand(mvff),
grainSize, FindDeleteNONE))
{
- RangeStruct pageRange, oldRange;
+ RangeStruct grainRange, oldRange;
Size size;
Res res;
Addr base, limit;
@@ -143,7 +143,7 @@ static void MVFFReduce(MVFF mvff)
base = AddrAlignUp(RangeBase(&freeRange), grainSize);
limit = AddrAlignDown(RangeLimit(&freeRange), grainSize);
- /* Give up if this block doesn't contain a whole aligned page,
+ /* Give up if this block doesn't contain a whole aligned grain,
even though smaller better-aligned blocks might, because
LandFindLargest won't be able to find those anyway. */
if (base >= limit)
@@ -155,12 +155,12 @@ static void MVFFReduce(MVFF mvff)
if (size > freeSize - targetFree)
size = SizeAlignUp(freeSize - targetFree, grainSize);
- /* Calculate the range of pages we can return to the arena near the
+ /* Calculate the range of grains we can return to the arena near the
top end of the free memory (because we're first fit). */
- RangeInit(&pageRange, AddrSub(limit, size), limit);
- AVER(!RangeIsEmpty(&pageRange));
- AVER(RangesNest(&freeRange, &pageRange));
- AVER(RangeIsAligned(&pageRange, grainSize));
+ RangeInit(&grainRange, AddrSub(limit, size), limit);
+ AVER(!RangeIsEmpty(&grainRange));
+ AVER(RangesNest(&freeRange, &grainRange));
+ AVER(RangeIsAligned(&grainRange, grainSize));
/* Delete the range from the free list before attempting to delete
it from the total allocated memory, so that we don't have
@@ -168,21 +168,21 @@ static void MVFFReduce(MVFF mvff)
to delete from the TotalCBS we add back to the free list, which
can't fail. */
- res = LandDelete(&oldRange, MVFFFreeLand(mvff), &pageRange);
+ res = LandDelete(&oldRange, MVFFFreeLand(mvff), &grainRange);
if (res != ResOK)
break;
- freeSize -= RangeSize(&pageRange);
+ freeSize -= RangeSize(&grainRange);
AVER(freeSize == LandSize(MVFFFreeLand(mvff)));
- res = LandDelete(&oldRange, MVFFTotalLand(mvff), &pageRange);
+ res = LandDelete(&oldRange, MVFFTotalLand(mvff), &grainRange);
if (res != ResOK) {
RangeStruct coalescedRange;
- res = LandInsert(&coalescedRange, MVFFFreeLand(mvff), &pageRange);
+ res = LandInsert(&coalescedRange, MVFFFreeLand(mvff), &grainRange);
AVER(res == ResOK);
break;
}
- ArenaFree(RangeBase(&pageRange), RangeSize(&pageRange), MVFFPool(mvff));
+ ArenaFree(RangeBase(&grainRange), RangeSize(&grainRange), MVFFPool(mvff));
}
}
@@ -445,9 +445,9 @@ static void MVFFDebugVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs)
/* MVFFInit -- initialize method for MVFF */
-ARG_DEFINE_KEY(mvff_slot_high, Bool);
-ARG_DEFINE_KEY(mvff_arena_high, Bool);
-ARG_DEFINE_KEY(mvff_first_fit, Bool);
+ARG_DEFINE_KEY(MVFF_SLOT_HIGH, Bool);
+ARG_DEFINE_KEY(MVFF_ARENA_HIGH, Bool);
+ARG_DEFINE_KEY(MVFF_FIRST_FIT, Bool);
static Res MVFFInit(Pool pool, ArgList args)
{
@@ -520,7 +520,7 @@ static Res MVFFInit(Pool pool, ArgList args)
LocusPrefInit(MVFFLocusPref(mvff));
LocusPrefExpress(MVFFLocusPref(mvff),
- arenaHigh ? LocusPrefHigh : LocusPrefLow, NULL);
+ arenaHigh ? LocusPrefHIGH : LocusPrefLOW, NULL);
/* An MFS pool is explicitly initialised for the two CBSs partly to
* share space, but mostly to avoid a call to PoolCreate, so that
@@ -595,6 +595,7 @@ static Bool mvffFinishVisitor(Bool *deleteReturn, Land land, Range range,
AVER(closureP != NULL);
pool = closureP;
AVERT(Pool, pool);
+ AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
ArenaFree(RangeBase(range), RangeSize(range), pool);
@@ -612,7 +613,8 @@ static void MVFFFinish(Pool pool)
AVERT(MVFF, mvff);
mvff->sig = SigInvalid;
- b = LandIterateAndDelete(MVFFTotalLand(mvff), mvffFinishVisitor, pool, 0);
+ b = LandIterateAndDelete(MVFFTotalLand(mvff), mvffFinishVisitor, pool,
+ UNUSED_SIZE);
AVER(b);
AVER(LandSize(MVFFTotalLand(mvff)) == 0);
diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c
index 676ab7e01f8..f507d41222b 100644
--- a/mps/code/poolsnc.c
+++ b/mps/code/poolsnc.c
@@ -387,6 +387,7 @@ static Res SNCInit(Pool pool, ArgList args)
format = arg.val.format;
AVERT(Format, format);
+ AVER(FormatArena(format) == PoolArena(pool));
pool->format = format;
snc->freeSegs = NULL;
snc->sig = SNCSig;
@@ -624,7 +625,7 @@ static void SNCFramePopPending(Pool pool, Buffer buf, AllocFrame frame)
}
-static void SNCWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f,
+static void SNCWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
void *p, size_t s)
{
AVERT(Pool, pool);
diff --git a/mps/code/prmci3fr.c b/mps/code/prmci3fr.c
index 6dbe5de09ae..75cf94e871f 100644
--- a/mps/code/prmci3fr.c
+++ b/mps/code/prmci3fr.c
@@ -1,7 +1,7 @@
/* prmci3fr.c: PROTECTION MUTATOR CONTEXT INTEL 386 (FREEBSD)
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* .purpose: This module implements the part of the protection module
* that decodes the MutatorFaultContext.
@@ -15,10 +15,10 @@
*
* ASSUMPTIONS
*
- * .sp: The stack pointer in the context is ESP (x86) or RSP (x86_64).
+ * .sp: The stack pointer in the context is ESP.
*
- * .context.regroots: The root regs are EDI, ESI, EBX, EDX, ECX, EAX (or
- * their x86_64 equivalents) are assumed to be recorded in the context at
+ * .context.regroots: The root regs are EDI, ESI, EBX, EDX, ECX, EAX,
+ * and they are assumed to be recorded in the context at
* pointer-aligned boundaries.
*/
@@ -27,6 +27,10 @@
SRCID(prmci3fr, "$Id$");
+#if !defined(MPS_OS_FR) || !defined(MPS_ARCH_I3)
+#error "prmci3fr.c is specific to MPS_OS_FR and MPS_ARCH_I3"
+#endif
+
Addr MutatorFaultContextSP(MutatorFaultContext mfc)
{
@@ -53,7 +57,7 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/prmci3li.c b/mps/code/prmci3li.c
index 5b5d150b8cc..08737d363c3 100644
--- a/mps/code/prmci3li.c
+++ b/mps/code/prmci3li.c
@@ -17,12 +17,12 @@
*
* ASSUMPTIONS
*
- * .sp: The stack pointer in the context is uc_stack.ss_sp.
+ * .sp: The stack pointer in the context is ESP.
*
* .context.regroots: The root regs are assumed to be recorded in the context
* at pointer-aligned boundaries.
*
- * .assume.regref: The resisters in the context can be modified by
+ * .assume.regref: The registers in the context can be modified by
* storing into an MRef pointer.
*/
@@ -31,6 +31,10 @@
SRCID(prmci3li, "$Id$");
+#if !defined(MPS_OS_LI) || !defined(MPS_ARCH_I3)
+#error "prmci3li.c is specific to MPS_OS_LI and MPS_ARCH_I3"
+#endif
+
/* Prmci3AddressHoldingReg -- return an address of a register in a context */
diff --git a/mps/code/prmci3w3.c b/mps/code/prmci3w3.c
index 4cf9584c988..4f85f677a81 100644
--- a/mps/code/prmci3w3.c
+++ b/mps/code/prmci3w3.c
@@ -1,4 +1,4 @@
-/* prmci3w3.c: PROTECTION MUTATOR CONTEXT INTEL 386 (Win32)
+/* prmci3w3.c: PROTECTION MUTATOR CONTEXT INTEL 386 (Windows)
*
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
@@ -15,7 +15,7 @@
*
* ASSUMPTIONS
*
- * .assume.regref: The resisters in the context can be modified by
+ * .assume.regref: The registers in the context can be modified by
* storing into an MRef pointer.
*/
@@ -25,6 +25,10 @@
SRCID(prmci3w3, "$Id$");
+#if !defined(MPS_OS_W3) || !defined(MPS_ARCH_I3)
+#error "prmci3w3.c is specific to MPS_OS_W3 and MPS_ARCH_I3"
+#endif
+
/* Prmci3AddressHoldingReg -- Return an address for a given machine register */
diff --git a/mps/code/prmci3xc.c b/mps/code/prmci3xc.c
index eafeff61540..67f3f5822df 100644
--- a/mps/code/prmci3xc.c
+++ b/mps/code/prmci3xc.c
@@ -20,14 +20,18 @@
* .context.regroots: The root regs are assumed to be recorded in the context
* at pointer-aligned boundaries.
*
- * .assume.regref: The resisters in the context can be modified by
+ * .assume.regref: The registers in the context can be modified by
* storing into an MRef pointer.
*/
#include "prmcxc.h"
#include "prmci3.h"
-SRCID(prmci3li, "$Id$");
+SRCID(prmci3xc, "$Id$");
+
+#if !defined(MPS_OS_XC) || !defined(MPS_ARCH_I3)
+#error "prmci3xc.c is specific to MPS_OS_XC and MPS_ARCH_I3"
+#endif
/* Prmci3AddressHoldingReg -- return an address of a register in a context */
diff --git a/mps/code/prmci6fr.c b/mps/code/prmci6fr.c
index 811d2c8f99d..db20d01216b 100644
--- a/mps/code/prmci6fr.c
+++ b/mps/code/prmci6fr.c
@@ -1,7 +1,7 @@
/* prmci6li.c: PROTECTION MUTATOR CONTEXT x64 (FREEBSD)
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* .purpose: This module implements the part of the protection module
* that decodes the MutatorFaultContext.
@@ -9,10 +9,10 @@
*
* ASSUMPTIONS
*
- * .sp: The stack pointer in the context is ESP (x86) or RSP (x86_64).
+ * .sp: The stack pointer in the context is RSP.
*
- * .context.regroots: The root regs are EDI, ESI, EBX, EDX, ECX, EAX (or
- * their x86_64 equivalents) are assumed to be recorded in the context at
+ * .context.regroots: The root regs are RDI, RSI, RBX, RDX, RCX, RAX,
+ * and they are assumed to be recorded in the context at
* pointer-aligned boundaries.
*/
@@ -21,6 +21,10 @@
SRCID(prmci6fr, "$Id$");
+#if !defined(MPS_OS_FR) || !defined(MPS_ARCH_I6)
+#error "prmci6fr.c is specific to MPS_OS_FR and MPS_ARCH_I6"
+#endif
+
Addr MutatorFaultContextSP(MutatorFaultContext mfc)
{
@@ -47,7 +51,7 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/prmci6li.c b/mps/code/prmci6li.c
index c00c1359014..38b11c3a627 100644
--- a/mps/code/prmci6li.c
+++ b/mps/code/prmci6li.c
@@ -14,12 +14,12 @@
*
* ASSUMPTIONS
*
- * .sp: The stack pointer in the context is uc_stack.ss_sp.
+ * .sp: The stack pointer in the context is RSP.
*
* .context.regroots: The root regs are assumed to be recorded in the context
* at pointer-aligned boundaries.
*
- * .assume.regref: The resisters in the context can be modified by
+ * .assume.regref: The registers in the context can be modified by
* storing into an MRef pointer.
*/
@@ -28,6 +28,10 @@
SRCID(prmci6li, "$Id$");
+#if !defined(MPS_OS_LI) || !defined(MPS_ARCH_I6)
+#error "prmci6li.c is specific to MPS_OS_LI and MPS_ARCH_I6"
+#endif
+
/* Prmci6AddressHoldingReg -- return an address of a register in a context */
@@ -75,7 +79,7 @@ MRef Prmci6AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum)
}
-/* Prmci3DecodeFaultContext -- decode fault to find faulting address and IP */
+/* Prmci6DecodeFaultContext -- decode fault to find faulting address and IP */
void Prmci6DecodeFaultContext(MRef *faultmemReturn,
Byte **insvecReturn,
@@ -87,7 +91,7 @@ void Prmci6DecodeFaultContext(MRef *faultmemReturn,
}
-/* Prmci3StepOverIns -- modify context to step over instruction */
+/* Prmci6StepOverIns -- modify context to step over instruction */
void Prmci6StepOverIns(MutatorFaultContext mfc, Size inslen)
{
diff --git a/mps/code/prmci6w3.c b/mps/code/prmci6w3.c
index 81641c00526..9fa31ed3187 100644
--- a/mps/code/prmci6w3.c
+++ b/mps/code/prmci6w3.c
@@ -1,4 +1,4 @@
-/* prmci6w3.c: PROTECTION MUTATOR CONTEXT INTEL 386 (Win32)
+/* prmci6w3.c: PROTECTION MUTATOR CONTEXT INTEL x64 (Windows)
*
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
@@ -13,7 +13,7 @@
*
* ASSUMPTIONS
*
- * .assume.regref: The resisters in the context can be modified by
+ * .assume.regref: The registers in the context can be modified by
* storing into an MRef pointer.
*/
@@ -23,6 +23,10 @@
SRCID(prmci6w3, "$Id$");
+#if !defined(MPS_OS_W3) || !defined(MPS_ARCH_I6)
+#error "prmci6w3.c is specific to MPS_OS_W3 and MPS_ARCH_I6"
+#endif
+
/* Prmci6AddressHoldingReg -- Return an address for a given machine register */
diff --git a/mps/code/prmci6xc.c b/mps/code/prmci6xc.c
index 131447cd0cc..4d3a5afe156 100644
--- a/mps/code/prmci6xc.c
+++ b/mps/code/prmci6xc.c
@@ -1,4 +1,4 @@
-/* prmci6xc.c: PROTECTION MUTATOR CONTEXT x64 (MAC OS X)
+/* prmci6xc.c: PROTECTION MUTATOR CONTEXT x64 (OS X)
*
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
@@ -9,22 +9,26 @@
*
* SOURCES
*
- * .source.linux.kernel: Linux kernel source files.
- *
*
* ASSUMPTIONS
*
+ * .sp: The stack pointer in the context is RSP.
+ *
* .context.regroots: The root regs are assumed to be recorded in the context
* at pointer-aligned boundaries.
*
- * .assume.regref: The resisters in the context can be modified by
+ * .assume.regref: The registers in the context can be modified by
* storing into an MRef pointer.
*/
#include "prmcxc.h"
#include "prmci6.h"
-SRCID(prmci6li, "$Id$");
+SRCID(prmci6xc, "$Id$");
+
+#if !defined(MPS_OS_XC) || !defined(MPS_ARCH_I6)
+#error "prmci6xc.c is specific to MPS_OS_XC and MPS_ARCH_I6"
+#endif
/* Prmci6AddressHoldingReg -- return an address of a register in a context */
@@ -70,7 +74,7 @@ MRef Prmci6AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum)
}
-/* Prmci3DecodeFaultContext -- decode fault to find faulting address and IP */
+/* Prmci6DecodeFaultContext -- decode fault to find faulting address and IP */
void Prmci6DecodeFaultContext(MRef *faultmemReturn,
Byte **insvecReturn,
@@ -81,7 +85,7 @@ void Prmci6DecodeFaultContext(MRef *faultmemReturn,
}
-/* Prmci3StepOverIns -- modify context to step over instruction */
+/* Prmci6StepOverIns -- modify context to step over instruction */
void Prmci6StepOverIns(MutatorFaultContext mfc, Size inslen)
{
diff --git a/mps/code/prot.h b/mps/code/prot.h
new file mode 100644
index 00000000000..7191cd01e86
--- /dev/null
+++ b/mps/code/prot.h
@@ -0,0 +1,78 @@
+/* prot.h: MEMORY PROTECTION INTERFACE
+ *
+ * $Id: //info.ravenbrook.com/project/mps/master/code/prot.h#1 $
+ * Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
+ *
+ * See for the design of the generic interface including
+ * the contracts for these functions.
+ *
+ * This interface has several different implementations, typically one
+ * per platform, see for the various implementations,
+ * and for the corresponding designs.
+ */
+
+#ifndef prot_h
+#define prot_h
+
+#include "mpmtypes.h"
+
+
+/* Protection Interface */
+
+extern void ProtSetup(void);
+extern Size ProtGranularity(void);
+extern void ProtSet(Addr base, Addr limit, AccessSet mode);
+extern void ProtSync(Arena arena);
+
+
+/* Mutator Fault Context */
+
+extern Bool ProtCanStepInstruction(MutatorFaultContext context);
+extern Res ProtStepInstruction(MutatorFaultContext context);
+extern Addr MutatorFaultContextSP(MutatorFaultContext mfc);
+extern Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc);
+
+
+#endif /* prot_h */
+
+
+/* C. COPYRIGHT AND LICENSE
+ *
+ * Copyright (C) 2014 Ravenbrook Limited .
+ * All rights reserved. This is an open source license. Contact
+ * Ravenbrook for commercial licensing options.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Redistributions in any form must be accompanied by information on how
+ * to obtain complete source code for this software and any accompanying
+ * software that uses this software. The source code must either be
+ * included in the distribution or be available for no more than the cost
+ * of distribution plus a nominal fee, and must be freely redistributable
+ * under reasonable conditions. For an executable file, complete source
+ * code means the source code for all modules it contains. It does not
+ * include source code for modules or files that typically accompany the
+ * major components of the operating system on which the executable file
+ * runs.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
diff --git a/mps/code/protan.c b/mps/code/protan.c
index 1959e42395b..0e4771f18da 100644
--- a/mps/code/protan.c
+++ b/mps/code/protan.c
@@ -1,7 +1,7 @@
/* protan.c: ANSI MEMORY PROTECTION
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
*
* DESIGN
@@ -36,8 +36,7 @@ Size ProtGranularity(void)
void ProtSet(Addr base, Addr limit, AccessSet pm)
{
AVER(base < limit);
- /* .improve.protset.check: There is nor AccessSetCheck, so we */
- /* don't check it. */
+ AVERT(AccessSet, pm);
UNUSED(pm);
NOOP;
}
@@ -74,7 +73,7 @@ void ProtSync(Arena arena)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/proti3.c b/mps/code/proti3.c
index d3a13aef299..76f7f7965f1 100644
--- a/mps/code/proti3.c
+++ b/mps/code/proti3.c
@@ -1,7 +1,7 @@
/* proti3.c: PROTECTION MUTATOR CONTEXT (INTEL 386)
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* .design: See for the generic design of the interface
* which is implemented in this module, including the contracts for the
@@ -54,6 +54,10 @@
SRCID(proti3, "$Id$");
+#if !defined(MPS_ARCH_I3)
+#error "proti3.c is specific to MPS_ARCH_I3"
+#endif
+
/* DecodeCB -- Decode an Intel x86 control byte into Hi, Medium & Low fields */
@@ -243,7 +247,7 @@ Res ProtStepInstruction(MutatorFaultContext context)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/proti6.c b/mps/code/proti6.c
index 37940f1103e..a681c51e63f 100644
--- a/mps/code/proti6.c
+++ b/mps/code/proti6.c
@@ -1,7 +1,7 @@
/* proti6.c: PROTECTION MUTATOR CONTEXT (x64)
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* .design: See for the generic design of the interface
* which is implemented in this module, including the contracts for the
@@ -31,6 +31,10 @@
SRCID(proti6, "$Id$");
+#if !defined(MPS_ARCH_I6)
+#error "proti6.c is specific to MPS_ARCH_I6"
+#endif
+
static Bool IsSimpleMov(Size *inslenReturn,
MRef *srcReturn,
@@ -84,7 +88,7 @@ Res ProtStepInstruction(MutatorFaultContext context)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/protix.c b/mps/code/protix.c
index a07350bedc6..a243b009491 100644
--- a/mps/code/protix.c
+++ b/mps/code/protix.c
@@ -1,14 +1,14 @@
/* protix.c: PROTECTION FOR UNIX
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
* Somewhat generic across different Unix systems. Shared between
- * Darwin (OS X), FreeBSD, and Linux.
+ * OS X, FreeBSD, and Linux.
*
- * This file does not contain a signal handler. That's in protsgix.c
- * (for FreeBSD and Darwin on Intel); in protxcpp.c (for Darwin on
- * PowerPC); in protlii3.c (for Intel Linux).
+ * This file does not contain a signal handler. That's in protsgix.c for
+ * historical reasons (there used to be separate implementations for the
+ * different flavours of Unix).
*
*
* SOURCES
@@ -20,12 +20,11 @@
* ASSUMPTIONS
*
* .assume.mprotect.base: We assume that the first argument to mprotect can
- * be safely passed as a void *. Single UNIX Specification Version 2
- * (aka X/OPEN XSH5) says that the parameter is a void *. Some
- * Unix-likes may declare this parameter as a caddr_t. FreeBSD used to
- * do this (on the now very obsolete FreeBSD 2.2.x series). The
- * Darwin man page documents it as caddr_t but it appears to be
- * implemented correctly as void *. caddr_t is usually char *.
+ * be safely passed as a void *. Single UNIX Specification Version 2 (aka
+ * X/OPEN XSH5) says that the parameter is a void *. Some Unix-likes may
+ * declare this parameter as a caddr_t. FreeBSD used to do this (on the now
+ * very obsolete FreeBSD 2.2.x series), as did OS X, but both now implement
+ * it correctly as void *. caddr_t is usually char *.
*
* .assume.write-only: More of an anti-assumption really. We
* assume that asking the OS for a write-only page (that is, flags =
@@ -67,6 +66,7 @@ void ProtSet(Addr base, Addr limit, AccessSet mode)
AVER(base < limit);
AVER(base != 0);
AVER(AddrOffset(base, limit) <= INT_MAX); /* should be redundant */
+ AVERT(AccessSet, mode);
/* Convert between MPS AccessSet and UNIX PROT thingies.
In this function, AccessREAD means protect against read accesses
@@ -123,7 +123,7 @@ Size ProtGranularity(void)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/protli.c b/mps/code/protli.c
index 1881cdd4f77..e157fe9875f 100644
--- a/mps/code/protli.c
+++ b/mps/code/protli.c
@@ -1,13 +1,10 @@
-/* protli.c: PROTECTION FOR LINUX (INTEL 386)
+/* protli.c: PROTECTION FOR LINUX
*
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* SOURCES
*
- * .source.i486: Intel486 Microprocessor Family Programmer's
- * Reference Manual
- *
* .source.linux.kernel: Linux kernel source files.
*/
@@ -25,6 +22,9 @@
SRCID(protli, "$Id$");
+#if !defined(MPS_OS_LI)
+#error "protli.c is specific to MPS_OS_LI"
+#endif
/* The previously-installed signal action, as returned by */
diff --git a/mps/code/protsgix.c b/mps/code/protsgix.c
index 680aa6c63e2..f74a840f6bb 100644
--- a/mps/code/protsgix.c
+++ b/mps/code/protsgix.c
@@ -3,9 +3,11 @@
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
- * Would ordinarily be part of protix.c (as the code is common to more
- * than one Unix-like operating system), but PowerPC Darwin requires a
- * different implementation of this module.
+ * This implements protection exception handling using POSIX signals.
+ * It is designed to run on any POSIX-compliant Unix, but currently is
+ * only used on FreeBSD, as we have separate implementions for OS X
+ * (see protxc.c) and Linux (see protli.c).
+ *
*
* SOURCES
*
@@ -18,11 +20,8 @@
#include "mpm.h"
-#if !defined(MPS_OS_XC) && !defined(MPS_OS_FR)
-#error "protsgix.c is Unix-specific, currently for MPS_OS_FR or XC"
-#endif
-#if defined(MPS_OS_XC) && defined(MPS_ARCH_PP)
-#error "protsgix.c does not work on Darwin on PowerPC. Use protxcpp.c"
+#if !defined(MPS_OS_FR)
+#error "protsgix.c is Unix-specific, currently for MPS_OS_FR"
#endif
#include /* for many functions */
diff --git a/mps/code/protw3.c b/mps/code/protw3.c
index 30c3edc0975..a8dddd74fe2 100644
--- a/mps/code/protw3.c
+++ b/mps/code/protw3.c
@@ -1,7 +1,7 @@
/* protw3.c: PROTECTION FOR WIN32
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*/
#include "mpm.h"
@@ -26,6 +26,7 @@ void ProtSet(Addr base, Addr limit, AccessSet mode)
AVER(base < limit);
AVER(base != 0);
+ AVERT(AccessSet, mode);
newProtect = PAGE_EXECUTE_READWRITE;
if((mode & AccessWRITE) != 0)
@@ -140,7 +141,7 @@ void ProtSync(Arena arena)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/reserv.c b/mps/code/reserv.c
index b0d431c3f9c..91a2fd52559 100644
--- a/mps/code/reserv.c
+++ b/mps/code/reserv.c
@@ -100,6 +100,7 @@ Bool ReservoirCheck(Reservoir reservoir)
}
CHECKL(SizeIsArenaGrains(reservoir->reservoirLimit, arena));
CHECKL(SizeIsArenaGrains(reservoir->reservoirSize, arena));
+ CHECKL(reservoir->reservoirSize <= reservoir->reservoirLimit);
return TRUE;
}
diff --git a/mps/code/root.c b/mps/code/root.c
index 71813ec9015..7a3e1205be2 100644
--- a/mps/code/root.c
+++ b/mps/code/root.c
@@ -1,7 +1,7 @@
/* root.c: ROOT IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
* .purpose: This is the implementation of the root datatype.
*
@@ -139,7 +139,7 @@ Bool RootCheck(Root root)
CHECKL(root->protBase != (Addr)0);
CHECKL(root->protLimit != (Addr)0);
CHECKL(root->protBase < root->protLimit);
- /* there is no AccessSetCheck */
+ CHECKL(AccessSetCheck(root->pm));
} else {
CHECKL(root->protBase == (Addr)0);
CHECKL(root->protLimit == (Addr)0);
@@ -263,7 +263,9 @@ Res RootCreateTable(Root *rootReturn, Arena arena,
AVERT(Arena, arena);
AVERT(Rank, rank);
AVER(base != 0);
- AVER(base < limit);
+ AVER(AddrIsAligned(base, sizeof(Word)));
+ AVER(base < limit);
+ AVER(AddrIsAligned(limit, sizeof(Word)));
theUnion.table.base = base;
theUnion.table.limit = limit;
@@ -304,6 +306,7 @@ Res RootCreateReg(Root *rootReturn, Arena arena,
AVERT(Arena, arena);
AVERT(Rank, rank);
AVERT(Thread, thread);
+ AVER(ThreadArena(thread) == arena);
AVER(scan != NULL);
theUnion.reg.scan = scan;
@@ -314,6 +317,13 @@ Res RootCreateReg(Root *rootReturn, Arena arena,
return rootCreate(rootReturn, arena, rank, (RootMode)0, RootREG, &theUnion);
}
+/* RootCreateFmt -- create root from block of formatted objects
+ *
+ * .fmt.no-align-check: Note that we don't check the alignment of base
+ * and limit. That's because we're only given the scan function, so we
+ * don't know the format's alignment requirements.
+ */
+
Res RootCreateFmt(Root *rootReturn, Arena arena,
Rank rank, RootMode mode, mps_fmt_scan_t scan,
Addr base, Addr limit)
@@ -374,9 +384,9 @@ void RootDestroy(Root root)
}
-/* RootArena -- return the rank of a root
+/* RootArena -- return the arena of a root
*
- * Must be thread-safe. */
+ * Must be thread-safe. See */
Arena RootArena(Root root)
{
@@ -548,7 +558,7 @@ Bool RootOfAddr(Root *rootReturn, Arena arena, Addr addr)
void RootAccess(Root root, AccessSet mode)
{
AVERT(Root, root);
- /* Can't AVERT mode. */
+ AVERT(AccessSet, mode);
AVER((root->pm & mode) != AccessSetEMPTY);
AVER(mode == AccessWRITE); /* only write protection supported */
@@ -697,7 +707,7 @@ Res RootsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/seg.c b/mps/code/seg.c
index cab4456f1d9..7007bca62b7 100644
--- a/mps/code/seg.c
+++ b/mps/code/seg.c
@@ -1,7 +1,7 @@
/* seg.c: SEGMENTS
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
* .design: The design for this module is .
*
@@ -529,7 +529,7 @@ Bool SegNextOfRing(Seg *segReturn, Arena arena, Pool pool, Ring next)
AVER_CRITICAL(segReturn != NULL); /* .seg.critical */
AVERT_CRITICAL(Arena, arena);
AVERT_CRITICAL(Pool, pool);
- AVER_CRITICAL(RingCheck(next));
+ AVERT_CRITICAL(Ring, next);
if (next == PoolSegRing(pool)) {
if (!PoolNext(&pool, arena, pool) ||
@@ -1174,7 +1174,7 @@ static void gcSegSetGreyInternal(Seg seg, TraceSet oldGrey, TraceSet grey)
if (oldGrey == TraceSetEMPTY) {
if (grey != TraceSetEMPTY) {
AVER(RankSetIsSingle(seg->rankSet));
- for(rank = 0; rank < RankLIMIT; ++rank)
+ for(rank = RankMIN; rank < RankLIMIT; ++rank)
if (RankSetIsMember(seg->rankSet, rank)) {
/* NOTE: We push the segment onto the front of the queue, so that
we preserve some locality of scanning, and so that we tend to
@@ -1224,7 +1224,7 @@ static void gcSegSetGrey(Seg seg, TraceSet grey)
Arena arena;
AVERT_CRITICAL(Seg, seg); /* .seg.method.check */
- AVER_CRITICAL(TraceSetCheck(grey)); /* .seg.method.check */
+ AVERT_CRITICAL(TraceSet, grey); /* .seg.method.check */
AVER(seg->rankSet != RankSetEMPTY);
gcseg = SegGCSeg(seg);
AVERT_CRITICAL(GCSeg, gcseg);
@@ -1264,7 +1264,7 @@ static void gcSegSetWhite(Seg seg, TraceSet white)
Addr addr, limit;
AVERT_CRITICAL(Seg, seg); /* .seg.method.check */
- AVER_CRITICAL(TraceSetCheck(white)); /* .seg.method.check */
+ AVERT_CRITICAL(TraceSet, white); /* .seg.method.check */
gcseg = SegGCSeg(seg);
AVERT_CRITICAL(GCSeg, gcseg);
AVER_CRITICAL(&gcseg->segStruct == seg);
@@ -1307,7 +1307,7 @@ static void gcSegSetRankSet(Seg seg, RankSet rankSet)
Arena arena;
AVERT_CRITICAL(Seg, seg); /* .seg.method.check */
- AVER_CRITICAL(RankSetCheck(rankSet)); /* .seg.method.check */
+ AVERT_CRITICAL(RankSet, rankSet); /* .seg.method.check */
AVER_CRITICAL(rankSet == RankSetEMPTY
|| RankSetIsSingle(rankSet)); /* .seg.method.check */
gcseg = SegGCSeg(seg);
@@ -1378,7 +1378,7 @@ static void gcSegSetRankSummary(Seg seg, RankSet rankSet, RefSet summary)
Arena arena;
AVERT_CRITICAL(Seg, seg); /* .seg.method.check */
- AVER_CRITICAL(RankSetCheck(rankSet)); /* .seg.method.check */
+ AVERT_CRITICAL(RankSet, rankSet); /* .seg.method.check */
AVER_CRITICAL(rankSet == RankSetEMPTY
|| RankSetIsSingle(rankSet)); /* .seg.method.check */
gcseg = SegGCSeg(seg);
@@ -1701,7 +1701,7 @@ void SegClassMixInNoSplitMerge(SegClass class)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/shield.c b/mps/code/shield.c
index 55625664ca7..0dfc1945db6 100644
--- a/mps/code/shield.c
+++ b/mps/code/shield.c
@@ -1,7 +1,7 @@
/* shield.c: SHIELD IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
* See: idea.shield, design.mps.shield.
*
@@ -83,7 +83,7 @@ void (ShieldSuspend)(Arena arena)
AVER(arena->insideShield);
if (!arena->suspended) {
- ThreadRingSuspend(ArenaThreadRing(arena));
+ ThreadRingSuspend(ArenaThreadRing(arena), ArenaDeadRing(arena));
arena->suspended = TRUE;
}
}
@@ -105,6 +105,7 @@ static void protLower(Arena arena, Seg seg, AccessSet mode)
AVERT_CRITICAL(Arena, arena);
UNUSED(arena);
AVERT_CRITICAL(Seg, seg);
+ AVERT_CRITICAL(AccessSet, mode);
if (SegPM(seg) & mode) {
SegSetPM(seg, SegPM(seg) & ~mode);
@@ -191,6 +192,7 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode)
/* can't check seg. Nor can we check arena as that checks the */
/* segs in the cache. */
+ AVERT(AccessSet, mode);
AVER((SegSM(seg) & mode) == AccessSetEMPTY);
SegSetSM(seg, SegSM(seg) | mode); /* inv.prot.shield preserved */
@@ -204,6 +206,7 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode)
void (ShieldLower)(Arena arena, Seg seg, AccessSet mode)
{
/* Don't check seg or arena, see .seg.broken */
+ AVERT(AccessSet, mode);
AVER((SegSM(seg) & mode) == mode);
/* synced(seg) is not changed by the following
* preserving inv.unsynced.suspended
@@ -263,7 +266,7 @@ void (ShieldLeave)(Arena arena)
/* Ensuring the mutator is running at this point
* guarantees inv.outside.running */
if (arena->suspended) {
- ThreadRingResume(ArenaThreadRing(arena));
+ ThreadRingResume(ArenaThreadRing(arena), ArenaDeadRing(arena));
arena->suspended = FALSE;
}
arena->insideShield = FALSE;
@@ -336,7 +339,7 @@ void (ShieldCover)(Arena arena, Seg seg)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/sp.h b/mps/code/sp.h
new file mode 100644
index 00000000000..e2a8bef4507
--- /dev/null
+++ b/mps/code/sp.h
@@ -0,0 +1,69 @@
+/* sp.h: STACK PROBE INTERFACE
+ *
+ * $Id: //info.ravenbrook.com/project/mps/master/code/sp.h#1 $
+ * Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
+ */
+
+#ifndef sp_h
+#define sp_h
+
+#include "mpmtypes.h"
+
+
+/* StackProbe -- probe above the stack to provoke early stack overflow
+ *
+ * This function should check that the stack has at least depth words
+ * available, and if not, then provoke a stack overflow exception or
+ * protection fault. The purpose is to ensure that the exception is
+ * generated before taking the arena lock where it can be handled
+ * safely, rather than at some later point where the arena lock is
+ * held and so handling the exception may cause the MPS to be entered
+ * recursively.
+ */
+
+extern void StackProbe(Size depth);
+
+
+#endif /* sp_h */
+
+
+/* C. COPYRIGHT AND LICENSE
+ *
+ * Copyright (C) 2014 Ravenbrook Limited .
+ * All rights reserved. This is an open source license. Contact
+ * Ravenbrook for commercial licensing options.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Redistributions in any form must be accompanied by information on how
+ * to obtain complete source code for this software and any accompanying
+ * software that uses this software. The source code must either be
+ * included in the distribution or be available for no more than the cost
+ * of distribution plus a nominal fee, and must be freely redistributable
+ * under reasonable conditions. For an executable file, complete source
+ * code means the source code for all modules it contains. It does not
+ * include source code for modules or files that typically accompany the
+ * major components of the operating system on which the executable file
+ * runs.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
diff --git a/mps/code/splay.c b/mps/code/splay.c
index fbcd3a4a771..ed46c7a4ba4 100644
--- a/mps/code/splay.c
+++ b/mps/code/splay.c
@@ -1,7 +1,7 @@
/* splay.c: SPLAY TREE IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
* .purpose: Splay trees are used to manage potentially unbounded
* collections of ordered things. In the MPS these are usually
@@ -9,10 +9,9 @@
*
* .source:
*
- * .note.stack: It's important that the MPS have a bounded stack
- * size, and this is a problem for tree algorithms. Basically,
- * we have to avoid recursion. TODO: Design documentation for this
- * requirement, meanwhile see job003651 and job003640.
+ * .note.stack: It's important that the MPS have a bounded stack size,
+ * and this is a problem for tree algorithms. Basically, we have to
+ * avoid recursion. See design.mps.sp.sol.depth.no-recursion.
*/
@@ -68,9 +67,9 @@ Bool SplayTreeCheck(SplayTree splay)
*/
void SplayTreeInit(SplayTree splay,
- TreeCompare compare,
- TreeKeyMethod nodeKey,
- SplayUpdateNodeMethod updateNode)
+ TreeCompareFunction compare,
+ TreeKeyFunction nodeKey,
+ SplayUpdateNodeFunction updateNode)
{
AVER(splay != NULL);
AVER(FUNCHECK(compare));
@@ -298,7 +297,8 @@ typedef struct SplayStateStruct {
*/
static Compare SplaySplitDown(SplayStateStruct *stateReturn,
- SplayTree splay, TreeKey key, TreeCompare compare)
+ SplayTree splay, TreeKey key,
+ TreeCompareFunction compare)
{
TreeStruct sentinel;
Tree middle, leftLast, rightFirst, leftPrev, rightNext;
@@ -503,7 +503,8 @@ static Tree SplayZagZagRev(Tree middle, Tree *leftLastIO)
*/
static Compare SplaySplitRev(SplayStateStruct *stateReturn,
- SplayTree splay, TreeKey key, TreeCompare compare)
+ SplayTree splay, TreeKey key,
+ TreeCompareFunction compare)
{
Tree middle, leftLast, rightFirst;
Compare cmp;
@@ -650,7 +651,8 @@ static void SplayAssembleRev(SplayTree splay, SplayState state)
/* SplaySplit -- call SplaySplitDown or SplaySplitRev as appropriate */
static Compare SplaySplit(SplayStateStruct *stateReturn,
- SplayTree splay, TreeKey key, TreeCompare compare)
+ SplayTree splay, TreeKey key,
+ TreeCompareFunction compare)
{
if (SplayHasUpdate(splay))
return SplaySplitRev(stateReturn, splay, key, compare);
@@ -688,7 +690,8 @@ static void SplayAssemble(SplayTree splay, SplayState state)
* See .
*/
-static Compare SplaySplay(SplayTree splay, TreeKey key, TreeCompare compare)
+static Compare SplaySplay(SplayTree splay, TreeKey key,
+ TreeCompareFunction compare)
{
Compare cmp;
SplayStateStruct stateStruct;
@@ -1020,7 +1023,7 @@ Tree SplayTreeNext(SplayTree splay, TreeKey oldKey) {
*/
static Res SplayNodeDescribe(Tree node, mps_lib_FILE *stream,
- TreeDescribeMethod nodeDescribe)
+ TreeDescribeFunction nodeDescribe)
{
Res res;
@@ -1083,8 +1086,8 @@ static Res SplayNodeDescribe(Tree node, mps_lib_FILE *stream,
*/
typedef struct SplayFindClosureStruct {
- SplayTestNodeMethod testNode;
- SplayTestTreeMethod testTree;
+ SplayTestNodeFunction testNode;
+ SplayTestTreeFunction testTree;
void *p;
Size s;
SplayTree splay;
@@ -1096,8 +1099,8 @@ static Compare SplayFindFirstCompare(Tree node, TreeKey key)
SplayFindClosure closure;
void *closureP;
Size closureS;
- SplayTestNodeMethod testNode;
- SplayTestTreeMethod testTree;
+ SplayTestNodeFunction testNode;
+ SplayTestTreeFunction testTree;
SplayTree splay;
AVERT(Tree, node);
@@ -1137,8 +1140,8 @@ static Compare SplayFindLastCompare(Tree node, TreeKey key)
SplayFindClosure closure;
void *closureP;
Size closureS;
- SplayTestNodeMethod testNode;
- SplayTestTreeMethod testTree;
+ SplayTestNodeFunction testNode;
+ SplayTestTreeFunction testTree;
SplayTree splay;
AVERT(Tree, node);
@@ -1190,8 +1193,8 @@ static Compare SplayFindLastCompare(Tree node, TreeKey key)
*/
Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay,
- SplayTestNodeMethod testNode,
- SplayTestTreeMethod testTree,
+ SplayTestNodeFunction testNode,
+ SplayTestTreeFunction testTree,
void *closureP, Size closureS)
{
SplayFindClosureStruct closureStruct;
@@ -1254,8 +1257,8 @@ Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay,
/* SplayFindLast -- As SplayFindFirst but in reverse address order */
Bool SplayFindLast(Tree *nodeReturn, SplayTree splay,
- SplayTestNodeMethod testNode,
- SplayTestTreeMethod testTree,
+ SplayTestNodeFunction testNode,
+ SplayTestTreeFunction testTree,
void *closureP, Size closureS)
{
SplayFindClosureStruct closureStruct;
@@ -1362,7 +1365,7 @@ void SplayNodeInit(SplayTree splay, Tree node)
*/
Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, Count depth,
- TreeDescribeMethod nodeDescribe)
+ TreeDescribeFunction nodeDescribe)
{
Res res;
@@ -1398,7 +1401,7 @@ Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, Count depth,
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/splay.h b/mps/code/splay.h
index 414eb8e6b51..c1b109e64a7 100644
--- a/mps/code/splay.h
+++ b/mps/code/splay.h
@@ -1,7 +1,7 @@
/* splay.h: SPLAY TREE HEADER
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* .source:
*/
@@ -15,21 +15,21 @@
typedef struct SplayTreeStruct *SplayTree;
-typedef Bool (*SplayTestNodeMethod)(SplayTree splay, Tree node,
- void *closureP, Size closureS);
-typedef Bool (*SplayTestTreeMethod)(SplayTree splay, Tree node,
- void *closureP, Size closureS);
+typedef Bool (*SplayTestNodeFunction)(SplayTree splay, Tree node,
+ void *closureP, Size closureS);
+typedef Bool (*SplayTestTreeFunction)(SplayTree splay, Tree node,
+ void *closureP, Size closureS);
-typedef void (*SplayUpdateNodeMethod)(SplayTree splay, Tree node);
+typedef void (*SplayUpdateNodeFunction)(SplayTree splay, Tree node);
extern void SplayTrivUpdate(SplayTree splay, Tree node);
#define SplayTreeSig ((Sig)0x5195B1A1) /* SIGnature SPLAY */
typedef struct SplayTreeStruct {
Sig sig;
- TreeCompare compare;
- TreeKeyMethod nodeKey;
- SplayUpdateNodeMethod updateNode;
+ TreeCompareFunction compare;
+ TreeKeyFunction nodeKey;
+ SplayUpdateNodeFunction updateNode;
Tree root;
} SplayTreeStruct;
@@ -38,9 +38,9 @@ typedef struct SplayTreeStruct {
extern Bool SplayTreeCheck(SplayTree splay);
extern void SplayTreeInit(SplayTree splay,
- TreeCompare compare,
- TreeKeyMethod nodeKey,
- SplayUpdateNodeMethod updateNode);
+ TreeCompareFunction compare,
+ TreeKeyFunction nodeKey,
+ SplayUpdateNodeFunction updateNode);
extern void SplayTreeFinish(SplayTree splay);
extern Bool SplayTreeInsert(SplayTree splay, Tree node);
@@ -55,24 +55,24 @@ extern Bool SplayTreeNeighbours(Tree *leftReturn,
extern Tree SplayTreeFirst(SplayTree splay);
extern Tree SplayTreeNext(SplayTree splay, TreeKey oldKey);
-typedef Bool (*SplayFindMethod)(Tree *nodeReturn, SplayTree splay,
- SplayTestNodeMethod testNode,
- SplayTestTreeMethod testTree,
- void *closureP, Size closureS);
+typedef Bool (*SplayFindFunction)(Tree *nodeReturn, SplayTree splay,
+ SplayTestNodeFunction testNode,
+ SplayTestTreeFunction testTree,
+ void *closureP, Size closureS);
extern Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay,
- SplayTestNodeMethod testNode,
- SplayTestTreeMethod testTree,
+ SplayTestNodeFunction testNode,
+ SplayTestTreeFunction testTree,
void *closureP, Size closureS);
extern Bool SplayFindLast(Tree *nodeReturn, SplayTree splay,
- SplayTestNodeMethod testNode,
- SplayTestTreeMethod testTree,
+ SplayTestNodeFunction testNode,
+ SplayTestTreeFunction testTree,
void *closureP, Size closureS);
extern void SplayNodeRefresh(SplayTree splay, Tree node);
extern void SplayNodeInit(SplayTree splay, Tree node);
extern Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream,
- Count depth, TreeDescribeMethod nodeDescribe);
+ Count depth, TreeDescribeFunction nodeDescribe);
extern void SplayDebugUpdate(SplayTree splay, Tree tree);
extern Count SplayDebugCount(SplayTree splay);
@@ -83,7 +83,7 @@ extern Count SplayDebugCount(SplayTree splay);
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/spw3i6.c b/mps/code/spw3i6.c
index 29b1f8b8dcf..90997cd1589 100644
--- a/mps/code/spw3i6.c
+++ b/mps/code/spw3i6.c
@@ -1,19 +1,13 @@
/* spw3i6.c: STACK PROBE FOR 64-BIT WINDOWS
*
* $Id$
- * Copyright (c) 2013 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2013-2014 Ravenbrook Limited. See end of file for license.
*
* The function StackProbe ensures that the stack has at least depth
* words available. It achieves this by exploiting an obscure but
* documented feature of Microsoft's function _alloca: "A stack
* overflow exception is generated if the space cannot be allocated."
* _alloca: http://msdn.microsoft.com/en-us/library/wb1s57t5.aspx
- *
- * The purpose of this function to ensure that the stack overflow
- * exception is generated here (before taking the arena lock) where it
- * can be handled safely rather than at some later point where the
- * arena lock is held and so handling the exception may cause the MPS
- * to be entered recursively.
*/
#include /* _alloca */
@@ -28,7 +22,7 @@ void StackProbe(Size depth)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2013 Ravenbrook Limited .
+ * Copyright (C) 2013-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/ssixi6.c b/mps/code/ssixi6.c
index 70954edb5da..e61af2ee961 100644
--- a/mps/code/ssixi6.c
+++ b/mps/code/ssixi6.c
@@ -1,13 +1,13 @@
/* ssixi6.c: UNIX/x64 STACK SCANNING
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* This scans the stack and fixes the registers which may contain
* roots. See
*
* This code was branched from ssixi3.c (32-bit Intel) initially for the
- * port to W3I6LL (Mac OS X on x86_64 with Clang).
+ * port to XCI6LL (Mac OS X on x86_64 with Clang).
*
* This code is common to more than one Unix implementation on
* Intel hardware (but is not portable Unix code). According to Wikipedia,
@@ -68,7 +68,7 @@ Res StackScan(ScanState ss, Addr *stackBot)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/steptest.c b/mps/code/steptest.c
index a66b85f1195..f857a85d7ff 100644
--- a/mps/code/steptest.c
+++ b/mps/code/steptest.c
@@ -16,6 +16,7 @@
#include "mpstd.h"
#include "mps.h"
+#include /* pow */
#include /* fflush, printf, putchar, stdout */
#define testArenaSIZE ((size_t)((size_t)64 << 20))
@@ -43,22 +44,6 @@ static mps_gen_param_s testChain[genCOUNT] = {
{gen3SIZE, gen3MORTALITY},
};
-/* run the test several times, calling mps_arena_step at a different
- * frequency each time. When we call it often, tracing is never done
- * during allocation. When we call it never, tracing is always done
- * during allocation.
- */
-
-static unsigned long step_frequencies[] = {
- 1000,
- 5000,
- 10000,
- 1000000000, /* one billion */
-};
-
-static unsigned test_number = 0;
-
-
/* objNULL needs to be odd so that it's ignored in exactRoots. */
#define objNULL ((mps_addr_t)MPS_WORD_CONST(0xDECEA5ED))
@@ -295,9 +280,8 @@ static void test_step(mps_arena_t arena, double multiplier)
/* test -- the body of the test */
-static void *test(void *arg, size_t s)
+static void test(mps_arena_t arena, unsigned long step_period)
{
- mps_arena_t arena;
mps_fmt_t format;
mps_chain_t chain;
mps_root_t exactRoot, ambigRoot;
@@ -310,9 +294,6 @@ static void *test(void *arg, size_t s)
double total_mps_time, total_time;
double t1;
- arena = (mps_arena_t)arg;
- (void)s; /* unused */
-
die(dylan_fmt(&format, arena), "fmt_create");
die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
@@ -336,8 +317,7 @@ static void *test(void *arg, size_t s)
&ambigRoots[0], ambigRootsCOUNT),
"root_create_table(ambig)");
- printf("Stepping every %lu allocations.\n",
- (unsigned long)step_frequencies[test_number]);
+ printf("Stepping every %lu allocations.\n", step_period);
mps_message_type_enable(arena, mps_message_type_gc());
@@ -376,7 +356,7 @@ static void *test(void *arg, size_t s)
++objs;
- if (objs % step_frequencies[test_number] == 0)
+ if (objs % step_period == 0)
test_step(arena, 0.0);
if (objs % multiStepFREQ == 0)
@@ -484,33 +464,19 @@ static void *test(void *arg, size_t s)
mps_pool_destroy(pool);
mps_chain_destroy(chain);
mps_fmt_destroy(format);
-
- return NULL;
}
int main(int argc, char *argv[])
{
+ mps_arena_t arena;
prepare_clock();
-
testlib_init(argc, argv);
-
- while (test_number < NELEMS(step_frequencies)) {
- mps_arena_t arena;
- mps_thr_t thread;
- void *r;
-
- set_clock_timing();
- die(mps_arena_create(&arena, mps_arena_class_vm(),
- testArenaSIZE),
- "arena_create");
- mps_arena_clamp(arena);
- die(mps_thread_reg(&thread, arena), "thread_reg");
- mps_tramp(&r, test, arena, 0);
- mps_thread_dereg(thread);
- mps_arena_destroy(arena);
- ++ test_number;
- }
-
+ set_clock_timing();
+ die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
+ "arena_create");
+ mps_arena_clamp(arena);
+ test(arena, (unsigned long)pow(10, rnd() % 10));
+ mps_arena_destroy(arena);
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
return 0;
}
diff --git a/mps/code/table.c b/mps/code/table.c
index 297fa4fb937..34552476298 100644
--- a/mps/code/table.c
+++ b/mps/code/table.c
@@ -222,8 +222,8 @@ Res TableGrow(Table table, Count extraCapacity)
extern Res TableCreate(Table *tableReturn,
Count length,
- TableAllocMethod tableAlloc,
- TableFreeMethod tableFree,
+ TableAllocFunction tableAlloc,
+ TableFreeFunction tableFree,
void *allocClosure,
Word unusedKey,
Word deletedKey)
diff --git a/mps/code/table.h b/mps/code/table.h
index 1697be09b9b..797f7644a38 100644
--- a/mps/code/table.h
+++ b/mps/code/table.h
@@ -1,5 +1,5 @@
/* table.h: Interface for a dictionary
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* $Id$
*/
@@ -15,8 +15,8 @@ typedef struct TableStruct *Table;
#define TableSig ((Sig)0x5192AB13) /* SIGnature TABLE */
-typedef void *(*TableAllocMethod)(void *closure, size_t size);
-typedef void (*TableFreeMethod)(void *closure, void *p, size_t size);
+typedef void *(*TableAllocFunction)(void *closure, size_t size);
+typedef void (*TableFreeFunction)(void *closure, void *p, size_t size);
typedef struct TableEntryStruct {
Word key;
@@ -28,8 +28,8 @@ typedef struct TableStruct {
Count length; /* Number of slots in the array */
Count count; /* Active entries in the table */
TableEntry array; /* Array of table slots */
- TableAllocMethod alloc;
- TableFreeMethod free;
+ TableAllocFunction alloc;
+ TableFreeFunction free;
void *allocClosure;
Word unusedKey; /* key marking unused (undefined) entries */
Word deletedKey; /* key marking deleted entries */
@@ -37,8 +37,8 @@ typedef struct TableStruct {
extern Res TableCreate(Table *tableReturn,
Count length,
- TableAllocMethod tableAlloc,
- TableFreeMethod tableFree,
+ TableAllocFunction tableAlloc,
+ TableFreeFunction tableFree,
void *allocClosure,
Word unusedKey,
Word deletedKey);
@@ -60,7 +60,7 @@ extern Res TableGrow(Table table, Count extraCapacity);
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/testthr.h b/mps/code/testthr.h
index 341f4f407b5..75602bcc56f 100644
--- a/mps/code/testthr.h
+++ b/mps/code/testthr.h
@@ -6,7 +6,7 @@
* .purpose: Simple interface to threads that makes it possible to
* write test cases that are portable between Windows (using the
* implementation in testthrw3.c) and Unix (using the implementation
- * in testthrix.c).
+ * in testthrix.c). See .
*/
#ifndef testthr_h
diff --git a/mps/code/th.h b/mps/code/th.h
index 8c7da150fd0..8f7996cc0b5 100644
--- a/mps/code/th.h
+++ b/mps/code/th.h
@@ -47,13 +47,14 @@ extern void ThreadDeregister(Thread thread, Arena arena);
/* ThreadRingSuspend/Resume
*
- * These functions suspend/resume the threads on the ring.
- * If the current thread is among them, it is not suspended,
- * nor is any attempt to resume it made.
+ * These functions suspend/resume the threads on the ring. If the
+ * current thread is among them, it is not suspended, nor is any
+ * attempt to resume it made. Threads that can't be suspended/resumed
+ * because they are dead are moved to deadRing.
*/
-extern void ThreadRingSuspend(Ring threadRing);
-extern void ThreadRingResume(Ring threadRing);
+extern void ThreadRingSuspend(Ring threadRing, Ring deadRing);
+extern void ThreadRingResume(Ring threadRing, Ring deadRing);
/* ThreadRingThread
diff --git a/mps/code/than.c b/mps/code/than.c
index 99ca267bab1..f1fb21006d8 100644
--- a/mps/code/than.c
+++ b/mps/code/than.c
@@ -5,11 +5,7 @@
*
* This is a single-threaded implementation of the threads manager.
* Has stubs for thread suspension.
- * See .
- *
- * .single: We only expect at most one thread on the ring.
- *
- * This supports the
+ * See .
*/
#include "mpm.h"
@@ -67,7 +63,6 @@ Res ThreadRegister(Thread *threadReturn, Arena arena)
AVERT(Thread, thread);
ring = ArenaThreadRing(arena);
- AVER(RingCheckSingle(ring)); /* .single */
RingAppend(ring, &thread->arenaRing);
@@ -91,16 +86,16 @@ void ThreadDeregister(Thread thread, Arena arena)
}
-void ThreadRingSuspend(Ring threadRing)
+void ThreadRingSuspend(Ring threadRing, Ring deadRing)
{
AVERT(Ring, threadRing);
- return;
+ AVERT(Ring, deadRing);
}
-void ThreadRingResume(Ring threadRing)
+void ThreadRingResume(Ring threadRing, Ring deadRing)
{
AVERT(Ring, threadRing);
- return;
+ AVERT(Ring, deadRing);
}
Thread ThreadRingThread(Ring threadRing)
@@ -113,11 +108,11 @@ Thread ThreadRingThread(Ring threadRing)
}
-/* Must be thread-safe. See . */
+/* Must be thread-safe. See . */
+
Arena ThreadArena(Thread thread)
{
- /* Can't AVER thread as that would not be thread-safe */
- /* AVERT(Thread, thread); */
+ AVER(TESTT(Thread, thread));
return thread->arena;
}
diff --git a/mps/code/thix.c b/mps/code/thix.c
index cc6a3b61219..c1a31c6e902 100644
--- a/mps/code/thix.c
+++ b/mps/code/thix.c
@@ -12,10 +12,10 @@
*
* ASSUMPTIONS
*
- * .error.resume: PThreadextResume is assumed to succeed unless the thread
- * has been destroyed.
- * .error.suspend: PThreadextSuspend is assumed to succeed unless the thread
- * has been destroyed. In this case, the suspend context is set to NULL;
+ * .error.resume: PThreadextResume is assumed to succeed unless the
+ * thread has been terminated.
+ * .error.suspend: PThreadextSuspend is assumed to succeed unless the
+ * thread has been terminated.
*
* .stack.full-descend: assumes full descending stack.
* i.e. stack pointer points to the last allocated location;
@@ -48,9 +48,10 @@ typedef struct mps_thr_s { /* PThreads thread structure */
Serial serial; /* from arena->threadSerial */
Arena arena; /* owning arena */
RingStruct arenaRing; /* threads attached to arena */
+ Bool alive; /* thread believed to be alive? */
PThreadextStruct thrextStruct; /* PThreads extension */
pthread_t id; /* Pthread object of thread */
- MutatorFaultContext mfc; /* Context if thread is suspended */
+ MutatorFaultContext mfc; /* Context if suspended, NULL if not */
} ThreadStruct;
@@ -62,6 +63,7 @@ Bool ThreadCheck(Thread thread)
CHECKU(Arena, thread->arena);
CHECKL(thread->serial < thread->arena->threadSerial);
CHECKD_NOSIG(Ring, &thread->arenaRing);
+ CHECKL(BoolCheck(thread->alive));
CHECKD(PThreadext, &thread->thrextStruct);
return TRUE;
}
@@ -98,6 +100,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena)
thread->serial = arena->threadSerial;
++arena->threadSerial;
thread->arena = arena;
+ thread->alive = TRUE;
thread->mfc = NULL;
PThreadextInit(&thread->thrextStruct, thread->id);
@@ -130,69 +133,83 @@ void ThreadDeregister(Thread thread, Arena arena)
}
-/* mapThreadRing -- map over threads on ring calling a function on each one
- * except the current thread
+/* mapThreadRing -- map over threads on ring calling a function on
+ * each one except the current thread.
+ *
+ * Threads that are found to be dead (that is, if func returns FALSE)
+ * are moved to deadRing, in order to implement
+ * design.thread-manager.sol.thread.term.attempt.
*/
-static void mapThreadRing(Ring threadRing, void (*func)(Thread))
+static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread))
{
Ring node, next;
pthread_t self;
AVERT(Ring, threadRing);
+ AVERT(Ring, deadRing);
+ AVER(FUNCHECK(func));
self = pthread_self();
RING_FOR(node, threadRing, next) {
Thread thread = RING_ELT(Thread, arenaRing, node);
AVERT(Thread, thread);
- if(! pthread_equal(self, thread->id)) /* .thread.id */
- (*func)(thread);
+ AVER(thread->alive);
+ if (!pthread_equal(self, thread->id) /* .thread.id */
+ && !(*func)(thread))
+ {
+ thread->alive = FALSE;
+ RingRemove(&thread->arenaRing);
+ RingAppend(deadRing, &thread->arenaRing);
+ }
}
}
-/* ThreadRingSuspend -- suspend all threads on a ring, expect the current one */
+/* ThreadRingSuspend -- suspend all threads on a ring, except the
+ * current one.
+ */
-
-static void threadSuspend(Thread thread)
+static Bool threadSuspend(Thread thread)
{
- /* .error.suspend */
- /* In the error case (PThreadextSuspend returning ResFAIL), we */
- /* assume the thread has been destroyed. */
- /* In which case we simply continue. */
+ /* .error.suspend: if PThreadextSuspend fails, we assume the thread
+ * has been terminated. */
Res res;
+ AVER(thread->mfc == NULL);
res = PThreadextSuspend(&thread->thrextStruct, &thread->mfc);
- if(res != ResOK)
- thread->mfc = NULL;
+ AVER(res == ResOK);
+ AVER(thread->mfc != NULL);
+ /* design.thread-manager.sol.thread.term.attempt */
+ return res == ResOK;
}
-void ThreadRingSuspend(Ring threadRing)
+void ThreadRingSuspend(Ring threadRing, Ring deadRing)
{
- mapThreadRing(threadRing, threadSuspend);
+ mapThreadRing(threadRing, deadRing, threadSuspend);
}
/* ThreadRingResume -- resume all threads on a ring (expect the current one) */
-static void threadResume(Thread thread)
+static Bool threadResume(Thread thread)
{
- /* .error.resume */
- /* If the previous suspend failed (thread->mfc == NULL), */
- /* or in the error case (PThreadextResume returning ResFAIL), */
- /* assume the thread has been destroyed. */
- /* In which case we simply continue. */
- if(thread->mfc != NULL) {
- (void)PThreadextResume(&thread->thrextStruct);
- thread->mfc = NULL;
- }
+ Res res;
+ /* .error.resume: If PThreadextResume fails, we assume the thread
+ * has been terminated. */
+ AVER(thread->mfc != NULL);
+ res = PThreadextResume(&thread->thrextStruct);
+ AVER(res == ResOK);
+ thread->mfc = NULL;
+ /* design.thread-manager.sol.thread.term.attempt */
+ return res == ResOK;
}
-void ThreadRingResume(Ring threadRing)
+void ThreadRingResume(Ring threadRing, Ring deadRing)
{
- mapThreadRing(threadRing, threadResume);
+ mapThreadRing(threadRing, deadRing, threadResume);
}
@@ -210,12 +227,12 @@ Thread ThreadRingThread(Ring threadRing)
/* ThreadArena -- get the arena of a thread
*
- * Must be thread-safe. See .
+ * Must be thread-safe. See .
*/
Arena ThreadArena(Thread thread)
{
- /* Can't check thread as that would not be thread-safe. */
+ AVER(TESTT(Thread, thread));
return thread->arena;
}
@@ -231,20 +248,16 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
self = pthread_self();
if(pthread_equal(self, thread->id)) {
/* scan this thread's stack */
+ AVER(thread->alive);
res = StackScan(ss, stackBot);
if(res != ResOK)
return res;
- } else {
+ } else if (thread->alive) {
MutatorFaultContext mfc;
Addr *stackBase, *stackLimit, stackPtr;
mfc = thread->mfc;
- if(mfc == NULL) {
- /* .error.suspend */
- /* We assume that the thread must have been destroyed. */
- /* We ignore the situation by returning immediately. */
- return ResOK;
- }
+ AVER(mfc != NULL);
stackPtr = MutatorFaultContextSP(mfc);
/* .stack.align */
@@ -280,6 +293,7 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
"Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial,
" arena $P ($U)\n",
(WriteFP)thread->arena, (WriteFU)thread->arena->serial,
+ " alive $S\n", WriteFYesNo(thread->alive),
" id $U\n", (WriteFU)thread->id,
"} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial,
NULL);
diff --git a/mps/code/thw3.c b/mps/code/thw3.c
index 96af1f83f6b..b8b8b106680 100644
--- a/mps/code/thw3.c
+++ b/mps/code/thw3.c
@@ -109,6 +109,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena)
thread->serial = arena->threadSerial;
++arena->threadSerial;
thread->arena = arena;
+ thread->alive = TRUE;
AVERT(Thread, thread);
@@ -138,60 +139,66 @@ void ThreadDeregister(Thread thread, Arena arena)
}
-/* Map over threads on ring calling f on each one except the
- * current thread.
+/* mapThreadRing -- map over threads on ring calling a function on
+ * each one except the current thread.
+ *
+ * Threads that are found to be dead (that is, if func returns FALSE)
+ * are moved to deadRing.
*/
-static void mapThreadRing(Ring ring, void (*f)(Thread thread))
+
+static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread))
{
- Ring node;
+ Ring node, next;
DWORD id;
+ AVERT(Ring, threadRing);
+ AVERT(Ring, deadRing);
+ AVER(FUNCHECK(func));
+
id = GetCurrentThreadId();
- node = RingNext(ring);
- while(node != ring) {
- Ring next = RingNext(node);
- Thread thread;
-
- thread = RING_ELT(Thread, arenaRing, node);
+ RING_FOR(node, threadRing, next) {
+ Thread thread = RING_ELT(Thread, arenaRing, node);
AVERT(Thread, thread);
- if(id != thread->id) /* .thread.id */
- (*f)(thread);
-
- node = next;
+ AVER(thread->alive);
+ if (id != thread->id /* .thread.id */
+ && !(*func)(thread))
+ {
+ thread->alive = FALSE;
+ RingRemove(&thread->arenaRing);
+ RingAppend(deadRing, &thread->arenaRing);
+ }
}
}
-static void suspend(Thread thread)
+static Bool suspendThread(Thread thread)
{
/* .thread.handle.susp-res */
/* .error.suspend */
- /* In the error case (SuspendThread returning 0xFFFFFFFF), we */
- /* assume the thread has been destroyed (as part of process shutdown). */
- /* In which case we simply continue. */
+ /* In the error case (SuspendThread returning -1), we */
+ /* assume the thread has been terminated. */
/* [GetLastError appears to return 5 when SuspendThread is called */
- /* on a destroyed thread, but I'm not sufficiently confident of this */
+ /* on a terminated thread, but I'm not sufficiently confident of this */
/* to check -- drj 1998-04-09] */
- (void)SuspendThread(thread->handle);
+ return SuspendThread(thread->handle) != (DWORD)-1;
}
-void ThreadRingSuspend(Ring ring)
+void ThreadRingSuspend(Ring threadRing, Ring deadRing)
{
- mapThreadRing(ring, suspend);
+ mapThreadRing(threadRing, deadRing, suspendThread);
}
-static void resume(Thread thread)
+static Bool resumeThread(Thread thread)
{
/* .thread.handle.susp-res */
/* .error.resume */
- /* In the error case (ResumeThread returning 0xFFFFFFFF), we */
- /* assume the thread has been destroyed (as part of process shutdown). */
- /* In which case we simply continue. */
- (void)ResumeThread(thread->handle);
+ /* In the error case (ResumeThread returning -1), we */
+ /* assume the thread has been terminated. */
+ return ResumeThread(thread->handle) != (DWORD)-1;
}
-void ThreadRingResume(Ring ring)
+void ThreadRingResume(Ring threadRing, Ring deadRing)
{
- mapThreadRing(ring, resume);
+ mapThreadRing(threadRing, deadRing, resumeThread);
}
@@ -204,11 +211,11 @@ Thread ThreadRingThread(Ring threadRing)
return thread;
}
-/* Must be thread-safe. See . */
+/* Must be thread-safe. See . */
+
Arena ThreadArena(Thread thread)
{
- /* Can't AVER thread as that would not be thread-safe */
- /* AVERT(Thread, thread); */
+ AVER(TESTT(Thread, thread));
return thread->arena;
}
@@ -220,6 +227,7 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
"Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial,
" arena $P ($U)\n",
(WriteFP)thread->arena, (WriteFU)thread->arena->serial,
+ " alive $S\n", WriteFYesNo(thread->alive),
" handle $W\n", (WriteFW)thread->handle,
" id $U\n", (WriteFU)thread->id,
"} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial,
diff --git a/mps/code/thw3.h b/mps/code/thw3.h
index 7e3cd68e2f1..b19bfccadba 100644
--- a/mps/code/thw3.h
+++ b/mps/code/thw3.h
@@ -26,6 +26,7 @@ typedef struct mps_thr_s { /* Win32 thread structure */
Serial serial; /* from arena->threadSerial */
Arena arena; /* owning arena */
RingStruct arenaRing; /* threads attached to arena */
+ Bool alive; /* thread believed to be alive? */
HANDLE handle; /* Handle of thread, see
* */
DWORD id; /* Thread id of thread */
diff --git a/mps/code/thw3i3.c b/mps/code/thw3i3.c
index 33424b6cf54..20e694ddc82 100644
--- a/mps/code/thw3i3.c
+++ b/mps/code/thw3i3.c
@@ -74,7 +74,13 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
id = GetCurrentThreadId();
- if(id != thread->id) { /* .thread.id */
+ if (id == thread->id) { /* .thread.id */
+ /* scan this thread's stack */
+ AVER(thread->alive);
+ res = StackScan(ss, stackBot);
+ if(res != ResOK)
+ return res;
+ } else if (thread->alive) {
CONTEXT context;
BOOL success;
Addr *stackBase, *stackLimit, stackPtr;
@@ -116,11 +122,6 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
(Addr *)((char *)&context + sizeof(CONTEXT)));
if(res != ResOK)
return res;
-
- } else { /* scan this thread's stack */
- res = StackScan(ss, stackBot);
- if(res != ResOK)
- return res;
}
return ResOK;
diff --git a/mps/code/thw3i6.c b/mps/code/thw3i6.c
index 9b0eae55db6..a13a031ec22 100644
--- a/mps/code/thw3i6.c
+++ b/mps/code/thw3i6.c
@@ -74,7 +74,13 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
id = GetCurrentThreadId();
- if(id != thread->id) { /* .thread.id */
+ if (id == thread->id) { /* .thread.id */
+ /* scan this thread's stack */
+ AVER(thread->alive);
+ res = StackScan(ss, stackBot);
+ if(res != ResOK)
+ return res;
+ } else if (thread->alive) {
CONTEXT context;
BOOL success;
Addr *stackBase, *stackLimit, stackPtr;
@@ -116,11 +122,6 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
(Addr *)((char *)&context + sizeof(CONTEXT)));
if(res != ResOK)
return res;
-
- } else { /* scan this thread's stack */
- res = StackScan(ss, stackBot);
- if(res != ResOK)
- return res;
}
return ResOK;
diff --git a/mps/code/thxc.c b/mps/code/thxc.c
index 8cde6dbbd7a..6ecc1ea726e 100644
--- a/mps/code/thxc.c
+++ b/mps/code/thxc.c
@@ -36,6 +36,7 @@ typedef struct mps_thr_s { /* OS X / Mach thread structure */
Serial serial; /* from arena->threadSerial */
Arena arena; /* owning arena */
RingStruct arenaRing; /* attaches to arena */
+ Bool alive; /* thread believed to be alive? */
thread_port_t port; /* thread kernel port */
} ThreadStruct;
@@ -46,6 +47,7 @@ Bool ThreadCheck(Thread thread)
CHECKU(Arena, thread->arena);
CHECKL(thread->serial < thread->arena->threadSerial);
CHECKD_NOSIG(Ring, &thread->arenaRing);
+ CHECKL(BoolCheck(thread->alive));
CHECKL(MACH_PORT_VALID(thread->port));
return TRUE;
}
@@ -78,6 +80,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena)
thread->serial = arena->threadSerial;
++arena->threadSerial;
+ thread->alive = TRUE;
thread->port = mach_thread_self();
thread->sig = ThreadSig;
AVERT(Thread, thread);
@@ -108,62 +111,80 @@ void ThreadDeregister(Thread thread, Arena arena)
}
-/* mapThreadRing -- map over threads on ring calling a function on each one
- * except the current thread
+/* mapThreadRing -- map over threads on ring calling a function on
+ * each one except the current thread.
+ *
+ * Threads that are found to be dead (that is, if func returns FALSE)
+ * are marked as dead and moved to deadRing, in order to implement
+ * design.thread-manager.sol.thread.term.attempt.
*/
-static void mapThreadRing(Ring threadRing, void (*func)(Thread))
+static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread))
{
Ring node, next;
mach_port_t self;
AVERT(Ring, threadRing);
+ AVERT(Ring, deadRing);
+ AVER(FUNCHECK(func));
self = mach_thread_self();
AVER(MACH_PORT_VALID(self));
RING_FOR(node, threadRing, next) {
Thread thread = RING_ELT(Thread, arenaRing, node);
AVERT(Thread, thread);
- if(thread->port != self)
- (*func)(thread);
+ AVER(thread->alive);
+ if (thread->port != self
+ && !(*func)(thread))
+ {
+ thread->alive = FALSE;
+ RingRemove(&thread->arenaRing);
+ RingAppend(deadRing, &thread->arenaRing);
+ }
}
}
-static void threadSuspend(Thread thread)
+static Bool threadSuspend(Thread thread)
{
kern_return_t kern_return;
kern_return = thread_suspend(thread->port);
/* No rendezvous is necessary: thread_suspend "prevents the thread
* from executing any more user-level instructions" */
AVER(kern_return == KERN_SUCCESS);
+ /* Experimentally, values other then KERN_SUCCESS indicate the thread has
+ terminated . */
+ /* design.thread-manager.sol.thread.term.attempt */
+ return kern_return == KERN_SUCCESS;
}
-static void threadResume(Thread thread)
+static Bool threadResume(Thread thread)
{
kern_return_t kern_return;
kern_return = thread_resume(thread->port);
/* Mach has no equivalent of EAGAIN. */
AVER(kern_return == KERN_SUCCESS);
+ /* Experimentally, values other then KERN_SUCCESS indicate the thread has
+ terminated . */
+ /* design.thread-manager.sol.thread.term.attempt */
+ return kern_return == KERN_SUCCESS;
}
/* ThreadRingSuspend -- suspend all threads on a ring, except the
* current one.
*/
-void ThreadRingSuspend(Ring threadRing)
+void ThreadRingSuspend(Ring threadRing, Ring deadRing)
{
- AVERT(Ring, threadRing);
- mapThreadRing(threadRing, threadSuspend);
+ mapThreadRing(threadRing, deadRing, threadSuspend);
}
/* ThreadRingResume -- resume all threads on a ring, except the
* current one.
*/
-void ThreadRingResume(Ring threadRing)
+void ThreadRingResume(Ring threadRing, Ring deadRing)
{
- AVERT(Ring, threadRing);
- mapThreadRing(threadRing, threadResume);
+ mapThreadRing(threadRing, deadRing, threadResume);
}
Thread ThreadRingThread(Ring threadRing)
@@ -176,11 +197,11 @@ Thread ThreadRingThread(Ring threadRing)
}
-/* Must be thread-safe. See . */
+/* Must be thread-safe. See . */
+
Arena ThreadArena(Thread thread)
{
- /* Can't AVER thread as that would not be thread-safe */
- /* AVERT(Thread, thread); */
+ AVER(TESTT(Thread, thread));
return thread->arena;
}
@@ -199,17 +220,18 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
AVER(MACH_PORT_VALID(self));
if (thread->port == self) {
/* scan this thread's stack */
+ AVER(thread->alive);
res = StackScan(ss, stackBot);
if(res != ResOK)
return res;
- } else {
+ } else if (thread->alive) {
MutatorFaultContextStruct mfcStruct;
THREAD_STATE_S threadState;
Addr *stackBase, *stackLimit, stackPtr;
mach_msg_type_number_t count;
kern_return_t kern_return;
- /* Note: We could get the thread state and check the suspend cound in
+ /* Note: We could get the thread state and check the suspend count in
order to assert that the thread is suspended, but it's probably
unnecessary and is a lot of work to check a static condition. */
@@ -257,6 +279,7 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
"Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial,
" arena $P ($U)\n",
(WriteFP)thread->arena, (WriteFU)thread->arena->serial,
+ " alive $S\n", WriteFYesNo(thread->alive),
" port $U\n", (WriteFU)thread->port,
"} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial,
NULL);
diff --git a/mps/code/trace.c b/mps/code/trace.c
index 056fda99eb0..7e918513279 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -1,7 +1,7 @@
/* trace.c: GENERIC TRACER IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited.
+ * Copyright (c) 2001-2015 Ravenbrook Limited.
* See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
@@ -233,7 +233,7 @@ Bool traceBandAdvance(Trace trace)
++trace->band;
trace->firstStretch = TRUE;
if(trace->band >= RankLIMIT) {
- trace->band = RankAMBIG;
+ trace->band = RankMIN;
return FALSE;
}
EVENT3(TraceBandAdvance, trace->arena, trace->ti, trace->band);
@@ -587,7 +587,7 @@ static Res traceFlip(Trace trace)
/* early, before the pool contents. @@@@ This isn't correct if there are */
/* higher ranking roots than data in pools. */
- for(rank = RankAMBIG; rank <= RankEXACT; ++rank) {
+ for(rank = RankMIN; rank <= RankEXACT; ++rank) {
rfc.rank = rank;
res = RootsIterate(ArenaGlobals(arena), rootFlip, (void *)&rfc);
if (res != ResOK)
@@ -607,7 +607,7 @@ static Res traceFlip(Trace trace)
/* grey objects so that it can't obtain white pointers. This is */
/* achieved by read protecting all segments containing objects */
/* which are grey for any of the flipped traces. */
- for(rank = 0; rank < RankLIMIT; ++rank)
+ for(rank = RankMIN; rank < RankLIMIT; ++rank)
RING_FOR(node, ArenaGreyRing(arena, rank), nextNode) {
Seg seg = SegOfGreyRing(node);
if(TraceSetInter(SegGrey(seg), arena->flippedTraces) == TraceSetEMPTY
@@ -685,7 +685,7 @@ found:
trace->mayMove = ZoneSetEMPTY;
trace->ti = ti;
trace->state = TraceINIT;
- trace->band = RankAMBIG; /* Required to be the earliest rank. */
+ trace->band = RankMIN;
trace->fix = PoolFix;
trace->fixClosure = NULL;
trace->chain = NULL;
@@ -910,7 +910,7 @@ Rank TraceRankForAccess(Arena arena, Seg seg)
AVERT(Arena, arena);
AVERT(Seg, seg);
- band = RankAMBIG; /* initialize band to avoid warning */
+ band = RankLIMIT; /* initialize with invalid rank */
ts = arena->flippedTraces;
AVER(TraceSetIsSingle(ts));
TRACE_SET_ITER(ti, trace, ts, arena)
@@ -1188,6 +1188,7 @@ void TraceSegAccess(Arena arena, Seg seg, AccessSet mode)
AVERT(Arena, arena);
AVERT(Seg, seg);
+ AVERT(AccessSet, mode);
/* If it's a read access, then the segment must be grey for a trace */
/* which is flipped. */
@@ -1962,7 +1963,7 @@ Res TraceDescribe(Trace trace, mps_lib_FILE *stream, Count depth)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited
+ * Copyright (C) 2001-2015 Ravenbrook Limited
* .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
diff --git a/mps/code/traceanc.c b/mps/code/traceanc.c
index 77fe772d587..ede8d012fe8 100644
--- a/mps/code/traceanc.c
+++ b/mps/code/traceanc.c
@@ -674,7 +674,7 @@ static Res arenaRememberSummaryOne(Globals global, Addr base, RefSet summary)
RememberedSummaryBlock newBlock;
int res;
- res = ControlAlloc(&p, arena, sizeof *newBlock, 0);
+ res = ControlAlloc(&p, arena, sizeof *newBlock, FALSE);
if(res != ResOK) {
return res;
}
@@ -704,12 +704,13 @@ static Res arenaRememberSummaryOne(Globals global, Addr base, RefSet summary)
protection state or not (for later restoration with
ArenaRestoreProtection).
*/
-void ArenaExposeRemember(Globals globals, int remember)
+void ArenaExposeRemember(Globals globals, Bool remember)
{
Seg seg;
Arena arena;
AVERT(Globals, globals);
+ AVERT(Bool, remember);
ArenaPark(globals);
diff --git a/mps/code/tract.c b/mps/code/tract.c
index 5d3bffe9721..9aa815f47ba 100644
--- a/mps/code/tract.c
+++ b/mps/code/tract.c
@@ -167,7 +167,8 @@ Bool ChunkCheck(Chunk chunk)
/* ChunkInit -- initialize generic part of chunk */
-Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, BootBlock boot)
+Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, Size reserved,
+ BootBlock boot)
{
Size size;
Count pages;
@@ -192,6 +193,7 @@ Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, BootBlock boot)
chunk->pageShift = pageShift = SizeLog2(chunk->pageSize);
chunk->base = base;
chunk->limit = limit;
+ chunk->reserved = reserved;
size = ChunkSize(chunk);
chunk->pages = pages = size >> pageShift;
@@ -262,17 +264,16 @@ void ChunkFinish(Chunk chunk)
PageIndexBase(chunk, chunk->allocBase),
chunk->limit);
+ ArenaChunkRemoved(arena, chunk);
+
chunk->sig = SigInvalid;
TreeFinish(&chunk->chunkTree);
RingRemove(&chunk->arenaRing);
- if (chunk->arena->primary == chunk)
- chunk->arena->primary = NULL;
-
/* Finish all other fields before class finish, because they might be */
/* unmapped there. */
- (chunk->arena->class->chunkFinish)(chunk);
+ (*arena->class->chunkFinish)(chunk);
}
diff --git a/mps/code/tract.h b/mps/code/tract.h
index 07906ad5756..ce7c602a176 100644
--- a/mps/code/tract.h
+++ b/mps/code/tract.h
@@ -148,6 +148,9 @@ typedef struct ChunkStruct {
BT allocTable; /* page allocation table */
Page pageTable; /* the page table */
Count pageTablePages; /* number of pages occupied by page table */
+ Size reserved; /* reserved address space for chunk (including overhead
+ such as losses due to alignment): must not change
+ (or arena reserved calculation will break) */
} ChunkStruct;
@@ -159,10 +162,11 @@ typedef struct ChunkStruct {
#define ChunkSizeToPages(chunk, size) ((Count)((size) >> (chunk)->pageShift))
#define ChunkPage(chunk, pi) (&(chunk)->pageTable[pi])
#define ChunkOfTree(tree) PARENT(ChunkStruct, chunkTree, tree)
+#define ChunkReserved(chunk) RVALUE((chunk)->reserved)
extern Bool ChunkCheck(Chunk chunk);
extern Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit,
- BootBlock boot);
+ Size reserved, BootBlock boot);
extern void ChunkFinish(Chunk chunk);
extern Compare ChunkCompare(Tree tree, TreeKey key);
extern TreeKey ChunkKey(Tree tree);
diff --git a/mps/code/tree.c b/mps/code/tree.c
index e6dd902f3fd..f87e8364ea7 100644
--- a/mps/code/tree.c
+++ b/mps/code/tree.c
@@ -1,7 +1,7 @@
/* tree.c: BINARY TREE IMPLEMENTATION
*
* $Id$
- * Copyright (C) 2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (C) 2014-2015 Ravenbrook Limited. See end of file for license.
*
* Simple binary trees with utilities, for use as building blocks.
* Keep it simple, like Rings (see ring.h).
@@ -9,10 +9,9 @@
* The performance requirements on tree implementation will depend on
* how each individual function is applied in the MPS.
*
- * .note.stack: It's important that the MPS have a bounded stack
- * size, and this is a problem for tree algorithms. Basically,
- * we have to avoid recursion. TODO: Design documentation for this
- * requirement, meanwhile see job003651 and job003640.
+ * .note.stack: It's important that the MPS have a bounded stack size,
+ * and this is a problem for tree algorithms. Basically, we have to
+ * avoid recursion. See design.mps.sp.sol.depth.no-recursion.
*/
#include "tree.h"
@@ -50,7 +49,8 @@ Bool TreeCheckLeaf(Tree tree)
*/
static Count TreeDebugCountBetween(Tree node,
- TreeCompare compare, TreeKeyMethod key,
+ TreeCompareFunction compare,
+ TreeKeyFunction key,
TreeKey min, TreeKey max)
{
if (node == TreeEMPTY)
@@ -63,7 +63,8 @@ static Count TreeDebugCountBetween(Tree node,
TreeDebugCountBetween(TreeRight(node), compare, key, key(node), max);
}
-Count TreeDebugCount(Tree tree, TreeCompare compare, TreeKeyMethod key)
+Count TreeDebugCount(Tree tree, TreeCompareFunction compare,
+ TreeKeyFunction key)
{
AVERT(Tree, tree);
return TreeDebugCountBetween(tree, compare, key, NULL, NULL);
@@ -80,7 +81,8 @@ Count TreeDebugCount(Tree tree, TreeCompare compare, TreeKeyMethod key)
* or CompareGREATER for its right.
*/
-Compare TreeFind(Tree *treeReturn, Tree root, TreeKey key, TreeCompare compare)
+Compare TreeFind(Tree *treeReturn, Tree root, TreeKey key,
+ TreeCompareFunction compare)
{
Tree node, parent;
Compare cmp = CompareEQUAL;
@@ -126,7 +128,8 @@ Compare TreeFind(Tree *treeReturn, Tree root, TreeKey key, TreeCompare compare)
* *treeReturn unchanged and return FALSE.
*/
-Bool TreeFindNext(Tree *treeReturn, Tree root, TreeKey key, TreeCompare compare)
+Bool TreeFindNext(Tree *treeReturn, Tree root, TreeKey key,
+ TreeCompareFunction compare)
{
Tree node, best = NULL;
Bool result = FALSE;
@@ -169,7 +172,7 @@ Bool TreeFindNext(Tree *treeReturn, Tree root, TreeKey key, TreeCompare compare)
*/
Bool TreeInsert(Tree *treeReturn, Tree root, Tree node,
- TreeKey key, TreeCompare compare)
+ TreeKey key, TreeCompareFunction compare)
{
Tree parent;
Compare cmp;
@@ -318,8 +321,8 @@ static Tree stepUpLeft(Tree node, Tree *parentIO)
}
Bool TreeTraverse(Tree tree,
- TreeCompare compare,
- TreeKeyMethod key,
+ TreeCompareFunction compare,
+ TreeKeyFunction key,
TreeVisitor visit, void *closureP, Size closureS)
{
Tree parent, node;
@@ -565,7 +568,7 @@ void TreeTraverseAndDelete(Tree *treeIO, TreeVisitor visitor,
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2014 Ravenbrook Limited .
+ * Copyright (C) 2014-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/tree.h b/mps/code/tree.h
index 296c9528a1a..7b463067f0e 100644
--- a/mps/code/tree.h
+++ b/mps/code/tree.h
@@ -25,21 +25,21 @@ typedef struct TreeStruct {
Tree left, right;
} TreeStruct;
-typedef Res (*TreeDescribeMethod)(Tree tree, mps_lib_FILE *stream);
+typedef Res (*TreeDescribeFunction)(Tree tree, mps_lib_FILE *stream);
-/* TreeKey and TreeCompare -- ordered binary trees
+/* TreeKeyFunction and TreeCompareFunction -- ordered binary trees
*
* Binary trees are almost always ordered, and these types provide the
- * abstraction for ordering. A TreeCompare method returns whether a key
- * is less than, equal to, or greater than the key in a tree node. A
- * TreeKeyMethod extracts a key from a node, depending on how TreeStruct
- * is embedded within its parent structure.
+ * abstraction for ordering. A TreeCompareFunction method returns
+ * whether a key is less than, equal to, or greater than the key in a
+ * tree node. A TreeKeyFunction extracts a key from a node, depending
+ * on how TreeStruct is embedded within its parent structure.
*/
typedef void *TreeKey;
-typedef Compare (*TreeCompare)(Tree tree, TreeKey key);
-typedef TreeKey (*TreeKeyMethod)(Tree tree);
+typedef Compare (*TreeCompareFunction)(Tree tree, TreeKey key);
+typedef TreeKey (*TreeKeyFunction)(Tree tree);
/* When storing Addrs in a tree, it is fastest to cast the Addr
@@ -67,7 +67,8 @@ typedef TreeKey (*TreeKeyMethod)(Tree tree);
extern Bool TreeCheck(Tree tree);
extern Bool TreeCheckLeaf(Tree tree);
-extern Count TreeDebugCount(Tree tree, TreeCompare compare, TreeKeyMethod key);
+extern Count TreeDebugCount(Tree tree, TreeCompareFunction compare,
+ TreeKeyFunction key);
#define TreeInit(tree) \
BEGIN \
@@ -115,17 +116,17 @@ extern Count TreeDebugCount(Tree tree, TreeCompare compare, TreeKeyMethod key);
#define TreeHasRight(tree) (TreeRight(tree) != TreeEMPTY)
extern Compare TreeFind(Tree *treeReturn, Tree root,
- TreeKey key, TreeCompare compare);
+ TreeKey key, TreeCompareFunction compare);
extern Bool TreeFindNext(Tree *treeReturn, Tree root,
- TreeKey key, TreeCompare compare);
+ TreeKey key, TreeCompareFunction compare);
extern Bool TreeInsert(Tree *treeReturn, Tree root, Tree node,
- TreeKey key, TreeCompare compare);
+ TreeKey key, TreeCompareFunction compare);
typedef Bool TreeVisitor(Tree tree, void *closureP, Size closureS);
extern Bool TreeTraverse(Tree tree,
- TreeCompare compare,
- TreeKeyMethod key,
+ TreeCompareFunction compare,
+ TreeKeyFunction key,
TreeVisitor visit, void *closureP, Size closureS);
extern Bool TreeTraverseMorris(Tree tree, TreeVisitor visit,
void *closureP, Size closureS);
diff --git a/mps/code/w3i3mv.nmk b/mps/code/w3i3mv.nmk
index 458fd033484..92e609b5f2f 100644
--- a/mps/code/w3i3mv.nmk
+++ b/mps/code/w3i3mv.nmk
@@ -5,90 +5,20 @@
PFM = w3i3mv
-PFMDEFS = /DCONFIG_PF_STRING="w3i3mv" /DCONFIG_PF_W3I3MV /DWIN32 /D_WINDOWS
-
-# MPM platform-specific sources.
MPMPF = \
- \
- \
- \
- \
- \
- \
- \
- \
- \
-
+ [lockw3] \
+ [mpsiw3] \
+ [prmci3w3] \
+ [proti3] \
+ [protw3] \
+ [spw3i3] \
+ [ssw3i3mv] \
+ [thw3] \
+ [thw3i3] \
+ [vmw3]
-!INCLUDE commpre.nmk
!INCLUDE mv.nmk
-
-
-# Source to object file mappings and CFLAGS amalgamation
-#
-# %%VARIETY %%PART: When adding a new variety or part, add new macros which
-# expand to the files included in the part for each variety
-#
-# %%VARIETY: When adding a new variety, add a CFLAGS macro which expands to
-# the flags that that variety should use when compiling C. And a LINKFLAGS
-# macro which expands to the flags that the variety should use when building
-# executables. And a LIBFLAGS macro which expands to the flags that the
-# variety should use when building libraries
-
-!IF "$(VARIETY)" == "hot"
-CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST)
-CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST)
-LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT)
-LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT)
-MPMOBJ0 = $(MPM:<=w3i3mv\hot\)
-FMTDYOBJ0 = $(FMTDY:<=w3i3mv\hot\)
-FMTTESTOBJ0 = $(FMTTEST:<=w3i3mv\hot\)
-FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i3mv\hot\)
-POOLNOBJ0 = $(POOLN:<=w3i3mv\hot\)
-TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\hot\)
-TESTTHROBJ0 = $(TESTTHR:<=w3i3mv\hot\)
-
-!ELSEIF "$(VARIETY)" == "cool"
-CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST)
-CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST)
-LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL)
-LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL)
-MPMOBJ0 = $(MPM:<=w3i3mv\cool\)
-FMTDYOBJ0 = $(FMTDY:<=w3i3mv\cool\)
-FMTTESTOBJ0 = $(FMTTEST:<=w3i3mv\cool\)
-FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i3mv\cool\)
-POOLNOBJ0 = $(POOLN:<=w3i3mv\cool\)
-TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\cool\)
-TESTTHROBJ0 = $(TESTTHR:<=w3i3mv\cool\)
-
-!ELSEIF "$(VARIETY)" == "rash"
-CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST)
-CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST)
-LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH)
-LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH)
-MPMOBJ0 = $(MPM:<=w3i3mv\rash\)
-FMTDYOBJ0 = $(FMTDY:<=w3i3mv\rash\)
-FMTTESTOBJ0 = $(FMTTEST:<=w3i3mv\rash\)
-FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i3mv\rash\)
-POOLNOBJ0 = $(POOLN:<=w3i3mv\rash\)
-TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\rash\)
-TESTTHROBJ0 = $(TESTTHR:<=w3i3mv\rash\)
-
-!ENDIF
-
-# %%PART: When adding a new part, add new macros which expand to the object
-# files included in the part
-
-MPMOBJ = $(MPMOBJ0:>=.obj)
-FMTDYOBJ = $(FMTDYOBJ0:>=.obj)
-FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj)
-FMTSCHEMEOBJ = $(FMTSCHEMEOBJ0:>=.obj)
-POOLNOBJ = $(POOLNOBJ0:>=.obj)
-TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj)
-TESTTHROBJ = $(TESTTHROBJ0:>=.obj)
-
-
-!INCLUDE commpost.nmk
+!INCLUDE comm.nmk
# C. COPYRIGHT AND LICENSE
diff --git a/mps/code/w3i3pc.nmk b/mps/code/w3i3pc.nmk
index f3e848a94dd..5ffe8892ebb 100644
--- a/mps/code/w3i3pc.nmk
+++ b/mps/code/w3i3pc.nmk
@@ -5,86 +5,20 @@
PFM = w3i3pc
-PFMDEFS = /DCONFIG_PF_STRING="w3i3pc" /DCONFIG_PF_W3I3PC /DWIN32 /D_WINDOWS
-
-# MPM platform-specific sources.
MPMPF = \
- \
- \
- \
- \
- \
- \
- \
- \
- \
-
+ [lockw3] \
+ [mpsiw3] \
+ [prmci3w3] \
+ [proti3] \
+ [protw3] \
+ [spw3i3] \
+ [ssw3i3pc] \
+ [thw3] \
+ [thw3i3] \
+ [vmw3]
-!INCLUDE commpre.nmk
!INCLUDE pc.nmk
-
-
-# Source to object file mappings and CFLAGS amalgamation
-#
-# %%VARIETY %%PART: When adding a new variety or part, add new macros which
-# expand to the files included in the part for each variety
-#
-# %%VARIETY: When adding a new variety, add a CFLAGS macro which expands to
-# the flags that that variety should use when compiling C. And a LINKFLAGS
-# macro which expands to the flags that the variety should use when building
-# executables. And a LIBFLAGS macro which expands to the flags that the
-# variety should use when building libraries
-
-!IF "$(VARIETY)" == "hot"
-CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST)
-CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST)
-LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT)
-LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT)
-MPMOBJ0 = $(MPM:<=w3i3pc\hot\)
-FMTDYOBJ0 = $(FMTDY:<=w3i3pc\hot\)
-FMTTESTOBJ0 = $(FMTTEST:<=w3i3pc\hot\)
-POOLNOBJ0 = $(POOLN:<=w3i3pc\hot\)
-TESTLIBOBJ0 = $(TESTLIB:<=w3i3pc\hot\)
-TESTTHROBJ0 = $(TESTTHR:<=w3i3pc\hot\)
-
-!ELSEIF "$(VARIETY)" == "cool"
-CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST)
-CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST)
-LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL)
-LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL)
-MPMOBJ0 = $(MPM:<=w3i3pc\cool\)
-FMTDYOBJ0 = $(FMTDY:<=w3i3pc\cool\)
-FMTTESTOBJ0 = $(FMTTEST:<=w3i3pc\cool\)
-POOLNOBJ0 = $(POOLN:<=w3i3pc\cool\)
-TESTLIBOBJ0 = $(TESTLIB:<=w3i3pc\cool\)
-TESTTHROBJ0 = $(TESTTHR:<=w3i3pc\cool\)
-
-!ELSEIF "$(VARIETY)" == "rash"
-CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST)
-CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST)
-LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH)
-LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH)
-MPMOBJ0 = $(MPM:<=w3i3pc\rash\)
-FMTDYOBJ0 = $(FMTDY:<=w3i3pc\rash\)
-FMTTESTOBJ0 = $(FMTTEST:<=w3i3pc\rash\)
-POOLNOBJ0 = $(POOLN:<=w3i3pc\rash\)
-TESTLIBOBJ0 = $(TESTLIB:<=w3i3pc\rash\)
-TESTTHROBJ0 = $(TESTTHR:<=w3i3pc\rash\)
-
-!ENDIF
-
-# %%PART: When adding a new part, add new macros which expand to the object
-# files included in the part
-
-MPMOBJ = $(MPMOBJ0:>=.obj)
-FMTDYOBJ = $(FMTDYOBJ0:>=.obj)
-FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj)
-POOLNOBJ = $(POOLNOBJ0:>=.obj)
-TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj)
-TESTTHROBJ = $(TESTTHROBJ0:>=.obj)
-
-
-!INCLUDE commpost.nmk
+!INCLUDE comm.nmk
# C. COPYRIGHT AND LICENSE
diff --git a/mps/code/w3i6mv.nmk b/mps/code/w3i6mv.nmk
index 5cfa511db91..eb36bc200d2 100644
--- a/mps/code/w3i6mv.nmk
+++ b/mps/code/w3i6mv.nmk
@@ -5,91 +5,20 @@
PFM = w3i6mv
-PFMDEFS = /DCONFIG_PF_STRING="w3i6mv" /DCONFIG_PF_W3I6MV /DWIN32 /D_WINDOWS
-MASM = ml64
-
-# MPM platform-specific sources.
MPMPF = \
- \
- \
- \
- \
- \
- \
- \
- \
- \
-
+ [lockw3] \
+ [mpsiw3] \
+ [prmci6w3] \
+ [proti6] \
+ [protw3] \
+ [spw3i6] \
+ [ssw3i6mv] \
+ [thw3] \
+ [thw3i6] \
+ [vmw3]
-!INCLUDE commpre.nmk
!INCLUDE mv.nmk
-
-
-# Source to object file mappings and CFLAGS amalgamation
-#
-# %%VARIETY %%PART: When adding a new variety or part, add new macros which
-# expand to the files included in the part for each variety
-#
-# %%VARIETY: When adding a new variety, add a CFLAGS macro which expands to
-# the flags that that variety should use when compiling C. And a LINKFLAGS
-# macro which expands to the flags that the variety should use when building
-# executables. And a LIBFLAGS macro which expands to the flags that the
-# variety should use when building libraries
-
-!IF "$(VARIETY)" == "hot"
-CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST)
-CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST)
-LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT)
-LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT)
-MPMOBJ0 = $(MPM:<=w3i6mv\hot\)
-FMTDYOBJ0 = $(FMTDY:<=w3i6mv\hot\)
-FMTTESTOBJ0 = $(FMTTEST:<=w3i6mv\hot\)
-FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i6mv\hot\)
-POOLNOBJ0 = $(POOLN:<=w3i6mv\hot\)
-TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\hot\)
-TESTTHROBJ0 = $(TESTTHR:<=w3i6mv\hot\)
-
-!ELSEIF "$(VARIETY)" == "cool"
-CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST)
-CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST)
-LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL)
-LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL)
-MPMOBJ0 = $(MPM:<=w3i6mv\cool\)
-FMTDYOBJ0 = $(FMTDY:<=w3i6mv\cool\)
-FMTTESTOBJ0 = $(FMTTEST:<=w3i6mv\cool\)
-FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i6mv\cool\)
-POOLNOBJ0 = $(POOLN:<=w3i6mv\cool\)
-TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\cool\)
-TESTTHROBJ0 = $(TESTTHR:<=w3i6mv\cool\)
-
-!ELSEIF "$(VARIETY)" == "rash"
-CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST)
-CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST)
-LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH)
-LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH)
-MPMOBJ0 = $(MPM:<=w3i6mv\rash\)
-FMTDYOBJ0 = $(FMTDY:<=w3i6mv\rash\)
-FMTTESTOBJ0 = $(FMTTEST:<=w3i6mv\rash\)
-FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i6mv\rash\)
-POOLNOBJ0 = $(POOLN:<=w3i6mv\rash\)
-TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\rash\)
-TESTTHROBJ0 = $(TESTTHR:<=w3i6mv\rash\)
-
-!ENDIF
-
-# %%PART: When adding a new part, add new macros which expand to the object
-# files included in the part
-
-MPMOBJ = $(MPMOBJ0:>=.obj)
-FMTDYOBJ = $(FMTDYOBJ0:>=.obj)
-FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj)
-FMTSCHEMEOBJ = $(FMTSCHEMEOBJ0:>=.obj)
-POOLNOBJ = $(POOLNOBJ0:>=.obj)
-TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj)
-TESTTHROBJ = $(TESTTHROBJ0:>=.obj)
-
-
-!INCLUDE commpost.nmk
+!INCLUDE comm.nmk
# C. COPYRIGHT AND LICENSE
diff --git a/mps/code/w3i6pc.nmk b/mps/code/w3i6pc.nmk
index 58488b757f7..31b86a82fc0 100644
--- a/mps/code/w3i6pc.nmk
+++ b/mps/code/w3i6pc.nmk
@@ -7,88 +7,22 @@
PFM = w3i6pc
-PFMDEFS = /DCONFIG_PF_STRING="w3i6pc" /DCONFIG_PF_W3I6PC /DWIN32 /D_WINDOWS
+CFLAGSTARGETPRE = /Tamd64-coff
-CFLAGSCOMMONPRE = $(CFLAGSCOMMONPRE) /Tamd64-coff
-
-# MPM platform-specific sources.
MPMPF = \
- \
- \
- \
- \
- \
- \
- \
- \
- \
-
+ [lockw3] \
+ [mpsiw3] \
+ [prmci6w3] \
+ [proti6] \
+ [protw3] \
+ [spw3i6] \
+ [ssw3i6pc] \
+ [thw3] \
+ [thw3i6] \
+ [vmw3]
-!INCLUDE commpre.nmk
!INCLUDE pc.nmk
-
-
-# Source to object file mappings and CFLAGS amalgamation
-#
-# %%VARIETY %%PART: When adding a new variety or part, add new macros which
-# expand to the files included in the part for each variety
-#
-# %%VARIETY: When adding a new variety, add a CFLAGS macro which expands to
-# the flags that that variety should use when compiling C. And a LINKFLAGS
-# macro which expands to the flags that the variety should use when building
-# executables. And a LIBFLAGS macro which expands to the flags that the
-# variety should use when building libraries
-
-!IF "$(VARIETY)" == "hot"
-CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST)
-CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST)
-LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT)
-LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT)
-MPMOBJ0 = $(MPM:<=w3i6pc\hot\)
-FMTDYOBJ0 = $(FMTDY:<=w3i6pc\hot\)
-FMTTESTOBJ0 = $(FMTTEST:<=w3i6pc\hot\)
-POOLNOBJ0 = $(POOLN:<=w3i6pc\hot\)
-TESTLIBOBJ0 = $(TESTLIB:<=w3i6pc\hot\)
-TESTTHROBJ0 = $(TESTTHR:<=w3i6pc\hot\)
-
-!ELSEIF "$(VARIETY)" == "cool"
-CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST)
-CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST)
-LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL)
-LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL)
-MPMOBJ0 = $(MPM:<=w3i6pc\cool\)
-FMTDYOBJ0 = $(FMTDY:<=w3i6pc\cool\)
-FMTTESTOBJ0 = $(FMTTEST:<=w3i6pc\cool\)
-POOLNOBJ0 = $(POOLN:<=w3i6pc\cool\)
-TESTLIBOBJ0 = $(TESTLIB:<=w3i6pc\cool\)
-TESTTHROBJ0 = $(TESTTHR:<=w3i6pc\cool\)
-
-!ELSEIF "$(VARIETY)" == "rash"
-CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST)
-CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST)
-LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH)
-LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH)
-MPMOBJ0 = $(MPM:<=w3i6pc\rash\)
-FMTDYOBJ0 = $(FMTDY:<=w3i6pc\rash\)
-FMTTESTOBJ0 = $(FMTTEST:<=w3i6pc\rash\)
-POOLNOBJ0 = $(POOLN:<=w3i6pc\rash\)
-TESTLIBOBJ0 = $(TESTLIB:<=w3i6pc\rash\)
-TESTTHROBJ0 = $(TESTTHR:<=w3i6pc\rash\)
-
-!ENDIF
-
-# %%PART: When adding a new part, add new macros which expand to the object
-# files included in the part
-
-MPMOBJ = $(MPMOBJ0:>=.obj)
-FMTDYOBJ = $(FMTDYOBJ0:>=.obj)
-FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj)
-POOLNOBJ = $(POOLNOBJ0:>=.obj)
-TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj)
-TESTTHROBJ = $(TESTTHROBJ0:>=.obj)
-
-
-!INCLUDE commpost.nmk
+!INCLUDE comm.nmk
# C. COPYRIGHT AND LICENSE
diff --git a/mps/code/walk.c b/mps/code/walk.c
index 544c9644498..38278cce1ad 100644
--- a/mps/code/walk.c
+++ b/mps/code/walk.c
@@ -56,7 +56,7 @@ static void ArenaFormattedObjectsStep(Addr object, Format format, Pool pool,
*
* So called because it walks all formatted objects in an arena. */
-static void ArenaFormattedObjectsWalk(Arena arena, FormattedObjectsStepMethod f,
+static void ArenaFormattedObjectsWalk(Arena arena, FormattedObjectsVisitor f,
void *p, size_t s)
{
Seg seg;
@@ -192,7 +192,7 @@ static void rootsStepClosureInit(rootsStepClosure rsc,
/* First initialize the ScanState superclass */
ss = &rsc->ssStruct;
- ScanStateInit(ss, TraceSetSingle(trace), GlobalsArena(arena), RankAMBIG,
+ ScanStateInit(ss, TraceSetSingle(trace), GlobalsArena(arena), RankMIN,
trace->white);
/* Initialize the fix method in the ScanState */
@@ -338,7 +338,7 @@ static Res ArenaRootsWalk(Globals arenaGlobals, mps_roots_stepper_t f,
rootsStepClosureInit(rsc, arenaGlobals, trace, RootsWalkFix, f, p, s);
ss = rootsStepClosure2ScanState(rsc);
- for(rank = RankAMBIG; rank < RankLIMIT; ++rank) {
+ for(rank = RankMIN; rank < RankLIMIT; ++rank) {
ss->rank = rank;
AVERT(ScanState, ss);
res = RootsIterate(arenaGlobals, rootWalk, (void *)ss);
diff --git a/mps/code/xci6ll.gmk b/mps/code/xci6ll.gmk
index d6787856a35..597979539ef 100644
--- a/mps/code/xci6ll.gmk
+++ b/mps/code/xci6ll.gmk
@@ -24,8 +24,6 @@ MPMPF = \
thxc.c \
vmix.c
-LIBS = -lm
-
include ll.gmk
include comm.gmk
diff --git a/mps/contributing.rst b/mps/contributing.rst
index d397be35ce1..82b5ff4c840 100644
--- a/mps/contributing.rst
+++ b/mps/contributing.rst
@@ -1,11 +1,5 @@
Contributing to the MPS
=======================
-:author: Richard Brooksby
-:organization: Ravenbrook Limited
-:date: 2013-07-05
-:revision: $Id$
-:confidentiality: public
-
We are very happy to receive contributions to the Memory Pool System so
that we can improve it for everyone.
diff --git a/mps/design/abq.txt b/mps/design/abq.txt
index 0273b4510eb..ec3c944355c 100644
--- a/mps/design/abq.txt
+++ b/mps/design/abq.txt
@@ -92,7 +92,7 @@ If the queue is full, return ``TRUE``, otherwise return ``FALSE``.
Return the number of elements in the queue.
-``typedef Bool (*ABQIterateMethod)(Bool *deleteReturn, void *element, void *closureP, Size closureS)``
+``typedef Bool (*ABQVisitor)(Bool *deleteReturn, void *element, void *closureP, Size closureS)``
A callback function for ``ABQIterate()``. The parameter ``element`` is
an element in the queue, and ``closureP`` and ``closureS`` are the
@@ -102,10 +102,10 @@ the queue, or ``TRUE`` if ``element`` must be deleted from the queue.
It must return ``TRUE`` if the iteration must continue, or ``FALSE``
if the iteration must stop after processing ``element``.
-``void ABQIterate(ABQ abq, ABQIterateMethod iterate, void *closureP, Size closureS)``
+``void ABQIterate(ABQ abq, ABQVisitor visitor, void *closureP, Size closureS)``
-Call ``iterate`` for each elements in the queue, passing the element
-and ``closureP``. See ``ABQIterateMethod`` for details.
+Call ``visitor`` for each element in the queue, passing the element
+and ``closureP``. See ``ABQVisitor`` for details.
Document History
diff --git a/mps/design/an.txt b/mps/design/an.txt
new file mode 100644
index 00000000000..7d6cc117407
--- /dev/null
+++ b/mps/design/an.txt
@@ -0,0 +1,216 @@
+.. mode: -*- rst -*-
+
+Generic modules
+===============
+
+:Tag: design.mps.an
+:Author: Gareth Rees
+:Date: 2014-11-02
+:Status: complete design
+:Revision: $Id$
+:Copyright: See `Copyright and License`_.
+:Index terms: pair: generic modules; design
+
+
+Introduction
+------------
+
+_`.intro`: This is the design of generic modules in the MPS.
+
+_`.readership`: Any MPS developer; anyone porting the MPS to a new
+platform.
+
+_`.overview`: Generic modules provide implementations of functional
+modules using only the features of the Standard C Library. These
+implementations are partially functional or non-functional, but
+provide a basis for ports of the MPS to new platforms.
+
+_`.name`: The name "ANSI" for the generic modules is historical: the C
+language was originally standardized by the American National
+Standards Institute, and so Standard C used to be known as "ANSI C".
+
+
+Requirements
+------------
+
+_`.req.port`: The MPS must be portable to new platforms. (Otherwise we
+can't meet the needs of customers using new platforms.)
+
+_`.req.port.rapid`: The MPS should be portable to new platforms
+rapidly.
+
+_`.req.port.rapid.expert`: An expert MPS developer (who may be a
+novice on the new platform) should be able to get a minimally useful
+implementation of the MPS running on a new platform within a few
+hours.
+
+_`.req.port.rapid.novice`: A novice MPS developer (who is an expert on
+the new platform) should be able to get the MPS running on a new
+platform within a few days.
+
+
+Design
+------
+
+_`.sol.modules`: Features of the MPS which can benefit from
+platform-specific implementations are divided into *functional
+modules*, with clean interfaces to the MPS and to each other. See
+`.mod`_ for a list of these modules. (This helps meet `.req.port`_ by
+isolating the platform dependencies, and it helps meet
+`.req.port.rapid`_ because a porter can mix and match implementations,
+using existing implementations where possible.)
+
+_`.sol.generic`: Each functional module has a generic implementation
+using only features of the Standard C Library. (This helps meet
+`.req.port.rapid`_ because the MPS can be ported in stages, starting
+with the generic modules and porting the modules needed to meet the
+most urgent requirements. The generic implementations help meet
+`.req.port.rapid.novice`_ by providing clear and illustrative
+examples.)
+
+_`.sol.fallback`: The interfaces to the modules are designed to make
+it possible to implement `.sol.generic`_. When a platform-specific
+feature is needed to meet performance (or other attribute)
+requirements, the interface also makes it possible to meet the
+functional requirements while missing the attribute requirements. See
+`.sol.fallback.example`_ for an example. (This helps meet
+`.req.port.rapid`_ by allowing the generic implementations to meet
+many or most of the functional requirements.)
+
+_`.sol.fallback.example`: The MPS normally uses incremental collection
+to meet requirements on pause times, but this requires barriers. The
+interface to the protection module is designed to make it possible to
+write an implementation without barriers, via the function
+``ProtSync()`` that synchronizes the mutator with the collector.
+
+_`.sol.test`: There are makefiles for the pseudo-platforms ``anangc``,
+``ananll`` and ``ananmv`` that compile and test the generic
+implementations. See design.mps.config.opt_ for the configuration
+options used to implement these platforms. (This supports
+`.req.port.rapid`_ by making sure that the generic implementations are
+working when it is time to use them.)
+
+.. _design.mps.config.opt: config#opt
+
+
+Modules
+-------
+
+_`.mod`: This section lists the functional modules in the MPS.
+
+_`.mod.lock`: Locks. See design.mps.lock_.
+
+_`.mod.prmc`: Protection mutator context. See design.mps.prmc_.
+
+_`.mod.prot`: Memory protection. See design.mps.prot_.
+
+_`.mod.ss`: Stack and register scanning. See design.mps.ss_.
+
+_`.mod.sp`: Stack probe. See design.mps.sp_.
+
+_`.mod.th`: Thread manager. See design.mps.thread-manager_.
+
+_`.mod.vm`: Virtual mapping. See design.mps.vm_.
+
+.. _design.mps.lock: lock
+.. _design.mps.prot: prot
+.. _design.mps.prmc: prmc
+.. _design.mps.sp: sp
+.. _design.mps.ss: ss
+.. _design.mps.thread-manager: thread-manager
+.. _design.mps.vm: vm
+
+
+Limitations of generic implementations
+--------------------------------------
+
+_`.lim`: This section summarizes the limitations of the generic
+implementations of the function modules.
+
+_`.lim.lock`: Requires a single-threaded mutator (see
+design.mps.lock.impl.an_).
+
+_`.lim.prmc`: Does not support single-stepping of accesses (see
+design.mps.prmc.impl.an.fault_) and requires a single-threaded mutator
+(see design.mps.prmc.impl.an.suspend_).
+
+_`.lim.prot`: Does not support incremental collection (see
+design.mps.prot.impl.an.sync_) and is not compatible with
+implementations of the protection mutator context module that support
+single-stepping of accesses (see design.mps.prot.impl.an.sync.issue_).
+
+_`.lim.sp`: Only suitable for use with programs that do not handle
+stack overflow faults, or do not call into the MPS from the handler
+(see design.mps.sp.issue.an_).
+
+_`.lim.ss`: Overscans compared to a platform-specific implementation
+(see design.mps.ss.impl.an_).
+
+_`.lim.th`: Requires a single-threaded mutator (see
+design.mps.thread-manager.impl.an.single_).
+
+_`.lim.vm`: Maps all reserved addresses into main memory (see
+design.mps.vm.impl.an.reserve_), thus using more main memory than a
+platform-specific implementation.
+
+.. _design.mps.lock.impl.an: lock#impl.an
+.. _design.mps.prmc.impl.an.fault: prmc#impl.an.fault
+.. _design.mps.prmc.impl.an.suspend: prmc#impl.an.suspend
+.. _design.mps.prot.impl.an.sync: prot#impl.an.sync
+.. _design.mps.prot.impl.an.sync.issue: prot#impl.an.sync.issue
+.. _design.mps.sp.issue.an: sp#issue.an
+.. _design.mps.ss.impl.an: ss#impl.an
+.. _design.mps.thread-manager.impl.an.single: thread-manager#impl.an.single
+.. _design.mps.vm.impl.an.reserve: vm#impl.an.reserve
+
+
+
+Document History
+----------------
+
+- 2014-11-02 GDR_ Initial draft based on design.mps.protan.
+
+.. _GDR: http://www.ravenbrook.com/consultants/gdr/
+
+
+Copyright and License
+---------------------
+
+Copyright © 2014 Ravenbrook Limited. All rights reserved.
+ . This is an open source license. Contact
+Ravenbrook for commercial licensing options.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+#. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+#. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+#. Redistributions in any form must be accompanied by information on how
+ to obtain complete source code for this software and any
+ accompanying software that uses this software. The source code must
+ either be included in the distribution or be available for no more than
+ the cost of distribution plus a nominal fee, and must be freely
+ redistributable under reasonable conditions. For an executable file,
+ complete source code means the source code for all modules it contains.
+ It does not include source code for modules or files that typically
+ accompany the major components of the operating system on which the
+ executable file runs.
+
+**This software is provided by the copyright holders and contributors
+"as is" and any express or implied warranties, including, but not
+limited to, the implied warranties of merchantability, fitness for a
+particular purpose, or non-infringement, are disclaimed. In no event
+shall the copyright holders and contributors be liable for any direct,
+indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or
+services; loss of use, data, or profits; or business interruption)
+however caused and on any theory of liability, whether in contract,
+strict liability, or tort (including negligence or otherwise) arising in
+any way out of the use of this software, even if advised of the
+possibility of such damage.**
diff --git a/mps/design/arena.txt b/mps/design/arena.txt
index 6b8c20517c1..a72bfbcb09c 100644
--- a/mps/design/arena.txt
+++ b/mps/design/arena.txt
@@ -63,11 +63,14 @@ Requirements
sources of requirements so that they are traceable to client
requirements. Most of these come from the architectural design
(design.mps.architecture) or the fix function design
- (design.mps.fix). Richard Brooksby, 1995-08-28.
+ (design.mps.fix_). Richard Brooksby, 1995-08-28.
- They were copied from design.mps.arena.vm(1) and edited slightly.
+ They were copied from design.mps.arena.vm_ and edited slightly.
David Jones, 1999-06-23.
+ .. _design.mps.fix: fix
+ .. _design.mps.arena.vm: arenavm
+
Block management
................
@@ -120,7 +123,7 @@ contiguous addresses at any time.
_`.req.fun.trans.white`: If the address is managed by an automatic
pool, the set of traces for which the address is white. This is
required so that the second-stage fix protocol can reject non-white
-addresses quickly. See `design.mps.critical-path`_.
+addresses quickly. See design.mps.critical-path_.
.. _design.mps.critical-path: critical-path
@@ -193,7 +196,7 @@ Arena classes
``typedef mps_arena_s *Arena``
_`.class`: The ``Arena`` data structure is designed to be subclassable
-(see `design.mps.protocol`_). Clients can select what arena class
+(see design.mps.protocol_). Clients can select what arena class
they'd like when instantiating one with ``mps_arena_create_k()``. The
arguments to ``mps_arena_create_k()`` are class-dependent.
@@ -240,9 +243,7 @@ _`.chunk.tracts`: A chunk contains a table of tracts. See `.tract`_.
_`.chunk.lookup`: Looking of the chunk of an address is the first
step in the second-stage fix operation, and so on the critical path.
-See `design.mps.critical-path`_.
-
-.. _design.mps.critical-path: critical-path
+See design.mps.critical-path_.
_`.chunk.tree`: For efficient lookup, chunks are stored in a balanced
tree; ``arena->chunkTree`` points to the root of the tree. Operations
@@ -314,7 +315,7 @@ use it for any purpose.
_`.tract.field.hasSeg`: The ``hasSeg`` bit-field is a Boolean which
indicates whether the ``p`` field is being used by the segment module.
If this field is ``TRUE``, then the value of ``p`` is a ``Seg``. See
-`design.mps.type.bool.bitfield`_ for why this is declared using the
+design.mps.type.bool.bitfield_ for why this is declared using the
``BOOLFIELD`` macro.
.. _design.mps.type.bool.bitfield: type#bool.bitfield
@@ -325,7 +326,7 @@ memory represented by the tract.
_`.tract.field.white`: The white bit-field indicates for which traces
the tract is white (`.req.fun.trans.white`_). This information is also
stored in the segment, but is duplicated here for efficiency during a
-call to ``TraceFix()`` (see `design.mps.trace.fix`_).
+call to ``TraceFix()`` (see design.mps.trace.fix_).
.. _design.mps.trace.fix: trace#fix
@@ -559,12 +560,12 @@ _`.ld.epoch`: ``arena->epoch`` is the "current epoch". This is the
number of 'flips' of traces in the arena since the arena was created.
From the mutator's point of view locations change atomically at flip.
-_`.ld.history`: ``arena->history`` is an array of ``ARENA_LD_LENGTH``
-elements of type ``RefSet``. These are the summaries of moved objects
-since the last ``ARENA_LD_LENGTH`` epochs. If ``e`` is one of these
-recent epochs, then ::
+_`.ld.history`: ``arena->history`` is a circular buffer of
+``LDHistoryLENGTH`` elements of type ``RefSet``. These are the
+summaries of moved objects since the last ``LDHistoryLENGTH`` epochs.
+If ``e`` is one of these recent epochs, then ::
- arena->history[e % ARENA_LD_LENGTH]
+ arena->history[e % LDHistoryLENGTH]
is a summary of (the original locations of) objects moved since epoch
``e``.
diff --git a/mps/design/arenavm.txt b/mps/design/arenavm.txt
index 92b24d8234d..d746f18d883 100644
--- a/mps/design/arenavm.txt
+++ b/mps/design/arenavm.txt
@@ -17,10 +17,11 @@ Virtual Memory Arena
Introduction
------------
-_`.intro`: This document describes the detailed design of the Virtual
-Memory Arena Class of the Memory Pool System. The VM Arena Class is
-just one class available in the MPS. The generic arena part is
-described in design.mps.arena.
+_`.intro`: This is the design of the Virtual Memory Arena Class of the
+Memory Pool System. The VM Arena Class is just one class available in
+the MPS. The generic arena part is described in design.mps.arena_.
+
+.. _design.mps.arena: arena
Overview
@@ -28,23 +29,30 @@ Overview
_`.overview`: VM arenas provide blocks of memory to all other parts of
the MPS in the form of "tracts" using the virtual mapping interface
-(design.mps.vm) to the operating system. The VM Arena Class is not
+(design.mps.vm_) to the operating system. The VM Arena Class is not
expected to be provided on platforms that do not have virtual memory
-(like MacOS, os.s7(1)).
+(for example, Macintosh System 7).
+
+.. _design.mps.vm: vm
_`.overview.gc`: The VM Arena Class provides some special services on
these blocks in order to facilitate garbage collection:
_`.overview.gc.zone`: Allocation of blocks with specific zones. This
-means that the generic fix function (design.mps.fix) can use a fast
+means that the generic fix function (design.mps.fix_) can use a fast
refset test to eliminate references to addresses that are not in the
condemned set. This assumes that a pool class that uses this placement
appropriately is being used (such as the generation placement policy
-used by AMC: see design.mps.poolamc(1)) and that the pool selects the
+used by AMC: see design.mps.poolamc_) and that the pool selects the
condemned sets to coincide with zone stripes.
+.. _design.mps.fix: fix
+.. _design.mps.poolamc: poolamc
+
_`.overview.gc.tract`: A fast translation from addresses to tract.
-(See design.mps.arena.req.fun.trans)
+(See design.mps.arena.req.fun.trans_.)
+
+.. _design.mps.arena.req.fun.trans: arena#req.fun.trans
Notes
@@ -52,16 +60,20 @@ Notes
_`.note.refset`: Some of this document simply assumes that RefSets
(see the horribly incomplete design.mps.refset) have been chosen as
-the solution for design.mps.arena.req.fun.set. It's a lot simpler that
-way. Both to write and understand.
+the solution for design.mps.arena.req.fun.set_. It's a lot simpler
+that way. Both to write and understand.
+
+.. _design.mps.arena.req.fun.set: arena#req.fun.set
Requirements
------------
Most of the requirements are in fact on the generic arena (see
-design.mps.arena.req). However, many of those requirements can only be
-met by a suitable arena class design.
+design.mps.arena.req_). However, many of those requirements can only
+be met by a suitable arena class design.
+
+.. _design.mps.arena.req: arena#req
Requirements particular to this arena class:
@@ -78,17 +90,17 @@ of suitable addresses.
Arena partition
...............
-_`.req.fun.set`: See design.mps.arena.req.fun.set. The approximation
-to sets of address must cooperate with the placement mechanism in the
-way required by `.req.fun.place`_ (above).
+_`.req.fun.set`: See design.mps.arena.req.fun.set_. The
+approximation to sets of address must cooperate with the placement
+mechanism in the way required by `.req.fun.place`_ (above).
Architecture
------------
_`.arch.memory`: The underlying memory is obtained from whatever
-Virtual Memory interface (see design.mps.vm). @@@@ Explain why this is
-used.
+Virtual Memory interface (see design.mps.vm_). @@@@ Explain why this
+is used.
Solution ideas
@@ -172,10 +184,14 @@ _`.table.page.partial`: The table is partially mapped on an
_`.table.page.tract`: Each page table entry contains a tract, which is
only valid if it is allocated to a pool. If it is not allocated to a
pool, the fields of the tract are used for other purposes. (See
-design.mps.arena.tract.field.pool)
+design.mps.arena.tract.field.pool_)
+
+.. _design.mps.arena.tract.field.pool: arena#tract.field.pool
_`.table.alloc`: The alloc table is a simple bit table (implemented
-using the BT module, design.mps.bt).
+using the BT module, design.mps.bt_).
+
+.. _design.mps.bt: bt
_`.table.alloc.map`: Each page in the VM has a corresponding alloc
table entry.
diff --git a/mps/design/bootstrap.txt b/mps/design/bootstrap.txt
new file mode 100644
index 00000000000..7eb79df1475
--- /dev/null
+++ b/mps/design/bootstrap.txt
@@ -0,0 +1,127 @@
+.. mode: -*- rst -*-
+
+Bootstrapping
+=============
+
+:Tag: design.mps.bootstrap
+:Author: Gareth Rees
+:Date: 2015-09-01
+:Status: incomplete design
+:Revision: $Id$
+:Copyright: See section `Copyright and License`_.
+:Index terms: pair: bootsrap; design
+
+
+Introduction
+------------
+
+_`.intro`: This explains how the MPS gets started.
+
+_`.readership`: Any MPS developer.
+
+_`.overview`: The job of the MPS is to allocate memory to a program.
+Before it can allocate memory, the MPS needs to create data structures
+to represent its internal state. But before it can create those data
+structures, it needs to allocate memory to store them in. This
+bootstrapping problem affects the MPS at several points, which are
+listed here, together with their solutions.
+
+
+Bootstrapping problems
+----------------------
+
+Virtual memory descriptor
+.........................
+
+_`.vm`: Before address space can be mapped into main memory, the
+virtual memory descriptor must be initialized. But before the virtual
+memory descriptor can be initialized, some address space must be
+mapped into main memory in order to store it. See
+`design.vm.req.bootstrap`_.
+
+_`.vm.sol`: The virtual memory descriptor is allocated initially on
+the stack, and then copied into its place in the chunk after the
+memory for it has been mapped. See `design.vm.sol.bootstrap`_.
+
+.. _design.vm.req.bootstrap: vm#req.bootstrap
+.. _design.vm.sol.bootstrap: vm#sol.bootstrap
+
+
+Arena descriptor
+................
+
+_`.arena`: Before chunks of address space can be reserved and mapped,
+the virtual memory arena descriptor must be initialized (so that the
+chunks can be added to the arena's chunk tree). But before a virtual
+memory arena descriptor can be initialized, address space must be
+reserved and mapped in order to store it.
+
+_`.arena.sol`: A small amount of address space is reserved and mapped
+directly via ``VMInit()`` and ``VMMap()`` (not via the chunk system)
+in order to provide enough memory for the arena descriptor.
+
+
+Arena's free land
+.................
+
+_`.land`: Before the arena can allocate memory, a range of addresses
+must be inserted into the arena's free land (so that the free land can
+hand out memory from this range). But before addresses can be inserted
+into the arena's free land, the arena must be able to allocate memory
+(to store the nodes in the tree representing those addresses).
+
+_`.land.sol`: The arena has two "back door" mechanisms and uses them
+in combination. First, there is a mechanism for allocating a block of
+memory directly from a chunk, bypassing the free land; second, the MFS
+pool class has a mechanism for extending it with a block of memory.
+
+
+Document History
+----------------
+
+- 2015-09-01 GDR_ Initial draft.
+
+.. _GDR: http://www.ravenbrook.com/consultants/gdr/
+
+
+Copyright and License
+---------------------
+
+Copyright © 2015 Ravenbrook Limited. All rights reserved.
+ . This is an open source license. Contact
+Ravenbrook for commercial licensing options.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+#. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+#. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+#. Redistributions in any form must be accompanied by information on how
+ to obtain complete source code for this software and any
+ accompanying software that uses this software. The source code must
+ either be included in the distribution or be available for no more than
+ the cost of distribution plus a nominal fee, and must be freely
+ redistributable under reasonable conditions. For an executable file,
+ complete source code means the source code for all modules it contains.
+ It does not include source code for modules or files that typically
+ accompany the major components of the operating system on which the
+ executable file runs.
+
+**This software is provided by the copyright holders and contributors
+"as is" and any express or implied warranties, including, but not
+limited to, the implied warranties of merchantability, fitness for a
+particular purpose, or non-infringement, are disclaimed. In no event
+shall the copyright holders and contributors be liable for any direct,
+indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or
+services; loss of use, data, or profits; or business interruption)
+however caused and on any theory of liability, whether in contract,
+strict liability, or tort (including negligence or otherwise) arising in
+any way out of the use of this software, even if advised of the
+possibility of such damage.**
diff --git a/mps/design/bt.txt b/mps/design/bt.txt
index 415484b775c..bc069efd2a9 100644
--- a/mps/design/bt.txt
+++ b/mps/design/bt.txt
@@ -15,14 +15,14 @@ Bit tables
Introduction
------------
-_`.intro`: This is the design of the Bit Tables module. A Bit Table is a
-linear array of bits. A Bit Table of length *n* is indexed using an
+_`.intro`: This is the design of the Bit Tables module. A Bit Table is
+a linear array of bits. A Bit Table of length *n* is indexed using an
integer from 0 up to (but not including) *n*. Each bit in a Bit Table
-can hold either the value 0 (aka ``FALSE``) or 1 (aka ``TRUE``). A
-variety of operations are provided including: set, reset, and
-retrieve, individual bits; set and reset a contiguous range of bits;
-search for a contiguous range of reset bits; making a "negative image"
-copy of a range.
+can hold either the value 0 (``FALSE``) or 1 (``TRUE``). A variety of
+operations are provided including: get, set, and reset individual
+bits; set and reset a contiguous range of bits; search for a
+contiguous range of reset bits; making a "negative image" copy of a
+range.
_`.readership`: MPS developers.
@@ -34,15 +34,13 @@ _`.def.set`: **Set**
Used as a verb meaning to assign the value 1 or ``TRUE`` to a bit.
Used descriptively to denote a bit containing the value 1. Note 1
- and ``TRUE`` are synonyms in MPS C code (see
- design.mps.type(0).bool.value).
+ and ``TRUE`` are synonyms in MPS C code (see ``Bool``).
_`.def.reset`: **Reset**
Used as a verb meaning to assign the value 0 or ``FALSE`` to a
bit. Used descriptively to denote a bit containing the value 0.
- Note 0 and ``FALSE`` are synonyms in MPS C code (see
- design.mps.type(0).bool.value).
+ Note 0 and ``FALSE`` are synonyms in MPS C code (see ``Bool``).
.. note::
@@ -55,7 +53,7 @@ _`.def.bt`: **Bit Table**
A Bit Table is a mapping from [0, *n*) to {0,1} for some *n*,
represented as a linear array of bits.
- _`..def.bt.justify`: They are called *bit tables* because a single
+ _`.def.bt.justify`: They are called *Bit Tables* because a single
bit is used to encode whether the image of a particular integer
under the map is 0 or 1.
@@ -68,22 +66,22 @@ _`.def.range`: **Range**
[*base*, *limit*), is used.
-
Requirements
------------
-_`.req.bit`: The storage for a Bit Table of *n* bits shall take no more
-than a small constant addition to the storage required for *n* bits.
-_`..req.bit.why`: This is so that clients can make some predictions
-about how much storage their algorithms use. A small constant is
-allowed over the minimal for two reasons: inevitable implementation
-overheads (such as only being able to allocate storage in multiples of
-32 bits), extra storage for robustness or speed (such as signature and
-length fields).
+_`.req.bit`: The storage for a Bit Table of *n* bits shall take no
+more than a small constant addition to the storage required for *n*
+bits. _`.req.bit.why`: This is so that clients can make some
+predictions about how much storage their algorithms use. A small
+constant is allowed over the minimal for two reasons: inevitable
+implementation overheads (such as only being able to allocate storage
+in multiples of 32 bits), extra storage for robustness or speed (such
+as signature and length fields).
-_`.req.create`: A means to create Bit Tables. _`.req.create.why`: Obvious.
+_`.req.create`: A means to create Bit Tables. _`.req.create.why`:
+Obvious.
-_`.req.destroy`: A means to destroy Bit Tables. _`.req.destroy.why`
+_`.req.destroy`: A means to destroy Bit Tables. _`.req.destroy.why`:
Obvious.
_`.req.ops`: The following operations shall be supported:
@@ -118,7 +116,7 @@ operations.
range of bits are all reset. _`.req.ops.test.range.reset.why`
As for IsSetRange, see `.req.ops.test.range.set.why`_.
-* _`.req.ops.find`: Find a range (which we'll denote [*i*, *j*)) of at
+* _`.req.ops.find`: Find a range, which we'll denote [*i*, *j*), of at
least *L* reset bits that lies in a specified subrange of the entire
Bit Table. Various find operations are required according to the
(additional) properties of the required range:
@@ -176,8 +174,8 @@ operations.
manipulation code in ``PoolClassAMS`` and ``PoolClassLO``.
_`.req.speed`: Operations shall take no more than a few memory
-operations per bit manipulated. _`.req.speed.why`: Any slower
-would be gratuitous.
+operations per bit manipulated. _`.req.speed.why`: Any slower would be
+gratuitous.
_`.req.speed.fast`: The following operations shall be very fast:
@@ -188,7 +186,7 @@ _`.req.speed.fast`: The following operations shall be very fast:
_`.req.speed.fast.find.short.why`: These two are used by the client
arena (design.mps.arena.client) and the VM arena
- (design.mps.arena.vm) for finding segments in page tables. The
+ (design.mps.arena.vm_) for finding segments in page tables. The
operation will be used sufficiently often that its speed will
noticeably affect the overall speed of the MPS. They will be called
with a length equal to the number of pages in a segment. Typical
@@ -198,19 +196,23 @@ _`.req.speed.fast`: The following operations shall be very fast:
it is populated at all, that is set bits will tend to be clustered
together in subranges.
+ .. _design.mps.arena.vm: arenavm
+
* _`.req.speed.fast.find.long`: FindLongResRange (the operation
used to meet `.req.ops.find.long.low`_)
_`.req.speed.fast.find.long.why`: Used in the allocator for
- ``PoolClassAWL`` (design.mps.poolawl(1)), ``PoolClassAMS``
- (design.mps.poolams(2)), ``PoolClassEPVM`` (design.mps.poolepvm(0)).
+ ``PoolClassAWL`` (design.mps.poolawl_), ``PoolClassAMS``
+ (design.mps.poolams_), ``PoolClassEPVM`` (design.mps.poolepvm(0)).
Of these AWL and EPVM have speed requirements. For AWL the length of
range to be found will be the length of a Dylan table in words.
- According to `mail.tony.1999-05-05.11-36`_, only
- objects are allocated in AWL (though not all objects
- are allocated in AWL), and the mean length of an
- object is 486 Words. No data for EPVM alas.
+ According to `mail.tony.1999-05-05.11-36`_, only ````
+ objects are allocated in AWL (though not all ````
+ objects are allocated in AWL), and the mean length of an
+ ```` object is 486 Words. No data for EPVM alas.
+ .. _design.mps.poolawl: poolawl
+ .. _design.mps.poolams: poolams
.. _mail.tony.1999-05-05.11-36: https://info.ravenbrook.com/project/mps/mail/1999/05/05/11-36/0.txt
_`.req.speed.fast.other.why`: We might expect mark and sweep pools to
@@ -244,10 +246,14 @@ Background
----------
_`.background`: Originally Bit Tables were used and implemented
-by ``PoolClassLO`` (design.mps.poollo). It was
+by ``PoolClassLO`` (design.mps.poollo_). It was
decided to lift them out into a separate module when designing the
Pool to manage Dylan Weak Tables which is also a mark and sweep pool
-and will make use of Bit Tables (see design.mps.poolawl).
+and will make use of Bit Tables (see design.mps.poolawl_).
+
+.. _design.mps.poollo: poollo
+.. _design.mps.poolawl: poolawl
+
_`.background.analysis`: analysis.mps.bt(0) contains
some of the analysis of the design decisions that were and were not
made in this document.
@@ -258,7 +264,7 @@ Clients
_`.clients`: Bit Tables are used throughout the MPS but the important
uses are in the client and VM arenas (design.mps.arena.client(0) and
-design.mps.arena.vm(1)) a bit table is used to record whether each
+design.mps.arena.vm_) a bit table is used to record whether each
page is free or not; several pool classes (``PoolClassLO``,
``PoolClassEPVM``, ``PoolClassAMS``) use bit tables to record which
locations are free and also to store colour.
@@ -368,7 +374,7 @@ _`.if.test.range.reset`: Returns ``TRUE`` if all the bits in the range
[``base``, ``limit``) are reset, ``FALSE`` otherwise. Meets
`.req.ops.test.range.reset`_.
-``Bool BTRangesSame(BT BTx, BT BTy, Index base, Index limit);``
+``Bool BTRangesSame(BT BTx, BT BTy, Index base, Index limit)``
_`.if.test.range.same`: returns ``TRUE`` if ``BTGet(BTx,i)`` equals
``BTGet(BTy,i)`` for ``i`` in [``base``, ``limit``), and ``FALSE``
@@ -695,10 +701,12 @@ _`.test.btcv`: ``btcv.c``. This is supposed to be a coverage test,
intended to execute all of the module's code in at least some minimal
way.
-_`.test.cbstest`: ``cbstest.c``. This was written as a test of the
-``CBS`` module (design.mps.cbs(2)). It compares the functional
-operation of a ``CBS`` with that of a ``BT`` so is a good functional
-test of either module.
+_`.test.landtest`: ``landtest.c``. This is a test of the ``Land``
+module (design.mps.land_) and its concrete implementations. It
+compares the functional operation of a ``Land`` with that of a ``BT``
+so is a good functional test of either module.
+
+.. _design.mps.land: land
_`.test.mmqa.120`: MMQA_test_function!210.c. This is used because it has
a fair amount of segment allocation and freeing so exercises the arena
diff --git a/mps/design/buffer.txt b/mps/design/buffer.txt
index 9b660ce4dd1..ae55fa34204 100644
--- a/mps/design/buffer.txt
+++ b/mps/design/buffer.txt
@@ -15,8 +15,8 @@ Allocation buffers and allocation points
Introduction
------------
-_`.scope`: This document describes the design of allocation buffers
-and allocation points.
+_`.scope`: This is the design of allocation buffers and allocation
+points.
_`.purpose`: The purpose of this document is to record design
decisions made concerning allocation buffers and allocation points and
@@ -128,7 +128,9 @@ Classes
-------
_`.class.hierarchy`: The ``Buffer`` data structure is designed to be
-subclassable (see design.mps.protocol).
+subclassable (see design.mps.protocol_).
+
+.. _design.mps.protocol: protocol
_`.class.hierarchy.buffer`: The basic buffer class (``BufferClass``)
supports basic allocation-point buffering, and is appropriate for
@@ -178,15 +180,19 @@ _`.subclassing`: Pools may create their own subclasses of the standard
buffer classes. This is sometimes useful if the pool needs to add an
extra field to the buffer. The convenience macro
``DEFINE_BUFFER_CLASS()`` may be used to define subclasses of buffer
-classes. See design.mps.protocol.int.define-special.
+classes. See design.mps.protocol.int.define-special_.
+
+.. _design.mps.protocol.int.define-special: protocol#int.define-special
_`.replay`: To work with the allocation replayer (see
-design.mps.telemetry.replayer), the buffer class has to emit an event
+design.mps.telemetry.replayer_), the buffer class has to emit an event
for each call to an external interface, containing all the parameters
passed by the user. If a new event type is required to carry this
information, the replayer (impl.c.eventrep) must then be extended to
recreate the call.
+.. _design.mps.telemetry.replayer: telemetry#replayer
+
_`.replay.pool-buffer`: The replayer must also be updated if the
association of buffer class to pool or the buffer class hierarchy is
changed.
@@ -288,13 +294,11 @@ pool using the ``PoolClass`` ``BufferEmpty()`` method).
_`.count.generic`: These fields are maintained by the generic buffer
code in ``BufferAttach()`` and ``BufferDetach()``.
-_`.count.other`: Similar count fields are maintained in the pool and
-the arena. They are maintained on an internal (buffers used internally
-by the MPS) and external (buffers used for mutator allocation points)
-basis. The fields are also updated by the buffer code. The fields are:
+_`.count.other`: Similar count fields are maintained in the arena.
+They are maintained on an internal (buffers used internally by the
+MPS) and external (buffers used for mutator allocation points) basis.
+The fields are also updated by the buffer code. The fields are:
-- in the pool: ``fillMutatorSize``, ``fillInternalSize``,
- ``emptyMutatorSize``, and ``emptyInternalSize`` (4 fields);
- in the arena, ``fillMutatorSize``, ``fillInternalSize``,
``emptyMutatorSize``, ``emptyInternalSize``, and
``allocMutatorSize`` (5 fields).
@@ -405,8 +409,6 @@ Memory Barriers will need to be placed at the points indicated.
* DESIGN
*
- * design.mps.buffer.
- *
* An allocation buffer is an interface to a pool which provides
* very fast allocation, and defers the need for synchronization in
* a multi-threaded environment.
@@ -613,7 +615,9 @@ _`.method.arena`: Returns the arena which owns a buffer.
_`.method.arena.thread-safe`: ``BufferArena()`` must be thread safe
(see impl.c.mpsi.thread-safety). This is achieved simple because the
underlying operation is a read of shared-non-mutable data (see
-design.mps.thread-safety).
+design.mps.thread-safety_).
+
+.. _design.mps.thread-safety: thread-safety
``Pool BufferPool(Buffer buffer)``
@@ -721,7 +725,9 @@ Document History
``BufferSpace()``, ``BufferSet()`` and ``BufferReset()`` are now
``BufferArena()``, ``BufferAttach()`` and ``BufferDetach()``
respectively; ``BufferExpose()`` and ``BufferCover()`` have been
- moved to the Shield interface; see design.mps.shield).
+ moved to the Shield interface; see design.mps.shield_).
+
+ .. _design.mps.shield: shield
.. _RB: http://www.ravenbrook.com/consultants/rb/
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
diff --git a/mps/design/cbs.txt b/mps/design/cbs.txt
index 496cc5ea246..34c2eedd4cd 100644
--- a/mps/design/cbs.txt
+++ b/mps/design/cbs.txt
@@ -76,14 +76,14 @@ class, a subclass of ``LandClass`` suitable for passing to
``LandClass CBSFastLandClassGet(void)``
-_`.function.class`: Returns a subclass of ``CBSLandClass`` that
+_`.function.class.fast`: Returns a subclass of ``CBSLandClass`` that
maintains, for each subtree, the size of the largest block in that
subtree. This enables the ``LandFindFirst()``, ``LandFindLast()``, and
``LandFindLargest()`` generic functions.
``LandClass CBSZonedLandClassGet(void)``
-_`.function.class`: Returns a subclass of ``CBSFastLandClass`` that
+_`.function.class.zoned`: Returns a subclass of ``CBSFastLandClass`` that
maintains, for each subtree, the union of the zone sets of all ranges
in that subtree. This enables the ``LandFindInZones()`` generic
function.
@@ -197,7 +197,9 @@ Testing
_`.test`: The following testing will be performed on this module:
_`.test.land`: A generic test for land implementations. See
-design.mps.land.test.
+design.mps.land.test_.
+
+.. _design.mps.land.test: land#test
_`.test.pool`: The arena and two pools (MVT_ and MVFF_) are
implemented on top of a CBS. These are subject to testing in
@@ -243,7 +245,9 @@ Document History
----------------
- 1998-05-01 Gavin Matthews. This document was derived from the
- outline in design.mps.poolmv2(2).
+ outline in design.mps.poolmv2_.
+
+.. _design.mps.poolmv2: poolmv2
- 1998-07-22 Gavin Matthews. Updated in response to approval comments
in change.epcore.anchovy.160040. There is too much fragmentation in
diff --git a/mps/design/check.txt b/mps/design/check.txt
index 47d757d3945..138c2a7fc1d 100644
--- a/mps/design/check.txt
+++ b/mps/design/check.txt
@@ -26,9 +26,10 @@ Implementation
_`.level`: There are three levels of checking:
-#. _`.level.sig`: The lowest level checks only that the
- structure has a valid ``Signature`` (see
- design.mps.sig).
+#. _`.level.sig`: The lowest level checks only that the structure has
+ a valid ``Signature`` (see design.mps.sig_).
+
+ .. _design.mps.sig: sig
#. _`.level.shallow`: Shallow checking checks all local fields
(including signature) and also checks the signatures of any parent
diff --git a/mps/design/class-interface.txt b/mps/design/class-interface.txt
index 70f83e01753..83e839cdc2f 100644
--- a/mps/design/class-interface.txt
+++ b/mps/design/class-interface.txt
@@ -20,9 +20,11 @@ the MPM and the pool class implementations.
.. note::
- This document should be merged into design.mps.pool. Pekka P.
+ This document should be merged into design.mps.pool_. Pekka P.
Pirinen, 1999-07-20.
+ .. _design.mps.pool: pool
+
Fields
------
@@ -37,7 +39,7 @@ memory is managed by the garbage collector, and ``"M"`` if memory is
managed by alloc/free. Examples are "AMC", "MV".
_`.field.attr`: The ``attr`` field must be a bitset of pool class
-attributes. See `design.mps.type.attr`_.
+attributes. See design.mps.type.attr_.
.. _design.mps.type.attr: type
@@ -152,7 +154,7 @@ belonging to a pool. This method is called via the generic function
(excepting any set that has been condemned in this trace) to be grey,
that is, ready for scanning. The pool should arrange that any
appropriate invariants are preserved, possibly by using the protection
-interface (see `design.mps.prot`_). Pool classes are not required to
+interface (see design.mps.prot_). Pool classes are not required to
provide this method, and not doing so indicates that all instances of
this class will have no fixable or traceable references in them.
@@ -220,12 +222,14 @@ Events
------
_`.replay`: To work with the allocation replayer (see
-design.mps.telemetry.replayer), the pool has to emit an event for each
+design.mps.telemetry.replayer_), the pool has to emit an event for each
call to an external interface, containing all the parameters passed by
the user. If a new event type is required to carry this information,
the replayer (impl.c.eventrep) must then be extended to recreate the
call.
+.. _design.mps.telemetry.replayer: telemetry#replayer
+
_`.replay.Init`: In particular, the ``init`` method should emit a
``PoolInit`` event with all the pool parameters.
diff --git a/mps/design/collection.txt b/mps/design/collection.txt
index 2b23a578c67..ebf0c05df9f 100644
--- a/mps/design/collection.txt
+++ b/mps/design/collection.txt
@@ -55,7 +55,9 @@ for the big picture.
Other notable components that the MPM manages to integrate into a
single framework are manually-managed memory and finalization services
-(see design.mps.finalize).
+(see design.mps.finalize_).
+
+.. _design.mps.finalize: finalize
.. note::
@@ -154,7 +156,9 @@ _`.refsets.scan`: The refset information is collected during scanning.
The scan state protocol provides a way for the pool and the format
scan methods to cooperate in this, and to pass this information to the
tracer module which checks it and updates the segment (see
-design.mps.scan).
+design.mps.scan_).
+
+.. _design.mps.scan: scan
.. note::
@@ -197,7 +201,9 @@ _`.tracer`: The tracer is an engine for implementing multiple garbage
collection processes. Each process (called a "trace") proceeds
independently of the others through five phases as described in
analysis.tracer. The following sections describe how the action of
-each phase fits into the framework. See design.mps.trace for details
+each phase fits into the framework. See design.mps.trace_ for details
+
+.. _design.mps.trace: trace
.. note::
@@ -226,9 +232,11 @@ on a given trace.
In each slice, it selects a small amount of work to do, based on the
state of the trace, and does it, using facilities provided by the
-pools. .trace.scan: A typical unit of work is to scan a single
-segment. The tracer can choose to do this for multiple traces at once,
-provided the segment is grey for more than one trace.
+pools.
+
+_`.trace.scan`: A typical unit of work is to scan a single segment.
+The tracer can choose to do this for multiple traces at once, provided
+the segment is grey for more than one trace.
_`.trace.barrier`: Barrier hits might also cause a need to scan :mps:a
segment (see `.hw-barriers.hit`_). Again, the tracer can
@@ -258,7 +266,9 @@ is much like allocation)
.. note::
- Soon, this will be handled by segment loci, see design.mps.locus.
+ Soon, this will be handled by segment loci, see design.mps.locus_.
+
+ .. _design.mps.locus: locus
_`.phase.condemn.mutator`: At this point, the mutator might reference
any objects, that is, it is grey. Allocation can be in any colour,
@@ -299,10 +309,12 @@ flip and because it doesn't cause any copying.
The flip phase
..............
-_`.phase.flip`: The roots (see design.mps.root) are scanned. This has
+_`.phase.flip`: The roots (see design.mps.root_) are scanned. This has
to be an atomic action as far as the mutator is concerned, so all
threads are suspended for the duration.
+.. _design.mps.root: root
+
_`.phase.flip.mutator`: After this, the mutator is black: if we use a
strong barrier (analysis.async-gc.strong), this means it cannot refer
to white objects. Allocation will be in black (could be grey as well,
diff --git a/mps/design/config.txt b/mps/design/config.txt
index b99191d7ab6..eff74388489 100644
--- a/mps/design/config.txt
+++ b/mps/design/config.txt
@@ -20,6 +20,9 @@ _`.intro`: This document describes how the `Memory Pool System
that it can target different architectures, operating systems, build
environments, varieties, and products.
+_`.readership`: Any MPS developer; anyone porting the MPS to a new
+platform.
+
Requirements
@@ -184,7 +187,7 @@ _`.var.rash`: ``RASH``
bugs tend to be extremely expensive to deal with.
_`.default.hot`: If no ``CONFIG_VAR`` is present, ``HOT`` is assumed in
-`config.h`_.
+config.h_.
_`.build.srcs`: The "srcs" are the set of sources that must be
compiled in order to build the target. The set of sources may vary
@@ -194,7 +197,7 @@ may be required to build different architectures.
.. note::
This is a dependency between the makefile (or whatever) and the
- module configuration in `config.h`_.
+ module configuration in config.h_.
_`.build.libs`: The "libs" are the set of libraries to which the
compiled sources must be linked in order to build the target. For
@@ -288,7 +291,7 @@ Publishing division of Harlequin.
Implementation
--------------
-_`.impl`: The two implementation files `config.h`_ and `mpstd.h`_ can be
+_`.impl`: The two implementation files config.h_ and mpstd.h_ can be
seen as preprocessor programs which "accept" build parameters and "emit"
configuration parameters (`.fig.impl`_). The build parameters are
defined either by the builder (in the case of target detection) or by
@@ -303,8 +306,8 @@ Build parameters Source file Configuration parameters
``_WIN32`` ⟶ ``mpstd.h`` ⟶ ``MPS_OS_W3``, etc.
=========================== ============== ===========================================
-_`.impl.dep`: No source code, other than the directives in `config.h`_
-and `mpstd.h`_, should depend on any build parameters. That is,
+_`.impl.dep`: No source code, other than the directives in config.h_
+and mpstd.h_, should depend on any build parameters. That is,
identifers beginning "CONFIG\_" should only appear in impl.h.config.
Code may depend on configuration parameters in certain, limited ways, as
defined below (`.conf`_).
@@ -317,7 +320,7 @@ Target platform detection
.........................
_`.pf`: The target platform is "detected" by the preprocessor directives in
-`mpstd.h`_.
+mpstd.h_.
_`.pf.form`: This file consists of sets of directives of the form::
@@ -357,11 +360,13 @@ the the target detected (`.pf.detect`_). For example::
_`.pf.word`: The declaration of ``MPS_T_WORD`` defines the unsigned
integral type which corresponds, on the detected target, to the
machine word. It is used to defined the MPS Word type
-(design.mps.type.word). For example::
+(design.mps.type.word_). For example::
#define MPS_T_WORD unsigned long
-We avoid using ``typedef`` here because `mpstd.h`_ could potentially
+.. _design.mps.type.word: type#word
+
+We avoid using ``typedef`` here because mpstd.h_ could potentially
be included in assembly language source code.
_`.pf.word-width`: The declaration of ``MPS_WORD_WIDTH`` defines the
diff --git a/mps/design/critical-path.txt b/mps/design/critical-path.txt
index f5714cee04e..6576ca3760e 100644
--- a/mps/design/critical-path.txt
+++ b/mps/design/critical-path.txt
@@ -28,7 +28,7 @@ design, with reference to more detailed documents.
What makes the critical path critical
-------------------------------------
-In order to determine which object can be recycled, the garbage
+In order to determine which objects can be recycled, the garbage
collector has to frequently examine a very large number of pointers in
the program's objects. It does this by scanning_ memory, both
allocated objects and roots (such as the thread stacks).
@@ -55,7 +55,7 @@ unnecessary scanning and fixing.
Firstly, the MPS must occasionally decide which objects to try to
recycle. It does this using various facts it knows about the objects,
primarily their age and whether they've survived previous attempts at
-recycling them. It then `"condemns"`_ a large number of objects
+recycling them. It then "`condemns`_" a large number of objects
at once, and each of these objects must be "preserved" by fixing
references to them.
@@ -67,16 +67,17 @@ the object or any other data structure.
The MPS arranges that objects which will probably die at the same time
are in the same zones.
-The MPS allocates in "segments". Each segment is of the order of one
+The MPS allocates in "segments". Each segment is of the order of one
"tract" of memory (generally the same as the operating system page
-size, usually 4KiB or 8KiB) but may be larger if there are large
-objects inside. The MPS maintains a "summary" of the zones pointed to
+size, usually 4Â KiB or 8Â KiB) but may be larger if there are large
+objects inside. The MPS maintains a "summary" of the zones pointed to
by all the pointers in a segment from previous scans.
So, once the MPS has decided what to condemn, it can quickly eliminate
-all segments which definitely do not point to anything in those zones.
-This avoids a large amount of scanning. It is an implementation of a
-`remembered set`_, though it is unlike that in most other GCs.
+all segments which definitely do not point to anything in those zones.
+This avoids a large amount of scanning. It is an implementation of a
+`remembered set`_, though it is unlike that in most other garbage
+collectors.
In addition, the fix operation can quickly ignore pointers to the wrong
zones. This is called the "zone check" and is a BIBOP_ technique.
@@ -104,10 +105,10 @@ Where to find the critical path
-------------------------------
Very briefly, the critical path consists of five stages:
-#. The scanner, which iterates over pointers in objects. The MPS has
- several internal scanners, but the most important ones will be format
- scanners in client code registered through ``mps_format_create()``
- functions.
+#. The scanner, which iterates over pointers in objects. The MPS has
+ several internal scanners, but the most important ones will be
+ format scanners in client code registered through
+ ``mps_fmt_create_k()``.
.. note::
@@ -118,17 +119,18 @@ Very briefly, the critical path consists of five stages:
scanner. This is implemented in ``MPS_FIX()`` macros in
mps.h_.
-.. _mps.h: ../code/mps.h
+ .. _mps.h: ../code/mps.h
#. The second-stage fix, which filters out pointers using general
- information about segments. This is ``_mps_fix2`` in
- `trace.c <../code/trace.c>`_.
+ information about segments. This is ``_mps_fix2()`` in trace.c_.
+
+ .. _trace.c: ../code/trace.c
#. The third-stage fix, which filters out pointers using pool-specific
- information. Implemented in pool class functions called ``AMCFix()``,
- ``LOFix()``, etc. in pool*.c.
+ information. Implemented in pool class functions called
+ ``AMCFix()``, ``LOFix()``, etc. in pool*.c.
-#. Preserving the object, which might entail
+#. Preserving the object, which might entail:
- marking_ it to prevent it being recycled; and/or
@@ -139,17 +141,15 @@ Very briefly, the critical path consists of five stages:
- adding it to a queue of objects to be scanned later, if it
contains pointers.
- Found in or near the pool class fix functions.
-
The format scanner
------------------
-The critical path starts when a format scan method is called. That is a
-call from the MPS to a client function of type ``mps_fmt_scan_t``
-registered with one of the ``mps_format_create()`` functions in mps.h_.
+The critical path starts when a format scan method is called. That is
+a call from the MPS to a client function of type ``mps_fmt_scan_t``
+registered with ``mps_fmt_create_k()``.
Here is an example of part of a format scanner for scanning contiguous
-runs of pointers, from `fmtdy.c <../code/fmtdy.c>`_, the scanner for the `Open Dylan`_
+runs of pointers, from fmtdy.c_, the scanner for the `Open Dylan`_
runtime::
static mps_res_t dylan_scan_contig(mps_ss_t mps_ss,
@@ -175,6 +175,8 @@ runtime::
return MPS_RES_OK;
}
+.. _fmtdy.c: ../code/fmtdy.c
+
(To help with understanding optimisation of this code, it's written in
a pseudo-assembler style, with one line roughly corresponding to each
instruction of an idealized intermediate code.)
@@ -188,7 +190,7 @@ remembered set.
The macros ``MPS_SCAN_BEGIN()`` and ``MPS_SCAN_END()`` load key data
from the scan state into local variables, and hopefully into processor
registers. This avoids aliasing values that we know won't change when
-calls are made to ``_mps_fix2`` later, and so allows the compiler to
+calls are made to ``_mps_fix2()`` later, and so allows the compiler to
keep the scan loop small and avoid unnecessary memory references.
This scanner knows that words not ending in 0b00 aren't pointers to
@@ -213,12 +215,12 @@ away from the tight loop with the zone check.
to as "fix stage 1" or "the first stage fix" in other documents and
comments.
-If these inline checks pass, ``_mps_fix2`` is called. If the MPS has
+If these inline checks pass, ``_mps_fix2()`` is called. If the MPS has
been built as a separate object file or library, this is where the
function call out of the scan loop happens. Since version 1.110 of the
MPS, we encourage clients to compile the MPS in the same translation
unit as their format code, so that the compiler can be intelligent
-about inlining parts of ``_mps_fix2`` in the format scanner. The
+about inlining parts of ``_mps_fix2()`` in the format scanner. The
instructions for doing this are in `Building the Memory Pool System
<../manual/build.txt>`_, part of the manual.
@@ -226,14 +228,15 @@ instructions for doing this are in `Building the Memory Pool System
The second stage fix in the MPM
-------------------------------
If a pointer gets past the first-stage fix filters, it is passed to
-``_mps_fix2``, the "second stage fix". The second stage can filter out
-yet more pointers using information about segments before it has to
-consult the pool class.
+``_mps_fix2()``, the "second stage fix". The second stage can filter
+out yet more pointers using information about segments before it has
+to consult the pool class.
The first test is to determine if the address points to a *chunk* (a
-contiguous regions of address space managed by the arena). Addresses
+contiguous region of address space managed by the arena). Addresses
that do not point to any chunk (for example, ambiguous references that
-are not in fact pointers) are rejected immediately.
+are not in fact pointers) are rejected immediately. See
+``ChunkOfAddr()``.
When there are many chunks (that is, when the arena has been extended
many times), this test can consume the majority of the garbage
@@ -243,16 +246,16 @@ objects when you initialize the arena.
The second test applied is the "tract test". The MPS looks up the
tract containing the address in the tract table, which is a simple
-linear table indexed by the address shifted -- a kind of flat page
-table.
+linear table indexed by the address shifted---a kind of flat page
+table. See ``TractOfAddr()``.
If the pointer is in an allocated tract, then the table also contains
-a cache of the "white set" -- the set of garbage collection traces for
+a cache of the "white set"---the set of garbage collection traces for
which the tract is "interesting". If a tract isn't interesting, then
we know that it contains no condemned objects, and we can filter out
the pointer.
-If the tract is interesting them it's part of a segment containing
+If the tract is interesting, then it's part of a segment containing
objects that have been condemned. The MPM can't know anything about
the internal layout of the segment, so at this point we dispatch to
the third stage fix.
@@ -273,9 +276,8 @@ table entry, and that should be in the cache.
dispatch to a pool class would indirect through the pool class object.
That would be a double indirection from the tract, so instead we have
a cache of the pool's fix method in the pool object. This also allows
-a pool class to vary its fix method per pool instance, a fact that is
-exploited to optimize fixing in the AMC Pool depending on what kind of
-object format it is managing.
+a pool class to vary its fix method per pool instance if that would
+improve performance.
The third stage fix in the pool class
@@ -302,16 +304,17 @@ according to its policy, and possibly ensure that the object gets
scanned at some point in the future, if it contains more pointers.
If the object is moved to preserve it (for instance, if the pool class
-implements a copying GC), or was already moved when fixing a previous
-reference to it, the reference being fixed must be updated (this is
-the origin of the term "fix").
+implements a copying collector), or was already moved when fixing a
+previous reference to it, the reference being fixed must be updated
+(this is the origin of the term "fix").
-As a simple example, ``LOFix()`` is the pool fix method for the Leaf
-Only pool class. It implements a marking garbage collector, and does
-not have to worry about scanning preserved objects because it is used
-to store objects that don't contain pointers. (It is used in compiler
-run-time systems to store binary data such as character strings, thus
-avoiding any scanning, decoding, or remembered set overhead for them.)
+As a simple example, ``LOFix()`` is the pool fix method for the LO
+(Leaf Object) pool class. It implements a marking garbage collector,
+and does not have to worry about scanning preserved objects because it
+is used to store objects that don't contain pointers. (It is used in
+compiler run-time systems to store binary data such as character
+strings, thus avoiding any scanning, decoding, or remembered set
+overhead for them.)
``LOFix()`` filters any ambiguous pointers that aren't aligned, since
they can't point to objects it allocated. Otherwise it subtracts the
@@ -319,8 +322,9 @@ segment base address and shifts the result to get an index into a mark
bit table. If the object wasn't marked and the pointer is weak, then
it sets the pointer to zero, since the object is about to be recycled.
Otherwise, the mark bit is set, which preserves the object from
-recycling when `LOReclaim` is called later on. `LOFix` illustrates
-about the minimum and most efficient thing a pool fix method can do.
+recycling when ``LOReclaim()`` is called later on. ``LOFix()``
+illustrates about the minimum and most efficient thing a pool fix
+method can do.
Other considerations
@@ -355,11 +359,11 @@ References
.. _scanning: http://www.memorymanagement.org/glossary/s.html#scan
.. _marking: http://www.memorymanagement.org/glossary/m.html#marking
.. _copying: http://www.memorymanagement.org/glossary/c.html#copying.garbage.collection
-.. _`"condemns"`: http://www.memorymanagement.org/glossary/c.html#condemned.set
+.. _condemns: http://www.memorymanagement.org/glossary/c.html#condemned.set
.. _BIBOP: http://www.memorymanagement.org/glossary/b.html#bibop
-.. _`remembered set`: http://www.memorymanagement.org/glossary/r.html#remembered.set
-.. _`reference tag`: http://www.memorymanagement.org/glossary/t.html#tag
-.. _`Open Dylan`: http://opendylan.org/
+.. _remembered set: http://www.memorymanagement.org/glossary/r.html#remembered.set
+.. _reference tag: http://www.memorymanagement.org/glossary/t.html#tag
+.. _Open Dylan: http://opendylan.org/
Document History
diff --git a/mps/design/diag.txt b/mps/design/diag.txt
index 0c9ee32c52b..f8e86e2bdda 100644
--- a/mps/design/diag.txt
+++ b/mps/design/diag.txt
@@ -58,9 +58,11 @@ diagnostics compiled-in. Currently, that means variety.cool. See
There are two mechanism for getting diagnostic output:
-#. Automatically via the telemetry system. See design.mps.telemetry,
+#. Automatically via the telemetry system. See design.mps.telemetry_,
and the "Telemetry" chapter in the manual.
+ .. _design.mps.telemetry: telemetry
+
#. Manually via the debugger. In the debugger, set break points at the
places where you want to inspect data structures (or wait for the
debugger to be entered via an ``abort()`` call or unhandled
@@ -147,13 +149,15 @@ systems:
additional events containing diagnostic information. Additionally,
the telemetry-log-events stream might in future be available as a
channel for emitting human-readable text diagnostics. See also
- design.mps.telemetry.
-
+ design.mps.telemetry_.
+
- The MPS message system. This is present in all varieties, and
manages asynchronous communication from the MPS to the client
program). However, the MPS message system might in future also be
available as a channel for emitting diagnostics. See also
- design.mps.message.
+ design.mps.message_.
+
+ .. _design.mps.message: message
diff --git a/mps/design/exec-env.txt b/mps/design/exec-env.txt
new file mode 100644
index 00000000000..65de1dd228f
--- /dev/null
+++ b/mps/design/exec-env.txt
@@ -0,0 +1,189 @@
+.. mode: -*- rst -*-
+
+Execution environment
+=====================
+
+:Tag: design.mps.exec-env
+:Author: Richard Brooksby
+:Date: 1996-08-30
+:Status: incomplete design
+:Revision: $Id$
+:Copyright: See section `Copyright and License`_.
+:Index terms: pair: execution; environment
+
+
+Introduction
+------------
+
+_`.intro`: This document describes how the MPS is designed to work in
+different execution environments (see standard.ansic section 5.1.2).
+
+
+Discussion
+----------
+
+_`.std`: These are the relevant statements from the International
+Standard ISO/IEC 9899:1990 "Programming languages — C", with tags
+added:
+
+ 4. Compliance
+
+ […]
+
+ _`.std.com.hosted`: A "conforming hosted implementation" shall
+ accept any strictly conforming program. _`.std.com.free`: A
+ "conforming freestanding implementation" shall accept any strictly
+ conforming program in which the use of the features specified in
+ the library clause (clause 7) is confined to the contents of the
+ standard headers ````, ````, ````,
+ and ````. A conforming implementation may have
+ extensions (including additional library functions), provided they
+ do not alter the behaviour of any strictly conforming program.
+
+ […]
+
+ 5.1.2 Execution environments
+
+ _`.std.def`: Two execution environments are defined:
+ "freestanding" and "hosted". […]
+
+ _`.std.init`: All objects in static storage shall be "initialized"
+ (set to their initial values) before program startup. The manner
+ and timing of such initialization are otherwise unspecified. […]
+
+ _`.std.term`: "Program termination" returns control to the execution
+ environment. […]
+
+ 5.1.2.1 Freestanding environment
+
+ _`.std.free.lib`: Any library facilities available to a
+ freestanding environment are implementation-defined.
+
+ _`.std.free.term`: The effect of program termination in a
+ free-standing environment is implementation-defined.
+
+
+Interpretation
+--------------
+
+_`.int.free`: We interpret the "freestanding environment" as being the
+sort of environment you'd expect in an embedded system. The classic
+example is a washing machine. There are no library facilities
+available, only language facilities.
+
+_`.int.free.lib`: We assume that the headers ````,
+````, ```` and ```` are available in the
+freestanding environment, because they define only language features
+and not library calls. We assume that we may not make use of
+definitions in any other headers in freestanding parts of the system.
+
+_`.int.free.term`: We may not terminate the program in a freestanding
+environment, and therefore we may not call :c:func:`abort`. We can't
+call :c:func:`abort` anyway, because it's not defined in the headers
+listed above (`.int.free.lib`_).
+
+_`.int.free.term.own`: We can add an interface for asserting, that is,
+reporting an error and not returning, for use in debugging builds
+only. This is because the environment can implement this in a way that
+does not return to the MPS, but doesn't terminate, either. We need
+this if debugging builds are to run in a (possibly simulated or
+emulated) freestanding environment at all.
+
+
+Requirements
+------------
+
+_`.req`: It should be possible to make use of the MPS in a
+freestanding environment such as an embedded controller.
+
+_`.req.conf`: There can be configurations of the MPS that are not
+freestanding (such as using a VM arena).
+
+
+Architecture
+------------
+
+_`.arch`: Like Gaul, the MPS is divided into three parts: the *core*,
+the *platform*, and the *plinth*.
+
+_`.arch.core`: The *core* consists of the Memory Pool Manager (the
+core data structures and algorithms) and the built-in Pool Classes.
+The core must be freestanding.
+
+_`.arch.platform`: The *platform* provides the core with interfaces to
+features of the operating system and processor (locks, memory
+protection, protection mutator context, stack probing, stack and
+register scanning, thread management, and virtual memory). The
+platform is specialized to a particular environment and so can safely
+use whatever features are available in that environment.
+
+_`.arch.plinth`: The *plinth* provides the core with interfaces to
+features of the user environment (time, assertions, and logging). See
+design.mps.io_ and design.mps.lib_.
+
+.. _design.mps.io: io
+.. _design.mps.lib: lib
+
+_`.arch.distinction`: The distinction between *plinth* and *platform*
+is that end users will need to customize the features provided by the
+plinth for most programs that use the MPS (and so the interface needs
+to be simple, documented and supported), whereas implementing the
+platform interface is a specialized task that will typically be done
+once for each platform and then maintained alongside the core.
+
+
+Document History
+----------------
+
+- 1996-08-30 RB_ Created to clarify concepts needed for
+ design.mps.io_.
+
+- 2015-02-06 GDR_ Converted to reStructuredText; bring the
+ architecture description up to date by describing the platform
+ interface.
+
+.. _RB: http://www.ravenbrook.com/consultants/rb/
+.. _GDR: http://www.ravenbrook.com/consultants/gdr/
+
+
+Copyright and License
+---------------------
+
+Copyright © 1996-2015 Ravenbrook Limited. All rights reserved.
+ . This is an open source license. Contact
+Ravenbrook for commercial licensing options.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+#. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+#. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+#. Redistributions in any form must be accompanied by information on how
+ to obtain complete source code for this software and any
+ accompanying software that uses this software. The source code must
+ either be included in the distribution or be available for no more than
+ the cost of distribution plus a nominal fee, and must be freely
+ redistributable under reasonable conditions. For an executable file,
+ complete source code means the source code for all modules it contains.
+ It does not include source code for modules or files that typically
+ accompany the major components of the operating system on which the
+ executable file runs.
+
+**This software is provided by the copyright holders and contributors
+"as is" and any express or implied warranties, including, but not
+limited to, the implied warranties of merchantability, fitness for a
+particular purpose, or non-infringement, are disclaimed. In no event
+shall the copyright holders and contributors be liable for any direct,
+indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or
+services; loss of use, data, or profits; or business interruption)
+however caused and on any theory of liability, whether in contract,
+strict liability, or tort (including negligence or otherwise) arising in
+any way out of the use of this software, even if advised of the
+possibility of such damage.**
diff --git a/mps/design/failover.txt b/mps/design/failover.txt
index 5fdb5a9b76d..1787da261a9 100644
--- a/mps/design/failover.txt
+++ b/mps/design/failover.txt
@@ -25,10 +25,10 @@ _`.overview`: The fail-over allocator combines two *land* instances.
It stores address ranges in one of the lands (the *primary*) unless
insertion fails, in which case it falls back to the other (the
*secondary*). The purpose is to be able to combine two lands with
-different properties: with a CBS_ for the primary and a Freelist_ for
-the secondary, operations are fast so long as there is memory to
-allocate new nodes in the CBS, but operations can continue using the
-Freelist when memory is low.
+different properties: with a CBS_ for the primary and a
+Freelist_ for the secondary, operations are fast so long as there
+is memory to allocate new nodes in the CBS_, but operations can
+continue using the Freelist_ when memory is low.
.. _CBS: cbs
.. _Freelist: freelist
@@ -80,8 +80,8 @@ Implementation
--------------
_`.impl.assume`: The implementation assumes that the primary is fast
-but space-hungry (a CBS) and the secondary is slow but space-frugal (a
-Freelist). This assumption is used in the following places:
+but space-hungry (a CBS_) and the secondary is slow but space-frugal
+(a Freelist_). This assumption is used in the following places:
_`.impl.assume.flush`: The fail-over allocator attempts to flush the
secondary to the primary before any operation, in order to benefit
@@ -91,7 +91,7 @@ where the secondary is empty this is cheap.
_`.impl.assume.delete`: When deletion of a range on the primary fails
due to lack of memory, we assume that this can only happen when there
are splinters on both sides of the deleted range, one of which needs
-to be allocated a new node (this is the case for CBS), and that
+to be allocated a new node (this is the case for CBS_), and that
therefore the following procedure will be effective: first, delete the
enclosing range from the primary (leaving no splinters and thus
requiring no allocation), and re-insert the splinters (failing over to
diff --git a/mps/design/finalize.txt b/mps/design/finalize.txt
index 2d70468c940..e3668716df7 100644
--- a/mps/design/finalize.txt
+++ b/mps/design/finalize.txt
@@ -16,11 +16,13 @@ Overview
--------
_`.overview`: Finalization is implemented internally using the
-Guardian Pool Class (design.mps.poolmrg). Objects can be registered
-for finalization using an interface function (called
-``mps_finalize()``). Notification of finalization is given to the client
-via the messaging interface. ``PoolClassMRG`` (design.mps.poolmrg)
-implements a Message Class which implements the finalization messages.
+Guardian pool class (design.mps.poolmrg_). Objects can be registered
+for finalization using ``mps_finalize()``. Notification of
+finalization is given to the client via the messaging interface. The
+Guardian pool class implements a ``Message`` subclass which implements
+the finalization messages.
+
+.. _design.mps.poolmrg: poolmrg
Requirements
@@ -62,7 +64,9 @@ Implementation
_`.int.over`: Registering an object for finalization corresponds to
allocating a reference of rank FINAL to that object. This reference is
allocated in a guardian object in a pool of ``PoolClassMRG`` (see
-design.mps.poolmrg).
+design.mps.poolmrg_).
+
+.. _design.mps.poolmrg: poolmrg
_`.int.arena.struct`: The MRG pool used for managing final references
is kept in the Arena (Space), referred to as the "final pool".
diff --git a/mps/design/fix.txt b/mps/design/fix.txt
index 9656229e158..dce6b561c84 100644
--- a/mps/design/fix.txt
+++ b/mps/design/fix.txt
@@ -40,10 +40,12 @@ condemned space).
_`.protocol.was-marked.conservative`: It is always okay to set the
``wasMarked`` field to ``TRUE``.
-_`.protocol.was-marked.finalizable`: The MRG pool (design.mps.poolmrg)
+_`.protocol.was-marked.finalizable`: The MRG pool (design.mps.poolmrg_)
uses the value of the ``wasMarked`` field to determine whether an
object is finalizable.
+.. _design.mps.poolmrg: poolmrg
+
Implementation
---------------
diff --git a/mps/design/freelist.txt b/mps/design/freelist.txt
index b0654468de1..c89181505c1 100644
--- a/mps/design/freelist.txt
+++ b/mps/design/freelist.txt
@@ -15,8 +15,7 @@ Free list allocator
Introduction
------------
-_`.intro`: This document describes the free list allocator for the
-Memory Pool System.
+_`.intro`: This is the design of the free list allocator.
_`.readership`: Any MPS developer.
@@ -133,7 +132,9 @@ Testing
_`.test`: The following testing will be performed on this module:
_`.test.land`: A generic test for land implementations. See
-design.mps.land.test.
+design.mps.land.test_.
+
+.. _design.mps.land.test: land#design.mps.land.test
_`.test.pool`: Two pools (MVT_ and MVFF_) use free lists as a fallback
when low on memory. These are subject to testing in development, QA,
diff --git a/mps/design/guide.hex.trans.txt b/mps/design/guide.hex.trans.txt
index c4b1e9594fd..8120f6e53e5 100644
--- a/mps/design/guide.hex.trans.txt
+++ b/mps/design/guide.hex.trans.txt
@@ -22,10 +22,11 @@ hexadecimal digits.
_`.readership`: This document is intended for anyone devising
arbitrary constants which may appear in hex-dumps.
-_`.sources`: This transliteration was supplied by RHSK in
-`mail.richardk.1997-04-07.13-44`_.
-
-.. _mail.richardk.1997-04-07.13-44: https://info.ravenbrook.com/project/mps/mail/1997/04/07/13-44/0.txt
+_`.sources`: This transliteration was supplied by Richard Kistruck
+[RHSK-1997-04-07]_ based on magic number encodings for object signatures
+used by Richard Brooksby [RB-1996-02-12]_, the existence of which was
+inspired by the structure marking used in the Multics operating system
+[THVV-1995]_.
Transliteration
@@ -78,13 +79,15 @@ _`.trans.t`: T is an exception to `.numbers`_, but is such a common
letter that it deserves it.
-4. Notes
---------
+Notes
+-----
_`.change`: This transliteration differs from the old transliteration
-used for signatures (see design.mps.sig(0)), as follows: J:6->1;
+used for signatures (see design.mps.sig_), as follows: J:6->1;
L:1->7; N:9->4; R:4->6; W:8->3; X:5->8; Y:E->I.
+.. _design.mps.sig: sig
+
_`.problem.mw`: There is a known problem that M and W are both common,
map to the same digit (3), and are hard to distinguish in context.
@@ -104,6 +107,33 @@ selected (by capitalisation), e.g.::
#define SpaceSig ((Sig)0x5195BACE) /* SIGnature SPACE */
+References
+----------
+
+.. [RB-1996-02-12]
+ "Signature magic numbers" (e-mail message);
+ `Richard Brooksby`_;
+ Harlequin;
+ 1996-12-02 12:05:30Z.
+
+.. _`Richard Brooksby`: mailto:rb@ravenbrook.com
+
+.. [RHSK-1997-04-07]
+ "Alpha-to-Hex v1.0 beta";
+ Richard Kistruck;
+ Ravenbrook;
+ 1997-04-07 14:42:02+0100;
+ .
+
+.. [THVV-1995]
+ "Structure Marking";
+ Tom Van Vleck;
+ multicians.org_;
+ .
+
+.. _multicians.org: http://www.multicians.org/
+
+
Document History
----------------
2013-05-10 RB_ Converted to reStructuredText and imported to MPS design.
diff --git a/mps/design/guide.impl.c.naming.txt b/mps/design/guide.impl.c.naming.txt
new file mode 100644
index 00000000000..bffc58554fc
--- /dev/null
+++ b/mps/design/guide.impl.c.naming.txt
@@ -0,0 +1,144 @@
+.. mode: -*- rst -*-
+
+C Style -- naming
+=================
+
+:Tag: guide.impl.c.naming
+:Author: Gareth Rees
+:Date: 2014-10-07
+:Status: incomplete guide
+:Format: rst
+:Revision: $Id$
+:Copyright: See `Copyright and License`_.
+:Index terms:
+ pair: C language; naming guide
+ pair: C language naming; guide
+
+
+Introduction
+------------
+
+_`.scope`: This document describes the conventions for naming in C
+source code that's internal in the MPS. See design.mps.interface-c_
+for the corresponding conventions for the public interface.
+
+.. _design.mps.interface-c: interface-c
+
+_`.readership`: This document is intended for anyone working on or
+with the C source code.
+
+
+Capitalization
+--------------
+
+_`.capital.macro`: Statement-like macros have names consisting of
+uppercase words separated by underscores, for example
+``ARG_DEFINE_KEY``.
+
+_`.capital.constant`: Constants have names consisting of a type (named
+according to `.capital.program`_ or `.capital.other`_), concatenated
+with an identifier in uppercase with underscores, for example
+``BufferFramePOP_PENDING``.
+
+_`.capital.program`: Other names with program scope consist of
+concatenated title-case words, for example ``BufferFramePush``.
+
+_`.capital.other`: Other names (including function parameters, names
+with block scope, and names with file scope) consist of concatenated
+words, the first of which is lowercase and the remainder are
+uppercase. For example, ``poolReturn``.
+
+
+Prefixes
+--------
+
+_`.prefix.program`: Any name with program scope must start with the
+name of the module to which it belongs. For example, names belonging
+to the buffer module must start with ``buffer`` or ``Buffer`` or
+``BUFFER``. Justification: the C language lacks a namespace facility
+so the only way to avoid name clashes is for each name to be globally
+unique.
+
+_`.prefix.file`: Any name with file scope should start with the name
+of the module to which it belongs. Justification: makes it easy to
+tell which module a function belongs to; makes it easy to set
+breakpoints in the debugger.
+
+
+Suffixes
+--------
+
+_`.suffix.struct`: The type of a structure must be the same as the
+structure tag, and must consist of the type of the pointer to the
+structure concatenated with ``Struct``. For example, ``ArenaStruct``.
+
+_`.suffix.union`: The type of a union must be the same as the union
+tag, and must consist of the type of the pointer to the union
+concatenated with ``Union``. For example, ``PageUnion``.
+
+_`.suffix.class`: The type of a class (see design.mps.protocol_)
+must end with ``Class``. For example, ``ArenaClass``.
+
+.. _design.mps.protocol: protocol
+
+_`.suffix.method`: The type of a method in a class must end with
+``Method``. For example, ``PoolFixMethod``.
+
+_`.suffix.visitor`: The type of a visitor function must end with
+``Visitor``. For example, ``TreeVisitor``.
+
+_`.suffix.function`: The type of other functions must end with
+``Function``. For example, ``TreeKeyFunction``.
+
+
+Document History
+----------------
+
+- 2014-10-07 GDR_ Created based on job003693_.
+
+.. _job003693: http://www.ravenbrook.com/project/mps/issue/job003693/
+.. _GDR: http://www.ravenbrook.com/consultants/gdr
+
+
+Copyright and License
+---------------------
+
+This document is copyright © 2002-2012 [Ravenbrook
+Limited](http://www.ravenbrook.com/). All rights reserved. This is an
+open source license. Contact Ravenbrook for commercial licensing
+options.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+#. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+#. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+#. Redistributions in any form must be accompanied by information on
+ how to obtain complete source code for this software and any
+ accompanying software that uses this software. The source code must
+ either be included in the distribution or be available for no more
+ than the cost of distribution plus a nominal fee, and must be freely
+ redistributable under reasonable conditions. For an executable file,
+ complete source code means the source code for all modules it
+ contains. It does not include source code for modules or files that
+ typically accompany the major components of the operating system on
+ which the executable file runs.
+
+**This software is provided by the copyright holders and contributors
+"as is" and any express or implied warranties, including, but not
+limited to, the implied warranties of merchantability, fitness for a
+particular purpose, or non-infringement, are disclaimed. In no event
+shall the copyright holders and contributors be liable for any direct,
+indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or
+services; loss of use, data, or profits; or business interruption)
+however caused and on any theory of liability, whether in contract,
+strict liability, or tort (including negligence or otherwise) arising in
+any way out of the use of this software, even if advised of the
+possibility of such damage.**
diff --git a/mps/design/vman.txt b/mps/design/guide.review.txt
similarity index 64%
rename from mps/design/vman.txt
rename to mps/design/guide.review.txt
index 11aa1028521..b1298b26b90 100644
--- a/mps/design/vman.txt
+++ b/mps/design/guide.review.txt
@@ -1,52 +1,62 @@
.. mode: -*- rst -*-
-ANSI fake VM
-============
+Review checklist
+================
-:Tag: design.mps.vman
-:Author: David Jones
-:Date: 1996-11-07
-:Status: incomplete document
+:Tag: guide.review
+:Status: incomplete documentation
+:Author: Gareth Rees
+:Organization: Ravenbrook Limited
+:Date: 2015-08-10
:Revision: $Id$
-:Copyright: See `Copyright and License`_.
-:Index terms: pair: ANSI fake VM; design
+:Copyright: See section `Copyright and License`_.
+:Index terms: pair: review; checklist
-_`.intro`: The ANSI fake VM is an implementation of the MPS VM
-interface (see `design.mps.vm`_) using only services provided by the
-ANSI C Library (standard.ansic.7).
+Introduction
+------------
-.. _design.mps.vm: vm
+_`.scope`: This document contains a list of checks to apply when
+reviewing code or other documents in the Memory Pool System.
-_`.page.size`: The VM uses a fake page size, given by the constant
-``VMAN_PAGE_SIZE`` in ``config.h``.
+_`.readership`: This document is intended for reviewers.
+
+_`.example`: The "example" links are issues caused by a failure to
+apply the checklist item.
+
+_`.diff`: Some items in the checklist are particularly susceptible to
+being ignored if one reviews only via the version control diff. These
+items refer to this tag.
+
+
+Checklist
+---------
+
+_`.test`: If a new feature has been added to the code, is there a test
+case? Example: job003923_.
+
+.. _job003923: http://www.ravenbrook.com/project/mps/issue/job003923/
+
+_`.unwind`: If code has been updated in a function that unwinds its
+state in failure cases, have the failure cases been updated to
+correspond? Example: job003922_. See `.diff`_.
+
+.. _job003922: http://www.ravenbrook.com/project/mps/issue/job003922/
-_`.align`: The VM is aligned to the arena grain size by adding the
-grain size to the requested size, allocating a block that large using
-``malloc()``, then rounding the pointer to the block up to a multiple
-of the grain size and storing the result in ``vm->base``. The block is
-stored in ``vm->block``, which is passed to ``free()`` in
-``VMFinish()``.
Document History
----------------
-- 1996-11-07 David Jones. Incomplete document.
-- 2002-06-07 RB_ Converted from MMInfo database design document.
+2015-08-10 GDR_ Created.
-- 2013-05-23 GDR_ Converted to reStructuredText.
-
-- 2014-06-18 GDR_ Bring up to date.
-
-.. _RB: http://www.ravenbrook.com/consultants/rb/
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
Copyright and License
---------------------
-Copyright © 2013-2014 Ravenbrook Limited. All rights reserved.
+Copyright © 2015 Ravenbrook Limited. All rights reserved.
. This is an open source license. Contact
Ravenbrook for commercial licensing options.
diff --git a/mps/design/index.txt b/mps/design/index.txt
index 39594723074..7e48b625319 100644
--- a/mps/design/index.txt
+++ b/mps/design/index.txt
@@ -40,36 +40,41 @@ Designs
====================== ================================================
abq_ Fixed-length queues
-alloc-frame_ Design of the MPS allocation frame protocol
-arena_ The design of the MPS arena
+alloc-frame_ Allocation frame protocol
+an_ Generic modules
+arena_ Arena
arenavm_ Virtual memory arena
+bootstrap_ Bootstrapping
bt_ Bit tables
buffer_ Allocation buffers and allocation points
-cbs_ Coalescing Block Structure land implementation
-check_ Design of checking in MPS
-class-interface_ Design of the pool class interface
-collection_ The collection framework
-config_ The design of MPS configuration
+cbs_ Coalescing block structures
+check_ Checking
+class-interface_ Pool class interface
+collection_ Collection framework
+config_ MPS configuration
critical-path_ The critical path through the MPS
-diag_ The design of MPS diagnostic feedback
-failover_ Fail-over land implementation
+diag_ Diagnostic feedback
+exec-env_ Execution environment
+failover_ Fail-over allocator
finalize_ Finalization
-fix_ The Design of the Generic Fix Function
-freelist_ Free list land implementation
-guide.hex.trans_ Guide to transliterating the alphabet into hexadecimal
+fix_ The generic fix function
+freelist_ Free list allocator
+guide.hex.trans_ Transliterating the alphabet into hexadecimal
guide.impl.c.format_ Coding standard: conventions for the general format of C source code in the MPS
-interface-c_ The design of the Memory Pool System interface to C
-io_ The design of the MPS I/O subsystem
-keyword-arguments_ The design of the MPS mechanism for passing arguments by keyword.
+guide.impl.c.naming_ Coding standard: conventions for internal names
+guide.review_ Review checklist
+interface-c_ C interface
+io_ I/O subsystem
+keyword-arguments_ Keyword arguments
land_ Lands (collections of address ranges)
-lib_ The design of the Memory Pool System library interface
-lock_ The design of the lock module
-locus_ The design for the locus manager
-message_ MPS to client message protocol
-message-gc_ Messages sent when garbage collection begins or ends
+lib_ Library interface
+lock_ Lock module
+locus_ Locus manager
+message_ Client message protocol
+message-gc_ GC messages
nailboard_ Nailboards for ambiguously referenced segments
-object-debug_ Debugging Features for Client Objects
-pool_ The design of the pool and pool class mechanisms
+object-debug_ Debugging features for client objects
+pool_ Pool and pool class mechanisms
poolamc_ Automatic Mostly-Copying pool class
poolams_ Automatic Mark-and-Sweep pool class
poolawl_ Automatic Weak Linked pool class
@@ -79,42 +84,46 @@ poolmrg_ Manual Rank Guardian pool class
poolmv_ Manual Variable pool class
poolmvt_ Manual Variable Temporal pool class
poolmvff_ Manual Variable First-Fit pool class
-prot_ Generic design of the protection module
-protan_ ANSI implementation of protection module
+prmc_ Protection mutator context
+prot_ Memory protection
protli_ Linux implementation of protection module
-protocol_ The design for protocol inheritance in MPS
+protocol_ Protocol inheritance
protsu_ SunOS 4 implementation of protection module
-pthreadext_ Design of the Posix thread extensions for MPS
+pthreadext_ POSIX thread extensions
range_ Ranges of addresses
-reservoir_ The design of the low-memory reservoir
-ring_ The design of the ring data structure
-root_ The design of the root manager
-scan_ The design of the generic scanner
-seg_ The design of the MPS segment data structure
-shield_ Shield abstraction: separate control of collector access and mutator (client) access to memory
+reservoir_ The low-memory reservoir
+ring_ Ring data structure
+root_ Root manager
+scan_ The generic scanner
+seg_ Segment data structure
+shield_ Shield
sig_ Signatures in the MPS
-splay_ Design of splay trees
+sp_ Stack probe
+splay_ Splay trees
+ss_ Stack and register scanning
sso1al_ Stack scanner for Digital Unix / Alpha systems
strategy_ Collection strategy
-telemetry_ The design of the MPS telemetry mechanism
-tests_ The design of MPS internal tests
-thread-manager_ The design of the MPS thread manager
-thread-safety_ Thread Safety in the MPS
+telemetry_ Telemetry
+tests_ Tests
+testthr_ Multi-threaded testing
+thread-manager_ Thread manager
+thread-safety_ Thread safety in the MPS
trace_ Tracer
-type_ The design of the general MPS types
-version-library_ Design of the MPS library version mechanism
-version_ Design of MPS software versions
-vm_ The design of the virtual mapping interface
-vman_ ANSI fake VM
+type_ General MPS types
+version-library_ Library version mechanism
+version_ Software versions
+vm_ Virtual mapping
vmo1_ VM Module on DEC Unix
vmso_ VM Design for Solaris
-writef_ The design of the MPS writef function
+writef_ The WriteF function
====================== ================================================
.. _abq: abq
.. _alloc-frame: alloc-frame
+.. _an: an
.. _arena: arena
.. _arenavm: arenavm
+.. _bootstrap: bootstrap
.. _bt: bt
.. _buffer: buffer
.. _cbs: cbs
@@ -124,12 +133,15 @@ writef_ The design of the MPS writef function
.. _config: config
.. _critical-path: critical-path
.. _diag: diag
+.. _exec-env: exec-env
.. _failover: failover
.. _finalize: finalize
.. _fix: fix
.. _freelist: freelist
.. _guide.hex.trans: guide.hex.trans
.. _guide.impl.c.format: guide.impl.c.format
+.. _guide.impl.c.naming: guide.impl.c.naming
+.. _guide.review: guide.review
.. _interface-c: interface-c
.. _io: io
.. _keyword-arguments: keyword-arguments
@@ -151,8 +163,8 @@ writef_ The design of the MPS writef function
.. _poolmv: poolmv
.. _poolmvt: poolmvt
.. _poolmvff: poolmvff
+.. _prmc: prmc
.. _prot: prot
-.. _protan: protan
.. _protli: protli
.. _protocol: protocol
.. _protsu: protsu
@@ -165,11 +177,14 @@ writef_ The design of the MPS writef function
.. _seg: seg
.. _shield: shield
.. _sig: sig
+.. _sp: sp
.. _splay: splay
+.. _ss: ss
.. _sso1al: sso1al
.. _strategy: strategy
.. _telemetry: telemetry
.. _tests: tests
+.. _testthr: testthr
.. _thread-manager: thread-manager
.. _thread-safety: thread-safety
.. _trace: trace
@@ -177,7 +192,6 @@ writef_ The design of the MPS writef function
.. _version-library: version-library
.. _version: version
.. _vm: vm
-.. _vman: vman
.. _vmo1: vmo1
.. _vmso: vmso
.. _writef: writef
@@ -223,7 +237,7 @@ Document History
Copyright and License
---------------------
-Copyright © 2002-2014 Ravenbrook Limited. All rights reserved.
+Copyright © 2002-2015 Ravenbrook Limited. All rights reserved.
. This is an open source license. Contact
Ravenbrook for commercial licensing options.
diff --git a/mps/design/interface-c.txt b/mps/design/interface-c.txt
index 96b20354b45..1e5424105b7 100644
--- a/mps/design/interface-c.txt
+++ b/mps/design/interface-c.txt
@@ -188,10 +188,19 @@ See guide.impl.c.misc.prototype.parameters.
Checking
--------
-_`.check.avert`: Before any use of a function paramater ``FOOÂ *foo``
-it is checked using ``AVERT(Foo, foo)``. The macro ``AVERT()`` in
-impl.h.check performs simple thread-safe checking of ``foo``, so it
-can be called outside of ``ArenaEnter()`` and ``ArenaLeave()``.
+_`.check.testt`: Before any use of a parameter ``foo`` belonging to a
+pointer type ``Foo``, it is checked using ``TESTT(Foo, foo)``. The
+macro ``TESTT()`` in impl.h.check performs simple thread-safe checking
+of ``foo``, so it can be called outside of ``ArenaEnter()`` and
+``ArenaLeave()``.
+
+_`.check.avert`: With the arena lock held, ``foo`` is checked using
+``AVERT(Foo, foo)``. This macro has different definitions depending on
+how the MPS is compiled (see design.mps.config.def.var_). It may
+expand to ``TESTT()``, or it may call the full checking function for
+the type.
+
+.. _design.mps.config.def.var: config#def-var
_`.check.types`: We use definitions of types in both our external
interface and our internal code, and we want to make sure that they
@@ -286,25 +295,31 @@ _`.cons`: The MPS C Interface constrains the MPS in order to provide
useful memory management services to a C or C++ program.
_`.cons.addr`: The interface constrains the MPS address type, Addr
-(design.mps.type.addr), to being the same as C's generic pointer type,
+(design.mps.type.addr_), to being the same as C's generic pointer type,
``void *``, so that the MPS can manage C objects in the natural way.
+.. _design.mps.type.addr: type#addr
+
_`.pun.addr`: We pun the type of ``mps_addr_t`` (which is ``void *``)
-into ``Addr`` (an incomplete type, see design.mps.type.addr). This
+into ``Addr`` (an incomplete type, see design.mps.type.addr_). This
happens in the call to the scan state's fix function, for example.
_`.cons.size`: The interface constrains the MPS size type, ``Size``
-(design.mps.type.size), to being the same as C's size type,
+(design.mps.type.size_), to being the same as C's size type,
``size_t``, so that the MPS can manage C objects in the natural way.
+
+.. _design.mps.type.size: type#size
_`.pun.size`: We pun the type of ``size_t`` in mps.h into ``Size`` in
the MPM, as an argument to the format methods. We assume this works.
-_`.cons.word`: The MPS assumes that ``Word`` (design.mps.type.word)
-and ``Addr`` (design.mps.type.addr) are the same size, and the
+_`.cons.word`: The MPS assumes that ``Word`` (design.mps.type.word_)
+and ``Addr`` (design.mps.type.addr_) are the same size, and the
interface constrains ``Word`` to being the same size as C's generic
pointer type, ``void *``.
+.. _design.mps.type.word: type#word
+
Implementation
--------------
diff --git a/mps/design/io.txt b/mps/design/io.txt
index 655eea8caf2..27ab9d7802a 100644
--- a/mps/design/io.txt
+++ b/mps/design/io.txt
@@ -95,17 +95,19 @@ which the MPM sends and receives "messages" to and from the hosted I/O
module.
_`.arch.module`: The modules are part of the MPS but not part of the
-freestanding core system (see design.mps.exec-env). The I/O module is
+freestanding core system (see design.mps.exec-env_). The I/O module is
responsible for transmitting those messages to the external tools, and
for receiving messages from external tools and passing them to the
MPM.
+.. _design.mps.exec-env: exec-env
+
_`.arch.module.example`: For example, the "file implementation" might
just send/write telemetry messages into a file so that they can be
received/read later by an off-line measurement tool.
_`.arch.external`: The I/O Interface is part of interface to the
-freestanding core system (see design.mps.exec-env). This is so that
+freestanding core system (see design.mps.exec-env_). This is so that
the MPS can be deployed in a freestanding environment, with a special
I/O module. For example, if the MPS is used in a washing machine the
I/O module could communicate by writing output to the seven-segment
@@ -429,7 +431,7 @@ Document History
Copyright and License
---------------------
-Copyright © 2013-2014 Ravenbrook Limited. All rights reserved.
+Copyright © 2013-2015 Ravenbrook Limited. All rights reserved.
. This is an open source license. Contact
Ravenbrook for commercial licensing options.
diff --git a/mps/design/keyword-arguments.txt b/mps/design/keyword-arguments.txt
index 849829ca661..af6db232a5a 100644
--- a/mps/design/keyword-arguments.txt
+++ b/mps/design/keyword-arguments.txt
@@ -137,6 +137,9 @@ arena or pool class. For example::
This leaves the main body of code, and any future code, free to just
handle keyword arguments only.
+Varargs methods must be thread-safe as they are called without taking
+the arena lock.
+
The use of varargs is deprecated in the manual and the interface and these
methods can be deleted at some point in the future.
diff --git a/mps/design/land.txt b/mps/design/land.txt
index f51795c4712..df16fc922b9 100644
--- a/mps/design/land.txt
+++ b/mps/design/land.txt
@@ -73,20 +73,20 @@ Interface
Types
.....
-``typedef LandStruct *Land;``
+``typedef LandStruct *Land``
_`.type.land`: The type of a generic land instance.
-``typedef Bool (*LandVisitor)(Land land, Range range, void *closureP, Size closureS);``
+``typedef Bool (*LandVisitor)(Land land, Range range, void *closureP, Size closureS)``
_`.type.visitor`: Type ``LandVisitor`` is a callback function that may
be passed to ``LandIterate()``. It is called for every isolated
contiguous range in address order. The function must return a ``Bool``
indicating whether to continue with the iteration.
-``typedef Bool (*LandDeleteVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS);``
+``typedef Bool (*LandDeleteVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS)``
-_`.type.visitor`: Type ``LandDeleteVisitor`` is a callback function that may
+_`.type.deletevisitor`: Type ``LandDeleteVisitor`` is a callback function that may
be passed to ``LandIterateAndDelete()``. It is called for every isolated
contiguous range in address order. The function must return a ``Bool``
indicating whether to continue with the iteration. It may additionally
@@ -187,6 +187,16 @@ _`.function.iterate.and.delete`: As ``LandIterate()``, but the visitor
function additionally returns a Boolean indicating whether the range
should be deleted from the land.
+_`.function.iterate.and.delete.justify`: The reason for having both
+``LandIterate()`` and ``LandIterateAndDelete()`` is that it may be
+possible to use a more efficient algorithm, or to preserve more
+properties of the data structure, when it is known that the land willl
+not be modified during the iteration. For example, in the CBS
+implementation, ``LandIterate()`` uses ``TreeTraverse()`` which
+preserves the tree structure, whereas ``LandIterateAndDelete()`` uses
+``TreeTraverseAndDelete()`` which flattens the tree structure, losing
+information about recently accessed nodes.
+
``Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)``
_`.function.find.first`: Locate the first block (in address order)
@@ -311,7 +321,7 @@ Document History
Copyright and License
---------------------
-Copyright © 2014 Ravenbrook Limited. All rights reserved.
+Copyright © 2014-2015 Ravenbrook Limited. All rights reserved.
. This is an open source license. Contact
Ravenbrook for commercial licensing options.
diff --git a/mps/design/lib.txt b/mps/design/lib.txt
index fa3973f0df8..1dd7efe6964 100644
--- a/mps/design/lib.txt
+++ b/mps/design/lib.txt
@@ -29,11 +29,13 @@ _`.goal`: The goals of the MPS library interface are:
_`.goal.host`: To control the dependency of the MPS on the hosted ISO
C library so that the core MPS remains freestanding (see
-design.mps.exec-env).
+design.mps.exec-env_).
+
+.. _design.mps.exec-env: exec-env
_`.goal.free`: To allow the core MPS convenient access to ISO C
functionality that is provided on freestanding platforms (see
-design.mps.exec-env.std.com.free).
+design.mps.exec-env_).
Description
@@ -46,7 +48,7 @@ _`.overview.access`: The core MPS needs to access functionality that
could be provided by an ISO C hosted environment.
_`.overview.hosted`: The core MPS must not make direct use of any
-facilities in the hosted environment (design.mps.exec-env). However,
+facilities in the hosted environment (design.mps.exec-env_). However,
it is sensible to make use of them when the MPS is deployed in a
hosted environment.
@@ -54,16 +56,6 @@ _`.overview.hosted.indirect`: The core MPS does not make any direct
use of hosted ISO C library facilities. Instead, it indirects through
the MPS Library Interface, impl.h.mpslib.
-_`.overview.free`: The core MPS can make direct use of freestanding
-ISO C library facilities and does not need to include any of the
-header files ````, ````, and ````
-directly.
-
-_`.overview.complete`: The MPS Library Interface can be considered as
-the complete "interface to ISO" (in that it provides direct access to
-facilities that we get in a freestanding environment and equivalents
-of any functionality we require from the hosted environment).
-
_`.overview.provision.client`: In a freestanding environment the
client is expected to provide functions meeting this interface to the
MPS.
@@ -72,19 +64,6 @@ _`.overview.provision.hosted`: In a hosted environment,
impl.c.mpsliban may be used. It just maps impl.h.mpslib directly onto
the ISO C library equivalents.
-[missing diagram]
-
-
-Outside the interface
-.....................
-
-We provide impl.c.mpsliban to the client, for two reasons:
-
-#. the client can use it to connect the MPS to the ISO C library if it
- exists;
-
-#. as an example implementation of the MPS Library Interface.
-
Implementation
--------------
@@ -97,8 +76,7 @@ which parallel those parts of the non-freestanding ISO headers which
are used by the MPS.
_`.impl.include`: The header file also includes the freestanding
-headers ````, ````, and ```` (and not
-````, though perhaps it should).
+header ````.
Document History
@@ -117,7 +95,7 @@ Document History
Copyright and License
---------------------
-Copyright © 2013-2014 Ravenbrook Limited. All rights reserved.
+Copyright © 2013-2015 Ravenbrook Limited. All rights reserved.
. This is an open source license. Contact
Ravenbrook for commercial licensing options.
diff --git a/mps/design/lock.txt b/mps/design/lock.txt
index 5663bc41b4f..069474ae428 100644
--- a/mps/design/lock.txt
+++ b/mps/design/lock.txt
@@ -1,50 +1,36 @@
.. mode: -*- rst -*-
-The lock module
-===============
+Lock module
+===========
:Tag: design.mps.lock
:Author: David Moore
:Date: 1995-11-21
-:Status: incomplete design
+:Status: complete design
:Revision: $Id$
:Copyright: See `Copyright and License`_.
:Index terms: pair: locking; design
-Purpose
--------
+Introduction
+------------
-_`.purpose`: Support the locking needs of the thread-safe design. In
-particular:
+_`.intro`: This is the design of the lock module.
-- recursive locks;
-- binary locks;
-- recursive "global" lock that need not be allocated or initialized by
- the client;
-- binary "global" lock that need not be allocated or initialized by
- the client.
-
-_`.context`: The MPS has to be able to operate in a multi-threaded
-environment. The thread-safe design (design.mps.thread-safety)
-requires client-allocatable binary locks, a global binary lock and a
-global recursive lock. An interface to client-allocatable recursive
-locks is also present to support any potential use, because of
-historic requirements, and because the implementation will presumably
-be necessary anyway for the global recursive lock.
+_`.readership`: Any MPS developer; anyone porting the MPS to a new
+platform.
Background
----------
_`.need`: In an environment where multiple threads are accessing
-shared data. The threads which access data which is shared with other
-threads need to cooperate with those threads to maintain consistency.
-Locks provide a simple mechanism for doing this.
+shared data, threads need to cooperate to maintain consistency. Locks
+provide a simple mechanism for doing this.
_`.ownership`: A lock is an object which may be "owned" by a single
thread at a time. By claiming ownership of a lock before executing
-some piece of code a thread can guarantee that no other thread owns
+some piece of code, a thread can guarantee that no other thread owns
the lock during execution of that code. If some other thread holds a
claim on a lock, the thread trying to claim the lock will suspend
until the lock is released by the owning thread.
@@ -56,44 +42,55 @@ accessing thread. More generally any set of operations which are
required to be mutually exclusive may be performed so by using locks.
-Overview
---------
+Requirements
+------------
-_`.adt`: There is an abstract datatype ``Lock`` which points to a
-locking structure ``LockStruct``. This structure is opaque to any
-client, although an interface is provided to supply the size of the
-structure for any client wishing to make a new lock. The lock is not
-allocated by the module as allocation itself may require locking.
-``LockStruct`` is implementation specific.
+_`.req.thread-safety`: Support the locking needs of
+design.mps.thread-safety_.
-_`.simple-lock`: There are facilities for claiming and releasing
-locks. ``Lock`` is used for both binary and recursive locking.
+.. _design.mps.thread-safety: thread-safety
-_`.global-locks`: "Global" locks are so called because they are used
-to protect data in a global location (such as a global variable). The
-lock module provides two global locks; one recursive and one binary.
-There are facilities for claiming and releasing both of these locks.
-These global locks have the advantage that they need not be allocated
-or atomically initialized by the client, so they may be used for
-locking the initialization of the allocator itself. The binary global
-lock is intended to protect mutable data, possibly in conjunction with
-other local locking strategies. The recursive global lock is intended
-to protect static read-only data during one-off initialization. See
-design.mps.thread-safety.
+_`.req.binary`: Provide *binary* locks: that is, locks that can be
+claimed, and until released, other attempts to claim them block. (This
+is needed to implement the arena lock.)
-_`.deadlock`: This module does not provide any deadlock protection.
-Clients are responsible for avoiding deadlock by using traditional
-strategies such as ordering of locks. (See
-design.mps.thread-safety.deadlock.)
+_`.req.recursive`: Provide *recursive* locks: that is, locks that can
+be claimed again by the thread currently holding them, without
+blocking or deadlocking. (This is needed to implement the global
+recursive lock.)
-_`.single-thread`: In the single-threaded configuration, locks are not
-needed and the claim/release interfaces defined to be no-ops.
+_`.req.global`: Provide *global* locks: that is locks that need not be
+allocated or initialized by the user.
+
+_`.req.global.binary`: Provide a global binary lock. (This is required
+to protect the data structure allowing multiple arenas to coordinate
+handling of protection faults: see
+design.mps.thread-safety.arch.global.binary_.)
+
+.. _design.mps.thread-safety.arch.global.binary: thread-safety#arch.global.binary
+
+_`.req.global.recursive`: Provide a global recursive lock. (This is
+required to protect pool class initialization: see
+design.mps.thread-safety.arch.global.recursive_.)
+
+.. _design.mps.thread-safety.arch.global.recursive: thread-safety#arch.global.recursive
+
+_`.req.deadlock.not`: There is no requirement to provide protection
+against deadlock. (Clients are able to avoid deadlock using
+traditional strategies such as ordering of locks; see
+design.mps.thread-safety.deadlock_.)
+
+.. _design.mps.thread-safety.deadlock: thread-safety#deadlock
-Detailed design
----------------
+Interface
+---------
-_`.interface`: The interface comprises the following functions:
+``typedef LockStruct *Lock``
+
+An opaque type representing a lock. Clients that needs to allocate
+space for a lock should dynamically allocate space for the structure,
+calling ``LockSize()`` to determine the size.
``size_t LockSize(void)``
@@ -101,18 +98,19 @@ Return the size of a ``LockStruct`` for allocation purposes.
``void LockInit(Lock lock)``
-After initialisation the lock is not owned by any thread.
+Initialize the lock. This must be called before any use of the lock.
+After initialization, the lock is not owned by any thread.
``void LockFinish(Lock lock)``
-Before finalisation the lock must not beowned by any thread.
+Finish the lock. The lock must not be owned by any thread.
``void LockClaim(Lock lock)``
-Claims ownership of a lock that was previously not held by current
-thread.
+Wait, if necessary, until the lock is not owned by any thread. Then
+claim ownership of the lock by the current thread.
-``void LockReleaseMPM(Lock lock)``
+``void LockRelease(Lock lock)``
Releases ownership of a lock that is currently owned.
@@ -123,8 +121,8 @@ thread and claims the lock (if not already held).
``void LockReleaseRecursive(Lock lock)``
-Testores the previous state of the lock stored by corresponding
-``LockClaimRecursive()`` call.
+Restores the previous state of the lock remembered by the
+corresponding ``LockClaimRecursive()`` call.
``void LockClaimGlobal(void)``
@@ -142,47 +140,135 @@ to the current thread and claims the lock (if not already held).
``void LockReleaseGlobalRecursive(void)``
-Restores the previous state of the recursive global lock stored by
-corresponding ``LockClaimGlobalRecursive()`` call.
+Restores the previous state of the recursive global lock remembered by
+the corresponding ``LockClaimGlobalRecursive()`` call.
+
+
+Implementation
+--------------
_`.impl.recursive`: For recursive claims, the list of previous states
-can be simply implemented by keeping a count of the number of claims
-made by the current thread so far. In multi-threaded implementation
-below this is handled by the operating system. A count is still kept
-and used to check correctness.
+can be implemented by keeping a count of the number of claims made by
+the current thread so far. In the multi-threaded implementations this
+is handled by the operating system interface, but a count is still
+kept and used to check correctness.
-_`.impl.global`: The binary and recursive global locks may actually be
-implemented using the same mechanism as normal locks.
+_`.impl.recursive.limit`: The implementation imposes a limit on the
+number of recursive claims (see issue.lock-claim-limit_). On Windows,
+the critical section object contains the field ``LONG
+RecursionCount``. In typical POSIX Threads implementations,
+``pthread_mutex_t`` uses an ``int`` for the count of recursive claims.
-_`.impl.ansi`: Single-Threaded Generic Implementation:
+.. _issue.lock-claim-limit: https://info.ravenbrook.com/project/mps/import/2001-09-27/mminfo/issue/lock-claim-limit
-- single-thread;
+_`.impl.global`: The binary and recursive global locks are typically
+implemented using the same mechanism as normal locks. (But an
+operating system-specific mechanism is used, if possible, to ensure
+that the global locks are initialized just once.)
+
+_`.impl.an`: Single-threaded generic implementation ``lockan.c``:
+
+- single-threaded;
- no need for locking;
- locking structure contains count;
- provides checking in debug version;
- otherwise does nothing except keep count of claims.
-_`.impl.win32`: Win32 Implementation:
+_`.impl.w3`: Windows implementation ``lockw3.c``:
-- supports Win32's threads;
-- uses Critical Sections [ref?];
-- locking structure contains a Critical Section;
-- both recursive and non-recursive calls use same Windows function;
+- supports Windows threads;
+- uses critical section objects [cso]_;
+- locking structure contains a critical section object;
+- recursive and non-recursive calls use the same Windows function;
- also performs checking.
-_`.impl.linux`: LinuxThreads Implementation (possibly suitable for all
-PThreads implementations):
+_`.impl.ix`: POSIX implementation ``lockix.c``:
-- supports LinuxThreads threads, which are an implementation of
- PThreads (see ` `_);
+- supports [POSIXThreads]_;
- locking structure contains a mutex, initialized to check for
recursive locking;
- locking structure contains a count of the number of active claims;
-- non-recursive locking calls ``pthread_mutex_lock()`` and expects success;
+- non-recursive locking calls ``pthread_mutex_lock()`` and expects
+ success;
- recursive locking calls ``pthread_mutex_lock()`` and expects either
success or ``EDEADLK`` (indicating a recursive claim);
- also performs checking.
+_`.impl.li`: Linux implementation ``lockli.c``:
+
+- supports [POSIXThreads]_;
+- also supports [LinuxThreads]_, a partial implementation of POSIX Threads
+ that was used in Linux 2.4 and 2.5;
+- almost identical to `.impl.posix`_, except that on LinuxThreads
+ ``pthread_mutexattr_setkind_np`` is used where POSIX has
+ ``pthread_mutexattr_settype``.
+
+
+Example
+-------
+
+_`.example.init`: An example of allocating and initializing a lock::
+
+ #include "lock.h"
+
+ static Lock lock;
+
+ void init()
+ {
+ mps_addr_t p;
+ if (mps_alloc(&p, pool, LockSize()) != MPS_RES_OK)
+ exit(1);
+ lock = p;
+ LockInit(lock);
+ }
+
+_`.example.binary`: An example of using a binary lock::
+
+ void binaryUse()
+ {
+ /* lock must not be owned by this thread, or else this deadlocks. */
+ LockClaim(lock);
+ /* lock is now owned by this thread. */
+ /* cannot call binaryUse() at this point. */
+ /* only one thread at a time may be at this point. */
+ LockRelease(lock);
+ /* lock not owned by this thread. */
+ }
+
+_`.example.recursive`: An example of using a recursive lock::
+
+ void recursiveUse()
+ {
+ /* lock may or may not already be owned by this thread. */
+ LockClaimRecursive(lock);
+ /* lock is now owned by this thread. */
+ /* cannot call binaryUse() at this point. */
+ /* can call recursiveUse() at this point. */
+ /* only one thread at a time may be at this point. */
+ LockReleaseRecursive(lock);
+ /* lock is still owned by this thread if it was before. */
+ }
+
+
+References
+----------
+
+.. [cso]
+ Microsoft Developer Network;
+ "Critical Section Objects";
+
+
+.. [LinuxThreads]
+ Xavier Leroy;
+ "The LinuxThreads library";
+
+
+.. [POSIXThreads]
+ The Open Group;
+ "The Single UNIX Specification, Version 2---Threads";
+
+
+
Document History
----------------
@@ -192,6 +278,8 @@ Document History
- 2013-04-14 GDR_ Converted to reStructuredText.
+- 2014-10-21 GDR_ Brought up to date.
+
.. _RB: http://www.ravenbrook.com/consultants/rb/
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
diff --git a/mps/design/locus.txt b/mps/design/locus.txt
index ed328336f42..4777857c9d7 100644
--- a/mps/design/locus.txt
+++ b/mps/design/locus.txt
@@ -1,7 +1,7 @@
.. mode: -*- rst -*-
-MPS Configuration
-=================
+Locus manager
+=============
:Tag: design.mps.locus
:Author: Gavin Matthews
@@ -84,7 +84,7 @@ Why is it important to manage address space?
The locus manager manages the mapping from clumps to zones.
- To specify a clump, pools can pass ``LocusPrefZoneSet`` and a set
+ To specify a clump, pools can pass ``LocusPrefZONESET`` and a set
of zones to ``LocusPrefExpress()``.
#. Prevent address space fragmentation (within the arena)
@@ -141,7 +141,7 @@ Why is it important to manage address space?
Pools can specify a preference for High and Low ends of address
space, which implies a search-order. Pools could also specify
- clumping, using either ``LocusPrefGen`` or ``LocusPrefZoneSet``.
+ clumping, using ``LocusPrefZONESET``.
Discovering the layout
@@ -515,7 +515,7 @@ _`.arch.chunk`: Arenas may allocate more address space in additional
chunks, which may be disjoint from the existing chunks. Inter-chunk
space will be represented by dummy regions. There are also sentinel
regions at both ends of the address space. See
-`design.mps.arena.chunk`_.
+design.mps.arena.chunk_.
.. _design.mps.arena.chunk: arena#chunk
diff --git a/mps/design/message-gc.txt b/mps/design/message-gc.txt
index 004e80d4bc3..f69a3d2c3f0 100644
--- a/mps/design/message-gc.txt
+++ b/mps/design/message-gc.txt
@@ -75,11 +75,14 @@ be extra content that is only meaningful to MPS staff, to help us
diagnose client problems.
While there is some overlap with the Diagnostic Feedback system
-(design.mps.diag) and the Telemetry system (design.mps.telemetry), the
+(design.mps.diag_) and the Telemetry system (design.mps.telemetry_), the
main contrasts are that these GC messages are present in release
builds, are stable from release to release, and are designed to be
parsed by the client program.
+.. _design.mps.telemetry: telemetry
+.. _design.mps.diag: diag
+
Names and parts
---------------
diff --git a/mps/design/message.txt b/mps/design/message.txt
index c81cb75e4f5..807f9cc6cdd 100644
--- a/mps/design/message.txt
+++ b/mps/design/message.txt
@@ -35,7 +35,7 @@ message should be critical.
_`.contents`: This document describes the design of the external and
internal interfaces and concludes with a sketch of an example design
of an internal client. The example is that of implementing
-finalization using PoolMRG.
+finalization using ``PoolMRG``.
_`.readership`: Any MPS developer.
@@ -44,10 +44,12 @@ Requirements
------------
_`.req`: The client message protocol will be used for implementing
-finalization (see design.mps.finalize and req.dylan.fun.final). It
+finalization (see design.mps.finalize_ and req.dylan.fun.final). It
will also be used for implementing the notification of various
conditions (possibly req.dylan.prot.consult is relevant here).
+.. _design.mps.finalize: finalize
+
External interface
------------------
@@ -139,7 +141,9 @@ abstractly: ``FinalizationMessage(Ref)``.
_`.type.finalization.semantics`: A finalization message indicates that
an object has been discovered to be finalizable (see
-design.mps.poolmrg.def.final.object for a definition of finalizable).
+design.mps.poolmrg.def.final.object_ for a definition of finalizable).
+
+.. _design.mps.poolmrg.def.final.object: poolmrg#def.final.object
_`.type.finalization.ref`: There is an accessor to get the reference
of the finalization message (i.e. a reference to the object which is
@@ -184,11 +188,13 @@ _`.message.instance`: Messages are instances of Message Classes.
_`.message.concrete`: Concretely a message is represented by a
``MessageStruct``. A ``MessageStruct`` has the usual signature field
-(see design.mps.sig). A ``MessageStruct`` has a type field which
+(see design.mps.sig_). A ``MessageStruct`` has a type field which
defines its type, a ring node, which is used to attach the message to
the queue of pending messages, a class field, which identifies a
``MessageClass`` object.
+.. _design.mps.sig: sig
+
_`.message.intent`: The intention is that a ``MessageStruct`` will be
embedded in some richer object which contains information relevant to
that specific type of message.
@@ -347,16 +353,21 @@ Finalization
.. note::
- Possibly out of date, see design.mps.finalize and
- design.mps.poolmrg instead. David Jones, 1997-08-28.
+ Possibly out of date, see design.mps.finalize_ and
+ design.mps.poolmrg_ instead. David Jones, 1997-08-28.
+
+ .. _design.mps.poolmrg: poolmrg
+ .. _design.mps.finalize: finalize
This subsection is a sketch of how PoolMRG will use Messages for
-finalization (see design.mps.poolmrg).
+finalization (see design.mps.poolmrg_).
-PoolMRG has guardians (see design.mps.poolmrg.guardian). Guardians are
-used to manage final references and detect when an object is
+PoolMRG has guardians (see design.mps.poolmrg.guardian_). Guardians
+are used to manage final references and detect when an object is
finalizable.
+.. _design.mps.poolmrg.guardian: poolmrg#guardian
+
The link part of a guardian will include a ``MessageStruct``.
The ``MessageStruct`` is allocated when the final reference is created
diff --git a/mps/design/nailboard.txt b/mps/design/nailboard.txt
index dd3608d8990..2f88b5b57b7 100644
--- a/mps/design/nailboard.txt
+++ b/mps/design/nailboard.txt
@@ -15,8 +15,7 @@ Nailboards for ambiguously referenced segments
Introduction
------------
-_`.intro`: This document describes the nailboard design for the Memory
-Pool System.
+_`.intro`: This is the design of the nailboard module.
_`.readership`: Any MPS developer.
@@ -28,7 +27,9 @@ will map to the same nail.
_`.purpose`: Nailboards are used by the AMC pool class to record
ambiguous references to grains within a segment. See
-design.mps.poolamc.nailboard.
+design.mps.poolamc.nailboard_.
+
+.. _design.mps.poolamc.nailboard: poolamc#nailboard
Requirements
@@ -180,7 +181,7 @@ Future
------
_`.future.tune`: The implementation makes heavy use of
-``BTIsResRange``, but this function is not well tuned for scanning
+``BTIsResRange()``, but this function is not well tuned for scanning
small arrays (which we expect to be the common case for nailboards).
Performance might be improved by special-casing the small levels.
diff --git a/mps/design/object-debug.txt b/mps/design/object-debug.txt
index cd85771c37a..df89b5cf21c 100644
--- a/mps/design/object-debug.txt
+++ b/mps/design/object-debug.txt
@@ -327,27 +327,26 @@ fenceposts in a pool (``AVER()`` if a problem is found)
_`.interface.fenceposting.format`: A function to wrap a format
(class) to provide fenceposting.
-``void (*mps_fmt_adjust_fencepost_t)(size_t *size_io)``
+``typedef void (*mps_fmt_adjust_fencepost_t)(size_t *size_io)``
_`.interface.fenceposting.adjust`: A format method to adjust size of a
block about to be allocted to allow for fenceposts.
-``void (*mps_fmt_put_fencepost_t)(mps_addr_t * addr_io, size_t size)``
+``typedef void (*mps_fmt_put_fencepost_t)(mps_addr_t * addr_io, size_t size)``
_`.interface.fenceposting.add`: A format method to add a fencepost
around a block about to be allocated. The ``NULL`` method adds a tail
fencepost.
-``mps_bool_t (*mps_fmt_check_fenceposts_t)(mps_addr_t)``
+``typedef mps_bool_t (*mps_fmt_check_fenceposts_t)(mps_addr_t)``
_`.interface.fenceposting.checker`: A format method to check the
fenceposts around an object. The ``NULL`` method checks tails.
-``mps_res_t mps_alloc(mps_addr_t *, mps_pool_t, size_t);``
-``mps_res_t mps_alloc_dbg(mps_addr_t *, mps_pool_t, size_t, ...);``
-``mps_res_t mps_alloc_dbg_v(mps_addr_t *, mps_pool_t, size_t, va_list);``
+``mps_res_t mps_alloc_dbg(mps_addr_t *, mps_pool_t, size_t, ...)``
+``mps_res_t mps_alloc_dbg_v(mps_addr_t *, mps_pool_t, size_t, va_list)``
-_`.interface.tags.alloc`: Three functions to replace existing
+_`.interface.tags.alloc`: Two functions to extend the existing
``mps_alloc()`` (request.???.??? proposes to remove the varargs)
``void (*mps_objects_step_t)(mps_addr_t addr, size_t size, mps_fmt_t format, mps_pool_t pool, void *tag_data, void *p)``
diff --git a/mps/design/poolamc.txt b/mps/design/poolamc.txt
index f2206f1cdc3..fca51e38da8 100644
--- a/mps/design/poolamc.txt
+++ b/mps/design/poolamc.txt
@@ -481,9 +481,11 @@ which is how segments get allocated in that generation.
_`.buffer.condemn`: We condemn buffered segments, but not the contents
of the buffers themselves, because we can't reclaim uncommitted
-buffers (see design.mps.buffer for details). If the segment has a
+buffers (see design.mps.buffer_ for details). If the segment has a
forwarding buffer on it, we detach it.
+.. _design.mps.buffer: buffer
+
.. note::
Why? Forwarding buffers are detached because they used to cause
@@ -696,15 +698,8 @@ memory block. See format documentation for details of the interface.
_`.header.client`: The code mostly deals in client pointers, only
computing the base and limit of a block when these are needed (such as
when an object is copied). In several places, the code gets a block of
-some sort, a segment or a buffer, and creates a client pointer by
-adding the header length (``pool->format->headerLength``).
-
-_`.header.fix`: There are two versions of the fix method, due to its
-criticality, with (``AMCHeaderFix()``) and without (``AMCFix()``)
-headers. The correct one is selected in ``AMCInitComm()``, and placed
-in the pool's fix field. This is the main reason why fix methods
-dispatch through the instance, rather than the class like all other
-methods.
+some sort (a segment or a buffer) and creates a client pointer by
+adding the header size (``pool->format->headerSize``).
Old and aging notes below here
diff --git a/mps/design/poolams.txt b/mps/design/poolams.txt
index 269dccd83f0..ef59e46724a 100644
--- a/mps/design/poolams.txt
+++ b/mps/design/poolams.txt
@@ -21,21 +21,25 @@ _`.intro`: This is the design of the AMS pool class.
_`.readership`: MM developers.
-_`.source`: design.mps.buffer, design.mps.trace, design.mps.scan,
-design.mps.action and design.mps.class-interface [none of these were
-actually used -- pekka 1998-04-21]. No requirements doc [we need a
+_`.source`: design.mps.buffer_, design.mps.trace_, design.mps.scan_,
+design.mps.action and design.mps.class-interface_ [none of these were
+actually used -- pekka 1998-04-21]. No requirements doc [we need a
req.mps that captures the commonalities between the products -- pekka
1998-01-27].
+.. _design.mps.class-interface: class-interface
+.. _design.mps.scan: scan
+.. _design.mps.trace: trace
+.. _design.mps.buffer: buffer
+
Overview
--------
-_`.overview`: This document describes the design of the AMS (Automatic
-Mark-and-Sweep) pool class. The AMS pool is a proof-of-concept design
-for a mark-sweep pool in the MPS. It's not meant to be efficient, but
-it could serve as a model for an implementation of a more advanced
-pool (such as EPVM).
+_`.overview`: This is the design of the AMS (Automatic Mark-and-Sweep)
+pool class. The AMS pool is a proof-of-concept design for a mark-sweep
+pool in the MPS. It's not meant to be efficient, but it could serve as
+a model for an implementation of a more advanced pool (such as EPVM).
Requirements
@@ -101,7 +105,7 @@ new segment.
_`.no-alloc`: Do not support ``PoolAlloc()``, because we can't support
one-phase allocation for a scannable pool (unless we disallow
-incremental collection). For exact details, see design.mps.buffer.
+incremental collection). For exact details, see design.mps.buffer_.
_`.no-free`: Do not support ``PoolFree()``, because automatic pools
don't need explicit free and having it encourages clients to use it
@@ -183,7 +187,7 @@ buffer (see `.iteration.buffer`_), as usual.
.. note::
- design.mps.buffer should explain why this works, but doesn't.
+ design.mps.buffer_ should explain why this works, but doesn't.
Pekka P. Pirinen, 1998-02-11.
_`.fix.to-black`: When fixing a reference to a white object, if the
@@ -235,7 +239,7 @@ the appropriate action, if any, on it.
.. note::
ScanLimit is used for reasons which are not documented in
- design.mps.buffer.
+ design.mps.buffer_.
Scanning Algorithm
@@ -425,13 +429,15 @@ what segments may be split or merged:
_`.split-merge.fail`: The split and merge methods are not proper
anti-methods for each other (see
-design.mps.seg.split-merge.fail.anti.no). Methods will not reverse the
+design.mps.seg.split-merge.fail.anti.no_). Methods will not reverse the
side-effects of their counterparts if the allocation of the colour and
allocation bit tables should fail. Client methods which over-ride
split and merge should not be written in such a way that they might
detect failure after calling the next method, unless they have reason
to know that the bit table allocations will not fail.
+.. _design.mps.seg.split-merge.fail.anti.no: seg#split-merge.fail.anti.no
+
Testing
-------
diff --git a/mps/design/poolawl.txt b/mps/design/poolawl.txt
index 253f7c04a5f..b8b74820645 100644
--- a/mps/design/poolawl.txt
+++ b/mps/design/poolawl.txt
@@ -159,7 +159,7 @@ AWL pools to be 1.
_`.awlseg`: The pool defines a segment class ``AWLSegClass``, which is
a subclass of ``GCSegClass`` (see
-design.mps.seg.over.hierarchy.gcseg). All segments allocated by the
+design.mps.seg.over.hierarchy.gcseg_). All segments allocated by the
pool are instances of this class, and are of type ``AWLSeg``, for
which the structure is::
@@ -175,10 +175,14 @@ which the structure is::
Sig sig;
}
+.. _design.mps.seg.over.hierarchy.gcseg: seg#over.hierarchy.gcseg
+
_`.awlseg.bt`: The mark, alloc, and scanned fields are bit-tables (see
-design.mps.bt). Each bit in the table corresponds to a a single
+design.mps.bt_). Each bit in the table corresponds to a a single
alignment grain in the pool.
+.. _design.mps.bt: bt
+
_`.awlseg.mark`: The mark bit table is used to record mark bits during
a trace. ``AWLCondemn()`` (see `.fun.condemn`_ below) sets all the
bits of this table to zero. Fix will read and set bits in this table.
@@ -411,7 +415,9 @@ perform another pass (see `.fun.scan.pass`_ above).
``Res AWLFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)``
_`.fun.fix`: ``ss->wasMarked`` is set to ``TRUE`` (clear compliance
-with design.mps.fix.protocol.was-marked.conservative).
+with design.mps.fix.protocol.was-marked.conservative_).
+
+.. _design.mps.fix.protocol.was-marked.conservative: fix#protocol.was-marked.conservative
If the rank (``ss->rank``) is ``RankAMBIG`` then fix returns
immediately unless the reference is aligned to the pool alignment.
diff --git a/mps/design/poollo.txt b/mps/design/poollo.txt
index f5bc78e7e31..ebb402c316b 100644
--- a/mps/design/poollo.txt
+++ b/mps/design/poollo.txt
@@ -152,10 +152,12 @@ _`.loseg.sig`: The signature for a loseg is 0x519705E9 (SIGLOSEG).
_`.loseg.lo`: The lo field points to the LO structure that owns this
segment.
-_`.loseg.bit`: Bit Tables (see design.mps.bt) are used to record
+_`.loseg.bit`: Bit Tables (see design.mps.bt_) are used to record
allocation and mark information. This is relatively straightforward,
but might be inefficient in terms of space in some circumstances.
+.. _design.mps.bt: bt
+
_`.loseg.mark`: This is a Bit Table that is used to mark objects
during a trace. Each grain in the segment is associated with 1 bit in
this table. When ``LOFix()`` (see `.fun.fix`_ below) is called the
diff --git a/mps/design/poolmrg.txt b/mps/design/poolmrg.txt
index 1460b39117c..148e016fae7 100644
--- a/mps/design/poolmrg.txt
+++ b/mps/design/poolmrg.txt
@@ -29,7 +29,10 @@ Generation-Based Garbage Collector") were used in this design. Some
analysis of this design (including various improvements and some more
in-depth justification) is in analysis.mps.poolmrg. That document
should be understood before changing this document. It is also helpful
-to look at design.mps.finalize and design.mps.message.
+to look at design.mps.finalize_ and design.mps.message_.
+
+.. _design.mps.message: message
+.. _design.mps.finalize: finalize
Goals
@@ -98,7 +101,9 @@ intended to provide the functionality of "finalization".
_`.over.internal`: The MRG pool class is internal to the MPM: it
is not intended to have a client interface. Clients are expected to
access the functionality provided by this pool (finalization) using a
-separate MPS finalization interface (design.mps.finalize).
+separate MPS finalization interface (design.mps.finalize_).
+
+.. _design.mps.finalize: finalize
_`.over.one-size`: The MRG pool class manages objects of a single
size, each object containing a single reference of rank final.
@@ -142,11 +147,13 @@ necessary for implementing finalization. It is the means by which the
MPS detects that objects are finalizable.
_`.over.message`: ``PoolClassMRG`` implements a ``MessageClass`` (see
-design.mps.message). All the messages are of one ``MessageType``. This
+design.mps.message_). All the messages are of one ``MessageType``. This
type is ``MessageTypeFinalization``. Messages are created when objects
are discovered to be finalizable and destroyed when the MPS client has
received the message.
+.. _design.mps.message: message
+
_`.over.message.justify`: Messages provide a means for the MPS to
communicate with its client. Notification of finalization is just such
a communication. Messages allow the MPS to inform the client of
@@ -174,7 +181,9 @@ Object Registration
_`.protocol.register`: There is a protocol by which objects can be
registered for finalization. This protocol is handled by the arena
module on behalf of finalization. see
-design.mps.finalize.int.finalize.
+design.mps.finalize.int.finalize_.
+
+.. _design.mps.finalize.int.finalize: finalize#int.finalize
Finalizer execution
@@ -193,7 +202,9 @@ Setup / destroy
_`.protocol.life`: An instance of PoolClassMRG is needed in order to
support finalization, it is called the "final" pool and is attached to
-the arena (see design.mps.finalize.int.arena.struct).
+the arena (see design.mps.finalize.int.arena.struct_).
+
+.. _design.mps.finalize.int.arena.struct: finalize#int.arena.struct
_`.protocol.life.birth`: The final pool is created lazily by
``ArenaFinalize()``.
diff --git a/mps/design/poolmvt.txt b/mps/design/poolmvt.txt
index 7df1fde0a6a..73f289017b7 100644
--- a/mps/design/poolmvt.txt
+++ b/mps/design/poolmvt.txt
@@ -25,10 +25,12 @@ _`.readership`: MM developers
_`.source`: req.dylan(6), req.epcore(16), req.product(2)
-_`.background`: design.mps.poolmv(0), design.mps.poolepdl(0),
+_`.background`: design.mps.poolmv_, design.mps.poolepdl(0),
design.product.soft.drop(0), paper.wil95(1), paper.vo96(0),
paper.grun92(1), paper.beck82(0), `mail.ptw.1998-02-25.22-18`_.
+.. _design.mps.poolmv: poolmv
+
.. _mail.ptw.1998-02-25.22-18: https://info.ravenbrook.com/project/mps/mail/1998/02/25/22-18/0.txt
@@ -78,9 +80,11 @@ object (see also, glossary.reference.count ).
_`.def.segment`: A segment is a contiguous extent of memory. In this
document, segment is used to mean a contiguous extent of memory
-managed by the MPS arena (design.mps.arena(1)) and subdivided by the
+managed by the MPS arena (design.mps.arena_) and subdivided by the
pool to provide blocks (see `.def.block`_) to its clients.
+.. _design.mps.arena: arena
+
_`.def.splay-tree`: A splay tree is a self-adjusting binary tree
(paper.st85(0), paper.sleator96(0)).
@@ -476,7 +480,7 @@ and space.
_`.anal.strategy.risk`: The current MPS segment substrate can cause
internal fragmentation which an individual pool can do nothing about.
-We expect that `request.epcore.170193.sugg.loci`_ will be implemented to
+We expect that request.epcore.170193.sugg.loci_ will be implemented to
remove this risk.
.. _`request.epcore.170193.sugg.loci`: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/epcore/170193/
@@ -777,8 +781,8 @@ Fail-over to address-ordered free list
......................................
_`.impl.c.freelist`: Because the CBS uses out-of-band storage, it may
-be unable to handle insert (design.mps.cbs.function.cbs.insert.fail)
-and delete (design.mps.cbs.function.cbs.delete.fail) operations. When
+be unable to handle insert (design.mps.cbs.function.cbs.insert.fail_)
+and delete (design.mps.cbs.function.cbs.delete.fail_) operations. When
this happen MVT fails over to an address-ordered singly linked free
list. This uses in-band storage and so cannot run out of memory, but
it has much worse performance than the CBS. Therefore MVT eagerly
@@ -786,7 +790,9 @@ attempts to flush blocks from the free list back to the CBS. See
design.mps.freelist_ for the design and implementation of the free
list.
-.. _design.mps.freelist: freelist.txt
+.. _design.mps.cbs.function.cbs.delete.fail: cbs#function.cbs.delete.fail
+.. _design.mps.cbs.function.cbs.insert.fail: cbs#function.cbs.insert.fail
+.. _design.mps.freelist: freelist
Available Block Queue
@@ -947,10 +953,11 @@ _`.test.component`: Components `.impl.c.splay`_, `.impl.c.cbs`_, and
`.impl.c.abq`_ will be subjected to individual component tests to
verify their functionality.
-_`.test.regression`: All tests applied to poolmv
-(design.mps.poolmv(0)) and poolepdl (design.mps.poolepdl(0)) will be
-applied to poolmvt to ensure that mvt is at least as functional as the
-pools it is replacing.
+_`.test.regression`: All tests applied to MV (design.mps.poolmv_) and
+EPDL (design.mps.poolepdl(0)) will be applied to poolmvt to ensure
+that mvt is at least as functional as the pools it is replacing.
+
+.. _design.mps.poolmv: poolmv
_`.test.qa`: Once poolmvt is integrated into the MPS, the standard MPS
QA tests will be applied to poolmvt prior to each release.
@@ -999,7 +1006,9 @@ B. Document History
.. _mail.ptw.1998-04-13.21-40: https://info.ravenbrook.com/project/mps/mail/1998/04/13/21-40/0.txt
- 1998-05-06 PTW Revised in response to review
- review.design.mps.poolmv2.2(0).
+ review.design.mps.poolmv2.2_(0).
+
+.. _design.mps.poolmv2.2: poolmv2#2
- 2002-06-07 RB_ Converted from MMInfo database design document.
diff --git a/mps/design/prmc.txt b/mps/design/prmc.txt
new file mode 100644
index 00000000000..0822e709527
--- /dev/null
+++ b/mps/design/prmc.txt
@@ -0,0 +1,311 @@
+.. mode: -*- rst -*-
+
+Protection mutator context
+==========================
+
+:Tag: design.mps.prmc
+:Author: Gareth Rees
+:Date: 2014-10-23
+:Status: complete design
+:Revision: $Id$
+:Copyright: See `Copyright and License`_.
+:Index terms: pair: protection mutator context; design
+
+
+Introduction
+------------
+
+_`.intro`: This is the design of the protection mutator context
+module.
+
+_`.readership`: Any MPS developer; anyone porting the MPS to a new
+platform.
+
+_`.overview`: The protection mutator context module decodes the
+*context* of a mutator thread at the point when it caused a protection
+fault, so that access to a protected region of memory can be handled,
+or when it was suspended by the thread manager, so that its registers
+and control stack can be scanned.
+
+_`.def.context`: The *context* of a thread (also called its
+*continuation*) is an abstract representation of the control state of
+the thread at a point in time, including enough information to
+continue the thread from that point.
+
+_`.status`: The protection mutator context module does not currently
+present a clean interface to the rest of the MPS: source files are
+inconsistently named, and the implementation is (necessarily) mixed up
+with the implementation of the memory protection module
+(design.mps.prot_) and the thread manager
+(design.mps.thread-manager_).
+
+.. _design.mps.prot: prot
+.. _design.mps.thread-manager: thread-manager
+
+
+Requirements
+------------
+
+_`.req.fault.addr`: Must determine the address that the mutator was
+trying to access when it caused a protection fault. (Without this
+address the MPS can't handle the fault. See ``ArenaAccess()``.)
+
+_`.req.fault.access`: Should determine whether the mutator was trying
+to read or write the address when it caused a protection fault. (This
+enables a performance improvement in the case of a write fault. A read
+fault must be handled by ensuring the address pointed to has been
+fixed, which may require scanning the segment, whereas a write fault
+merely requires that the segment's summary be discarded. See
+``TraceSegAccess()``.)
+
+_`.req.fault.step`: Should be able to emulate the access that caused
+the fault. (This enables a significant performance improvement for
+weak hash tables. See request.dylan.160044_.)
+
+.. _request.dylan.160044: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160044/
+
+_`.req.suspend.scan`: Must capature enough information to ambiguously
+scan all roots in the context of a thread that has been suspended by
+the thread manager. (This is necessary for conservative garbage
+collection to work. See design.mps.thread-manager.if.scan_.)
+
+.. _design.mps.thread-manager.if.scan: thread-manager#if.scan
+
+
+Interface
+---------
+
+``typedef MutatorFaultContextStruct *MutatorFaultContext``
+
+_`.if.context`: A structure representing the context of the mutator at
+the point when a protection fault occurred, or when it was suspended
+by the thread manager. This structure should be declared in a header
+so that it can be inlined in the ``Thread`` structure if necessary.
+See design.mps.thread-manager.if.thread_.
+
+.. _design.mps.thread-manager.if.thread: thread-manager#if.thread
+
+``Bool ProtCanStepInstruction(MutatorFaultContext context)``
+
+_`.if.canstep`: Examine the context to determine whether the
+protection module can single-step the instruction which is causing the
+fault. Return ``TRUE`` if ``ProtStepInstruction()`` is capable of
+single-stepping the instruction, or ``FALSE`` if not.
+
+``Bool Res ProtStepInstruction(MutatorFaultContext context)``
+
+_`.if.step`: Single-step the instruction which is causing the fault.
+Update the mutator context according to the emulation or execution of
+the instruction, so that resuming the mutator will not cause the
+instruction which was caused the fault to be re-executed. Return
+``ResOK`` if the instruction was single-stepped successfully, or
+``ResUNIMPL`` if the instruction cannot be single-stepped.
+
+This function is only called if ``ProtCanStepInstruction(context)``
+returned ``TRUE``.
+
+``Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext context)``
+
+_`.if.context.scan`: Scan all roots found in ``context`` using the
+given scan state (typically by calling ``TraceScanAreaTagged()``), and
+return the result code from the scanner.
+
+``Addr MutatorFaultContextSP(MutatorFaultContext context)``
+
+_`.if.context.sp`: Return the pointer to the "top" of the thread's
+stack at the point given by ``context``. In the common case, where the
+stack grows downwards, this is actually the lowest stack address.
+
+
+Implementations
+---------------
+
+Generic implementation
+......................
+
+_`.impl.an`: In ``prmcan.c``.
+
+_`.impl.an.context`: There is no definition of
+``MutatorFaultContextStruct`` and so the mutator context cannot be
+decoded.
+
+_`.impl.an.fault`: Compatible only with the generic memory protection
+module (design.mps.prot.impl.an_) where there are no protection
+faults.
+
+.. _design.mps.prot.impl.an: prot#impl.an
+
+_`.impl.an.suspend`: Compatible only with the generic thread manager
+module (design.mps.thread-manager.impl.an_) where there is only one
+thread, and so no threads are suspended.
+
+.. _design.mps.thread-manager.impl.an: thread-manager#impl.an
+
+
+Unix implementation
+...................
+
+_`.impl.ix`: In ``protsgix.c``, with processor-specific parts in
+``proti3.c`` and ``proti6.c``, and other platform-specific parts in
+``prmci3fr.c``, ``prmci3li.c``, ``prmci6fr.c``, and ``prmci6li.c``.
+
+_`.impl.ix.context`: The context consists of the |siginfo_t|_ and
+|ucontext_t|_ structures. POSIX specifies some of the fields in
+``siginfo_t``, but says nothing about the contents of ``ucontext_t``.
+This is decoded on a platform-by-platform basis.
+
+.. |siginfo_t| replace:: ``siginfo_t``
+.. _siginfo_t: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html
+.. |ucontext_t| replace:: ``ucontext_t``
+.. _ucontext_t: http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html
+
+_`.impl.ix.fault.addr`: POSIX specifies that ``siginfo_t.si_addr`` is
+the address that the faulting instruction was attempting to access.
+
+_`.impl.ix.fault.mode`: This implementation does not attempt to
+determine whether the fault was a read or write.
+
+_`.impl.ix.fault.step`: This is implemented only on IA-32, and only
+for "simple MOV" instructions.
+
+_`.impl.ix.suspend`: ``PThreadextSuspend()`` records the context of
+each suspended thread, and ``ThreadRingSuspend()`` stores this in the
+``Thread`` structure.
+
+_`.impl.ix.context.scan`: The context's root registers are found in
+the ``ucontext_t.uc_mcontext`` structure.
+
+_`.impl.ix.context.sp`: The stack pointer is obtained from
+``ucontext_t.uc_mcontext.mc_esp`` (FreeBSD on IA-32),
+``uc_mcontext.gregs[REG_ESP]`` (Linux on IA-32),
+``ucontext_t.uc_mcontext.mc_rsp`` (FreeBSD on x86-64), or
+``uc_mcontext.gregs[REG_RSP]`` (Linux on x86-64).
+
+
+Windows implementation
+......................
+
+_`.impl.w3`: In ``proti3.c``, ``proti6.c``, ``prmci3w3.c``, and
+``prmci6w3.c``.
+
+_`.impl.w3.context`: The context of a thread that hit a protection
+fault is given by the |EXCEPTION_POINTERS|_ structure passed to a
+vectored exception handler, which points to |EXCEPTION_RECORD|_ and
+|CONTEXT|_ structures.
+
+.. |EXCEPTION_POINTERS| replace:: ``EXCEPTION_POINTERS``
+.. _EXCEPTION_POINTERS: http://msdn.microsoft.com/en-us/library/windows/desktop/ms679331.aspx
+.. |EXCEPTION_RECORD| replace:: ``EXCEPTION_RECORD``
+.. _EXCEPTION_RECORD: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363082.aspx
+.. |CONTEXT| replace:: ``CONTEXT``
+.. _CONTEXT: http://msdn.microsoft.com/en-gb/library/windows/desktop/ms679284.aspx
+
+_`.impl.w3.fault.addr`: ``EXCEPTION_RECORD.ExceptionAddress`` is the
+address that the faulting instruction was trying to access.
+
+_`.impl.w3.fault.mode`: ``EXCEPTION_RECORD.ExceptionInformation[0]``
+is 0 for a read fault, 1 for a write fault, and 8 for an execute
+fault (which we handle as a read fault).
+
+_`.impl.w3.fault.step`: This is implemented only on IA-32, and only
+for "simple MOV" instructions.
+
+_`.impl.w3.suspend`: The context of a suspended thread is returned by
+|GetThreadContext|_.
+
+.. |GetThreadContext| replace:: ``GetThreadContext()``
+.. _GetThreadContext: http://msdn.microsoft.com/en-gb/library/windows/desktop/ms679362.aspx
+
+_`.impl.w3.context.scan`: The context's root registers are found in
+the |CONTEXT|_ structure.
+
+_`.impl.w3.context.sp`: The stack pointer is obtained from
+``CONTEXT.Esp`` (on IA-32) or ``CONTEXT.Rsp`` (on x86-64).
+
+
+OS X implementation
+...................
+
+_`.impl.xc`: In ``protxc.c``, with processor-specific parts in
+``proti3.c`` and ``proti6.c``, and other platform-specific parts in
+``prmci3xc.c`` and ``prmci6xc.c``.
+
+_`.impl.xc.context`: The context consists of the
+``__Request__mach_exception_raise_state_identity_t`` and
+``x86_thread_state32_t`` or ``x86_thread_state64_t`` structures. There
+doesn't seem to be any documentation for these structures, but they
+are defined in the Mach headers.
+
+_`.impl.xc.fault.addr`: ``__Request__mach_exception_raise_state_identity_t.code[1]`` is the
+address that the faulting instruction was trying to access.
+
+_`.impl.xc.fault.mode`: This implementation does not attempt to
+determine whether the fault was a read or write.
+
+_`.impl.xc.fault.step`: This is implemented only on IA-32, and only
+for "simple MOV" instructions.
+
+_`.impl.xc.suspend`: The context of a suspended thread is obtained by
+calling |thread_get_state|_.
+
+.. |thread_get_state| replace:: ``thread_get_state()``
+.. _thread_get_state: http://www.gnu.org/software/hurd/gnumach-doc/Thread-Execution.html
+
+_`.impl.xc.context.scan`: The thread's registers are found in the
+``x86_thread_state32_t`` or ``x86_thread_state64_t`` structure.
+
+_`.impl.xc.context.sp`: The stack pointer is obtained from
+``x86_thread_state32_t.__esp`` (on IA-32) or
+``x86_thread_state64_t.__rsp`` (on x86-64).
+
+
+Document History
+----------------
+
+- 2014-10-23 GDR_ Initial draft based on design.mps.thread-manager_
+ and design.mps.prot_.
+
+.. _GDR: http://www.ravenbrook.com/consultants/gdr/
+
+
+Copyright and License
+---------------------
+
+Copyright © 2014 Ravenbrook Limited. All rights reserved.
+ . This is an open source license. Contact
+Ravenbrook for commercial licensing options.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+#. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+#. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+#. Redistributions in any form must be accompanied by information on how
+ to obtain complete source code for this software and any
+ accompanying software that uses this software. The source code must
+ either be included in the distribution or be available for no more than
+ the cost of distribution plus a nominal fee, and must be freely
+ redistributable under reasonable conditions. For an executable file,
+ complete source code means the source code for all modules it contains.
+ It does not include source code for modules or files that typically
+ accompany the major components of the operating system on which the
+ executable file runs.
+
+**This software is provided by the copyright holders and contributors
+"as is" and any express or implied warranties, including, but not
+limited to, the implied warranties of merchantability, fitness for a
+particular purpose, or non-infringement, are disclaimed. In no event
+shall the copyright holders and contributors be liable for any direct,
+indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or
+services; loss of use, data, or profits; or business interruption)
+however caused and on any theory of liability, whether in contract,
+strict liability, or tort (including negligence or otherwise) arising in
+any way out of the use of this software, even if advised of the
+possibility of such damage.**
diff --git a/mps/design/prot.txt b/mps/design/prot.txt
index 0d30017fede..fb06b78b328 100644
--- a/mps/design/prot.txt
+++ b/mps/design/prot.txt
@@ -1,26 +1,73 @@
.. mode: -*- rst -*-
-The protection module
-=====================
+Memory protection
+=================
:Tag: design.mps.prot
:Author: David Jones
:Date: 1997-04-02
-:Status: incomplete document
+:Status: complete design
:Revision: $Id$
:Copyright: See `Copyright and License`_.
-:Index terms: pair: protection interface; design
+:Index terms: pair: memory protection; design
Introduction
------------
-_`.intro`: This is the generic design of the Protection Module. The
-protection module provides protection services to other parts of the
-MPS. It is expected that different operating systems will have
-different implementations of this module.
+_`.intro`: This is the design of the memory protection module.
-_`.readership`: Any MPS developer.
+_`.readership`: Any MPS developer; anyone porting the MPS to a new
+platform.
+
+_`.overview`: The memory protection module ensures that the mutator
+sees a consistent view of memory during incremental collection, by
+applying protection to areas of memory, ensuring that attempts to read
+or write from those areas cause protection faults, and implementing
+the means for the MPS to handle these faults.
+
+
+Requirements
+------------
+
+_`.req.consistent`: Must ensure that the mutator sees a consistent
+view of memory during incremental collection: in particular, the
+mutator must never see objects in oldspace. (Otherwise there's no way
+for the MPS to interface with uncooperative code.)
+
+_`.req.prot.read`: Should allow collections to proceed incrementally,
+by read-protecting pages that are not consistent from the mutator's
+point of view. (This is the only way for the MPS to meet real-time
+requirements on pause times.)
+
+_`.req.prot.write`: Should allow the MPS to maintain remembered sets
+for segments that it has scanned, by write-protecting pages in these
+segments. (This improves performance by allowing the MPS to avoid
+scanning these segments again.)
+
+_`.req.fault.handle`: If the module implements protection, it must
+also provide a mechanism for handling protection faults. (Otherwise
+the MPS cannot take the correct action: that is, fixing references in
+a read-protected segment, and discarding the remembered set from a
+write-protected segment. See ``TraceSegAccess()``.)
+
+
+Design
+------
+
+_`.sol.sync`: If memory protection is not available, only way to meet
+`.req.consistent`_, is ensure that no protection is required,
+essentially by running the collector until it has no more incremental
+work to do. (This makes it impossible to meet real-time requirements
+on pause times, but may be the best that can be done.)
+
+_`.sol.fault.handle`: The protection module handles protection faults
+by decoding the context of the fault (see
+design.mps.prmc.req.fault.addr_ and design.mps.prmc.req.fault.access_)
+and calling ``ArenaAccess()``.
+
+.. _design.mps.prmc.req.fault.addr: prmc#req.fault.addr
+.. _design.mps.prmc.req.fault.access: prmc#req.fault.access
Interface
@@ -28,58 +75,73 @@ Interface
``void ProtSetup(void)``
-_`.if.setup`: ``ProtSetup()`` will be called exactly once (per
-process). It will be called as part of the initialization of the first
-space that is created. It should arrange for the setup and
-initialization of any datastructures or services that are necessary in
-order to implement the protection module. (On UNIX it expected that it
-will install a signal handler, on Windows it will do nothing)
+_`.if.setup`: Called exactly once (per process) as part of the
+initialization of the first arena that is created. It must arrange for
+the setup and initialization of any data structures or services that
+are necessary in order to implement the memory protection module.
+
+``Size ProtGranularity(void)``
+
+_`.if.granularity`: Return the granularity of protection. The ``base``
+and ``limit`` arguments to ``ProtSet()`` must be multiples of the
+protection granularity.
``void ProtSet(Addr base, Addr limit, AccessSet mode)``
-_`.if.set`: ``ProtSet()`` should set the protection of the memory
-between base and limit, including base, but not including limit (ie
-the half-open interval [base,limit)) to that specified by mode. The
-mode parameter should have the ``AccessWRITE`` bit set if write
-accesses to the page are to be forbidden, and should have the
-``AccessREAD`` bit set if read accesses to the page are to be
-forbidden. A request to forbid read accesses (that is, ``AccessREAD``
-is set) may also forbid write accesses, but read accesses will not be
-forbidden unless ``AccessREAD`` is set.
+_`.if.set`: Set the protection of the range of memory between ``base``
+(inclusive) and ``limit`` (exclusive) to *forbid* the specified modes.
+The addresses ``base`` and ``limit`` are multiples of the protection
+granularity. The ``mode`` parameter contains the ``AccessWRITE`` bit
+if write accesses to the range are to be forbidden, and contains the
+``AccessREAD`` bit if read accesses to the range are to be forbidden.
-``void ProtSync(Space space)``
+_`.if.set.read`: If the request is to forbid read accesses (that is,
+``AccessREAD`` is set) then the implemntation may also forbid write
+accesses, but read accesses must not be forbidden unless
+``AccessREAD`` is set.
-_`.if.sync`: ``ProtSync()`` is called to ensure that the actual
-protection of each segment (as determined by the OS) is in accordance
-with the segments's ``pm`` field.
+_`.if.set.noop`: ``ProtSet()`` is permitted to be a no-op if
+``ProtSync()`` is implemented.
-``typedef struct MutatorFaultContextStruct *MutatorFaultContext``
+``void ProtSync(Arena arena)``
-_`.if.context-type`: This abstract type is implemented by the
-protection module (impl.c.prot*). It represents the continuation of
-the mutator which is restored after a mutator fault has been handled.
-The functions ``ProtCanStepInstruction()`` (`.if.canstep`_ below) and
-``ProtStepInstruction()`` (`.if.step`_ below) inspect and manipulate
-the context.
+_`.if.sync`: Ensure that the actual protection (as determined by the
+operating system) of every segment in the arena matches the segment's
+protection mode (``seg->pm``).
-``Bool ProtCanStepInstruction(MutatorFaultContext context)``
+_`.if.sync.noop`: ``ProtSync()`` is permitted to be a no-op if
+``ProtSet()`` is implemented.
-_`.if.canstep`: Examines the context to determine whether the
-protection module can single-step the instruction which is causing the
-fault. Should return ``TRUE`` if and only if the instruction can be
-single-stepped (that is, ``ProtStepInstruction()`` can be called).
-``Bool Res ProtStepInstruction(MutatorFaultContext context)``
+Implementations
+---------------
-_`.if.step`: Single-steps the instruction which is causing the fault.
-This function should only be called if ``ProtCanStepInstruction()``
-applied to the context returned ``TRUE``. It should return
-``ResUNIMPL`` if the instruction cannot be single-stepped. It should
-return ``ResOK`` if the instruction is single-stepped.
+_`.impl.an`: Generic implementation in ``protan.c``.
-The mutator context will be updated by the emulation/execution of the
-instruction such that resuming the mutator will not cause the
-instruction which was causing the fault to be executed.
+_`.impl.an.set`: ``ProtSet()`` does nothing.
+
+_`.impl.an.sync`: ``ProtSync()`` has no way of changing the protection
+of a segment, so it simulates faults on all segments that are supposed
+to be protected, by calling ``TraceSegAccess()``, until it determines
+that no segments require protection any more. This forces the trace to
+proceed until it is completed, preventing incremental collection.
+
+_`.impl.an.sync.issue`: This relies on the pool actually removing the
+protection, otherwise there is an infinite loop here. This is
+therefore not compatible with implementations of the protection
+mutator context module that support single-stepping of accesses (see design.mps.prmc.req.fault.step_).
+
+.. _design.mps.prmc.req.fault.step: prmc#req.fault.step
+
+_`.impl.ix`: POSIX implementation.
+
+_`.impl.li`: Linux implementation. See design.mps.protli_.
+
+.. _design.mps.protli: protli
+
+_`.impl.w3`: Windows implementation.
+
+_`.impl.xc`: OS X implementation.
Document History
@@ -91,6 +153,11 @@ Document History
- 2013-05-23 GDR_ Converted to reStructuredText.
+- 2014-10-23 GDR_ Move protection mutator context interface to
+ design.mps.prmc_. Bring design up to date.
+
+ .. _design.mps.prmc: prmc
+
.. _RB: http://www.ravenbrook.com/consultants/rb/
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
diff --git a/mps/design/protan.txt b/mps/design/protan.txt
deleted file mode 100644
index 4ab046d7e47..00000000000
--- a/mps/design/protan.txt
+++ /dev/null
@@ -1,135 +0,0 @@
-.. mode: -*- rst -*-
-
-ANSI implementation of protection module
-========================================
-
-:Tag: design.mps.protan
-:Author: David Jones
-:Date: 1997-03-19
-:Status: incomplete document
-:Revision: $Id$
-:Copyright: See `Copyright and License`_.
-:Index terms:
- pair: ANSI; protection interface design
- pair: ANSI protection interface; design
-
-
-Introduction
-------------
-
-_`.readership`: Any MPS developer.
-
-_`.intro`: This is the design for the ANSI implementation of the
-protection module.
-
-
-Requirements
-------------
-
-_`.req.test`: This module is required for testing. Particularly on
-platforms where no real implementation of the protection module
-exists.
-
-_`.req.rapid-port`: This module is required for rapid porting. It
-should enable a developer to port a minimally useful configuration of
-the MPS to new platforms very quickly.
-
-
-Overview
---------
-
-_`.overview`: Most of the functions in the module do nothing. The
-exception is ``ProtSync()`` which traverses over all segments in the
-arena and simulates an access to each segment that has any protection
-on it. This means that this module depends on certain fields in the
-segment structure.
-
-_`.overview.noos`: No operating system specific (or even ANSI hosted
-specific) code is in this module. It can therefore be used on any
-platform, particularly where no real implementation of the module
-exists. It satisfies `.req.test`_ and `.req.rapid-port`_ in this way.
-
-
-Functions
----------
-
-_`.fun.protsetup`: ``ProtSetup()`` does nothing as there is nothing to
-do (under UNIX we might expect the protection module to install one or
-more signal handlers at this pointer, but that is not appropriate for
-the ANSI implementation). Of course, we can't have an empty function
-body, so there is a ``NOOP;`` here.
-
-_`.fun.sync`: ``ProtSync()`` is called to ensure that the actual
-protection of each segment (as determined by the OS) is in accordance
-with the segments's pm field. In the ANSI implementation we have no
-way of changing the protection of a segment, so instead we generate
-faults on all protected segments in the assumption that that will
-remove the protection on segments.
-
-_`.fun.sync.how`: Continually loops over all the segments until it
-finds that all segments have no protection.
-
-_`.fun.sync.seg`: If it finds a segment that is protected then
-``PoolAccess()`` is called on that segment's pool and with that
-segment. The call to ``PoolAccess()`` is wrapped with a
-``ShieldEnter()`` and ``ShieldLeave()`` thereby giving the pool the
-illusion that the fault was generated outside the MM. This depends on
-being able to determine the protection of a segment (using the ``pm``
-field), on being able to call ``ShieldEnter()`` and ``ShieldLeave()``,
-and on being able to call ``PoolAccess()``.
-
-
-Document History
-----------------
-
-- 1997-03-19 David Jones. Incomplete document.
-
-- 2002-06-07 RB_ Converted from MMInfo database design document.
-
-- 2013-05-23 GDR_ Converted to reStructuredText.
-
-.. _RB: http://www.ravenbrook.com/consultants/rb/
-.. _GDR: http://www.ravenbrook.com/consultants/gdr/
-
-
-Copyright and License
----------------------
-
-Copyright © 2013-2014 Ravenbrook Limited. All rights reserved.
- . This is an open source license. Contact
-Ravenbrook for commercial licensing options.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-#. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-#. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-#. Redistributions in any form must be accompanied by information on how
- to obtain complete source code for this software and any
- accompanying software that uses this software. The source code must
- either be included in the distribution or be available for no more than
- the cost of distribution plus a nominal fee, and must be freely
- redistributable under reasonable conditions. For an executable file,
- complete source code means the source code for all modules it contains.
- It does not include source code for modules or files that typically
- accompany the major components of the operating system on which the
- executable file runs.
-
-**This software is provided by the copyright holders and contributors
-"as is" and any express or implied warranties, including, but not
-limited to, the implied warranties of merchantability, fitness for a
-particular purpose, or non-infringement, are disclaimed. In no event
-shall the copyright holders and contributors be liable for any direct,
-indirect, incidental, special, exemplary, or consequential damages
-(including, but not limited to, procurement of substitute goods or
-services; loss of use, data, or profits; or business interruption)
-however caused and on any theory of liability, whether in contract,
-strict liability, or tort (including negligence or otherwise) arising in
-any way out of the use of this software, even if advised of the
-possibility of such damage.**
diff --git a/mps/design/protli.txt b/mps/design/protli.txt
index 9b0958ac191..8d4a2f7b395 100644
--- a/mps/design/protli.txt
+++ b/mps/design/protli.txt
@@ -28,7 +28,9 @@ Requirements
------------
_`.req.general`: Required to implement the general protection
-interface defined in design.mps.prot.if.
+interface defined in design.mps.prot.if_.
+
+.. _design.mps.prot.if: prot#if
Data structures
@@ -68,7 +70,7 @@ _`.fun.set`: ``ProtSet()`` uses ``mprotect()`` to adjust the
protection for pages.
_`.fun.set.convert`: The requested protection (which is expressed in
-the ``mode`` parameter, see design.mps.prot.if.set) is translated into
+the ``mode`` parameter, see design.mps.prot.if.set_) is translated into
an operating system protection. If read accesses are to be forbidden
then all accesses are forbidden, this is done by setting the
protection of the page to ``PROT_NONE``. If write accesses are to be
@@ -77,6 +79,8 @@ and read accesses are allowed, this is done by setting the protection
of the page to ``PROT_READ|PROT_EXEC``. Otherwise (all access are
okay), the protection is set to ``PROT_READ|PROT_WRITE|PROT_EXEC``.
+.. _design.mps.prot.if.set: prot#if.set
+
_`.fun.set.assume.mprotect`: We assume that the call to ``mprotect()``
always succeeds.
@@ -94,24 +98,31 @@ Threads
_`.threads`: The design must operate in a multi-threaded environment
(with LinuxThreads) and cooperate with the Linux support for locks
-(see design.mps.lock) and the thread suspension mechanism (see
-design.mps.pthreadext ).
+(see design.mps.lock_) and the thread suspension mechanism (see
+design.mps.pthreadext_ ).
+
+.. _design.mps.pthreadext: pthreadext
+.. _design.mps.lock: lock
_`.threads.suspend`: The ``SIGSEGV`` signal handler does not mask out
any signals, so a thread may be suspended while the handler is active,
as required by the design (see
-design.mps.pthreadext.req.suspend.protection). The signal handlers
+design.mps.pthreadext.req.suspend.protection_). The signal handlers
simply nest at top of stack.
+.. _design.mps.pthreadext.req.suspend.protection: pthreadext#req.suspend.protection
+
_`.threads.async`: POSIX (and hence Linux) imposes some restrictions
on signal handler functions (see
-design.mps.pthreadext.anal.signal.safety). Basically the rules say the
+design.mps.pthreadext.anal.signal.safety_). Basically the rules say the
behaviour of almost all POSIX functions inside a signal handler is
undefined, except for a handful of functions which are known to be
"async-signal safe". However, if it's known that the signal didn't
happen inside a POSIX function, then it is safe to call arbitrary
POSIX functions inside a handler.
+.. _design.mps.pthreadext.anal.signal.safety: pthreadext#anal.signal.safety
+
_`.threads.async.protection`: If the signal handler is invoked because
of an MPS access, then we know the access must have been caused by
client code, because the client is not allowed to permit access to
diff --git a/mps/design/protocol.txt b/mps/design/protocol.txt
index 2ae5605d4f1..bddebf3f2a3 100644
--- a/mps/design/protocol.txt
+++ b/mps/design/protocol.txt
@@ -519,7 +519,9 @@ macro uses a global recursive lock instead. The lock is only claimed
after an initial unlocked access of the guard variable shows that the
class is not initialized. This avoids any locking overhead for the
common case where the class is already initialized. This lock is
-provided by the lock module -- see design.mps.lock(0).
+provided by the lock module -- see design.mps.lock_.
+
+.. _design.mps.lock: lock
Document History
diff --git a/mps/design/protsu.txt b/mps/design/protsu.txt
index 1bd57e1004a..e31edf3fe73 100644
--- a/mps/design/protsu.txt
+++ b/mps/design/protsu.txt
@@ -34,7 +34,9 @@ Requirements
------------
_`.req.general`: Required to implement the general protection
-interface defined in design.mps.prot.if.*.
+interface defined in design.mps.prot.if_.
+
+.. _design.mps.prot.if: prot#if
Overview
@@ -93,7 +95,7 @@ necessary to chain the handler, so we don't.
_`.fun.set`: ``ProtSet()``
_`.fun.set.convert`: The requested protection (which is expressed in
-the mode parameter, see design.mps.prot.if.set) is translated into an
+the mode parameter, see design.mps.prot.if.set_) is translated into an
operating system protection. If read accesses are to be forbidden then
all accesses are forbidden, this is done by setting the protection of
the page to ``PROT_NONE``. If write access are to be forbidden (and
@@ -102,6 +104,8 @@ are allowed, this is done by setting the protection of the page to
``PROT_READ | PROT_EXEC``. Otherwise (all access are okay), the
protection is set to ``PROT_READ | PROT_WRITE | PROT_EXEC``.
+.. _design.mps.prot.if.set: prot#if.set
+
_`.fun.set.assume.mprotect`: We assume that the call to ``mprotect()``
always succeeds. This is because we should always call the function
with valid arguments (aligned, references to mapped pages, and with an
diff --git a/mps/design/pthreadext.txt b/mps/design/pthreadext.txt
index aa5072f0289..18b7b2d9d9f 100644
--- a/mps/design/pthreadext.txt
+++ b/mps/design/pthreadext.txt
@@ -42,7 +42,9 @@ any progress.
_`.req.suspend.why`: Needed by the thread manager so that other
threads registered with an arena can be suspended (see
-design.mps.thread-manager). Not directly provided by Pthreads.
+design.mps.thread-manager_). Not directly provided by Pthreads.
+
+.. _design.mps.thread-manager: thread-manager
_`.req.resume`: A means to resume suspended threads, so that they are
able to make progress again. _`.req.resume.why`: Needed by the thread
diff --git a/mps/design/scan.txt b/mps/design/scan.txt
index a1822a3ce6a..2b4c992d185 100644
--- a/mps/design/scan.txt
+++ b/mps/design/scan.txt
@@ -36,7 +36,7 @@ There are two reasons that it is not an equality relation:
The reason that ``ss.unfixedSummary`` is always a subset of the
previous summary is due to an "optimization" which has not been made
-in ``TraceFix``. See `design.mps.trace.fix.fixed.all`_.
+in ``TraceFix``. See design.mps.trace.fix.fixed.all_.
.. _design.mps.trace.fix.fixed.all: trace#fix.fixed.all
diff --git a/mps/design/seg.txt b/mps/design/seg.txt
index 405eb75b52b..db797f233c0 100644
--- a/mps/design/seg.txt
+++ b/mps/design/seg.txt
@@ -15,7 +15,7 @@ Segment data structure
Introduction
------------
-_`.intro`: This document describes the MPS Segment data structure.
+_`.intro`: This is the design of the segment data structure.
Overview
@@ -43,12 +43,14 @@ methods SegBase, SegLimit, and SegSize which map a segment onto the
addresses of the memory block it represents.
_`.over.hierarchy`: The Segment datastructure is designed to be
-subclassable (see design.mps.protocol). The basic segment class
+subclassable (see design.mps.protocol_). The basic segment class
(``Seg``) supports colour and protection for use by the tracer, as
well as support for a pool ring, and all generic segment functions.
Clients may use ``Seg`` directly, but will most probably want to use a
subclass with additional properties.
+.. _design.mps.protocol: protocol
+
_`.over.hierarchy.gcseg`: The segment module provides ``GCSeg`` - a
subclass of ``Seg`` which has full support for GC including buffering
and the ability to be linked onto the grey ring.
@@ -246,7 +248,9 @@ allocation, which may use the reservoir if ``withReservoirPermit`` is
_`.method.split.next`: A split method should always call the next
method, either before or after any class-specific code (see
-design.mps.protocol.overview.next-method).
+design.mps.protocol.overview.next-method_).
+
+.. _design.mps.protocol.overview.next-method: protocol#overview.next-method
``typedef Res (*SegMergeMethod)(Seg seg, Seg segHi, Addr base, Addr mid, Addr limit, Bool withReservoirPermit)``
@@ -262,7 +266,9 @@ reservoir if ``withReservoirPermit`` is ``TRUE``.
_`.method.merge.next`: A merge method should always call the next
method, either before or after any class-specific code (see
-design.mps.protocol.overview.next-method).
+design.mps.protocol.overview.next-method_).
+
+.. _design.mps.protocol.overview.next-method: protocol#overview.next-method
_`.split-merge.shield`: Split and merge methods may assume that the
segments they are manipulating are not in the shield cache.
@@ -283,9 +289,11 @@ method (for example, by allocating any objects early in the method).
_`.split-merge.fail.anti`: If it's not possible to detect failure
before calling the next method, the appropriate anti-method must be
-used (see design.mps.protocol.guide.fail.after-next). Split methods
+used (see design.mps.protocol.guide.fail.after-next_). Split methods
are anti-methods for merge methods, and vice-versa.
+.. _design.mps.protocol.guide.fail.after-next: protocol#guide.fail.after-next
+
_`.split-merge.fail.anti.constrain`: In general, care should be taken
when writing split and merge methods to ensure that they really are
anti-methods for each other. The anti-method must not fail if the
diff --git a/mps/design/sig.txt b/mps/design/sig.txt
index 4b4cfbbe838..992d0ba52d9 100644
--- a/mps/design/sig.txt
+++ b/mps/design/sig.txt
@@ -101,18 +101,24 @@ Do not do anything else with signatures. See `.rule.purpose`_.
Checking
--------
-The signature is checked in various ways. Every function that takes a
-(pointer to) a signed structure should check its argument using the
-``AVERT`` macro. This macro has different definitions depending on how
-the MPS is compiled (see design.mps.config.def.var_). It may simply check
-the signature directly, or call the full checking function for the
-structure.
+_`.check.arg`: Every function that takes a pointer to a signed
+structure should check its argument.
+
+_`.check.arg.unlocked`: A function that does not hold the arena lock
+should check the argument using ``AVER(TESTT(type, val))``, which
+checks that ``val->sig`` is the correct signature for ``type``.
+
+_`.check.arg.locked`: A function that holds the arena lock should
+check the argument using the ``AVERT`` macro. This macro has different
+definitions depending on how the MPS is compiled (see
+design.mps.config.def.var_). It may simply check the signature, or
+call the full checking function for the structure.
.. _design.mps.config.def.var: config#def-var
-The checking function for the structure should also validate the
-signature as its first step using the ``CHECKS()`` macro (see
-check.h_). For example::
+_`.check.sig`: The checking function for the structure should also
+validate the signature as its first step using the ``CHECKS()`` macro
+(see check.h_). For example::
Bool MessageCheck(Message message)
{
@@ -127,6 +133,7 @@ pointer into a function.
.. _check.h: ../code/check.h
+
Rules
-----
_`.rule.purpose`: **Do not** use signatures for any other purpose. For
diff --git a/mps/design/sp.txt b/mps/design/sp.txt
new file mode 100644
index 00000000000..47dab436b4e
--- /dev/null
+++ b/mps/design/sp.txt
@@ -0,0 +1,226 @@
+.. mode: -*- rst -*-
+
+Stack probe
+===========
+
+:Tag: design.mps.sp
+:Author: Gareth Rees
+:Date: 2014-10-23
+:Status: complete design
+:Revision: $Id$
+:Copyright: See `Copyright and License`_.
+:Index terms: pair: stack probe; design
+
+
+Introduction
+------------
+
+_`.intro`: This is the design of the stack probe module.
+
+_`.readership`: Any MPS developer; anyone porting the MPS to a new
+platform.
+
+_`.overview`: This module ensures that the stack cannot overflow while
+the MPS is holding a lock, so that a mutator can handle stack overflow
+faults and call into the MPS from the handler.
+
+
+Requirements
+------------
+
+_`.req.overflow`: The mutator should be able to call into the MPS from
+a stack overflow fault handler. (This is a convenient way to handle
+stack overflows in dynamic language implementations: if the stack
+overflow exception and associated backtrace are to be represented as
+objects, this may require allocation, and hence a call into the MPS.)
+
+_`.req.complete`: In an application where the mutator might call into
+the MPS from a stack overflow fault handler, then whenever the MPS
+takes a lock, it must complete the operation and release the lock
+without running out of stack. (This is because running out of stack
+would cause a stack overflow fault, causing the mutator would enter
+the MPS recursively, which would fail because the lock is held.)
+
+
+Design
+------
+
+_`.sol.probe`: Before taking the arena lock in ``ArenaEnterLock()``,
+the MPS *probes* the stack: that is, it checks whether there are at
+least ``StackProbeDEPTH`` words available, and provokes a stack
+overflow fault if there are not. (This ensures that the fault occurs
+outside of the arena lock where it can be handled safely.)
+
+_`.sol.depth`: The configuration parameter ``StackProbeDEPTH``
+specifies the maximum number of words of stack that the MPS might use.
+(It is simpler, faster, and more reliable, to determine this globally
+than to try to figure it out dynamically.)
+
+_`.sol.depth.constraint`: Operating systems typically use a single
+"guard page" to detect stack overflow and grow the stack. (See for
+example the documentation for Windows_.) This means that the probe
+will be ineffective if it skips over the guard page into the memory
+beyond. If ``StackProbeDEPTH`` is greater than or equal to the number
+of words per page, the implementation might need to carry out multiple
+probes. (This constraint is checked in ``MPMCheck()``.)
+
+.. _Windows: http://support.microsoft.com/kb/100775
+
+_`.sol.depth.no-recursion`: In order to implement this design, the MPS
+must have constant bounded stack depth, and therefore, no recursion.
+
+_`.sol.depth.analysis`: Here's a table showing a deep call into the
+MPS (in the master sources at changelevel 187378), starting in
+``ArenaAccess()`` at the point where the arena ring lock is taken. The
+access forces a scan of a segment in an AMC pool, which fixes a
+reference to an object in an AMC pool's oldspace, which has to be
+forwarded, and this overflows the forwarding buffer, which requires
+the arena to allocate a new buffer in an appropriate zone, by
+searching the splay tree representing free memory.
+
+The "Args" column gives the number of arguments to the function (all
+arguments to functions in the MPS are word-sized or smaller, since we
+prohibit passing structures by value), and the "Locals" column gives
+the number of words in local variables. The value "≤64" for the stack
+usage of the object format's scan method is the limit that's
+documented in the manual.
+
+==== ====== ========================
+Args Locals Function
+==== ====== ========================
+ 5 0 ``PoolAccess()``
+ 5 0 ``PoolSegAccess()``
+ 3 5 ``TraceSegAccess()``
+ 4 1 ``traceScanSeg()``
+ 4 8 ``traceScanSegRes()``
+ 4 0 ``PoolScan()``
+ 4 5 ``AMCScan()``
+ 3 ≤64 ``format->scan()``
+ 4 15 ``AMCFix()``
+ 4 5 ``BufferFill()``
+ 6 10 ``AMCBufferFill()``
+ 6 9 ``PoolGenAlloc()``
+ 7 5 ``SegAlloc()``
+ 5 5 ``ArenaAlloc()``
+ 5 5 ``arenaAllocPolicy()``
+ 5 11 ``arenaAllocFromLand()``
+ 7 1 ``LandFindInZones()``
+ 7 16 ``cbsFindInZones()``
+ 5 3 ``cbsFindFirst()``
+ 6 7 ``SplayFindFirst()``
+ 3 7 ``SplaySplay()``
+ 4 8 ``SplaySplitDown()``
+ 3 0 ``SplayZig()``
+ 109 ≤190 **Total**
+==== ====== ========================
+
+We expect that a compiler will often be able to share stack space
+between function arguments and local variables, but in the worst case
+where it cannot, this call requires no more than 299 words of stack
+space.
+
+This isn't necessarily the deepest call into the MPS (the MPS's
+modular design and class system makes it hard to do a complete
+analysis using call graph tools), but it's probably close. The value
+for ``StackProbeDEPTH`` is thus chosen to be a round number that's
+comfortably larger than this.
+
+
+Interface
+---------
+
+``void StackProbe(Size depth)``
+
+_`.if.probe`: If there are at least ``depth`` words of stack
+available, return. If not, provoke a stack overflow fault.
+
+
+Issues
+------
+
+_`.issue.an`: The generic implementation is non-functional. This means
+that it is only suitable for use with programs that do not handle
+stack overflow faults, or do not call into the MPS from the handler.
+This is because our customers have only required `.req.overflow`_ on
+Windows so far. If this becomes a requirement on other platforms, the
+following Standard C implementation might work::
+
+ void StackProbe(Size depth) {
+ volatile Word w;
+ Word *p = &w - depth;
+ w = *p;
+ }
+
+The use of ``volatile`` here is to prevent compilers from warning
+about the variable ``w`` being written but never read, or worse,
+optimizing away the whole statement under the "as if" rule.
+
+
+Implementations
+---------------
+
+_`.impl.an`: Generic implementation in ``span.c``. This implementation
+does nothing. See `.issue.an`_.
+
+_`.impl.w3i3`: Implementation for Windows on IA-32 in ``spw3i3.c``.
+This uses assembly to get the stack pointer (from the ESP register)
+and to read the location ``depth`` words below the stack pointer.
+
+_`.impl.w3i6`: Implementation for Windows on x86-64 in ``spw3i6.c``.
+This passes the argument ``depth*sizeof(Word)`` to the Windows
+function |alloca|_, for which the documentation says, "A stack
+overflow exception is generated if the space cannot be allocated."
+
+.. |alloca| replace:: ``_alloca()``
+.. _alloca: http://msdn.microsoft.com/en-us/library/wb1s57t5.aspx
+
+
+Document History
+----------------
+
+- 2014-10-23 GDR_ Initial draft.
+
+.. _GDR: http://www.ravenbrook.com/consultants/gdr/
+
+
+Copyright and License
+---------------------
+
+Copyright © 2014 Ravenbrook Limited. All rights reserved.
+ . This is an open source license. Contact
+Ravenbrook for commercial licensing options.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+#. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+#. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+#. Redistributions in any form must be accompanied by information on how
+ to obtain complete source code for this software and any
+ accompanying software that uses this software. The source code must
+ either be included in the distribution or be available for no more than
+ the cost of distribution plus a nominal fee, and must be freely
+ redistributable under reasonable conditions. For an executable file,
+ complete source code means the source code for all modules it contains.
+ It does not include source code for modules or files that typically
+ accompany the major components of the operating system on which the
+ executable file runs.
+
+**This software is provided by the copyright holders and contributors
+"as is" and any express or implied warranties, including, but not
+limited to, the implied warranties of merchantability, fitness for a
+particular purpose, or non-infringement, are disclaimed. In no event
+shall the copyright holders and contributors be liable for any direct,
+indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or
+services; loss of use, data, or profits; or business interruption)
+however caused and on any theory of liability, whether in contract,
+strict liability, or tort (including negligence or otherwise) arising in
+any way out of the use of this software, even if advised of the
+possibility of such damage.**
diff --git a/mps/design/splay-rotate-left.svg b/mps/design/splay-rotate-left.svg
index f5e50922aa8..00ae646a735 100644
--- a/mps/design/splay-rotate-left.svg
+++ b/mps/design/splay-rotate-left.svg
@@ -388,7 +388,7 @@
id="tspan4371"
x="388"
y="96.362183"
- style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">x
+ style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">y
y
+ sodipodi:role="line">x
diff --git a/mps/design/splay-rotate-right.svg b/mps/design/splay-rotate-right.svg
index 39fea1b2a20..d2a02bc48bb 100644
--- a/mps/design/splay-rotate-right.svg
+++ b/mps/design/splay-rotate-right.svg
@@ -374,7 +374,7 @@
id="tspan4371"
x="388"
y="96.362183"
- style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">x
+ style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">y
y
+ sodipodi:role="line">x
diff --git a/mps/design/splay.txt b/mps/design/splay.txt
index 05554152ff9..0e77835f734 100644
--- a/mps/design/splay.txt
+++ b/mps/design/splay.txt
@@ -57,7 +57,7 @@ _`.def.key`: A *key* is a value associated with each node; the keys
are totally ordered by a client provided comparator.
_`.def.comparator`: A *comparator* is a function that compares keys to
-determine their ordering (see also `.type.tree.compare.method`_).
+determine their ordering (see also `.type.tree.compare.function`_).
_`.def.successor`: Node *N*\ :subscript:`2` is the *successor* of node
*N*\ :subscript:`1` if *N*\ :subscript:`1` and *N*\ :subscript:`2` are
@@ -165,17 +165,17 @@ _`.type.treekey`: ``TreeKey`` is the type of a key associated with a
node in a binary tree. It is an alias for ``void *`` but expresses the
intention.
-``typedef TreeKey (*TreeKeyMethod)(Tree tree)``
+``typedef TreeKey (*TreeKeyFunction)(Tree tree)``
-_`.type.tree.key.method`: A function of type ``TreeKey`` returns the
+_`.type.tree.key.function`: A function of type ``TreeKey`` returns the
key associated with a node in a binary tree. (Since there is no space
in a ``TreeStruct`` to store a key, it is expected that the
``TreeStruct`` is embedded in another structure from which the key can
be extracted.)
-``typedef Compare (*TreeCompare)(Tree tree, TreeKey key)``
+``typedef Compare (*TreeCompareFunction)(Tree tree, TreeKey key)``
-_`.type.tree.compare.method`: A function of type ``TreeCompare`` is
+_`.type.tree.compare.function`: A function of type ``TreeCompareFunction`` is
required to compare ``key`` with the key the client associates with
that splay tree node ``tree``, and return the appropriate Compare
value (see `.usage.compare`_ for an example). The function compares a
@@ -184,10 +184,10 @@ more obvious. This is because the details of the mapping between nodes
and keys is left to the client (see `.type.tree`_), and the splaying
operations compare keys with nodes (see `.impl.splay`_).
-``typedef Res (*TreeDescribeMethod)(Tree tree, mps_lib_FILE *stream)``
+``typedef Res (*TreeDescribeFunction)(Tree tree, mps_lib_FILE *stream)``
-_`.type.tree.describe.method`: A function of type
-``TreeDescribeMethod`` is required to write (via ``WriteF()``) a
+_`.type.tree.describe.function`: A function of type
+``TreeDescribeFunction`` is required to write (via ``WriteF()``) a
client-oriented representation of the splay node. The output should be
non-empty, short, and without newline characters. This is provided for
debugging only.
@@ -219,32 +219,32 @@ the root of the splay tree. It is intended that the
`.usage.client-tree`_ for an example). No convenience functions are
provided for allocation or deallocation.
-``typedef Bool (*SplayTestNodeMethod)(SplayTree splay, Tree tree, void *closureP, Size closureS)``
+``typedef Bool (*SplayTestNodeFunction)(SplayTree splay, Tree tree, void *closureP, Size closureS)``
-_`.type.splay.test.node.method`: A function of type
-``SplayTestNodeMethod`` required to determine whether the node itself
+_`.type.splay.test.node.function`: A function of type
+``SplayTestNodeFunction`` required to determine whether the node itself
meets some client determined property (see `.prop`_ and
`.usage.test.node`_ for an example). Parameters ``closureP`` and
``closureS`` describe the environment for the function (see
`.function.splay.find.first`_ and `.function.splay.find.last`_).
-``typedef Bool (*SplayTestTreeMethod)(SplayTree splay, Tree tree, void *closureP, Size closureS)``
+``typedef Bool (*SplayTestTreeFunction)(SplayTree splay, Tree tree, void *closureP, Size closureS)``
-_`.type.splay.test.tree.method`: A function of type
-``SplayTestTreeMethod`` is required to determine whether any of the
+_`.type.splay.test.tree.function`: A function of type
+``SplayTestTreeFunction`` is required to determine whether any of the
nodes in the sub-tree rooted at the given node meet some client
determined property (see `.prop`_ and `.usage.test.tree`_ for an
example). In particular, it must be a precise (not conservative)
indication of whether there are any nodes in the sub-tree for which
-the ``testNode`` method (see `.type.splay.test.node.method`_) would
+the ``testNode`` function (see `.type.splay.test.node.function`_) would
return ``TRUE``. Parameters ``closureP`` and ``closureS`` describe the
environment for the function (see `.function.splay.find.first`_ and
`.function.splay.find.last`_).
-``typedef void (*SplayUpdateNodeMethod)(SplayTree splay, Tree tree)``
+``typedef void (*SplayUpdateNodeFunction)(SplayTree splay, Tree tree)``
-_`.type.splay.update.node.method`: A function of type
-``SplayUpdateNodeMethod`` is required to update any client data
+_`.type.splay.update.node.function`: A function of type
+``SplayUpdateNodeFunction`` is required to update any client data
structures associated with a node to maintain some client determined
property (see `.prop`_) given that the children of the node have
changed. (See `.usage.callback`_ for an example)
@@ -256,9 +256,9 @@ Functions
_`.function.no-thread`: The interface functions are not designed to be
either thread-safe or re-entrant. Clients of the interface are
responsible for synchronization, and for ensuring that client-provided
-methods invoked by the splay module (`.type.tree.compare.method`_,
-`.type.tree.key.method`_, `.type.splay.test.node.method`_,
-`.type.splay.test.tree.method`_, `.type.splay.update.node.method`_) do
+functions invoked by the splay module (`.type.tree.compare.function`_,
+`.type.tree.key.function`_, `.type.splay.test.node.function`_,
+`.type.splay.test.tree.function`_, `.type.splay.update.node.function`_) do
not call functions of the splay module.
``Bool SplayTreeCheck(SplayTree splay)``
@@ -267,16 +267,16 @@ _`.function.splay.tree.check`: This is a check function for the
``SplayTree`` type (see guide.impl.c.adt.method.check and
design.mps.check_).
-``void SplayTreeInit(SplayTree splay, TreeCompareMethod compare, TreeKeyMethod nodeKey, SplayUpdateNodeMethod updateNode)``
+``void SplayTreeInit(SplayTree splay, TreeCompareFunction compare, TreeKeyFunction nodeKey, SplayUpdateNodeFunction updateNode)``
_`.function.splay.tree.init`: This function initialises a
``SplayTree`` (see guide.impl.c.adt.method.init). The ``nodeKey``
function extracts a key from a tree node, and the ``compare`` function
defines a total ordering on keys of nodes (see `.req.order`_). The
-effect of supplying a compare method that does not implement a total
-ordering is undefined. The ``updateNode`` method is used to keep
+effect of supplying a compare function that does not implement a total
+ordering is undefined. The ``updateNode`` function is used to keep
client properties up to date when the tree structure changes; the
-value ``SplayTrivUpdate`` may be used for this method if there is no
+value ``SplayTrivUpdate`` may be used for this function if there is no
need to maintain client properties. (See `.usage.initialization`_ for
an example use).
@@ -340,7 +340,7 @@ _`.function.splay.tree.next`: If the tree contains a right neighbour
for ``key``, splay the tree at that node and return it. Otherwise
return ``TreeEMPTY``. See `.req.iterate`_.
-``Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, Count depth, TreeDescribeMethod nodeDescribe)``
+``Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, Count depth, TreeDescribeFunction nodeDescribe)``
_`.function.splay.tree.describe`: This function prints (using
``WriteF()``) to the stream a textual representation of the given
@@ -348,25 +348,25 @@ splay tree, using ``nodeDescribe`` to print client-oriented
representations of the nodes (see `.req.debug`_). Provided for
debugging only.
-``Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeMethod testNode, SplayTestTreeMethod testTree, void *closureP, Size closureS)``
+``Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeFunction testNode, SplayTestTreeFunction testTree, void *closureP, Size closureS)``
_`.function.splay.find.first`: Find the first node in the tree that
satisfies some client property, as determined by the ``testNode`` and
-``testTree`` methods (see `.req.property.find`_). ``closureP`` and
+``testTree`` functions (see `.req.property.find`_). ``closureP`` and
``closureS`` are arbitrary values, and are passed to the ``testNode``
-and ``testTree`` methods which may use the values as closure
+and ``testTree`` functions which may use the values as closure
environments. If there is no satisfactory node, return ``FALSE``;
otherwise set ``*nodeReturn`` to the node and return ``TRUE``. See
`.usage.delete`_ for an example.
-``Bool SplayFindLast(Tree *nodeReturn, SplayTree splay, SplayTestNodeMethod testNode, SplayTestTreeMethod testTree, void *closureP, Size closureS)``
+``Bool SplayFindLast(Tree *nodeReturn, SplayTree splay, SplayTestNodeFunction testNode, SplayTestTreeFunction testTree, void *closureP, Size closureS)``
_`.function.splay.find.last`: As ``SplayFindFirst()``, but find the
last node in the tree that satisfies the client property.
``void SplayNodeRefresh(SplayTree splay, Tree tree, TreeKey key)``
-_`.function.splay.node.refresh`: Call the ``updateNode`` method on the
+_`.function.splay.node.refresh`: Call the ``updateNode`` function on the
given node, and on any other nodes that may require updating. The
client key for the node must also be supplied; the function splays the
tree at this key. (See `.usage.insert`_ for an example use). This
@@ -375,7 +375,7 @@ a node changes (see `.req.property.change`_).
``void SplayNodeUpdate(SplayTree splay, Tree node)``
-_`.function.splay.node.update`: Call the ``updateNode`` method on the
+_`.function.splay.node.update`: Call the ``updateNode`` function on the
given node, but leave other nodes unchanged. This may be called when a
new node is created, to get the client property off the ground.
@@ -388,21 +388,21 @@ implementation provides additional features to permit clients to cache
maximum (or minimum) values of client properties for all the nodes in
a subtree. The splay tree implementation uses the cached values as
part of ``SplayFindFirst()`` and ``SplayFindLast()`` via the
-``testNode`` and ``testTree`` methods. The client is free to choose
+``testNode`` and ``testTree`` functions. The client is free to choose
how to represent the client property, and how to compute and store the
cached value.
_`.prop.update`: The cached values depend upon the topology of the
tree, which may vary as a result of operations on the tree. The client
is given the opportunity to compute new cache values whenever
-necessary, via the ``updateNode`` method (see
+necessary, via the ``updateNode`` function (see
`.function.splay.tree.init`_). This happens whenever the tree is
-restructured. The client may use the ``SplayNodeRefresh()`` method to
+restructured. The client may use the ``SplayNodeRefresh()`` function to
indicate that the client attributes at a node have changed (see
`.req.property.change`_). A call to ``SplayNodeRefresh()`` splays the
tree at the specified node, which may provoke calls to the
-``updateNode`` method as a result of the tree restructuring. The
-``updateNode`` method will also be called whenever a new splay node is
+``updateNode`` function as a result of the tree restructuring. The
+``updateNode`` function will also be called whenever a new splay node is
inserted into the tree.
_`.prop.example`: For example, if implementing an address-ordered tree
@@ -412,7 +412,7 @@ each block as the client property. The client can then maintain as a
cached value in each node the size of the largest block in the subtree
rooted at that node. This will permit a fast search for the first or
last block of at least a given size. See `.usage.callback`_ for an
-example ``updateNode`` method for such a client.
+example ``updateNode`` function for such a client.
_`.prop.ops`: The splay operations must cause client properties for
nodes to be updated in the following circumstances (see `.impl`_ for
@@ -470,8 +470,8 @@ _`.usage.client-node`: Node structure to embed a ``Tree`` (see `.type.tree`_)::
Size maxSize; /* cached value for maximum size in subtree */
} FreeBlockStruct;
-_`.usage.callback`: ``updateNode`` callback method (see
-`.type.splay.update.node.method`_)::
+_`.usage.callback`: ``updateNode`` callback function (see
+`.type.splay.update.node.function`_)::
void FreeBlockUpdateNode(SplayTree splay, Tree tree)
{
@@ -499,7 +499,7 @@ _`.usage.callback`: ``updateNode`` callback method (see
freeNode->maxSize = maxSize;
}
-_`.usage.compare`: Comparison function (see `.type.tree.compare.method`_)::
+_`.usage.compare`: Comparison function (see `.type.tree.compare.function`_)::
Compare FreeBlockCompare(Tree tree, TreeKey key) {
Addr base1, base2, limit2;
@@ -518,7 +518,7 @@ _`.usage.compare`: Comparison function (see `.type.tree.compare.method`_)::
}
_`.usage.test.tree`: Test tree function (see
-`.type.splay.test.tree.method`_)::
+`.type.splay.test.tree.function`_)::
Bool FreeBlockTestTree(SplayTree splay, Tree tree
void *closureP, Size closureS) {
@@ -532,7 +532,7 @@ _`.usage.test.tree`: Test tree function (see
}
_`.usage.test.node`: Test node function (see
-`.type.splay.test.node.method`_)::
+`.type.splay.test.node.function`_)::
Bool FreeBlockTestNode(SplayTree splay, Tree tree
void *closureP, Size closureS) {
@@ -832,7 +832,7 @@ splay around the same key. The new root will be the last node in the
sub-tree and will have a null right child; this is set to be the right
child of the node to be deleted.
-_`.impl.search`: ``SplayTreeSearch()``: Splay the node around the
+_`.impl.find`: ``SplayTreeFind()``: Splay the node around the
supplied key. If the splay found a matching node, return it; otherwise
return failure.
@@ -877,9 +877,11 @@ Testing
-------
_`.test`: There is no plan to test splay trees directly. It is
-believed that the testing described in design.mps.cbs.test will be
+believed that the testing described in design.mps.cbs.test_ will be
sufficient to test this implementation.
+.. _design.mps.cbs.test: cbs#test
+
Error Handling
--------------
@@ -895,7 +897,7 @@ _`.error.bad-compare`: Initialising a ``SplayTree`` with a compare
function that is not a valid compare function, or which doesn't
implement a total ordering on splay nodes.
-_`.error.bad-describe`: Passing an invalid describe method to
+_`.error.bad-describe`: Passing an invalid describe function to
``SplayTreeDescribe()``.
_`.error.out-of-stack`: Stack exhaustion under ``SplayTreeDescribe()``.
diff --git a/mps/design/ss.txt b/mps/design/ss.txt
new file mode 100644
index 00000000000..60b5c2817fa
--- /dev/null
+++ b/mps/design/ss.txt
@@ -0,0 +1,170 @@
+.. mode: -*- rst -*-
+
+Stack and register scanning
+===========================
+
+:Tag: design.mps.ss
+:Author: Gareth Rees
+:Date: 2014-10-22
+:Status: complete design
+:Revision: $Id$
+:Copyright: See `Copyright and License`_.
+:Index terms: pair: stack and register scanning; design
+
+
+Introduction
+------------
+
+_`.intro`: This is the design of the stack and register scanning
+module.
+
+_`.readership`: Any MPS developer; anyone porting the MPS to a new
+platform.
+
+_`.overview`: This module locates and scans references in the control
+stack and registers of the *current* thread.
+
+_`.other`: The thread manager module is responsible for scanning the
+control stack and registers of *other* threads. See
+design.mps.thread-manager.if.scan_.
+
+.. _design.mps.thread-manager.if.scan: thread-manager#if.scan
+
+
+Requirements
+------------
+
+_`.req.stack.top`: Must locate the top of the mutator's stack. (This
+is needed to support conservative garbage collection of uncooperative
+code, where references might be stored by mutator on its stack.)
+
+_`.req.stack.bottom.not`: There is no requirement to locate the bottom
+of the stack. (The mutator supplies this as an argument to
+``mps_root_create_reg()``.)
+
+_`.req.registers`: Must locate and scan all references in the *root
+registers*, the subset of registers which might contain references
+that do not also appear on the stack. (This is needed to support
+conservative garbage collection of uncooperative code, where
+references might appear in registers.)
+
+
+Design
+------
+
+_`.sol.stack.top`: Implementations find the top of the stack by
+taking the address of a local variable.
+
+_`.sol.registers`: Implementations spill the root registers onto the
+stack so that they can be scanned there.
+
+_`.sol.registers.root`: The *root registers* are the subset of the
+callee-save registers that may contain pointers.
+
+_`.sol.registers.root.justify`: The caller-save registers will have
+been spilled onto the stack by the time the MPS is entered, so will be
+scanned by the stack scan. Floating-point registers and debugging
+registers do not, as far as we are aware, contain pointers.
+
+_`.sol.inner`: Having located the top of the stack (``stackTop``), and
+spilled the root registers into the next ``n`` words, implementations
+call the generic function ``StackScanInner(ss, stackBot, stackTop,
+n)`` to actually do the scanning.
+
+
+Interface
+---------
+
+``Res StackScan(ScanState ss, Addr *stackBot)``
+
+_`.if.scan`: Scan the root registers of the current thread, and the
+control stack between ``stackBot`` and the top of the stack, in the
+context of the given scan state. Return ``ResOK`` if successful, or
+another result code if not.
+
+
+Issue
+-----
+
+_`.issue.overscan`: This design leads to over-scanning, because by the
+time ``StackScan()`` is called, there are several MPS functions on the
+stack. The scan thus ends up scanning references that belong the MPS,
+not to the mutator. See job003525_.
+
+.. _job003525: http://www.ravenbrook.com/project/mps/issue/job003525/
+
+
+Implementations
+---------------
+
+_`.impl.an`: Generic implementation in ``ssan.c``. This calls
+``setjmp()`` with a stack-allocated ``jmp_buf`` to spill the registers
+onto the stack. The C standard specifies that ``jmp_buf`` "is an array
+type suitable for holding the information needed to restore a calling
+environment. The environment of a call to the ``setjmp`` macro
+consists of information sufficient for a call to the ``longjmp``
+function to return execution to the correct block and invocation of
+that block, were it called recursively." Note that the C standard does
+not specify where the callee-save registers appear in the ``jmp_buf``,
+so the whole buffer must be scanned.
+
+_`.impl.ix`: Unix implementation in ``ssixi3.c`` and ``ssixi6.c``.
+Assembler instructions are used to spill exactly the callee-save
+registers. (Clang and GCC support a common assembler syntax.)
+
+_`.impl.w3`: Windows implementation in ``ssw3i3mv.c`` and
+``ssw3i6mv.c``. Like `.impl.an`_, this implementation uses
+``setjmp()`` with a stack-allocated ``jmp_buf`` to spill the registers
+onto the stack. However, we know the layout of the ``jmp_buf`` used by
+the compiler, and so can scan exactly the subset of registers we need.
+
+
+Document History
+----------------
+
+- 2014-10-22 GDR_ Initial draft.
+
+.. _GDR: http://www.ravenbrook.com/consultants/gdr/
+
+
+Copyright and License
+---------------------
+
+Copyright © 2014 Ravenbrook Limited. All rights reserved.
+ . This is an open source license. Contact
+Ravenbrook for commercial licensing options.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+#. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+#. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+#. Redistributions in any form must be accompanied by information on how
+ to obtain complete source code for this software and any
+ accompanying software that uses this software. The source code must
+ either be included in the distribution or be available for no more than
+ the cost of distribution plus a nominal fee, and must be freely
+ redistributable under reasonable conditions. For an executable file,
+ complete source code means the source code for all modules it contains.
+ It does not include source code for modules or files that typically
+ accompany the major components of the operating system on which the
+ executable file runs.
+
+**This software is provided by the copyright holders and contributors
+"as is" and any express or implied warranties, including, but not
+limited to, the implied warranties of merchantability, fitness for a
+particular purpose, or non-infringement, are disclaimed. In no event
+shall the copyright holders and contributors be liable for any direct,
+indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or
+services; loss of use, data, or profits; or business interruption)
+however caused and on any theory of liability, whether in contract,
+strict liability, or tort (including negligence or otherwise) arising in
+any way out of the use of this software, even if advised of the
+possibility of such damage.**
diff --git a/mps/design/telemetry.txt b/mps/design/telemetry.txt
index 08a0ae6df18..c19bbab0056 100644
--- a/mps/design/telemetry.txt
+++ b/mps/design/telemetry.txt
@@ -432,8 +432,7 @@ Allocation replayer tool
........................
_`.replayer`: A tool for replaying an allocation sequence from a log
-is available in impl.c.replay. For details, see
-design.mps.telemetry.replayer.
+is available in impl.c.replay.
Document History
diff --git a/mps/design/testthr.txt b/mps/design/testthr.txt
new file mode 100644
index 00000000000..a1bf99bb247
--- /dev/null
+++ b/mps/design/testthr.txt
@@ -0,0 +1,157 @@
+.. mode: -*- rst -*-
+
+Multi-threaded testing
+======================
+
+:Tag: design.mps.testthr
+:Author: Gareth Rees
+:Date: 2014-10-21
+:Status: complete design
+:Revision: $Id$
+:Copyright: See section `Copyright and License`_.
+:Index terms: pair: threads; testing
+
+
+Introduction
+------------
+
+_`.intro`: This is the design of the multi-threaded testing module
+in the Memory Pool System.
+
+_`.readership`: Any MPS developer.
+
+_`.overview`: The MPS is designed to work in a multi-threaded
+environment (see design.mps.thread-safety_) and this needs to be
+tested on all supported platforms. The multi-threaded testing module
+provides an interface for creating and joining threads, so that
+multi-threaded test cases are portable to all platforms on which the
+MPS runs.
+
+.. _design.mps.thread-safety: thread-safety
+
+
+Requirements
+------------
+
+_`.req.create`: The module must provide an interface for creating
+threads and running code in them. (Because there is no such interface
+in the Standard C Library.)
+
+_`.req.join`: The module must provide an interface for joining a
+running thread: that is, waiting for the thread to finish and
+collecting a result. (Because we want to be able to test that the MPS
+behaves correctly when interacting with a finished thread.)
+
+_`.req.portable`: The module must be easily portable to all the
+platforms on which the MPS runs.
+
+_`.req.usable`: The module must be simple to use, not requiring
+elaborate setup or tear-down or error handling. (Because we want test
+cases to be easy to write.)
+
+
+Implementation
+--------------
+
+_`.impl.posix`: To meet `.req.portable`_ and `.req.usable`_, the
+module presents an interface that is essentially identical to the
+POSIX Threads interface [pthreads]_, except for the names. On POSIX
+platforms the implementation is trivial; on Windows it is
+necessary to translate the concepts back and forth.
+
+_`.impl.storage`: To meet `.req.usable`_, the module defines the
+``testthr_t`` type in the header ``testthr.h`` (even though this
+requires an ``#if``), so that test cases can easily declare variables
+and allocate storage for thread identifiers.
+
+_`.impl.error`: To meet `.req.usable`_, the module does not propagate
+error codes, but calls ``error()`` from the test library if anything
+goes wrong. There is thus no need for the test cases to check result
+codes.
+
+
+Interface
+---------
+
+``typedef testthr_t``
+
+The type of thread identifiers.
+
+``typedef void *(*testthr_routine_t)(void *)``
+
+The type of a function that can be called when a thread is created.
+
+``void testthr_create(testthr_t *thread_o, testthr_routine_t start, void *arg)``
+
+Create a thread. Store the identifier of the newly created thread in
+``*thread_o``, and call ``start()``, passing ``arg`` as the single
+parameter.
+
+``void testthr_join(testthr_t *thread, void **result_o)``
+
+Wait for a thread to complete. Suspend execution of the calling thread
+until the target thread terminates (if necessary), and if ``result_o``
+is non-NULL, update ``*result_o`` with the return value of the
+thread's ``start()`` function.
+
+
+References
+----------
+
+.. [pthreads]
+ The Open Group;
+ "The Single UNIX Specification, Version 2---Threads";
+
+
+
+Document History
+----------------
+
+- 2014-10-21 GDR_ Initial draft.
+
+.. _GDR: http://www.ravenbrook.com/consultants/gdr/
+
+
+Copyright and License
+---------------------
+
+Copyright © 2014 Ravenbrook Limited. All rights reserved.
+ . This is an open source license. Contact
+Ravenbrook for commercial licensing options.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+#. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+#. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+#. Redistributions in any form must be accompanied by information on how
+ to obtain complete source code for this software and any
+ accompanying software that uses this software. The source code must
+ either be included in the distribution or be available for no more than
+ the cost of distribution plus a nominal fee, and must be freely
+ redistributable under reasonable conditions. For an executable file,
+ complete source code means the source code for all modules it contains.
+ It does not include source code for modules or files that typically
+ accompany the major components of the operating system on which the
+ executable file runs.
+
+**This software is provided by the copyright holders and contributors
+"as is" and any express or implied warranties, including, but not
+limited to, the implied warranties of merchantability, fitness for a
+particular purpose, or non-infringement, are disclaimed. In no event
+shall the copyright holders and contributors be liable for any direct,
+indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or
+services; loss of use, data, or profits; or business interruption)
+however caused and on any theory of liability, whether in contract,
+strict liability, or tort (including negligence or otherwise) arising in
+any way out of the use of this software, even if advised of the
+possibility of such damage.**
+
+
diff --git a/mps/design/thread-manager.txt b/mps/design/thread-manager.txt
index c80a818c337..48cbb912533 100644
--- a/mps/design/thread-manager.txt
+++ b/mps/design/thread-manager.txt
@@ -1,6 +1,6 @@
.. mode: -*- rst -*-
-Thread Manager
+Thread manager
==============
:Tag: design.mps.thread-manager
@@ -9,149 +9,312 @@ Thread Manager
:Status: incomplete design
:Revision: $Id$
:Copyright: See `Copyright and License`_.
-:Index terms: pair: thread manager; design
+:Index terms: pair: thread manager; design
-Purpose
--------
+Introduction
+------------
-The Thread Manager handles various thread-related functions required
-by the MPS. These are:
+_`.intro`: This is the design of the thread manager module.
-- stack scanning;
-- suspension and resumption of the mutator threads.
+_`.readership`: Any MPS developer; anyone porting the MPS to a new
+platform.
+
+_`.overview`: The thread manager implements two features that allow
+the MPS to work in a multi-threaded environment: exclusive access to
+memory, and scanning of roots in a thread's registers and control
+stack.
-Context
--------
+Requirements
+------------
-The barrier requires suspension and resumption of threads in order to
-ensure that the collector has exclusive access to part of memory.
-[design.mps.barrier.@@@@]
+_`.req.exclusive`: The thread manager must provide the MPS with
+exclusive access to the memory it manages in critical sections of the
+code. (This is necessary to avoid for the MPS to be able to flip
+atomically from the point of view of the mutator.)
-Stack scanning is provided as a service to the client. [Link?@@@@]
+_`.req.scan`: The thread manager must be able to locate references in
+the registers and control stack of the current thread, or of a
+suspended thread. (This is necessary in order to implement
+conservative collection, in environments where the registers and
+control stack contain ambiguous roots. Scanning of roots is carried
+out during the flip, hence while other threads are suspended.)
+
+_`.req.register.multi`: It must be possible to register the same
+thread multiple times. (This is needed to support the situation where
+a program that does not use the MPS is calling into MPS-using code
+from multiple threads. On entry to the MPS-using code, the thread can
+be registered, but it may not be possible to ensure that the thread is
+deregistered on exit, because control may be transferred by some
+non-local mechanism such as an exception or ``longjmp()``. We don't
+want to insist that the client program keep a table of threads it has
+registered, because maintaining the table might require allocation,
+which might provoke a collection. See request.dylan.160252_.)
+
+.. _request.dylan.160252: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160252/
+
+_`.req.thread.die`: It would be nice if the MPS coped with threads
+that die while registered. (This makes it easier for a client program
+to interface with foreign code that terminates threads without the
+client program being given an opportunity to deregister them. See
+request.dylan.160022_ and request.mps.160093_.)
+
+.. _request.dylan.160022: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160022
+.. _request.mps.160093: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/mps/160093/
-Overview
---------
+Design
+------
+
+_`.sol.exclusive`: In order to meet `.req.exclusive`_, the arena
+maintains a ring of threads (in ``arena->threadRing``) that have been
+registered by the client program. When the MPS needs exclusive access
+to memory, it suspends all the threads in the ring except for the
+currently running thread. When the MPS no longer needs exclusive
+access to memory, it resumes all threads in the ring.
+
+_`.sol.exclusive.assumption`: This relies on the assumption that any
+thread that might refer to, read from, or write to memory in
+automatically managed pool classes is registered with the MPS. This is
+documented in the manual under ``mps_thread_reg()``.
+
+_`.sol.thread.term`: The thread manager cannot reliably detect that a
+thread has terminated. The reason is that threading systems do not
+guarantee behaviour in this case. For example, POSIX_ says, "A
+conforming implementation is free to reuse a thread ID after its
+lifetime has ended. If an application attempts to use a thread ID
+whose lifetime has ended, the behavior is undefined." For this reason,
+the documentation for ``mps_thread_dereg()`` specifies that it is an
+error if a thread dies while registered.
+
+.. _POSIX: http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_02
+
+_`.sol.thread.term.attempt`: Nonetheless, the thread manager makes a
+"best effort" to continue running after detecting a terminated thread,
+by moving the thread to a ring of dead threads, and avoiding scanning
+it. This might allow a malfunctioning client program to limp along.
+
+
+Interface
+---------
``typedef struct mps_thr_s *Thread``
-Each thread is represented by an object of type ``Thread``. The
-``Thread`` type is implemented as an ADT. A list of ``Thread`` objects
-is maintained in the arena (as the ``Ring`` structure
-``arena->threadRing``). The ``Thread`` object contains
-operating-system-dependent information about the thread -- information
-necessary for manipulating the thread and for scanning the thread
-context. Thread "registration" adds or removes the current thread to
-the ``Thread`` list in the arena.
+_`.if.thread`: The type of threads. It is a pointer to an opaque
+structure, which must be defined by the implementation.
+``Bool ThreadCheck(Thread thread)``
-Detailed Design
----------------
+_`.if.check`: The check function for threads. See design.mps.check_.
-Stack scan
-..........
+.. _design.mps.check: check
-This is a module providing a stack scanning function. The scanning is
-architecture and operating system dependent. Typically the function
-will push the subste of the save registers (those preserved across
-function calls) which may contain pointers (that is, neither
-floating-point or debugging registers) and call ``TraceScanStack()``
-on the appropriate range.
+``Bool ThreadCheckSimple(Thread thread)``
+_`.if.check.simple`: A thread-safe check function for threads, for use
+by ``mps_thread_dereg()``. It can't use ``AVER(TESTT(Thread,
+thread))``, as recommended by design.mps.sig.check.arg.unlocked_,
+since ``Thread`` is an opaque type.
-Thread interface
-................
+.. _design.mps.sig.check.arg.unlocked: sig#check.arg.unlocked
+
+``Arena ThreadArena(Thread thread)``
+
+_`.if.arena`: Return the arena that the thread is registered with.
+Must be thread-safe as it needs to be called by ``mps_thread_dereg()``
+before taking the arena lock.
``Res ThreadRegister(Thread *threadReturn, Arena arena)``
-Register the current thread with the arena, allocating a new
-``*threadReturn`` to point to it.
+_`.if.register`: Register the current thread with the arena,
+allocating a new ``Thread`` object. If successful, update
+``*threadReturn`` to point to the new thread and return ``ResOK``.
+Otherwise, return a result code indicating the cause of the error.
``void ThreadDeregister(Thread thread, Arena arena)``
-Remove ``thread`` from the list of threads managed by the arena and
-free it.
+_`.if.deregister`: Remove ``thread`` from the list of threads managed
+by the arena and free it.
-``void ThreadRingSuspend(Ring threadRing)``
+``void ThreadRingSuspend(Ring threadRing, Ring deadRing)``
-Suspend all the threads on the list ``threadRing``, except for the
-current thread.
+_`.if.ring.suspend`: Suspend all the threads on ``threadRing``, except
+for the current thread. If any threads are discovered to have
+terminated, move them to ``deadRing``.
-``void ThreadRingResume(Ring threadRing)``
+``void ThreadRingResume(Ring threadRing, Ring deadRing)``
-Resume all the threads on the list ``threadRing``.
+_`.if.ring.resume`: Resume all the threads on ``threadRing``. If any
+threads are discovered to have terminated, move them to ``deadRing``.
+
+``Thread ThreadRingThread(Ring threadRing)``
+
+_`.if.ring.thread`: Return the thread that owns the given element of
+the thread ring.
``Res ThreadScan(ScanState ss, Thread thread, void *stackBot)``
-Scan the stacks and root registers of ``thread``, treating each value
-found as an ambiguous reference. The exact definition is operating
-system and architecture dependent
+_`.if.scan`: Scan the stacks and root registers of ``thread``,
+treating each value found as an ambiguous reference. ``stackBot``
+points to the "bottom" of the thread's stack---this is the value that
+was supplied by the client program when it called
+``mps_root_create_reg()``. In the common case, where the stack grows
+downwards, ``stackBot`` is actually the highest stack address. Return
+``ResOK`` if successful, another result code otherwise.
-Single-threaded generic implementation
-......................................
+Implementations
+---------------
-In ``than.c``.
+Generic implementation
+......................
-- Single threaded (calling ``ThreadRegister()`` on a second thread
- causes an assertion failure).
-- ``ThreadRingSuspend()`` and ``ThreadRingResume()`` do nothing
- because there are no other threads.
-- ``ThreadScan()`` calls ``StackScan()``.
+_`.impl.an`: In ``than.c``.
+
+_`.impl.an.single`: Supports a single thread. (This cannot be enforced
+because of `.req.register.multi`_.)
+
+_`.impl.an.register.multi`: There is no need for any special treatment
+of multiple threads, because ``ThreadRingSuspend()`` and
+``ThreadRingResume()`` do nothing.
+
+_`.impl.an.suspend`: ``ThreadRingSuspend()`` does nothing because
+there are no other threads.
+
+_`.impl.an.resume`: ``ThreadRingResume()`` does nothing because no
+threads are ever suspended.
+
+_`.impl.an.scan`: Just calls ``StackScan()`` since there are no
+suspended threads.
POSIX threads implementation
............................
-In ``thix.c``. See design.mps.pthreadext.
+_`.impl.ix`: In ``thix.c`` and ``pthrdext.c``. See
+design.mps.pthreadext_.
+
+.. _design.mps.pthreadext: pthreadext
+
+_`.impl.ix.multi`: Supports multiple threads.
+
+_`.impl.ix.register`: ``ThreadRegister()`` records the thread id
+the current thread by calling |pthread_self|_.
+
+.. |pthread_self| replace:: ``pthread_self()``
+.. _pthread_self: http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_self.html
+
+_`.impl.ix.register.multi`: Multiply-registered threads are handled
+specially by the POSIX thread extensions. See
+design.mps.pthreadext.req.suspend.multiple_ and
+design.mps.pthreadext.req.resume.multiple_.
+
+.. _design.mps.pthreadext.req.suspend.multiple: pthreadext#req.suspend.multiple
+.. _design.mps.pthreadext.req.resume.multiple: pthreadext#req.resume.multiple
+
+_`.impl.ix.suspend`: ``ThreadRingSuspend()`` calls
+``PThreadextSuspend()``. See design.mps.pthreadext.if.suspend_.
+
+.. _design.mps.pthreadext.if.suspend: pthreadext#if.suspend
+
+_`.impl.ix.resume`: ``ThreadRingResume()`` calls
+``PThreadextResume()``. See design.mps.pthreadext.if.resume_.
+
+.. _design.mps.pthreadext.if.resume: pthreadext#if.resume
+
+_`.impl.ix.scan.current`: ``ThreadScan()`` calls ``StackScan()`` if
+the thread is current.
+
+_`.impl.ix.scan.suspended`: ``PThreadextSuspend()`` records the
+context of each suspended thread, and ``ThreadRingSuspend()`` stores
+this in the ``Thread`` structure, so that is available by the time
+``ThreadScan()`` is called.
-Win32 implementation
-....................
+Windows implementation
+......................
-In ``thw3.c``.
+_`.impl.w3`: In ``thw3.c``.
-- Supports multiple threads.
-- Structured exception style faults are expected.
-- ``ThreadRingSuspend()`` and ``ThreadRingResume()`` loop over threads
- and call Win32 API functions ``SuspendThread()`` and
- ``ResumeThread()``.
-- ``ThreadRegister()`` records information for the current thread:
+_`.impl.w3.multi`: Supports multiple threads.
- - A Win32 "handle" with access flags ``THREAD_SUSPEND_RESUME`` and
- ``THREAD_GET_CONTEXT``. This handle is needed as parameter to
- ``SuspendThread()`` and ``ResumeThread()``.
- - The Win32 ``GetCurrentThreadId()`` so that the current thread may
- be identified.
+_`.impl.w3.register`: ``ThreadRegister()`` records the following
+information for the current thread:
-- Stack scanning is Win32 specific:
+ - A ``HANDLE`` to the process, with access flags
+ ``THREAD_SUSPEND_RESUME`` and ``THREAD_GET_CONTEXT``. This handle
+ is needed as parameter to |SuspendThread|_ and
+ |ResumeThread|_.
- - ``ThreadScan()`` calls ``StackScan()`` if the thread is current.
- ``GetThreadContext()`` doesn't work on the current thread (the
- context would not necessarily have the values which were in the
- saved registers on entry to the MM).
- - Otherwise it calls ``GetThreadContext()`` to get the root
- registers and the stack pointer.
- - The thread's registers are dumped into a ``CONTEXT`` structure and
- fixed in memory.
- - Scan the stack (getting the stack pointer from ``CONTEXT.Rsp``).
+ - The result of |GetCurrentThreadId|_, so that the current thread
+ may be identified in the ring of threads.
+
+.. |SuspendThread| replace:: ``SuspendThread()``
+.. _SuspendThread: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686345.aspx
+.. |ResumeThread| replace:: ``ResumeThread()``
+.. _ResumeThread: http://msdn.microsoft.com/en-us/library/windows/desktop/ms685086.aspx
+.. |GetCurrentThreadId| replace:: ``GetCurrentThreadId()``
+.. _GetCurrentThreadId: http://msdn.microsoft.com/en-us/library/windows/desktop/ms683183.aspx
+
+_`.impl.w3.register.multi`: There is no need for any special treatment
+of multiple threads, because Windows maintains a suspend count that is
+incremented on |SuspendThread|_ and decremented on
+|ResumeThread|_.
+
+_`.impl.w3.suspend`: ``ThreadRingSuspend()`` calls |SuspendThread|_.
+
+_`.impl.w3.resume`: ``ThreadRingResume()`` calls |ResumeThread|_.
+
+_`.impl.w3.scan.current`: ``ThreadScan()`` calls ``StackScan()`` if
+the thread is current. This is because |GetThreadContext|_ doesn't
+work on the current thread: the context would not necessarily have the
+values which were in the saved registers on entry to the MPS.
+
+.. |GetThreadContext| replace:: ``GetThreadContext()``
+.. _GetThreadContext: http://msdn.microsoft.com/en-us/library/windows/desktop/ms679362.aspx
+
+_`.impl.w3.scan.suspended`: Otherwise, ``ThreadScan()`` calls
+|GetThreadContext|_ to get the root registers and the stack
+pointer.
-Issues
-------
+OS X implementation
+...................
-#. Scanning after exceptions. ``StackScan()`` relies on the
- non-preserved registers having been pushed on the stack. If we want
- to scan after a fault we must make sure that these registers are
- either already stored on the stack, or, have an extra function to
- do this explicitly.
+_`.impl.xc`: In ``thxc.c``.
-#. Multiple registration. It is not clear whether a thread should be
- allowed to be registered multiple times. We do not provide a
- mechanism for knowing whether a thread is already registered with
- an arena.
+_`.impl.xc.multi`: Supports multiple threads.
+
+_`.impl.xc.register`: ``ThreadRegister()`` records the Mach port of
+the current thread by calling |mach_thread_self|_.
+
+.. |mach_thread_self| replace:: ``mach_thread_self()``
+.. _mach_thread_self: http://www.gnu.org/software/hurd/gnumach-doc/Thread-Information.html
+
+_`.impl.xc.register.multi`: There is no need for any special treatment
+of multiple threads, because Mach maintains a suspend count that is
+incremented on |thread_suspend|_ and decremented on
+|thread_resume|_.
+
+.. |thread_suspend| replace:: ``thread_suspend()``
+.. _thread_suspend: http://www.gnu.org/software/hurd/gnumach-doc/Thread-Execution.html
+.. |thread_resume| replace:: ``thread_resume()``
+.. _thread_resume: http://www.gnu.org/software/hurd/gnumach-doc/Thread-Execution.html
+
+_`.impl.xc.suspend`: ``ThreadRingSuspend()`` calls
+|thread_suspend|_.
+
+_`.impl.xc.resume`: ``ThreadRingResume()`` calls |thread_resume|_.
+
+_`.impl.xc.scan.current`: ``ThreadScan()`` calls ``StackScan()`` if
+the thread is current.
+
+_`.impl.xc.scan.suspended`: Otherwise, ``ThreadScan()`` calls
+|thread_get_state|_ to get the root registers and the stack pointer.
+
+.. |thread_get_state| replace:: ``thread_get_state()``
+.. _thread_get_state: http://www.gnu.org/software/hurd/gnumach-doc/Thread-Execution.html
Document History
@@ -163,6 +326,8 @@ Document History
- 2013-05-26 GDR_ Converted to reStructuredText.
+- 2014-10-22 GDR_ Complete design.
+
.. _RB: http://www.ravenbrook.com/consultants/rb/
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
diff --git a/mps/design/thread-safety.txt b/mps/design/thread-safety.txt
index b091ac984ab..826d008a596 100644
--- a/mps/design/thread-safety.txt
+++ b/mps/design/thread-safety.txt
@@ -26,10 +26,12 @@ threads calling into the MPS. The initial approach is very simple.
Some of the code is known to operate with exclusive access to the data
it manipulates, so this code is safe. For the rest of the code, shared
data structures are locked by the use of a single binary lock
-(design.mps.lock(0)) per arena. This lock is claimed on entry to the
+(design.mps.lock_) per arena. This lock is claimed on entry to the
MPS and released on exit from it. So there is at most a single thread
(per arena) running "inside" the MPS at a time.
+.. _design.mps.lock: lock
+
Requirements
------------
@@ -47,11 +49,15 @@ _`.arch.arena`: Arena Lock: no shared data between arenas.
_`.arch.global.binary`: Global binary lock: protects mutable data
shared between arenas -- that is, the arena ring, see
-design.mps.arena.static.ring.lock.
+design.mps.arena.static.ring.lock_.
+
+.. _design.mps.arena.static.ring.lock: arena#static.ring.lock
_`.arch.global.recursive`: Global recursive lock: protects static data
which must be initialized once -- for example, pool classes, see
-design.mps.protocol.impl.init-lock.
+design.mps.protocol.impl.init-lock_.
+
+.. _design.mps.protocol.impl.init-lock: protocol#impl.init-lock
_`.arch.other`: Other: data not shared.
@@ -118,12 +124,14 @@ running on genuine multiprocessor `.lock-cost.wait`_ is irrelevant.
_`.anal.perf.alloc`: During typical use we expect that it is
allocation that is the most frequent activity. Allocation buffers
-(design.mps.buffer) are designed to allow allocation in concurrent
+(design.mps.buffer_) are designed to allow allocation in concurrent
threads without needing a lock. So the most significant time a thread
spends in the MPS will be on a buffer-fill or during a collection. The
next most significant use is likely to be buffer create and deletion,
as a separate buffer will be required for each thread.
+.. _design.mps.buffer: buffer
+
_`.anal.perf.lock`: So overall the performance cost of locking is, I
estimate, most significantly the overhead of calling the locking
functions. Hence it would be undesirable from a performance point of
@@ -184,7 +192,7 @@ would avoid deadlock.
Implementation
--------------
-Use MPS locks (design.mps.lock) to do locking.
+Use MPS locks (design.mps.lock_) to do locking.
Locking Functions
.................
diff --git a/mps/design/trace.txt b/mps/design/trace.txt
index 349a64bfce8..76ed0fa954c 100644
--- a/mps/design/trace.txt
+++ b/mps/design/trace.txt
@@ -249,13 +249,12 @@ can reach by following references of the third, second, and first
ranks. And so on. The description of the tracer working like this
originated in [RHSK_2007-06-25]_.
-A trace keep track of which band it is tracing. This is returned by
+A trace keeps track of which band it is tracing. This is returned by
the ``TraceBand()`` method. Keeping this band information helps it
implement the semantics of finalization and weakness. The band used to
not be explicitly stored, but this hindered the implementation of good
-finalization semantics (essentially in some circumstances finalization
-messages were delayed by at least one collection cycle, see
-job001658_.
+finalization semantics (in some circumstances finalization messages
+were delayed by at least one collection cycle: see job001658_).
.. _job001658: https://info.ravenbrook.com/project/mps/issue/job001658/
diff --git a/mps/design/type.txt b/mps/design/type.txt
index c90a9335456..25943f41a4b 100644
--- a/mps/design/type.txt
+++ b/mps/design/type.txt
@@ -108,7 +108,7 @@ Attribute Description
=================== ===================================================
There is an attribute field in the pool class (``PoolClassStruct``)
-which declares the attributes of that class. See `design.mps.class-interface.field.attr`_.
+which declares the attributes of that class. See design.mps.class-interface.field.attr_.
.. _design.mps.class-interface.field.attr: class-interface
@@ -180,8 +180,8 @@ Mode Description
======================== ==============================================
``BufferModeATTACHED`` Buffer is attached to a region of memory.
``BufferModeFLIPPED`` Buffer has been flipped.
-``BufferModeLOGGED`` Buffer emits the events ``BufferReserve`` and
- ``BufferCommit``.
+``BufferModeLOGGED`` Buffer remains permanently trapped, so that
+ all reserve and commit events can be logged.
``BufferModeTRANSITION`` Buffer is in the process of being detached.
======================== ==============================================
@@ -323,6 +323,21 @@ determined then the smallest unsigned integer with a large enough
range may be used instead.
+``typedef int LocusPrefKind``
+
+_`.segprefkind`: The type ``LocusPrefKind`` expresses a preference for
+addresses within an address space. It takes one of the following
+values:
+
+==================== ====================================
+Kind Description
+==================== ====================================
+``LocusPrefHIGH`` Prefer high addresses.
+``LocusPrefLOW`` Prefer low addresses.
+``LocusPrefZONESET`` Prefer addresses in specified zones.
+==================== ====================================
+
+
``typedef unsigned MessageType``
_`.messagetype`: ``MessageType`` is the type of a message. See
@@ -400,9 +415,7 @@ intended.
``typedef Word RefSet``
_`.refset`: ``RefSet`` is a conservative approximation to a set of
-references. See design.mps.refset_.
-
-.. _design.mps.refset: refset
+references. See design.mps.refset.
``typedef int Res``
@@ -493,21 +506,6 @@ _`.rootvar`: The type ``RootVar`` is the type of the discriminator for
the union within ``RootStruct``.
-``typedef int LocusPrefKind``
-
-_`.segprefkind`: The type ``LocusPrefKind`` expresses a preference for
-addresses within an address space. It takes one of the following
-values:
-
-==================== ====================================
-Kind Description
-==================== ====================================
-``LocusPrefHigh`` Prefer high addresses.
-``LocusPrefLow`` Prefer low addresses.
-``LocusPrefZoneSet`` Prefer addresses in specified zones.
-==================== ====================================
-
-
``typedef unsigned Serial``
_`.serial`: A ``Serial`` is a number which is assigned to a structure
@@ -576,7 +574,7 @@ space as the client data.
_`.traceid`: A ``TraceId`` is an unsigned integer which is less than
``TraceLIMIT``. Each running trace has a different ``TraceId`` which
is used to index into the tables and bitfields that record the state
-of that trace. See `design.mps.trace.instance.limit`_.
+of that trace. See design.mps.trace.instance.limit_.
.. _design.mps.trace.instance.limit: trace#instance.limit
@@ -655,7 +653,9 @@ required that might range as large as the machine word.
_`.word.source`: ``Word`` is derived from the macro ``MPS_T_WORD``
which is declared in impl.h.mpstd according to the target platform
-(design.mps.config.pf.word).
+(design.mps.config.pf.word_).
+
+.. _design.mps.config.pf.word: config#pf.word
_`.word.conv.c`: ``Word`` is converted to ``mps_word_t`` in the MPS C
Interface.
@@ -667,7 +667,7 @@ _`.word.ops`: ``WordIsAligned()``, ``WordAlignUp()``,
``typedef Word ZoneSet``
_`.zoneset`: ``ZoneSet`` is a conservative approximation to a set of
-zones. See design.mps.refset_.
+zones. See design.mps.refset.
Abstract types
diff --git a/mps/design/version.txt b/mps/design/version.txt
index 2259645844e..798c01ead99 100644
--- a/mps/design/version.txt
+++ b/mps/design/version.txt
@@ -38,10 +38,12 @@ consideration:
There are issues of programmatic and human access to these versions.
_`.overview.split`: The design is split accordingly. See
-design.mps.version-library for the design of a system for
+design.mps.version-library_ for the design of a system for
determining the version of the library one is using. And other
non-existent documents for the others.
+.. _design.mps.version-library: version-library
+
Document History
----------------
diff --git a/mps/design/vm.txt b/mps/design/vm.txt
index cf282c94b69..fb1be6eb5da 100644
--- a/mps/design/vm.txt
+++ b/mps/design/vm.txt
@@ -6,118 +6,194 @@ Virtual mapping
:Tag: design.mps.vm
:Author: richard
:Date: 1998-05-11
-:Status: incomplete design
+:Status: complete design
:Revision: $Id$
:Copyright: See `Copyright and License`_.
-:Index terms: pair: virtual mapping; design
+:Index terms: pair: virtual mapping; design
Introduction
------------
-_`.intro`: This the design of the VM interface. The VM interface
-provides a simple, low-level, operating-system independent interface
-to address-space. Each call to ``VMInit()`` reserves (from the
-operating-system) a single contiguous range of addresses, and updates
-a ``VMStruct`` thereafter used to manage this address-space. The VM
-interface has separate implementations for each platform that supports
-it (at least conceptually, in practice some of them may be the same).
-The VM module provides a mechanism to reserve large (relative to the
-amount of RAM) amounts of address space, and functions to map (back
-with RAM) and unmap portions of this address space.
+_`.intro`: This is the design of the virtual mapping module.
-_`.motivation`: The VM is used by the VM Arena Class. It provides the
-basic substrate to provide sparse address maps. Sparse address maps
-have at least two uses: to encode information into the address of an
-object which is used in tracing (the Zone Test) to speed things up; to
-avoid fragmentation at the segment level and above (since the amount
-of address space reserved is large compared to the RAM, the hope is
-that there will also be enough address space somewhere to fit any
-particular segment in).
+_`.readership`: Any MPS developer; anyone porting the MPS to a new
+platform.
+
+_`.overview`: The virtual mapping module provides a simple, portable,
+low-level interface to address space, with functions for reserving,
+releasing, mapping and unmapping ranges of addresses.
+
+_`.motivation`: The virtual mapping module is heavily used by the VM
+Arena Class (see design.mps.arena.vm_).
+
+.. _design.mps.arena.vm: arenavm
-Definitions
------------
+Requirements
+------------
-_`.def.reserve`: The *reserve* operation: exclusively reserve a
-portion of the virtual address space without arranging RAM or backing
-store for the virtual addresses. The intention is that no other
-component in the process will make use of the reserved virtual
-addresses, but in practice this may entail assuming a certain amount
-of cooperation. When reserving address space, the requester simply
-asks for a particular size, not a particular range of virtual
-addresses. Accessing (read/write/execute) reserved addresses is
-illegal unless those addresses have been mapped.
+_`.req.granularity`: The virtual mapping module must report the
+*granularity* with which address space can be managed. (This is
+necessary for the arena to be able to portably determine its grain
+size; see design.mps.arena.def.grain_.)
-_`.def.map`: The *map* operation: arrange that a specified portion of
-the virtual address space is mapped from the swap, effectively
-allocating RAM and/or swap space for a particular range of addresses.
-If successful, accessing the addresses is now legal. Only reserved
-addresses should be mapped.
+.. _design.mps.arena.def.grain: arena#def.grain
-_`.def.unmap`: The *unmap* operation: the inverse of the map
-operation. Arrange that a specified portion of the virtual address
-space is no longer mapped, effectively freeing up the RAM and swap
-space that was in use. Accessing the addresses is now illegal. The
-addresses return to the reserved state.
+_`.req.reserve`: The *reserve* operation must reserves a chunk of
+address space.
-_`.def.vm`: "VM" stands for Virtual Memory. Various meanings: a
-processor architecture's virtual space and structure; the generic
-idea, interface, or implementation of the MPS VM module; the C
-structure (``struct VMStruct``) used to encapsulate the functionality
-of the MPS VM module; an instance of such a structure.
+_`.req.reserve.exclusive`: The MPS should have exclusive use of the
+reserved chunk. (None of our supported operating systems can actually
+provide this feature, alas. We rely on co-operation with the client
+program.)
-_`.def.vm.mps`: In the MPS, a "VM" is a ``VMStruct``, providing access
-to the single contiguous range of address-space that was reserved
-(from the operating-system) when ``VMInit()`` was called.
+_`.req.reserve.continguous`: The reserved chunk is a *contiguous*
+portion of address space. (Contiguity is needed for zones to work; see
+design.mps.arena.vm.overview.gc.zone_.)
+
+.. _design.mps.arena.vm.overview.gc.zone: arenavm#overview.gc.zone
+
+_`.req.reserve.size`: The reserved chunk is at least a *specified
+size*. (This is necessary for zones to work.)
+
+_`.req.reserve.align`: The reserved chunk is aligned to a *specified
+alignment*. (This is necessary for the arena to be able to manage
+address space in terms of grains.)
+
+_`.req.reserve.overhead`: The reserved chunk is not much larger than
+specified, preferably with no more than a grain of overhead. (This is
+necessary in order to allow the client program to specify the amount
+of address space the MPS uses, so that it can co-operate with other
+subsystems that use address space.)
+
+.. _design.mps.arena.vm.overview.gc.zone: arenavm#overview.gc.zone
+
+_`.req.reserve.address.not`: There is no requirement to be able to
+reserve address space at a particular address. (The zone
+implementation uses bits from the middle of the address, so can cope
+wherever the portion is placed in the address space.)
+
+_`.req.reserve.map.not`: The reserve operation should not map the
+chunk into main memory or swap space. (The zone strategy is most
+efficient if address space is use sparsely, but main memory is a
+limited resource.)
+
+_`.req.release`: The *release* operation should release a previously
+reserved chunk of address space so that it may be used by other
+subsystems of the client program. (This is needed to support client
+programs on systems where address space is tight, and the client's
+subsystems need to co-operate in their use of address space.)
+
+_`.req.reserved`: The virtual mapping module must report the total
+amount of reserved memory in each chunk of address space. (This is
+needed to implement ``mps_arena_reserved()``.)
+
+_`.req.map`: The *map* operation must arrange for a (previously
+reserved) range of address space to be mapped into main memory or swap
+space, so that addresses in the range can be read and written.
+
+_`.req.unmap`: The *unmap* operation should arrange for a previously
+mapped range of address space to no longer be mapped into main memory
+or swap space. (This is needed to support client programs on systems
+where main memory is scarce, and the client's subsystems need to
+co-operate in their use of main memory.)
+
+_`.req.mapped`: The virtual mapping module must maintain the total
+amount of mapped memory in each chunk of address space. (This is
+needed to allow the client program to limit the use of main memory by
+the MPS via the "commit limit" mechanism.)
+
+_`.req.bootstrap`: The virtual mapping module must be usable without
+allocating heap memory. (This is necessary for the VM arena to get off
+the ground.)
+
+_`.req.params`: The interface should make it possible for MPS to allow
+the client program to modify the behaviour of the virtual mapping
+implementation. (This is needed to implement the
+``MPS_KEY_VMW3_MEM_TOP_DOWN`` keyword argument.)
+
+
+Design
+------
+
+_`.sol.overhead`: To meet `.req.reserve.contiguous`_,
+`.req.reserve.align`_ and `.req.reserve.overhead`_, most VM
+implementations ask the operating system for ``size + grainSize -
+pageSize`` bytes of address space. This ensures that wherever the
+operating system places the reserved address space, it contains a
+continguous region of ``size`` bytes aligned to a multiple of
+``grainSize``. The overhead is thus ``grainSize - pageSize``, and in
+the common case where ``grainSize`` is equal to ``pageSize``, this is
+zero.
+
+_`.sol.bootstrap`: To meet `.req.bootstrap`_, the interface provides
+the function ``VMCopy()``. This allows the initialization of a
+``VMChunk`` to proceed in four steps. First, allocate space for a
+temporary VM descriptor on the stack. Second, call ``VMInit()`` to
+reserve address space and initialize the temporary VM descriptor.
+Third, call ``VMMap()`` on the new VM to map enough memory to store a
+``VMChunk``. Fourth, call ``VMCopy()`` to copy the temporary VM
+descriptor into its place in the ``VMChunk``.
+
+_`.sol.params`: To meet `.req.params`_, the interface provides the
+function ``VMParamFromArgs()``, which decodes relevant keyword
+arguments into a temporary buffer provided by the caller; this buffer
+is then passed to ``VMInit()``. The size of the buffer must be
+statically determinable so that the caller can allocate it on the
+stack: it is given by the constant ``VMParamSize``. Since this is
+potentially platform-dependent it is defined in ``config.h``.
Interface
---------
+``typedef VMStruct *VM``
+
+_`.if.vm`: ``VM`` is a descriptor for a reserved chunk of address
+space. It points to a ``VMStruct`` structure, which is defined in
+``vm.h`` so that it can be inlined in the ``VMChunkStruct`` by the VM
+arena class.
+
``Size PageSize(void)``
-_`.if.page.size`: Return the operating system's "page size", that is,
-the granularity with which the operating system can map and unmap
-virtual memory. For speed (on systems like Windows where determining
-the page size involves a system call), this is cached in each VM
-descriptor and accessible via the ``VMPageSize()`` function.
+_`.if.page.size`: Return the "page size": that is, the granularity
+with which the operating system can reserve and map address space.
+
+_`.if.page.size.cache`: On some systems (for example, Windows),
+determining the page size requires a system call, so for speed the
+page size is cached in each VM descriptor and should be retrieved by
+calling the ``VMPageSize()`` function.
``Res VMParamFromArgs(void *params, size_t paramSize, ArgList args)``
-_`.if.param.from.args`: This function processes the keyword arguments
-(the ones that are relevant to the VM implementation) in the ``args``
-parameter and stores a description of them in the buffer pointed to by
-``params`` (which is ``paramSize`` bytes long). It is an error if the
-buffer is not big enough store the parameters for this VM
+_`.if.param.from.args`: Decode the relevant keyword arguments in the
+``args`` parameter, and store a description of them in the buffer
+pointed to by ``params`` (which is ``paramSize`` bytes long). It is an
+error if the buffer is not big enough store the parameters for the VM
implementation.
``Res VMInit(VM vm, Size size, Size grainSize, void *params)``
-_`.if.init`: ``VMInit()`` is responsible for reserving an amount
-of virtual address space. The ``params`` argument points to a
-parameter block initialized by a call to ``VMParamFromArgs()``. If
-successful, the VM descriptor given by the parameter ``vm`` is
-updated to describe the address space, and ``ResOK`` is returned. The
-created VM has at least ``size`` bytes of virtual memory reserved
-starting at an address which is a multiple of ``grainSize``.
-
-If there's not enough address space to reserve a block of the given
-size, ``ResRESOURCE`` is returned. The reserved virtual memory can be
-mapped and unmapped by calling ``VMMap()`` and ``VMUnmap()``.
+_`.if.init`: Reserve a chunk of address space that contains at least
+``size`` addresses, starting at an address which is a multiple of
+``grainSize``. The ``params`` argument points to a parameter block
+that was initialized by a call to ``VMParamFromArgs()``. If
+successful, update ``vm`` to describe the reserved chunk, and
+return ``ResOK``. Otherwise, return ``ResRESOURCE``.
``void VMFinish(VM vm)``
-_`.if.finish`: A VM is destroyed by calling ``VMFinish()``. Any
-address space that was mapped through this VM is unmapped.
+_`.if.finish`: Release the chunk of address space described by ``vm``.
+Any addresses that were mapped through this VM are now unmapped.
``Res VMMap(VM vm, Addr base, Addr limit)``
_`.if.map`: Map the range of addresses from ``base`` (inclusive) to
-``limit`` (exclusive) into memory. It is an error if the range does
-not lie between ``VMBase(vm)`` and ``VMLimit(vm)``, or if ``base`` and
-``limit`` are not multiples of ``VMPageSize(vm)``. Return ``ResOK``
-if successful, ``ResMEMORY`` if not.
+``limit`` (exclusive) into main memory. It is an error if the range
+does not lie between ``VMBase(vm)`` and ``VMLimit(vm)``, or if
+``base`` and ``limit`` are not multiples of ``VMPageSize(vm)``. Return
+``ResOK`` if successful, ``ResMEMORY`` otherwise.
``void VMUnmap(VM vm, Addr base, Addr limit)``
@@ -137,22 +213,122 @@ last grain that is wholly inside the VM).
``Size VMReserved(VM vm)``
-_`.if.reserved`: Return the total number of bytes of address space
-reserved by the VM. (This may include addresses that are not available
+_`.if.reserved`: Return the amount of address space (in bytes)
+reserved by the VM. This may include addresses that are not available
for mapping because of the requirement for ``VMBase(vm)`` and
-``VMLimit(vm)`` to be multiples of the grain size.)
+``VMLimit(vm)`` to be multiples of the grain size.
``Size VMMapped(VM vm)``
-_`.if.mapped`: Return the total number of bytes of address space
-currently mapped into memory by the VM.
+_`.if.mapped`: Return the amount of address space (in bytes) currently
+mapped into memory by the VM.
+
+``void VMCopy(VM dest, VM src)``
+
+_`.if.copy`: Copy the VM descriptor from ``src`` to ``dest``.
-Notes
------
+Implementations
+---------------
-_`.testing`: It is important to test that a VM implementation will
-work in extreme cases.
+
+Generic implementation
+......................
+
+_`.impl.an`: In ``vman.c``.
+
+_`.impl.an.page.size`: The generic VM uses a fake page size, given by
+the constant ``VMAN_PAGE_SIZE`` in ``config.h``.
+
+_`.impl.an.param`: Decodes no keyword arguments.
+
+_`.impl.an.reserve`: Address space is "reserved" by calling
+``malloc()``.
+
+_`.impl.an.release`: Address space is "released" by calling
+``free()``.
+
+_`.impl.an.map`: Mapping (and unmapping) just fills the mapped region
+with copies of ``VMJunkBYTE`` to emulate the erasure of freshly mapped
+pages by virtual memory systems.
+
+
+Unix implementation
+...................
+
+_`.impl.ix`: In ``vmix.c``.
+
+_`.impl.ix.page.size`: The page size is given by ``getpagesize()``.
+
+_`.impl.ix.param`: Decodes no keyword arguments.
+
+_`.impl.ix.reserve`: Address space is reserved by calling |mmap|_,
+passing ``PROT_NONE`` and ``MAP_PRIVATE | MAP_ANON``.
+
+.. |mmap| replace:: ``mmap()``
+.. _mmap: http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html
+
+_`.impl.ix.anon.trans`: Note that ``MAP_ANON`` ("map anonymous
+memory not associated with any specific file") is an extension to
+POSIX, but it is supported by FreeBSD, Linux, and OS X. A work-around
+that was formerly used on systems lacking ``MAP_ANON`` was to map
+the file ``/dev/zero``.
+
+_`.impl.ix.release`: Address space is released by calling |munmap|_.
+
+.. |munmap| replace:: ``munmap()``
+.. _munmap: http://pubs.opengroup.org/onlinepubs/9699919799/functions/munmap.html
+
+_`.impl.ix.map`: Address space is mapped to main memory by calling
+|mmap|_, passing ``PROT_READ | PROT_WRITE | PROT_EXEC`` and
+``MAP_ANON | MAP_PRIVATE | MAP_FIXED``.
+
+_`.impl.ix.unmap`: Address space is unmapped from main memory by
+calling |mmap|_, passing ``PROT_NONE`` and ``MAP_ANON | MAP_PRIVATE |
+MAP_FIXED``.
+
+
+Windows implementation
+......................
+
+_`.impl.w3`: In ``vmw3.c``.
+
+_`.impl.w3.page.size`: The page size is retrieved by calling
+|GetSystemInfo|_ and consulting ``SYSTEMINFO.dwPageSize``.
+
+.. |GetSystemInfo| replace:: ``GetSystemInfo()``
+.. _GetSystemInfo: http://msdn.microsoft.com/en-gb/library/windows/desktop/ms724381.aspx
+
+_`.impl.w3.param`: Decodes the keyword argument
+``MPS_KEY_VMW3_MEM_TOP_DOWN``, and if it is set, arranges for
+``VMInit()`` to pass the ``MEM_TOP_DOWN`` flag to |VirtualAlloc|_.
+
+_`.impl.w3.reserve`: Address space is reserved by calling
+|VirtualAlloc|_, passing ``MEM_RESERVE`` (and optionally
+``MEM_TOP_DOWN``) and ``PAGE_NOACCESS``.
+
+.. |VirtualAlloc| replace:: ``VirtualAlloc()``
+.. _VirtualAlloc: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887.aspx
+
+_`.impl.w3.release`: Address space is released by calling
+|VirtualFree|_, passing ``MEM_RELEASE``.
+
+.. |VirtualFree| replace:: ``VirtualFree()``
+.. _VirtualFree: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366892.aspx
+
+_`.impl.w3.map`: Address space is mapped to main memory by calling
+|VirtualAlloc|_, passing ``MEM_COMMIT`` and
+``PAGE_EXECUTE_READWRITE``.
+
+_`.impl.w3.unmap`: Address space is unmapped from main memory by
+calling |VirtualFree|_, passing ``MEM_DECOMMIT``.
+
+
+Testing
+-------
+
+_`.testing`: It is important to test that a VM implementation works in
+extreme cases.
_`.testing.large`: It must be able to reserve a large address space.
Clients will want multi-GB spaces, more than that OSs will allow. If
@@ -160,7 +336,7 @@ they ask for too much, ``mps_arena_create()`` (and hence
``VMInit()``) must fail in a predictable way.
_`.testing.larger`: It must be possible to allocate in a large space;
-sometimes commiting will fail, because there's not enough space to
+sometimes committing will fail, because there's not enough space to
replace the "reserve" mapping. See request.epcore.160201_ for details.
.. _request.epcore.160201: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/epcore/160201
@@ -184,6 +360,8 @@ Document History
- 2014-06-16 GDR_ Document the whole interface.
+- 2014-10-22 GDR_ Refactor module description into requirements.
+
.. _RB: http://www.ravenbrook.com/consultants/rb/
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
diff --git a/mps/design/vmo1.txt b/mps/design/vmo1.txt
index c98fdcc4a7f..33c90858439 100644
--- a/mps/design/vmo1.txt
+++ b/mps/design/vmo1.txt
@@ -25,7 +25,9 @@ _`.readership`: Any MPS developer.
_`.intro`: This is the design of the VM Module for Digital UNIX (also
known as OSF/1 and Tru64 Unix; see os.o1). In general aspects
-(including interface) the design is as for design.mps.vm.
+(including interface) the design is as for design.mps.vm_.
+
+.. _design.mps.vm: vm
Functions
diff --git a/mps/design/vmso.txt b/mps/design/vmso.txt
index c51aa4c3cd9..a73a0d65cbd 100644
--- a/mps/design/vmso.txt
+++ b/mps/design/vmso.txt
@@ -23,23 +23,27 @@ Introduction
_`.intro`: This is the design for the VM implementation on Solaris 2.x
(see os.so for OS details). The implementation is in MMsrc!vmso.c
(impl.c.vm). The design follows the design for and implements the
-contract of the generic VM interface (design.mps.vm). To summarize:
+contract of the generic VM interface (design.mps.vm_). To summarize:
The VM module provides a mechanism to reserve large (relative to the
amount of RAM) amounts of address space, and functions to map (back
with RAM) and unmap portions of this address space.
+.. _design.mps.vm: vm
+
_`.source`: Much of the implementation (and hence the design) was
inherited from the SunOS4 implementation. Not that there's any design
for that. You'll find the ``mmap(2)`` (for the system call ``mmap()``)
and the ``zero(7d)`` (for the device ``/dev/zero``) man pages useful
as well. The generic interface and some generic design is in
-design.mps.vm.
+design.mps.vm_.
Definitions
-----------
-_`.def`: See design.mps.vm.def.* for definitions common to all VMs.
+_`.def`: See design.mps.vm.def_ for definitions common to all VMs.
+
+.. _design.mps.vm.def: vm#def
Overview
diff --git a/mps/design/writef.txt b/mps/design/writef.txt
index add8284c32e..2a0277990e0 100644
--- a/mps/design/writef.txt
+++ b/mps/design/writef.txt
@@ -6,7 +6,7 @@ The WriteF function
:Tag: design.mps.writef
:Author: Richard Brooksby
:Date: 1996-10-18
-:Status: incomplete design
+:Status: complete design
:Revision: $Id$
:Copyright: See `Copyright and License`_.
:Index terms: pair: WriteF function; design
@@ -16,23 +16,27 @@ Introduction
------------
_`.intro`: This document describes the ``WriteF()`` function, which
-allows formatted output in a manner similar to ANSI C ``printf``, but
-allows the MPM to operate in a freestanding environment (see
-design.mps.exec-env).
+allows formatted output in a manner similar to ``printf()`` from the
+Standard C library, but allows the Memory Pool Manager (MPM) to
+operate in a freestanding environment (see design.mps.exec-env_).
-_`.background`: The documents design.mps.exec-env and design.mps.lib
+.. _design.mps.exec-env: exec-env
+
+_`.background`: The documents design.mps.exec-env_ and design.mps.lib_
describe the design of the library interface and the reason that it
exists.
+.. _design.mps.lib: lib
+
Design
------
_`.no-printf`: There is no dependency on ``printf()``. The MPM only
-depends on ``fputc()`` and ``fputs()``, via the Library Interface
-(design.mps.lib). This makes it much easier to deploy the MPS in a
-freestanding environment. This is achieved by implementing our own
-internal output routines in mpm.c.
+depends on ``mps_io_fputc()`` and ``mps_io_fputs()``, via the library
+interface (design.mps.lib_), part of the *plinth*. This makes it much
+easier to deploy the MPS in a freestanding environment. This is
+achieved by implementing our own output routines.
_`.writef`: Our output requirements are few, so the code is short. The
only output function which should be used in the rest of the MPM is
@@ -40,9 +44,9 @@ only output function which should be used in the rest of the MPM is
``Res WriteF(mps_lib_FILE *stream, Count depth, ...)``
-If ``depth`` is greater than zero, then the first format character,
-and each format character after a newline, is preceded by ``depth``
-spaces.
+If ``depth`` is greater than zero, then the first output character,
+and each output character after a newline in a format string, is
+preceded by ``depth`` spaces.
``WriteF()`` expects a format string followed by zero or more items to
insert into the output, followed by another format string, more items,
@@ -52,7 +56,8 @@ and so on, and finally a ``NULL`` format string. For example::
"Hello: $A\n", (WriteFA)address,
"Spong: $U ($S)\n", (WriteFU)number, (WriteFS)string,
NULL);
- if (res != ResOK) return res;
+ if (res != ResOK)
+ return res;
This makes ``Describe()`` methods much easier to write. For example, ``BufferDescribe()`` contains the following code::
@@ -81,14 +86,15 @@ This makes ``Describe()`` methods much easier to write. For example, ``BufferDes
" alignment $W\n", (WriteFW)buffer->alignment,
" rampCount $U\n", (WriteFU)buffer->rampCount,
NULL);
- if (res != ResOK) return res;
+ if (res != ResOK)
+ return res;
-_`.types`: For each format ``$X`` that ``WriteF()`` supports, there is a
-type defined in impl.h.mpmtypes ``WriteFX()`` which is the promoted
-version of that type. These are provided both to ensure promotion and
-to avoid any confusion about what type should be used in a cast. It is
-easy to check the casts against the formats to ensure that they
-correspond.
+_`.types`: For each format ``$X`` that ``WriteF()`` supports, there is
+a type ``WriteFX`` defined in mpmtypes.h, which is the promoted
+version of that type. These types are provided both to ensure
+promotion and to avoid any confusion about what type should be used in
+a cast. It is easy to check the casts against the formats to ensure
+that they correspond.
_`.types.cast`: Every argument to ``WriteF()`` must be cast, because
in variable-length argument lists the "default argument promotion"
@@ -105,19 +111,19 @@ used in future in some generalisation of varargs in the MPS.
_`.formats`: The formats supported are as follows.
-======= =========== ================== ======================================
+======= =========== ================== =======================================
Code Name Type Example rendering
-======= =========== ================== ======================================
+======= =========== ================== =======================================
``$A`` address ``Addr`` ``000000019EF60010``
``$P`` pointer ``void *`` ``000000019EF60100``
-``$F`` function ``void *(*)()`` ``0001D69E01000000`` (see `.f`_)
+``$F`` function ``void *(*)()`` ``0001D69E01000000`` (see `.function`_)
``$S`` string ``char *`` ``hello``
``$C`` character ``char`` ``x``
``$W`` word ``ULongest`` ``0000000000109AE0``
``$U`` decimal ``ULongest`` ``42``
``$B`` binary ``ULongest`` ``00000000000000001011011110010001``
``$$`` dollar -- ``$``
-======= =========== ================== ======================================
+======= =========== ================== =======================================
Note that ``WriteFC`` is an ``int``, because that is the default
promotion of a ``char`` (see `.types`_).
@@ -127,10 +133,11 @@ incredible snazzy output engine. We only need it for ``Describe()``
methods. At the moment it's a simple bit of code -- let's keep it that
way.
-_`.f`: The ``F`` code is used for function pointers. ISO C forbids casting
-function pointers to other types, so the bytes of their representation are
-written sequentially, and may have a different endianness to other pointers.
-Could be smarter, or even look up function names, but see `.snazzy`_.
+_`.function`: The ``F`` code is used for function pointers. ISO C
+forbids casting function pointers to other types, so the bytes of
+their representation are written sequentially, and may have a
+different endianness to other pointers. Could be smarter, or even look
+up function names, but see `.snazzy`_.
Document History
@@ -151,7 +158,7 @@ Document History
Copyright and License
---------------------
-Copyright © 2013-2014 Ravenbrook Limited. All rights reserved.
+Copyright © 2013-2015 Ravenbrook Limited. All rights reserved.
. This is an open source license. Contact
Ravenbrook for commercial licensing options.
diff --git a/mps/example/scheme/scheme-advanced.c b/mps/example/scheme/scheme-advanced.c
index f73bf06512a..5089366f0af 100644
--- a/mps/example/scheme/scheme-advanced.c
+++ b/mps/example/scheme/scheme-advanced.c
@@ -887,7 +887,7 @@ static int table_rehash(obj_t tbl, size_t new_length, obj_t key, size_t *key_buc
* moved by the garbage collector: in this case we need to re-hash the
* table. See topic/location.
*/
-static int table_find(obj_t tbl, buckets_t buckets, obj_t key, int add, size_t *b)
+static int table_find(obj_t tbl, obj_t key, int add, size_t *b)
{
if (!buckets_find(tbl, tbl->table.keys, key, add, b)) {
return 0;
@@ -904,7 +904,7 @@ static obj_t table_ref(obj_t tbl, obj_t key)
{
size_t b;
assert(TYPE(tbl) == TYPE_TABLE);
- if (table_find(tbl, tbl->table.keys, key, 0, &b)) {
+ if (table_find(tbl, key, 0, &b)) {
obj_t k = tbl->table.keys->bucket[b];
if (k != obj_unused && k != obj_deleted)
return tbl->table.values->bucket[b];
@@ -916,7 +916,7 @@ static int table_try_set(obj_t tbl, obj_t key, obj_t value)
{
size_t b;
assert(TYPE(tbl) == TYPE_TABLE);
- if (!table_find(tbl, tbl->table.keys, key, 1, &b))
+ if (!table_find(tbl, key, 1, &b))
return 0;
if (tbl->table.keys->bucket[b] == obj_unused) {
tbl->table.keys->bucket[b] = key;
@@ -952,7 +952,7 @@ static void table_delete(obj_t tbl, obj_t key)
{
size_t b;
assert(TYPE(tbl) == TYPE_TABLE);
- if(table_find(tbl, tbl->table.keys, key, 0, &b)
+ if(table_find(tbl, key, 0, &b)
&& tbl->table.keys->bucket[b] != obj_unused
&& tbl->table.keys->bucket[b] != obj_deleted)
{
diff --git a/mps/example/scheme/scheme.c b/mps/example/scheme/scheme.c
index 794fdfa77d4..1e7b7084759 100644
--- a/mps/example/scheme/scheme.c
+++ b/mps/example/scheme/scheme.c
@@ -946,7 +946,7 @@ static struct bucket_s *table_rehash(obj_t tbl, size_t new_length, obj_t key)
* moved by the garbage collector: in this case we need to re-hash the
* table. See topic/location.
*/
-static struct bucket_s *table_find(obj_t tbl, obj_t buckets, obj_t key, int add)
+static struct bucket_s *table_find(obj_t tbl, obj_t key, int add)
{
struct bucket_s *b;
assert(TYPE(tbl) == TYPE_TABLE);
@@ -963,7 +963,7 @@ static obj_t table_ref(obj_t tbl, obj_t key)
{
struct bucket_s *b;
assert(TYPE(tbl) == TYPE_TABLE);
- b = table_find(tbl, tbl->table.buckets, key, 0);
+ b = table_find(tbl, key, 0);
if (b && b->key != NULL && b->key != obj_deleted)
return b->value;
return NULL;
@@ -973,7 +973,7 @@ static int table_try_set(obj_t tbl, obj_t key, obj_t value)
{
struct bucket_s *b;
assert(TYPE(tbl) == TYPE_TABLE);
- b = table_find(tbl, tbl->table.buckets, key, 1);
+ b = table_find(tbl, key, 1);
if (b == NULL)
return 0;
if (b->key == NULL) {
@@ -1009,7 +1009,7 @@ static void table_delete(obj_t tbl, obj_t key)
{
struct bucket_s *b;
assert(TYPE(tbl) == TYPE_TABLE);
- b = table_find(tbl, tbl->table.buckets, key, 0);
+ b = table_find(tbl, key, 0);
if (b && b->key != NULL && b->key != obj_deleted) {
b->key = obj_deleted;
++ tbl->table.buckets->buckets.deleted;
diff --git a/mps/manual/build.txt b/mps/manual/build.txt
index 5403d7ffc44..7b8e17c51b9 100644
--- a/mps/manual/build.txt
+++ b/mps/manual/build.txt
@@ -96,8 +96,7 @@ Building the MPS for development
If you're making modifications to the MPS itself, want to build MPS
libraries for linking, or want to build MPS tests and tools, you should
-use the MPS build. This uses makefiles or Xcode projects. [Coming
-soon, Microsoft Visual Studio solutions.]
+use the MPS build. This uses makefiles or Xcode projects.
Prerequisites
diff --git a/mps/manual/source/_templates/links.html b/mps/manual/source/_templates/links.html
index b62c13d7813..b7263205f3e 100644
--- a/mps/manual/source/_templates/links.html
+++ b/mps/manual/source/_templates/links.html
@@ -1,13 +1,11 @@
Downloads
-MPS Kit release {{ release }}
All MPS Kit releases
Issues
-Known issues
-Issues fixed in release {{ release }}
+All open issues
diff --git a/mps/manual/source/contributing.rst b/mps/manual/source/contributing.rst
new file mode 100644
index 00000000000..9c004b268ee
--- /dev/null
+++ b/mps/manual/source/contributing.rst
@@ -0,0 +1,8 @@
+.. index::
+ single: building
+ single: compiling
+ single: installing
+
+.. _contributing:
+
+.. include:: ../../contributing.rst
diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst
index 8ac8bb9e9c2..b8da67a4333 100644
--- a/mps/manual/source/design/index.rst
+++ b/mps/manual/source/design/index.rst
@@ -7,19 +7,33 @@ Design
:numbered:
abq
+ an
+ bootstrap
cbs
config
critical-path
+ exec-env
failover
freelist
guide.hex.trans
guide.impl.c.format
+ guide.impl.c.naming
+ guide.review
interface-c
keyword-arguments
land
+ lock
nailboard
+ prmc
+ prot
range
ring
+ sp
sig
splay
+ ss
+ testthr
+ thread-manager
type
+ vm
+ writef
diff --git a/mps/manual/source/design/old.rst b/mps/manual/source/design/old.rst
index 2aefac2a40c..8a8e71be1a6 100644
--- a/mps/manual/source/design/old.rst
+++ b/mps/manual/source/design/old.rst
@@ -27,7 +27,6 @@ Old design
fix
io
lib
- lock
locus
message
message-gc
@@ -42,8 +41,6 @@ Old design
poolmv
poolmvt
poolmvff
- prot
- protan
protli
protsu
protocol
@@ -57,13 +54,9 @@ Old design
strategy
telemetry
tests
- thread-manager
thread-safety
trace
version-library
version
- vm
- vman
vmo1
vmso
- writef
diff --git a/mps/manual/source/extensions/mps/designs.py b/mps/manual/source/extensions/mps/designs.py
index 3bf60a006b7..42acd049d62 100644
--- a/mps/manual/source/extensions/mps/designs.py
+++ b/mps/manual/source/extensions/mps/designs.py
@@ -42,6 +42,8 @@ typedef = re.compile(r'^``typedef ([^`]*)``$', re.MULTILINE)
func = re.compile(r'``([A-Za-z][A-Za-z0-9_]+\(\))``')
typename = re.compile(r'``({0}|[A-Z][A-Za-z0-9_]*(?:Class|Struct|Method)|mps_[a-z_]+_[stu])``(?: )?'
.format('|'.join(map(re.escape, TYPES.split()))))
+design_ref = re.compile(r'^( *\.\. _design\.mps\.(?:[^:\n]+): (?:[^#:\n]+))$', re.MULTILINE)
+design_frag_ref = re.compile(r'^( *\.\. _design\.mps\.([^:\n]+)\.([^:\n]+): (?:[^#:\n]+))#\3$', re.MULTILINE)
history = re.compile(r'^Document History\n.*',
re.MULTILINE | re.IGNORECASE | re.DOTALL)
@@ -116,6 +118,8 @@ def convert_file(name, source, dest):
s = macro.sub(r':c:macro:`\1`', s)
s = secnum.sub(secnum_sub, s)
s = citation.sub(citation_sub, s)
+ s = design_ref.sub(r'\1.html', s)
+ s = design_frag_ref.sub(r'\1.html#design.mps.\2.\3', s)
s = history.sub('', s)
try:
os.makedirs(os.path.dirname(dest))
diff --git a/mps/manual/source/glossary/b.rst b/mps/manual/source/glossary/b.rst
index 8356404267c..12d4838e466 100644
--- a/mps/manual/source/glossary/b.rst
+++ b/mps/manual/source/glossary/b.rst
@@ -182,9 +182,22 @@ Memory Management Glossary: B
.. relevance::
Bitmaps are sometimes used to represent the marks in a
- :term:`mark-sweep` collector, or the used memory in a
- :term:`bitmapped fits` :term:`allocator`.
+ :term:`mark-sweep` collector (see :term:`bitmap marking`),
+ or the used memory in a :term:`bitmapped fits`
+ :term:`allocator`.
+ bitmap marking
+
+ In :term:`mark-sweep` collectors, bitmap marking is a
+ technique for :term:`marking` objects that stores the mark
+ bits for the objects in a contiguous range of memory in a
+ separate :term:`bitmap`. This improves the collector's
+ :term:`locality of reference` and cache performance, because
+ it avoids setting the :term:`dirty bit` on the :term:`pages`
+ containing the marked objects.
+
+ .. bibref:: :ref:`Zorn (1989) `.
+
bitmapped fit
A class of :term:`allocation mechanisms` that use a
diff --git a/mps/manual/source/glossary/f.rst b/mps/manual/source/glossary/f.rst
index eedbd00a9da..a6d648abe4a 100644
--- a/mps/manual/source/glossary/f.rst
+++ b/mps/manual/source/glossary/f.rst
@@ -414,10 +414,34 @@ Memory Management Glossary: F
.. seealso:: :term:`free block`, :term:`free block chain`.
+
+ freestanding
+
+ In the :term:`C` programming language as defined by
+ :term:`C90`, a freestanding implementation "accepts any
+ strictly conforming program in which the use of the features
+ specified in the library section is confined to the contents
+ of the standard headers ````, ````,
+ ````, and ````." The :term:`C99` standard
+ adds ````, ````, and ```` to
+ this list.
+
+ In particular, a freestanding implementation need not provide
+ the other features of the standard C library, including I/O,
+ time, and string operations.
+
+ .. opposite:: :term:`hosted`.
+
+ .. mps:specific::
+
+ The MPS is designed to be portable to a freestanding
+ implementation, by restricting the use of other features
+ either to :term:`platform`\-specific modules or to the
+ replaceable :term:`plinth` modules.
+
+ .. bibref:: :ref:`ISO/IEC 9899:1990 `, :ref:`ISO/IEC 9899:1999 `.
+
free store
-
- .. see:: :term:`heap`.
-
freestore
.. see:: :term:`heap`.
diff --git a/mps/manual/source/glossary/h.rst b/mps/manual/source/glossary/h.rst
index 43f4c99891e..8d292f98379 100644
--- a/mps/manual/source/glossary/h.rst
+++ b/mps/manual/source/glossary/h.rst
@@ -98,6 +98,16 @@ Memory Management Glossary: H
.. opposite:: :term:`miss rate`.
+ hosted
+
+ In the :term:`C` programming language, a hosted implementation
+ is one that provides all the features of the standard C
+ library.
+
+ .. opposite:: :term:`freestanding`.
+
+ .. bibref:: :ref:`ISO/IEC 9899:1990 `, :ref:`ISO/IEC 9899:1999 `.
+
hot
.. mps:specific::
diff --git a/mps/manual/source/glossary/index.rst b/mps/manual/source/glossary/index.rst
index a0484b3c5ee..6c15cbd4e84 100644
--- a/mps/manual/source/glossary/index.rst
+++ b/mps/manual/source/glossary/index.rst
@@ -84,6 +84,7 @@ All
:term:`bit table `
:term:`bit vector `
:term:`bitmap`
+:term:`bitmap marking`
:term:`bitmapped fit`
:term:`bitmask`
:term:`bitset `
diff --git a/mps/manual/source/glossary/m.rst b/mps/manual/source/glossary/m.rst
index db4d8b88a59..92abdcf2740 100644
--- a/mps/manual/source/glossary/m.rst
+++ b/mps/manual/source/glossary/m.rst
@@ -207,7 +207,11 @@ Memory Management Glossary: M
though any conservative representation of a predicate on the
:term:`memory location` of the object can be used. In
particular, storing the mark bit within the object can lead to
- poor :term:`locality of reference`.
+ poor :term:`locality of reference` and to poor cache
+ performance, because the marking phases ends up setting the
+ :term:`dirty bit` on all :term:`pages` in the :term:`working
+ set`. An alternative is to store the mark bits separately:
+ see :term:`bitmap marking`.
.. seealso:: :term:`sweep `, :term:`compact `.
diff --git a/mps/manual/source/glossary/r.rst b/mps/manual/source/glossary/r.rst
index 9f4449a930e..cbab9a255fe 100644
--- a/mps/manual/source/glossary/r.rst
+++ b/mps/manual/source/glossary/r.rst
@@ -39,7 +39,7 @@ Memory Management Glossary: R
.. mps:specific::
A value of :c:type:`mps_rank_t` indicating whether a
- :term:`root` is :term:`ambiguous `
+ :term:`reference` is :term:`ambiguous `
(:c:func:`mps_rank_ambig`), :term:`exact `
(:c:func:`mps_rank_exact`) or :term:`weak `
(:c:func:`mps_rank_weak`).
diff --git a/mps/manual/source/guide/advanced.rst b/mps/manual/source/guide/advanced.rst
index c40db2d0774..b56edf14fa4 100644
--- a/mps/manual/source/guide/advanced.rst
+++ b/mps/manual/source/guide/advanced.rst
@@ -347,7 +347,7 @@ In the toy Scheme interpreter this behaviour is encapsulated into ``table_find``
.. code-block:: c
:emphasize-lines: 7
- static struct bucket_s *table_find(obj_t tbl, obj_t buckets, obj_t key, int add)
+ static struct bucket_s *table_find(obj_t tbl, obj_t key, int add)
{
struct bucket_s *b;
assert(TYPE(tbl) == TYPE_TABLE);
diff --git a/mps/manual/source/guide/index.rst b/mps/manual/source/guide/index.rst
index a7218dd2ba5..fd98e0481e5 100644
--- a/mps/manual/source/guide/index.rst
+++ b/mps/manual/source/guide/index.rst
@@ -13,4 +13,4 @@ Guide
debug
perf
advanced
-
+ malloc
diff --git a/mps/manual/source/guide/lang.rst b/mps/manual/source/guide/lang.rst
index 68473613ba2..88c7ec93eb5 100644
--- a/mps/manual/source/guide/lang.rst
+++ b/mps/manual/source/guide/lang.rst
@@ -266,6 +266,25 @@ code for creating the object format for the toy Scheme interpreter::
} MPS_ARGS_END(args);
if (res != MPS_RES_OK) error("Couldn't create obj format");
+The keyword arguments specify the :term:`alignment` and the
+:term:`format methods` required by the AMC pool class. These are
+described in the following sections.
+
+.. topics::
+
+ :ref:`topic-format`.
+
+
+.. index::
+ single: alignment
+ single: alignment; object
+ single: Scheme; object alignment
+
+.. _guide-lang-alignment:
+
+Alignment
+^^^^^^^^^
+
The argument for the keyword :c:macro:`MPS_KEY_FMT_ALIGN` is the
:term:`alignment` of objects belonging to this format. Determining the
alignment is hard to do portably, because it depends on the target
@@ -294,13 +313,19 @@ memory. Here are some things you might try:
#define ALIGNMENT sizeof(mps_word_t)
-The other keyword arguments specify the :term:`format methods`
-required by the AMC pool class, which are described in the following
-sections.
+#. The MPS interface provides the type :c:type:`MPS_PF_ALIGN`, which
+ is the :term:`natural alignment` of the platform: the largest
+ alignment that might be required. So as a last resort, you can
+ use::
-.. topics::
+ #define ALIGNMENT MPS_PF_ALIGN
- :ref:`topic-format`.
+ But this may be larger than necessary and so waste space. For
+ example, on Windows on x86-64, :c:type:`MPS_PF_ALIGN` is 16 bytes,
+ but this is only necessary for SSE_ types; ordinary types on this
+ platform require no more than 8-byte alignment.
+
+ .. _SSE: http://msdn.microsoft.com/en-us/library/t467de55.aspx
.. index::
diff --git a/mps/manual/source/guide/malloc.rst b/mps/manual/source/guide/malloc.rst
new file mode 100644
index 00000000000..843fc2371ed
--- /dev/null
+++ b/mps/manual/source/guide/malloc.rst
@@ -0,0 +1,70 @@
+.. index::
+ single: malloc; implementing
+ single: free; implementing
+
+.. _guide-malloc:
+
+Implementing malloc and free
+============================
+
+The MPS function :c:func:`mps_free` is unlike the Standard C Library
+function :c:func:`free` in that it takes a ``size`` argument. That's
+because it's nearly always the case that either the size of a block is
+known statically based on its type (for example, a structure), or else
+the size of the block is easily computed from information that needs
+to be stored anyway (for example, a vector), and so memory can be
+saved by not storing the size separately. It's also better for virtual
+memory performance, as a block does not have to be touched in order
+to free it.
+
+But sometimes you need to interact with :term:`foreign code` which
+requires :c:func:`malloc` and :c:func:`free` (or a pair of functions
+with the same interface). In this situation you can implement this
+interface using a global pool variable, and putting the size of each
+block into its header, like this::
+
+ #include "mps.h"
+
+ static mps_pool_t malloc_pool;
+
+ typedef union {
+ size_t size;
+ char alignment[MPS_PF_ALIGN]; /* see note below */
+ } header_u;
+
+ void *malloc(size_t size) {
+ mps_res_t res;
+ mps_addr_t p;
+ header_u *header;
+ size += sizeof *header;
+ res = mps_alloc(&p, malloc_pool, size);
+ if (res != MPS_RES_OK)
+ return NULL;
+ header = p;
+ header->size = size;
+ return header + 1;
+ }
+
+ void free(void *p) {
+ if (p) {
+ header_u *header = ((header_u *)p) - 1;
+ mps_free(malloc_pool, header, header->size);
+ }
+ }
+
+The ``alignment`` member of ``union header_u`` ensures that
+allocations are aligned to the platform's :term:`natural alignment`
+(see :ref:`guide-lang-alignment`).
+
+The pool needs to belong to a :term:`manually managed ` pool class, for example :ref:`pool-mvff` (or its
+:ref:`debugging counterpart `)::
+
+ #include "mpscmvff.h"
+
+ void malloc_pool_init(mps_arena_t arena) {
+ mps_res_t res;
+ res = mps_pool_create_k(&malloc_pool, arena, mps_class_mvff(), mps_args_none);
+ if (res != RES_OK)
+ abort();
+ }
diff --git a/mps/manual/source/guide/overview.rst b/mps/manual/source/guide/overview.rst
index 6082bd4a279..3156469f27e 100644
--- a/mps/manual/source/guide/overview.rst
+++ b/mps/manual/source/guide/overview.rst
@@ -37,7 +37,7 @@ Ravenbrook by arrangement. Please :ref:`contact us ` at
`mps-questions@ravenbrook.com `_
for details.
-.. comment:: Keep this section synchronized with readme.txt
+.. comment: Keep this section synchronized with readme.txt
.. index::
single: Memory Pool System; supported target platforms
diff --git a/mps/manual/source/index.rst b/mps/manual/source/index.rst
index 4edc69bbf60..57758fea8ef 100644
--- a/mps/manual/source/index.rst
+++ b/mps/manual/source/index.rst
@@ -21,6 +21,7 @@ Appendices
glossary/index
copyright
contact
+ contributing
release
* :ref:`genindex`
diff --git a/mps/manual/source/mmref/lang.rst b/mps/manual/source/mmref/lang.rst
index 247eb7c6c25..d00ffa49c37 100644
--- a/mps/manual/source/mmref/lang.rst
+++ b/mps/manual/source/mmref/lang.rst
@@ -440,6 +440,11 @@ Memory management in various languages
Lisp Machines are used in today's implementations, at a cost
of a few more cycles.
+ .. link::
+
+ `Lisp Machine Manual, 6th edition `_,
+ `The Garbage Collector `_.
+
Lua
Lua is a dynamically typed language created by Roberto
diff --git a/mps/manual/source/pool/amc.rst b/mps/manual/source/pool/amc.rst
index edd1dbd3e07..a21594202c6 100644
--- a/mps/manual/source/pool/amc.rst
+++ b/mps/manual/source/pool/amc.rst
@@ -115,7 +115,7 @@ AMC interface
method`, a :term:`forward method`, an :term:`is-forwarded
method` and a :term:`padding method`.
- It accepts four optional keyword arguments:
+ It accepts three optional keyword arguments:
* :c:macro:`MPS_KEY_CHAIN` (type :c:type:`mps_chain_t`) specifies
the :term:`generation chain` for the pool. If not specified, the
@@ -128,8 +128,10 @@ AMC interface
pointers` keep objects alive.
* :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`,
- default 4096) is the default :term:`size` of segment that the pool will
- request from the :term:`arena`.
+ default 4096) is the minimum :term:`size` of the memory segments
+ that the pool requests from the :term:`arena`. Larger segments
+ reduce the per-segment overhead, but increase
+ :term:`fragmentation` and :term:`retention`.
For example::
@@ -138,20 +140,12 @@ AMC interface
res = mps_pool_create_k(&pool, arena, mps_class_amc(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the format and
- chain like this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_amc(),
- mps_fmt_t fmt,
- mps_chain_t chain)
-
.. index::
pair: AMC; introspection
+.. _pool-amc-introspection:
+
AMC introspection
-----------------
diff --git a/mps/manual/source/pool/amcz.rst b/mps/manual/source/pool/amcz.rst
index 9993647d0db..4f65d205d1b 100644
--- a/mps/manual/source/pool/amcz.rst
+++ b/mps/manual/source/pool/amcz.rst
@@ -87,12 +87,11 @@ AMCZ interface
res = mps_pool_create_k(&pool, arena, mps_class_amcz(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
+
+.. index::
+ pair: AMCZ; introspection
- When using :c:func:`mps_pool_create`, pass the format and
- chain like this::
+AMCZ introspection
+------------------
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_amcz(),
- mps_fmt_t fmt,
- mps_chain_t chain)
+See :ref:`pool-amc-introspection`.
diff --git a/mps/manual/source/pool/ams.rst b/mps/manual/source/pool/ams.rst
index 98da5eda587..4d66fdc0fc3 100644
--- a/mps/manual/source/pool/ams.rst
+++ b/mps/manual/source/pool/ams.rst
@@ -41,7 +41,8 @@ AMS properties
* Supports allocation via :term:`allocation points`. If an allocation
point is created in an AMS pool, the call to
- :c:func:`mps_ap_create_k` takes no keyword arguments.
+ :c:func:`mps_ap_create_k` takes one optional keyword argument,
+ :c:macro:`MPS_KEY_RANK`.
* Supports :term:`allocation frames` but does not use them to improve
the efficiency of stack-like allocation.
@@ -137,19 +138,8 @@ AMS interface
res = mps_pool_create_k(&pool, arena, mps_class_ams(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the format,
- chain, and ambiguous flag like this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_ams(),
- mps_fmt_t fmt,
- mps_chain_t chain,
- mps_bool_t support_ambiguous)
-
When creating an :term:`allocation point` on an AMS pool,
- :c:func:`mps_ap_create_k` accepts one keyword argument:
+ :c:func:`mps_ap_create_k` accepts one optional keyword argument:
* :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default
:c:func:`mps_rank_exact`) specifies the :term:`rank` of references
@@ -166,13 +156,6 @@ AMS interface
res = mps_ap_create_k(&ap, ams_pool, args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_ap_create`, pass the rank like this::
-
- mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool,
- mps_rank_t rank)
-
.. c:function:: mps_pool_class_t mps_class_ams_debug(void)
@@ -186,15 +169,3 @@ AMS interface
:c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` are as described above,
and :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging
options. See :c:type:`mps_pool_debug_option_s`.
-
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the arguments like
- this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_ams_debug(),
- mps_pool_debug_option_s debug_option,
- mps_fmt_t fmt,
- mps_chain_t chain,
- mps_bool_t support_ambiguous)
diff --git a/mps/manual/source/pool/awl.rst b/mps/manual/source/pool/awl.rst
index e4437ebe5ee..63eca08635e 100644
--- a/mps/manual/source/pool/awl.rst
+++ b/mps/manual/source/pool/awl.rst
@@ -59,7 +59,7 @@ AWL properties
* Supports allocation via :term:`allocation points`. If an allocation
point is created in an AWL pool, the call to
- :c:func:`mps_ap_create_k` accepts one keyword argument,
+ :c:func:`mps_ap_create_k` accepts one optional keyword argument,
:c:macro:`MPS_KEY_RANK`.
* Supports :term:`allocation frames` but does not use them to improve
@@ -350,18 +350,8 @@ AWL interface
res = mps_pool_create_k(&pool, arena, mps_class_awl(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the format and
- find-dependent function like this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_awl(),
- mps_fmt_t fmt,
- mps_awl_find_dependent_t find_dependent)
-
When creating an :term:`allocation point` on an AWL pool,
- :c:func:`mps_ap_create_k` accepts one keyword argument:
+ :c:func:`mps_ap_create_k` accepts one optional keyword argument:
* :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default
:c:func:`mps_rank_exact`) specifies the :term:`rank` of
@@ -378,13 +368,6 @@ AWL interface
res = mps_ap_create_k(&ap, awl_pool, args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_ap_create`, pass the rank like this::
-
- mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool,
- mps_rank_t rank)
-
.. c:type:: mps_addr_t (*mps_awl_find_dependent_t)(mps_addr_t addr)
diff --git a/mps/manual/source/pool/lo.rst b/mps/manual/source/pool/lo.rst
index edd784c1fe5..197e8b57138 100644
--- a/mps/manual/source/pool/lo.rst
+++ b/mps/manual/source/pool/lo.rst
@@ -136,12 +136,3 @@ LO interface
MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt);
res = mps_pool_create_k(&pool, arena, mps_class_lo(), args);
} MPS_ARGS_END(args);
-
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the format like
- this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_lo(),
- mps_fmt_t fmt)
diff --git a/mps/manual/source/pool/mfs.rst b/mps/manual/source/pool/mfs.rst
index e130e3fcda4..c1e13a5479d 100644
--- a/mps/manual/source/pool/mfs.rst
+++ b/mps/manual/source/pool/mfs.rst
@@ -87,14 +87,15 @@ MFS interface
:term:`size` of blocks that will be allocated from this pool, in
:term:`bytes (1)`. It must be at least one :term:`word`.
- In addition, :c:func:`mps_pool_create_k` may take:
+ In addition, :c:func:`mps_pool_create_k` accepts one optional
+ keyword argument:
- * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default 65536) is the
- :term:`size` of segment that the pool will request from the
- :term:`arena`. It must be at least as big as the unit size
- specified by the :c:macro:`MPS_KEY_MFS_UNIT_SIZE` keyword
- argument. If this is not a multiple of the unit size, there will
- be wasted space in each segment.
+ * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`,
+ default 65536) is the :term:`size` of block that the pool will
+ request from the :term:`arena`. It must be at least as big as
+ the unit size specified by the :c:macro:`MPS_KEY_MFS_UNIT_SIZE`
+ keyword argument. If this is not a multiple of the unit size,
+ there will be wasted space in each block.
For example::
@@ -103,13 +104,3 @@ MFS interface
MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, 1024 * 1024);
res = mps_pool_create_k(&pool, arena, mps_class_mfs(), args);
} MPS_ARGS_END(args);
-
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the segment size and
- unit size like this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_mfs(),
- size_t extend_size,
- size_t unit_size)
diff --git a/mps/manual/source/pool/mv.rst b/mps/manual/source/pool/mv.rst
index 1e098ff5a63..27e691ed3af 100644
--- a/mps/manual/source/pool/mv.rst
+++ b/mps/manual/source/pool/mv.rst
@@ -7,10 +7,6 @@
MV (Manual Variable)
====================
-.. deprecated:: starting with version 1.111.
-
- :ref:`pool-mvff` or :ref:`pool-mvt` should be used instead.
-
**MV** is a general-purpose :term:`manually managed ` :term:`pool class` that manages :term:`blocks` of
variable size.
@@ -70,8 +66,8 @@ MV interface
Return the :term:`pool class` for an MV (Manual Variable)
:term:`pool`.
- When creating an MV pool, :c:func:`mps_pool_create_k` may take
- the following :term:`keyword arguments`:
+ When creating an MV pool, :c:func:`mps_pool_create_k` takes four
+ optional :term:`keyword arguments`:
* :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is
:c:macro:`MPS_PF_ALIGN`) is the
@@ -80,7 +76,7 @@ MV interface
:c:func:`mps_free`, it will be rounded up to the pool's alignment.
* :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`,
- default 65536) is the :term:`size` of segment that the pool will
+ default 65536) is the :term:`size` of block that the pool will
request from the :term:`arena`.
* :c:macro:`MPS_KEY_MEAN_SIZE` (type :c:type:`size_t`, default 32)
@@ -105,17 +101,6 @@ MV interface
res = mps_pool_create_k(&pool, arena, mps_class_mfs(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the segment size,
- mean size, and maximum size like this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_mv(),
- size_t extend_size,
- size_t average_size,
- mps_size_t maximum_size)
-
.. c:function:: mps_pool_class_t mps_class_mv_debug(void)
@@ -123,49 +108,8 @@ MV interface
class.
When creating a debugging MV pool, :c:func:`mps_pool_create_k`
- takes the following keyword arguments: :c:macro:`MPS_KEY_ALIGN`,
+ takes five optional keyword arguments: :c:macro:`MPS_KEY_ALIGN`,
:c:macro:`MPS_KEY_EXTEND_SIZE`, :c:macro:`MPS_KEY_MEAN_SIZE`,
:c:macro:`MPS_KEY_MAX_SIZE` are as described above, and
:c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging
- options. See :c:type:`mps_debug_option_s`.
-
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the arguments like
- this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_mv_debug(),
- mps_pool_debug_option_s debug_option,
- mps_size_t extend_size,
- mps_size_t average_size,
- mps_size_t maximum_size)
-
-
-.. index::
- pair: MV; introspection
-
-MV introspection
-----------------
-
-::
-
- #include "mpscmv.h"
-
-.. c:function:: size_t mps_mv_free_size(mps_pool_t pool)
-
- Return the total amount of free space in an MV pool.
-
- ``pool`` is the MV pool.
-
- Returns the total free space in the pool, in :term:`bytes (1)`.
-
-
-.. c:function:: size_t mps_mv_size(mps_pool_t pool)
-
- Return the total size of an MV pool.
-
- ``pool`` is the MV pool.
-
- Returns the total size of the pool, in :term:`bytes (1)`. This
- is the sum of allocated space and free space.
+ options. See :c:type:`mps_pool_debug_option_s`.
diff --git a/mps/manual/source/pool/mvff.rst b/mps/manual/source/pool/mvff.rst
index 5dce87d5f3c..04a7d48603d 100644
--- a/mps/manual/source/pool/mvff.rst
+++ b/mps/manual/source/pool/mvff.rst
@@ -42,16 +42,6 @@ on the same pool, because the worst-fit policy of buffer filling will
grab all the large blocks, leading to severe fragmentation. If you
need both forms of allocation, use two separate pools.
-Note that buffered allocation can't allocate across segment boundaries
-(see :ref:`topic-allocation-point-implementation` for the technical
-reason). This can cause added external fragmentation if objects are
-allocated that are a significant fraction of the segment size.
-
-.. note::
-
- If you need to allocate large objects in an MVFF pool,
- :ref:`contact us `.
-
.. index::
single: MVFF; properties
@@ -112,11 +102,11 @@ MVFF interface
Return the :term:`pool class` for an MVFF (Manual Variable First
Fit) :term:`pool`.
- When creating an MVFF pool, :c:func:`mps_pool_create_k` may take
- the following :term:`keyword arguments`:
+ When creating an MVFF pool, :c:func:`mps_pool_create_k` accepts
+ seven optional :term:`keyword arguments`:
* :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default
- 65536) is the :term:`size` of segment that the pool will request
+ 65536) is the :term:`size` of block that the pool will request
from the :term:`arena`.
* :c:macro:`MPS_KEY_MEAN_SIZE` (type :c:type:`size_t`, default 32)
@@ -139,18 +129,18 @@ MVFF interface
arena for use by other pools.
* :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` (type :c:type:`mps_bool_t`,
- default false) determines whether new segments are acquired at high
+ default false) determines whether new blocks are acquired at high
addresses (if true), or at low addresses (if false).
- * :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` [#not-ap]_ (type :c:type:`mps_bool_t`,
- default false) determines whether to search for the highest
- addressed free area (if true) or lowest (if false) when allocating
- using :c:func:`mps_alloc`.
+ * :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` [#not-ap]_ (type
+ :c:type:`mps_bool_t`, default false) determines whether to
+ search for the highest addressed free area (if true) or lowest
+ (if false) when allocating using :c:func:`mps_alloc`.
- * :c:macro:`MPS_KEY_MVFF_FIRST_FIT` [#not-ap]_ (type :c:type:`mps_bool_t`, default
- true) determines whether to allocate from the highest address in a
- found free area (if true) or lowest (if false) when allocating
- using :c:func:`mps_alloc`.
+ * :c:macro:`MPS_KEY_MVFF_FIRST_FIT` [#not-ap]_ (type
+ :c:type:`mps_bool_t`, default true) determines whether to
+ allocate from the highest address in a found free area (if true)
+ or lowest (if false) when allocating using :c:func:`mps_alloc`.
.. [#not-ap]
@@ -160,12 +150,12 @@ MVFF interface
They use a worst-fit policy in order to maximise the number of
in-line allocations.
- The defaults yield a a simple first-fit allocator. Specify
+ The defaults yield a a simple first-fit allocator. Specify
:c:macro:`MPS_KEY_MVFF_ARENA_HIGH` and
:c:macro:`MPS_KEY_MVFF_SLOT_HIGH` true, and
:c:macro:`MPS_KEY_MVFF_FIRST_FIT` false to get a first-fit
- allocator that works from the top of memory downwards.
- Other combinations may be useful in special circumstances.
+ allocator that works from the top of memory downwards. Other
+ combinations may be useful in special circumstances.
For example::
@@ -179,20 +169,6 @@ MVFF interface
res = mps_pool_create_k(&pool, arena, mps_class_mvff(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the arguments like
- this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_mvff(),
- size_t extend_size,
- size_t average_size,
- mps_align_t alignment,
- mps_bool_t slot_high,
- mps_bool_t arena_high,
- mps_bool_t first_fit)
-
.. c:function:: mps_pool_class_t mps_class_mvff_debug(void)
@@ -200,55 +176,11 @@ MVFF interface
class.
When creating a debugging MVFF pool, :c:func:`mps_pool_create_k`
- takes seven :term:`keyword arguments`.
-
- * :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE`,
- :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_MVFF_ARENA_HIGH`,
- :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, and
- :c:macro:`MPS_KEY_MVFF_FIRST_FIT` are as described above, and
- :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging
- options. See :c:type:`mps_pool_debug_option_s`.
-
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the arguments like
- this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_mvff_debug(),
- mps_pool_debug_option_s debug_option,
- size_t extend_size,
- size_t average_size,
- mps_align_t alignment,
- mps_bool_t slot_high,
- mps_bool_t arena_high,
- mps_bool_t first_fit)
-
-
-.. index::
- pair: MVFF; introspection
-
-MVFF introspection
-------------------
-
-::
-
- #include "mpscmvff.h"
-
-.. c:function:: size_t mps_mvff_free_size(mps_pool_t pool)
-
- Return the total amount of free space in an MVFF pool.
-
- ``pool`` is the MVFF pool.
-
- Returns the total free space in the pool, in :term:`bytes (1)`.
-
-
-.. c:function:: size_t mps_mvff_size(mps_pool_t pool)
-
- Return the total size of an MVFF pool.
-
- ``pool`` is the MVFF pool.
-
- Returns the total size of the pool, in :term:`bytes (1)`. This
- is the sum of allocated space and free space.
+ accepts eight optional :term:`keyword arguments`:
+ :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE`,
+ :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_SPARE`,
+ :c:macro:`MPS_KEY_MVFF_ARENA_HIGH`,
+ :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, and
+ :c:macro:`MPS_KEY_MVFF_FIRST_FIT` are as described above, and
+ :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging
+ options. See :c:type:`mps_pool_debug_option_s`.
diff --git a/mps/manual/source/pool/mvt.rst b/mps/manual/source/pool/mvt.rst
index a5b9daafbdc..da2ce024baa 100644
--- a/mps/manual/source/pool/mvt.rst
+++ b/mps/manual/source/pool/mvt.rst
@@ -111,8 +111,8 @@ MVT interface
Return the :term:`pool class` for an MVT (Manual Variable
Temporal) :term:`pool`.
- When creating an MVT pool, :c:func:`mps_pool_create_k` may take
- six :term:`keyword arguments`:
+ When creating an MVT pool, :c:func:`mps_pool_create_k` accepts six
+ optional :term:`keyword arguments`:
* :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is
:c:macro:`MPS_PF_ALIGN`) is the
@@ -142,7 +142,7 @@ MVT interface
that will break is the partial freeing of large blocks.
* :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` (type
- :c:type:`mps_count_t`, default 1024) is the expected hysteresis
+ :c:type:`mps_word_t`, default 1024) is the expected hysteresis
of the population of the pool. When blocks are freed, the pool
will retain sufficient storage to allocate this many blocks of the
mean size for near term allocations (rather than immediately
@@ -196,51 +196,3 @@ MVT interface
MPS_ARGS_ADD(args, MPS_KEY_MVT_FRAG_LIMIT, 0.5);
res = mps_pool_create_k(&pool, arena, mps_class_mvt(), args);
} MPS_ARGS_END(args);
-
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the arguments like
- this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_mvt(),
- size_t minimum_size,
- size_t mean_size,
- size_t maximum_size,
- mps_count_t reserve_depth,
- mps_count_t fragmentation_limit)
-
- .. note::
-
- The fragmentation_limit is a percentage from 0 to 100
- inclusive when passed to :c:func:`mps_pool_create`, not a
- double from 0.0 to 1.0 as in :c:func:`mps_pool_create_k`.
-
-
-.. index::
- pair: MVT; introspection
-
-MVT introspection
------------------
-
-::
-
- #include "mpscmvt.h"
-
-.. c:function:: size_t mps_mvt_free_size(mps_pool_t pool)
-
- Return the total amount of free space in an MVT pool.
-
- ``pool`` is the MVT pool.
-
- Returns the total free space in the pool, in :term:`bytes (1)`.
-
-
-.. c:function:: size_t mps_mvt_size(mps_pool_t pool)
-
- Return the total size of an MVT pool.
-
- ``pool`` is the MVT pool.
-
- Returns the total size of the pool, in :term:`bytes (1)`. This
- is the sum of allocated space and free space.
diff --git a/mps/manual/source/pool/snc.rst b/mps/manual/source/pool/snc.rst
index 2e82d055e7c..d39a392c614 100644
--- a/mps/manual/source/pool/snc.rst
+++ b/mps/manual/source/pool/snc.rst
@@ -39,7 +39,7 @@ SNC properties
* Supports allocation via :term:`allocation points` only. If an
allocation point is created in an SNC pool, the call to
- :c:func:`mps_ap_create_k` requires one keyword argument,
+ :c:func:`mps_ap_create_k` accepts one optional keyword argument,
:c:macro:`MPS_KEY_RANK`.
* Does not support deallocation via :c:func:`mps_free`.
@@ -83,8 +83,8 @@ SNC properties
.. index::
single: SNC; interface
-SNC introspection
------------------
+SNC interface
+-------------
::
@@ -111,21 +111,12 @@ SNC introspection
res = mps_pool_create_k(&pool, arena, mps_class_snc(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the format like
- this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_snc(),
- mps_fmt_t fmt)
-
When creating an :term:`allocation point` on an SNC pool,
- :c:func:`mps_ap_create_k` requires one keyword argument:
+ :c:func:`mps_ap_create_k` accepts one optional keyword argument:
- * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`) specifies
- the :term:`rank` of references in objects allocated on this
- allocation point. It must be :c:func:`mps_rank_exact`.
+ * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default
+ :c:func:`mps_rank_exact`) specifies the :term:`rank` of references
+ in objects allocated on this allocation point.
For example::
@@ -133,10 +124,3 @@ SNC introspection
MPS_ARGS_ADD(args, MPS_KEY_RANK, mps_rank_exact());
res = mps_ap_create_k(&ap, awl_pool, args);
} MPS_ARGS_END(args);
-
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_ap_create`, pass the rank like this::
-
- mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool,
- mps_rank_t rank)
diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst
index e7718a1cbf1..49fbae67579 100644
--- a/mps/manual/source/release.rst
+++ b/mps/manual/source/release.rst
@@ -9,6 +9,15 @@ Release notes
Release 1.115.0
---------------
+New features
+............
+
+#. When creating an :ref:`pool-amc` pool, :c:func:`mps_pool_create_k`
+ accepts the new keyword argument :c:macro:`MPS_KEY_EXTEND_BY`,
+ specifying the minimum size of the memory segments that the pool
+ requests from the :term:`arena`.
+
+
Interface changes
.................
@@ -16,9 +25,45 @@ Interface changes
name :c:type:`mps_class_t` is still available via a ``typedef``,
but is deprecated.
+#. The functions :c:func:`mps_mv_free_size`, :c:func:`mps_mv_size`,
+ :c:func:`mps_mvff_free_size`, :c:func:`mps_mvff_size`,
+ :c:func:`mps_mvt_free_size` and :c:func:`mps_mvt_size` are now
+ deprecated in favour of the generic functions
+ :c:func:`mps_pool_free_size` and :c:func:`mps_pool_total_size`.
+
Other changes
--------------
+.............
+
+#. :c:func:`mps_arena_committed` now returns a meaningful value (the
+ amount of memory marked as in use in the page tables) for
+ :term:`client arenas`. See job001887_.
+
+ .. _job001887: https://www.ravenbrook.com/project/mps/issue/job001887/
+
+#. :ref:`pool-amc` pools now assert that exact references into the
+ pool are aligned to the pool's alignment. See job002175_.
+
+ .. _job002175: https://www.ravenbrook.com/project/mps/issue/job002175/
+
+#. Internal calculation of the address space available to the MPS no
+ longer takes time proportional to the number of times the arena has
+ been extended, speeding up allocation when memory is tight. See
+ job003814_.
+
+ .. _job003814: https://www.ravenbrook.com/project/mps/issue/job003814/
+
+#. Setting :c:macro:`MPS_KEY_SPARE` for a :ref:`pool-mvff` pool now
+ works. See job003870_.
+
+ .. _job003870: https://www.ravenbrook.com/project/mps/issue/job003870/
+
+#. When the arena is out of memory and cannot be extended without
+ hitting the :term:`commit limit`, the MPS now returns
+ :c:macro:`MPS_RES_COMMIT_LIMIT` rather than substituting
+ :c:macro:`MPS_RES_RESOURCE`. See job003899_.
+
+ .. _job003899: https://www.ravenbrook.com/project/mps/issue/job003899/
#. Unfinalizable objects can no longer be registered for finalization.
Previously the objects would be registered but never finalized. See
@@ -73,8 +118,8 @@ New features
generation sizes. (This is not necessary, but may improve
performance.)
-#. New pool introspection functions :c:func:`mps_pool_total_size` and
- :c:func:`mps_pool_free_size`.
+#. New pool introspection functions :c:func:`mps_pool_free_size` and
+ :c:func:`mps_pool_total_size`.
Interface changes
@@ -163,8 +208,8 @@ Other changes
#. Allocation into :ref:`pool-awl` pools again reliably provokes
garbage collections of the generation that the pool belongs to. (In
- release 1.113.0, the generation would only be collected if a pool
- of some other class allocated into it.) See job003772_.
+ version 1.113, the generation would only be collected if a pool of
+ some other class allocated into it.) See job003772_.
.. _job003772: https://www.ravenbrook.com/project/mps/issue/job003772/
@@ -176,13 +221,21 @@ Other changes
.. _job003773: https://www.ravenbrook.com/project/mps/issue/job003773/
#. The :ref:`pool-mvt` and :ref:`pool-mvff` pool classes are now
- around 25% faster (in our benchmarks) than they were in release
- 1.113.0.
+ around 25% faster (in our benchmarks) than they were in version
+ 1.113.
-#. The default assertion handler in the ANSI plinth now flushes the
- telemetry stream before aborting. See
+#. The default assertion handler in the default :term:`plinth` now
+ flushes the telemetry stream before aborting. See
:c:func:`mps_lib_assert_fail`.
+#. Garbage collection performance is substantially improved in the
+ situation where the arena has been extended many times. Critical
+ operations now take time logarithmic in the number of times the
+ arena has been extended (rather than linear, as in version 1.113
+ and earlier). See job003554_.
+
+ .. _job003554: https://www.ravenbrook.com/project/mps/issue/job003554/
+
.. _release-notes-1.113:
@@ -294,8 +347,8 @@ Interface changes
along indefinitely. See :ref:`topic-error-assertion-handling`.
#. The behaviour when an assertion is triggered is now configurable in
- the standard ANSI :term:`plinth` by installing an assertion
- handler. See :c:func:`mps_lib_assert_fail_install`.
+ the default :term:`plinth` by installing an assertion handler. See
+ :c:func:`mps_lib_assert_fail_install`.
#. Functions that take a variable number of arguments
(:c:func:`mps_arena_create`, :c:func:`mps_pool_create`,
@@ -453,3 +506,74 @@ Other changes
later. See job003473_.
.. _job003473: https://www.ravenbrook.com/project/mps/issue/job003473/
+
+
+.. _release-notes-1.110:
+
+Release 1.110.0
+---------------
+
+New features
+............
+
+#. New supported platforms:
+
+ * ``fri6gc`` (FreeBSD, x86-64, GCC)
+ * ``lii6gc`` (Linux, x86-64, GCC)
+ * ``w3i6mv`` (Windows, x86-64, Microsoft Visual C)
+ * ``xci3ll`` (OS X, IA-32, Clang/LLVM)
+ * ``xci6gc`` (OS X, x86-64, GCC)
+ * ``xci6ll`` (OS X, x86-64, Clang/LLVM)
+
+#. Support removed for platforms:
+
+ * ``iam4cc`` (Irix 6, MIPS R4000, MIPSpro C)
+ * ``lii3eg`` (Linux, IA-32, EGCS)
+ * ``lippgc`` (Linux, PowerPC, GCC)
+ * ``o1alcc`` (OSF/1, Alpha, Digital C)
+ * ``o1algc`` (OSF/1, Alpha, GCC)
+ * ``s7ppmw`` (System 7, PowerPC, MetroWerks C)
+ * ``sos8gc`` (Solaris, SPARC 8, GCC)
+ * ``sos9sc`` (Solaris, SPARC 9, SunPro C)
+ * ``sus8gc`` (SunOS, SPARC 8, GCC)
+ * ``xcppgc`` (OS X, PowerPC, GCC)
+
+#. On Unix platforms, the MPS can now be built and installed by
+ running ``./configure && make install``. See :ref:`guide-build`.
+
+#. The MPS can be compiled in a single step via the new source file
+ ``mps.c``. This also allows you to compile the MPS in the same
+ compilation unit as your object format, allowing the compiler to
+ perform global optimizations between the two. See
+ :ref:`guide-build`.
+
+#. The set of build varieties has been reduced to three: the
+ :term:`cool` variety for development and debugging, the :term:`hot`
+ variety for production, and the :term:`rash` variety for people who
+ like to live dangerously. See :ref:`topic-error-variety`.
+
+#. The environment variable :envvar:`MPS_TELEMETRY_CONTROL` can now be
+ set to a space-separated list of event kinds. See
+ :ref:`topic-telemetry`.
+
+#. Telemetry output is now emitted to the file named by the
+ environment variable :envvar:`MPS_TELEMETRY_FILENAME`, if it is
+ set. See :ref:`topic-telemetry`.
+
+
+Interface changes
+.................
+
+#. Deprecated constants ``MPS_MESSAGE_TYPE_FINALIZATION``,
+ ``MPS_MESSAGE_TYPE_GC`` and ``MPS_MESSAGE_TYPE_GC_START`` have been
+ removed. Use :c:func:`mps_message_type_finalization`,
+ :c:func:`mps_message_type_gc` and
+ :c:func:`mps_message_type_gc_start` instead.
+
+#. Deprecated constants ``MPS_RANK_AMBIG``, ``MPS_RANK_EXACT`` and
+ ``MPS_RANK_WEAK`` have been removed. Use :c:func:`mps_rank_ambig`,
+ :c:func:`mps_rank_exact` and :c:func:`mps_rank_weak` instead.
+
+#. Deprecated functions with names starting ``mps_space_`` have been
+ removed. Use the functions with names starting ``mps_arena_``
+ instead.
diff --git a/mps/manual/source/topic/allocation.rst b/mps/manual/source/topic/allocation.rst
index 41c59190690..4075cfe006a 100644
--- a/mps/manual/source/topic/allocation.rst
+++ b/mps/manual/source/topic/allocation.rst
@@ -119,37 +119,6 @@ many small objects. They must be used according to the
:term:`thread`: each thread must create its own allocation
point or points.
- .. note::
-
- There's an alternative function :c:func:`mps_ap_create_v` that
- takes its extra arguments using the standard :term:`C`
- ``va_list`` mechanism.
-
-
-.. c:function:: mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, ...)
-
- .. deprecated:: starting with version 1.112.
-
- Use :c:func:`mps_ap_create_k` instead: the :term:`keyword
- arguments` interface is more reliable and produces better
- error messages.
-
- An alternative to :c:func:`mps_ap_create_k` that takes its extra
- arguments using the standard :term:`C` variable argument list
- mechanism.
-
-
-.. c:function:: mps_res_t mps_ap_create_v(mps_ap_t *ap_o, mps_pool_t pool, va_list args)
-
- .. deprecated:: starting with version 1.112.
-
- Use :c:func:`mps_ap_create_k` instead: the :term:`keyword
- arguments` interface is more reliable and produces better
- error messages.
-
- An alternative to :c:func:`mps_ap_create_k` that takes its extra
- arguments using the standard :term:`C` ``va_list`` mechanism.
-
.. c:function:: void mps_ap_destroy(mps_ap_t ap)
@@ -246,7 +215,8 @@ is thus::
size_t aligned_size = ALIGN(size); /* see note 1 */
do {
mps_res_t res = mps_reserve(&p, ap, aligned_size);
- if (res != MPS_RES_OK) /* handle the error */;
+ if (res != MPS_RES_OK)
+ /* handle the error */;
/* p is now an ambiguous reference to the reserved block */
obj = p;
/* initialize obj */
@@ -595,8 +565,9 @@ The *reserve* operation thus looks like this::
}
}
-The critical path consists of an add, a store, and a branch (and
-branch prediction should work well since the test usually succeeds).
+The critical path consists of three loads, an add, two stores, and a
+branch (and branch prediction should work well since the test usually
+succeeds).
.. note::
@@ -629,8 +600,9 @@ The *commit* operation thus looks like this::
/* p is valid */
}
-The critical path here consists of a store and a branch (and again,
-branch prediction should work well since the test almost never fails).
+The critical path here consists of three loads, a store and a branch
+(and again, branch prediction should work well since the test almost
+never fails).
.. note::
diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst
index ce313166161..d33242e279d 100644
--- a/mps/manual/source/topic/arena.rst
+++ b/mps/manual/source/topic/arena.rst
@@ -92,32 +92,6 @@ the way that they acquire the memory to be managed.
:c:func:`mps_arena_destroy`.
-.. c:function:: mps_res_t mps_arena_create(mps_arena_t *arena_o, mps_arena_class_t arena_class, ...)
-
- .. deprecated:: starting with version 1.112.
-
- Use :c:func:`mps_arena_create_k` instead: the :term:`keyword
- arguments` interface is more reliable and produces better
- error messages.
-
- An alternative to :c:func:`mps_arena_create_k` that takes its
- extra arguments using the standard :term:`C` variable argument
- list mechanism.
-
-
-.. c:function:: mps_res_t mps_arena_create_v(mps_arena_t *arena_o, mps_arena_class_t arena_class, va_list args)
-
- .. deprecated:: starting with version 1.112.
-
- Use :c:func:`mps_arena_create_k` instead: the :term:`keyword
- arguments` interface is more reliable and produces better
- error messages.
-
- An alternative to :c:func:`mps_arena_create_k` that takes its
- extra arguments using the standard :term:`C` ``va_list``
- mechanism.
-
-
.. c:function:: void mps_arena_destroy(mps_arena_t arena)
Destroy an :term:`arena`.
@@ -192,15 +166,6 @@ Client arenas
Client arenas have no mechanism for returning unused memory.
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_arena_create`, pass the size and base
- address like this::
-
- mps_res_t mps_arena_create(mps_arena_t *arena_o,
- mps_arena_class_t mps_arena_class_cl,
- size_t size, mps_addr_t base)
-
.. c:function:: mps_res_t mps_arena_extend(mps_arena_t arena, mps_addr_t base, size_t size)
@@ -244,7 +209,7 @@ Virtual memory arenas
accepts two optional :term:`keyword arguments` on all platforms:
* :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type:`size_t`, default
- 256\ :term:`megabytes`) is the initial amount of virtual address
+ 256Â :term:`megabytes`) is the initial amount of virtual address
space, in :term:`bytes (1)`, that the arena will reserve (this
space is initially reserved so that the arena can subsequently
use it without interference from other parts of the program, but
@@ -254,6 +219,14 @@ Virtual memory arenas
necessary. The MPS is most efficient if you reserve an address
space that is several times larger than your peak memory usage.
+ If you specify a value for :c:macro:`MPS_KEY_ARENA_SIZE` that's
+ too small for the virtual memory arena, then the MPS rounds it
+ up to the minimum and continues. The minimum size for the
+ virtual memory arena is :c:macro:`MPS_WORD_WIDTH` ×
+ :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` bytes. For example, on a
+ 64-bit platform with a 4Â :term:`kilobyte` page size, this is
+ 256\Â :term:`kilobytes`.
+
.. note::
The MPS asks for more address space if it runs out, but the
@@ -262,13 +235,16 @@ Virtual memory arenas
* :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` (type :c:type:`size_t`) is
the granularity with which the arena will manage memory
- internally. It must be a power of 2. It will be aligned up to a
- multiple of the operating system's page size if necessary. If
- not provided, the operating system's page size is used. Larger
- granularity reduces overheads, but increases
- :term:`fragmentation` and :term:`retention`.
+ internally. It must be a power of 2. If not provided, the
+ operating system's page size is used. Larger granularity reduces
+ overheads, but increases :term:`fragmentation` and
+ :term:`retention`.
- A second optional :term:`keyword argument` may be passed, but it
+ If you specify a value of :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE`
+ that's smaller than the operating system page size, the MPS
+ rounds it up to the page size and continues.
+
+ A third optional :term:`keyword argument` may be passed, but it
only has any effect on the Windows operating system:
* :c:macro:`MPS_KEY_VMW3_TOP_DOWN` (type :c:type:`mps_bool_t`). If
@@ -297,18 +273,9 @@ Virtual memory arenas
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, size);
- res = mps_arena_create_k(&arena, mps_arena_class_cl(), args);
+ res = mps_arena_create_k(&arena, mps_arena_class_vm(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_arena_create`, pass the size like
- this::
-
- mps_res_t mps_arena_create(mps_arena_t *arena_o,
- mps_arena_class_t arena_class_vm(),
- size_t size)
-
.. index::
single: arena; properties
@@ -380,9 +347,18 @@ Arena properties
``arena`` is the arena.
- Returns the total amount of memory that has been committed to RAM
+ Returns the total amount of memory that has been committed for use
by the MPS, in :term:`bytes (1)`.
+ For a :term:`virtual memory arena`, this is the amount of memory
+ mapped to RAM by the operating system's virtual memory interface.
+
+ For a :term:`client arena`, this is the amount of memory marked as
+ in use in the arena's page tables. This is not particularly
+ meaningful by itself, but it corresponds to the amount of mapped
+ memory that the MPS would use if switched to a virtual memory
+ arena.
+
The committed memory is generally larger than the sum of the sizes
of the allocated :term:`blocks`. The reasons for this are:
@@ -409,10 +385,10 @@ Arena properties
state>`). If it is called when the arena is in the unclamped state
then the value may change after this function returns. A possible
use might be to call it just after :c:func:`mps_arena_collect` to
- (over-)estimate the size of the heap.
+ estimate the size of the heap.
If you want to know how much memory the MPS is using then you're
- probably interested in the value :c:func:`mps_arena_committed()` −
+ probably interested in the value :c:func:`mps_arena_committed` −
:c:func:`mps_arena_spare_committed`.
The amount of committed memory can be limited with the function
@@ -436,12 +412,12 @@ Arena properties
.. note::
- For a client arena, the reserved address may be lower than the
- sum of the :c:macro:`MPS_KEY_ARENA_SIZE` keyword argument
- passed to :c:func:`mps_arena_create_k` and the ``size``
- arguments passed to :c:func:`mps_arena_extend`, because the
- arena may be unable to use the whole of each chunk for reasons
- of alignment.
+ For a :term:`client arena`, the reserved address space may be
+ lower than the sum of the :c:macro:`MPS_KEY_ARENA_SIZE`
+ keyword argument passed to :c:func:`mps_arena_create_k` and
+ the ``size`` arguments passed to :c:func:`mps_arena_extend`,
+ because the arena may be unable to use the whole of each chunk
+ for reasons of alignment.
.. c:function:: size_t mps_arena_spare_commit_limit(mps_arena_t arena)
@@ -506,6 +482,11 @@ Arena properties
functions for limiting the amount of :term:`committed `
memory.
+ .. note::
+
+ :term:`Client arenas` do not use spare committed memory, and
+ so this function always returns 0.
+
.. index::
single: arena; states
@@ -828,114 +809,3 @@ Arena introspection
return storage to the operating system). For reliable results
call this function and interpret the result while the arena is
in the :term:`parked state`.
-
-
-.. index::
- pair: arena; protection
-
-Protection interface
---------------------
-
-.. c:function:: void mps_arena_expose(mps_arena_t arena)
-
- .. deprecated:: starting with version 1.111.
-
- Ensure that the MPS is not protecting any :term:`page` in the
- :term:`arena` with a :term:`read barrier` or :term:`write
- barrier`.
-
- ``mps_arena`` is the arena to expose.
-
- This is expected to only be useful for debugging. The arena is
- left in the :term:`clamped state`.
-
- Since barriers are used during a collection, calling this function
- has the same effect as calling :c:func:`mps_arena_park`: all
- collections are run to completion, and the arena is clamped so
- that no new collections begin. The MPS also uses barriers to
- maintain :term:`remembered sets`, so calling this
- function will effectively destroy the remembered sets and any
- optimization gains from them.
-
- Calling this function is time-consuming: any active collections
- will be run to completion; and the next collection will have to
- recompute all the remembered sets by scanning the entire arena.
-
- The recomputation of the remembered sets can be avoided by calling
- :c:func:`mps_arena_unsafe_expose_remember_protection` instead of
- :c:func:`mps_arena_expose`, and by calling
- :c:func:`mps_arena_unsafe_restore_protection` before calling
- :c:func:`mps_arena_release`. Those functions have unsafe aspects
- and place restrictions on what the :term:`client program` can do
- (basically no exposed data can be changed).
-
-
-.. c:function:: void mps_arena_unsafe_expose_remember_protection(mps_arena_t arena)
-
- .. deprecated:: starting with version 1.111.
-
- Ensure that the MPS is not protecting any :term:`page` in the
- :term:`arena` with a :term:`read barrier` or :term:`write
- barrier`. In addition, request the MPS to remember some parts of its
- internal state so that they can be restored later.
-
- ``mps_arena`` is the arena to expose.
-
- This function is the same as :c:func:`mps_arena_expose`, but
- additionally causes the MPS to remember its protection state. The
- remembered protection state can optionally be restored later by
- calling the :c:func:`mps_arena_unsafe_restore_protection` function.
- This is an optimization that avoids the MPS having to recompute
- all the remembered sets by scanning the entire arena.
-
- However, restoring the remembered protections is only safe if the
- contents of the exposed pages have not been changed; therefore
- this function should only be used if you do not intend to change
- the pages, and the remembered protection must only be restored if
- the pages have not been changed.
-
- The MPS will only remember the protection state if resources
- (memory) are available. If memory is low then only some or
- possibly none of the protection state will be remembered, with a
- corresponding necessity to recompute it later. The MPS provides no
- mechanism for the :term:`client program` to determine whether the
- MPS has in fact remembered the protection state.
-
- The remembered protection state, if any, is discarded after
- calling :c:func:`mps_arena_unsafe_restore_protection`, or as soon
- as the arena leaves the :term:`clamped state` by calling
- :c:func:`mps_arena_release`.
-
-
-.. c:function:: void mps_arena_unsafe_restore_protection(mps_arena_t arena)
-
- .. deprecated:: starting with version 1.111.
-
- Restore the remembered protection state for an :term:`arena`.
-
- ``mps_arena`` is the arena to restore the protection state for.
-
- This function restores the protection state that the MPS has
- remembered when the :term:`client program` called
- :c:func:`mps_arena_unsafe_expose_remember_protection`. The purpose
- of remembering and restoring the protection state is to avoid the
- need for the MPS to recompute all the :term:`remembered sets` by scanning the entire arena, that occurs when
- :c:func:`mps_arena_expose` is used, and which causes the next
- :term:`garbage collection` to be slow.
-
- The client program must not change the exposed data between the
- call to :c:func:`mps_arena_unsafe_expose_remember_protection` and
- :c:func:`mps_arena_unsafe_restore_protection`. If the client
- program has changed the exposed data then
- :c:func:`mps_arena_unsafe_restore_protection` must not be called:
- in this case simply call :c:func:`mps_arena_release`.
-
- Calling this function does not release the arena from the clamped
- state: :c:func:`mps_arena_release` must be called to continue
- normal collections.
-
- Calling this function causes the MPS to forget the remember
- protection state; as a consequence the same remembered state
- cannot be restored more than once.
-
-
diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst
new file mode 100644
index 00000000000..dfd4d8d74cb
--- /dev/null
+++ b/mps/manual/source/topic/deprecated.rst
@@ -0,0 +1,745 @@
+.. index::
+ single: deprecated interfaces
+
+.. _topic-deprecated:
+
+Deprecated interfaces
+=====================
+
+This chapter documents the public symbols in the MPS interface that
+are now deprecated. These symbols may be removed in any future release
+(see :ref:`topic-interface-support` for details). If you are using one
+of these symbols, then you should update your code to use the
+supported interface.
+
+.. note::
+
+ If you are relying on a deprecated interface, and there is no
+ supported alternative, please :ref:`contact us `. It
+ makes a difference if we know that someone is using a feature.
+
+
+.. index::
+ single: deprecated interfaces; in version 1.115
+
+Deprecated in version 1.115
+...........................
+
+.. c:type:: typedef mps_pool_class_t mps_class_t
+
+ .. deprecated::
+
+ The former name for :c:type:`mps_pool_class_t`, chosen when
+ pools were the only objects in the MPS that belonged to
+ classes.
+
+
+.. c:function:: size_t mps_mv_free_size(mps_pool_t pool)
+
+ .. deprecated::
+
+ Use the generic function :c:func:`mps_pool_free_size` instead.
+
+ Return the total amount of free space in an MV pool.
+
+ ``pool`` is the MV pool.
+
+ Returns the total free space in the pool, in :term:`bytes (1)`.
+
+
+.. c:function:: size_t mps_mv_size(mps_pool_t pool)
+
+ .. deprecated::
+
+ Use the generic function :c:func:`mps_pool_total_size`
+ instead.
+
+ Return the total size of an MV pool.
+
+ ``pool`` is the MV pool.
+
+ Returns the total size of the pool, in :term:`bytes (1)`. This
+ is the sum of allocated space and free space.
+
+
+.. c:function:: size_t mps_mvff_free_size(mps_pool_t pool)
+
+ .. deprecated::
+
+ Use the generic function :c:func:`mps_pool_free_size` instead.
+
+ Return the total amount of free space in an MVFF pool.
+
+ ``pool`` is the MVFF pool.
+
+ Returns the total free space in the pool, in :term:`bytes (1)`.
+
+
+.. c:function:: size_t mps_mvff_size(mps_pool_t pool)
+
+ .. deprecated::
+
+ Use the generic function :c:func:`mps_pool_total_size`
+ instead.
+
+ Return the total size of an MVFF pool.
+
+ ``pool`` is the MVFF pool.
+
+ Returns the total size of the pool, in :term:`bytes (1)`. This
+ is the sum of allocated space and free space.
+
+
+.. c:function:: size_t mps_mvt_free_size(mps_pool_t pool)
+
+ .. deprecated::
+
+ Use the generic function :c:func:`mps_pool_free_size` instead.
+
+ Return the total amount of free space in an MVT pool.
+
+ ``pool`` is the MVT pool.
+
+ Returns the total free space in the pool, in :term:`bytes (1)`.
+
+
+.. c:function:: size_t mps_mvt_size(mps_pool_t pool)
+
+ .. deprecated::
+
+ Use the generic function :c:func:`mps_pool_total_size`
+ instead.
+
+ Return the total size of an MVT pool.
+
+ ``pool`` is the MVT pool.
+
+ Returns the total size of the pool, in :term:`bytes (1)`. This
+ is the sum of allocated space and free space.
+
+
+.. index::
+ single: deprecated interfaces; in version 1.113
+
+Deprecated in version 1.113
+...........................
+
+.. c:function:: MPS_ARGS_DONE(args)
+
+ .. deprecated::
+
+ Formerly this was used to finalize a list of :term:`keyword
+ arguments` before passing it to a function. It is no longer
+ needed.
+
+
+.. index::
+ single: deprecated interfaces; in version 1.112
+
+Deprecated in version 1.112
+...........................
+
+.. c:function:: mps_res_t mps_arena_create(mps_arena_t *arena_o, mps_arena_class_t arena_class, ...)
+
+ .. deprecated::
+
+ Use :c:func:`mps_arena_create_k` instead.
+
+ An alternative to :c:func:`mps_arena_create_k` that takes its
+ extra arguments using the standard :term:`C` variable argument
+ list mechanism.
+
+ When creating an arena of class :c:func:`mps_arena_class_cl`, pass
+ the values for the keyword arguments :c:macro:`MPS_KEY_ARENA_SIZE`
+ and :c:macro:`MPS_KEY_ARENA_CL_BASE` like this::
+
+ mps_res_t mps_arena_create(mps_arena_t *arena_o,
+ mps_arena_class_t mps_arena_class_cl(),
+ size_t arena_size,
+ mps_addr_t cl_base)
+
+ When creating an arena of class :c:func:`mps_arena_class_vm`, pass
+ the value for the keyword argument :c:macro:`MPS_KEY_ARENA_SIZE`
+ like this::
+
+ mps_res_t mps_arena_create(mps_arena_t *arena_o,
+ mps_arena_class_t mps_arena_class_vm(),
+ size_t arena_size)
+
+
+.. c:function:: mps_res_t mps_arena_create_v(mps_arena_t *arena_o, mps_arena_class_t arena_class, va_list args)
+
+ .. deprecated::
+
+ Use :c:func:`mps_arena_create_k` instead.
+
+ An alternative to :c:func:`mps_arena_create_k` that takes its
+ extra arguments using the standard :term:`C` ``va_list``
+ mechanism. See :c:func:`mps_arena_create` for details of which
+ arguments to pass for the different arena classes.
+
+
+.. c:function:: mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, ...)
+
+ .. deprecated::
+
+ Use :c:func:`mps_pool_create_k` instead.
+
+ An alternative to :c:func:`mps_pool_create_k` that takes its
+ extra arguments using the standard :term:`C` variable argument
+ list mechanism.
+
+ When creating a pool of class :c:func:`mps_class_amc` or
+ :c:func:`mps_class_amcz`, pass the values for the keyword
+ arguments :c:macro:`MPS_KEY_FORMAT` and :c:macro:`MPS_KEY_CHAIN`
+ like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_amc(),
+ mps_fmt_t format,
+ mps_chain_t chain)
+
+ When creating a pool of class :c:func:`mps_class_ams`, pass the
+ values for the keyword arguments :c:macro:`MPS_KEY_FORMAT`,
+ :c:macro:`MPS_KEY_CHAIN` and ambiguous flag
+ :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_ams(),
+ mps_fmt_t format,
+ mps_chain_t chain,
+ mps_bool_t ams_support_ambiguous)
+
+ When creating a pool of class :c:func:`mps_class_ams_debug`, pass
+ the values for the keyword arguments
+ :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`, :c:macro:`MPS_KEY_FORMAT`,
+ :c:macro:`MPS_KEY_CHAIN` and
+ :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_ams_debug(),
+ mps_pool_debug_option_s *pool_debug_options,
+ mps_fmt_t format,
+ mps_chain_t chain,
+ mps_bool_t ams_support_ambiguous)
+
+ When creating a pool of class :c:func:`mps_class_awl`, pass the
+ values for the keyword arguments :c:macro:`MPS_KEY_FORMAT` and
+ :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_awl(),
+ mps_fmt_t format,
+ mps_awl_find_dependent_t awl_find_dependent)
+
+ When creating a pool of class :c:func:`mps_class_lo`, pass the
+ value for the keyword argument :c:macro:`MPS_KEY_FORMAT` like
+ this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_lo(),
+ mps_fmt_t format)
+
+ When creating a pool of class :c:func:`mps_class_mfs`, pass the
+ values for the keyword arguments :c:macro:`MPS_KEY_EXTEND_BY` and
+ :c:macro:`MPS_KEY_MFS_UNIT_SIZE` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_mfs(),
+ size_t extend_by,
+ size_t unit_size)
+
+ When creating a pool of class :c:func:`mps_class_mv`, pass the
+ values for the keyword arguments :c:macro:`MPS_KEY_EXTEND_BY`,
+ :c:macro:`MPS_KEY_MEAN_SIZE`, and :c:macro:`MPS_KEY_MAX_SIZE` like
+ this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_mv(),
+ size_t extend_by,
+ size_t mean_size,
+ size_t max_size)
+
+ When creating a pool of class :c:func:`mps_class_mv_debug`, pass
+ the values for the keyword arguments
+ :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`,
+ :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE` and
+ :c:macro:`MPS_KEY_MAX_SIZE` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_mv_debug(),
+ mps_pool_debug_option_s *pool_debug_options,
+ size_t extend_by,
+ size_t mean_size,
+ size_t max_size)
+
+ When creating a pool of class :c:func:`mps_class_mvff`, pass the
+ values for the keyword arguments :c:macro:`MPS_KEY_EXTEND_BY`,
+ :c:macro:`MPS_KEY_MEAN_SIZE`, :c:macro:`MPS_KEY_ALIGN`,
+ :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`,
+ :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` and
+ :c:macro:`MPS_KEY_MVFF_FIRST_FIT` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_mvff(),
+ size_t extend_by,
+ size_t mean_size,
+ mps_align_t align,
+ mps_bool_t mvff_slot_high,
+ mps_bool_t mvff_arena_high,
+ mps_bool_t mvff_first_fit)
+
+ When creating a pool of class :c:func:`mps_class_mvff_debug`, pass
+ the values for the keyword arguments
+ :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`,
+ :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE`,
+ :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`,
+ :c:macro:`MPS_KEY_MVFF_ARENA_HIGH`, and
+ :c:macro:`MPS_KEY_MVFF_FIRST_FIT` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_mvff_debug(),
+ mps_pool_debug_option_s *pool_debug_options,
+ size_t extend_by,
+ size_t mean_size,
+ mps_align_t align,
+ mps_bool_t mvff_slot_high,
+ mps_bool_t mvff_arena_high,
+ mps_bool_t mvff_first_fit)
+
+ When creating a pool of class :c:func:`mps_class_mvt`, pass the
+ values for the keyword arguments :c:macro:`MPS_KEY_MIN_SIZE`,
+ :c:macro:`MPS_KEY_MEAN_SIZE`, :c:macro:`MPS_KEY_MAX_SIZE`,
+ :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` and
+ :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_mvt(),
+ size_t min_size,
+ size_t mean_size,
+ size_t max_size,
+ mps_word_t mvt_reserve_depth,
+ mps_word_t mvt_frag_limit)
+
+ .. note::
+
+ The ``mvt_frag_limit`` is a percentage from 0 to 100
+ inclusive when passed to :c:func:`mps_pool_create`, not a
+ double from 0.0 to 1.0 as in :c:func:`mps_pool_create_k`.
+
+ When creating a pool of class :c:func:`mps_class_snc`, pass the
+ value for the keyword argument :c:macro:`MPS_KEY_FORMAT` like
+ this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_snc(),
+ mps_fmt_t format)
+
+
+.. c:function:: mps_res_t mps_pool_create_v(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, va_list args)
+
+ .. deprecated::
+
+ Use :c:func:`mps_pool_create_k` instead.
+
+ An alternative to :c:func:`mps_pool_create_k` that takes its extra
+ arguments using the standard :term:`C` ``va_list`` mechanism. See
+ :c:func:`mps_pool_create` for details of which arguments to pass
+ for the different pool classes.
+
+
+.. c:function:: mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, ...)
+
+ .. deprecated::
+
+ Use :c:func:`mps_ap_create_k` instead.
+
+ An alternative to :c:func:`mps_ap_create_k` that takes its extra
+ arguments using the standard :term:`C` variable argument list
+ mechanism.
+
+ When creating an allocation point on a pool of class
+ :c:func:`mps_class_ams`, :c:func:`mps_class_ams_debug`,
+ :c:func:`mps_class_awl` or :c:func:`mps_class_snc`, pass the
+ keyword argument :c:macro:`MPS_KEY_RANK` like this::
+
+ mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool,
+ mps_rank_t rank)
+
+
+.. c:function:: mps_res_t mps_ap_create_v(mps_ap_t *ap_o, mps_pool_t pool, va_list args)
+
+ .. deprecated::
+
+ Use :c:func:`mps_ap_create_k` instead.
+
+ An alternative to :c:func:`mps_ap_create_k` that takes its extra
+ arguments using the standard :term:`C` ``va_list`` mechanism. See
+ :c:func:`mps_ap_create` for details of which arguments to pass
+ for the different pool classes.
+
+
+.. c:type:: mps_fmt_A_s
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ The type of the structure used to create an :term:`object format`
+ of variant A. ::
+
+ typedef struct mps_fmt_A_s {
+ mps_align_t align;
+ mps_fmt_scan_t scan;
+ mps_fmt_skip_t skip;
+ mps_fmt_copy_t copy;
+ mps_fmt_fwd_t fwd;
+ mps_fmt_isfwd_t isfwd;
+ mps_fmt_pad_t pad;
+ } mps_fmt_A_s;
+
+ The fields of this structure correspond to the keyword arguments
+ to :c:func:`mps_fmt_create_k`, except for ``copy``, which is not
+ used. In older versions of the MPS this was a *copy method*
+ that copied objects belonging to this format.
+
+
+.. c:function:: mps_res_t mps_fmt_create_A(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_A_s *fmt_A)
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ Create an :term:`object format` based on a description of an
+ object format of variant A.
+
+
+.. c:type:: mps_fmt_B_s
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ The type of the structure used to create an :term:`object format`
+ of variant B. ::
+
+ typedef struct mps_fmt_B_s {
+ mps_align_t align;
+ mps_fmt_scan_t scan;
+ mps_fmt_skip_t skip;
+ mps_fmt_copy_t copy;
+ mps_fmt_fwd_t fwd;
+ mps_fmt_isfwd_t isfwd;
+ mps_fmt_pad_t pad;
+ mps_fmt_class_t mps_class;
+ } mps_fmt_B_s;
+
+ Variant B is the same as variant A except for the addition of the
+ ``mps_class`` method. See :c:type:`mps_fmt_A_s`.
+
+
+.. c:function:: mps_res_t mps_fmt_create_B(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_B_s *fmt_B)
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ Create an :term:`object format` based on a description of an
+ object format of variant B.
+
+
+.. c:type:: mps_fmt_auto_header_s
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ The type of the structure used to create an :term:`object format`
+ of variant auto-header. ::
+
+ typedef struct mps_fmt_auto_header_s {
+ mps_align_t align;
+ mps_fmt_scan_t scan;
+ mps_fmt_skip_t skip;
+ mps_fmt_fwd_t fwd;
+ mps_fmt_isfwd_t isfwd;
+ mps_fmt_pad_t pad;
+ size_t mps_headerSize;
+ } mps_fmt_auto_header_s;
+
+ Variant auto-header is the same as variant A except for the
+ removal of the unused ``copy`` method, and the addition of the
+ ``mps_headerSize`` field. See :c:type:`mps_fmt_A_s`.
+
+
+.. c:function:: mps_res_t mps_fmt_create_auto_header(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_auto_header_s *fmt_ah)
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ Create an :term:`object format` based on a description of an
+ object format of variant auto-header.
+
+
+.. c:type:: mps_fmt_fixed_s
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ The type of the structure used to create an :term:`object format`
+ of variant fixed. ::
+
+ typedef struct mps_fmt_fixed_s {
+ mps_align_t align;
+ mps_fmt_scan_t scan;
+ mps_fmt_fwd_t fwd;
+ mps_fmt_isfwd_t isfwd;
+ mps_fmt_pad_t pad;
+ } mps_fmt_fixed_s;
+
+ Variant fixed is the same as variant A except for the removal of
+ the unused ``copy`` method, and the lack of a ``skip`` method
+ (this is not needed because the objects are fixed in size). See
+ :c:type:`mps_fmt_A_s`.
+
+
+.. c:function:: mps_res_t mps_fmt_create_fixed(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_fixed_s *fmt_fixed)
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ Create an :term:`object format` based on a description of an
+ object format of variant fixed.
+
+
+.. index::
+ single: deprecated interfaces; in version 1.111
+
+Deprecated in version 1.111
+...........................
+
+.. c:function:: mps_res_t mps_fix(mps_ss_t ss, mps_addr_t *ref_io)
+
+ .. deprecated::
+
+ Use :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2` instead.
+
+ :term:`Fix` a :term:`reference`.
+
+ This is a function equivalent to::
+
+ MPS_SCAN_BEGIN(ss);
+ res = MPS_FIX12(ss, ref_io);
+ MPS_SCAN_END(ss);
+ return res;
+
+ Because :term:`scanning ` is an operation on the
+ :term:`critical path`, we recommend that you use
+ :c:func:`MPS_FIX12` (or :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2`)
+ to ensure that the "stage 1 fix" is inlined.
+
+ .. note::
+
+ If you call this between :c:func:`MPS_SCAN_BEGIN` and
+ :c:func:`MPS_SCAN_END`, you must use :c:func:`MPS_FIX_CALL` to
+ ensure that the scan state is passed correctly.
+
+
+.. c:function:: mps_word_t mps_telemetry_control(mps_word_t reset_mask, mps_word_t flip_mask)
+
+ .. deprecated::
+
+ Use :c:func:`mps_telemetry_get`,
+ :c:func:`mps_telemetry_reset`, and :c:func:`mps_telemetry_set`
+ instead.
+
+ Update and return the :term:`telemetry filter`.
+
+ ``reset_mask`` is a :term:`bitmask` indicating the bits in the
+ telemetry filter that should be reset.
+
+ ``flip_mask`` is a bitmask indicating the bits in the telemetry
+ filter whose value should be flipped after the resetting.
+
+ Returns the previous value of the telemetry filter, prior to the
+ reset and the flip.
+
+ The parameters ``reset_mask`` and ``flip_mask`` allow the
+ specification of any binary operation on the filter control. For
+ typical operations, the parameters should be set as follows:
+
+ ============ ============== =============
+ Operation ``reset_mask`` ``flip_mask``
+ ============ ============== =============
+ ``set(M)`` ``M`` ``M``
+ ------------ -------------- -------------
+ ``reset(M)`` ``M`` ``0``
+ ------------ -------------- -------------
+ ``flip(M)`` ``0`` ``M``
+ ------------ -------------- -------------
+ ``read()`` ``0`` ``0``
+ ============ ============== =============
+
+
+.. c:function:: void mps_tramp(void **r_o, mps_tramp_t f, void *p, size_t s)
+
+ .. deprecated::
+
+ The MPS trampoline is no longer required on any operating
+ system supported by the MPS.
+
+ Call a function via the MPS trampoline.
+
+ ``r_o`` points to a location that will store the result of calling
+ ``f``.
+
+ ``f`` is the function to call.
+
+ ``p`` and ``s`` are arguments that will be passed to ``f`` each
+ time it is called. This is intended to make it easy to pass, for
+ example, an array and its size as parameters.
+
+ The MPS relies on :term:`barriers (1)` to protect memory
+ that is in an inconsistent state. On some operating systems,
+ barrier hits generate exceptions that have to be caught by a
+ handler that is on the stack. On these operating systems, any code
+ that uses memory managed by the MPS must be called from inside
+ such an exception handler, that is, inside a call to
+ :c:func:`mps_tramp`.
+
+ If you have multiple threads that run code that uses memory
+ managed by the MPS, each thread must execute such code inside a
+ call to :c:func:`mps_tramp`.
+
+
+.. index::
+ single: trampoline
+
+.. c:type:: void *(*mps_tramp_t)(void *p, size_t s)
+
+ .. deprecated::
+
+ The MPS trampoline is no longer required on any operating
+ system supported by the MPS.
+
+ The type of a function called by :c:func:`mps_tramp`.
+
+ ``p`` and ``s`` are the corresponding arguments that were passed
+ to :c:func:`mps_tramp`.
+
+
+.. c:function:: void mps_arena_expose(mps_arena_t arena)
+
+ .. deprecated::
+
+ If you need access to protected memory for debugging,
+ :ref:`contact us `.
+
+ Ensure that the MPS is not protecting any :term:`page` in the
+ :term:`arena` with a :term:`read barrier` or :term:`write
+ barrier`.
+
+ ``arena`` is the arena to expose.
+
+ This is expected to only be useful for debugging. The arena is
+ left in the :term:`clamped state`.
+
+ Since barriers are used during a collection, calling this function
+ has the same effect as calling :c:func:`mps_arena_park`: all
+ collections are run to completion, and the arena is clamped so
+ that no new collections begin. The MPS also uses barriers to
+ maintain :term:`remembered sets`, so calling this
+ function will effectively destroy the remembered sets and any
+ optimization gains from them.
+
+ Calling this function is time-consuming: any active collections
+ will be run to completion; and the next collection will have to
+ recompute all the remembered sets by scanning the entire arena.
+
+ The recomputation of the remembered sets can be avoided by calling
+ :c:func:`mps_arena_unsafe_expose_remember_protection` instead of
+ :c:func:`mps_arena_expose`, and by calling
+ :c:func:`mps_arena_unsafe_restore_protection` before calling
+ :c:func:`mps_arena_release`. Those functions have unsafe aspects
+ and place restrictions on what the :term:`client program` can do
+ (basically no exposed data can be changed).
+
+
+.. c:function:: void mps_arena_unsafe_expose_remember_protection(mps_arena_t arena)
+
+ .. deprecated::
+
+ If you need access to protected memory for debugging,
+ :ref:`contact us