1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-04-27 08:43:40 -07:00

Merge branch/2014-10-11/snc into the master sources.

Copied from Perforce
 Change: 191102
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Gareth Rees 2016-04-13 17:52:34 +01:00
commit 034d378148
34 changed files with 640 additions and 523 deletions

View file

@ -28,10 +28,6 @@
SRCID(buffer, "$Id$");
/* forward declarations */
static void BufferFrameNotifyPopPending(Buffer buffer);
/* BufferCheck -- check consistency of a buffer
*
* See .ap.async. */
@ -50,15 +46,6 @@ Bool BufferCheck(Buffer buffer)
CHECKL(buffer->emptySize <= buffer->fillSize);
CHECKL(buffer->alignment == buffer->pool->alignment);
CHECKL(AlignCheck(buffer->alignment));
CHECKL(BoolCheck(buffer->ap_s._enabled));
if (buffer->ap_s._enabled) {
/* no useful check for frameptr - mutator may be updating it */
CHECKL(BoolCheck(buffer->ap_s._lwpoppending));
} else {
CHECKL(buffer->ap_s._lwpoppending == FALSE);
CHECKL(buffer->ap_s._frameptr == NULL);
}
/* If any of the buffer's fields indicate that it is reset, make */
/* sure it is really reset. Otherwise, check various properties */
@ -79,8 +66,6 @@ Bool BufferCheck(Buffer buffer)
/* Nothing reliable to check for lightweight frame state */
CHECKL(buffer->poolLimit == (Addr)0);
} else {
Addr aplimit;
/* The buffer is attached to a region of memory. */
/* Check consistency. */
CHECKL(buffer->mode & BufferModeATTACHED);
@ -99,14 +84,6 @@ Bool BufferCheck(Buffer buffer)
CHECKL(AddrIsAligned(buffer->ap_s.limit, buffer->alignment));
CHECKL(AddrIsAligned(buffer->poolLimit, buffer->alignment));
/* .lwcheck: If LW frames are enabled, the buffer may become */
/* trapped asynchronously. It can't become untrapped */
/* asynchronously, though. See <design/alloc-frame/#lw-frame.pop>. */
/* Read a snapshot value of the limit field. Use this to determine */
/* if we are trapped, and to permit more useful checking when not */
/* yet trapped. */
aplimit = buffer->ap_s.limit;
/* If the buffer isn't trapped then "limit" should be the limit */
/* set by the owning pool. Otherwise, "init" is either at the */
/* same place it was at flip (.commit.before) or has been set */
@ -117,12 +94,10 @@ Bool BufferCheck(Buffer buffer)
/* request.dylan.170429.sol.zero_). */
/* .. _request.dylan.170429.sol.zero: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/170429 */
if ((buffer->ap_s._enabled && aplimit == (Addr)0) /* see .lwcheck */
|| (!buffer->ap_s._enabled && BufferIsTrapped(buffer))) {
if (BufferIsTrapped(buffer)) {
/* .check.use-trapped: This checking function uses BufferIsTrapped, */
/* So BufferIsTrapped can't do checking as that would cause an */
/* infinite loop. */
CHECKL(aplimit == (Addr)0);
if (buffer->mode & BufferModeFLIPPED) {
CHECKL(buffer->ap_s.init == buffer->initAtFlip
|| buffer->ap_s.init == buffer->ap_s.alloc);
@ -131,7 +106,6 @@ Bool BufferCheck(Buffer buffer)
}
/* Nothing special to check in the logged mode. */
} else {
CHECKL(aplimit == buffer->poolLimit); /* see .lwcheck */
CHECKL(buffer->initAtFlip == (Addr)0);
}
}
@ -228,9 +202,6 @@ static Res BufferInit(Buffer buffer, BufferClass class,
buffer->ap_s.init = (mps_addr_t)0;
buffer->ap_s.alloc = (mps_addr_t)0;
buffer->ap_s.limit = (mps_addr_t)0;
buffer->ap_s._frameptr = NULL;
buffer->ap_s._enabled = FALSE;
buffer->ap_s._lwpoppending = FALSE;
buffer->poolLimit = (Addr)0;
buffer->rampCount = 0;
@ -316,8 +287,6 @@ void BufferDetach(Buffer buffer, Pool pool)
/* Ask the owning pool to do whatever it needs to before the */
/* buffer is detached (e.g. copy buffer state into pool state). */
(*pool->class->bufferEmpty)(pool, buffer, init, limit);
/* Use of lightweight frames must have been disabled by now */
AVER(BufferFrameState(buffer) == BufferFrameDISABLED);
/* run any class-specific detachment method */
buffer->class->detach(buffer);
@ -341,7 +310,6 @@ void BufferDetach(Buffer buffer, Pool pool)
buffer->poolLimit = (Addr)0;
buffer->mode &=
~(BufferModeATTACHED|BufferModeFLIPPED|BufferModeTRANSITION);
BufferFrameSetState(buffer, BufferFrameDISABLED);
EVENT2(BufferEmpty, buffer, spare);
}
@ -378,11 +346,6 @@ void BufferFinish(Buffer buffer)
AVER(BufferIsReady(buffer));
/* <design/alloc-frame/#lw-frame.sync.trip> */
if (BufferIsTrappedByMutator(buffer)) {
BufferFrameNotifyPopPending(buffer);
}
BufferDetach(buffer, pool);
/* Dispatch to the buffer class method to perform any */
@ -458,44 +421,6 @@ static void BufferSetUnflipped(Buffer buffer)
}
/* BufferFrameState
*
* Returns the frame state of a buffer. See
* <design/alloc-frame/#lw-frame.states>. */
FrameState BufferFrameState(Buffer buffer)
{
AVERT(Buffer, buffer);
if (buffer->ap_s._enabled) {
if (buffer->ap_s._lwpoppending) {
return BufferFramePOP_PENDING;
} else {
AVER(buffer->ap_s._frameptr == NULL);
return BufferFrameVALID;
}
} else {
AVER(buffer->ap_s._frameptr == NULL);
AVER(buffer->ap_s._lwpoppending == FALSE);
return BufferFrameDISABLED;
}
}
/* BufferFrameSetState
*
* Sets the frame state of a buffer. Only the mutator may set the
* PopPending state. See <design/alloc-frame/#lw-frame.states>. */
void BufferFrameSetState(Buffer buffer, FrameState state)
{
AVERT(Buffer, buffer);
AVER(state == BufferFrameVALID || state == BufferFrameDISABLED);
buffer->ap_s._frameptr = NULL;
buffer->ap_s._lwpoppending = FALSE;
buffer->ap_s._enabled = (state == BufferFrameVALID);
}
/* BufferSetAllocAddr
*
* Sets the init & alloc pointers of a buffer. */
@ -513,32 +438,6 @@ void BufferSetAllocAddr(Buffer buffer, Addr addr)
}
/* BufferFrameNotifyPopPending
*
* Notifies the pool when a lightweight frame pop operation has been
* deferred and needs to be processed. See
* <design/alloc-frame/#lw-frame.sync.trip>. */
static void BufferFrameNotifyPopPending(Buffer buffer)
{
AllocFrame frame;
Pool pool;
AVER(BufferIsTrappedByMutator(buffer));
AVER(BufferFrameState(buffer) == BufferFramePOP_PENDING);
frame = (AllocFrame)buffer->ap_s._frameptr;
/* Unset PopPending state & notify the pool */
BufferFrameSetState(buffer, BufferFrameVALID);
/* If the frame is no longer trapped, undo the trap by resetting */
/* the AP limit pointer */
if (!BufferIsTrapped(buffer)) {
buffer->ap_s.limit = buffer->poolLimit;
}
pool = BufferPool(buffer);
(*pool->class->framePopPending)(pool, buffer, frame);
}
/* BufferFramePush
*
* See <design/alloc-frame/>. */
@ -550,17 +449,12 @@ Res BufferFramePush(AllocFrame *frameReturn, Buffer buffer)
AVER(frameReturn != NULL);
/* Process any flip or PopPending */
/* Process any flip */
if (!BufferIsReset(buffer) && buffer->ap_s.limit == (Addr)0) {
/* .fill.unflip: If the buffer is flipped then we unflip the buffer. */
if (buffer->mode & BufferModeFLIPPED) {
BufferSetUnflipped(buffer);
}
/* check for PopPending */
if (BufferIsTrappedByMutator(buffer)) {
BufferFrameNotifyPopPending(buffer);
}
}
pool = BufferPool(buffer);
return (*pool->class->framePush)(frameReturn, pool, buffer);
@ -692,11 +586,6 @@ Res BufferFill(Addr *pReturn, Buffer buffer, Size size)
BufferSetUnflipped(buffer);
}
/* <design/alloc-frame/#lw-frame.sync.trip> */
if (BufferIsTrappedByMutator(buffer)) {
BufferFrameNotifyPopPending(buffer);
}
/* .fill.logged: If the buffer is logged then we leave it logged. */
next = AddrAdd(buffer->ap_s.alloc, size);
if (next > (Addr)buffer->ap_s.alloc &&
@ -795,8 +684,6 @@ Bool BufferTrip(Buffer buffer, Addr p, Size size)
AVER(buffer->ap_s.limit == 0);
/* Of course we should be trapped. */
AVER(BufferIsTrapped(buffer));
/* But the mutator shouldn't have caused the trap */
AVER(!BufferIsTrappedByMutator(buffer));
/* The init and alloc fields should be equal at this point, because */
/* the step .commit.update has happened. */
@ -943,21 +830,7 @@ void BufferReassignSeg(Buffer buffer, Seg seg)
Bool BufferIsTrapped(Buffer buffer)
{
/* Can't check buffer, see .check.use-trapped */
return BufferIsTrappedByMutator(buffer)
|| ((buffer->mode & (BufferModeFLIPPED|BufferModeLOGGED)) != 0);
}
/* BufferIsTrappedByMutator
*
* Indicates whether the mutator trapped the buffer. See
* <design/alloc-frame/#lw-frame.sync.trip> and .ap.async. */
Bool BufferIsTrappedByMutator(Buffer buffer)
{
AVER(!buffer->ap_s._lwpoppending || buffer->ap_s._enabled);
/* Can't check buffer, see .check.use-trapped */
return buffer->ap_s._lwpoppending;
return (buffer->mode & (BufferModeFLIPPED|BufferModeLOGGED)) != 0;
}

View file

@ -283,6 +283,7 @@ TEST_TARGETS=\
qs \
sacss \
segsmss \
sncss \
steptest \
tagtest \
teletest \
@ -526,15 +527,18 @@ $(PFM)/$(VARIETY)/sacss: $(PFM)/$(VARIETY)/sacss.o \
$(PFM)/$(VARIETY)/segsmss: $(PFM)/$(VARIETY)/segsmss.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/sncss: $(PFM)/$(VARIETY)/sncss.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/steptest: $(PFM)/$(VARIETY)/steptest.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/tagtest: $(PFM)/$(VARIETY)/tagtest.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/teletest: $(PFM)/$(VARIETY)/teletest.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/steptest: $(PFM)/$(VARIETY)/steptest.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/walkt0: $(PFM)/$(VARIETY)/walkt0.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a

View file

@ -288,6 +288,9 @@ $(PFM)\$(VARIETY)\sacss.exe: $(PFM)\$(VARIETY)\sacss.obj \
$(PFM)\$(VARIETY)\segsmss.exe: $(PFM)\$(VARIETY)\segsmss.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\sncss.exe: $(PFM)\$(VARIETY)\sncss.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\steptest.exe: $(PFM)\$(VARIETY)\steptest.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)

View file

@ -191,8 +191,10 @@ static void test_trees(int mode, const char *name, mps_arena_t arena,
++ collections;
{
size_t live_size = (object_count - finals) * sizeof(void *) * 3;
size_t alloc_size = mps_pool_total_size(pool) - mps_pool_free_size(pool);
Insist(live_size <= alloc_size);
size_t total_size = mps_pool_total_size(pool);
size_t free_size = mps_pool_free_size(pool);
Insist(free_size <= total_size);
Insist(free_size + live_size <= total_size);
}
while (mps_message_poll(arena)) {
mps_message_t message;

View file

@ -628,7 +628,7 @@ static mps_res_t dylan_scan_weak(mps_ss_t mps_ss,
return MPS_RES_OK;
}
static mps_addr_t dylan_skip(mps_addr_t object)
mps_addr_t dylan_skip(mps_addr_t object)
{
mps_addr_t *p; /* cursor in object */
mps_word_t *w; /* wrapper cursor */
@ -746,6 +746,14 @@ void dylan_pad(mps_addr_t addr, size_t size)
}
}
mps_bool_t dylan_ispad(mps_addr_t addr)
{
mps_word_t *p;
p = (mps_word_t *)addr;
return p[0] == 1 || p[0] == 2;
}
/* The dylan format structures */

View file

@ -24,8 +24,10 @@ extern mps_res_t dylan_fmt_weak(mps_fmt_t *, mps_arena_t);
extern mps_addr_t dylan_weak_dependent(mps_addr_t);
extern void dylan_pad(mps_addr_t addr, size_t size);
extern int dylan_wrapper_check(mps_word_t *w);
extern mps_addr_t dylan_skip(mps_addr_t);
extern void dylan_pad(mps_addr_t, size_t);
extern mps_bool_t dylan_ispad(mps_addr_t);
extern int dylan_wrapper_check(mps_word_t *);
/* Constants describing wrappers. Used only for debugging / testing */
#define WW 0 /* offset of Wrapper-Wrapper */

View file

@ -352,10 +352,8 @@ Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size,
size = SegSize(seg);
pgen->totalSize += size;
STATISTIC_STAT ({
++ pgen->segs;
pgen->freeSize += size;
});
++ pgen->segs;
pgen->freeSize += size;
*segReturn = seg;
return ResOK;
}
@ -451,13 +449,13 @@ Res PoolGenInit(PoolGen pgen, GenDesc gen, Pool pool)
pgen->pool = pool;
pgen->gen = gen;
RingInit(&pgen->genRing);
STATISTIC(pgen->segs = 0);
pgen->segs = 0;
pgen->totalSize = 0;
STATISTIC(pgen->freeSize = 0);
pgen->freeSize = 0;
pgen->newSize = 0;
STATISTIC(pgen->oldSize = 0);
pgen->oldSize = 0;
pgen->newDeferredSize = 0;
STATISTIC(pgen->oldDeferredSize = 0);
pgen->oldDeferredSize = 0;
pgen->sig = PoolGenSig;
AVERT(PoolGen, pgen);
@ -474,12 +472,10 @@ void PoolGenFinish(PoolGen pgen)
AVER(pgen->totalSize == 0);
AVER(pgen->newSize == 0);
AVER(pgen->newDeferredSize == 0);
STATISTIC_STAT ({
AVER(pgen->segs == 0);
AVER(pgen->freeSize == 0);
AVER(pgen->oldSize == 0);
AVER(pgen->oldDeferredSize == 0);
});
AVER(pgen->segs == 0);
AVER(pgen->freeSize == 0);
AVER(pgen->oldSize == 0);
AVER(pgen->oldDeferredSize == 0);
pgen->sig = SigInvalid;
RingRemove(&pgen->genRing);
@ -495,12 +491,10 @@ Bool PoolGenCheck(PoolGen pgen)
CHECKU(Pool, pgen->pool);
CHECKU(GenDesc, pgen->gen);
CHECKD_NOSIG(Ring, &pgen->genRing);
STATISTIC_STAT ({
CHECKL((pgen->totalSize == 0) == (pgen->segs == 0));
CHECKL(pgen->totalSize >= pgen->segs * ArenaGrainSize(PoolArena(pgen->pool)));
CHECKL(pgen->totalSize == pgen->freeSize + pgen->newSize + pgen->oldSize
+ pgen->newDeferredSize + pgen->oldDeferredSize);
});
CHECKL((pgen->totalSize == 0) == (pgen->segs == 0));
CHECKL(pgen->totalSize >= pgen->segs * ArenaGrainSize(PoolArena(pgen->pool)));
CHECKL(pgen->totalSize == pgen->freeSize + pgen->newSize + pgen->oldSize
+ pgen->newDeferredSize + pgen->oldDeferredSize);
return TRUE;
}
@ -520,10 +514,8 @@ void PoolGenAccountForFill(PoolGen pgen, Size size, Bool deferred)
AVERT(PoolGen, pgen);
AVERT(Bool, deferred);
STATISTIC_STAT ({
AVER(pgen->freeSize >= size);
pgen->freeSize -= size;
});
AVER(pgen->freeSize >= size);
pgen->freeSize -= size;
if (deferred)
pgen->newDeferredSize += size;
else
@ -552,7 +544,7 @@ void PoolGenAccountForEmpty(PoolGen pgen, Size unused, Bool deferred)
AVER(pgen->newSize >= unused);
pgen->newSize -= unused;
}
STATISTIC(pgen->freeSize += unused);
pgen->freeSize += unused;
}
@ -572,11 +564,11 @@ void PoolGenAccountForAge(PoolGen pgen, Size size, Bool deferred)
if (deferred) {
AVER(pgen->newDeferredSize >= size);
pgen->newDeferredSize -= size;
STATISTIC(pgen->oldDeferredSize += size);
pgen->oldDeferredSize += size;
} else {
AVER(pgen->newSize >= size);
pgen->newSize -= size;
STATISTIC(pgen->oldSize += size);
pgen->oldSize += size;
}
}
@ -594,16 +586,14 @@ void PoolGenAccountForReclaim(PoolGen pgen, Size reclaimed, Bool deferred)
AVERT(PoolGen, pgen);
AVERT(Bool, deferred);
STATISTIC_STAT ({
if (deferred) {
AVER(pgen->oldDeferredSize >= reclaimed);
pgen->oldDeferredSize -= reclaimed;
} else {
AVER(pgen->oldSize >= reclaimed);
pgen->oldSize -= reclaimed;
}
pgen->freeSize += reclaimed;
});
if (deferred) {
AVER(pgen->oldDeferredSize >= reclaimed);
pgen->oldDeferredSize -= reclaimed;
} else {
AVER(pgen->oldSize >= reclaimed);
pgen->oldSize -= reclaimed;
}
pgen->freeSize += reclaimed;
}
@ -619,11 +609,9 @@ void PoolGenAccountForReclaim(PoolGen pgen, Size reclaimed, Bool deferred)
void PoolGenUndefer(PoolGen pgen, Size oldSize, Size newSize)
{
AVERT(PoolGen, pgen);
STATISTIC_STAT ({
AVER(pgen->oldDeferredSize >= oldSize);
pgen->oldDeferredSize -= oldSize;
pgen->oldSize += oldSize;
});
AVER(pgen->oldDeferredSize >= oldSize);
pgen->oldDeferredSize -= oldSize;
pgen->oldSize += oldSize;
AVER(pgen->newDeferredSize >= newSize);
pgen->newDeferredSize -= newSize;
pgen->newSize += newSize;
@ -635,10 +623,8 @@ void PoolGenUndefer(PoolGen pgen, Size oldSize, Size newSize)
void PoolGenAccountForSegSplit(PoolGen pgen)
{
AVERT(PoolGen, pgen);
STATISTIC_STAT ({
AVER(pgen->segs >= 1); /* must be at least one segment to split */
++ pgen->segs;
});
AVER(pgen->segs >= 1); /* must be at least one segment to split */
++ pgen->segs;
}
@ -647,10 +633,8 @@ void PoolGenAccountForSegSplit(PoolGen pgen)
void PoolGenAccountForSegMerge(PoolGen pgen)
{
AVERT(PoolGen, pgen);
STATISTIC_STAT ({
AVER(pgen->segs >= 2); /* must be at least two segments to merge */
-- pgen->segs;
});
AVER(pgen->segs >= 2); /* must be at least two segments to merge */
-- pgen->segs;
}
@ -681,12 +665,10 @@ void PoolGenFree(PoolGen pgen, Seg seg, Size freeSize, Size oldSize,
AVER(pgen->totalSize >= size);
pgen->totalSize -= size;
STATISTIC_STAT ({
AVER(pgen->segs > 0);
-- pgen->segs;
AVER(pgen->freeSize >= size);
pgen->freeSize -= size;
});
AVER(pgen->segs > 0);
-- pgen->segs;
AVER(pgen->freeSize >= size);
pgen->freeSize -= size;
SegFree(seg);
}

View file

@ -280,8 +280,6 @@ extern Res PoolNoFramePush(AllocFrame *frameReturn, Pool pool, Buffer buf);
extern Res PoolTrivFramePush(AllocFrame *frameReturn, Pool pool, Buffer buf);
extern Res PoolNoFramePop(Pool pool, Buffer buf, AllocFrame frame);
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, FormattedObjectsVisitor f,
void *p, size_t s);
@ -696,6 +694,7 @@ extern Res SegDescribe(Seg seg, mps_lib_FILE *stream, Count depth);
extern void SegSetSummary(Seg seg, RefSet summary);
extern Buffer SegBuffer(Seg seg);
extern void SegSetBuffer(Seg seg, Buffer buffer);
extern Addr SegBufferScanLimit(Seg seg);
extern Bool SegCheck(Seg seg);
extern Bool GCSegCheck(GCSeg gcseg);
extern Bool SegClassCheck(SegClass class);
@ -808,7 +807,6 @@ extern Addr BufferScanLimit(Buffer buffer);
extern void BufferReassignSeg(Buffer buffer, Seg seg);
extern Bool BufferIsTrapped(Buffer buffer);
extern Bool BufferIsTrappedByMutator(Buffer buffer);
extern void BufferRampBegin(Buffer buffer, AllocPattern pattern);
extern Res BufferRampEnd(Buffer buffer);
@ -816,8 +814,6 @@ extern void BufferRampReset(Buffer buffer);
extern Res BufferFramePush(AllocFrame *frameReturn, Buffer buffer);
extern Res BufferFramePop(Buffer buffer, AllocFrame frame);
extern FrameState BufferFrameState(Buffer buffer);
extern void BufferFrameSetState(Buffer buffer, FrameState state);
/* DEFINE_BUFFER_CLASS -- define a buffer class */

View file

@ -74,7 +74,6 @@ typedef struct mps_pool_class_s {
PoolRampEndMethod rampEnd; /* end a ramp pattern */
PoolFramePushMethod framePush; /* push an allocation frame */
PoolFramePopMethod framePop; /* pop an allocation frame */
PoolFramePopPendingMethod framePopPending; /* notify pending pop */
PoolAddrObjectMethod addrObject; /* find client pointer to object */
PoolWalkMethod walk; /* walk over a segment */
PoolFreeWalkMethod freewalk; /* walk over free blocks */

View file

@ -72,7 +72,6 @@ typedef struct BufferClassStruct *BufferClass; /* <design/buffer/> */
typedef BufferClass SegBufClass; /* <design/buffer/> */
typedef BufferClass RankBufClass; /* <design/buffer/> */
typedef unsigned BufferMode; /* <design/buffer/> */
typedef unsigned FrameState; /* <design/alloc-frame/> */
typedef struct mps_fmt_s *Format; /* design.mps.format */
typedef struct LockStruct *Lock; /* <code/lock.c>* */
typedef struct mps_pool_s *Pool; /* <design/pool/> */
@ -222,8 +221,6 @@ typedef Res (*PoolFramePushMethod)(AllocFrame *frameReturn,
Pool pool, Buffer buf);
typedef Res (*PoolFramePopMethod)(Pool pool, Buffer buf,
AllocFrame frame);
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, FormattedObjectsVisitor f,
@ -317,14 +314,6 @@ enum {
#define BufferModeTRANSITION ((BufferMode)(1<<3))
/* Buffer frame states. See <design/alloc-frame/#lw-frame.states> */
enum {
BufferFrameVALID = 1,
BufferFramePOP_PENDING,
BufferFrameDISABLED
};
/* Rank constants -- see <design/type/#rank> */
/* These definitions must match <code/mps.h#rank>. */
/* This is checked by <code/mpsi.c#check>. */

View file

@ -321,9 +321,6 @@ typedef struct mps_ap_s { /* allocation point descriptor */
mps_addr_t init; /* limit of initialized memory */
mps_addr_t alloc; /* limit of allocated memory */
mps_addr_t limit; /* limit of available memory */
mps_addr_t _frameptr; /* lightweight frame pointer */
mps_bool_t _enabled; /* lightweight frame status */
mps_bool_t _lwpoppending; /* lightweight pop pending? */
} mps_ap_s;

View file

@ -112,6 +112,7 @@
22B2BC3918B643AD00C33E63 /* PBXTargetDependency */,
22B2BC3B18B643B000C33E63 /* PBXTargetDependency */,
3104B04A156D3AE4000A585A /* PBXTargetDependency */,
229E228819EAB10D00E21417 /* PBXTargetDependency */,
31D6009D156D404B00337B26 /* PBXTargetDependency */,
314CB6EB1C6D272A0073CA42 /* PBXTargetDependency */,
3114A62E156E94AA001E0AA3 /* PBXTargetDependency */,
@ -135,6 +136,9 @@
2231BB6118CA97DC002D6322 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
2231BB6A18CA984F002D6322 /* locusss.c in Sources */ = {isa = PBXBuildFile; fileRef = 2231BB6918CA983C002D6322 /* locusss.c */; };
2231BB6B18CA9861002D6322 /* locbwcss.c in Sources */ = {isa = PBXBuildFile; fileRef = 2231BB6818CA9834002D6322 /* locbwcss.c */; };
223E795D19EAB00B00DC26A6 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
223E795F19EAB00B00DC26A6 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
223E796719EAB05C00DC26A6 /* sncss.c in Sources */ = {isa = PBXBuildFile; fileRef = 223E796619EAB04100DC26A6 /* sncss.c */; };
224CC791175E1821002FF81B /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
224CC793175E1821002FF81B /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
224CC79F175E321C002FF81B /* mv2test.c in Sources */ = {isa = PBXBuildFile; fileRef = 3114A686156E9674001E0AA3 /* mv2test.c */; };
@ -394,6 +398,13 @@
remoteGlobalIDString = 2231BB5A18CA97DC002D6322;
remoteInfo = locusss;
};
223E795A19EAB00B00DC26A6 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 31EEABFA156AAF9D00714D05;
remoteInfo = mps;
};
224CC78E175E1821002FF81B /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
@ -464,6 +475,13 @@
remoteGlobalIDString = 2291A5C1175CAFCA001D4920;
remoteInfo = expt825;
};
229E228719EAB10D00E21417 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 223E795819EAB00B00DC26A6;
remoteInfo = sncss;
};
22B2BC3818B643AD00C33E63 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
@ -1017,6 +1035,15 @@
);
runOnlyForDeploymentPostprocessing = 1;
};
223E796019EAB00B00DC26A6 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
224CC794175E1821002FF81B /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
@ -1431,6 +1458,8 @@
2231BB6918CA983C002D6322 /* locusss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = locusss.c; sourceTree = "<group>"; };
223475CB194CA09500C69128 /* vm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vm.c; sourceTree = "<group>"; };
223475CC194CA09500C69128 /* vm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vm.h; sourceTree = "<group>"; };
223E796519EAB00B00DC26A6 /* sncss */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sncss; sourceTree = BUILT_PRODUCTS_DIR; };
223E796619EAB04100DC26A6 /* sncss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sncss.c; sourceTree = "<group>"; };
224CC799175E1821002FF81B /* fotest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fotest; sourceTree = BUILT_PRODUCTS_DIR; };
224CC79E175E3202002FF81B /* fotest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fotest.c; sourceTree = "<group>"; };
22561A9618F4263300372C66 /* testthr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = testthr.h; sourceTree = "<group>"; };
@ -1771,6 +1800,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
223E795E19EAB00B00DC26A6 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
223E795F19EAB00B00DC26A6 /* libmps.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
224CC792175E1821002FF81B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@ -2263,7 +2300,6 @@
3124CAB3156BE1B700753214 /* Tests */ = {
isa = PBXGroup;
children = (
22F846AF18F4379C00982BA7 /* lockut.c */,
3114A63D156E94EA001E0AA3 /* abqtest.c */,
22FACED1188807FF000FDBC1 /* airtest.c */,
3124CAF5156BE81100753214 /* amcss.c */,
@ -2296,6 +2332,7 @@
2291A5E9175CB4EC001D4920 /* landtest.c */,
2231BB6818CA9834002D6322 /* locbwcss.c */,
31D60036156D3E0200337B26 /* lockcov.c */,
22F846AF18F4379C00982BA7 /* lockut.c */,
2231BB6918CA983C002D6322 /* locusss.c */,
3114A5A1156E9168001E0AA3 /* locv.c */,
3114A69F156E9725001E0AA3 /* messtest.c */,
@ -2307,6 +2344,7 @@
3114A5B7156E92F0001E0AA3 /* qs.c */,
3104AFD6156D3602000A585A /* sacss.c */,
31D60006156D3C5F00337B26 /* segsmss.c */,
223E796619EAB04100DC26A6 /* sncss.c */,
31D60098156D403C00337B26 /* steptest.c */,
31108A391C6B90D600E728EA /* tagtest.c */,
3114A628156E949A001E0AA3 /* teletest.c */,
@ -2407,6 +2445,7 @@
22C2ACAF18BE400A006B3677 /* nailboardtest */,
22F846BD18F437B900982BA7 /* lockut */,
31108A471C6B90E900E728EA /* tagtest */,
223E796519EAB00B00DC26A6 /* sncss */,
);
name = Products;
sourceTree = "<group>";
@ -2631,6 +2670,24 @@
productReference = 2231BB6718CA97DC002D6322 /* locusss */;
productType = "com.apple.product-type.tool";
};
223E795819EAB00B00DC26A6 /* sncss */ = {
isa = PBXNativeTarget;
buildConfigurationList = 223E796119EAB00B00DC26A6 /* Build configuration list for PBXNativeTarget "sncss" */;
buildPhases = (
223E795B19EAB00B00DC26A6 /* Sources */,
223E795E19EAB00B00DC26A6 /* Frameworks */,
223E796019EAB00B00DC26A6 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
223E795919EAB00B00DC26A6 /* PBXTargetDependency */,
);
name = sncss;
productName = apss;
productReference = 223E796519EAB00B00DC26A6 /* sncss */;
productType = "com.apple.product-type.tool";
};
224CC78C175E1821002FF81B /* fotest */ = {
isa = PBXNativeTarget;
buildConfigurationList = 224CC795175E1821002FF81B /* Build configuration list for PBXNativeTarget "fotest" */;
@ -3515,6 +3572,7 @@
3114A5A6156E92C0001E0AA3 /* qs */,
3104AFC7156D35E2000A585A /* sacss */,
3104B03C156D3AD7000A585A /* segsmss */,
223E795819EAB00B00DC26A6 /* sncss */,
31D6008B156D402900337B26 /* steptest */,
3114A61B156E9485001E0AA3 /* teletest */,
3114A6AB156E9759001E0AA3 /* walkt0 */,
@ -3622,6 +3680,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
223E795B19EAB00B00DC26A6 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
223E796719EAB05C00DC26A6 /* sncss.c in Sources */,
223E795D19EAB00B00DC26A6 /* testlib.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
224CC78F175E1821002FF81B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -4147,6 +4214,11 @@
target = 2231BB5A18CA97DC002D6322 /* locusss */;
targetProxy = 2231BB6E18CA986D002D6322 /* PBXContainerItemProxy */;
};
223E795919EAB00B00DC26A6 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 31EEABFA156AAF9D00714D05 /* mps */;
targetProxy = 223E795A19EAB00B00DC26A6 /* PBXContainerItemProxy */;
};
224CC78D175E1821002FF81B /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 31EEABFA156AAF9D00714D05 /* mps */;
@ -4197,6 +4269,11 @@
target = 2291A5C1175CAFCA001D4920 /* expt825 */;
targetProxy = 2291A5E7175CB20E001D4920 /* PBXContainerItemProxy */;
};
229E228819EAB10D00E21417 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 223E795819EAB00B00DC26A6 /* sncss */;
targetProxy = 229E228719EAB10D00E21417 /* PBXContainerItemProxy */;
};
22B2BC3918B643AD00C33E63 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 31FCAE0917692403008C034C /* scheme */;
@ -4706,6 +4783,27 @@
};
name = RASH;
};
223E796219EAB00B00DC26A6 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
223E796319EAB00B00DC26A6 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
223E796419EAB00B00DC26A6 /* RASH */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = RASH;
};
224CC796175E1821002FF81B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -5961,6 +6059,16 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
223E796119EAB00B00DC26A6 /* Build configuration list for PBXNativeTarget "sncss" */ = {
isa = XCConfigurationList;
buildConfigurations = (
223E796219EAB00B00DC26A6 /* Debug */,
223E796319EAB00B00DC26A6 /* Release */,
223E796419EAB00B00DC26A6 /* RASH */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
224CC795175E1821002FF81B /* Build configuration list for PBXNativeTarget "fotest" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View file

@ -958,7 +958,7 @@ mps_res_t (mps_ap_frame_push)(mps_frame_t *frame_o, mps_ap_t mps_ap)
return MPS_RES_FAIL;
}
if (!mps_ap->_lwpoppending) {
if (mps_ap->init < mps_ap->limit) {
/* Valid state for a lightweight push */
*frame_o = (mps_frame_t)mps_ap->init;
return MPS_RES_OK;
@ -991,6 +991,9 @@ mps_res_t (mps_ap_frame_push)(mps_frame_t *frame_o, mps_ap_t mps_ap)
mps_res_t (mps_ap_frame_pop)(mps_ap_t mps_ap, mps_frame_t frame)
{
Buffer buf;
Pool pool;
AVER(mps_ap != NULL);
/* Can't check frame because it's an arbitrary value */
@ -999,20 +1002,27 @@ mps_res_t (mps_ap_frame_pop)(mps_ap_t mps_ap, mps_frame_t frame)
return MPS_RES_FAIL;
}
if (mps_ap->_enabled) {
/* Valid state for a lightweight pop */
mps_ap->_frameptr = (mps_addr_t)frame; /* record pending pop */
mps_ap->_lwpoppending = TRUE;
mps_ap->limit = (mps_addr_t)0; /* trap the buffer */
buf = BufferOfAP(mps_ap);
AVER(TESTT(Buffer, buf));
pool = buf->pool;
AVER(TESTT(Pool, pool));
/* It's not thread-safe to read BufferBase here in an automatically
* managed pool (see job003947), so test AttrGC first. */
if (!PoolHasAttr(pool, AttrGC)
&& BufferBase(buf) <= (Addr)frame
&& (mps_addr_t)frame < mps_ap->init)
{
/* Lightweight pop to earlier address in same buffer in a manually
* managed pool. */
mps_ap->init = mps_ap->alloc = (mps_addr_t)frame;
return MPS_RES_OK;
} else {
/* Need a heavyweight pop */
Buffer buf = BufferOfAP(mps_ap);
Arena arena;
Res res;
AVER(TESTT(Buffer, buf));
arena = BufferArena(buf);
ArenaEnter(arena);

View file

@ -65,7 +65,6 @@ Bool PoolClassCheck(PoolClass class)
CHECKL(FUNCHECK(class->rampEnd));
CHECKL(FUNCHECK(class->framePush));
CHECKL(FUNCHECK(class->framePop));
CHECKL(FUNCHECK(class->framePopPending));
CHECKL(FUNCHECK(class->addrObject));
CHECKL(FUNCHECK(class->walk));
CHECKL(FUNCHECK(class->freewalk));

View file

@ -57,7 +57,6 @@ void PoolClassMixInBuffer(PoolClass class)
/* By default, buffered pools treat frame operations as NOOPs */
class->framePush = PoolTrivFramePush;
class->framePop = PoolTrivFramePop;
class->framePopPending = PoolTrivFramePopPending;
class->bufferClass = BufferClassGet;
}
@ -138,7 +137,6 @@ DEFINE_CLASS(AbstractPoolClass, class)
class->rampEnd = PoolNoRampEnd;
class->framePush = PoolNoFramePush;
class->framePop = PoolNoFramePop;
class->framePopPending = PoolNoFramePopPending;
class->addrObject = PoolNoAddrObject;
class->walk = PoolNoWalk;
class->freewalk = PoolTrivFreeWalk;
@ -590,16 +588,6 @@ Res PoolNoFramePop(Pool pool, Buffer buf, AllocFrame frame)
}
void PoolNoFramePopPending(Pool pool, Buffer buf, AllocFrame frame)
{
AVERT(Pool, pool);
AVERT(Buffer, buf);
/* frame is of an abstract type & can't be checked */
UNUSED(frame);
NOTREACHED;
}
Res PoolTrivFramePush(AllocFrame *frameReturn, Pool pool, Buffer buf)
{
AVER(frameReturn != NULL);
@ -619,16 +607,6 @@ Res PoolTrivFramePop(Pool pool, Buffer buf, AllocFrame frame)
}
void PoolTrivFramePopPending(Pool pool, Buffer buf, AllocFrame frame)
{
AVERT(Pool, pool);
AVERT(Buffer, buf);
/* frame is of an abstract type & can't be checked */
UNUSED(frame);
NOOP;
}
Res PoolNoAddrObject(Addr *pReturn, Pool pool, Seg seg, Addr addr)
{
AVER(pReturn != NULL);

View file

@ -1712,11 +1712,7 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg)
headerSize = format->headerSize;
ShieldExpose(arena, seg);
p = SegBase(seg);
if(SegBuffer(seg) != NULL) {
limit = BufferScanLimit(SegBuffer(seg));
} else {
limit = SegLimit(seg);
}
limit = SegBufferScanLimit(seg);
padBase = p;
padLength = 0;
while(p < limit) {
@ -1864,14 +1860,7 @@ static void AMCWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
AVERT(AMC, amc);
format = pool->format;
/* If the segment is buffered, only walk as far as the end */
/* of the initialized objects. cf. AMCScan */
if(SegBuffer(seg) != NULL)
limit = BufferScanLimit(SegBuffer(seg));
else
limit = SegLimit(seg);
limit = AddrAdd(limit, format->headerSize);
limit = AddrAdd(SegBufferScanLimit(seg), format->headerSize);
object = AddrAdd(SegBase(seg), format->headerSize);
while(object < limit) {
/* Check not a broken heart. */

View file

@ -163,7 +163,7 @@ static void SNCBufFinish(Buffer buffer)
pool = BufferPool(buffer);
snc = PoolSNC(pool);
/* Put any segments which haven't bee popped onto the free list */
/* Put any segments which haven't been popped onto the free list */
sncPopPartialSegChain(snc, buffer, NULL);
sncbuf->sig = SigInvalid;
@ -206,9 +206,7 @@ typedef struct SNCSegStruct {
#define SegSNCSeg(seg) ((SNCSeg)(seg))
#define SNCSegSeg(sncseg) ((Seg)(sncseg))
#define sncSegNext(seg) \
(SNCSegSeg(SegSNCSeg(seg)->next))
#define sncSegNext(seg) RVALUE(SNCSegSeg(SegSNCSeg(seg)->next))
#define sncSegSetNext(seg, nextseg) \
((void)(SegSNCSeg(seg)->next = SegSNCSeg(nextseg)))
@ -278,7 +276,7 @@ static void sncRecordAllocatedSeg(Buffer buffer, Seg seg)
/* sncRecordFreeSeg - stores a segment on the freelist */
static void sncRecordFreeSeg(SNC snc, Seg seg)
static void sncRecordFreeSeg(Arena arena, SNC snc, Seg seg)
{
AVERT(SNC, snc);
AVERT(Seg, seg);
@ -289,6 +287,11 @@ static void sncRecordFreeSeg(SNC snc, Seg seg)
SegSetGrey(seg, TraceSetEMPTY);
SegSetRankAndSummary(seg, RankSetEMPTY, RefSetEMPTY);
/* Pad the whole segment so we don't try to walk it. */
ShieldExpose(arena, seg);
(*SNCPool(snc)->format->pad)(SegBase(seg), SegSize(seg));
ShieldCover(arena, seg);
sncSegSetNext(seg, snc->freeSegs);
snc->freeSegs = seg;
}
@ -315,7 +318,7 @@ static void sncPopPartialSegChain(SNC snc, Buffer buf, Seg upTo)
AVER(free != NULL);
next = sncSegNext(free);
sncSegSetNext(free, NULL);
sncRecordFreeSeg(snc, free);
sncRecordFreeSeg(BufferArena(buf), snc, free);
free = next;
}
/* Make upTo the head of the buffer chain */
@ -458,8 +461,6 @@ found:
AVERT(Seg, seg);
/* put the segment on the buffer chain */
sncRecordAllocatedSeg(buffer, seg);
/* Permit the use of lightweight frames - .lw-frame-state */
BufferFrameSetState(buffer, BufferFrameVALID);
*baseReturn = SegBase(seg);
*limitReturn = SegLimit(seg);
return ResOK;
@ -481,13 +482,10 @@ static void SNCBufferEmpty(Pool pool, Buffer buffer,
AVER(SegLimit(seg) == limit);
snc = PoolSNC(pool);
AVERT(SNC, snc);
AVER(BufferFrameState(buffer) == BufferFrameVALID);
/* .lw-frame-state */
BufferFrameSetState(buffer, BufferFrameDISABLED);
arena = BufferArena(buffer);
/* Pad the end unused space at the end of the segment */
/* Pad the unused space at the end of the segment */
size = AddrOffset(init, limit);
if (size > 0) {
ShieldExpose(arena, seg);
@ -513,14 +511,7 @@ static Res SNCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
format = pool->format;
base = SegBase(seg);
/* If the segment is buffered, only walk as far as the end */
/* of the initialized objects. */
if (SegBuffer(seg) != NULL) {
limit = BufferScanLimit(SegBuffer(seg));
} else {
limit = SegLimit(seg);
}
limit = SegBufferScanLimit(seg);
if (base < limit) {
res = FormatScan(format, ss, base, limit);
@ -540,43 +531,36 @@ static Res SNCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
static Res SNCFramePush(AllocFrame *frameReturn, Pool pool, Buffer buf)
{
FrameState state;
AVER(frameReturn != NULL);
AVERT(Pool, pool);
AVERT(Buffer, buf);
state = BufferFrameState(buf);
/* Sould have been notified of pending pops before this */
AVER(state == BufferFrameVALID || state == BufferFrameDISABLED);
if (state == BufferFrameDISABLED) {
AVER(BufferIsReset(buf)); /* The buffer must be reset */
if (BufferIsReset(buf)) {
AVER(sncBufferTopSeg(buf) == NULL); /* The stack must be empty */
/* Use NULL to indicate an empty stack. .lw-frame-null */
*frameReturn = NULL;
} else if (BufferGetInit(buf) < SegLimit(BufferSeg(buf))) {
/* Frame pointer is limit of initialized objects in buffer. */
*frameReturn = (AllocFrame)BufferGetInit(buf);
} else {
/* Use the scan limit as the lightweight frame pointer */
*frameReturn = (AllocFrame)BufferScanLimit(buf);
/* Can't use the limit of initialized objects as the frame pointer
* because it's not in the segment (see job003882). Instead, refill
* the buffer and put the frame pointer at the beginning. */
Res res;
Addr base, limit;
BufferDetach(buf, pool);
res = SNCBufferFill(&base, &limit, pool, buf, PoolAlignment(pool));
if (res != ResOK)
return res;
BufferAttach(buf, base, limit, base, 0);
AVER(BufferGetInit(buf) < SegLimit(BufferSeg(buf)));
*frameReturn = (AllocFrame)BufferGetInit(buf);
}
return ResOK;
}
static Res SNCFramePop(Pool pool, Buffer buf, AllocFrame frame)
{
AVERT(Pool, pool);
AVERT(Buffer, buf);
/* Normally the Pop would be handled as a lightweight pop */
/* The only reason that might not happen is if the stack is empty */
AVER(sncBufferTopSeg(buf) == NULL);
/* The only valid frame must also be NULL - .lw-frame-null */
AVER(frame == NULL);
/* Popping an empty frame is a NOOP */
return ResOK;
}
static void SNCFramePopPending(Pool pool, Buffer buf, AllocFrame frame)
{
Addr addr;
SNC snc;
@ -585,8 +569,6 @@ static void SNCFramePopPending(Pool pool, Buffer buf, AllocFrame frame)
/* frame is an Addr and can't be directly checked */
snc = PoolSNC(pool);
AVERT(SNC, snc);
AVER(BufferFrameState(buf) == BufferFrameVALID);
if (frame == NULL) {
/* corresponds to a pop to bottom of stack. .lw-frame-null */
@ -602,6 +584,7 @@ static void SNCFramePopPending(Pool pool, Buffer buf, AllocFrame frame)
addr = (Addr)frame;
foundSeg = SegOfAddr(&seg, arena, addr);
AVER(foundSeg);
AVER(SegPool(seg) == pool);
if (SegBuffer(seg) == buf) {
/* don't need to change the segment - just the alloc pointers */
@ -612,10 +595,10 @@ static void SNCFramePopPending(Pool pool, Buffer buf, AllocFrame frame)
BufferDetach(buf, pool);
sncPopPartialSegChain(snc, buf, seg);
BufferAttach(buf, SegBase(seg), SegLimit(seg), addr, (Size)0);
/* Permit the use of lightweight frames - .lw-frame-state */
BufferFrameSetState(buf, BufferFrameVALID);
}
}
return ResOK;
}
@ -639,13 +622,7 @@ static void SNCWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
snc = PoolSNC(pool);
AVERT(SNC, snc);
format = pool->format;
/* If the segment is buffered, only walk as far as the end */
/* of the initialized objects. Cf. SNCScan. */
if (SegBuffer(seg) != NULL)
limit = BufferScanLimit(SegBuffer(seg));
else
limit = SegLimit(seg);
limit = SegBufferScanLimit(seg);
while(object < limit) {
(*f)(object, format, pool, p, s);
@ -721,7 +698,6 @@ DEFINE_POOL_CLASS(SNCPoolClass, this)
this->scan = SNCScan;
this->framePush = SNCFramePush;
this->framePop = SNCFramePop;
this->framePopPending = SNCFramePopPending;
this->walk = SNCWalk;
this->bufferClass = SNCBufClassGet;
this->totalSize = SNCTotalSize;

View file

@ -348,6 +348,27 @@ void SegSetBuffer(Seg seg, Buffer buffer)
}
/* SegBufferScanLimit -- limit of scannable objects in segment */
Addr SegBufferScanLimit(Seg seg)
{
Addr limit;
Buffer buf;
AVERT(Seg, seg);
buf = SegBuffer(seg);
if (buf == NULL) {
/* Segment is unbuffered: entire segment scannable */
limit = SegLimit(seg);
} else {
/* Segment is buffered: scannable up to limit of initialized objects. */
limit = BufferScanLimit(buf);
}
return limit;
}
/* SegDescribe -- describe a segment */
Res SegDescribe(Seg seg, mps_lib_FILE *stream, Count depth)

238
mps/code/sncss.c Normal file
View file

@ -0,0 +1,238 @@
/* sncss.c: SNC STRESS TEST
*
* $Id$
* Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
*/
#include "mpm.h"
#include "mpscmv.h"
#include "mpscmvt.h"
#include "mpscmvff.h"
#include "mpscsnc.h"
#include "mpsavm.h"
#include "mps.h"
#include "testlib.h"
#include <stdio.h> /* printf */
/* Simple format for the SNC pool. */
typedef struct obj_s {
size_t size;
int pad;
} obj_s, *obj_t;
/* make -- allocate one object, and if it's big enough, store the size
* in the first word, for the benefit of the object format */
static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size)
{
mps_addr_t addr;
mps_res_t res;
do {
obj_t obj;
res = mps_reserve(&addr, ap, size);
if (res != MPS_RES_OK)
return res;
obj = addr;
obj->size = size;
obj->pad = 0;
} while (!mps_commit(ap, addr, size));
*p = addr;
return MPS_RES_OK;
}
static mps_res_t fmtScan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
{
testlib_unused(ss);
testlib_unused(base);
testlib_unused(limit);
return MPS_RES_OK;
}
static mps_addr_t fmtSkip(mps_addr_t addr)
{
obj_t obj = addr;
return (char *)addr + obj->size;
}
static void fmtPad(mps_addr_t addr, size_t size)
{
obj_t obj = addr;
obj->size = size;
obj->pad = 1;
}
typedef struct env_s {
size_t obj;
size_t pad;
} env_s, *env_t;
static void fmtVisitor(mps_addr_t object, mps_fmt_t format,
mps_pool_t pool, void *p, size_t s)
{
env_t env = p;
obj_t obj = object;
testlib_unused(format);
testlib_unused(pool);
testlib_unused(s);
if (obj->pad)
env->pad += obj->size;
else
env->obj += obj->size;
}
#define AP_MAX 3 /* Number of allocation points */
#define DEPTH_MAX 20 /* Maximum depth of frame push */
typedef struct ap_s {
mps_ap_t ap; /* An allocation point on an ANC pool */
size_t depth; /* Number of frames pushed */
size_t alloc[DEPTH_MAX + 1]; /* Total allocation at each depth */
size_t push[DEPTH_MAX]; /* Total allocation when we pushed */
mps_frame_t frame[DEPTH_MAX]; /* The frame pointers at each depth */
} ap_s, *ap_t;
static void test(mps_pool_class_t pool_class)
{
size_t i, j;
mps_align_t align;
mps_arena_t arena;
mps_fmt_t fmt;
mps_pool_t pool;
ap_s aps[AP_MAX];
align = sizeof(obj_s) << (rnd() % 4);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none),
"mps_arena_create");
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_FMT_SCAN, fmtScan);
MPS_ARGS_ADD(args, MPS_KEY_FMT_SKIP, fmtSkip);
MPS_ARGS_ADD(args, MPS_KEY_FMT_PAD, fmtPad);
die(mps_fmt_create_k(&fmt, arena, args), "fmt_create");
} MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt);
die(mps_pool_create_k(&pool, arena, pool_class, args), "pool_create");
} MPS_ARGS_END(args);
for (i = 0; i < NELEMS(aps); ++i) {
ap_t a = &aps[i];
die(mps_ap_create_k(&a->ap, pool, mps_args_none), "ap_create");
a->depth = 0;
a->alloc[0] = 0;
}
for (i = 0; i < 1000000; ++i) {
size_t k = rnd() % NELEMS(aps);
ap_t a = &aps[k];
if (rnd() % 10 == 0) {
j = rnd() % NELEMS(a->frame);
if (j < a->depth) {
a->depth = j;
mps_ap_frame_pop(a->ap, a->frame[j]);
a->alloc[j] = a->push[j];
} else {
a->push[a->depth] = a->alloc[a->depth];
mps_ap_frame_push(&a->frame[a->depth], a->ap);
++ a->depth;
a->alloc[a->depth] = 0;
}
} else {
size_t size = alignUp(1 + rnd() % 128, align);
mps_addr_t p;
make(&p, a->ap, size);
a->alloc[a->depth] += size;
}
}
{
env_s env = {0, 0};
size_t alloc = 0;
size_t free = mps_pool_free_size(pool);
size_t total = mps_pool_total_size(pool);
for (i = 0; i < NELEMS(aps); ++i) {
ap_t a = &aps[i];
for (j = 0; j <= a->depth; ++j) {
alloc += a->alloc[j];
}
}
mps_arena_formatted_objects_walk(arena, fmtVisitor, &env, 0);
printf("alloc=%lu obj=%lu pad=%lu free=%lu total=%lu\n",
(unsigned long)alloc,
(unsigned long)env.obj,
(unsigned long)env.pad,
(unsigned long)free,
(unsigned long)total);
Insist(alloc == env.obj);
}
for (i = 0; i < NELEMS(aps); ++i) {
mps_ap_destroy(aps[i].ap);
}
mps_pool_destroy(pool);
mps_fmt_destroy(fmt);
mps_arena_destroy(arena);
}
int main(int argc, char *argv[])
{
testlib_init(argc, argv);
test(mps_class_snc());
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (c) 2001-2014 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:
*
* 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.
*/

View file

@ -14,9 +14,11 @@
#include "mpscams.h"
#include "mpscawl.h"
#include "mpsclo.h"
#include "mpscsnc.h"
#include "mpsavm.h"
#include "mpstd.h"
#include "mps.h"
#include "mpm.h"
#include <stdio.h> /* printf */
@ -88,12 +90,16 @@ static mps_addr_t make(void)
* ...2: comparing with what we expect for:
* pool
* fmt
*
* ...3: accumulating the count and size of objects found
*/
struct stepper_data {
mps_arena_t arena;
mps_pool_t expect_pool;
mps_fmt_t expect_fmt;
unsigned long count;
size_t count; /* number of non-padding objects found */
size_t objSize; /* total size of non-padding objects */
size_t padSize; /* total size of padding objects */
};
static void stepper(mps_addr_t object, mps_fmt_t format,
@ -104,6 +110,7 @@ static void stepper(mps_addr_t object, mps_fmt_t format,
mps_bool_t b;
mps_pool_t query_pool;
mps_fmt_t query_fmt;
size_t size;
Insist(s == sizeof *sd);
sd = p;
@ -120,20 +127,26 @@ static void stepper(mps_addr_t object, mps_fmt_t format,
Insist(b);
Insist(query_fmt == format);
Insist(format == sd->expect_fmt);
sd->count += 1;
return;
size = AddrOffset(object, dylan_skip(object));
if (dylan_ispad(object)) {
sd->padSize += size;
} else {
++ sd->count;
sd->objSize += size;
}
}
/* test -- the body of the test */
static void *test(mps_arena_t arena, mps_pool_class_t pool_class)
static void test(mps_arena_t arena, mps_pool_class_t pool_class)
{
mps_chain_t chain;
mps_fmt_t format;
mps_pool_t pool;
mps_root_t exactRoot;
size_t i;
size_t totalSize, freeSize, allocSize, bufferSize;
unsigned long objs;
struct stepper_data sdStruct, *sd;
@ -175,25 +188,38 @@ static void *test(mps_arena_t arena, mps_pool_class_t pool_class)
++objs;
}
mps_arena_park(arena);
sd = &sdStruct;
sd->arena = arena;
sd->expect_pool = pool;
sd->expect_fmt = format;
sd->count = 0;
sd->objSize = 0;
sd->padSize = 0;
mps_arena_formatted_objects_walk(arena, stepper, sd, sizeof *sd);
/* Note: stepper finds more than we expect, due to pad objects */
/* printf("stepper found %ld objs\n", sd->count); */
Insist(sd->count == objs);
totalSize = mps_pool_total_size(pool);
freeSize = mps_pool_free_size(pool);
allocSize = totalSize - freeSize;
bufferSize = AddrOffset(ap->init, ap->limit);
printf("%s: obj=%lu pad=%lu total=%lu free=%lu alloc=%lu buffer=%lu\n",
((Pool)pool)->class->name,
(unsigned long)sd->objSize,
(unsigned long)sd->padSize,
(unsigned long)totalSize,
(unsigned long)freeSize,
(unsigned long)allocSize,
(unsigned long)bufferSize);
Insist(sd->objSize + sd->padSize + bufferSize == allocSize);
mps_arena_park(arena);
mps_ap_destroy(ap);
mps_root_destroy(exactRoot);
mps_pool_destroy(pool);
mps_chain_destroy(chain);
mps_fmt_destroy(format);
mps_arena_release(arena);
return NULL;
}
int main(int argc, char *argv[])
@ -213,6 +239,7 @@ int main(int argc, char *argv[])
/* TODO: test(arena, mps_class_ams()); -- see job003738 */
test(arena, mps_class_awl());
test(arena, mps_class_lo());
test(arena, mps_class_snc());
mps_thread_dereg(thread);
mps_arena_destroy(arena);

View file

@ -170,11 +170,11 @@ as parameters.
_`.op.obligatory`: The following operations are supported on any
allocation point which supports allocation frames:-
_`.operation.push`: The ``PushFrame()`` operation creates a new
_`.operation.push`: The *FramePush* operation creates a new
allocation frame of the currently chosen frame class, makes this new
frame the current frame, and returns a handle for the frame.
_`.operation.pop`: The ``PopFrame()`` operation takes a frame handle
_`.operation.pop`: The *FramePop* operation takes a frame handle
as a parameter. Some pool classes might insist or assume that this is
the handle for the current frame. It finds the parent of that frame
and makes it the current frame. The operation indicates that all
@ -190,23 +190,23 @@ allocation frames, but not all. Pools may choose to support some or
all of these operations for certain frame classes. An unsupported
operation will return a failure value:-
_`.operation.select`: The ``SelectFrame()`` operation takes a frame
_`.operation.select`: The *FrameSelect* operation takes a frame
handle as a parameter and makes that frame the current frame. It does
not indicate that any children of the current frame contain objects
which are likely to be dead.
_`.operation.select-addr`: The ``SelectFrameOfAddr()`` operation takes
_`.operation.select-addr`: The *FrameSelectOfAddr* operation takes
an address as a parameter and makes the frame of that address the
current frame. It does not indicate that any children of the current
frame contain objects which are likely to be dead.
_`.operation.in-frame`: The ``AddrInFrame()`` operation determines
_`.operation.in-frame`: The *FrameHasAddr* operation determines
whether the supplied address is the address of an object allocated in
the supplied frame, or any child of that frame.
_`.operation.set`: The ``SetFrameClass()`` operation takes a frame
_`.operation.set`: The *SetFrameClass* operation takes a frame
class and an allocation point as parameters, and makes that the
current frame class for the allocation point. The next ``PushFrame()``
current frame class for the allocation point. The next *FramePush*
operation will create a new frame of that class.
@ -231,32 +231,32 @@ External functions
..................
_`.fn.client.push`: ``mps_ap_frame_push()`` is used by clients to
invoke the ``PushFrame()`` operation. For lightweight frames, this
invoke the *FramePush* operation. For lightweight frames, this
might not invoke the corresponding internal function.
_`.fn.client.pop`: ``mps_ap_frame_pop()`` is used by clients to invoke
the ``PopFrame()`` operation. For lightweight frames, this might not
the *FramePop* operation. For lightweight frames, this might not
invoke the corresponding internal function.
``mps_res_t mps_ap_frame_select(mps_ap_t buf, mps_frame_t frame)``
_`.fn.client.select`: This following function is used by clients to
invoke the ``SelectFrame()`` operation.
invoke the *FrameSelect* operation.
``mps_res_t mps_ap_frame_select_from_addr(mps_ap_t buf, mps_addr_t addr)``
_`.fn.client.select-addr`: This function is used by clients to invoke
the ``SelectFrameOfAddr()`` operation.
the *FrameSelectOfAddr* operation.
``mps_res_t mps_ap_addr_in_frame(mps_bool_t *inframe_o, mps_ap_t buf, mps_addr_t *addrref, mps_frame_t frame)``
_`.fn.client.in-frame`: This function is used by clients to invoke the
``AddrInFrame()`` operation.
*FrameHasAddr* operation.
``mps_res_t mps_ap_set_frame_class(mps_ap_t buf, mps_frame_class_t class)``
_`.fn.client.set`: This function is used by clients to invoke the
``SetFrameClass()`` operation.
*SetFrameClass* operation.
``mps_frame_class_t mps_alloc_frame_class_stack(void)``
@ -278,32 +278,32 @@ _`.type.frame-class`: Frame classes are defined as an abstract type.
``typedef Res (*PoolFramePushMethod)(AllocFrame *frameReturn, Pool pool, Buffer buf)``
_`.fn.push`: A pool method of this type is called (if needed) to
invoke the ``PushFrame()`` operation.
invoke the *FramePush* operation.
``typedef Res (*PoolFramePopMethod)(Pool pool, Buffer buf, AllocFrame frame)``
_`.fn.pop`: A pool method of this type is called (if needed)
to invoke the PopFrame operation:
to invoke the *FramePop* operation:
``typedef Res (*PoolFrameSelectMethod)(Pool pool, Buffer buf, AllocFrame frame)``
_`.fn.select`: A pool method of this type is called to invoke the
``SelectFrame()`` operation.
*FrameSelect* operation.
``typedef Res (*PoolFrameSelectFromAddrMethod)(Pool pool, Buffer buf, Addr addr)``
_`.fn.select-addr`: A pool method of this type is called to invoke the
``SelectFrameOfAddr()`` operation.
*FrameSelectOfAddr* operation.
``typedef Res (*PoolAddrInFrameMethod)(Bool *inframeReturn, Pool pool, Seg seg, Addr *addrref, AllocFrame frame)``
``typedef Res (*PoolFrameHasAddrMethod)(Bool *inframeReturn, Pool pool, Seg seg, Addr *addrref, AllocFrame frame)``
_`.fn.in-frame`: A pool method of this type is called to invoke the
``AddrInFrame()`` operation.
*FrameHasAddr* operation.
``typedef Res (*PoolSetFrameClassMethod)(Pool pool, Buffer buf, AllocFrameClass class)``
_`.fn.set`: A pool method of this type is called to invoke the
``SetFrameClass()`` operation.
*SetFrameClass* operation.
Lightweight frames
@ -313,96 +313,23 @@ Overview
........
_`.lw-frame.overview`: Allocation points provide direct support for
lightweight frames, and are designed to permit PushFrame and PopFrame
operations without the need for locking and delegation to the pool
method. Pools can disable this mechanism for any allocation point, so
that the pool method is always called. The pool method will be called
whenever synchronization is required for other reasons (e.g. the
buffer is tripped).
lightweight frames, and are designed to permit *FramePush* and
*FramePop* operations without the need for locking and delegation to
the pool method. The pool method will be called whenever
synchronization is required for other reasons (e.g. the buffer is
tripped).
_`.lw-frame.model`: Lightweight frames offer direct support for a
particular model of allocation frame use, whereby the PushFrame
particular model of allocation frame use, whereby the *FramePush*
operation returns the current allocation pointer as a frame handle,
and the PopFrame operation causes the allocation pointer to be reset
and the *FramePop* operation causes the allocation pointer to be reset
to the address of the frame handle. This model should be suitable for
simple stack frames, where more advanced operations like SelectFrame
simple stack frames, where more advanced operations like *FrameSelect*
are not supported. It may also be suitable for more advanced
allocation frame models when they are being used simply. The use of a
complex operation always involves synchronization via locking, and the
pool may disable lightweight synchronization temporarily at this time.
State
.....
_`.lw-frame.states`: Allocation points supporting lightweight frames
will be in one of the following states:
============ ================================================================
Valid Indicates that ``PushFrame()`` can be a lightweight
operation and need not be synchronized.
PopPending Indicates that there has been a ``PopFrame()`` operation
that the pool must respond to.
Disabled Indicates that the pool has disabled support for lightweight
operations for this AP.
============ ================================================================
These states are in addition to the state normally held by an AP for
allocation purposes. An AP will be in the Disabled state at creation.
_`.lw-frame.transitions`: State transitions happen under the following
circumstances:
======================= ====================================================
Valid → PopPending As a result of a client ``PopFrame()``
operation.
Valid → Disabled At the choice of the pool (for example, when
responding to a ``SelectFrame()`` operation).
PopPending → Valid At the choice of the pool, when processing a
``PopFrame()``.
PopPending → Disabled At the choice of the pool, when processing a
``PopFrame()``.
Disabled → Valid At the choice of the pool.
Disabled → Popframe Illegal.
======================= ====================================================
_`.lw-frame.state-impl`: Each AP contains 3 additional fields to hold this state::
mps_addr_t frameptr;
mps_bool_t enabled;
mps_bool_t lwPopPending;
_`.lw-frame.enabled`: The ``enabled`` slot holds the following values for
each state:
========== ==========
Valid ``TRUE``
PopPending ``TRUE``
Disabled ``FALSE``
========== ==========
_`.lw-frame.frameptr`: The ``frameptr`` slot holds the following values
for each state:
========== ============================================
Valid ``NULL``
PopPending Frame handle for most recently popped frame.
Disabled ``NULL``
========== ============================================
_`.lw-frame.lwPopPending`: The ``lwPopPending`` slot holds the
following values for each state:
========== =========
Valid ``FALSE``
PopPending ``TRUE``
Disabled ``FALSE``
========== =========
_`.lw-frame.state-for-gc`: It is not necessary for the tracer, format
code, pool, or any other part of the GC support in MPS to read either
of the two additional AP fields in order to scan a segment which
supports a lightweight allocation frame.
Synchronization
...............
@ -414,49 +341,51 @@ operation on an AP may only be performed by a single mutator thread at
a time. Each of the operations on allocation frames counts as an
operation on an AP.
_`.lw-frame.sync.pool`: Pools are permitted to read or modify the
lightweight frame state of an AP only in response to an operation on
that AP.
_`.lw-frame.sync.external`: The external functions
``mps_ap_frame_push()`` and ``mps_ap_frame_pop()`` are permitted to
read the values of the ``enabled`` and ``frameptr`` fields for the
supplied AP without claiming the arena lock. They are permitted to
modify the ``frameptr`` field if and only if ``enabled == FALSE``.
_`.lw-frame.sync.trip`: When a buffer trip happens, and the trap
wasn't set by MPS itself (that is, it wasn't because of a flip or for
logging), then the buffer code must check whether the AP has state
PopPending. If it does, the buffer code must call the Pool.
Implementation
..............
_`.lw-frame.push`: The external ``PushFrame()`` operation
(``mps_ap_frame_push()``) performs the following operations::
_`.lw-frame.push`: The external *FramePush* operation
``mps_ap_frame_push()`` performs the following operations::
IF (!APIsTrapped(ap) && StateOfFrame(ap) == Valid && ap->init == ap->alloc)
IF ap->init != ap->alloc
FAIL
ELSE IF ap->init < ap->limit
*frame_o = ap->init;
ELSE
WITH_ARENA_LOCK
PerformInternalPushFrameOperation(...)
PerformInternalFramePushOperation(...)
END
END
_`.lw-frame.pop`: The external ``PopFrame()`` operation
_`.lw-frame.push.limit`: The reason for testing ``ap->init <
ap->limit`` and not ``ap->init <= ap->limit`` is that a frame pointer
at the limit of a buffer (and possibly therefore of a segment) would
be ambiguous: is it at the limit of the segment, or at the base of the
segment that's adjacent in memory? The internal operation must handle
this case, for example by refilling the buffer and setting the frame
at the beginning.
_`.lw-frame.pop`: The external *FramePop* operation
(``mps_ap_frame_pop()``) performs the following operations::
IF (StateOfFrame(ap) != Disabled)
TrapAP(ap); /* ensure next allocation or push involves the pool */
ap->frameptr = frame;
ap->lwpopPending = TRUE;
IF ap->init != ap->alloc
FAIL
ELSE IF BufferBase(ap) <= frame AND frame < ap->init
ap->init = ap->alloc = frame;
ELSE
WITH_ARENA_LOCK
PerformInternalPopFrameOperation(...)
PerformInternalFramePopOperation(...)
END
END
_`.lw-frame.pop.buffer`: The reason for testing that ``frame`` is in
the buffer is that if it's not, then we're popping to an address in
some other segment, and that means that some objects in the other
segment (and all objects in any segments on the stack in between) are
now dead, and the only way for the pool to mark them as being dead is
to do a heavyweight pop.
Document History
----------------

View file

@ -277,29 +277,6 @@ Value Description
==================== ==================================================
``typedef unsigned FrameState``
_`.framestate`: ``FrameState`` represents the current state in a
buffer frame's lifecycle. See design.mps.alloc-frame_. It takes one of
the following values:
.. _design.mps.alloc-frame: alloc-frame
========================== ============================================
State Description
========================== ============================================
``BufferFrameVALID`` Indicates that ``PushFrame()`` can be a
lightweight operation and need not be
synchronized.
``BufferFramePOP_PENDING`` Indicates that there has been a
``PopFrame()`` operation that the pool
must respond to.
``BufferFrameDISABLED`` Indicates that the pool has disabled
support for lightweight operations for
this buffer.
========================== ============================================
``typedef void (*Fun)(void)``
_`.fun`: ``Fun`` is the type of a pointer to a function about which

View file

@ -20,13 +20,13 @@ TYPES = '''
AccessSet Accumulation Addr Align AllocFrame AllocPattern AP Arg
Arena Attr Bool BootBlock BT Buffer BufferMode Byte Chain Chunk
Clock Compare Count Epoch EventClock FindDelete Format FrameState
Fun GenDesc Globals Index Land LD Lock LocusPref LocusPrefKind
Message MessageType MutatorFaultContext Page Pointer Pool PoolGen
PThreadext Range Rank RankSet ReadonlyAddr Ref RefSet Res
Ring Root RootMode RootVar ScanState Seg SegBuf Serial
Shift Sig Size Space SplayNode SplayTree StackContext Thread Trace
TraceId TraceSet TraceStartWhy TraceState ULongest VM Word ZoneSet
Clock Compare Count Epoch EventClock FindDelete Format Fun GenDesc
Globals Index Land LD Lock LocusPref LocusPrefKind Message
MessageType MutatorFaultContext Page Pointer Pool PoolGen
PThreadext Range Rank RankSet ReadonlyAddr Ref RefSet Res Ring
Root RootMode RootVar ScanState Seg SegBuf Serial Shift Sig Size
Space SplayNode SplayTree StackContext Thread Trace TraceId
TraceSet TraceStartWhy TraceState ULongest VM Word ZoneSet
'''

View file

@ -144,16 +144,6 @@ Memory Management Glossary: D
.. see:: :term:`interior pointer`.
derived type
.. mps:specific::
In the MPS interface, a *derived type* is a type that is
neither an :term:`opaque type` nor a :term:`transparent
type`, but is instead a structure or function type based
on transparent and opaque types and on built-in C types.
See :ref:`topic-interface`.
destructor (1)
A destructor is a function or a method that performs the

View file

@ -169,7 +169,6 @@ All
:term:`deferred reference counting`
:term:`dependent object`
:term:`derived pointer <interior pointer>`
:term:`derived type`
:term:`destructor (1)`
:term:`destructor (2)`
:term:`DGC <distributed garbage collection>`

View file

@ -127,7 +127,7 @@ Memory Management Glossary: O
mps_arena_s *``, but the implementation of ``struct
mps_arena_s`` is not public. See :ref:`topic-interface`.
.. opposite:: :term:`derived type`, :term:`transparent type`.
.. opposite:: :term:`transparent type`.
out parameter

View file

@ -264,7 +264,7 @@ Memory Management Glossary: T
example, :c:type:`mps_addr_t` is a transparent alias for
``void *``. See :ref:`topic-interface`.
.. opposite:: :term:`derived type`, :term:`opaque type`.
.. opposite:: :term:`opaque type`.
transport

View file

@ -107,7 +107,7 @@ references (1)`.
Supports :c:func:`mps_alloc`?, no, no, no, no, no, yes, yes, yes, no, no
Supports :c:func:`mps_free`?, no, no, no, no, no, yes, yes, yes, yes, no
Supports allocation points?, yes, yes, yes, yes, yes, no, yes, yes, yes, yes
Supports allocation frames?, yes, yes, yes, yes, yes, no, no, yes, yes, yes
Manages memory using allocation frames?, no, no, no, no, no, no, no, no, no, yes
Supports segregated allocation caches?, no, no, no, no, no, yes, yes, yes, no, no
Timing of collections? [2]_, auto, auto, auto, auto, auto, ---, ---, ---, ---, ---
May contain references? [3]_, yes, no, yes, yes, no, no, no, no, no, yes

View file

@ -11,11 +11,6 @@
SNC (Stack No Checking)
=======================
.. deprecated:: starting with version 1.111.
If you need special handling of stack-like allocation,
:ref:`contact us <contact>`.
**SNC** is a :term:`manually managed <manual memory management>`
:term:`pool class` that supports a stack-like protocol for allocation
and deallocation using :term:`allocation frames` on :term:`allocation
@ -23,10 +18,15 @@ points`. See :ref:`topic-frame`.
If :c:func:`mps_ap_frame_pop` is used on an allocation point in an SNC
pool (after a corresponding call to :c:func:`mps_ap_frame_push`), then
the objects affected by the pop are effectively declared dead, and may
be reclaimed by the collector. Extant references to such objects from
reachable or *de facto* alive objects are safe, but such other objects
should be dead; that is, such references must never be used.
the objects affected by the pop are assumed to be dead, and are
reclaimed by the collector without checking whether there are any
references to them.
This pool class is intended to be used to implement stack languages
like Forth and PostScript, where some objects are allocated in stack
frames and are known to be dead when the stack is popped, because the
language can ensure that objects that are kept alive when the stack is
popped are copied to the heap.
.. index::

View file

@ -3,6 +3,28 @@
Release notes
=============
.. _release-notes-1.116:
Release 1.116.0
---------------
Interface changes
.................
#. The pool class :ref:`pool-snc` is no longer deprecated.
#. Allocation frames are no longer deprecated. See :ref:`topic-frame`.
Other changes
.............
#. Objects in :ref:`pool-snc` pools are no longer scanned after their
:term:`allocation frame` is popped, and so do not keep objects in
automatically managed pools alive. See job003883_.
.. _job003883: https://www.ravenbrook.com/project/mps/issue/job003883/
.. _release-notes-1.115:
@ -76,6 +98,10 @@ Interface changes
#. The function :c:func:`mps_root_create_table_masked` is deprecated in
favour of :c:func:`mps_root_create_table_tagged`.
#. The :ref:`pool-snc` pool class now implements
:c:func:`mps_pool_total_size` and :c:func:`mps_pool_free_size`.
Other changes
.............
@ -102,6 +128,12 @@ Other changes
.. _job003870: https://www.ravenbrook.com/project/mps/issue/job003870/
#. In the :term:`hot` (production) variety,
:c:func:`mps_pool_free_size` now returns the correct result for
:ref:`pool-awl` and :ref:`pool-lo` pools. See job003884_.
.. _job003884: https://www.ravenbrook.com/project/mps/issue/job003884/
#. 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

View file

@ -633,7 +633,6 @@ never fails).
mps_addr_t init;
mps_addr_t alloc;
mps_addr_t limit;
/* ... private fields ... */
} mps_ap_s;
``init`` is the limit of initialized memory.

View file

@ -13,11 +13,6 @@
Allocation frames
=================
.. deprecated:: starting with version 1.111.
If you need special handling of stack-like allocation,
:ref:`contact us <contact>`.
An allocation frame is a marker that can pushed onto an
:term:`allocation point` by calling :c:func:`mps_ap_frame_push`, and
then popped by calling :c:func:`mps_ap_frame_pop` to indicate that all
@ -27,14 +22,15 @@ dead (in the case of :term:`automatic <automatic memory management>`
pools).
Allocation frames can be used by the :term:`client program` to
efficiently implement stack-like patterns of allocation.
efficiently implement stack-like patterns of allocation, for example
in implementations of stack languages like Forth and PostScript, where
some objects are allocated in stack frames and die when the stack is
popped.
.. note::
All :term:`pool classes` that support :term:`allocation points`
also support pushing and popping of allocation frames, but only
the :ref:`pool-snc` pool class actually uses these frames to
manage its blocks.
The only :term:`pool class` in the MPS that supports allocation
frames is :ref:`pool-snc`.
.. c:type:: mps_frame_t

View file

@ -115,8 +115,8 @@ Identifiers
Types
-----
There are three kinds of types declared in the MPS interface:
*transparent types*, *opaque types*, and *derived types*.
There are two kinds of types declared in the MPS interface:
*transparent types* and *opaque types*.
#. A *transparent type* is an alias defined using ``typedef``, and this
is documented so that the :term:`client program` can rely on that
@ -138,13 +138,6 @@ There are three kinds of types declared in the MPS interface:
scanning macros such as :c:func:`MPS_SCAN_BEGIN` and
:c:func:`MPS_FIX12`.
#. A *derived type* is a structure or function type based on
transparent and opaque types and on built-in C types. The degree
to which you may or must depend upon the implementation of a
derived type is covered by the documentation for the type. For
example, the structure type :c:type:`mps_ap_s` has a mixture of
public and private members.
.. index::
single: interface; functions

View file

@ -37,6 +37,7 @@ poolncv
qs
sacss
segsmss
sncss
steptest =P
tagtest
teletest =N interactive