1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-02-05 07:01:11 -08:00

Improvements following review.

Copied from Perforce
 Change: 186227
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Gareth Rees 2014-05-21 00:43:06 +01:00
parent 8acf4952a4
commit a0e076be57
11 changed files with 107 additions and 71 deletions

View file

@ -494,7 +494,7 @@ Res ArenaDescribe(Arena arena, mps_lib_FILE *stream)
}
/* ArenaDescribeTractsInChunk -- describe all the tracts in a chunk */
/* ArenaDescribeTractsInChunk -- describe the tracts in a chunk */
static Bool arenaDescribeTractsInChunk(Tree tree, void *closureP, Size closureS)
{
@ -509,20 +509,30 @@ static Bool arenaDescribeTractsInChunk(Tree tree, void *closureP, Size closureS)
if (stream == NULL) return ResFAIL;
UNUSED(closureS);
res = WriteF(stream, "Chunk [$P, $P) ($U) {\n",
(WriteFP)chunk->base, (WriteFP)chunk->limit,
(WriteFU)chunk->serial,
NULL);
if (res != ResOK) return res;
TRACT_TRACT_FOR(tract, addr, ChunkArena(chunk),
PageTract(ChunkPage(chunk, chunk->allocBase)),
chunk->limit)
{
res = WriteF(stream,
"[$P, $P) $U $P ($S)\n",
" [$P, $P) $P $U ($S)\n",
(WriteFP)TractBase(tract), (WriteFP)TractLimit(tract),
(WriteFW)ArenaAlign(ChunkArena(chunk)),
(WriteFP)TractPool(tract),
(WriteFU)(TractPool(tract)->serial),
(WriteFS)(TractPool(tract)->class->name),
NULL);
if (res != ResOK) return res;
}
return ResOK;
res = WriteF(stream, "} Chunk [$P, $P)\n",
(WriteFP)chunk->base, (WriteFP)chunk->limit,
NULL);
return res;
}
@ -599,17 +609,7 @@ Res ControlDescribe(Arena arena, mps_lib_FILE *stream)
}
/* ArenaChunkInsert -- insert chunk into arena's chunk tree
*
* Note that there's no corresponding ArenaChunkDelete. That's because
* we don't have a function that deletes an item from a balanced tree
* efficiently. Instead, deletions from the chunk tree are carried out
* by calling TreeToVine, iterating over the vine (where deletion is
* straightforward) and then calling TreeBalance. This is efficient
* when deleting all the chunks at a time in ArenaFinish, and
* acceptable in VMCompact when multiple chunks may be deleted from
* the tree.
*/
/* ArenaChunkInsert -- insert chunk into arena's chunk tree */
void ArenaChunkInsert(Arena arena, Tree tree) {
Bool inserted;
@ -689,13 +689,12 @@ static Res arenaAllocPage(Addr *baseReturn, Arena arena, Pool pool)
/* Favour the primary chunk, because pages allocated this way aren't
currently freed, and we don't want to prevent chunks being destroyed. */
/* TODO: Consider how the ArenaCBSBlockPool might free pages. */
if (arenaAllocPageInChunk(&arena->primary->chunkTree, &closure, 0) == FALSE)
if (!arenaAllocPageInChunk(&arena->primary->chunkTree, &closure, 0))
goto found;
closure.avoid = arena->primary;
if (TreeTraverse(ArenaChunkTree(arena), ChunkCompare, ChunkKey,
arenaAllocPageInChunk, &closure, 0)
== FALSE)
if (!TreeTraverse(ArenaChunkTree(arena), ChunkCompare, ChunkKey,
arenaAllocPageInChunk, &closure, 0))
goto found;
return ResRESOURCE;

View file

@ -295,7 +295,8 @@ static void ClientArenaFinish(Arena arena)
clientArena = Arena2ClientArena(arena);
AVERT(ClientArena, clientArena);
/* destroy all chunks, including the primary */
/* Destroy all chunks, including the primary. See
* <design/arena/#chunk.delete> */
arena->primary = NULL;
TREE_DESTROY(treeref, tree, next, arena->chunkTree) {
clientChunkDestroy(ChunkOfTree(tree));

View file

@ -597,12 +597,13 @@ static void VMArenaFinish(Arena arena)
EVENT1(ArenaDestroy, vmArena);
/* destroy all chunks, including the primary */
/* Destroy all chunks, including the primary. See
* <design/arena/#chunk.delete> */
arena->primary = NULL;
TREE_DESTROY(treeref, tree, next, arena->chunkTree) {
vmChunkDestroy(ChunkOfTree(tree));
}
/* Destroying the chunks should have purged and removed all spare pages. */
RingFinish(&vmArena->spareRing);
@ -1095,11 +1096,9 @@ static void VMCompact(Arena arena, Trace trace)
vmem1 = VMArenaReserved(arena);
/* Destroy all the chunks that are completely free. Be very careful
* about the order of operations on the tree because vmChunkDestroy
* unmaps the memory that the tree node resides in, so the next tree
* node has to be looked up first. TODO: add hysteresis here. See
* job003815. */
/* Destroy chunks that are completely free, but not the primary
* chunk. See <design/arena/#chunk.delete>
* TODO: add hysteresis here. See job003815. */
tree = &arena->chunkTree;
TreeToVine(tree);
while (*tree != TreeEMPTY) {

View file

@ -694,7 +694,7 @@ static Compare SplaySplay(SplayTree splay, TreeKey key, TreeCompare compare)
SplayStateStruct stateStruct;
#ifdef SPLAY_DEBUG
Count count = TreeDebugCount(SplayTreeRoot(splay), splay->compare, splay->nodeKey);
Count count = SplayDebugCount(splay);
#endif
/* Short-circuit common cases. Splay trees often bring recently
@ -714,7 +714,7 @@ static Compare SplaySplay(SplayTree splay, TreeKey key, TreeCompare compare)
SplayTreeSetRoot(splay, stateStruct.middle);
#ifdef SPLAY_DEBUG
AVER(count == TreeDebugCount(SplayTreeRoot(splay), splay->compare, splay->nodeKey));
AVER(count == SplayDebugCount(splay));
#endif
return cmp;
@ -909,7 +909,7 @@ Bool SplayTreeNeighbours(Tree *leftReturn, Tree *rightReturn,
Bool found;
Compare cmp;
#ifdef SPLAY_DEBUG
Count count = TreeDebugCount(SplayTreeRoot(splay), splay->compare, splay->nodeKey);
Count count = SplayDebugCount(splay);
#endif
@ -951,7 +951,7 @@ Bool SplayTreeNeighbours(Tree *leftReturn, Tree *rightReturn,
SplayTreeSetRoot(splay, stateStruct.middle);
#ifdef SPLAY_DEBUG
AVER(count == TreeDebugCount(SplayTreeRoot(splay), splay->compare, splay->nodeKey));
AVER(count == SplayDebugCount(splay));
#endif
return found;
@ -970,9 +970,8 @@ Bool SplayTreeNeighbours(Tree *leftReturn, Tree *rightReturn,
* unmodified.
*
* IMPORTANT: Iterating over the tree using these functions will leave
* the tree totally unbalanced, throwing away optimisations of the
* tree shape caused by previous splays. Consider using
* SplayTreeTraverse instead.
* the tree totally unbalanced, throwing away optimisations of the tree
* shape caused by previous splays. Consider using TreeTraverse instead.
*/
Tree SplayTreeFirst(SplayTree splay) {
@ -1013,16 +1012,6 @@ Tree SplayTreeNext(SplayTree splay, TreeKey oldKey) {
}
/* SplayTreeTraverse -- iterate over splay tree without splaying it */
Bool SplayTreeTraverse(SplayTree splay, TreeVisitor visitor,
void *closureP, Size closureS)
{
return TreeTraverse(splay->root, splay->compare, splay->nodeKey,
visitor, closureP, closureS);
}
/* SplayNodeDescribe -- Describe a node in the splay tree
*
* Note that this breaks the restriction of .note.stack.

View file

@ -55,8 +55,6 @@ extern Bool SplayTreeNeighbours(Tree *leftReturn,
extern Tree SplayTreeFirst(SplayTree splay);
extern Tree SplayTreeNext(SplayTree splay, TreeKey oldKey);
extern Bool SplayTreeTraverse(SplayTree splay, TreeVisitor visitor,
void *closureP, Size closureS);
typedef Bool (*SplayFindMethod)(Tree *nodeReturn, SplayTree splay,
SplayTestNodeMethod testNode,
@ -79,6 +77,7 @@ extern Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream,
extern void SplayDebugUpdate(SplayTree splay, Tree tree);
extern Count SplayDebugCount(SplayTree splay);
#endif /* splay_h */

View file

@ -119,11 +119,11 @@ Compare TreeFind(Tree *treeReturn, Tree root, TreeKey key, TreeCompare compare)
/* TreeFindNext -- search for node containing key, or next node
*
* If there is a node that is greater than key, set treeReturn to that
* If there is a node that is greater than key, set *treeReturn to that
* node and return TRUE.
*
* Otherwise, key is greater than all nodes in the tree, so leave
* treeReturn unchanged and return FALSE.
* *treeReturn unchanged and return FALSE.
*/
Bool TreeFindNext(Tree *treeReturn, Tree root, TreeKey key, TreeCompare compare)

View file

@ -136,7 +136,7 @@ extern void TreeBalance(Tree *treeIO);
/* TREE_DESTROY -- iterate over a tree while destroying it.
*
* root is a lvalue storing the root of the tree.
* root is an lvalue storing the root of the tree.
* treeref is a variable of type Tree*.
* tree and next are variables of type Tree.
* In the body of the loop, tree is the current node.
@ -145,7 +145,7 @@ extern void TreeBalance(Tree *treeIO);
for ((treeref = &(root), TreeToVine(treeref), next = TreeEMPTY); \
(tree = *treeref) != TreeEMPTY \
? (next = tree->right, TRUE) \
: (TreeBalance(treeref), FALSE); \
: FALSE; \
*treeref = next)

View file

@ -220,6 +220,49 @@ implementations of those methods which must be overridden. Instead
each abstract method is initialized to ``NULL``.
Chunks
......
_`.chunk`: Each contiguous region of address space managed by the MPS
is represented by a *chunk*.
_`.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
_`.chunk.tree`: For efficient lookup, chunks are stored in a balanced
tree; ``arena->chunkTree`` points to the root of the tree. Operations
on this tree must ensure that the tree remains balanced, otherwise
performance degrades badly with many chunks.
_`.chunk.insert`: New chunks are inserted into the tree by calling
``ArenaChunkInsert()``. This calls ``TreeInsert()``, followed by
``TreeBalance()`` to ensure that the tree is balanced.
_`.chunk.delete`: There is no corresponding function
``ArenaChunkDelete()``. Instead, deletions from the chunk tree are
carried out by calling ``TreeToVine()``, iterating over the vine
(where deletion is straightforward, with care) and then calling
``TreeBalance()`` if any chunks might remain. The macro
``TREE_DESTROY()`` assists with the common case.
_`.chunk.delete.justify`: This is because we don't have a function
that deletes an item from a balanced tree efficiently, and because all
functions that delete chunks do so in a loop that may delete multiple
chunks. The procedure is efficient when deleting all the chunks in
``ArenaFinish()``, and has acceptable performance in ``VMCompact()``
where multiple chunks may be deleted from the tree.
_`.chunk.delete.tricky`: Deleting chunks from the chunk tree is tricky
in the virtual memory arena because ``vmChunkDestroy()`` unmaps the
memory containing the chunk, which includes the tree node. So the next
chunk must be looked up before deleting the current chunk.
Tracts
......
@ -233,11 +276,11 @@ associating their own data with each allocation grain.
_`.tract.structure`: The tract structure definition looks like this::
typedef struct TractStruct { /* Tract structure */
PagePoolUnion pool; /* MUST BE FIRST (design.mps.arena.tract.field.pool) */
void *p; /* pointer for use of owning pool */
Addr base; /* Base address of the tract */
TraceSet white : TRACE_MAX; /* traces for which tract is white */
unsigned int hasSeg : 1; /* does tract have a seg in p? */
PagePoolUnion pool; /* MUST BE FIRST (<design/arena/#tract.field> pool) */
void *p; /* pointer for use of owning pool */
Addr base; /* Base address of the tract */
TraceSet white : TraceLIMIT; /* traces for which tract is white */
unsigned hasSeg : 1; /* does tract have a seg in p? See .bool */
} TractStruct;
_`.tract.field.pool`: The pool.pool field indicates to which pool the tract
@ -263,9 +306,11 @@ 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``.
``hasSeg`` is typed as an ``unsigned int``, rather than a ``Bool``.
This ensures that there won't be sign conversion problems when
converting the bit-field value.
``hasSeg`` has type ``unsigned:1`` rather than ``Bool:1`` to avoid
sign conversion problems when converting the bit-field value. See
`design.mps.type.bool.bitfield`_.
.. _design.mps.type.bool.bitfield: type#bool.bitfield
_`.tract.field.base`: The base field contains the base address of the
memory represented by the tract.

View file

@ -511,7 +511,10 @@ requested (to allow for large objects).
_`.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.
regions at both ends of the address space. See
`design.mps.arena.chunk`_.
.. _design.mps.arena.chunk: arena#chunk
Overview of strategy

View file

@ -63,21 +63,20 @@ Data Structure
The implementations are as follows::
typedef struct SegStruct { /* segment structure */
Sig sig; /* impl.h.misc.sig */
Sig sig; /* <code/misc.h#sig> */
SegClass class; /* segment class structure */
Tract firstTract; /* first tract of segment */
RingStruct poolRing; /* link in list of segs in pool */
Addr limit; /* limit of segment */
unsigned depth : SHIELD_DEPTH_WIDTH; /* see impl.c.shield.def.depth */
AccessSet pm : AccessMAX; /* protection mode, impl.c.shield */
AccessSet sm : AccessMAX; /* shield mode, impl.c.shield */
TraceSet grey : TRACE_MAX; /* traces for which seg is grey */
TraceSet white : TRACE_MAX; /* traces for which seg is white */
TraceSet nailed : TRACE_MAX; /* traces for which seg has nailed objects */
RankSet rankSet : RankMAX; /* ranks of references in this seg */
unsigned depth : ShieldDepthWIDTH; /* see <code/shield.c#def.depth> */
AccessSet pm : AccessLIMIT; /* protection mode, <code/shield.c> */
AccessSet sm : AccessLIMIT; /* shield mode, <code/shield.c> */
TraceSet grey : TraceLIMIT; /* traces for which seg is grey */
TraceSet white : TraceLIMIT; /* traces for which seg is white */
TraceSet nailed : TraceLIMIT; /* traces for which seg has nailed objects */
RankSet rankSet : RankLIMIT; /* ranks of references in this seg */
} SegStruct;
typedef struct GCSegStruct { /* GC segment structure */
SegStruct segStruct; /* superclass fields must come first */
RingStruct greyRing; /* link in list of grey segs */

View file

@ -564,9 +564,11 @@ space as the client data.
``typedef unsigned TraceId``
_`.traceid`: A ``TraceId`` is an unsigned integer which is less than
``TRACE_MAX``. Each running trace has a different ``TraceId`` which is
used to index into tables and bitfields used to remember the state of
that trace.
``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`_.
.. _design.mps.trace.instance.limit: trace#instance.limit
``typedef unsigned TraceSet``