1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-20 11:33:09 -08:00
emacs/mps/src/poolmrg.c
David Jones fb987e4bdd Should use arenaalign, not vmalign
Copied from Perforce
 Change: 16536
 ServerID: perforce.ravenbrook.com
1997-02-11 16:27:53 +00:00

537 lines
13 KiB
C

/* impl.c.poolmrg
*
* MANUAL RANK GUARDIAN POOL
*
* $HopeName: MMsrc!poolmrg.c(trunk.1) $
* Copyright(C) 1995,1997 Harlequin Group, all rights reserved
*
* READERSHIP
*
* Any MPS developer. It will help to read design.mps.poolmrg.
*
* DESIGN
*
* See design.mps.poolmrg.
*
* .update.wasold: At the moment the fix interface provides no way for
* the caller to determine whether the referent was in old space.
* This is necessary for finalization. For now, the callsite to fix
* (which will need to be changed when the fix interface changes) bears
* this tag.
*
* .access.exact: There is no way to to determine the "correct" rank to
* scan at when an access fault is taken (we should use whatever rank the
* tracer is at). We default to scanning at the RankEXACT.
*
* .improve.rank: At the moment, the pool is a guardian for the final
* rank. It could be generalized to be a guardian for an arbitrary
* rank (a guardian for RankEXACT would tell you if the object was
* ambiguously referenced, for example). The code that would need to be
* modified bears this tag.
*/
#include "mpm.h"
#include "poolmrg.h"
SRCID(poolmrg, "$HopeName: MMsrc!poolmrg.c(trunk.1) $");
#define MRGSig ((Sig)0x519B0349)
typedef struct MRGStruct {
PoolStruct poolStruct; /* generic pool structure */
RingStruct entry; /* design.mps.poolmrg.poolstruct.entry */
RingStruct exit; /* design.mps.poolmrg.poolstruct.exit */
RingStruct free; /* design.mps.poolmrg.poolstruct.free */
RingStruct group; /* design.mps.poolmrg.poolstruct.group */
Size extendBy; /* design.mps.poolmrg.extend */
Sig sig; /* impl.h.mps.sig */
} MRGStruct;
#define PoolPoolMRG(pool) PARENT(MRGStruct, poolStruct, pool)
static Pool MRGPool(MRG mrg);
/* design.mps.poolmrg.guardian.assoc */
static Index indexOfRefPart(Addr a, Space space)
{
Seg seg;
Bool b;
Addr base;
Addr *pbase, *pa;
b = SegOfAddr(&seg, space, a);
AVER(b);
base = SegBase(space, seg);
pbase = (Addr *)base;
pa = (Addr *)a;
return pa - pbase;
}
/* design.mps.poolmrg.guardian.assoc */
static Index indexOfLinkPart(Addr a, Space space)
{
Seg seg;
Bool b;
Addr base ;
RingStruct *pbase, *pa;
b = SegOfAddr(&seg, space, a);
AVER(b);
base = SegBase(space, seg);
pbase = (RingStruct *)base;
pa = (RingStruct *)a;
return pa - pbase;
}
#define MRGGroupSig ((Sig)0x5193499b)
typedef struct MRGGroupStruct {
Sig sig; /* impl.h.misc.sig */
RingStruct group; /* design.mps.poolmrg.group.group */
TraceSet grey; /* design.mps.poolmrg.group.grey */
Seg refseg; /* design.mps.poolmrg.group.segs */
Seg linkseg; /* design.mps.poolmrg.group.segs */
} MRGGroupStruct;
typedef MRGGroupStruct *MRGGroup;
static void MRGGroupDestroy(MRGGroup group, MRG mrg)
{
Pool pool;
pool = MRGPool(mrg);
RingRemove(&group->group);
PoolSegFree(pool, group->refseg);
PoolSegFree(pool, group->linkseg);
SpaceFree(PoolSpace(pool), (Addr)group, (Size)sizeof(MRGGroupStruct));
}
static Res MRGGroupCreate(MRGGroup *groupReturn, MRG mrg)
{
Addr base;
MRGGroup group;
Pool pool;
Res res;
RingStruct *linkpart;
Seg linkseg;
Seg refseg;
Size linksegsize;
Space space;
Addr *refpart;
Word i, guardians;
void *v;
pool = MRGPool(mrg);
space = PoolSpace(pool);
res = SpaceAlloc(&v, space, (Size)sizeof(MRGGroupStruct));
if(res != ResOK)
goto failSpaceAlloc;
group = v;
res = PoolSegAlloc(&refseg, pool, mrg->extendBy);
if(res != ResOK)
goto failRefSegAlloc;
guardians = mrg->extendBy / sizeof(Addr); /* per seg */
linksegsize = guardians * sizeof(RingStruct);
linksegsize = SizeAlignUp(linksegsize, ArenaAlign(space));
res = PoolSegAlloc(&linkseg, pool, linksegsize);
if(res != ResOK)
goto failLinkSegAlloc;
/* Link Segment is coerced to an array of RingStructs, each one */
/* is appended to the free Ring. */
/* The ref part of each guardian is cleared. */
AVER(guardians > 0);
base = SegBase(space, linkseg);
linkpart = (RingStruct *)base;
refpart = (Addr *)SegBase(space, refseg);
for(i=0; i<guardians; ++i) {
RingInit(&linkpart[i]);
RingAppend(&mrg->free, &linkpart[i]);
refpart[i] = 0;
}
AVER((Addr)(&linkpart[i]) <= SegLimit(space, linkseg));
AVER((Addr)(&refpart[i]) <= SegLimit(space, refseg));
refseg->rank = RankFINAL;
group->refseg = refseg;
group->linkseg = linkseg;
refseg->p = group;
linkseg->p = group;
group->grey = TraceSetEMPTY;
RingInit(&group->group);
RingAppend(&mrg->group, &group->group);
group->sig = MRGGroupSig;
return ResOK;
failLinkSegAlloc:
PoolSegFree(pool, refseg);
failRefSegAlloc:
SpaceFree(space, (Addr)group, (Size)sizeof(MRGGroupStruct));
failSpaceAlloc:
return res;
}
static Res MRGGroupScan(ScanState ss, MRGGroup group, MRG mrg)
{
Addr base;
Res res;
Space space;
Addr *refpart;
Word guardians, i;
int wasOld = 0;
space = PoolSpace(MRGPool(mrg));
ShieldExpose(space, group->refseg);
guardians = mrg->extendBy / sizeof(Addr); /* per seg */
AVER(guardians > 0);
base = SegBase(space, group->refseg);
refpart = (Addr *)base;
TRACE_SCAN_BEGIN(ss) {
for(i=0; i<guardians; ++i) {
if(!TRACE_FIX1(ss, refpart[i])) continue;
res = TRACE_FIX2(ss, &refpart[i]); /* .update.wasold */
if(res != ResOK) {
return res;
}
if(wasOld && ss->rank == RankFINAL) { /* .improve.rank */
RingStruct *linkpart =
(RingStruct *)SegBase(space, group->linkseg);
RingRemove(&linkpart[i]);
RingAppend(&mrg->exit, &linkpart[i]);
}
}
} TRACE_SCAN_END(ss);
group->grey = TraceSetDelete(group->grey, ss->traceId);
ShieldLower(space, group->refseg, AccessREAD | AccessWRITE);
ShieldCover(space, group->refseg);
return ResOK;
}
static Bool MRGCheck(MRG mrg);
static Res MRGInit(Pool pool, va_list args)
{
MRG mrg = PoolPoolMRG(pool);
UNUSED(args);
RingInit(&mrg->entry);
RingInit(&mrg->exit);
RingInit(&mrg->free);
RingInit(&mrg->group);
mrg->extendBy = ArenaAlign(PoolSpace(pool));
mrg->sig = MRGSig;
AVERT(MRG, mrg);
return ResOK;
}
static void MRGFinish(Pool pool)
{
MRG mrg;
Ring node;
AVERT(Pool, pool);
mrg = PoolPoolMRG(pool);
AVERT(MRG, mrg);
node = RingNext(&mrg->group);
while(node != &mrg->group) {
Ring next = RingNext(node);
MRGGroup group = RING_ELT(MRGGroup, group, node);
MRGGroupDestroy(group, mrg);
node = next;
}
mrg->sig = SigInvalid;
}
static Pool MRGPool(MRG mrg)
{
AVERT(MRG, mrg);
return &mrg->poolStruct;
}
static Res MRGAlloc(Addr *pReturn, Pool pool, Size size)
{
Addr *refpart;
Bool b;
Index gi;
MRG mrg;
MRGGroup group;
MRGGroup junk; /* .group.useless */
Res res;
Ring f;
Seg seg;
Space space;
AVERT(Pool, pool);
mrg = PoolPoolMRG(pool);
AVERT(MRG, mrg);
AVER(pReturn != NULL);
AVER(size == sizeof(Addr)); /* design.mps.poolmrg.alloc.one-size */
space = PoolSpace(pool);
f = RingNext(&mrg->free);
/* design.mps.poolmrg.alloc.grow */
if(f == &mrg->free) { /* (Ring has no elements) */
res = MRGGroupCreate(&junk, mrg); /* .group.useless: group isn't used */
if(res != ResOK) {
return res;
}
f = RingNext(&mrg->free);
}
AVER(f != &mrg->free);
/* design.mps.poolmrg.alloc.pop */
RingRemove(f);
RingAppend(&mrg->entry, f);
gi = indexOfLinkPart((Addr)f, space);
b = SegOfAddr(&seg, space, (Addr)f);
AVER(b);
group = seg->p;
refpart = (Addr *)SegBase(space, group->refseg);
/* design.mps.poolmrg.guardian.ref.alloc */
*pReturn = (Addr)(&refpart[gi]);
return ResOK;
}
static void MRGFree(Pool pool, Addr old, Size size)
{
MRG mrg;
Index gi;
Space space;
Seg seg;
MRGGroup group;
Bool b;
RingStruct *linkpart;
AVERT(Pool, pool);
mrg = PoolPoolMRG(pool);
AVERT(MRG, mrg);
AVER(old != (Addr)0);
AVER(size == sizeof(Addr));
space = PoolSpace(pool);
b = SegOfAddr(&seg, space, old);
AVER(b);
group = seg->p;
linkpart = (RingStruct *)SegBase(space, group->linkseg);
/* design.mps.poolmrg.guardian.ref.free */
gi = indexOfRefPart(old, space);
AVERT(Ring, &linkpart[gi]);
RingRemove(&linkpart[gi]);
RingAppend(&mrg->free, &linkpart[gi]);
*(Addr *)old = 0; /* design.mps.poolmrg.free.overwrite */
}
static Res MRGDescribe(Pool pool, mps_lib_FILE *stream)
{
MRG mrg;
Ring r;
Space space;
Bool b;
MRGGroup group;
Index gi;
Seg seg;
Addr *refpart;
AVERT(Pool, pool);
mrg = PoolPoolMRG(pool);
AVERT(MRG, mrg);
/* Cannot check stream */
space = PoolSpace(pool);
WriteF(stream, " extendBy $W\n", mrg->extendBy, NULL);
WriteF(stream, " Entry queue:\n", NULL);
RING_FOR(r, &mrg->entry) {
b = SegOfAddr(&seg, space, (Addr)r);
AVER(b);
group = seg->p;
refpart = (Addr *)SegBase(space, group->refseg);
gi = indexOfLinkPart((Addr)r, space);
WriteF(stream,
" at $A ref $A\n",
(WriteFA)&refpart[gi], (WriteFA)refpart[gi],
NULL);
}
WriteF(stream, " Exit queue:\n", NULL);
RING_FOR(r, &mrg->exit) {
b = SegOfAddr(&seg, space, (Addr)r);
AVER(b);
group = seg->p;
refpart = (Addr *)SegBase(space, group->refseg);
gi = indexOfLinkPart((Addr)r, space);
WriteF(stream,
" at $A ref $A\n",
(WriteFA)&refpart[gi], (WriteFA)refpart[gi],
NULL);
}
return ResOK;
}
static void MRGGrey(Pool pool, Space space, TraceId ti)
{
MRG mrg;
Ring r;
AVERT(Pool, pool);
mrg = PoolPoolMRG(pool);
AVERT(MRG, mrg);
AVERT(Space, space);
AVERT(TraceId, ti);
RING_FOR(r, &mrg->group) {
MRGGroup group;
group = RING_ELT(MRGGroup, group, r);
group->grey = TraceSetAdd(group->grey, ti);
ShieldRaise(space, group->refseg, AccessREAD | AccessWRITE);
}
}
static Res MRGScan(ScanState ss, Pool pool, Bool *finishedReturn)
{
MRG mrg;
Res res;
AVERT(ScanState, ss);
AVERT(Pool, pool);
mrg = PoolPoolMRG(pool);
AVERT(MRG, mrg);
AVER(finishedReturn != NULL);
if(ss->rank == RankFINAL) {
Ring r;
RING_FOR(r, &mrg->group) {
MRGGroup group;
group = RING_ELT(MRGGroup, group, r);
if(TraceSetIsMember(group->grey, ss->traceId)) {
res = MRGGroupScan(ss, group, mrg);
if(res != ResOK) {
return res;
}
*finishedReturn = FALSE;
return ResOK;
}
}
}
*finishedReturn = TRUE;
return ResOK;
}
/* .amc.copy: This code is an almost exact copy of the analogous
* method in impl.c.amc. This is worrying.
*/
static void MRGAccess(Pool pool, Seg seg, AccessSet mode)
{
Space space;
MRG mrg;
MRGGroup group;
Res res;
ScanStateStruct ss;
AVERT(Pool, pool);
mrg = PoolPoolMRG(pool);
AVERT(MRG, mrg);
AVERT(Seg, seg);
AVER(seg->pool == pool);
/* Cannot check AccessSet */
space = PoolSpace(pool);
group = (MRGGroup)seg->p;
ss.fix = TraceFix;
ss.zoneShift = space->zoneShift;
ss.summary = RefSetEmpty;
ss.space = space;
ss.sig = ScanStateSig;
ss.rank = RankEXACT; /* .access.exact */
ss.weakSplat = (Addr)0xadd4badd;
/* impl.c.amc.access.multi (!) */
for(ss.traceId = 0; ss.traceId < TRACE_MAX; ++ss.traceId) {
if(TraceSetIsMember(space->busyTraces, ss.traceId)) {
ss.condemned = space->trace[ss.traceId].condemned;
res = MRGGroupScan(&ss, group, mrg);
AVER(res == ResOK); /* impl.c.amc.access.error (!) */
}
}
}
static PoolClassStruct PoolClassMRGStruct = {
PoolClassSig, /* sig */
"MRG", /* name */
sizeof(MRGStruct), /* size */
offsetof(MRGStruct, poolStruct), /* offset */
AttrSCAN | AttrALLOC | AttrFREE | AttrINCR_RB,
MRGInit, /* init */
MRGFinish, /* finish */
MRGAlloc, /* alloc */
MRGFree, /* free */
PoolNoBufferInit, /* bufferInit */
PoolNoBufferFinish, /* bufferFinish */
PoolNoBufferFill, /* bufferFill */
PoolNoBufferTrip, /* bufferTrip */
PoolNoBufferExpose, /* bufferExpose */
PoolNoBufferCover, /* bufferCover */
PoolNoCondemn, /* condemn */
MRGGrey, /* grey */
MRGScan, /* scan */
PoolNoFix, /* fix */
PoolNoReclaim, /* reclaim */
MRGAccess, /* access */
MRGDescribe, /* describe */
PoolClassSig /* impl.h.mpmst.class.end-sig */
};
PoolClass PoolClassMRG(void)
{
return &PoolClassMRGStruct;
}
/* .check.norecurse: the expression &mrg->poolStruct is used instead of
* the more natural MRGPool(mrg). The latter results in infinite
* recursion because MRGPool calls MRGCheck.
*/
static Bool MRGCheck(MRG mrg)
{
Space space;
CHECKS(MRG, mrg);
CHECKD(Pool, &mrg->poolStruct);
CHECKL(mrg->poolStruct.class == &PoolClassMRGStruct);
CHECKL(RingCheck(&mrg->entry));
CHECKL(RingCheck(&mrg->exit));
CHECKL(RingCheck(&mrg->free));
CHECKL(RingCheck(&mrg->group));
space = PoolSpace(&mrg->poolStruct); /* .check.norecurse */
CHECKL(mrg->extendBy == ArenaAlign(space));
return TRUE;
}