1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-10 05:30:45 -08:00

Refactor arenapeekseg so that it maintains the mps invariants by scanning the segment if necessary. arenaread is now a thin wrapper around arenapeekseg. new function arenawrite is now the corresponding wrapper around arenapokeseg.

MRG reference segments inherit from GCSeg (not MutatorSeg) and so don't have hardware barriers. Instead, the code implements software barriers by always using ArenaRead and ArenaWrite.

Copied from Perforce
 Change: 193990
This commit is contained in:
Gareth Rees 2018-06-19 16:25:52 +01:00
parent 7f7822d4ab
commit e93949aeef
5 changed files with 104 additions and 112 deletions

View file

@ -871,7 +871,7 @@ Res ArenaDefinalize(Arena arena, Ref obj)
}
/* Peek / Poke */
/* ArenaPeek -- read a single reference, possibly through a barrier */
Ref ArenaPeek(Arena arena, Ref *p)
{
@ -888,74 +888,19 @@ Ref ArenaPeek(Arena arena, Ref *p)
return ref;
}
/* ArenaPeekSeg -- as ArenaPeek, but p must be in seg. */
Ref ArenaPeekSeg(Arena arena, Seg seg, Ref *p)
{
Ref ref;
AVERT(Arena, arena);
AVERT(Seg, seg);
AVER(SegBase(seg) <= (Addr)p);
AVER((Addr)p < SegLimit(seg));
/* TODO: Consider checking p's alignment using seg->pool->alignment */
ShieldExpose(arena, seg);
ref = *p;
ShieldCover(arena, seg);
return ref;
}
void ArenaPoke(Arena arena, Ref *p, Ref ref)
{
Seg seg;
AVERT(Arena, arena);
/* Can't check p as it is arbitrary */
/* Can't check ref as it is arbitrary */
if (SegOfAddr(&seg, arena, (Addr)p))
ArenaPokeSeg(arena, seg, p, ref);
else
*p = ref;
}
void ArenaPokeSeg(Arena arena, Seg seg, Ref *p, Ref ref)
{
RefSet summary;
AVERT(Arena, arena);
AVERT(Seg, seg);
AVER(SegBase(seg) <= (Addr)p);
AVER((Addr)p < SegLimit(seg));
/* TODO: Consider checking p's alignment using seg->pool->alignment */
/* ref is arbitrary and can't be checked */
ShieldExpose(arena, seg);
*p = ref;
summary = SegSummary(seg);
summary = RefSetAdd(arena, summary, (Addr)ref);
SegSetSummary(seg, summary);
ShieldCover(arena, seg);
}
/* ArenaRead -- read a single reference, possibly through a barrier
*
* This forms part of a software barrier. It provides fine-grain access
* to single references in segments.
*
* See also PoolSingleAccess and PoolSegAccess. */
Ref ArenaRead(Arena arena, Ref *p)
{
Bool b;
Seg seg = NULL; /* suppress "may be used uninitialized" */
Rank rank;
AVERT(Arena, arena);
b = SegOfAddr(&seg, arena, (Addr)p);
AVER(b == TRUE);
AVERT(Seg, seg);
AVER(PoolArena(SegPool(seg)) == arena);
AVER(SegBase(seg) <= (Addr)p);
AVER((Addr)p < SegLimit(seg));
/* TODO: Consider checking p's alignment using seg->pool->alignment */
/* .read.flipped: We AVER that the reference that we are reading */
/* refers to an object for which all the traces that the object is */
@ -977,11 +922,81 @@ Ref ArenaRead(Arena arena, Ref *p)
/* We don't need to update the Seg Summary as in PoolSingleAccess
* because we are not changing it after it has been scanned. */
ShieldExpose(arena, seg);
ref = *p;
ShieldCover(arena, seg);
return ref;
}
/* ArenaPoke -- write a single reference, possibly through a barrier */
void ArenaPoke(Arena arena, Ref *p, Ref ref)
{
Seg seg;
AVERT(Arena, arena);
/* Can't check p as it is arbitrary */
/* Can't check ref as it is arbitrary */
if (SegOfAddr(&seg, arena, (Addr)p))
ArenaPokeSeg(arena, seg, p, ref);
else
*p = ref;
}
/* ArenaPokeSeg -- as ArenaPoke, but p must be in seg. */
void ArenaPokeSeg(Arena arena, Seg seg, Ref *p, Ref ref)
{
RefSet summary;
AVERT(Arena, arena);
AVERT(Seg, seg);
AVER(PoolArena(SegPool(seg)) == arena);
AVER(SegBase(seg) <= (Addr)p);
AVER((Addr)p < SegLimit(seg));
/* TODO: Consider checking p's alignment using seg->pool->alignment */
/* ref is arbitrary and can't be checked */
ShieldExpose(arena, seg);
*p = ref;
summary = SegSummary(seg);
summary = RefSetAdd(arena, summary, (Addr)ref);
SegSetSummary(seg, summary);
ShieldCover(arena, seg);
}
/* ArenaRead -- like ArenaPeek, but reference known to be owned by arena */
Ref ArenaRead(Arena arena, Ref *p)
{
Bool b;
Seg seg = NULL; /* suppress "may be used uninitialized" */
AVERT(Arena, arena);
b = SegOfAddr(&seg, arena, (Addr)p);
AVER(b == TRUE);
/* get the possibly fixed reference */
return ArenaPeekSeg(arena, seg, p);
}
/* ArenaWrite -- like ArenaPoke, but reference known to be owned by arena */
void ArenaWrite(Arena arena, Ref *p, Ref ref)
{
Bool b;
Seg seg = NULL; /* suppress "may be used uninitialized" */
AVERT(Arena, arena);
b = SegOfAddr(&seg, arena, (Addr)p);
AVER(b == TRUE);
ArenaPokeSeg(arena, seg, p, ref);
}
/* GlobalsDescribe -- describe the arena globals */

View file

@ -563,37 +563,32 @@ extern void ControlFree(Arena arena, void *base, size_t size);
extern Res ControlDescribe(Arena arena, mps_lib_FILE *stream, Count depth);
/* Peek/Poke
/* Peek/Poke/Read/Write -- read/write possibly through barrier
*
* These are provided so that modules in the MPS can make occasional
* access to client data. They perform the appropriate shield and
* summary manipulations that are necessary.
* access to client data, and to implement a software barrier for
* segments that are not handed out to the mutator. They protect the
* necessary colour, shield and summary invariants.
*
* Note that Peek and Poke can be called with address that may or
* may not be in arena managed memory. */
* Note that Peek and Poke can be called with an address that may or
* may not be in memory managed by arena, whereas Read and Write
* assert this is the case.
*/
/* Peek reads a value */
extern Ref ArenaPeek(Arena arena, Ref *p);
/* Same, but p known to be owned by arena */
extern Ref ArenaRead(Arena arena, Ref *p);
/* Same, but p must be in seg */
extern Ref ArenaPeekSeg(Arena arena, Seg seg, Ref *p);
/* Poke stores a value */
extern void ArenaPoke(Arena arena, Ref *p, Ref ref);
/* Same, but p known to be owned by arena */
extern void ArenaWrite(Arena arena, Ref *p, Ref ref);
/* Same, but p must be in seg */
extern void ArenaPokeSeg(Arena arena, Seg seg, Ref *p, Ref ref);
/* Read/Write
*
* These simulate mutator reads and writes to locations.
* They are effectively a software barrier, and maintain the tricolor
* invariant (hence performing any scanning or color manipulation
* necessary).
*
* Only Read provided right now. */
Ref ArenaRead(Arena arena, Ref *p);
extern Size ArenaReserved(Arena arena);
extern Size ArenaCommitted(Arena arena);
extern Size ArenaSpareCommitted(Arena arena);

View file

@ -74,7 +74,8 @@ typedef struct RefPartStruct {
} RefPartStruct;
/* MRGRefPartRef,MRGRefPartSetRef -- Peek and poke the reference
/* MRGRefPartRef,MRGRefPartSetRef -- read and write the reference
* using the software barrier
*
* Might be more efficient to take a seg, rather than calculate it
* every time.
@ -87,7 +88,7 @@ static Ref MRGRefPartRef(Arena arena, RefPart refPart)
AVER(refPart != NULL);
ref = ArenaPeek(arena, &refPart->ref);
ref = ArenaRead(arena, &refPart->ref);
return ref;
}
@ -102,7 +103,7 @@ static void MRGRefPartSetRef(Arena arena, RefPart refPart, Ref ref)
{
AVER(refPart != NULL);
ArenaPoke(arena, &refPart->ref, ref);
ArenaWrite(arena, &refPart->ref, ref);
}
@ -166,7 +167,7 @@ typedef struct MRGRefSegStruct {
/* forward declarations */
DECLARE_CLASS(Seg, MRGLinkSeg, Seg);
DECLARE_CLASS(Seg, MRGRefSeg, MutatorSeg);
DECLARE_CLASS(Seg, MRGRefSeg, GCSeg);
/* MRGLinkSegCheck -- check a link segment
@ -296,7 +297,7 @@ DEFINE_CLASS(Seg, MRGLinkSeg, klass)
DEFINE_CLASS(Seg, MRGRefSeg, klass)
{
INHERIT_CLASS(klass, MRGRefSeg, MutatorSeg);
INHERIT_CLASS(klass, MRGRefSeg, GCSeg);
SegClassMixInNoSplitMerge(klass); /* no support for this */
klass->size = sizeof(MRGRefSegStruct);
klass->init = MRGRefSegInit;

View file

@ -1247,7 +1247,7 @@ static void gcSegSetWhite(Seg seg, TraceSet white)
AVER_CRITICAL(trseg == seg);
TractSetWhite(tract, BS_BITFIELD(Trace, white));
}
AVER(addr == limit);
AVER_CRITICAL(addr == limit);
seg->white = BS_BITFIELD(Trace, white);
}
@ -1339,7 +1339,7 @@ static void gcSegSetSummary(Seg seg, RefSet summary)
gcseg->summary = summary;
AVER(seg->rankSet != RankSetEMPTY);
AVER_CRITICAL(seg->rankSet != RankSetEMPTY);
}
@ -1371,7 +1371,7 @@ static void gcSegSetRankSummary(Seg seg, RankSet rankSet, RefSet summary)
AVER_CRITICAL(&gcseg->segStruct == seg);
/* rankSet == RankSetEMPTY implies summary == RefSetEMPTY */
AVER(rankSet != RankSetEMPTY || summary == RefSetEMPTY);
AVER_CRITICAL(rankSet != RankSetEMPTY || summary == RefSetEMPTY);
seg->rankSet = BS_BITFIELD(Rank, rankSet);
gcseg->summary = summary;

View file

@ -74,30 +74,11 @@ then ``ArenaDestroy()`` destroys the final pool.
_`.impl.access`: ``mps_message_finalization_ref()`` needs to access
the finalization message to retrieve the reference and then write it
to where the client asks. This must be done carefully, in order to
avoid hitting the write barrier or invalidating collection invariants
such as the segment summary.
avoid invalidating collection invariants such as the segment summary.
_`.impl.invariants`: We protect the invariants by using special
routines ``ArenaRead()`` and ``ArenaPoke()`` to read and write the
reference. This works as long as there's no write-barrier collection.
.. note::
Instead of ``ArenaPoke()``, we could put in an ``ArenaWrite()``
that would be identical to ``ArenaPoke()``, except that it would
``AVER()`` the invariant (or it can just ``AVER()`` that there are
no busy traces unflipped). When we get write-barrier collection,
we could change it to do the real thing, but in the absence of a
write-barrier, it's functionally identical to ``ArenaPoke()``.
Pekka P. Pirinen, 1997-12-09.
.. note::
There is no need to maintain a write barrier on segments belonging
to the MRG pool, as these segments are never given to the mutator.
See job004030_.
.. _job004030: https://www.ravenbrook.com/project/mps/issue/job004030/
_`.impl.invariants`: We protect the invariants by using
``ArenaRead()`` and ``ArenaWrite()`` to read and write the reference
via the software barrier.
External interface