1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-27 07:41:28 -08:00

Merge branch/2018-06-18/mrgseg into the master sources.

Copied from Perforce
 Change: 194453
This commit is contained in:
Gareth Rees 2018-07-05 16:28:15 +01:00
commit 551d35fa0a
20 changed files with 311 additions and 216 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

@ -605,11 +605,11 @@ static void PoolGenAccountForAlloc(PoolGen pgen, Size size)
/* PoolGenAlloc -- allocate a segment in a pool generation
*
* Allocate a GCSeg, attach it to the generation, and update the
* accounting.
* Allocate a segment belong to klass (which must be GCSegClass or a
* subclass), attach it to the generation, and update the accounting.
*/
Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size,
Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass klass, Size size,
ArgList args)
{
LocusPrefStruct pref;
@ -621,7 +621,8 @@ Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size,
AVER(segReturn != NULL);
AVERT(PoolGen, pgen);
AVERT(SegClass, class);
AVERT(SegClass, klass);
AVER(IsSubclass(klass, GCSeg));
AVER(size > 0);
AVERT(ArgList, args);
@ -633,7 +634,7 @@ Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size,
pref.high = FALSE;
pref.zones = zones;
pref.avoid = ZoneSetBlacklist(arena);
res = SegAlloc(&seg, class, &pref, size, pgen->pool, args);
res = SegAlloc(&seg, klass, &pref, size, pgen->pool, args);
if (res != ResOK)
return res;

View file

@ -551,37 +551,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);
@ -651,6 +646,7 @@ extern Bool SegNext(Seg *segReturn, Arena arena, Seg seg);
extern Bool SegNextOfRing(Seg *segReturn, Arena arena, Pool pool, Ring next);
extern void SegSetWhite(Seg seg, TraceSet white);
extern void SegSetGrey(Seg seg, TraceSet grey);
extern void SegFlip(Seg seg, Trace trace);
extern void SegSetRankSet(Seg seg, RankSet rankSet);
extern void SegSetRankAndSummary(Seg seg, RankSet rankSet, RefSet summary);
extern Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi);
@ -684,6 +680,7 @@ extern Bool SegClassCheck(SegClass klass);
DECLARE_CLASS(Inst, SegClass, InstClass);
DECLARE_CLASS(Seg, Seg, Inst);
DECLARE_CLASS(Seg, GCSeg, Seg);
DECLARE_CLASS(Seg, MutatorSeg, GCSeg);
#define SegGCSeg(seg) MustBeA(GCSeg, (seg))
extern void SegClassMixInNoSplitMerge(SegClass klass);

View file

@ -191,6 +191,7 @@ typedef struct SegClassStruct {
SegSetBufferMethod setBuffer; /* set the segment buffer */
SegUnsetBufferMethod unsetBuffer; /* unset the segment buffer */
SegSetGreyMethod setGrey; /* change greyness of segment */
SegFlipMethod flip; /* raise barrier for a flipped trace */
SegSetWhiteMethod setWhite; /* change whiteness of segment */
SegSetRankSetMethod setRankSet; /* change rank set of segment */
SegSetRankSummaryMethod setRankSummary; /* change rank set & summary */

View file

@ -153,6 +153,7 @@ typedef void (*FreeBlockVisitor)(Addr base, Addr limit, Pool pool, void *p);
typedef Res (*SegInitMethod)(Seg seg, Pool pool, Addr base, Size size,
ArgList args);
typedef void (*SegSetGreyMethod)(Seg seg, TraceSet grey);
typedef void (*SegFlipMethod)(Seg seg, Trace trace);
typedef void (*SegSetWhiteMethod)(Seg seg, TraceSet white);
typedef void (*SegSetRankSetMethod)(Seg seg, RankSet rankSet);
typedef void (*SegSetRankSummaryMethod)(Seg seg, RankSet rankSet,

View file

@ -44,7 +44,7 @@ typedef AMC AMCPool;
DECLARE_CLASS(Pool, AMCPool, AMCZPool);
DECLARE_CLASS(Buffer, amcBuf, SegBuf);
DECLARE_CLASS(Seg, amcSeg, GCSeg);
DECLARE_CLASS(Seg, amcSeg, MutatorSeg);
/* amcGenStruct -- pool AMC generation descriptor */
@ -351,7 +351,7 @@ static Res AMCSegDescribe(Inst inst, mps_lib_FILE *stream, Count depth)
DEFINE_CLASS(Seg, amcSeg, klass)
{
INHERIT_CLASS(klass, amcSeg, GCSeg);
INHERIT_CLASS(klass, amcSeg, MutatorSeg);
SegClassMixInNoSplitMerge(klass); /* no support for this (yet) */
klass->instClassStruct.describe = AMCSegDescribe;
klass->instClassStruct.finish = amcSegFinish;

View file

@ -615,7 +615,7 @@ static Res AMSSegDescribe(Inst inst, mps_lib_FILE *stream, Count depth)
DEFINE_CLASS(Seg, AMSSeg, klass)
{
INHERIT_CLASS(klass, AMSSeg, GCSeg);
INHERIT_CLASS(klass, AMSSeg, MutatorSeg);
klass->instClassStruct.describe = AMSSegDescribe;
klass->instClassStruct.finish = AMSSegFinish;
klass->size = sizeof(AMSSegStruct);

View file

@ -172,7 +172,7 @@ DECLARE_CLASS(Pool, AMSPool, AbstractCollectPool);
typedef AMS AMSDebugPool;
DECLARE_CLASS(Pool, AMSDebugPool, AMSPool);
DECLARE_CLASS(Seg, AMSSeg, GCSeg);
DECLARE_CLASS(Seg, AMSSeg, MutatorSeg);
#endif /* poolams_h */

View file

@ -111,10 +111,7 @@ typedef AWL AWLPool;
DECLARE_CLASS(Pool, AWLPool, AbstractCollectPool);
/* AWLSegStruct -- AWL segment subclass
*
* Subclass of GCSeg
*/
/* AWLSegStruct -- AWL segment subclass */
#define AWLSegSig ((Sig)0x519A3759) /* SIGnature AWL SeG */
@ -134,7 +131,7 @@ typedef struct AWLSegStruct {
Sig sig; /* <code/misc.h#sig> */
} AWLSegStruct, *AWLSeg;
DECLARE_CLASS(Seg, AWLSeg, GCSeg);
DECLARE_CLASS(Seg, AWLSeg, MutatorSeg);
ATTRIBUTE_UNUSED
static Bool AWLSegCheck(AWLSeg awlseg)
@ -277,7 +274,7 @@ static void AWLSegFinish(Inst inst)
DEFINE_CLASS(Seg, AWLSeg, klass)
{
INHERIT_CLASS(klass, AWLSeg, GCSeg);
INHERIT_CLASS(klass, AWLSeg, MutatorSeg);
SegClassMixInNoSplitMerge(klass); /* no support for this (yet) */
klass->instClassStruct.finish = AWLSegFinish;
klass->size = sizeof(AWLSegStruct);

View file

@ -31,7 +31,7 @@ typedef struct LOStruct {
typedef LO LOPool;
#define LOPoolCheck LOCheck
DECLARE_CLASS(Pool, LOPool, AbstractSegBufPool);
DECLARE_CLASS(Seg, LOSeg, GCSeg);
DECLARE_CLASS(Seg, LOSeg, MutatorSeg);
/* forward declaration */
@ -71,7 +71,7 @@ static void loSegWalk(Seg seg, Format format, FormattedObjectsVisitor f,
DEFINE_CLASS(Seg, LOSeg, klass)
{
INHERIT_CLASS(klass, LOSeg, GCSeg);
INHERIT_CLASS(klass, LOSeg, MutatorSeg);
SegClassMixInNoSplitMerge(klass);
klass->instClassStruct.finish = loSegFinish;
klass->size = sizeof(LOSegStruct);

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);
}

View file

@ -47,7 +47,7 @@ typedef SNC SNCPool;
#define SNCPoolCheck SNCCheck
DECLARE_CLASS(Pool, SNCPool, AbstractSegBufPool);
DECLARE_CLASS(Seg, SNCSeg, GCSeg);
DECLARE_CLASS(Seg, SNCSeg, MutatorSeg);
DECLARE_CLASS(Buffer, SNCBuf, RankBuf);
static Bool SNCCheck(SNC snc);
static void sncPopPartialSegChain(SNC snc, Buffer buf, Seg upTo);
@ -171,7 +171,7 @@ DEFINE_CLASS(Buffer, SNCBuf, klass)
/* SNCSegStruct -- SNC segment subclass
*
* This subclass of GCSeg links segments in chains.
* This subclass of MutatorSeg links segments in chains.
*/
#define SNCSegSig ((Sig)0x51954C59) /* SIGSNCSeG */
@ -247,7 +247,7 @@ static void sncSegFinish(Inst inst)
DEFINE_CLASS(Seg, SNCSeg, klass)
{
INHERIT_CLASS(klass, SNCSeg, GCSeg);
INHERIT_CLASS(klass, SNCSeg, MutatorSeg);
SegClassMixInNoSplitMerge(klass); /* no support for this (yet) */
klass->instClassStruct.finish = sncSegFinish;
klass->size = sizeof(SNCSegStruct);

View file

@ -7,15 +7,8 @@
*
* PURPOSE
*
* .purpose: This is the implementation of the generic segment interface.
* It defines the interface functions and two useful segment classes:
* .purpose.class.seg: Class Seg is a class which is as simple
* as efficiency demands permit. (It includes fields for storing colour
* for efficiency). It may be subclassed by clients of the module.
* .purpose.class.seg-gc: Class GCSeg is a concrete class support all
* all current GC features, and providing full backwards compatibility
* with "old-style" segments. It may be subclassed by clients of the
* module.
* .purpose: This is the implementation of the generic segment
* interface and the segment classes Seg, GCSeg and MutatorSeg.
*/
#include "tract.h"
@ -113,7 +106,7 @@ void SegFree(Seg seg)
/* SegInit -- initialize a segment */
static Res SegAbsInit(Seg seg, Pool pool, Addr base, Size size, ArgList args)
static Res segAbsInit(Seg seg, Pool pool, Addr base, Size size, ArgList args)
{
Arena arena;
Addr addr, limit;
@ -185,7 +178,7 @@ static Res SegInit(Seg seg, SegClass klass, Pool pool, Addr base, Size size, Arg
/* SegFinish -- finish a segment */
static void SegAbsFinish(Inst inst)
static void segAbsFinish(Inst inst)
{
Seg seg = MustBeA(Seg, inst);
Arena arena;
@ -259,6 +252,22 @@ void SegSetGrey(Seg seg, TraceSet grey)
greyness, or if the segment doesn't contain any references. */
if (grey != SegGrey(seg) && SegRankSet(seg) != RankSetEMPTY)
Method(Seg, seg, setGrey)(seg, grey);
EVENT3(SegSetGrey, PoolArena(SegPool(seg)), seg, grey);
}
/* SegFlip -- update barriers for trace that's about to flip */
void SegFlip(Seg seg, Trace trace)
{
AVERT(Seg, seg);
AVERT(Trace, trace);
/* Don't dispatch to the class method unless the segment is grey for
the trace that's about to flip, and contains references. */
if (TraceSetIsMember(SegGrey(seg), trace) && SegRankSet(seg) != RankSetEMPTY)
Method(Seg, seg, flip)(seg, trace);
}
@ -385,7 +394,7 @@ Addr SegBufferScanLimit(Seg seg)
/* SegDescribe -- describe a segment */
Res SegAbsDescribe(Inst inst, mps_lib_FILE *stream, Count depth)
static Res segAbsDescribe(Inst inst, mps_lib_FILE *stream, Count depth)
{
Seg seg = CouldBeA(Seg, inst);
Res res;
@ -929,6 +938,16 @@ static void segNoSetGrey(Seg seg, TraceSet grey)
}
/* segTrivFlip -- ignore trace that's about to flip */
static void segTrivFlip(Seg seg, Trace trace)
{
AVERT(Seg, seg);
AVERT(Trace, trace);
AVER(seg->rankSet != RankSetEMPTY);
}
/* segNoSetWhite -- non-method to change the whiteness of a segment */
static void segNoSetWhite(Seg seg, TraceSet white)
@ -1308,7 +1327,7 @@ static void segNoGreyen(Seg seg, Trace trace)
}
/* segNoGreyen -- blacken method for non-GC segs */
/* segNoBlacken -- blacken method for non-GC segs */
static void segNoBlacken(Seg seg, TraceSet traceSet)
{
@ -1369,9 +1388,7 @@ static void segTrivWalk(Seg seg, Format format, FormattedObjectsVisitor f,
}
/* Class GCSeg -- Segment class with GC support
*/
/* Class GCSeg -- collectable segment class */
/* GCSegCheck -- check the integrity of a GCSeg */
@ -1520,31 +1537,39 @@ static void gcSegSetGreyInternal(Seg seg, TraceSet oldGrey, TraceSet grey)
/* gcSegSetGrey -- GCSeg method to change the greyness of a segment
*
* Sets the segment greyness to the trace set grey and adjusts
* the shielding on the segment appropriately.
* Sets the segment greyness to the trace set grey.
*/
static void gcSegSetGrey(Seg seg, TraceSet grey)
{
GCSeg gcseg;
AVERT_CRITICAL(Seg, seg); /* .seg.method.check */
AVERT_CRITICAL(TraceSet, grey); /* .seg.method.check */
AVER_CRITICAL(seg->rankSet != RankSetEMPTY);
gcSegSetGreyInternal(seg, seg->grey, grey); /* do the work */
}
/* mutatorSegSetGrey -- MutatorSeg method to change greyness of segment
*
* As gcSegSetGrey, but also raise or lower the read barrier.
*/
static void mutatorSegSetGrey(Seg seg, TraceSet grey)
{
TraceSet oldGrey, flippedTraces;
Arena arena;
AVERT_CRITICAL(Seg, seg); /* .seg.method.check */
AVERT_CRITICAL(TraceSet, grey); /* .seg.method.check */
AVER(seg->rankSet != RankSetEMPTY);
gcseg = SegGCSeg(seg);
AVERT_CRITICAL(GCSeg, gcseg);
AVER_CRITICAL(&gcseg->segStruct == seg);
UNUSED(gcseg);
arena = PoolArena(SegPool(seg));
oldGrey = seg->grey;
gcSegSetGreyInternal(seg, oldGrey, grey); /* do the work */
NextMethod(Seg, MutatorSeg, setGrey)(seg, grey);
/* The read barrier is raised when the segment is grey for */
/* some _flipped_ trace, i.e., is grey for a trace for which */
/* the mutator is black. */
arena = PoolArena(SegPool(seg));
flippedTraces = arena->flippedTraces;
if (TraceSetInter(oldGrey, flippedTraces) == TraceSetEMPTY) {
if (TraceSetInter(grey, flippedTraces) != TraceSetEMPTY)
@ -1553,8 +1578,31 @@ static void gcSegSetGrey(Seg seg, TraceSet grey)
if (TraceSetInter(grey, flippedTraces) == TraceSetEMPTY)
ShieldLower(arena, seg, AccessREAD);
}
}
EVENT3(SegSetGrey, arena, seg, grey);
/* mutatorSegFlip -- update barriers for a trace that's about to flip */
static void mutatorSegFlip(Seg seg, Trace trace)
{
TraceSet flippedTraces;
Arena arena;
NextMethod(Seg, MutatorSeg, flip)(seg, trace);
arena = PoolArena(SegPool(seg));
flippedTraces = arena->flippedTraces;
AVER(!TraceSetIsMember(flippedTraces, trace));
/* Raise the read barrier if the segment was not grey for any
currently flipped trace. */
if (TraceSetInter(SegGrey(seg), flippedTraces) == TraceSetEMPTY) {
ShieldRaise(arena, seg, AccessREAD);
} else {
/* If the segment is grey for some currently flipped trace then
the read barrier must already have been raised, either in this
method or in mutatorSegSetGrey. */
AVER(SegSM(seg) & AccessREAD);
}
}
@ -1588,19 +1636,13 @@ 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);
}
/* gcSegSetRankSet -- GCSeg method to set the rank set of a segment
*
* If the rank set is made non-empty then the segment's summary is
* now a subset of the mutator's (which is assumed to be RefSetUNIV)
* so the write barrier must be imposed on the segment. If the
* rank set is made empty then there are no longer any references
* on the segment so the barrier is removed.
*
* The caller must set the summary to empty before setting the rank
* set to empty. The caller must set the rank set to non-empty before
@ -1609,38 +1651,62 @@ static void gcSegSetWhite(Seg seg, TraceSet white)
static void gcSegSetRankSet(Seg seg, RankSet rankSet)
{
GCSeg gcseg;
RankSet oldRankSet;
Arena arena;
AVERT_CRITICAL(Seg, seg); /* .seg.method.check */
AVERT_CRITICAL(RankSet, rankSet); /* .seg.method.check */
AVER_CRITICAL(rankSet == RankSetEMPTY
|| RankSetIsSingle(rankSet)); /* .seg.method.check */
gcseg = SegGCSeg(seg);
AVERT_CRITICAL(GCSeg, gcseg);
AVER_CRITICAL(&gcseg->segStruct == seg);
arena = PoolArena(SegPool(seg));
oldRankSet = seg->rankSet;
seg->rankSet = BS_BITFIELD(Rank, rankSet);
}
/* mutatorSegSetRankSet -- MutatorSeg method to set rank set of segment
*
* As gcSegSetRankSet, but also sets or clears the write barrier on
* the segment.
*
* If the rank set is made non-empty then the segment's summary is now
* a subset of the mutator's (which is assumed to be RefSetUNIV) so
* the write barrier must be imposed on the segment. If the rank set
* is made empty then there are no longer any references on the
* segment so the barrier is removed.
*/
static void mutatorSegSetRankSet(Seg seg, RankSet rankSet)
{
RankSet oldRankSet;
AVERT_CRITICAL(Seg, seg); /* .seg.method.check */
oldRankSet = seg->rankSet;
NextMethod(Seg, MutatorSeg, setRankSet)(seg, rankSet);
if (oldRankSet == RankSetEMPTY) {
if (rankSet != RankSetEMPTY) {
AVER(gcseg->summary == RefSetEMPTY);
ShieldRaise(arena, seg, AccessWRITE);
AVER_CRITICAL(SegGCSeg(seg)->summary == RefSetEMPTY);
ShieldRaise(PoolArena(SegPool(seg)), seg, AccessWRITE);
}
} else {
if (rankSet == RankSetEMPTY) {
AVER(gcseg->summary == RefSetEMPTY);
ShieldLower(arena, seg, AccessWRITE);
AVER_CRITICAL(SegGCSeg(seg)->summary == RefSetEMPTY);
ShieldLower(PoolArena(SegPool(seg)), seg, AccessWRITE);
}
}
}
static void gcSegSyncWriteBarrier(Seg seg, Arena arena)
/* mutatorSegSyncWriteBarrier -- raise or lower write barrier on segment
*
* We only need to raise the write barrier if the segment contains
* references, and its summary is strictly smaller than the summary of
* the unprotectable data (that is, the mutator). We don't maintain
* such a summary, assuming that the mutator can access all
* references, so its summary is RefSetUNIV.
*/
static void mutatorSegSyncWriteBarrier(Seg seg)
{
Arena arena = PoolArena(SegPool(seg));
/* Can't check seg -- this function enforces invariants tested by SegCheck. */
if (SegSummary(seg) == RefSetUNIV)
ShieldLower(arena, seg, AccessWRITE);
@ -1649,40 +1715,41 @@ static void gcSegSyncWriteBarrier(Seg seg, Arena arena)
}
/* gcSegSetSummary -- GCSeg method to change the summary on a segment
*
* In fact, we only need to raise the write barrier if the
* segment contains references, and its summary is strictly smaller
* than the summary of the unprotectable data (i.e. the mutator).
* We don't maintain such a summary, assuming that the mutator can
* access all references, so its summary is RefSetUNIV.
*/
/* gcSegSetSummary -- GCSeg method to change the summary on a segment */
static void gcSegSetSummary(Seg seg, RefSet summary)
{
GCSeg gcseg;
Arena arena;
AVERT_CRITICAL(Seg, seg); /* .seg.method.check */
gcseg = SegGCSeg(seg);
AVERT_CRITICAL(GCSeg, gcseg);
AVER_CRITICAL(&gcseg->segStruct == seg);
arena = PoolArena(SegPool(seg));
gcseg->summary = summary;
AVER(seg->rankSet != RankSetEMPTY);
gcSegSyncWriteBarrier(seg, arena);
AVER_CRITICAL(seg->rankSet != RankSetEMPTY);
}
/* mutatorSegSetSummary -- MutatorSeg method to change summary on segment
*
* As gcSegSetSummary, but also raise or lower the write barrier.
*/
static void mutatorSegSetSummary(Seg seg, RefSet summary)
{
NextMethod(Seg, MutatorSeg, setSummary)(seg, summary);
mutatorSegSyncWriteBarrier(seg);
}
/* gcSegSetRankSummary -- GCSeg method to set both rank set and summary */
static void gcSegSetRankSummary(Seg seg, RankSet rankSet, RefSet summary)
{
GCSeg gcseg;
Arena arena;
AVERT_CRITICAL(Seg, seg); /* .seg.method.check */
AVERT_CRITICAL(RankSet, rankSet); /* .seg.method.check */
@ -1693,15 +1760,17 @@ static void gcSegSetRankSummary(Seg seg, RankSet rankSet, RefSet summary)
AVER_CRITICAL(&gcseg->segStruct == seg);
/* rankSet == RankSetEMPTY implies summary == RefSetEMPTY */
AVER(rankSet != RankSetEMPTY || summary == RefSetEMPTY);
arena = PoolArena(SegPool(seg));
AVER_CRITICAL(rankSet != RankSetEMPTY || summary == RefSetEMPTY);
seg->rankSet = BS_BITFIELD(Rank, rankSet);
gcseg->summary = summary;
}
static void mutatorSegSetRankSummary(Seg seg, RankSet rankSet, RefSet summary)
{
NextMethod(Seg, MutatorSeg, setRankSummary)(seg, rankSet, summary);
if (rankSet != RankSetEMPTY)
gcSegSyncWriteBarrier(seg, arena);
mutatorSegSyncWriteBarrier(seg);
}
@ -1997,8 +2066,8 @@ Bool SegClassCheck(SegClass klass)
CHECKL(FUNCHECK(klass->walk));
/* Check that segment classes override sets of related methods. */
CHECKL((klass->init == SegAbsInit)
== (klass->instClassStruct.finish == SegAbsFinish));
CHECKL((klass->init == segAbsInit)
== (klass->instClassStruct.finish == segAbsFinish));
CHECKL((klass->init == gcSegInit)
== (klass->instClassStruct.finish == gcSegFinish));
CHECKL((klass->merge == segTrivMerge) == (klass->split == segTrivSplit));
@ -2021,15 +2090,16 @@ DEFINE_CLASS(Inst, SegClass, klass)
DEFINE_CLASS(Seg, Seg, klass)
{
INHERIT_CLASS(&klass->instClassStruct, Seg, Inst);
klass->instClassStruct.describe = SegAbsDescribe;
klass->instClassStruct.finish = SegAbsFinish;
klass->instClassStruct.describe = segAbsDescribe;
klass->instClassStruct.finish = segAbsFinish;
klass->size = sizeof(SegStruct);
klass->init = SegAbsInit;
klass->init = segAbsInit;
klass->setSummary = segNoSetSummary;
klass->buffer = segNoBuffer;
klass->setBuffer = segNoSetBuffer;
klass->unsetBuffer = segNoUnsetBuffer;
klass->setGrey = segNoSetGrey;
klass->flip = segTrivFlip;
klass->setWhite = segNoSetWhite;
klass->setRankSet = segNoSetRankSet;
klass->setRankSummary = segNoSetRankSummary;
@ -2083,6 +2153,22 @@ DEFINE_CLASS(Seg, GCSeg, klass)
}
/* MutatorSegClass -- collectable mutator segment class definition */
typedef SegClassStruct MutatorSegClassStruct;
DEFINE_CLASS(Seg, MutatorSeg, klass)
{
INHERIT_CLASS(klass, MutatorSeg, GCSeg);
klass->setSummary = mutatorSegSetSummary;
klass->setGrey = mutatorSegSetGrey;
klass->flip = mutatorSegFlip;
klass->setRankSet = mutatorSegSetRankSet;
klass->setRankSummary = mutatorSegSetRankSummary;
AVERT(SegClass, klass);
}
/* SegClassMixInNoSplitMerge -- Mix-in for unsupported merge
*
* Classes which don't support segment splitting and merging

View file

@ -590,15 +590,11 @@ static Res traceFlip(Trace trace)
/* drj 2003-02-19) */
/* Now that the mutator is black we must prevent it from reading */
/* 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. */
/* grey objects so that it can't obtain white pointers. */
for(rank = RankMIN; rank < RankLIMIT; ++rank)
RING_FOR(node, ArenaGreyRing(arena, rank), nextNode) {
Seg seg = SegOfGreyRing(node);
if(TraceSetInter(SegGrey(seg), arena->flippedTraces) == TraceSetEMPTY
&& TraceSetIsMember(SegGrey(seg), trace))
ShieldRaise(arena, seg, AccessREAD);
SegFlip(seg, trace);
}
/* @@@@ When write barrier collection is implemented, this is where */

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

View file

@ -350,7 +350,10 @@ Segments
--------
_`.seg.class`: AMC allocates segments of class ``AMCSegClass``, which
is a subclass of ``GCSegClass``.
is a subclass of ``MutatorSegClass`` (see
design.mps.seg.over.hierarchy.mutatorseg_).
.. _design.mps.seg.over.hierarchy.mutatorseg: seg#over-hierarchy-mutatorseg
_`.seg.gen`: AMC organizes the segments it manages into generations.

View file

@ -112,9 +112,9 @@ _`.poolstruct`: The class specific pool structure is::
}
_`.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
pool are instances of this class, and are of type ``AWLSeg``, for
a subclass of ``MutatorSegClass`` (see
design.mps.seg.over.hierarchy.mutatorseg_). All segments allocated by
the pool are instances of this class, and are of type ``AWLSeg``, for
which the structure is::
struct AWLSegStruct {
@ -132,7 +132,7 @@ which the structure is::
Sig sig; /* <code/misc.h#sig> */
}
.. _design.mps.seg.over.hierarchy.gcseg: seg#over-hierarchy-gcseg
.. _design.mps.seg.over.hierarchy.mutatorseg: seg#over-hierarchy-mutatorseg
_`.awlseg.bt`: The ``mark``, ``alloc``, and ``scanned`` fields are
bit-tables (see design.mps.bt_). Each bit in the table corresponds to

View file

@ -121,8 +121,12 @@ _`.poolstruct`: The class specific pool structure is::
Sig sig; /* <code/misc.h#sig> */
} LOStruct;
_`.loseg`: Every segment is an instance of segment class ``LOSegClass``, a
subclass of ``GCSegClass``, and is an object of type ``LOSegStruct``.
_`.loseg`: Every segment is an instance of segment class
``LOSegClass``, a subclass of ``MutatorSegClass`` (see
design.mps.seg.over.hierarchy.mutatorseg_), and is an object of type
``LOSegStruct``.
.. _design.mps.seg.over.hierarchy.mutatorseg: seg#over-hierarchy-mutatorseg
_`.loseg.purpose`: The purpose of the ``LOSeg`` structure is to
associate the bit tables used for recording allocation and mark

View file

@ -336,7 +336,7 @@ the latter will be used to store the link parts of guardians (see
one of each class, by the function ``MRGSegPairCreate()``. Each
segment contains a link to its pair.
_`.mrgseg.ref`: ``MRGRefSegClass`` is a subclass of ``GCSegClass``.
_`.mrgseg.ref`: ``MRGRefSegClass`` is a subclass of ``MutatorSegClass``.
Instances are of type ``MRGRefSeg``, and contain:
- _`.mrgseg.ref.mrgring`: a field for the ring of ref part segments in

View file

@ -51,9 +51,15 @@ 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.
_`.over.hierarchy.gcseg`: ``GCSeg`` is a subclass of ``Seg`` which
implements garbage collection, including buffering and the ability to
be linked onto the grey ring. It does not implement hardware barriers,
and so can only be used with software barriers, for example internally
in the MPS.
_`.over.hierarchy.mutatorseg`: ``MutatorSeg`` is a subclass of
``GCSeg`` implementing hardware barriers. It is suitable for handing
out to the mutator.
Data Structure
@ -345,6 +351,12 @@ in the walk. Segment classes need not provide this method. This
method is called by the genetic function ``SegWalk()``, which is
called by the heap walker ``mps_arena_formatted_objects_walk()``.
``typedef void (*SegFlipMethod)(Seg seg, Trace trace)``
_`.method.flip`: Raise the read barrier, if necessary, for a trace
that's about to flip and for which the segment is grey and potentially
contains references.
Splitting and merging
.....................