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:
commit
034d378148
34 changed files with 640 additions and 523 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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>. */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = (
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
238
mps/code/sncss.c
Normal 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.
|
||||
*/
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
----------------
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
'''
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>`
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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::
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ poolncv
|
|||
qs
|
||||
sacss
|
||||
segsmss
|
||||
sncss
|
||||
steptest =P
|
||||
tagtest
|
||||
teletest =N interactive
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue