From e9bac9cb1e7495d389f5b91c59b4cc653d1b4837 Mon Sep 17 00:00:00 2001 From: David Lovemore
) */
GenDescStruct topGen; /* generation descriptor for dynamic gen */
diff --git a/mps/code/mps.h b/mps/code/mps.h
index 758c1b389b4..fc1fb0fcd57 100644
--- a/mps/code/mps.h
+++ b/mps/code/mps.h
@@ -163,6 +163,9 @@ extern const struct mps_key_s _mps_key_arena_grain_size;
extern const struct mps_key_s _mps_key_arena_zoned;
#define MPS_KEY_ARENA_ZONED (&_mps_key_arena_zoned)
#define MPS_KEY_ARENA_ZONED_FIELD b
+extern const struct mps_key_s _mps_key_arena_incremental;
+#define MPS_KEY_ARENA_INCREMENTAL (&_mps_key_arena_incremental)
+#define MPS_KEY_ARENA_INCREMENTAL_FIELD b
extern const struct mps_key_s _mps_key_format;
#define MPS_KEY_FORMAT (&_mps_key_format)
#define MPS_KEY_FORMAT_FIELD format
diff --git a/mps/code/seg.c b/mps/code/seg.c
index 212b1f2baa7..ef930071850 100644
--- a/mps/code/seg.c
+++ b/mps/code/seg.c
@@ -1207,17 +1207,18 @@ static void gcSegSetGrey(Seg seg, TraceSet grey)
arena = PoolArena(SegPool(seg));
oldGrey = seg->grey;
gcSegSetGreyInternal(seg, oldGrey, grey); /* do the work */
-
/* The read barrier is raised when the segment is grey for */
/* some _flipped_ trace, i.e., is grey for a trace for which */
/* the mutator is black. */
- flippedTraces = arena->flippedTraces;
- if (TraceSetInter(oldGrey, flippedTraces) == TraceSetEMPTY) {
- if (TraceSetInter(grey, flippedTraces) != TraceSetEMPTY)
- ShieldRaise(arena, seg, AccessREAD);
- } else {
- if (TraceSetInter(grey, flippedTraces) == TraceSetEMPTY)
- ShieldLower(arena, seg, AccessREAD);
+ if (arena->incremental) {
+ flippedTraces = arena->flippedTraces;
+ if (TraceSetInter(oldGrey, flippedTraces) == TraceSetEMPTY) {
+ if (TraceSetInter(grey, flippedTraces) != TraceSetEMPTY)
+ ShieldRaise(arena, seg, AccessREAD);
+ } else {
+ if (TraceSetInter(grey, flippedTraces) == TraceSetEMPTY)
+ ShieldLower(arena, seg, AccessREAD);
+ }
}
EVENT3(SegSetGrey, arena, seg, grey);
diff --git a/mps/code/trace.c b/mps/code/trace.c
index 71d062a3e45..453977002cb 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -607,13 +607,14 @@ static Res traceFlip(Trace trace)
/* grey objects so that it can't obtain white pointers. This is */
/* achieved by read protecting all segments containing objects */
/* which are grey for any of the flipped traces. */
- for(rank = 0; rank < RankLIMIT; ++rank)
- RING_FOR(node, ArenaGreyRing(arena, rank), nextNode) {
- Seg seg = SegOfGreyRing(node);
- if(TraceSetInter(SegGrey(seg), arena->flippedTraces) == TraceSetEMPTY
- && TraceSetIsMember(SegGrey(seg), trace))
- ShieldRaise(arena, seg, AccessREAD);
- }
+ if (arena->incremental)
+ for (rank = 0; rank < RankLIMIT; ++rank)
+ RING_FOR(node, ArenaGreyRing(arena, rank), nextNode) {
+ Seg seg = SegOfGreyRing(node);
+ if(TraceSetInter(SegGrey(seg), arena->flippedTraces) == TraceSetEMPTY
+ && TraceSetIsMember(SegGrey(seg), trace))
+ ShieldRaise(arena, seg, AccessREAD);
+ }
/* @@@@ When write barrier collection is implemented, this is where */
/* write protection should be removed for all segments which are */
@@ -1134,7 +1135,10 @@ static Res traceScanSegRes(TraceSet ts, Rank rank, Arena arena, Seg seg)
* scan, consistent with the recorded SegSummary?
*/
AVER(RefSetSub(ScanStateUnfixedSummary(ss), SegSummary(seg)));
+
+ SegSetSummary(seg, RefSetUNIV);
+#if 0
if(res != ResOK || !wasTotal) {
/* scan was partial, so... */
/* scanned summary should be ORed into segment summary. */
@@ -1144,6 +1148,7 @@ static Res traceScanSegRes(TraceSet ts, Rank rank, Arena arena, Seg seg)
/* scanned summary should replace the segment summary. */
SegSetSummary(seg, ScanStateSummary(ss));
}
+#endif
ScanStateFinish(ss);
}
@@ -1817,7 +1822,6 @@ Size TracePoll(Globals globals)
Res res;
Arena arena;
Size scannedSize;
- Bool incremental = FALSE;
AVERT(Globals, globals);
arena = GlobalsArena(globals);
@@ -1891,7 +1895,7 @@ Size TracePoll(Globals globals)
oldScanned = traceWorkClock(trace);
do {
TraceQuantum(trace);
- } while(!incremental && trace->state != TraceFINISHED);
+ } while(!arena->incremental && trace->state != TraceFINISHED);
scannedSize = traceWorkClock(trace) - oldScanned;
if(trace->state == TraceFINISHED) {
TraceDestroy(trace);
From a1d1c3ff6e3de20158c634497a4f75e82f7921f6 Mon Sep 17 00:00:00 2001
From: David Lovemore
Date: Thu, 21 Aug 2014 14:03:09 +0100
Subject: [PATCH 004/759] Use write barrier in incremental mode.
This was previously completely disabled.
Copied from Perforce
Change: 186973
ServerID: perforce.ravenbrook.com
---
mps/code/trace.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/mps/code/trace.c b/mps/code/trace.c
index 453977002cb..4f5b1477d81 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -1136,19 +1136,19 @@ static Res traceScanSegRes(TraceSet ts, Rank rank, Arena arena, Seg seg)
*/
AVER(RefSetSub(ScanStateUnfixedSummary(ss), SegSummary(seg)));
-
- SegSetSummary(seg, RefSetUNIV);
-#if 0
- if(res != ResOK || !wasTotal) {
- /* scan was partial, so... */
- /* scanned summary should be ORed into segment summary. */
- SegSetSummary(seg, RefSetUnion(SegSummary(seg), ScanStateSummary(ss)));
+ if (arena->incremental) {
+ if(res != ResOK || !wasTotal) {
+ /* scan was partial, so... */
+ /* scanned summary should be ORed into segment summary. */
+ SegSetSummary(seg, RefSetUnion(SegSummary(seg), ScanStateSummary(ss)));
+ } else {
+ /* all objects on segment have been scanned, so... */
+ /* scanned summary should replace the segment summary. */
+ SegSetSummary(seg, ScanStateSummary(ss));
+ }
} else {
- /* all objects on segment have been scanned, so... */
- /* scanned summary should replace the segment summary. */
- SegSetSummary(seg, ScanStateSummary(ss));
+ SegSetSummary(seg, RefSetUNIV);
}
-#endif
ScanStateFinish(ss);
}
From d2439c4be7afb9bb809b95fd4b217cdb85f04b4a Mon Sep 17 00:00:00 2001
From: David Lovemore
Date: Thu, 21 Aug 2014 15:53:57 +0100
Subject: [PATCH 005/759] Added experimental control over write barrier
eagerness.
The write barrier is only raised after three unnecessary scans.
Copied from Perforce
Change: 186975
ServerID: perforce.ravenbrook.com
---
mps/code/config.h | 6 ++++++
mps/code/mpmst.h | 1 +
mps/code/seg.c | 1 +
mps/code/trace.c | 13 ++++++++++++-
4 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/mps/code/config.h b/mps/code/config.h
index ac5d7a849ec..59a44ee3780 100644
--- a/mps/code/config.h
+++ b/mps/code/config.h
@@ -635,6 +635,12 @@
{ 36 * 1024, 0.45 } /* second gen, after which dynamic */ \
}
+/* Experimental Scan Barrier threshold
+ *
+ * The number of unecessary scans performed, before raising the write
+ * barrier to remember the refset summary.
+ */
+#define TRACE_SCAN_BARRIER_THRESHOLD 3
#endif /* config_h */
diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h
index 219858f0f54..ba0be7aba58 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -300,6 +300,7 @@ typedef struct GCSegStruct { /* GC segment structure */
RingStruct greyRing; /* link in list of grey segs */
RefSet summary; /* summary of references out of seg */
Buffer buffer; /* non-NULL if seg is buffered */
+ unsigned unnecessaryScans; /* consecutive unnecessary scans performed */
Sig sig; /* */
} GCSegStruct;
diff --git a/mps/code/seg.c b/mps/code/seg.c
index ef930071850..e5923c170f7 100644
--- a/mps/code/seg.c
+++ b/mps/code/seg.c
@@ -1082,6 +1082,7 @@ static Res gcSegInit(Seg seg, Pool pool, Addr base, Size size,
gcseg->summary = RefSetEMPTY;
gcseg->buffer = NULL;
+ gcseg->unnecessaryScans = 0;
RingInit(&gcseg->greyRing);
gcseg->sig = GCSegSig;
diff --git a/mps/code/trace.c b/mps/code/trace.c
index 4f5b1477d81..bbe09b2d2c6 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -1105,6 +1105,7 @@ static Res traceScanSegRes(TraceSet ts, Rank rank, Arena arena, Seg seg)
} else { /* scan it */
ScanStateStruct ssStruct;
ScanState ss = &ssStruct;
+ Bool considerBarrier = FALSE;
ScanStateInit(ss, ts, arena, rank, white);
/* Expose the segment to make sure we can scan it. */
@@ -1135,8 +1136,18 @@ static Res traceScanSegRes(TraceSet ts, Rank rank, Arena arena, Seg seg)
* scan, consistent with the recorded SegSummary?
*/
AVER(RefSetSub(ScanStateUnfixedSummary(ss), SegSummary(seg)));
+ if (ZoneSetInter(ScanStateUnfixedSummary(ss), white) == ZoneSetEMPTY) {
+ /* a scan was not necessary */
+ if (((GCSeg)seg)->unnecessaryScans < TRACE_SCAN_BARRIER_THRESHOLD) {
+ ((GCSeg)seg)->unnecessaryScans++;
+ } else {
+ considerBarrier = TRUE;
+ }
+ } else {
+ ((GCSeg)seg)->unnecessaryScans = 0;
+ }
- if (arena->incremental) {
+ if (considerBarrier) {
if(res != ResOK || !wasTotal) {
/* scan was partial, so... */
/* scanned summary should be ORed into segment summary. */
From 476ce386fe4ac17816612711f932db7e6dd48b5d Mon Sep 17 00:00:00 2001
From: David Lovemore
Date: Wed, 27 Aug 2014 11:21:18 +0100
Subject: [PATCH 006/759] Added more control over write barrier. in particular
separated scans after a hit.
Copied from Perforce
Change: 186988
ServerID: perforce.ravenbrook.com
---
mps/code/config.h | 14 +++++++++++---
mps/code/mpmst.h | 2 +-
mps/code/seg.c | 2 +-
mps/code/trace.c | 16 ++++++++--------
4 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/mps/code/config.h b/mps/code/config.h
index 59a44ee3780..f9ce6fb9396 100644
--- a/mps/code/config.h
+++ b/mps/code/config.h
@@ -637,10 +637,18 @@
/* Experimental Scan Barrier threshold
*
- * The number of unecessary scans performed, before raising the write
- * barrier to remember the refset summary.
*/
-#define TRACE_SCAN_BARRIER_THRESHOLD 3
+/* Number of bits needed to keep the seg scan count */
+#define SEG_SCANS_BITS 10
+/* The number of unecessary scans performed, before raising the write
+ * barrier to remember the refset summary. */
+#define SEG_SCANS_INIT 3
+/* The number of unecessary scans performed, before raising the write
+ * barrier to remember the refset summary, after a necessary scan */
+#define SEG_SCANS_AFTER_NEEDED_SCAN 3
+/* The number of unecessary scans performed, before raising the write
+ * barrier to remember the refset summary, after a barrier hit */
+#define SEG_SCANS_AFTER_HIT 1
#endif /* config_h */
diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h
index ba0be7aba58..39625a470f6 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -285,6 +285,7 @@ typedef struct SegStruct { /* segment structure */
TraceSet white : TraceLIMIT; /* traces for which seg is white */
TraceSet nailed : TraceLIMIT; /* traces for which seg has nailed objects */
RankSet rankSet : RankLIMIT; /* ranks of references in this seg */
+ unsigned scans : SEG_SCANS_BITS; /* use write barrier after this many scans */
} SegStruct;
@@ -300,7 +301,6 @@ typedef struct GCSegStruct { /* GC segment structure */
RingStruct greyRing; /* link in list of grey segs */
RefSet summary; /* summary of references out of seg */
Buffer buffer; /* non-NULL if seg is buffered */
- unsigned unnecessaryScans; /* consecutive unnecessary scans performed */
Sig sig; /* */
} GCSegStruct;
diff --git a/mps/code/seg.c b/mps/code/seg.c
index e5923c170f7..99e3c48e47c 100644
--- a/mps/code/seg.c
+++ b/mps/code/seg.c
@@ -160,6 +160,7 @@ static Res SegInit(Seg seg, Pool pool, Addr base, Size size,
seg->grey = TraceSetEMPTY;
seg->pm = AccessSetEMPTY;
seg->sm = AccessSetEMPTY;
+ seg->scans = SEG_SCANS_INIT;
seg->depth = 0;
seg->firstTract = NULL;
@@ -1082,7 +1083,6 @@ static Res gcSegInit(Seg seg, Pool pool, Addr base, Size size,
gcseg->summary = RefSetEMPTY;
gcseg->buffer = NULL;
- gcseg->unnecessaryScans = 0;
RingInit(&gcseg->greyRing);
gcseg->sig = GCSegSig;
diff --git a/mps/code/trace.c b/mps/code/trace.c
index bbe09b2d2c6..2856d3339cb 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -1105,7 +1105,6 @@ static Res traceScanSegRes(TraceSet ts, Rank rank, Arena arena, Seg seg)
} else { /* scan it */
ScanStateStruct ssStruct;
ScanState ss = &ssStruct;
- Bool considerBarrier = FALSE;
ScanStateInit(ss, ts, arena, rank, white);
/* Expose the segment to make sure we can scan it. */
@@ -1138,16 +1137,14 @@ static Res traceScanSegRes(TraceSet ts, Rank rank, Arena arena, Seg seg)
AVER(RefSetSub(ScanStateUnfixedSummary(ss), SegSummary(seg)));
if (ZoneSetInter(ScanStateUnfixedSummary(ss), white) == ZoneSetEMPTY) {
/* a scan was not necessary */
- if (((GCSeg)seg)->unnecessaryScans < TRACE_SCAN_BARRIER_THRESHOLD) {
- ((GCSeg)seg)->unnecessaryScans++;
- } else {
- considerBarrier = TRUE;
- }
+ if (seg->scans > 0)
+ seg->scans--;
} else {
- ((GCSeg)seg)->unnecessaryScans = 0;
+ if (seg->scans < SEG_SCANS_AFTER_NEEDED_SCAN)
+ seg->scans = SEG_SCANS_AFTER_NEEDED_SCAN;
}
- if (considerBarrier) {
+ if (seg->scans == 0) {
if(res != ResOK || !wasTotal) {
/* scan was partial, so... */
/* scanned summary should be ORed into segment summary. */
@@ -1217,6 +1214,9 @@ void TraceSegAccess(Arena arena, Seg seg, AccessSet mode)
EVENT3(TraceAccess, arena, seg, mode);
+ if ((mode & SegSM(seg) & AccessWRITE) != 0) /* write barrier? */
+ seg->scans = SEG_SCANS_AFTER_HIT;
+
if((mode & SegSM(seg) & AccessREAD) != 0) { /* read barrier? */
Trace trace;
TraceId ti;
From a40ab9cb59a26abb9284817968923cc8407dda4e Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sat, 11 Oct 2014 13:38:51 +0100
Subject: [PATCH 007/759] Branching master to branch/2014-10-11/snc.
Copied from Perforce
Change: 187210
ServerID: perforce.ravenbrook.com
From 1c04adf17b4bf93d6b07dc2415d7caf6dd288f49 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sat, 11 Oct 2014 17:56:27 +0100
Subject: [PATCH 008/759] New function dylan_ispad determines if an object is a
padding object. (this is for use by test cases, to check that pools have
accounted correctly for padding objects.)
Copied from Perforce
Change: 187214
ServerID: perforce.ravenbrook.com
---
mps/code/fmtdy.c | 10 +++++++++-
mps/code/fmtdy.h | 6 ++++--
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/mps/code/fmtdy.c b/mps/code/fmtdy.c
index 0cb4adea11d..35f2c9e11cd 100644
--- a/mps/code/fmtdy.c
+++ b/mps/code/fmtdy.c
@@ -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 */
diff --git a/mps/code/fmtdy.h b/mps/code/fmtdy.h
index b7434abebd7..67483639c2b 100644
--- a/mps/code/fmtdy.h
+++ b/mps/code/fmtdy.h
@@ -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 */
From 77fc63dea3d51d76faeda7a01fbd45e819e17422 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sat, 11 Oct 2014 18:04:05 +0100
Subject: [PATCH 009/759] Add totalsize and freesize methods for snc.
Copied from Perforce
Change: 187215
ServerID: perforce.ravenbrook.com
---
mps/code/poolsnc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c
index df2d964340b..6bdf4597064 100644
--- a/mps/code/poolsnc.c
+++ b/mps/code/poolsnc.c
@@ -663,6 +663,52 @@ static void SNCWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
}
+/* SNCTotalSize -- total memory allocated from the arena */
+
+static Size SNCTotalSize(Pool pool)
+{
+ SNC snc;
+ Ring ring, node, nextNode;
+ Size total = 0;
+
+ AVERT(Pool, pool);
+ snc = PoolSNC(pool);
+ AVERT(SNC, snc);
+
+ ring = &pool->segRing;
+ RING_FOR(node, ring, nextNode) {
+ Seg seg = SegOfPoolRing(node);
+ AVERT(Seg, seg);
+ total += SegSize(seg);
+ }
+
+ return total;
+}
+
+
+/* SNCFreeSize -- free memory (unused by client program) */
+
+static Size SNCFreeSize(Pool pool)
+{
+ SNC snc;
+ Seg seg;
+ Size free = 0;
+
+ AVERT(Pool, pool);
+ snc = PoolSNC(pool);
+ AVERT(SNC, snc);
+
+ seg = snc->freeSegs;
+ while (seg != NULL) {
+ AVERT(Seg, seg);
+ free += SegSize(seg);
+ seg = sncSegNext(seg);
+ }
+
+ return free;
+}
+
+
/* SNCPoolClass -- the class definition */
DEFINE_POOL_CLASS(SNCPoolClass, this)
@@ -683,6 +729,8 @@ DEFINE_POOL_CLASS(SNCPoolClass, this)
this->framePopPending = SNCFramePopPending;
this->walk = SNCWalk;
this->bufferClass = SNCBufClassGet;
+ this->totalSize = SNCTotalSize;
+ this->freeSize = SNCFreeSize;
AVERT(PoolClass, this);
}
From cbdf8cc7b75c7a8ba2804482e430d3967e0b8dae Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sat, 11 Oct 2014 18:06:05 +0100
Subject: [PATCH 010/759] Make walkt0 test case much more stringent: it now
checks the size and count of the objects found in the walk.
Add SNC to the walkt0 test case.
Copied from Perforce
Change: 187216
ServerID: perforce.ravenbrook.com
---
mps/code/walkt0.c | 47 +++++++++++++++++++++++++++++++++++++----------
1 file changed, 37 insertions(+), 10 deletions(-)
diff --git a/mps/code/walkt0.c b/mps/code/walkt0.c
index 6a378ffe659..332202bfd86 100644
--- a/mps/code/walkt0.c
+++ b/mps/code/walkt0.c
@@ -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 /* 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);
From 8bffa21ca92d1e83005554bb7b7c51a5e1a8da08 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sat, 11 Oct 2014 21:07:29 +0100
Subject: [PATCH 011/759] New test case sncss.
Copied from Perforce
Change: 187217
ServerID: perforce.ravenbrook.com
---
mps/code/comm.gmk | 6 +-
mps/code/commpost.nmk | 3 +
mps/code/commpre.nmk | 1 +
mps/code/sncss.c | 201 +++++++++++++++++++++++++++++++++++++++++
mps/tool/testcases.txt | 1 +
5 files changed, 211 insertions(+), 1 deletion(-)
create mode 100644 mps/code/sncss.c
diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk
index 2eb68381a3f..dd8eff633fb 100644
--- a/mps/code/comm.gmk
+++ b/mps/code/comm.gmk
@@ -283,6 +283,7 @@ TEST_TARGETS=\
qs \
sacss \
segsmss \
+ sncss \
steptest \
teletest \
walkt0 \
@@ -511,12 +512,15 @@ $(PFM)/$(VARIETY)/sacss: $(PFM)/$(VARIETY)/sacss.o \
$(PFM)/$(VARIETY)/segsmss: $(PFM)/$(VARIETY)/segsmss.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
-$(PFM)/$(VARIETY)/teletest: $(PFM)/$(VARIETY)/teletest.o \
+$(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)/teletest: $(PFM)/$(VARIETY)/teletest.o \
+ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
+
$(PFM)/$(VARIETY)/walkt0: $(PFM)/$(VARIETY)/walkt0.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk
index ffb6b6a9efb..7eeb735c674 100644
--- a/mps/code/commpost.nmk
+++ b/mps/code/commpost.nmk
@@ -225,6 +225,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)
diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk
index 147c438bd02..0a9d6a04391 100644
--- a/mps/code/commpre.nmk
+++ b/mps/code/commpre.nmk
@@ -91,6 +91,7 @@ TEST_TARGETS=\
qs.exe \
sacss.exe \
segsmss.exe \
+ sncss.exe \
steptest.exe \
teletest.exe \
walkt0.exe \
diff --git a/mps/code/sncss.c b/mps/code/sncss.c
new file mode 100644
index 00000000000..ffd15b5d471
--- /dev/null
+++ b/mps/code/sncss.c
@@ -0,0 +1,201 @@
+/* framess.c: ALLOCATION FRAME 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 /* printf */
+
+
+/* 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 obj;
+ mps_res_t res;
+
+ do {
+ res = mps_reserve(&obj, ap, size);
+ if(res != MPS_RES_OK)
+ return res;
+ if(size >= sizeof size)
+ *(size_t *)obj = size;
+ } while(!mps_commit(ap, *p, size));
+
+ *p = obj;
+ return MPS_RES_OK;
+}
+
+
+/* Simple format for the SNC pool. Each object starts with a word
+ giving its length. */
+
+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)
+{
+ size_t *obj = addr;
+ return (char *)addr + *obj;
+}
+
+static void fmtPad(mps_addr_t addr, size_t size)
+{
+ size_t *obj = addr;
+ *obj = size;
+}
+
+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;
+ struct ap_s {
+ mps_ap_t ap;
+ size_t frames;
+ mps_frame_t frame[20];
+ size_t alloc[21];
+ } aps[3];
+
+ align = sizeof(void *) << (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) {
+ struct ap_s *a = &aps[i];
+ die(mps_ap_create_k(&a->ap, pool, mps_args_none), "ap_create");
+ a->frames = 0;
+ a->alloc[0] = 0;
+ }
+
+ for (i = 0; i < 100000; ++i) {
+ size_t k = rnd() % NELEMS(aps);
+ struct ap_s *a = &aps[k];
+ if (rnd() % 100 == 0) {
+ j = rnd() % NELEMS(a->frame);
+ if (j < a->frames) {
+ a->frames = j;
+ mps_ap_frame_pop(a->ap, a->frame[j]);
+ printf("%lu: pop %lu\n", (unsigned long)k, (unsigned long)j);
+ } else {
+ mps_ap_frame_push(&a->frame[a->frames], a->ap);
+ printf("%lu: push %lu\n", (unsigned long)k, (unsigned long)a->frames);
+ ++ a->frames;
+ a->alloc[a->frames] = 0;
+ }
+ } else {
+ size_t size = alignUp(1 + rnd() % 128, align);
+ mps_addr_t p;
+ make(&p, a->ap, size);
+ a->alloc[a->frames] += size;
+ }
+ }
+
+ {
+ size_t alloc = 0;
+ size_t unused = 0;
+ for (i = 0; i < NELEMS(aps); ++i) {
+ struct ap_s *a = &aps[i];
+ for (j = 0; j <= a->frames; ++j) {
+ alloc += a->alloc[j];
+ }
+ unused += AddrOffset(a->ap->init, a->ap->limit);
+ }
+ printf("alloc=%lu unused=%lu, total=%lu free=%lu a+u+f=%lu\n",
+ (unsigned long)alloc,
+ (unsigned long)unused,
+ (unsigned long)mps_pool_total_size(pool),
+ (unsigned long)mps_pool_free_size(pool),
+ (unsigned long)(alloc + unused + mps_pool_free_size(pool)));
+ }
+
+ 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 .
+ * 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.
+ */
diff --git a/mps/tool/testcases.txt b/mps/tool/testcases.txt
index 0b45b8cc548..98a3fb60e88 100644
--- a/mps/tool/testcases.txt
+++ b/mps/tool/testcases.txt
@@ -37,6 +37,7 @@ poolncv
qs
sacss
segsmss
+sncss
steptest =P
teletest =N interactive
walkt0
From 531e7cf14df01d5ad45a394168abcee6576e76d7 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sun, 12 Oct 2014 11:20:55 +0100
Subject: [PATCH 012/759] Check that the found segment belongs to the right
pool.
Copied from Perforce
Change: 187219
ServerID: perforce.ravenbrook.com
---
mps/code/poolsnc.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c
index 6bdf4597064..a3dfe841c93 100644
--- a/mps/code/poolsnc.c
+++ b/mps/code/poolsnc.c
@@ -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;
@@ -490,7 +490,7 @@ static void SNCBufferEmpty(Pool pool, Buffer buffer,
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);
@@ -551,7 +551,7 @@ static Res SNCFramePush(AllocFrame *frameReturn, Pool pool, Buffer buf)
AVERT(Buffer, buf);
state = BufferFrameState(buf);
- /* Sould have been notified of pending pops before this */
+ /* Should have been notified of pending pops before this */
AVER(state == BufferFrameVALID || state == BufferFrameDISABLED);
if (state == BufferFrameDISABLED) {
AVER(BufferIsReset(buf)); /* The buffer must be reset */
@@ -607,6 +607,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 */
From 49341c0ad5d5c11d4bb7935dbc488cddaa3b3a63 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sun, 12 Oct 2014 11:58:13 +0100
Subject: [PATCH 013/759] Don't set a frame pointer at the limit of a segment,
as this is ambiguous: is it at the limit of the segment, or at the base of
the segment that's adjacent in memory?
Copied from Perforce
Change: 187220
ServerID: perforce.ravenbrook.com
---
mps/code/mpsi.c | 2 +-
mps/code/poolsnc.c | 15 ++++++++++++++-
mps/design/alloc-frame.txt | 19 ++++++++++++++++---
3 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index 69e072a3d7b..a692f43d170 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -950,7 +950,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->_lwpoppending && mps_ap->init < mps_ap->limit) {
/* Valid state for a lightweight push */
*frame_o = (mps_frame_t)mps_ap->init;
return MPS_RES_OK;
diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c
index a3dfe841c93..081f5e73c50 100644
--- a/mps/code/poolsnc.c
+++ b/mps/code/poolsnc.c
@@ -558,9 +558,22 @@ static Res SNCFramePush(AllocFrame *frameReturn, Pool pool, Buffer buf)
AVER(sncBufferTopSeg(buf) == NULL); /* The stack must be empty */
/* Use NULL to indicate an empty stack. .lw-frame-null */
*frameReturn = NULL;
- } else {
+ } else if (BufferScanLimit(buf) < SegLimit(BufferSeg(buf))) {
/* Use the scan limit as the lightweight frame pointer */
*frameReturn = (AllocFrame)BufferScanLimit(buf);
+ } else {
+ /* Can't use the scan limit as the lightweight frame pointer as
+ * 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), FALSE);
+ if (res != ResOK)
+ return res;
+ BufferAttach(buf, base, limit, base, 0);
+ AVER(BufferScanLimit(buf) < SegLimit(BufferSeg(buf)));
+ *frameReturn = (AllocFrame)BufferScanLimit(buf);
}
return ResOK;
}
diff --git a/mps/design/alloc-frame.txt b/mps/design/alloc-frame.txt
index b199c2c567f..c00e0aeae7b 100644
--- a/mps/design/alloc-frame.txt
+++ b/mps/design/alloc-frame.txt
@@ -434,9 +434,13 @@ Implementation
..............
_`.lw-frame.push`: The external ``PushFrame()`` operation
-(``mps_ap_frame_push()``) performs the following operations::
+``mps_ap_frame_push()`` performs the following operations::
- IF (!APIsTrapped(ap) && StateOfFrame(ap) == Valid && ap->init == ap->alloc)
+ IF !APIsTrapped(ap)
+ AND StateOfFrame(ap) == Valid
+ AND ap->init == ap->alloc
+ AND ap->init < ap->limit
+ THEN
*frame_o = ap->init;
ELSE
WITH_ARENA_LOCK
@@ -444,10 +448,19 @@ _`.lw-frame.push`: The external ``PushFrame()`` operation
END
END
+_`.lw-frame.push.limit`: The reason for not using the lightweight
+operation when ``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 ``PopFrame()`` operation
(``mps_ap_frame_pop()``) performs the following operations::
- IF (StateOfFrame(ap) != Disabled)
+ IF StateOfFrame(ap) != Disabled
+ THEN
TrapAP(ap); /* ensure next allocation or push involves the pool */
ap->frameptr = frame;
ap->lwpopPending = TRUE;
From 7622475a16a77d38961aef8320fcc7bfa56dcf54 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sun, 12 Oct 2014 13:58:26 +0100
Subject: [PATCH 014/759] Add sncss test case to xcode project.
Copied from Perforce
Change: 187222
ServerID: perforce.ravenbrook.com
---
mps/code/mps.xcodeproj/project.pbxproj | 110 ++++++++++++++++++++++++-
1 file changed, 109 insertions(+), 1 deletion(-)
diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj
index c83a1026d6e..082caf1b671 100644
--- a/mps/code/mps.xcodeproj/project.pbxproj
+++ b/mps/code/mps.xcodeproj/project.pbxproj
@@ -112,6 +112,7 @@
22B2BC3918B643AD00C33E63 /* PBXTargetDependency */,
22B2BC3B18B643B000C33E63 /* PBXTargetDependency */,
3104B04A156D3AE4000A585A /* PBXTargetDependency */,
+ 229E228819EAB10D00E21417 /* PBXTargetDependency */,
31D6009D156D404B00337B26 /* PBXTargetDependency */,
3114A62E156E94AA001E0AA3 /* PBXTargetDependency */,
3114A6B9156E9763001E0AA3 /* PBXTargetDependency */,
@@ -134,6 +135,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 */; };
@@ -392,6 +396,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 */;
@@ -462,6 +473,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 */;
@@ -1001,6 +1019,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;
@@ -1406,6 +1433,8 @@
2231BB6918CA983C002D6322 /* locusss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = locusss.c; sourceTree = ""; };
223475CB194CA09500C69128 /* vm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vm.c; sourceTree = ""; };
223475CC194CA09500C69128 /* vm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vm.h; sourceTree = ""; };
+ 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 = ""; };
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 = ""; };
22561A9618F4263300372C66 /* testthr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = testthr.h; sourceTree = ""; };
@@ -1735,6 +1764,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 223E795E19EAB00B00DC26A6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 223E795F19EAB00B00DC26A6 /* libmps.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
224CC792175E1821002FF81B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -2207,7 +2244,6 @@
3124CAB3156BE1B700753214 /* Tests */ = {
isa = PBXGroup;
children = (
- 22F846AF18F4379C00982BA7 /* lockut.c */,
3114A63D156E94EA001E0AA3 /* abqtest.c */,
22FACED1188807FF000FDBC1 /* airtest.c */,
3124CAF5156BE81100753214 /* amcss.c */,
@@ -2240,6 +2276,7 @@
2291A5E9175CB4EC001D4920 /* landtest.c */,
2231BB6818CA9834002D6322 /* locbwcss.c */,
31D60036156D3E0200337B26 /* lockcov.c */,
+ 22F846AF18F4379C00982BA7 /* lockut.c */,
2231BB6918CA983C002D6322 /* locusss.c */,
3114A5A1156E9168001E0AA3 /* locv.c */,
3114A69F156E9725001E0AA3 /* messtest.c */,
@@ -2251,6 +2288,7 @@
3114A5B7156E92F0001E0AA3 /* qs.c */,
3104AFD6156D3602000A585A /* sacss.c */,
31D60006156D3C5F00337B26 /* segsmss.c */,
+ 223E796619EAB04100DC26A6 /* sncss.c */,
31D60098156D403C00337B26 /* steptest.c */,
3114A628156E949A001E0AA3 /* teletest.c */,
31EEAC9E156AB73400714D05 /* testlib.c */,
@@ -2351,6 +2389,7 @@
22FACEED18880983000FDBC1 /* airtest */,
22C2ACAF18BE400A006B3677 /* nailboardtest */,
22F846BD18F437B900982BA7 /* lockut */,
+ 223E796519EAB00B00DC26A6 /* sncss */,
);
name = Products;
sourceTree = "";
@@ -2576,6 +2615,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" */;
@@ -3442,6 +3499,7 @@
3114A5A6156E92C0001E0AA3 /* qs */,
3104AFC7156D35E2000A585A /* sacss */,
3104B03C156D3AD7000A585A /* segsmss */,
+ 223E795819EAB00B00DC26A6 /* sncss */,
31D6008B156D402900337B26 /* steptest */,
3114A61B156E9485001E0AA3 /* teletest */,
3114A6AB156E9759001E0AA3 /* walkt0 */,
@@ -3548,6 +3606,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;
@@ -4066,6 +4133,11 @@
target = 2231BB5A18CA97DC002D6322 /* locusss */;
targetProxy = 2231BB6E18CA986D002D6322 /* PBXContainerItemProxy */;
};
+ 223E795919EAB00B00DC26A6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 31EEABFA156AAF9D00714D05 /* mps */;
+ targetProxy = 223E795A19EAB00B00DC26A6 /* PBXContainerItemProxy */;
+ };
224CC78D175E1821002FF81B /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 31EEABFA156AAF9D00714D05 /* mps */;
@@ -4116,6 +4188,11 @@
target = 2291A5C1175CAFCA001D4920 /* expt825 */;
targetProxy = 2291A5E7175CB20E001D4920 /* PBXContainerItemProxy */;
};
+ 229E228819EAB10D00E21417 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 223E795819EAB00B00DC26A6 /* sncss */;
+ targetProxy = 229E228719EAB10D00E21417 /* PBXContainerItemProxy */;
+ };
22B2BC3918B643AD00C33E63 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 31FCAE0917692403008C034C /* scheme */;
@@ -4615,6 +4692,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 = {
@@ -5840,6 +5938,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 = (
From b06795251e40707d8b45affa3f6ee97d04f4a124 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sun, 12 Oct 2014 15:20:57 +0100
Subject: [PATCH 015/759] Fix scanning/walking for snc:
Record which segments are free and don't walk them (objects in these segments are dead).
If a buffered segment has a pending pop, don't scan or walk objects beyond the address that's going to be popped to (these objects are also dead).
Don't try to do a lightweight pop to an address that's not in the segment attached to the buffer -- the segment being popped to (and any other segments on the stack in between) are now dead, and the only way to mark them as being dead is to do a heavyweight pop.
Copied from Perforce
Change: 187224
ServerID: perforce.ravenbrook.com
---
mps/code/mpsi.c | 14 +++--
mps/code/poolsnc.c | 92 +++++++++++++++++++++------------
mps/code/sncss.c | 125 +++++++++++++++++++++++++++++----------------
3 files changed, 149 insertions(+), 82 deletions(-)
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index a692f43d170..96b1b6937f7 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -983,6 +983,8 @@ 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;
+
AVER(mps_ap != NULL);
/* Can't check frame because it's an arbitrary value */
@@ -991,8 +993,14 @@ 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 */
+ buf = BufferOfAP(mps_ap);
+ AVER(TESTT(Buffer, buf));
+
+ if (mps_ap->_enabled
+ && BufferBase(buf) <= (Addr)frame
+ && (mps_addr_t)frame < mps_ap->init)
+ {
+ /* Lightweight pop to address in same buffer */
mps_ap->_frameptr = (mps_addr_t)frame; /* record pending pop */
mps_ap->_lwpoppending = TRUE;
mps_ap->limit = (mps_addr_t)0; /* trap the buffer */
@@ -1000,11 +1008,9 @@ mps_res_t (mps_ap_frame_pop)(mps_ap_t mps_ap, mps_frame_t frame)
} else {
/* Need a heavyweight pop */
- Buffer buf = BufferOfAP(mps_ap);
Arena arena;
Res res;
- AVER(TESTT(Buffer, buf));
arena = BufferArena(buf);
ArenaEnter(arena);
diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c
index 081f5e73c50..4a992e4ca52 100644
--- a/mps/code/poolsnc.c
+++ b/mps/code/poolsnc.c
@@ -200,18 +200,20 @@ typedef struct SNCSegStruct *SNCSeg;
typedef struct SNCSegStruct {
GCSegStruct gcSegStruct; /* superclass fields must come first */
SNCSeg next; /* Next segment in chain, or NULL */
+ Bool free; /* Segment is free? */
Sig sig;
} 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)))
+#define sncSegFree(seg) RVALUE(SegSNCSeg(seg)->free)
+#define sncSegSetFree(seg, _free) ((void)(SegSNCSeg(seg)->free = (_free)))
+
ATTRIBUTE_UNUSED
static Bool SNCSegCheck(SNCSeg sncseg)
{
@@ -220,6 +222,7 @@ static Bool SNCSegCheck(SNCSeg sncseg)
if (NULL != sncseg->next) {
CHECKS(SNCSeg, sncseg->next);
}
+ CHECKL(BoolCheck(sncseg->free));
return TRUE;
}
@@ -246,6 +249,7 @@ static Res sncSegInit(Seg seg, Pool pool, Addr base, Size size,
return res;
sncseg->next = NULL;
+ sncseg->free = TRUE;
sncseg->sig = SNCSegSig;
AVERT(SNCSeg, sncseg);
return ResOK;
@@ -273,6 +277,7 @@ static void sncRecordAllocatedSeg(Buffer buffer, Seg seg)
AVERT(Seg, seg);
AVER(sncSegNext(seg) == NULL);
+ sncSegSetFree(seg, FALSE);
sncSegSetNext(seg, sncBufferTopSeg(buffer));
sncBufferSetTopSeg(buffer, seg);
}
@@ -291,6 +296,7 @@ static void sncRecordFreeSeg(SNC snc, Seg seg)
SegSetGrey(seg, TraceSetEMPTY);
SegSetRankAndSummary(seg, RankSetEMPTY, RefSetEMPTY);
+ sncSegSetFree(seg, TRUE);
sncSegSetNext(seg, snc->freeSegs);
snc->freeSegs = seg;
}
@@ -500,6 +506,42 @@ static void SNCBufferEmpty(Pool pool, Buffer buffer,
}
+/* SNCScanLimit -- limit of scannable objects in segment */
+
+static Addr SNCScanLimit(Arena arena, Seg seg)
+{
+ Addr limit;
+ Buffer buf;
+ buf = SegBuffer(seg);
+ if (buf == NULL) {
+ /* Segment is unbuffered: entire segment scannable */
+ limit = SegLimit(seg);
+ } else if (BufferFrameState(buf) != BufferFramePOP_PENDING) {
+ /* No pop pending: scannable up to limit of initialized objects. */
+ limit = BufferScanLimit(buf);
+ } else {
+ Addr addr = (Addr)buf->ap_s._frameptr;
+ if (addr == NULL) {
+ /* Pop pending to bottom of stack */
+ limit = BufferBase(buf);
+ } else {
+ Seg popSeg;
+ Bool foundSeg = SegOfAddr(&popSeg, arena, addr);
+ AVER(foundSeg);
+ if (popSeg == seg) {
+ /* Pop pending to address in same segment */
+ AVER(addr <= BufferScanLimit(buf)); /* check direction of pop */
+ limit = addr;
+ } else {
+ /* Pop pending to address in different segment */
+ limit = BufferBase(buf);
+ }
+ }
+ }
+ return limit;
+}
+
+
static Res SNCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
{
Addr base, limit;
@@ -516,14 +558,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 = SNCScanLimit(PoolArena(pool), seg);
if (base < limit) {
res = (*format->scan)(&ss->ss_s, base, limit);
@@ -579,21 +614,6 @@ static Res SNCFramePush(AllocFrame *frameReturn, Pool pool, Buffer buf)
}
-
-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;
@@ -638,6 +658,16 @@ static void SNCFramePopPending(Pool pool, Buffer buf, AllocFrame frame)
}
+static Res SNCFramePop(Pool pool, Buffer buf, AllocFrame frame)
+{
+ AVERT(Pool, pool);
+ AVERT(Buffer, buf);
+ BufferFrameSetState(buf, BufferFrameVALID);
+ SNCFramePopPending(pool, buf, frame);
+ return ResOK;
+}
+
+
static void SNCWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
void *p, size_t s)
{
@@ -648,7 +678,7 @@ static void SNCWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
/* Avoid applying the function to grey objects. */
/* They may have pointers to old-space. */
- if (SegGrey(seg) == TraceSetEMPTY) {
+ if (SegGrey(seg) == TraceSetEMPTY && !sncSegFree(seg)) {
Addr object = SegBase(seg);
Addr nextObject;
Addr limit;
@@ -658,13 +688,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 = SNCScanLimit(PoolArena(pool), seg);
while(object < limit) {
(*f)(object, format, pool, p, s);
diff --git a/mps/code/sncss.c b/mps/code/sncss.c
index ffd15b5d471..e6f62e30911 100644
--- a/mps/code/sncss.c
+++ b/mps/code/sncss.c
@@ -16,30 +16,35 @@
#include /* 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 obj;
+ mps_addr_t addr;
mps_res_t res;
do {
- res = mps_reserve(&obj, ap, size);
- if(res != MPS_RES_OK)
+ obj_t obj;
+ res = mps_reserve(&addr, ap, size);
+ if (res != MPS_RES_OK)
return res;
- if(size >= sizeof size)
- *(size_t *)obj = size;
- } while(!mps_commit(ap, *p, size));
+ obj = addr;
+ obj->size = size;
+ obj->pad = 0;
+ } while (!mps_commit(ap, addr, size));
- *p = obj;
+ *p = addr;
return MPS_RES_OK;
}
-
-/* Simple format for the SNC pool. Each object starts with a word
- giving its length. */
-
static mps_res_t fmtScan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
{
testlib_unused(ss);
@@ -50,16 +55,47 @@ static mps_res_t fmtScan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
static mps_addr_t fmtSkip(mps_addr_t addr)
{
- size_t *obj = addr;
- return (char *)addr + *obj;
+ obj_t obj = addr;
+ return (char *)addr + obj->size;
}
static void fmtPad(mps_addr_t addr, size_t size)
{
- size_t *obj = addr;
- *obj = 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;
@@ -67,14 +103,9 @@ static void test(mps_pool_class_t pool_class)
mps_arena_t arena;
mps_fmt_t fmt;
mps_pool_t pool;
- struct ap_s {
- mps_ap_t ap;
- size_t frames;
- mps_frame_t frame[20];
- size_t alloc[21];
- } aps[3];
+ ap_s aps[AP_MAX];
- align = sizeof(void *) << (rnd() % 4);
+ align = sizeof(obj_s) << (rnd() % 4);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none),
"mps_arena_create");
@@ -93,51 +124,57 @@ static void test(mps_pool_class_t pool_class)
} MPS_ARGS_END(args);
for (i = 0; i < NELEMS(aps); ++i) {
- struct ap_s *a = &aps[i];
+ ap_t a = &aps[i];
die(mps_ap_create_k(&a->ap, pool, mps_args_none), "ap_create");
- a->frames = 0;
+ a->depth = 0;
a->alloc[0] = 0;
}
- for (i = 0; i < 100000; ++i) {
+ for (i = 0; i < 1000000; ++i) {
size_t k = rnd() % NELEMS(aps);
- struct ap_s *a = &aps[k];
- if (rnd() % 100 == 0) {
+ ap_t a = &aps[k];
+ if (rnd() % 10 == 0) {
j = rnd() % NELEMS(a->frame);
- if (j < a->frames) {
- a->frames = j;
+ if (j < a->depth) {
+ a->depth = j;
mps_ap_frame_pop(a->ap, a->frame[j]);
- printf("%lu: pop %lu\n", (unsigned long)k, (unsigned long)j);
+ a->alloc[j] = a->push[j];
} else {
- mps_ap_frame_push(&a->frame[a->frames], a->ap);
- printf("%lu: push %lu\n", (unsigned long)k, (unsigned long)a->frames);
- ++ a->frames;
- a->alloc[a->frames] = 0;
+ 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->frames] += size;
+ a->alloc[a->depth] += size;
}
}
{
+ env_s env = {0, 0};
size_t alloc = 0;
- size_t unused = 0;
+ size_t free = mps_pool_free_size(pool);
+ size_t total = mps_pool_total_size(pool);
+
for (i = 0; i < NELEMS(aps); ++i) {
- struct ap_s *a = &aps[i];
- for (j = 0; j <= a->frames; ++j) {
+ ap_t a = &aps[i];
+ for (j = 0; j <= a->depth; ++j) {
alloc += a->alloc[j];
}
- unused += AddrOffset(a->ap->init, a->ap->limit);
}
- printf("alloc=%lu unused=%lu, total=%lu free=%lu a+u+f=%lu\n",
+
+ 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)unused,
- (unsigned long)mps_pool_total_size(pool),
- (unsigned long)mps_pool_free_size(pool),
- (unsigned long)(alloc + unused + mps_pool_free_size(pool)));
+ (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) {
From 021dc7b98f54c08a64aa8ad80cd1459d690344df Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sun, 12 Oct 2014 15:24:53 +0100
Subject: [PATCH 016/759] Update the design of the frame pop algorithm, with
justification.
Copied from Perforce
Change: 187225
ServerID: perforce.ravenbrook.com
---
mps/design/alloc-frame.txt | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/mps/design/alloc-frame.txt b/mps/design/alloc-frame.txt
index c00e0aeae7b..9da25ed5b37 100644
--- a/mps/design/alloc-frame.txt
+++ b/mps/design/alloc-frame.txt
@@ -460,6 +460,8 @@ _`.lw-frame.pop`: The external ``PopFrame()`` operation
(``mps_ap_frame_pop()``) performs the following operations::
IF StateOfFrame(ap) != Disabled
+ AND BufferBase(ap) <= frame
+ AND frame < ap->init
THEN
TrapAP(ap); /* ensure next allocation or push involves the pool */
ap->frameptr = frame;
@@ -470,6 +472,13 @@ _`.lw-frame.pop`: The external ``PopFrame()`` operation
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
----------------
From d06cf2cb1300e081a1d85e8606ee48f66eabda60 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 13 Oct 2014 11:04:30 +0100
Subject: [PATCH 017/759] Make finaltest more strict so that it catches
job003884.
Fix mps_pool_free_size for AWL and LO in the hot variety.
Copied from Perforce
Change: 187230
ServerID: perforce.ravenbrook.com
---
mps/code/finaltest.c | 6 ++-
mps/code/locus.c | 94 ++++++++++++++++++--------------------------
2 files changed, 42 insertions(+), 58 deletions(-)
diff --git a/mps/code/finaltest.c b/mps/code/finaltest.c
index 9f3ef13b967..853561e0cf6 100644
--- a/mps/code/finaltest.c
+++ b/mps/code/finaltest.c
@@ -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;
diff --git a/mps/code/locus.c b/mps/code/locus.c
index 0c5bacb86b5..4e92cb1d7dc 100644
--- a/mps/code/locus.c
+++ b/mps/code/locus.c
@@ -350,10 +350,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;
}
@@ -512,13 +510,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);
@@ -535,12 +533,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);
@@ -556,12 +552,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;
}
@@ -581,10 +575,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
@@ -613,7 +605,7 @@ void PoolGenAccountForEmpty(PoolGen pgen, Size unused, Bool deferred)
AVER(pgen->newSize >= unused);
pgen->newSize -= unused;
}
- STATISTIC(pgen->freeSize += unused);
+ pgen->freeSize += unused;
}
@@ -633,11 +625,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;
}
}
@@ -655,16 +647,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;
}
@@ -680,11 +670,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;
@@ -696,10 +684,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;
}
@@ -708,10 +694,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;
}
@@ -742,12 +726,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);
}
From f99f963e81a2cdf1607d384c386765e65dd9b5ef Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 13 Oct 2014 11:07:16 +0100
Subject: [PATCH 018/759] It's neater to pad out free segments instead of
adding a field to the segment structure.
Copied from Perforce
Change: 187231
ServerID: perforce.ravenbrook.com
---
mps/code/poolsnc.c | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c
index 4a992e4ca52..05d2875f2f6 100644
--- a/mps/code/poolsnc.c
+++ b/mps/code/poolsnc.c
@@ -200,7 +200,6 @@ typedef struct SNCSegStruct *SNCSeg;
typedef struct SNCSegStruct {
GCSegStruct gcSegStruct; /* superclass fields must come first */
SNCSeg next; /* Next segment in chain, or NULL */
- Bool free; /* Segment is free? */
Sig sig;
} SNCSegStruct;
@@ -211,9 +210,6 @@ typedef struct SNCSegStruct {
#define sncSegSetNext(seg, nextseg) \
((void)(SegSNCSeg(seg)->next = SegSNCSeg(nextseg)))
-#define sncSegFree(seg) RVALUE(SegSNCSeg(seg)->free)
-#define sncSegSetFree(seg, _free) ((void)(SegSNCSeg(seg)->free = (_free)))
-
ATTRIBUTE_UNUSED
static Bool SNCSegCheck(SNCSeg sncseg)
{
@@ -222,7 +218,6 @@ static Bool SNCSegCheck(SNCSeg sncseg)
if (NULL != sncseg->next) {
CHECKS(SNCSeg, sncseg->next);
}
- CHECKL(BoolCheck(sncseg->free));
return TRUE;
}
@@ -249,7 +244,6 @@ static Res sncSegInit(Seg seg, Pool pool, Addr base, Size size,
return res;
sncseg->next = NULL;
- sncseg->free = TRUE;
sncseg->sig = SNCSegSig;
AVERT(SNCSeg, sncseg);
return ResOK;
@@ -277,7 +271,6 @@ static void sncRecordAllocatedSeg(Buffer buffer, Seg seg)
AVERT(Seg, seg);
AVER(sncSegNext(seg) == NULL);
- sncSegSetFree(seg, FALSE);
sncSegSetNext(seg, sncBufferTopSeg(buffer));
sncBufferSetTopSeg(buffer, seg);
}
@@ -296,7 +289,9 @@ static void sncRecordFreeSeg(SNC snc, Seg seg)
SegSetGrey(seg, TraceSetEMPTY);
SegSetRankAndSummary(seg, RankSetEMPTY, RefSetEMPTY);
- sncSegSetFree(seg, TRUE);
+ /* Pad the whole segment so we don't try to walk it. */
+ (*SNCPool(snc)->format->pad)(SegBase(seg), SegSize(seg));
+
sncSegSetNext(seg, snc->freeSegs);
snc->freeSegs = seg;
}
@@ -678,7 +673,7 @@ static void SNCWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
/* Avoid applying the function to grey objects. */
/* They may have pointers to old-space. */
- if (SegGrey(seg) == TraceSetEMPTY && !sncSegFree(seg)) {
+ if (SegGrey(seg) == TraceSetEMPTY) {
Addr object = SegBase(seg);
Addr nextObject;
Addr limit;
From da626d1bc69a43cfa3b6e3ff3b183f9a6671c8c6 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 13 Oct 2014 12:46:28 +0100
Subject: [PATCH 019/759] Because of the requirement to make popped objects
dead in a timely fashion, we can only implement lightweight pops to an
address in the buffer. in particular we can't support pending pops, which
means that there's no need for the fields in the allocation point that
support pending pops.
Copied from Perforce
Change: 187232
ServerID: perforce.ravenbrook.com
---
mps/code/buffer.c | 133 +--------------------------
mps/code/mpm.h | 3 -
mps/code/mpmst.h | 1 -
mps/code/mpmtypes.h | 10 ---
mps/code/mps.h | 3 -
mps/code/mpsi.c | 12 ++-
mps/code/pool.c | 1 -
mps/code/poolabs.c | 22 -----
mps/code/poolsnc.c | 55 ++----------
mps/design/alloc-frame.txt | 179 +++++++++----------------------------
10 files changed, 58 insertions(+), 361 deletions(-)
diff --git a/mps/code/buffer.c b/mps/code/buffer.c
index 2e2ed0bc458..bd2f78e7752 100644
--- a/mps/code/buffer.c
+++ b/mps/code/buffer.c
@@ -30,10 +30,6 @@
SRCID(buffer, "$Id$");
-/* forward declarations */
-static void BufferFrameNotifyPopPending(Buffer buffer);
-
-
/* BufferCheck -- check consistency of a buffer
*
* See .ap.async. */
@@ -52,15 +48,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 */
@@ -81,8 +68,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);
@@ -101,14 +86,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 . */
- /* 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 */
@@ -119,12 +96,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);
@@ -133,7 +108,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);
}
}
@@ -230,9 +204,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;
@@ -319,8 +290,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);
@@ -346,7 +315,6 @@ void BufferDetach(Buffer buffer, Pool pool)
buffer->poolLimit = (Addr)0;
buffer->mode &=
~(BufferModeATTACHED|BufferModeFLIPPED|BufferModeTRANSITION);
- BufferFrameSetState(buffer, BufferFrameDISABLED);
EVENT2(BufferEmpty, buffer, spare);
}
@@ -383,11 +351,6 @@ void BufferFinish(Buffer buffer)
AVER(BufferIsReady(buffer));
- /* */
- if (BufferIsTrappedByMutator(buffer)) {
- BufferFrameNotifyPopPending(buffer);
- }
-
BufferDetach(buffer, pool);
/* Dispatch to the buffer class method to perform any */
@@ -463,44 +426,6 @@ static void BufferSetUnflipped(Buffer buffer)
}
-/* BufferFrameState
- *
- * Returns the frame state of a buffer. See
- * . */
-
-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 . */
-
-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. */
@@ -518,32 +443,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
- * . */
-
-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 . */
@@ -555,17 +454,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);
@@ -702,11 +596,6 @@ Res BufferFill(Addr *pReturn, Buffer buffer, Size size,
BufferSetUnflipped(buffer);
}
- /* */
- 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 &&
@@ -807,8 +696,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. */
@@ -955,21 +842,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
- * 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;
}
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index e5c11897a1f..b53acf252eb 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -273,8 +273,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);
@@ -800,7 +798,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);
diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h
index ac59492bea5..bf3de9a8916 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -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 */
diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h
index c59b32adef5..6989ded5d8d 100644
--- a/mps/code/mpmtypes.h
+++ b/mps/code/mpmtypes.h
@@ -226,8 +226,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,
@@ -321,14 +319,6 @@ enum {
#define BufferModeTRANSITION ((BufferMode)(1<<3))
-/* Buffer frame states. See */
-enum {
- BufferFrameVALID = 1,
- BufferFramePOP_PENDING,
- BufferFrameDISABLED
-};
-
-
/* Rank constants -- see */
/* These definitions must match . */
/* This is checked by . */
diff --git a/mps/code/mps.h b/mps/code/mps.h
index fc3d4c62fb9..3298b6ccdc1 100644
--- a/mps/code/mps.h
+++ b/mps/code/mps.h
@@ -305,9 +305,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;
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index 96b1b6937f7..4ce28a48626 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -950,7 +950,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 && mps_ap->init < mps_ap->limit) {
+ 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;
@@ -996,14 +996,12 @@ mps_res_t (mps_ap_frame_pop)(mps_ap_t mps_ap, mps_frame_t frame)
buf = BufferOfAP(mps_ap);
AVER(TESTT(Buffer, buf));
- if (mps_ap->_enabled
- && BufferBase(buf) <= (Addr)frame
+ /* FIXME: is it thread-safe to read BufferBase here? */
+ if (BufferBase(buf) <= (Addr)frame
&& (mps_addr_t)frame < mps_ap->init)
{
- /* Lightweight pop to address in same buffer */
- mps_ap->_frameptr = (mps_addr_t)frame; /* record pending pop */
- mps_ap->_lwpoppending = TRUE;
- mps_ap->limit = (mps_addr_t)0; /* trap the buffer */
+ /* Lightweight pop to earlier address in same buffer */
+ mps_ap->init = mps_ap->alloc = (mps_addr_t)frame;
return MPS_RES_OK;
} else {
diff --git a/mps/code/pool.c b/mps/code/pool.c
index bbdacc68616..b9033d0003c 100644
--- a/mps/code/pool.c
+++ b/mps/code/pool.c
@@ -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));
diff --git a/mps/code/poolabs.c b/mps/code/poolabs.c
index 712f24152e5..b21d83b15ab 100644
--- a/mps/code/poolabs.c
+++ b/mps/code/poolabs.c
@@ -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;
@@ -598,16 +596,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);
@@ -627,16 +615,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);
diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c
index 05d2875f2f6..25d0ae1de38 100644
--- a/mps/code/poolsnc.c
+++ b/mps/code/poolsnc.c
@@ -462,8 +462,6 @@ static Res SNCBufferFill(Addr *baseReturn, Addr *limitReturn,
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;
@@ -485,9 +483,6 @@ 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);
@@ -503,7 +498,7 @@ static void SNCBufferEmpty(Pool pool, Buffer buffer,
/* SNCScanLimit -- limit of scannable objects in segment */
-static Addr SNCScanLimit(Arena arena, Seg seg)
+static Addr SNCScanLimit(Seg seg)
{
Addr limit;
Buffer buf;
@@ -511,27 +506,9 @@ static Addr SNCScanLimit(Arena arena, Seg seg)
if (buf == NULL) {
/* Segment is unbuffered: entire segment scannable */
limit = SegLimit(seg);
- } else if (BufferFrameState(buf) != BufferFramePOP_PENDING) {
- /* No pop pending: scannable up to limit of initialized objects. */
- limit = BufferScanLimit(buf);
} else {
- Addr addr = (Addr)buf->ap_s._frameptr;
- if (addr == NULL) {
- /* Pop pending to bottom of stack */
- limit = BufferBase(buf);
- } else {
- Seg popSeg;
- Bool foundSeg = SegOfAddr(&popSeg, arena, addr);
- AVER(foundSeg);
- if (popSeg == seg) {
- /* Pop pending to address in same segment */
- AVER(addr <= BufferScanLimit(buf)); /* check direction of pop */
- limit = addr;
- } else {
- /* Pop pending to address in different segment */
- limit = BufferBase(buf);
- }
- }
+ /* Segment is buffered: scannable up to limit of initialized objects. */
+ limit = BufferScanLimit(buf);
}
return limit;
}
@@ -553,7 +530,7 @@ static Res SNCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
format = pool->format;
base = SegBase(seg);
- limit = SNCScanLimit(PoolArena(pool), seg);
+ limit = SNCScanLimit(seg);
if (base < limit) {
res = (*format->scan)(&ss->ss_s, base, limit);
@@ -575,16 +552,11 @@ 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);
- /* Should 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;
@@ -609,7 +581,7 @@ static Res SNCFramePush(AllocFrame *frameReturn, Pool pool, Buffer buf)
}
-static void SNCFramePopPending(Pool pool, Buffer buf, AllocFrame frame)
+static Res SNCFramePop(Pool pool, Buffer buf, AllocFrame frame)
{
Addr addr;
SNC snc;
@@ -618,8 +590,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 */
@@ -646,19 +616,9 @@ 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);
}
}
-}
-
-static Res SNCFramePop(Pool pool, Buffer buf, AllocFrame frame)
-{
- AVERT(Pool, pool);
- AVERT(Buffer, buf);
- BufferFrameSetState(buf, BufferFrameVALID);
- SNCFramePopPending(pool, buf, frame);
return ResOK;
}
@@ -683,7 +643,7 @@ static void SNCWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
snc = PoolSNC(pool);
AVERT(SNC, snc);
format = pool->format;
- limit = SNCScanLimit(PoolArena(pool), seg);
+ limit = SNCScanLimit(seg);
while(object < limit) {
(*f)(object, format, pool, p, s);
@@ -759,7 +719,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;
diff --git a/mps/design/alloc-frame.txt b/mps/design/alloc-frame.txt
index 9da25ed5b37..2275c09746d 100644
--- a/mps/design/alloc-frame.txt
+++ b/mps/design/alloc-frame.txt
@@ -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,61 +341,41 @@ 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
+_`.lw-frame.push`: The external *FramePush* operation
``mps_ap_frame_push()`` performs the following operations::
- IF !APIsTrapped(ap)
- AND StateOfFrame(ap) == Valid
- AND ap->init == ap->alloc
- AND ap->init < ap->limit
- THEN
+ 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.push.limit`: The reason for not using the lightweight
-operation when ``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
+_`.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 ``PopFrame()`` operation
+_`.lw-frame.pop`: The external *FramePop* operation
(``mps_ap_frame_pop()``) performs the following operations::
- IF StateOfFrame(ap) != Disabled
- AND BufferBase(ap) <= frame
- AND frame < ap->init
- THEN
- 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
From 850c88c1524e603f1808e1528a85b391e364a959 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 13 Oct 2014 13:40:11 +0100
Subject: [PATCH 020/759] Remove framestate type.
Copied from Perforce
Change: 187234
ServerID: perforce.ravenbrook.com
---
mps/code/mpm.h | 2 --
mps/code/mpmtypes.h | 1 -
mps/design/type.txt | 23 ---------------------
mps/manual/source/extensions/mps/designs.py | 2 +-
4 files changed, 1 insertion(+), 27 deletions(-)
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index b53acf252eb..eb52f275de8 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -805,8 +805,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 */
diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h
index 6989ded5d8d..06527f00923 100644
--- a/mps/code/mpmtypes.h
+++ b/mps/code/mpmtypes.h
@@ -71,7 +71,6 @@ typedef struct BufferClassStruct *BufferClass; /* */
typedef BufferClass SegBufClass; /* */
typedef BufferClass RankBufClass; /* */
typedef unsigned BufferMode; /* */
-typedef unsigned FrameState; /* */
typedef struct mps_fmt_s *Format; /* design.mps.format */
typedef struct LockStruct *Lock; /* * */
typedef struct mps_pool_s *Pool; /* */
diff --git a/mps/design/type.txt b/mps/design/type.txt
index c90a9335456..a140b33fad9 100644
--- a/mps/design/type.txt
+++ b/mps/design/type.txt
@@ -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
diff --git a/mps/manual/source/extensions/mps/designs.py b/mps/manual/source/extensions/mps/designs.py
index 3bf60a006b7..e54ed64e8d6 100644
--- a/mps/manual/source/extensions/mps/designs.py
+++ b/mps/manual/source/extensions/mps/designs.py
@@ -20,7 +20,7 @@
AccessSet Accumulation Addr Align AllocFrame AllocPattern AP Arg
Arena Attr Bool BootBlock BT Buffer BufferMode Byte Chain Chunk
- Clock Compare Count Epoch FindDelete Format FrameState Fun GenDesc
+ Clock Compare Count Epoch 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
From bf6b84879f07d1f2516be9a62e5cf215f2c839b8 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 13 Oct 2014 13:57:02 +0100
Subject: [PATCH 021/759] Expose the segment being padded.
Copied from Perforce
Change: 187237
ServerID: perforce.ravenbrook.com
---
mps/code/poolsnc.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c
index 25d0ae1de38..873547bd0ca 100644
--- a/mps/code/poolsnc.c
+++ b/mps/code/poolsnc.c
@@ -278,7 +278,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);
@@ -290,7 +290,10 @@ static void sncRecordFreeSeg(SNC snc, Seg seg)
SegSetRankAndSummary(seg, RankSetEMPTY, RefSetEMPTY);
/* Pad the whole segment so we don't try to walk it. */
+ /* FIXME: are the Expose and Cover calls necessary here? */
+ ShieldExpose(arena, seg);
(*SNCPool(snc)->format->pad)(SegBase(seg), SegSize(seg));
+ ShieldCover(arena, seg);
sncSegSetNext(seg, snc->freeSegs);
snc->freeSegs = seg;
@@ -318,7 +321,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 */
From fdf0a3ab2247dfdd39779bb881b5781f82f6ebb2 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 13 Oct 2014 21:57:41 +0100
Subject: [PATCH 022/759] Branching master to branch/2014-10-13/format.
Copied from Perforce
Change: 187249
ServerID: perforce.ravenbrook.com
From 821dc9114d6ac89aaee1ba81e206aec8963f22d5 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 13 Oct 2014 22:44:20 +0100
Subject: [PATCH 023/759] Attach the pools using a format to a ring in the
format, so that when we destroy the format, we can check that no pools are
using it.
Copied from Perforce
Change: 187253
ServerID: perforce.ravenbrook.com
---
mps/code/format.c | 4 ++++
mps/code/mpmst.h | 2 ++
mps/code/pool.c | 8 +++++++-
mps/code/poolamc.c | 1 +
mps/code/poolams.c | 1 +
mps/code/poolawl.c | 1 +
mps/code/poollo.c | 1 +
mps/code/poolsnc.c | 1 +
mps/test/conerr/12.c | 4 ++++
9 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/mps/code/format.c b/mps/code/format.c
index 763682a0a50..fc369f6a4ba 100644
--- a/mps/code/format.c
+++ b/mps/code/format.c
@@ -22,6 +22,7 @@ Bool FormatCheck(Format format)
CHECKU(Arena, format->arena);
CHECKL(format->serial < format->arena->formatSerial);
CHECKD_NOSIG(Ring, &format->arenaRing);
+ CHECKD_NOSIG(Ring, &format->poolRing);
CHECKL(AlignCheck(format->alignment));
/* TODO: Define the concept of the maximum alignment it is possible to
request from the MPS, document and provide an interface to it, and then
@@ -141,6 +142,7 @@ Res FormatCreate(Format *formatReturn, Arena arena, ArgList args)
format->arena = arena;
RingInit(&format->arenaRing);
+ RingInit(&format->poolRing);
format->alignment = fmtAlign;
format->headerSize = fmtHeaderSize;
format->scan = fmtScan;
@@ -168,12 +170,14 @@ Res FormatCreate(Format *formatReturn, Arena arena, ArgList args)
void FormatDestroy(Format format)
{
AVERT(Format, format);
+ AVER(RingIsSingle(&format->poolRing));
RingRemove(&format->arenaRing);
format->sig = SigInvalid;
RingFinish(&format->arenaRing);
+ RingFinish(&format->poolRing);
ControlFree(format->arena, format, sizeof(FormatStruct));
}
diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h
index ac59492bea5..62d82d658ce 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -110,6 +110,7 @@ typedef struct mps_pool_s { /* generic structure */
RingStruct segRing; /* segs are attached to pool */
Align alignment; /* alignment for units */
Format format; /* format only if class->attr&AttrFMT */
+ RingStruct formatRing; /* link in list of pools using format */
PoolFixMethod fix; /* fix method */
double fillMutatorSize; /* bytes filled, mutator buffers */
double emptyMutatorSize; /* bytes emptied, mutator buffers */
@@ -410,6 +411,7 @@ typedef struct mps_fmt_s {
Serial serial; /* from arena->formatSerial */
Arena arena; /* owning arena */
RingStruct arenaRing; /* formats are attached to the arena */
+ RingStruct poolRing; /* ring of pools using the format */
Align alignment; /* alignment of formatted objects */
mps_fmt_scan_t scan;
mps_fmt_skip_t skip;
diff --git a/mps/code/pool.c b/mps/code/pool.c
index bbdacc68616..05160aba216 100644
--- a/mps/code/pool.c
+++ b/mps/code/pool.c
@@ -153,6 +153,7 @@ Res PoolInit(Pool pool, Arena arena, PoolClass class, ArgList args)
RingInit(&pool->arenaRing);
RingInit(&pool->bufferRing);
RingInit(&pool->segRing);
+ RingInit(&pool->formatRing);
pool->bufferSerial = (Serial)0;
pool->alignment = MPS_PF_ALIGN;
pool->format = NULL;
@@ -181,6 +182,7 @@ Res PoolInit(Pool pool, Arena arena, PoolClass class, ArgList args)
failInit:
pool->sig = SigInvalid; /* Leave arena->poolSerial incremented */
+ RingFinish(&pool->formatRing);
RingFinish(&pool->segRing);
RingFinish(&pool->bufferRing);
RingFinish(&pool->arenaRing);
@@ -237,10 +239,14 @@ void PoolFinish(Pool pool)
/* Do any class-specific finishing. */
(*pool->class->finish)(pool);
- /* Detach the pool from the arena, and unsig it. */
+ /* Detach the pool from the arena and format, and unsig it. */
RingRemove(&pool->arenaRing);
+ if (pool->format) {
+ RingRemove(&pool->formatRing);
+ }
pool->sig = SigInvalid;
+ RingFinish(&pool->formatRing);
RingFinish(&pool->segRing);
RingFinish(&pool->bufferRing);
RingFinish(&pool->arenaRing);
diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c
index 4e9ed70396d..34d9ee568c3 100644
--- a/mps/code/poolamc.c
+++ b/mps/code/poolamc.c
@@ -832,6 +832,7 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args)
ArgRequire(&arg, args, MPS_KEY_FORMAT);
pool->format = arg.val.format;
+ RingAppend(&pool->format->poolRing, &pool->formatRing);
if (ArgPick(&arg, args, MPS_KEY_CHAIN))
chain = arg.val.chain;
else
diff --git a/mps/code/poolams.c b/mps/code/poolams.c
index bbb6d70e96a..f94695ad1ef 100644
--- a/mps/code/poolams.c
+++ b/mps/code/poolams.c
@@ -838,6 +838,7 @@ Res AMSInitInternal(AMS ams, Format format, Chain chain, unsigned gen,
pool = AMSPool(ams);
AVERT(Pool, pool);
pool->format = format;
+ RingAppend(&format->poolRing, &pool->formatRing);
pool->alignment = pool->format->alignment;
ams->grainShift = SizeLog2(PoolAlignment(pool));
diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c
index 0ab42f36e27..2abbdb06680 100644
--- a/mps/code/poolawl.c
+++ b/mps/code/poolawl.c
@@ -576,6 +576,7 @@ static Res AWLInit(Pool pool, ArgList args)
AVERT(Format, format);
pool->format = format;
+ RingAppend(&format->poolRing, &pool->formatRing);
pool->alignment = format->alignment;
AVER(FUNCHECK(findDependent));
diff --git a/mps/code/poollo.c b/mps/code/poollo.c
index 5b3ddd608f9..55e7104448c 100644
--- a/mps/code/poollo.c
+++ b/mps/code/poollo.c
@@ -494,6 +494,7 @@ static Res LOInit(Pool pool, ArgList args)
ArgRequire(&arg, args, MPS_KEY_FORMAT);
pool->format = arg.val.format;
+ RingAppend(&pool->format->poolRing, &pool->formatRing);
if (ArgPick(&arg, args, MPS_KEY_CHAIN))
chain = arg.val.chain;
else {
diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c
index df2d964340b..c56ce9f74c8 100644
--- a/mps/code/poolsnc.c
+++ b/mps/code/poolsnc.c
@@ -388,6 +388,7 @@ static Res SNCInit(Pool pool, ArgList args)
AVERT(Format, format);
pool->format = format;
+ RingAppend(&format->poolRing, &pool->formatRing);
snc->freeSegs = NULL;
snc->sig = SNCSig;
diff --git a/mps/test/conerr/12.c b/mps/test/conerr/12.c
index a8f932114ab..f904f1e3267 100644
--- a/mps/test/conerr/12.c
+++ b/mps/test/conerr/12.c
@@ -4,6 +4,10 @@ TEST_HEADER
summary = destroy a format though attached to a pool
language = c
link = testlib.o
+OUTPUT_SPEC
+ assert = true
+ assertfile P= format.c
+ assertcond = RingIsSingle(&format->poolRing)
END_HEADER
*/
From 9c044f7542dea518cb7b72304e434ff196db4339 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 14 Oct 2014 10:07:41 +0100
Subject: [PATCH 024/759] Simpler and more robust to add the pool to the
formatring in poolinit, after we know that the initialization has succeeded.
Copied from Perforce
Change: 187261
ServerID: perforce.ravenbrook.com
---
mps/code/pool.c | 5 +++++
mps/code/poolamc.c | 1 -
mps/code/poolams.c | 1 -
mps/code/poolawl.c | 1 -
mps/code/poollo.c | 1 -
mps/code/poolsnc.c | 1 -
6 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/mps/code/pool.c b/mps/code/pool.c
index 05160aba216..96f853eb94b 100644
--- a/mps/code/pool.c
+++ b/mps/code/pool.c
@@ -178,6 +178,11 @@ Res PoolInit(Pool pool, Arena arena, PoolClass class, ArgList args)
/* Add initialized pool to list of pools in arena. */
RingAppend(&globals->poolRing, &pool->arenaRing);
+ /* Add initialized pool to list of pools using format. */
+ if (pool->format) {
+ RingAppend(&pool->format->poolRing, &pool->formatRing);
+ }
+
return ResOK;
failInit:
diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c
index 34d9ee568c3..4e9ed70396d 100644
--- a/mps/code/poolamc.c
+++ b/mps/code/poolamc.c
@@ -832,7 +832,6 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args)
ArgRequire(&arg, args, MPS_KEY_FORMAT);
pool->format = arg.val.format;
- RingAppend(&pool->format->poolRing, &pool->formatRing);
if (ArgPick(&arg, args, MPS_KEY_CHAIN))
chain = arg.val.chain;
else
diff --git a/mps/code/poolams.c b/mps/code/poolams.c
index f94695ad1ef..bbb6d70e96a 100644
--- a/mps/code/poolams.c
+++ b/mps/code/poolams.c
@@ -838,7 +838,6 @@ Res AMSInitInternal(AMS ams, Format format, Chain chain, unsigned gen,
pool = AMSPool(ams);
AVERT(Pool, pool);
pool->format = format;
- RingAppend(&format->poolRing, &pool->formatRing);
pool->alignment = pool->format->alignment;
ams->grainShift = SizeLog2(PoolAlignment(pool));
diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c
index 2abbdb06680..0ab42f36e27 100644
--- a/mps/code/poolawl.c
+++ b/mps/code/poolawl.c
@@ -576,7 +576,6 @@ static Res AWLInit(Pool pool, ArgList args)
AVERT(Format, format);
pool->format = format;
- RingAppend(&format->poolRing, &pool->formatRing);
pool->alignment = format->alignment;
AVER(FUNCHECK(findDependent));
diff --git a/mps/code/poollo.c b/mps/code/poollo.c
index 55e7104448c..5b3ddd608f9 100644
--- a/mps/code/poollo.c
+++ b/mps/code/poollo.c
@@ -494,7 +494,6 @@ static Res LOInit(Pool pool, ArgList args)
ArgRequire(&arg, args, MPS_KEY_FORMAT);
pool->format = arg.val.format;
- RingAppend(&pool->format->poolRing, &pool->formatRing);
if (ArgPick(&arg, args, MPS_KEY_CHAIN))
chain = arg.val.chain;
else {
diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c
index c56ce9f74c8..df2d964340b 100644
--- a/mps/code/poolsnc.c
+++ b/mps/code/poolsnc.c
@@ -388,7 +388,6 @@ static Res SNCInit(Pool pool, ArgList args)
AVERT(Format, format);
pool->format = format;
- RingAppend(&format->poolRing, &pool->formatRing);
snc->freeSegs = NULL;
snc->sig = SNCSig;
From e102a569586e56f208c18d9010dd4435d3b33119 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 16 Oct 2014 22:59:00 +0100
Subject: [PATCH 025/759] Use a reference count to discover cases where a
format is deleted when a pool is still using it, as suggested by rb
.
Copied from Perforce
Change: 187279
ServerID: perforce.ravenbrook.com
---
mps/code/format.c | 6 ++----
mps/code/mpmst.h | 3 +--
mps/code/pool.c | 8 +++-----
mps/test/conerr/12.c | 2 +-
4 files changed, 7 insertions(+), 12 deletions(-)
diff --git a/mps/code/format.c b/mps/code/format.c
index fc369f6a4ba..69e7ff1ddbe 100644
--- a/mps/code/format.c
+++ b/mps/code/format.c
@@ -22,7 +22,6 @@ Bool FormatCheck(Format format)
CHECKU(Arena, format->arena);
CHECKL(format->serial < format->arena->formatSerial);
CHECKD_NOSIG(Ring, &format->arenaRing);
- CHECKD_NOSIG(Ring, &format->poolRing);
CHECKL(AlignCheck(format->alignment));
/* TODO: Define the concept of the maximum alignment it is possible to
request from the MPS, document and provide an interface to it, and then
@@ -142,7 +141,7 @@ Res FormatCreate(Format *formatReturn, Arena arena, ArgList args)
format->arena = arena;
RingInit(&format->arenaRing);
- RingInit(&format->poolRing);
+ format->poolCount = 0;
format->alignment = fmtAlign;
format->headerSize = fmtHeaderSize;
format->scan = fmtScan;
@@ -170,14 +169,13 @@ Res FormatCreate(Format *formatReturn, Arena arena, ArgList args)
void FormatDestroy(Format format)
{
AVERT(Format, format);
- AVER(RingIsSingle(&format->poolRing));
+ AVER(format->poolCount == 0);
RingRemove(&format->arenaRing);
format->sig = SigInvalid;
RingFinish(&format->arenaRing);
- RingFinish(&format->poolRing);
ControlFree(format->arena, format, sizeof(FormatStruct));
}
diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h
index 62d82d658ce..2885f193d31 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -110,7 +110,6 @@ typedef struct mps_pool_s { /* generic structure */
RingStruct segRing; /* segs are attached to pool */
Align alignment; /* alignment for units */
Format format; /* format only if class->attr&AttrFMT */
- RingStruct formatRing; /* link in list of pools using format */
PoolFixMethod fix; /* fix method */
double fillMutatorSize; /* bytes filled, mutator buffers */
double emptyMutatorSize; /* bytes emptied, mutator buffers */
@@ -411,7 +410,7 @@ typedef struct mps_fmt_s {
Serial serial; /* from arena->formatSerial */
Arena arena; /* owning arena */
RingStruct arenaRing; /* formats are attached to the arena */
- RingStruct poolRing; /* ring of pools using the format */
+ Count poolCount; /* number of pools using the format */
Align alignment; /* alignment of formatted objects */
mps_fmt_scan_t scan;
mps_fmt_skip_t skip;
diff --git a/mps/code/pool.c b/mps/code/pool.c
index 96f853eb94b..2e59c08a69a 100644
--- a/mps/code/pool.c
+++ b/mps/code/pool.c
@@ -153,7 +153,6 @@ Res PoolInit(Pool pool, Arena arena, PoolClass class, ArgList args)
RingInit(&pool->arenaRing);
RingInit(&pool->bufferRing);
RingInit(&pool->segRing);
- RingInit(&pool->formatRing);
pool->bufferSerial = (Serial)0;
pool->alignment = MPS_PF_ALIGN;
pool->format = NULL;
@@ -180,14 +179,13 @@ Res PoolInit(Pool pool, Arena arena, PoolClass class, ArgList args)
/* Add initialized pool to list of pools using format. */
if (pool->format) {
- RingAppend(&pool->format->poolRing, &pool->formatRing);
+ ++ pool->format->poolCount;
}
return ResOK;
failInit:
pool->sig = SigInvalid; /* Leave arena->poolSerial incremented */
- RingFinish(&pool->formatRing);
RingFinish(&pool->segRing);
RingFinish(&pool->bufferRing);
RingFinish(&pool->arenaRing);
@@ -247,11 +245,11 @@ void PoolFinish(Pool pool)
/* Detach the pool from the arena and format, and unsig it. */
RingRemove(&pool->arenaRing);
if (pool->format) {
- RingRemove(&pool->formatRing);
+ AVER(pool->format->poolCount > 0);
+ -- pool->format->poolCount;
}
pool->sig = SigInvalid;
- RingFinish(&pool->formatRing);
RingFinish(&pool->segRing);
RingFinish(&pool->bufferRing);
RingFinish(&pool->arenaRing);
diff --git a/mps/test/conerr/12.c b/mps/test/conerr/12.c
index f904f1e3267..139abce195b 100644
--- a/mps/test/conerr/12.c
+++ b/mps/test/conerr/12.c
@@ -7,7 +7,7 @@ TEST_HEADER
OUTPUT_SPEC
assert = true
assertfile P= format.c
- assertcond = RingIsSingle(&format->poolRing)
+ assertcond = format->poolCount == 0
END_HEADER
*/
From b151173b074216412fe9382abc121270d24efa66 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 21 Oct 2014 10:38:36 +0100
Subject: [PATCH 026/759] Release notes for job003880, job003883, and
job003884.
Copied from Perforce
Change: 187310
ServerID: perforce.ravenbrook.com
---
mps/manual/source/release.rst | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst
index fc9cc438c55..3f4271e14a3 100644
--- a/mps/manual/source/release.rst
+++ b/mps/manual/source/release.rst
@@ -16,6 +16,24 @@ Interface changes
name :c:type:`mps_class_t` is still available via a ``typedef``,
but is deprecated.
+#. The :ref:`pool-snc` pool class now implements the
+ :c:func:`mps_pool_total_size` and :c:func:`mps_pool_free_size`.
+
+
+Other changes
+.............
+
+#. Objects in :ref:`pool-snc` pools now die immediately when their
+ :term:`allocation frame` is popped. See job003883_.
+
+ .. _job003883: https://www.ravenbrook.com/project/mps/issue/job003883/
+
+#. 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/
+
.. _release-notes-1.114:
From bdbae45be90328277f779bf6ee1074adb2f9840b Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sat, 25 Oct 2014 19:45:48 +0100
Subject: [PATCH 027/759] Add poolcount to formatdescribe.
Copied from Perforce
Change: 187396
ServerID: perforce.ravenbrook.com
---
mps/code/format.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/mps/code/format.c b/mps/code/format.c
index 69e7ff1ddbe..da6c33d19a8 100644
--- a/mps/code/format.c
+++ b/mps/code/format.c
@@ -203,6 +203,7 @@ Res FormatDescribe(Format format, mps_lib_FILE *stream, Count depth)
"Format $P ($U) {\n", (WriteFP)format, (WriteFU)format->serial,
" arena $P ($U)\n",
(WriteFP)format->arena, (WriteFU)format->arena->serial,
+ " poolCount $U\n", (WriteFU)format->poolCount,
" alignment $W\n", (WriteFW)format->alignment,
" scan $F\n", (WriteFF)format->scan,
" skip $F\n", (WriteFF)format->skip,
From 1fa1633cf6d0933d8534c743c5096959772ad1b2 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sun, 26 Oct 2014 11:09:49 +0000
Subject: [PATCH 028/759] Branching master to branch/2014-10-26/sc.
Copied from Perforce
Change: 187404
ServerID: perforce.ravenbrook.com
From 55d913579236d9343b497fd45f2b49632178663e Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sun, 26 Oct 2014 22:18:57 +0000
Subject: [PATCH 029/759] Save mutator context on entry to the mps.
Copied from Perforce
Change: 187412
ServerID: perforce.ravenbrook.com
---
mps/code/fri3gc.gmk | 2 +-
mps/code/fri6gc.gmk | 19 +--
mps/code/global.c | 4 +-
mps/code/lii3gc.gmk | 2 +-
mps/code/lii6gc.gmk | 2 +-
mps/code/lii6ll.gmk | 2 +-
mps/code/mpm.h | 2 +
mps/code/mpmst.h | 4 +-
mps/code/mps.c | 12 +-
mps/code/mpsi.c | 97 +++++++-------
mps/code/sc.h | 205 -----------------------------
mps/code/ss.c | 84 ++++++------
mps/code/ss.h | 61 ++++++++-
mps/code/ssan.c | 51 ++++----
mps/code/ssw3i3mv.c | 45 ++++---
mps/code/ssw3i3pc.c | 32 +++--
mps/code/ssw3i6mv.c | 47 ++++---
mps/code/ssw3i6pc.c | 46 ++++---
mps/code/{ssixi3.c => ssxci3.c} | 81 ++++--------
mps/code/{ssixi6.c => ssxci6.c} | 94 ++++++--------
mps/code/xci3gc.gmk | 19 +--
mps/code/xci6ll.gmk | 2 +-
mps/design/ss.txt | 223 ++++++++++++++++++++++++++------
23 files changed, 580 insertions(+), 556 deletions(-)
delete mode 100644 mps/code/sc.h
rename mps/code/{ssixi3.c => ssxci3.c} (51%)
rename mps/code/{ssixi6.c => ssxci6.c} (51%)
diff --git a/mps/code/fri3gc.gmk b/mps/code/fri3gc.gmk
index 99d455e51fa..2a4f6893012 100644
--- a/mps/code/fri3gc.gmk
+++ b/mps/code/fri3gc.gmk
@@ -15,7 +15,7 @@ MPMPF = \
protsgix.c \
pthrdext.c \
span.c \
- ssixi3.c \
+ ssan.c \
thix.c \
vmix.c
diff --git a/mps/code/fri6gc.gmk b/mps/code/fri6gc.gmk
index a0cb6270c12..5e58bf4e931 100644
--- a/mps/code/fri6gc.gmk
+++ b/mps/code/fri6gc.gmk
@@ -7,23 +7,26 @@
PFM = fri6gc
-MPMPF = lockix.c thix.c pthrdext.c vmix.c \
- protix.c protsgix.c prmcan.c prmci6fr.c ssixi6.c span.c
+MPMPF = \
+ lockix.c \
+ prmcan.c \
+ prmci6fr.c \
+ protix.c \
+ protsgix.c \
+ pthrdext.c \
+ span.c \
+ ssan.c \
+ thix.c \
+ vmix.c
LIBS = -lm -pthread
include gc.gmk
-# FIXME: We pun types through the MPS interface, setting off this warning.
-# Can we avoid this? The puns might indeed be dangerous.
-CFLAGSCOMPILER += -Wno-strict-aliasing
-
# For SQLite3.
LINKFLAGS += -L/usr/local/lib
CFLAGSCOMPILER += -I/usr/local/include
-CC = cc
-
include comm.gmk
diff --git a/mps/code/global.c b/mps/code/global.c
index df0095d3195..e26d6c781f3 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -218,7 +218,7 @@ Bool GlobalsCheck(Globals arenaGlobals)
if (arenaGlobals->defaultChain != NULL)
CHECKD(Chain, arenaGlobals->defaultChain);
- /* can't check arena->stackAtArenaEnter */
+ /* can't check arena->scAtArenaEnter */
return TRUE;
}
@@ -320,7 +320,7 @@ Res GlobalsInit(Globals arenaGlobals)
arena->emergency = FALSE;
- arena->stackAtArenaEnter = NULL;
+ arena->scAtArenaEnter = NULL;
arenaGlobals->defaultChain = NULL;
diff --git a/mps/code/lii3gc.gmk b/mps/code/lii3gc.gmk
index 00be40c673c..9ecf05d148b 100644
--- a/mps/code/lii3gc.gmk
+++ b/mps/code/lii3gc.gmk
@@ -15,7 +15,7 @@ MPMPF = \
protli.c \
pthrdext.c \
span.c \
- ssixi3.c \
+ ssan.c \
thix.c \
vmix.c
diff --git a/mps/code/lii6gc.gmk b/mps/code/lii6gc.gmk
index 91f8f5d9066..b5df73fe7f7 100644
--- a/mps/code/lii6gc.gmk
+++ b/mps/code/lii6gc.gmk
@@ -15,7 +15,7 @@ MPMPF = \
protli.c \
pthrdext.c \
span.c \
- ssixi6.c \
+ ssan.c \
thix.c \
vmix.c
diff --git a/mps/code/lii6ll.gmk b/mps/code/lii6ll.gmk
index 5988b0c0b17..4e4811e3204 100644
--- a/mps/code/lii6ll.gmk
+++ b/mps/code/lii6ll.gmk
@@ -15,7 +15,7 @@ MPMPF = \
protli.c \
pthrdext.c \
span.c \
- ssixi6.c \
+ ssan.c \
thix.c \
vmix.c
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index 6b3730495d6..febcca738a0 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -75,6 +75,8 @@ extern Word (WordAlignDown)(Word word, Align align);
#define PointerAlignUp(p, s) \
((void *)WordAlignUp((Word)(p), (Align)(s)))
+#define PointerAlignDown(p, s) \
+ ((void *)WordAlignDown((Word)(p), (Align)(s)))
#define AddrAdd(p, s) ((Addr)PointerAdd((void *)(p), s))
#define AddrSub(p, s) ((Addr)PointerSub((void *)(p), s))
diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h
index a7749aa738d..ff5577cedf6 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -791,8 +791,8 @@ typedef struct mps_arena_s {
Bool emergency; /* garbage collect in emergency mode? */
- Addr *stackAtArenaEnter; /* NULL or top of client stack, in the thread */
- /* that then entered the MPS. */
+ StackContext scAtArenaEnter; /* NULL or mutator context, in the thread */
+ /* that then entered the MPS. */
Sig sig;
} ArenaStruct;
diff --git a/mps/code/mps.c b/mps/code/mps.c
index 95919d9680c..8f542891114 100644
--- a/mps/code/mps.c
+++ b/mps/code/mps.c
@@ -122,7 +122,7 @@
#include "proti3.c" /* 32-bit Intel mutator context decoding */
#include "prmci3xc.c" /* 32-bit Intel for Mac OS X mutator context */
#include "span.c" /* generic stack probe */
-#include "ssixi3.c" /* Posix on 32-bit Intel stack scan */
+#include "ssxci3.c" /* OS X on 32-bit Intel stack scan */
/* Mac OS X on 64-bit Intel build with Clang or GCC */
@@ -136,7 +136,7 @@
#include "proti6.c" /* 64-bit Intel mutator context decoding */
#include "prmci6xc.c" /* 64-bit Intel for Mac OS X mutator context */
#include "span.c" /* generic stack probe */
-#include "ssixi6.c" /* Posix on 64-bit Intel stack scan */
+#include "ssxci6.c" /* OS X on 64-bit Intel stack scan */
/* FreeBSD on 32-bit Intel built with GCC */
@@ -151,7 +151,7 @@
#include "prmcan.c" /* generic mutator context */
#include "prmci3fr.c" /* 32-bit Intel for FreeBSD mutator context */
#include "span.c" /* generic stack probe */
-#include "ssixi3.c" /* Posix on 32-bit Intel stack scan */
+#include "ssan.c" /* generic stack scan */
/* FreeBSD on 64-bit Intel built with GCC */
@@ -166,7 +166,7 @@
#include "prmcan.c" /* generic mutator context */
#include "prmci6fr.c" /* 64-bit Intel for FreeBSD mutator context */
#include "span.c" /* generic stack probe */
-#include "ssixi6.c" /* Posix on 64-bit Intel stack scan */
+#include "ssan.c" /* generic stack scan */
/* Linux on 32-bit Intel with GCC */
@@ -181,7 +181,7 @@
#include "proti3.c" /* 32-bit Intel mutator context */
#include "prmci3li.c" /* 32-bit Intel for Linux mutator context */
#include "span.c" /* generic stack probe */
-#include "ssixi3.c" /* Posix on 32-bit Intel stack scan */
+#include "ssan.c" /* generic stack scan */
/* Linux on 64-bit Intel with GCC or Clang */
@@ -196,7 +196,7 @@
#include "proti6.c" /* 64-bit Intel mutator context */
#include "prmci6li.c" /* 64-bit Intel for Linux mutator context */
#include "span.c" /* generic stack probe */
-#include "ssixi6.c" /* Posix on 64-bit Intel stack scan */
+#include "ssan.c" /* generic stack scan */
/* Windows on 32-bit Intel with Microsoft Visual Studio */
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index c00da18c201..3dcfadbddf8 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -231,9 +231,9 @@ void mps_arena_clamp(mps_arena_t arena)
void mps_arena_release(mps_arena_t arena)
{
- ArenaEnter(arena);
- ArenaRelease(ArenaGlobals(arena));
- ArenaLeave(arena);
+ STACK_CONTEXT_BEGIN(arena) {
+ ArenaRelease(ArenaGlobals(arena));
+ } STACK_CONTEXT_END(arena);
}
@@ -271,18 +271,19 @@ void mps_arena_unsafe_restore_protection(mps_arena_t arena)
mps_res_t mps_arena_start_collect(mps_arena_t arena)
{
Res res;
- ArenaEnter(arena);
- res = ArenaStartCollect(ArenaGlobals(arena), TraceStartWhyCLIENTFULL_INCREMENTAL);
- ArenaLeave(arena);
+ STACK_CONTEXT_BEGIN(arena) {
+ res = ArenaStartCollect(ArenaGlobals(arena),
+ TraceStartWhyCLIENTFULL_INCREMENTAL);
+ } STACK_CONTEXT_END(arena);
return (mps_res_t)res;
}
mps_res_t mps_arena_collect(mps_arena_t arena)
{
Res res;
- ArenaEnter(arena);
- res = ArenaCollect(ArenaGlobals(arena), TraceStartWhyCLIENTFULL_BLOCK);
- ArenaLeave(arena);
+ STACK_CONTEXT_BEGIN(arena) {
+ res = ArenaCollect(ArenaGlobals(arena), TraceStartWhyCLIENTFULL_BLOCK);
+ } STACK_CONTEXT_END(arena);
return (mps_res_t)res;
}
@@ -291,9 +292,9 @@ mps_bool_t mps_arena_step(mps_arena_t arena,
double multiplier)
{
Bool b;
- ArenaEnter(arena);
- b = ArenaStep(ArenaGlobals(arena), interval, multiplier);
- ArenaLeave(arena);
+ STACK_CONTEXT_BEGIN(arena) {
+ b = ArenaStep(ArenaGlobals(arena), interval, multiplier);
+ } STACK_CONTEXT_END(arena);
return b;
}
@@ -733,22 +734,22 @@ mps_res_t mps_alloc(mps_addr_t *p_o, mps_pool_t pool, size_t size)
AVER(TESTT(Pool, pool));
arena = PoolArena(pool);
- ArenaEnter(arena);
+ STACK_CONTEXT_BEGIN(arena) {
- ArenaPoll(ArenaGlobals(arena)); /* .poll */
+ ArenaPoll(ArenaGlobals(arena)); /* .poll */
- AVER(p_o != NULL);
- AVERT(Pool, pool);
- AVER(size > 0);
- /* Note: class may allow unaligned size, see */
- /* . */
- /* Rest ignored, see .varargs. */
+ AVER(p_o != NULL);
+ AVERT(Pool, pool);
+ AVER(size > 0);
+ /* Note: class may allow unaligned size, see */
+ /* . */
+ /* Rest ignored, see .varargs. */
- /* @@@@ There is currently no requirement for reservoirs to work */
- /* with unbuffered allocation. */
- res = PoolAlloc(&p, pool, size, FALSE);
+ /* @@@@ There is currently no requirement for reservoirs to work */
+ /* with unbuffered allocation. */
+ res = PoolAlloc(&p, pool, size, FALSE);
- ArenaLeave(arena);
+ } STACK_CONTEXT_END(arena);
if (res != ResOK)
return (mps_res_t)res;
@@ -1040,18 +1041,18 @@ mps_res_t mps_ap_fill(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size)
AVER(TESTT(Buffer, buf));
arena = BufferArena(buf);
- ArenaEnter(arena);
+ STACK_CONTEXT_BEGIN(arena) {
- ArenaPoll(ArenaGlobals(arena)); /* .poll */
+ ArenaPoll(ArenaGlobals(arena)); /* .poll */
- AVER(p_o != NULL);
- AVERT(Buffer, buf);
- AVER(size > 0);
- AVER(SizeIsAligned(size, BufferPool(buf)->alignment));
+ AVER(p_o != NULL);
+ AVERT(Buffer, buf);
+ AVER(size > 0);
+ AVER(SizeIsAligned(size, BufferPool(buf)->alignment));
- res = BufferFill(&p, buf, size, FALSE);
+ res = BufferFill(&p, buf, size, FALSE);
- ArenaLeave(arena);
+ } STACK_CONTEXT_END(arena);
if (res != ResOK)
return (mps_res_t)res;
@@ -1072,18 +1073,18 @@ mps_res_t mps_ap_fill_with_reservoir_permit(mps_addr_t *p_o, mps_ap_t mps_ap,
AVER(TESTT(Buffer, buf));
arena = BufferArena(buf);
- ArenaEnter(arena);
+ STACK_CONTEXT_BEGIN(arena) {
- ArenaPoll(ArenaGlobals(arena)); /* .poll */
+ ArenaPoll(ArenaGlobals(arena)); /* .poll */
- AVER(p_o != NULL);
- AVERT(Buffer, buf);
- AVER(size > 0);
- AVER(SizeIsAligned(size, BufferPool(buf)->alignment));
+ AVER(p_o != NULL);
+ AVERT(Buffer, buf);
+ AVER(size > 0);
+ AVER(SizeIsAligned(size, BufferPool(buf)->alignment));
- res = BufferFill(&p, buf, size, TRUE);
+ res = BufferFill(&p, buf, size, TRUE);
- ArenaLeave(arena);
+ } STACK_CONTEXT_END(arena);
if (res != ResOK)
return (mps_res_t)res;
@@ -1873,12 +1874,12 @@ mps_res_t mps_ap_alloc_pattern_end(mps_ap_t mps_ap,
UNUSED(alloc_pattern); /* .ramp.hack */
arena = BufferArena(buf);
- ArenaEnter(arena);
- res = BufferRampEnd(buf);
- ArenaPoll(ArenaGlobals(arena)); /* .poll */
+ STACK_CONTEXT_BEGIN(arena) {
+ res = BufferRampEnd(buf);
+ ArenaPoll(ArenaGlobals(arena)); /* .poll */
+ } STACK_CONTEXT_END(arena);
- ArenaLeave(arena);
return (mps_res_t)res;
}
@@ -1893,12 +1894,12 @@ mps_res_t mps_ap_alloc_pattern_reset(mps_ap_t mps_ap)
AVER(TESTT(Buffer, buf));
arena = BufferArena(buf);
- ArenaEnter(arena);
- BufferRampReset(buf);
- ArenaPoll(ArenaGlobals(arena)); /* .poll */
+ STACK_CONTEXT_BEGIN(arena) {
+ BufferRampReset(buf);
+ ArenaPoll(ArenaGlobals(arena)); /* .poll */
+ } STACK_CONTEXT_END(arena);
- ArenaLeave(arena);
return MPS_RES_OK;
}
diff --git a/mps/code/sc.h b/mps/code/sc.h
deleted file mode 100644
index 765c4ccb033..00000000000
--- a/mps/code/sc.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/* sc.h: STACK CONTEXT
- *
- * $Id$
- * Copyright (c) 2012 Ravenbrook Limited. See end of file for license.
- *
- * Provides a context to hold the registers and stack pointer
- *
- * This file provide wrappers for using setjmp or some similar mechanism
- * to save the current callee-saves on the stack.
- *
- * See http://info.ravenbrook.com/mail/2012/08/03/14-36-35/0/ and the rest of
- * the thread for the origin of the idea.
- *
- * TODO: Make StackScan take a StackContext
- */
-
-#ifndef sc_h
-#define sc_h
-
-#include "mpm.h"
-
-
-/* StackContext -- holds the registers including a stack pointer
- *
- * This contains the callee-save registers and the stack pointer.
- *
- * This is used to save the registers after or on entry to the arena so that
- * they can be scanned.
- */
-
-/* STACK_CONTEXT_SAVE - save the callee-saves and stack pointer
- *
- * This macro saves the callee-saves and stack pointer for the
- * current function into the passed StackContext. The StackContext
- * is no longer valid after the function returns.
- *
- * This needs to be a macro because the compiler may need to do
- * setjmp magic.
- */
-
-/* StackContextStackTop - return the stack top from the stack context.
- *
- * We assume the stack is full. In other words the stack top points at
- * a word that contains a potential Ref.
- */
-
-
-/* Mac OS X on 32-bit Intel built with Clang or GCC */
-
-#if defined(MPS_PF_XCI3LL) || defined(MPS_PF_XCI3GC)
-
-#include
-
-typedef struct StackContextStruct {
- jmp_buf jumpBuffer;
-} StackContextStruct;
-
-/* See the implementation of _setjmp in
- * */
-
-#define JB_ESP 36 /* offset into the jmp_buf in bytes as defined in _setjmp.s */
-
-#define STACK_CONTEXT_SAVE(sc) ((void)_setjmp((sc)->jumpBuffer))
-
-#define StackContextSP(sc) ((Addr *)(sc)->jumpBuffer[JB_ESP/sizeof(int)])
-
-/* On MacOS X the stackPointer can end up pointing above the StackContext
- * which we assume to be stored on the stack because it is no longer
- * needed once we have _longjmp()ed back. So take the minimum of the
- * SP and the base of the StackContext structure. */
-#define StackContextStackTop(sc) \
- (StackContextSP(sc) < (Addr*)(sc) ? StackContextSP(sc) : (Addr*)(sc))
-
-
-/* Mac OS X on 64-bit Intel build with Clang or GCC */
-
-#elif defined(MPS_PF_XCI6LL) || defined(MPS_PF_XCI6GC)
-
-#include
-
-/* We could use getcontext() from libunwind but that produces
- * deprecation warnings. See
- *
- */
-
-typedef struct StackContextStruct {
- jmp_buf jumpBuffer;
-} StackContextStruct;
-
-/* See the implementation of _setjmp in
- * */
-
-#define STACK_CONTEXT_SAVE(sc) ((void)_setjmp((sc)->jumpBuffer))
-
-#define JB_RSP 16 /* offset into the jmp_buf in bytes as defined in _setjmp.s */
-
-/* jmp_buf is an int[] but the stack pointer is 8 bytes so we need a cast */
-/* FIXME: possible aliasing problem */
-#define StackContextSP(sc) \
- (*(Addr **)((char *)(sc)->jumpBuffer+JB_RSP))
-
-/* On MacOS X the stackPointer can end up pointing above the StackContext
- * which we assume to be stored on the stack because it is no longer
- * needed once we have _longjmp()ed back. So take the minimum of the
- * SP and the base of the StackContext structure. */
-#define StackContextStackTop(sc) \
- (StackContextSP(sc) < (Addr*)(sc) ? StackContextSP(sc) : (Addr*)(sc))
-
-
-/* Windows on 32-bit Intel with Microsoft Visual Studio */
-
-#elif defined(MPS_PF_W3I3MV)
-
-#include
-
-typedef struct StackContextStruct {
- jmp_buf jumpBuffer;
-} StackContextStruct;
-
-#define STACK_CONTEXT_SAVE(sc) ((void)setjmp((sc)->jumpBuffer))
-
-#define StackContextStackTop(sc) \
- ((Addr *)((_JUMP_BUFFER *)(sc)->jumpBuffer)->Esp)
-
-
-/* Windows on 64-bit Intel with Microsoft Visual Studio */
-
-#elif defined(MPS_PF_W3I6MV)
-
-#include
-
-typedef struct StackContextStruct {
- jmp_buf jumpBuffer;
-} StackContextStruct;
-
-#define STACK_CONTEXT_SAVE(sc) ((void)setjmp((sc)->jumpBuffer))
-
-#define StackContextStackTop(sc) \
- ((Addr *)((_JUMP_BUFFER *)(sc)->jumpBuffer)->Rsp)
-
-
-#else
-
-/* TODO: implement this on other platforms in a safer way.
- * Potentially the callee saves from the calling function could be spilled
- * underneath the jmp_buf so returning the address of the jmp_buf for the
- * stack top is not completely safe.
- */
-
-#include
-
-typedef struct StackContextStruct {
- jmp_buf jumpBuffer;
-} StackContextStruct;
-
-#define STACK_CONTEXT_SAVE(sc) ((void)setjmp((sc)->jumpBuffer))
-
-#define StackContextStackTop(sc) ((Addr *)(sc)->jumpBuffer)
-
-
-#endif /* platform defines */
-
-#endif /* sc_h */
-
-
-/* C. COPYRIGHT AND LICENSE
- *
- * Copyright (C) 2001-2012 Ravenbrook Limited .
- * 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.
- */
diff --git a/mps/code/ss.c b/mps/code/ss.c
index 8c5bc44b022..53db27246dc 100644
--- a/mps/code/ss.c
+++ b/mps/code/ss.c
@@ -3,13 +3,8 @@
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
- * This is part of the code that scans the stack and fixes the registers
- * that may contain roots. See
- *
- * Each platform ABI has a set of callee-save registers that may still
- * contain roots. The StackScan function is defined for each ABI in source
- * files like ss*.c and ss*.asm. That function saves the callee save
- * registers in its frame, then calls StackScanInner to do the scanning.
+ * This scans the mutator's stack and fixes the registers that may
+ * contain roots. See .
*/
#include "mpm.h"
@@ -17,51 +12,60 @@
SRCID(ss, "$Id$");
-/* StackScanInner -- carry out stack scanning
+/* StackScan -- scan the mutator's stack and registers
*
- * This function should be called by StackScan once it has saved the
- * callee-save registers for the platform ABI in order to do the actual
- * scanning.
+ * StackScan scans the stack between stackBot and the top of the
+ * mutator's stack that was recorded by STACK_CONTEXT_BEGIN when the
+ * arena was entered. It also scans any roots which were in the
+ * mutator's callee-save registers at that point.
+ *
+ * See the specific implementations of StackContextScan for the exact
+ * registers which are scanned.
*/
-Res StackScanInner(ScanState ss,
- Addr *stackBot,
- Addr *stackTop,
- Count nSavedRegs)
+static Res stackScanInner(Arena arena, ScanState ss, Addr *stackBot,
+ StackContext sc)
+{
+ Addr *stackTop;
+ Res res;
+
+ AVERT(Arena, arena);
+ AVERT(ScanState, ss);
+
+ stackTop = StackContextStackTop(sc);
+ AVER(stackTop < stackBot);
+ AVER(AddrIsAligned((Addr)stackTop, sizeof(Addr))); /* .assume.align */
+
+ res = TraceScanAreaTagged(ss, stackTop, stackBot);
+ if (res != ResOK)
+ return res;
+
+ res = StackContextScan(ss, sc);
+ if (res != ResOK)
+ return res;
+
+ return ResOK;
+}
+
+Res StackScan(ScanState ss, Addr *stackBot)
{
Arena arena;
Res res;
AVERT(ScanState, ss);
- AVER(stackTop < stackBot);
- AVER(AddrIsAligned((Addr)stackTop, sizeof(Addr))); /* .assume.align */
- AVER(0 < nSavedRegs);
- AVER(nSavedRegs < 128); /* sanity check */
-
arena = ss->arena;
- /* If a stack pointer was stored when we entered the arena (through the
- MPS interface in mpsi*.c) then we scan just the saved registers and
- the stack starting there, in order to avoid false ambiguous references
- in the MPS stack. This is particularly important for transforms
- (trans.c). Otherwise, scan the whole stack. */
-
- if (arena->stackAtArenaEnter != NULL) {
- AVER(stackTop < arena->stackAtArenaEnter);
- AVER(arena->stackAtArenaEnter < stackBot);
- res = TraceScanAreaTagged(ss, stackTop, stackTop + nSavedRegs);
- if (res != ResOK)
- return res;
- res = TraceScanAreaTagged(ss, arena->stackAtArenaEnter, stackBot);
- if (res != ResOK)
- return res;
+ /* See */
+ AVER(arena->scAtArenaEnter);
+ if (arena->scAtArenaEnter) {
+ res = stackScanInner(arena, ss, stackBot, arena->scAtArenaEnter);
} else {
- res = TraceScanAreaTagged(ss, stackTop, stackBot);
- if (res != ResOK)
- return res;
+ /* Somehow missed saving the context at the entry point: do it now. */
+ StackContextStruct sc;
+ STACK_CONTEXT_SAVE(&sc);
+ res = stackScanInner(arena, ss, stackBot, &sc);
}
-
- return ResOK;
+ return res;
}
diff --git a/mps/code/ss.h b/mps/code/ss.h
index 831ad98aea8..11b01ac07da 100644
--- a/mps/code/ss.h
+++ b/mps/code/ss.h
@@ -3,7 +3,9 @@
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
- * Provides a function for scanning the stack and registers
+ * This module saves the mutator context on entry to the MPS, and
+ * provides functsions for decoding the context and scanning the root
+ * registers. See .
*/
#ifndef ss_h
@@ -11,6 +13,63 @@
#include "mpm.h"
+
+/* StackContext -- structure containing the callee-save registers and
+ * the stack pointer */
+
+#include
+
+typedef struct StackContextStruct {
+ jmp_buf jumpBuffer;
+} StackContextStruct;
+
+
+/* STACK_CONTEXT_BEGIN -- enter arena and save context */
+
+#define STACK_CONTEXT_BEGIN(arena) BEGIN \
+ StackContextStruct _sc; \
+ ArenaEnter(arena); \
+ STACK_CONTEXT_SAVE(&_sc); \
+ AVER(arena->scAtArenaEnter == NULL); \
+ arena->scAtArenaEnter = &_sc; \
+ BEGIN
+
+
+/* STACK_CONTEXT_END -- clear context and leave arena */
+
+#define STACK_CONTEXT_END(arena) END; \
+ arena->scAtArenaEnter = NULL; \
+ ArenaLeave(arena); \
+ END
+
+
+/* StackContextStackTop -- return the "top" of the mutator's stack at
+ * the point when the context was saved by STACK_CONTEXT_BEGIN. */
+
+extern Addr *StackContextStackTop(StackContext sc);
+
+
+/* StackContextScan -- scan references in the stack context */
+
+extern Res StackContextScan(ScanState ss, StackContext sc);
+
+
+/* STACK_CONTEXT_SAVE -- save the callee-saves and stack pointer */
+
+#if defined(MPS_OS_XC)
+
+/* We call _setjmp rather than setjmp because _setjmp saves only the
+ * register set and the stack while setjmp also saves the signal mask.
+ * See _setjmp(2). */
+
+#define STACK_CONTEXT_SAVE(sc) ((void)_setjmp((sc)->jumpBuffer))
+
+#else /* other platforms */
+
+#define STACK_CONTEXT_SAVE(sc) ((void)setjmp((sc)->jumpBuffer))
+
+#endif /* platform defines */
+
/* StackScan -- scan the current thread's stack
*
diff --git a/mps/code/ssan.c b/mps/code/ssan.c
index 27233e7b9f6..8f5fa47934b 100644
--- a/mps/code/ssan.c
+++ b/mps/code/ssan.c
@@ -1,47 +1,50 @@
-/* ssan.c: ANSI STACK SCANNER
+/* ssan.c: GENERIC STACK SCANNING
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
- * This module makes a best effort to scan the stack and fix the
+ * This makes a best effort to decode the stack context and scan the
* registers which may contain roots, using only the features of the
- * Standard C library.
- *
- * .assume.setjmp: The implementation assumes that setjmp stores all
- * the registers that need to be scanned in the jmp_buf.
+ * Standard C library. See .
*/
-#include
-
-#include "mpmtypes.h"
-#include "misc.h"
#include "ss.h"
-
SRCID(ssan, "$Id$");
-Res StackScan(ScanState ss, Addr *stackBot)
+/* StackContextStackTop -- return the "top" of the mutator's stack at
+ * the point when the context was saved by STACK_CONTEXT_BEGIN.
+ *
+ * .assume: This assumes that the structure pointed to by sc is
+ * stack-allocated "above" the mutator's stack, and so its address is
+ * a conservative approximation to the top of the mutator's stack. The
+ * use of STACK_CONTEXT_BEGIN in mpsi.c assures this.
+ */
+
+Addr *StackContextStackTop(StackContext sc)
{
- jmp_buf jb;
- void *stackTop = &jb;
+ return (void *)sc;
+}
- /* .assume.stack: This implementation assumes that the stack grows
- * downwards, so that the address of the jmp_buf is the limit of the
- * part of the stack that needs to be scanned. (StackScanInner makes
- * the same assumption.)
- */
- AVER(stackTop < (void *)stackBot);
- (void)setjmp(jb);
+/* StackContextScan -- scan references in the stack context
+ *
+ * This conservatively scans the whole of the StackContext. The
+ * PointerAlignDown is necessary in case the size of the jump buffer
+ * is not a multiple of sizeof(Addr).
+ */
- return StackScanInner(ss, stackBot, stackTop, sizeof jb / sizeof(Addr*));
+Res StackContextScan(ScanState ss, StackContext sc)
+{
+ return TraceScanAreaTagged(ss, (void *)sc,
+ PointerAlignDown(sc + 1, sizeof(Addr)));
}
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/ssw3i3mv.c b/mps/code/ssw3i3mv.c
index d879780734a..c750aafc71a 100644
--- a/mps/code/ssw3i3mv.c
+++ b/mps/code/ssw3i3mv.c
@@ -1,10 +1,10 @@
-/* ssw3i3mv.c: STACK SCANNING FOR WIN32 WITH MICROSOFT C
+/* ssw3i3mv.c: STACK SCANNING FOR WINDOWS ON IA-32 WITH MICROSOFT VISUAL C
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
- * This scans the stack and fixes the registers which may contain roots.
- * See .
+ * This decodes the stack context and scans the registers which may
+ * contain roots. See .
*
* REFERENCES
*
@@ -17,34 +17,49 @@
*/
#include "mpm.h"
-#include
SRCID(ssw3i3mv, "$Id$");
+#if !defined(MPS_PF_W3I3MV)
+#error "ssw3i3mv.c is specific to MPS_PF_W3I3MV."
+#endif
-Res StackScan(ScanState ss, Addr *stackBot)
+
+/* StackContextStackTop -- return the "top" of the mutator's stack at
+ * the point when the context was saved by STACK_CONTEXT_BEGIN. */
+
+Addr *StackContextStackTop(StackContext sc)
{
- jmp_buf jb;
+ _JUMP_BUFFER *jb = &sc->jumpBuffer;
+ Addr **p_esp = (void *)&jb->Esp;
+ return *p_esp;
+}
- /* We rely on the fact that Microsoft C's setjmp stores the callee-save
- registers in the jmp_buf. */
- (void)setjmp(jb);
+
+/* StackContextScan -- scan references in the stack context */
+
+Res StackContextScan(ScanState ss, StackContext sc)
+{
+ _JUMP_BUFFER *jb = &sc->jumpBuffer;
+ Addr *p_ebx = (void *)&jb->Ebx;
/* These checks will just serve to warn us at compile-time if the
setjmp.h header changes to indicate that the registers we want aren't
saved any more. */
- AVER(sizeof(((_JUMP_BUFFER *)jb)->Edi) == sizeof(Addr));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->Esi) == sizeof(Addr));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->Ebx) == sizeof(Addr));
+ AVER(sizeof jb->Edi == sizeof(Addr));
+ AVER(sizeof jb->Esi == sizeof(Addr));
+ AVER(sizeof jb->Ebx == sizeof(Addr));
/* Ensure that the callee-save registers will be found by
- StackScanInner when it's passed the address of the Ebx field. */
+ TraceScanAreaTagged when it's passed the address of the Ebx
+ field. */
AVER(offsetof(_JUMP_BUFFER, Edi) == offsetof(_JUMP_BUFFER, Ebx) + 4);
AVER(offsetof(_JUMP_BUFFER, Esi) == offsetof(_JUMP_BUFFER, Ebx) + 8);
- return StackScanInner(ss, stackBot, (Addr *)&((_JUMP_BUFFER *)jb)->Ebx, 3);
+ return TraceScanAreaTagged(ss, p_ebx, p_ebx + 3);
}
+
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited .
diff --git a/mps/code/ssw3i3pc.c b/mps/code/ssw3i3pc.c
index e03754c7eba..8b76e7d93d0 100644
--- a/mps/code/ssw3i3pc.c
+++ b/mps/code/ssw3i3pc.c
@@ -1,10 +1,10 @@
-/* ssw3i3pc.c: STACK SCANNING FOR WIN32 WITH PELLES C
+/* ssw3i3pc.c: STACK SCANNING FOR WINDOWS ON IA-32 WITH PELLES C
*
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
- * This scans the stack and fixes the registers which may contain roots.
- * See .
+ * This decodes the stack context and scans the registers which may
+ * contain roots. See .
*
* .assume.ms-compat: We rely on the fact that Pelles C's setjmp stores
* the callee-save registers in the jmp_buf and is compatible with Microsoft
@@ -27,6 +27,10 @@
SRCID(ssw3i3pc, "$Id$");
+#if !defined(MPS_PF_W3I3PC)
+#error "ssw3i3pc.c is specific to MPS_PF_W3I3PC."
+#endif
+
/* This definition isn't in the Pelles C headers, so we reproduce it here.
* See .assume.ms-compat. */
@@ -46,19 +50,31 @@ typedef struct __JUMP_BUFFER {
} _JUMP_BUFFER;
-Res StackScan(ScanState ss, Addr *stackBot)
-{
- jmp_buf jb;
+/* StackContextStackTop -- return the "top" of the mutator's stack at
+ * the point when the context was saved by STACK_CONTEXT_BEGIN. */
+Addr *StackContextStackTop(StackContext sc)
+{
+ _JUMP_BUFFER *jb = &sc->jumpBuffer;
+ Addr **p_esp = (void *)&jb->Esp;
+ return *p_esp;
+}
+
+
+/* StackContextScan -- scan references in the stack context */
+
+Res StackContextScan(ScanState ss, StackContext sc)
+{
/* .assume.ms-compat */
- (void)setjmp(jb);
+ _JUMP_BUFFER *jb = &sc->jumpBuffer;
+ Addr *p_ebx = (void *)&jb->Ebx;
/* Ensure that the callee-save registers will be found by
StackScanInner when it's passed the address of the Ebx field. */
AVER(offsetof(_JUMP_BUFFER, Edi) == offsetof(_JUMP_BUFFER, Ebx) + 4);
AVER(offsetof(_JUMP_BUFFER, Esi) == offsetof(_JUMP_BUFFER, Ebx) + 8);
- return StackScanInner(ss, stackBot, (Addr *)&((_JUMP_BUFFER *)jb)->Ebx, 3);
+ return TraceScanAreaTagged(ss, p_ebx, p_ebx + 3);
}
diff --git a/mps/code/ssw3i6mv.c b/mps/code/ssw3i6mv.c
index 16c33e3fb74..c1b78320148 100644
--- a/mps/code/ssw3i6mv.c
+++ b/mps/code/ssw3i6mv.c
@@ -3,10 +3,8 @@
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
- * This scans the stack and fixes the registers which may contain roots.
- * See . It's unlikely that the callee-save
- * registers contain mutator roots by the time this function is called, but
- * we can't be certain, so we must scan them anyway.
+ * This decodes the stack context and scans the registers which may
+ * contain roots. See .
*
* REFERENCES
*
@@ -29,25 +27,39 @@
SRCID(ssw3i6mv, "$Id$");
+#if !defined(MPS_PF_W3I6MV)
+#error "ssw3i6mv.c is specific to MPS_PF_W3I6MV."
+#endif
-Res StackScan(ScanState ss, Addr *stackBot)
+
+/* StackContextStackTop -- return the "top" of the mutator's stack at
+ * the point when the context was saved by STACK_CONTEXT_BEGIN. */
+
+Addr *StackContextStackTop(StackContext sc)
{
- jmp_buf jb;
+ _JUMP_BUFFER *jb = &sc->jumpBuffer;
+ Addr **p_rsp = (void *)&jb->Rsp;
+ return *p_rsp;
+}
- /* We rely on the fact that Microsoft C's setjmp stores the callee-save
- registers in the jmp_buf. */
- (void)setjmp(jb);
+
+/* StackContextScan -- scan references in the stack context */
+
+Res StackScan(ScanState ss, StackContext sc)
+{
+ _JUMP_BUFFER *jb = &sc->jumpBuffer;
+ Addr **p_rbx = (void *)&jb->Rbx;
/* These checks will just serve to warn us at compile-time if the
setjmp.h header changes to indicate that the registers we want aren't
saved any more. */
- AVER(sizeof(((_JUMP_BUFFER *)jb)->Rdi) == sizeof(Addr));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Addr));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->Rbp) == sizeof(Addr));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->R12) == sizeof(Addr));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->R13) == sizeof(Addr));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->R14) == sizeof(Addr));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->R15) == sizeof(Addr));
+ AVER(sizeof jb->Rdi == sizeof(Addr));
+ AVER(sizeof jb->Rsi == sizeof(Addr));
+ AVER(sizeof jb->Rbp == sizeof(Addr));
+ AVER(sizeof jb->R12 == sizeof(Addr));
+ AVER(sizeof jb->R13 == sizeof(Addr));
+ AVER(sizeof jb->R14 == sizeof(Addr));
+ AVER(sizeof jb->R15 == sizeof(Addr));
/* The layout of the jmp_buf forces us to harmlessly scan Rsp as well. */
AVER(offsetof(_JUMP_BUFFER, Rsp) == offsetof(_JUMP_BUFFER, Rbx) + 8);
@@ -59,9 +71,10 @@ Res StackScan(ScanState ss, Addr *stackBot)
AVER(offsetof(_JUMP_BUFFER, R14) == offsetof(_JUMP_BUFFER, Rbx) + 56);
AVER(offsetof(_JUMP_BUFFER, R15) == offsetof(_JUMP_BUFFER, Rbx) + 64);
- return StackScanInner(ss, stackBot, (Addr *)&((_JUMP_BUFFER *)jb)->Rbx, 9);
+ return TraceScanAreaTagged(ss, p_rbx, p_rbx + 9);
}
+
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited .
diff --git a/mps/code/ssw3i6pc.c b/mps/code/ssw3i6pc.c
index 89fbbeac420..ff565ec10b4 100644
--- a/mps/code/ssw3i6pc.c
+++ b/mps/code/ssw3i6pc.c
@@ -3,8 +3,8 @@
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
- * This scans the stack and fixes the registers which may contain roots.
- * See .
+ * This decodes the stack context and scans the registers which may
+ * contain roots. See .
*
* .assume.ms-compat: We rely on the fact that Pelles C's setjmp stores
* the callee-save registers in the jmp_buf and is compatible with Microsoft
@@ -33,6 +33,10 @@
SRCID(ssw3i6pc, "$Id$");
+#if !defined(MPS_PF_W3I6PC)
+#error "ssw3i6pc.c is specific to MPS_PF_W3I6PC."
+#endif
+
/* This definition isn't in the Pelles C headers, so we reproduce it here.
* See .assume.ms-compat. */
@@ -68,24 +72,34 @@ typedef struct _JUMP_BUFFER {
} _JUMP_BUFFER;
-Res StackScan(ScanState ss, Addr *stackBot)
-{
- jmp_buf jb;
+/* StackContextStackTop -- return the "top" of the mutator's stack at
+ * the point when the context was saved by STACK_CONTEXT_BEGIN. */
- /* We rely on the fact that Pelles C's setjmp stores the callee-save
- registers in the jmp_buf. */
- (void)setjmp(jb);
+Addr *StackContextStackTop(StackContext sc)
+{
+ _JUMP_BUFFER *jb = &sc->jumpBuffer;
+ Addr **p_rsp = (void *)&jb->Rsp;
+ return *p_rsp;
+}
+
+
+/* StackContextScan -- scan references in the stack context */
+
+Res StackContextScan(ScanState ss, StackContext sc)
+{
+ _JUMP_BUFFER *jb = &sc->jumpBuffer;
+ Addr **p_rbx = (void *)&jb->Rbx;
/* These checks will just serve to warn us at compile-time if the
setjmp.h header changes to indicate that the registers we want aren't
saved any more. */
- AVER(sizeof(((_JUMP_BUFFER *)jb)->Rdi) == sizeof(Addr));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Addr));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->Rbp) == sizeof(Addr));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->R12) == sizeof(Addr));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->R13) == sizeof(Addr));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->R14) == sizeof(Addr));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->R15) == sizeof(Addr));
+ AVER(sizeof jb->Rdi == sizeof(Addr));
+ AVER(sizeof jb->Rsi == sizeof(Addr));
+ AVER(sizeof jb->Rbp == sizeof(Addr));
+ AVER(sizeof jb->R12 == sizeof(Addr));
+ AVER(sizeof jb->R13 == sizeof(Addr));
+ AVER(sizeof jb->R14 == sizeof(Addr));
+ AVER(sizeof jb->R15 == sizeof(Addr));
/* The layout of the jmp_buf forces us to harmlessly scan Rsp as well. */
AVER(offsetof(_JUMP_BUFFER, Rsp) == offsetof(_JUMP_BUFFER, Rbx) + 8);
@@ -97,7 +111,7 @@ Res StackScan(ScanState ss, Addr *stackBot)
AVER(offsetof(_JUMP_BUFFER, R14) == offsetof(_JUMP_BUFFER, Rbx) + 56);
AVER(offsetof(_JUMP_BUFFER, R15) == offsetof(_JUMP_BUFFER, Rbx) + 64);
- return StackScanInner(ss, stackBot, (Addr *)&((_JUMP_BUFFER *)jb)->Rbx, 9);
+ return TraceScanAreaTagged(ss, p_rbx, p_rbx + 9);
}
diff --git a/mps/code/ssixi3.c b/mps/code/ssxci3.c
similarity index 51%
rename from mps/code/ssixi3.c
rename to mps/code/ssxci3.c
index 8cc1f8cbd45..a5893f31f8c 100644
--- a/mps/code/ssixi3.c
+++ b/mps/code/ssxci3.c
@@ -1,74 +1,49 @@
-/* ssixi3.c: UNIX/INTEL STACK SCANNING
+/* ssxci3.c: STACK SCANNING FOR OS X ON IA-32
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
- *
- * This scans the stack and fixes the registers which may contain
- * roots. See
- *
- * This code was originally developed and tested on Linux, and then
- * copied to the FreeBSD and Darwin (OS X) operating systems where it
- * also seems to work. Note that on FreeBSD and Darwin it has not
- * been indepently verified with respect to any ABI documentation.
- *
- * This code is common to more than one Unix implementation on
- * Intel hardware (but is not portable Unix code).
- *
- * The registers edi, esi, ebx are the registers defined to be preserved
- * across function calls and therefore may contain roots.
- * These are pushed on the stack for scanning.
- *
- * SOURCES
- *
- * .source.callees.saves: Set of callee-saved registers taken from
- * CALL_USED_REGISTERS in /config/i386/i386.h.
- * ebp added to the list because gcc now doesn't always use it as
- * a frame pointer so it could contain a root.
- *
- * ASSUMPTIONS
- *
- * .assume.align: The stack pointer is assumed to be aligned on a word
- * boundary.
- *
- * .assume.asm.stack: The compiler must not do wacky things with the
- * stack pointer around a call since we need to ensure that the
- * callee-save regs are visible during TraceScanArea.
- *
- * .assume.asm.order: The volatile modifier should prevent movement
- * of code, which might break .assume.asm.stack.
+ * Copyright (c) 2012-2014 Ravenbrook Limited. See end of file for license.
*
+ * This decodes the stack context and scans the registers which may
+ * contain roots. See .
*/
-
#include "mpm.h"
-SRCID(ssixi3, "$Id$");
+SRCID(ssxci3, "$Id$");
+
+#if !defined(MPS_OS_XC) || !defined(MPS_ARCH_I3)
+#error "ssxci3.c is specific to MPS_OS_XC and MPS_ARCH_I3."
+#endif
-/* .assume.asm.order */
-#define ASMV(x) __asm__ volatile (x)
+/* Offset of ESP in the jmp_buf in bytes, as defined in _setjmp.s.
+ * See the implementation of _setjmp in
+ * */
+
+#define JB_ESP 36
-Res StackScan(ScanState ss, Addr *stackBot)
+/* StackContextStackTop -- return the "top" of the mutator's stack at
+ * the point when the context was saved by STACK_CONTEXT_BEGIN. */
+
+Addr *StackContextStackTop(StackContext sc)
{
- Addr calleeSaveRegs[4];
+ Addr **p_esp = PointerAdd(&sc->jumpBuffer, JB_ESP);
+ return *p_esp;
+}
- /* .assume.asm.stack */
- /* Store the callee save registers on the stack so they get scanned
- * as they may contain roots.
- */
- ASMV("mov %%ebx, %0" : "=m" (calleeSaveRegs[0]));
- ASMV("mov %%esi, %0" : "=m" (calleeSaveRegs[1]));
- ASMV("mov %%edi, %0" : "=m" (calleeSaveRegs[2]));
- ASMV("mov %%ebp, %0" : "=m" (calleeSaveRegs[3]));
-
- return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs));
+
+/* StackContextScan -- scan references in the stack context */
+
+Res StackContextScan(ScanState ss, StackContext sc)
+{
+ return TraceScanAreaTagged(ss, (void *)sc, (void *)(sc + 1));
}
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2012-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/ssixi6.c b/mps/code/ssxci6.c
similarity index 51%
rename from mps/code/ssixi6.c
rename to mps/code/ssxci6.c
index e61af2ee961..901c59f513b 100644
--- a/mps/code/ssixi6.c
+++ b/mps/code/ssxci6.c
@@ -1,74 +1,60 @@
-/* ssixi6.c: UNIX/x64 STACK SCANNING
+/* ssxci6.c: STACK SCANNING FOR OS X ON x86-64
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
- *
- * This scans the stack and fixes the registers which may contain
- * roots. See
- *
- * This code was branched from ssixi3.c (32-bit Intel) initially for the
- * port to XCI6LL (Mac OS X on x86_64 with Clang).
- *
- * This code is common to more than one Unix implementation on
- * Intel hardware (but is not portable Unix code). According to Wikipedia,
- * all the non-Windows platforms use the System V AMD64 ABI. See
- * .sources.callees.saves.
- *
- * SOURCES
- *
- * .sources.callees.saves:
- * "Registers %rbp, %rbx and %r12 through %r15 "belong" to the calling
- * function and the called function is required to preserve their values.
- * In other words, a called function must preserve these registers’ values
- * for its caller." -- System V AMD64 ABI
- *
- *
- * ASSUMPTIONS
- *
- * .assume.align: The stack pointer is assumed to be aligned on a word
- * boundary.
- *
- * .assume.asm.stack: The compiler must not do wacky things with the
- * stack pointer around a call since we need to ensure that the
- * callee-save regs are visible during TraceScanArea.
- *
- * .assume.asm.order: The volatile modifier should prevent movement
- * of code, which might break .assume.asm.stack.
+ * Copyright (c) 2012-2014 Ravenbrook Limited. See end of file for license.
*
+ * This decodes the stack context and scans the registers which may
+ * contain roots. See .
*/
-
#include "mpm.h"
-SRCID(ssixi6, "$Id$");
+SRCID(ssxci6, "$Id$");
+
+#if !defined(MPS_OS_XC) || !defined(MPS_ARCH_I6)
+#error "ssxci6.c is specific to MPS_OS_XC and MPS_ARCH_I6."
+#endif
-/* .assume.asm.order */
-#define ASMV(x) __asm__ volatile (x)
+/* Offset of RSP in the jmp_buf in bytes, as defined in _setjmp.s.
+ * See the implementation of _setjmp in
+ * */
+
+#define JB_RSP 16
-Res StackScan(ScanState ss, Addr *stackBot)
+/* StackContextStackTop -- return the "top" of the mutator's stack at
+ * the point when the context was saved by STACK_CONTEXT_BEGIN. */
+
+Addr *StackContextStackTop(StackContext sc)
{
- Addr calleeSaveRegs[6];
-
- /* .assume.asm.stack */
- /* Store the callee save registers on the stack so they get scanned
- * as they may contain roots.
- */
- ASMV("mov %%rbp, %0" : "=m" (calleeSaveRegs[0]));
- ASMV("mov %%rbx, %0" : "=m" (calleeSaveRegs[1]));
- ASMV("mov %%r12, %0" : "=m" (calleeSaveRegs[2]));
- ASMV("mov %%r13, %0" : "=m" (calleeSaveRegs[3]));
- ASMV("mov %%r14, %0" : "=m" (calleeSaveRegs[4]));
- ASMV("mov %%r15, %0" : "=m" (calleeSaveRegs[5]));
-
- return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs));
+ Addr **p_rsp = PointerAdd(&(sc)->jumpBuffer, JB_RSP);
+ return *p_rsp;
+}
+
+
+/* StackContextScan -- scan references in the stack context
+ *
+ * We conservatively scan the whole of the jump buffer, assuming that
+ * all references are stored at aligned positions.
+ *
+ * The PointerAlignDown is necessary because the size of the jump
+ * buffer is not a multiple of sizeof(Addr) on this platform: see
+ * setjmp.h, where _JBLEN is 37.
+ *
+ * _setjmp.s,
+ */
+
+Res StackContextScan(ScanState ss, StackContext sc)
+{
+ return TraceScanAreaTagged(ss, (void *)sc,
+ PointerAlignDown(sc + 1, sizeof(Addr)));
}
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2012-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/xci3gc.gmk b/mps/code/xci3gc.gmk
index 2ba7c8af121..1540fe1ddc1 100644
--- a/mps/code/xci3gc.gmk
+++ b/mps/code/xci3gc.gmk
@@ -9,17 +9,18 @@
PFM = xci3gc
-MPMPF = lockix.c thxc.c vmix.c protix.c proti3.c prmci3xc.c span.c ssixi3.c \
- protxc.c
-
-LIBS =
-
-RANLIB=ranlib
+MPMPF = \
+ lockix.c \
+ prmci3xc.c \
+ proti3.c \
+ protix.c \
+ protxc.c \
+ span.c \
+ ssxci3.c \
+ thxc.c \
+ vmix.c
include gc.gmk
-
-CC = gcc -arch i386
-
include comm.gmk
diff --git a/mps/code/xci6ll.gmk b/mps/code/xci6ll.gmk
index 597979539ef..8849e4d4b58 100644
--- a/mps/code/xci6ll.gmk
+++ b/mps/code/xci6ll.gmk
@@ -20,7 +20,7 @@ MPMPF = \
protix.c \
protxc.c \
span.c \
- ssixi6.c \
+ ssxci6.c \
thxc.c \
vmix.c
diff --git a/mps/design/ss.txt b/mps/design/ss.txt
index 01dd2caf268..9387009a934 100644
--- a/mps/design/ss.txt
+++ b/mps/design/ss.txt
@@ -7,7 +7,7 @@ Stack and register scanning
:Author: Gareth Rees
:Date: 2014-10-22
:Status: complete design
-:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/thread-manager.txt#7 $
+:Revision: $Id$
:Copyright: See `Copyright and License`_.
:Index terms: pair: stack and register scanning; design
@@ -35,25 +35,40 @@ Requirements
------------
_`.req.stack.top`: Must locate the top of the mutator's stack. (This
-is needed to support conservative garbage collection of uncooperative
-code, where references might be stored by mutator on its stack.)
+is needed for conservative garbage collection of uncooperative code,
+where references might be stored by mutator on its stack, to work.)
+
+.. _job003525: http://www.ravenbrook.com/project/mps/issue/job003525/
_`.req.stack.bottom.not`: There is no requirement to locate the bottom
of the stack. (The mutator supplies this as an argument to
``mps_root_create_reg()``.)
-_`.req.registers`: Must locate and scan all references in the *root
-registers*, the subset of registers which might contain references
-that do not also appear on the stack. (This is needed to support
-conservative garbage collection of uncooperative code, where
-references might appear in registers.)
+_`.req.registers`: Must locate and scan all references in the
+mutator's *root registers*, the subset of registers which might
+contain references that do not also appear on the stack. (This is
+needed for conservative garbage collection of uncooperative code,
+where references might appear in registers, to work.)
+
+_`.req.entry`: Should save the mutator's context (stack and registers)
+at the point where it enters the MPS. (This avoids scanning registers
+and stack that belong to the MPS rather than the mutator, leading to
+unnecessary pinning and zone pollution; see job003525_.)
+
+_`.req.setjmp`: The implementation must follow the C Standard in its
+use of the ``setjmp`` macro. (So that it is reliable and portable.)
Design
------
-_`.sol.stack.top`: Implementations find the top of the stack by
-taking the address of a local variable.
+_`.origin`: The design was originally proposed in
+mail.richard.2012-08-03.14-36_.
+
+.. _mail.richard.2012-08-03.14-36: https://info.ravenbrook.com/mail/2012/08/03/14-36-35/0/
+
+_`.sol.entry-points`: To meet `.req.stack.entry`_, the mutator's
+registers and stack must be recorded when the mutator enters the MPS.
_`.sol.registers`: Implementations spill the root registers onto the
stack so that they can be scanned there.
@@ -66,57 +81,179 @@ been spilled onto the stack by the time the MPS is entered, so will be
scanned by the stack scan. Floating-point registers and debugging
registers do not, as far as we are aware, contain pointers.
-_`.sol.inner`: Having located the top of the stack (``stackTop``), and
-spilled the root registers into the next ``n`` words, implementations
-call the generic function ``StackScanInner(ss, stackBot, stackTop,
-n)`` to actually do the scanning.
+_`.sol.setjmp`: The C standard specifies that ``jmp_buf``
+"is an array type suitable for holding the information needed to
+restore a calling environment. The environment of a call to the
+``setjmp`` macro consists of information sufficient for a call to the
+``longjmp`` function to return execution to the correct block and
+invocation of that block, were it called recursively." This is what we
+need: the jump buffer needs to include the root registers in order to
+work as described. (A sufficiently perverse implementation could
+defeat this, but it works on all our supported platforms.)
+
+_`.sol.setjmp.scan`: An implementation can decode the jump
+buffer and scan just the root registers, or it can conservatively scan
+the whole of the jump buffer.
+
+_`.sol.stack.top`: Similarly, an implementation can decode the jump
+buffer and get the top of the mutator's stack from the stack pointer
+register, or it can conservatively use the address of a local variable
+in the entry point to the MPS.
+
+_`.sol.xc.alternative`: On OS X, we could use ``getcontext()`` from
+libunwind (see here_), but that produces deprecation warnings and
+introduces a dependency on that library.
+
+.. _here: http://stackoverflow.com/questions/3592914/how-can-i-implement-cooperative-lightweight-threading-with-c-on-mac-os-x
+
+
+Analysis
+--------
+
+_`.anal.setjmp`: The C90 Standard says:
+
+ An invocation of the ``setjmp`` macro shall appear only in one of
+ the following contexts:
+
+ - the entire controlling expression of a selection or iteration
+ statement;
+
+ - one operand of a relational or equality operator with the other
+ operand an integral constant expression, with the resulting
+ expression being the entire controlling expression of a
+ selection or iteration statement;
+
+ - the operand of a unary ``!`` operator with the resulting
+ expression being the entire controlling expression of a
+ selection or iteration statement; or
+
+ - the entire expression of an expression statement (possibly cast
+ to ``void``).
+
+And C99 adds:
+
+ If the invocation appears in any other context, the behavior is
+ undefined.
+
+_`.anal.entry-points`: Here's a reverse call graph (in the master
+sources at changelevel 187410) showing which entry points might call
+``StackScan()`` and so need to record the stack context::
+
+ StackScan
+ └ThreadScan
+ └mps_stack_scan_ambig
+ └RootScan
+ └traceScanRootRes
+ └traceScanRoot
+ └rootFlip
+ └traceFlip
+ └TraceStart
+ ├TracePoll
+ │ ├ArenaStep
+ │ │ └mps_arena_step
+ │ └ArenaPoll
+ │ ├mps_alloc
+ │ ├mps_ap_fill
+ │ ├mps_ap_fill_with_reservoir_permit
+ │ ├mps_ap_alloc_pattern_end
+ │ ├mps_ap_alloc_pattern_reset
+ │ └ArenaRelease
+ │ ├mps_arena_release
+ │ └ArenaStartCollect
+ │ ├mps_arena_start_collect
+ │ └ArenaCollect
+ │ └mps_arena_collect
+ └TraceStartCollectAll
+ ├ArenaStep ⤴
+ ├ArenaStartCollect ⤴
+ └TracePoll ⤴
+
+So the entry points that need to save the stack context are
+``mps_arena_step()``, ``mps_alloc()``, ``mps_ap_fill()``,
+``mps_ap_fill_with_reservoir_permit()``,
+``mps_ap_alloc_pattern_end()``, ``mps_ap_alloc_pattern_reset()``,
+``mps_arena_release()``, ``mps_arena_start_collect()``, and
+``mps_arena_collect()``.
Interface
---------
+``typedef StackContextStruct *StackContext``
+
+_`.if.sc`: A structure encapsulating the mutator context.
+
+``Addr StackContextStackTop(StackContext sc)``
+
+_`.if.stack.top`: Return (a conservative approximation to) the address
+of the "top" of the mutator's stack at the point where ``sc`` was
+stored. In the common case, where the stack grows downwards, this is
+actually the lowest stack address.
+
``Res StackScan(ScanState ss, Addr *stackBot)``
-_`.if.scan`: Scan the root registers of the current thread, and the
-control stack between ``stackBot`` and the top of the stack, in the
-context of the given scan state. Return ``ResOK`` if successful, or
-another result code if not.
+_`.if.scan`: Scan the stack between ``stackBot`` and the "top" of the
+mutator's stack that was recorded by ``STACK_CONTEXT_BEGIN()`` when
+the arena was entered. Also scan any roots which were in the mutator's
+callee-save registers at that point. Return ``ResOK`` if successful,
+or another result code if not.
+``STACK_CONTEXT_SAVE(StackContext sc)``
-Issue
------
+_`.if.save`: Store the mutator context in the structure ``sc``.
-_`.issue.overscan`: This design leads to over-scanning, because by the
-time ``StackScan()`` is called, there are several MPS functions on the
-stack. The scan thus ends up scanning references that belong the MPS,
-not to the mutator. See job003525_.
+_`.if.save.macro`: This must be implemented as a macro because it
+needs to run in the stack frame of the entry point (if it runs in some
+other function it does not necessarily get the mutator's registers).
+This necessity to have the definition in scope in ``mpsi.c``, while
+also having different definitions on different platforms, requires a
+violation of design.mps.config.no-spaghetti_.
-.. _job003525: http://www.ravenbrook.com/project/mps/issue/job003525/
+.. _design.mps.config.no-spaghetti: config#no-spaghetti
+
+``STACK_CONTEXT_BEGIN(Arena arena)``
+
+_`.if.begin`: Start an MPS operation that needs to know the mutator
+context. This macro must be used like this::
+
+ Res res;
+ STACK_CONTEXT_BEGIN(arena) {
+ res = ArenaStartCollect(arena);
+ } STACK_CONTEXT_END(arena);
+ return res;
+
+That is, it must be paired with ``STACK_CONTEXT_END()``, and there
+must be no ``return`` between the two macro invocations.
+
+This macro takes the arena lock, stores the mutator context in a
+``StackContext`` structure allocated on the stack, and sets
+``arena->stackAtArenaEnter`` to the address of the top of the
+mutator's stack.
+
+``STACK_CONTEXT_END(Arena arena)``
+
+_`.if.end`: Finish the MPS operation that was started by ``STACK_CONTEXT_BEGIN()``.
+
+This macro sets ``arena->stackAtArenaEnter`` to ``NULL`` and releases
+the arena lock.
Implementations
---------------
-_`.impl.an`: Generic implementation in ``ssan.c``. This calls
-``setjmp()`` with a stack-allocated ``jmp_buf`` to spill the registers
-onto the stack. The C standard specifies that ``jmp_buf`` "is an array
-type suitable for holding the information needed to restore a calling
-environment. The environment of a call to the ``setjmp`` macro
-consists of information sufficient for a call to the ``longjmp``
-function to return execution to the correct block and invocation of
-that block, were it called recursively." Note that the C standard does
-not specify where the callee-save registers appear in the ``jmp_buf``,
-so the whole buffer must be scanned.
-
-_`.impl.ix`: Unix implementation in ``ssixi3.c`` and ``ssixi6.c``.
-Assembler instructions are used to spill exactly the callee-save
-registers. (Clang and GCC support a common assembler syntax.)
+_`.impl.an`: Generic implementation in ``ssan.c``. Since the C
+standard does not specify where the callee-save registers appear in
+the jump buffer, the whole buffer must be scanned, and the top of the
+stack must be taken conservatively from a local variable.
_`.impl.w3`: Windows implementation in ``ssw3i3mv.c`` and
-``ssw3i6mv.c``. Like `.impl.an`_, this implementation uses
-``setjmp()`` with a stack-allocated ``jmp_buf`` to spill the registers
-onto the stack. However, we know the layout of the ``jmp_buf`` used by
-the compiler, and so can scan exactly the subset of registers we need.
+``ssw3i6mv.c``. We know the layout of the jump buffer used by the
+compiler, and so can scan exactly the subset of registers we need, and
+decode the stack pointer from ESP (on IA-32) or RSP (on x86-64).
+
+_`.impl.xc`: OS X implementation in ``ssxci3.c`` and ``ssxci6.c``.
+Scans the jump buffer conservatively as for `.impl.an`_, but decodes
+the stack pointer from ESP (on IA-32) or RSP (on x86-64).
Document History
From 15baf0680283c5718ce84ec8835467f3a4bdca10 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sun, 26 Oct 2014 22:24:39 +0000
Subject: [PATCH 030/759] Better reference for setjmp.h.
Copied from Perforce
Change: 187413
ServerID: perforce.ravenbrook.com
---
mps/code/ssxci6.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/mps/code/ssxci6.c b/mps/code/ssxci6.c
index 901c59f513b..1deb5c8153f 100644
--- a/mps/code/ssxci6.c
+++ b/mps/code/ssxci6.c
@@ -41,8 +41,7 @@ Addr *StackContextStackTop(StackContext sc)
* The PointerAlignDown is necessary because the size of the jump
* buffer is not a multiple of sizeof(Addr) on this platform: see
* setjmp.h, where _JBLEN is 37.
- *
- * _setjmp.s,
+ *
*/
Res StackContextScan(ScanState ss, StackContext sc)
From 0f2e2b8c098c5b95b0d8437c413e5edc2e48d049 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 31 Oct 2014 14:09:40 +0000
Subject: [PATCH 031/759] Check the result of calling setjmp.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Avoid "might be clobbered by ‘longjmp’ or ‘vfork’" error from gcc.
Explain why we don't use assembly language to spill the registers.
Copied from Perforce
Change: 187423
ServerID: perforce.ravenbrook.com
---
mps/code/mpsi.c | 16 ++++++----------
mps/code/ss.h | 10 ++++++++--
mps/design/ss.txt | 4 ++++
3 files changed, 18 insertions(+), 12 deletions(-)
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index 3dcfadbddf8..83a7dc2302e 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -1864,19 +1864,17 @@ mps_res_t mps_ap_alloc_pattern_begin(mps_ap_t mps_ap,
mps_res_t mps_ap_alloc_pattern_end(mps_ap_t mps_ap,
mps_alloc_pattern_t alloc_pattern)
{
- Buffer buf;
Arena arena;
Res res;
AVER(mps_ap != NULL);
- buf = BufferOfAP(mps_ap);
- AVER(TESTT(Buffer, buf));
+ AVER(TESTT(Buffer, BufferOfAP(mps_ap)));
UNUSED(alloc_pattern); /* .ramp.hack */
- arena = BufferArena(buf);
+ arena = BufferArena(BufferOfAP(mps_ap));
STACK_CONTEXT_BEGIN(arena) {
- res = BufferRampEnd(buf);
+ res = BufferRampEnd(BufferOfAP(mps_ap));
ArenaPoll(ArenaGlobals(arena)); /* .poll */
} STACK_CONTEXT_END(arena);
@@ -1886,17 +1884,15 @@ mps_res_t mps_ap_alloc_pattern_end(mps_ap_t mps_ap,
mps_res_t mps_ap_alloc_pattern_reset(mps_ap_t mps_ap)
{
- Buffer buf;
Arena arena;
AVER(mps_ap != NULL);
- buf = BufferOfAP(mps_ap);
- AVER(TESTT(Buffer, buf));
+ AVER(TESTT(Buffer, BufferOfAP(mps_ap)));
- arena = BufferArena(buf);
+ arena = BufferArena(BufferOfAP(mps_ap));
STACK_CONTEXT_BEGIN(arena) {
- BufferRampReset(buf);
+ BufferRampReset(BufferOfAP(mps_ap));
ArenaPoll(ArenaGlobals(arena)); /* .poll */
} STACK_CONTEXT_END(arena);
diff --git a/mps/code/ss.h b/mps/code/ss.h
index 11b01ac07da..e2aeaddb872 100644
--- a/mps/code/ss.h
+++ b/mps/code/ss.h
@@ -62,11 +62,17 @@ extern Res StackContextScan(ScanState ss, StackContext sc);
* register set and the stack while setjmp also saves the signal mask.
* See _setjmp(2). */
-#define STACK_CONTEXT_SAVE(sc) ((void)_setjmp((sc)->jumpBuffer))
+#define STACK_CONTEXT_SAVE(sc) BEGIN \
+ int _set = _setjmp((sc)->jumpBuffer); \
+ AVER(_set == 0); \
+ END
#else /* other platforms */
-#define STACK_CONTEXT_SAVE(sc) ((void)setjmp((sc)->jumpBuffer))
+#define STACK_CONTEXT_SAVE(sc) BEGIN \
+ int _set = setjmp((sc)->jumpBuffer); \
+ AVER(_set == 0); \
+ END
#endif /* platform defines */
diff --git a/mps/design/ss.txt b/mps/design/ss.txt
index 9387009a934..79421a6fdb3 100644
--- a/mps/design/ss.txt
+++ b/mps/design/ss.txt
@@ -58,6 +58,10 @@ unnecessary pinning and zone pollution; see job003525_.)
_`.req.setjmp`: The implementation must follow the C Standard in its
use of the ``setjmp`` macro. (So that it is reliable and portable.)
+_`.req.assembly`: The implementation should not use assembly language.
+(So that it can be developed in tools like Microsoft Visual Studio
+that don't support this.)
+
Design
------
From 4a387a0381f7ccea165d124d6101b8155788c5e5 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 31 Oct 2014 14:39:51 +0000
Subject: [PATCH 032/759] Fix compilation on windows.
Copied from Perforce
Change: 187424
ServerID: perforce.ravenbrook.com
---
mps/code/ssw3i3mv.c | 4 ++--
mps/code/ssw3i3pc.c | 7 ++++---
mps/code/ssw3i6mv.c | 8 ++++----
mps/code/ssw3i6pc.c | 6 +++---
4 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/mps/code/ssw3i3mv.c b/mps/code/ssw3i3mv.c
index c750aafc71a..6cf6525da9d 100644
--- a/mps/code/ssw3i3mv.c
+++ b/mps/code/ssw3i3mv.c
@@ -30,7 +30,7 @@ SRCID(ssw3i3mv, "$Id$");
Addr *StackContextStackTop(StackContext sc)
{
- _JUMP_BUFFER *jb = &sc->jumpBuffer;
+ _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
Addr **p_esp = (void *)&jb->Esp;
return *p_esp;
}
@@ -40,7 +40,7 @@ Addr *StackContextStackTop(StackContext sc)
Res StackContextScan(ScanState ss, StackContext sc)
{
- _JUMP_BUFFER *jb = &sc->jumpBuffer;
+ _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
Addr *p_ebx = (void *)&jb->Ebx;
/* These checks will just serve to warn us at compile-time if the
diff --git a/mps/code/ssw3i3pc.c b/mps/code/ssw3i3pc.c
index 8b76e7d93d0..9b5b6a46464 100644
--- a/mps/code/ssw3i3pc.c
+++ b/mps/code/ssw3i3pc.c
@@ -55,7 +55,7 @@ typedef struct __JUMP_BUFFER {
Addr *StackContextStackTop(StackContext sc)
{
- _JUMP_BUFFER *jb = &sc->jumpBuffer;
+ _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
Addr **p_esp = (void *)&jb->Esp;
return *p_esp;
}
@@ -66,11 +66,12 @@ Addr *StackContextStackTop(StackContext sc)
Res StackContextScan(ScanState ss, StackContext sc)
{
/* .assume.ms-compat */
- _JUMP_BUFFER *jb = &sc->jumpBuffer;
+ _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
Addr *p_ebx = (void *)&jb->Ebx;
/* Ensure that the callee-save registers will be found by
- StackScanInner when it's passed the address of the Ebx field. */
+ TraceScanAreaTagged when it's passed the address of the Ebx
+ field. */
AVER(offsetof(_JUMP_BUFFER, Edi) == offsetof(_JUMP_BUFFER, Ebx) + 4);
AVER(offsetof(_JUMP_BUFFER, Esi) == offsetof(_JUMP_BUFFER, Ebx) + 8);
diff --git a/mps/code/ssw3i6mv.c b/mps/code/ssw3i6mv.c
index c1b78320148..bfc5793d5ab 100644
--- a/mps/code/ssw3i6mv.c
+++ b/mps/code/ssw3i6mv.c
@@ -37,7 +37,7 @@ SRCID(ssw3i6mv, "$Id$");
Addr *StackContextStackTop(StackContext sc)
{
- _JUMP_BUFFER *jb = &sc->jumpBuffer;
+ _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
Addr **p_rsp = (void *)&jb->Rsp;
return *p_rsp;
}
@@ -45,10 +45,10 @@ Addr *StackContextStackTop(StackContext sc)
/* StackContextScan -- scan references in the stack context */
-Res StackScan(ScanState ss, StackContext sc)
+Res StackContextScan(ScanState ss, StackContext sc)
{
- _JUMP_BUFFER *jb = &sc->jumpBuffer;
- Addr **p_rbx = (void *)&jb->Rbx;
+ _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
+ Addr *p_rbx = (void *)&jb->Rbx;
/* These checks will just serve to warn us at compile-time if the
setjmp.h header changes to indicate that the registers we want aren't
diff --git a/mps/code/ssw3i6pc.c b/mps/code/ssw3i6pc.c
index ff565ec10b4..adbc1a68aa0 100644
--- a/mps/code/ssw3i6pc.c
+++ b/mps/code/ssw3i6pc.c
@@ -77,7 +77,7 @@ typedef struct _JUMP_BUFFER {
Addr *StackContextStackTop(StackContext sc)
{
- _JUMP_BUFFER *jb = &sc->jumpBuffer;
+ _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
Addr **p_rsp = (void *)&jb->Rsp;
return *p_rsp;
}
@@ -87,8 +87,8 @@ Addr *StackContextStackTop(StackContext sc)
Res StackContextScan(ScanState ss, StackContext sc)
{
- _JUMP_BUFFER *jb = &sc->jumpBuffer;
- Addr **p_rbx = (void *)&jb->Rbx;
+ _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
+ Addr *p_rbx = (void *)&jb->Rbx;
/* These checks will just serve to warn us at compile-time if the
setjmp.h header changes to indicate that the registers we want aren't
From 87af8bf916ce9cf40f33deb039df88baa3c2e10e Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 31 Oct 2014 15:07:36 +0000
Subject: [PATCH 033/759] Avoid copying out design into the code -- keep things
in one place.
No need for a prototype for StackScanInner.
Explain the fragility of the analysis and how we cope with it.
Copied from Perforce
Change: 187425
ServerID: perforce.ravenbrook.com
---
mps/code/ss.c | 11 +----------
mps/code/ss.h | 25 +------------------------
mps/design/ss.txt | 23 ++++++++++++++++++-----
3 files changed, 20 insertions(+), 39 deletions(-)
diff --git a/mps/code/ss.c b/mps/code/ss.c
index 53db27246dc..733cd573228 100644
--- a/mps/code/ss.c
+++ b/mps/code/ss.c
@@ -12,16 +12,7 @@
SRCID(ss, "$Id$");
-/* StackScan -- scan the mutator's stack and registers
- *
- * StackScan scans the stack between stackBot and the top of the
- * mutator's stack that was recorded by STACK_CONTEXT_BEGIN when the
- * arena was entered. It also scans any roots which were in the
- * mutator's callee-save registers at that point.
- *
- * See the specific implementations of StackContextScan for the exact
- * registers which are scanned.
- */
+/* StackScan -- scan the mutator's stack and registers */
static Res stackScanInner(Arena arena, ScanState ss, Addr *stackBot,
StackContext sc)
diff --git a/mps/code/ss.h b/mps/code/ss.h
index e2aeaddb872..14058dc2cdf 100644
--- a/mps/code/ss.h
+++ b/mps/code/ss.h
@@ -77,34 +77,11 @@ extern Res StackContextScan(ScanState ss, StackContext sc);
#endif /* platform defines */
-/* StackScan -- scan the current thread's stack
- *
- * StackScan scans the stack of the current thread, Between stackBot and the
- * current top of stack. It also fixes any roots which may be in callee-save
- * registers.
- *
- * See the specific implementation for the exact registers which are scanned.
- *
- * If a stack pointer has been stashed at arena entry (through the MPS
- * interface in mpsi*.c) then only the registers and the stack between
- * stackAtArenaEnter and stackBot is scanned, to avoid scanning false
- * ambiguous references on the MPS's own stack. This is particularly
- * important for transforms (trans.c).
- *
- * The word pointed to by stackBot is fixed if the stack is by convention
- * empty, and not fixed if it is full. Where empty means sp points to first
- * free word beyond the top of stack. Full means sp points to the top of
- * stack itself.
- */
+/* StackScan -- scan the mutator's stack and registers */
extern Res StackScan(ScanState ss, Addr *stackBot);
-extern Res StackScanInner(ScanState ss,
- Addr *stackBot,
- Addr *stackTop,
- Count nSavedRegs);
-
#endif /* ss_h */
diff --git a/mps/design/ss.txt b/mps/design/ss.txt
index 79421a6fdb3..069b1e90a69 100644
--- a/mps/design/ss.txt
+++ b/mps/design/ss.txt
@@ -110,6 +110,14 @@ introduces a dependency on that library.
.. _here: http://stackoverflow.com/questions/3592914/how-can-i-implement-cooperative-lightweight-threading-with-c-on-mac-os-x
+_`.sol.entry-points.fragile`: The analysis of which entry points might
+need to save the context (see `.anal.entry-points`_ below) is fragile.
+It might be incorrect now, or become incomplete if we refactor the
+internals of tracing and polling. As a defence against errors of this
+form, ``StackScan()`` asserts that the context was saved, but if the
+client program continues from the assertion, it saves the context
+anyway and continues.
+
Analysis
--------
@@ -196,11 +204,16 @@ actually the lowest stack address.
``Res StackScan(ScanState ss, Addr *stackBot)``
-_`.if.scan`: Scan the stack between ``stackBot`` and the "top" of the
-mutator's stack that was recorded by ``STACK_CONTEXT_BEGIN()`` when
-the arena was entered. Also scan any roots which were in the mutator's
-callee-save registers at that point. Return ``ResOK`` if successful,
-or another result code if not.
+_`.if.scan`: Scan the stack of the current thread, between
+``stackBot`` and the "top" of the mutator's stack that was recorded by
+``STACK_CONTEXT_BEGIN()`` when the arena was entered. Also scan any
+roots which were in the mutator's callee-save registers at that point.
+Return ``ResOK`` if successful, or another result code if not. See the
+platform-specific implementation of ``StackContextScan()`` for the
+exact registers which are scanned.
+
+_`.if.scan.bottom`: Note that the word pointed to by ``stackBot`` is
+not fixed.
``STACK_CONTEXT_SAVE(StackContext sc)``
From faac1d82abf3fec2a71dcd87414851e3d5b1b5e3 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 31 Oct 2014 15:10:00 +0000
Subject: [PATCH 034/759] Better cross-reference.
Copied from Perforce
Change: 187426
ServerID: perforce.ravenbrook.com
---
mps/code/ss.c | 2 +-
mps/design/ss.txt | 16 ++++++++--------
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/mps/code/ss.c b/mps/code/ss.c
index 733cd573228..ae387b4c4c4 100644
--- a/mps/code/ss.c
+++ b/mps/code/ss.c
@@ -46,7 +46,7 @@ Res StackScan(ScanState ss, Addr *stackBot)
AVERT(ScanState, ss);
arena = ss->arena;
- /* See */
+ /* See */
AVER(arena->scAtArenaEnter);
if (arena->scAtArenaEnter) {
res = stackScanInner(arena, ss, stackBot, arena->scAtArenaEnter);
diff --git a/mps/design/ss.txt b/mps/design/ss.txt
index 069b1e90a69..bf94264dea4 100644
--- a/mps/design/ss.txt
+++ b/mps/design/ss.txt
@@ -74,6 +74,14 @@ mail.richard.2012-08-03.14-36_.
_`.sol.entry-points`: To meet `.req.stack.entry`_, the mutator's
registers and stack must be recorded when the mutator enters the MPS.
+_`.sol.entry-points.fragile`: The analysis of which entry points might
+need to save the context (see `.anal.entry-points`_ below) is fragile.
+It might be incorrect now, or become incomplete if we refactor the
+internals of tracing and polling. As a defence against errors of this
+form, ``StackScan()`` asserts that the context was saved, but if the
+client program continues from the assertion, it saves the context
+anyway and continues.
+
_`.sol.registers`: Implementations spill the root registers onto the
stack so that they can be scanned there.
@@ -110,14 +118,6 @@ introduces a dependency on that library.
.. _here: http://stackoverflow.com/questions/3592914/how-can-i-implement-cooperative-lightweight-threading-with-c-on-mac-os-x
-_`.sol.entry-points.fragile`: The analysis of which entry points might
-need to save the context (see `.anal.entry-points`_ below) is fragile.
-It might be incorrect now, or become incomplete if we refactor the
-internals of tracing and polling. As a defence against errors of this
-form, ``StackScan()`` asserts that the context was saved, but if the
-client program continues from the assertion, it saves the context
-anyway and continues.
-
Analysis
--------
From cc9becad74c574b62f719abf06e37125c96640ce Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 31 Oct 2014 15:19:49 +0000
Subject: [PATCH 035/759] Fix typo; document the assumptions used by stackscan.
Copied from Perforce
Change: 187428
ServerID: perforce.ravenbrook.com
---
mps/code/ss.c | 15 +++++++++++++--
mps/code/ss.h | 2 +-
mps/design/ss.txt | 3 ---
3 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/mps/code/ss.c b/mps/code/ss.c
index ae387b4c4c4..efdad8eda34 100644
--- a/mps/code/ss.c
+++ b/mps/code/ss.c
@@ -5,6 +5,17 @@
*
* This scans the mutator's stack and fixes the registers that may
* contain roots. See .
+ *
+ * This is a generic implementation, but it makes assumptions that,
+ * while true on all the platforms we currently (version 1.115)
+ * support, may not be true on all platforms.
+ *
+ * .assume.down: The stack grows downwards.
+ *
+ * .assume.bottom: There is no need to scan the word pointed to by
+ * stackBot.
+ *
+ * .assume.align: Addresses on the stack are aligned to sizeof(Addr).
*/
#include "mpm.h"
@@ -24,10 +35,10 @@ static Res stackScanInner(Arena arena, ScanState ss, Addr *stackBot,
AVERT(ScanState, ss);
stackTop = StackContextStackTop(sc);
- AVER(stackTop < stackBot);
+ AVER(stackTop < stackBot); /* .assume.down */
AVER(AddrIsAligned((Addr)stackTop, sizeof(Addr))); /* .assume.align */
- res = TraceScanAreaTagged(ss, stackTop, stackBot);
+ res = TraceScanAreaTagged(ss, stackTop, stackBot); /* .assume.bottom */
if (res != ResOK)
return res;
diff --git a/mps/code/ss.h b/mps/code/ss.h
index 14058dc2cdf..0036f50886f 100644
--- a/mps/code/ss.h
+++ b/mps/code/ss.h
@@ -4,7 +4,7 @@
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* This module saves the mutator context on entry to the MPS, and
- * provides functsions for decoding the context and scanning the root
+ * provides functions for decoding the context and scanning the root
* registers. See .
*/
diff --git a/mps/design/ss.txt b/mps/design/ss.txt
index bf94264dea4..4765a0dd080 100644
--- a/mps/design/ss.txt
+++ b/mps/design/ss.txt
@@ -212,9 +212,6 @@ Return ``ResOK`` if successful, or another result code if not. See the
platform-specific implementation of ``StackContextScan()`` for the
exact registers which are scanned.
-_`.if.scan.bottom`: Note that the word pointed to by ``stackBot`` is
-not fixed.
-
``STACK_CONTEXT_SAVE(StackContext sc)``
_`.if.save`: Store the mutator context in the structure ``sc``.
From fdc3ceb3f68dea373fed117c55a72fb1ac9380fb Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 31 Oct 2014 15:28:33 +0000
Subject: [PATCH 036/759] Stack context is saved by stack_context_save, not
just by stack_context_begin.
Copied from Perforce
Change: 187430
ServerID: perforce.ravenbrook.com
---
mps/code/ss.h | 10 +++++-----
mps/code/ssan.c | 4 ++--
mps/code/ssw3i3mv.c | 2 +-
mps/code/ssw3i3pc.c | 2 +-
mps/code/ssw3i6mv.c | 2 +-
mps/code/ssw3i6pc.c | 2 +-
mps/code/ssxci3.c | 2 +-
mps/code/ssxci6.c | 2 +-
8 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/mps/code/ss.h b/mps/code/ss.h
index 0036f50886f..87cbf85e539 100644
--- a/mps/code/ss.h
+++ b/mps/code/ss.h
@@ -44,7 +44,7 @@ typedef struct StackContextStruct {
/* StackContextStackTop -- return the "top" of the mutator's stack at
- * the point when the context was saved by STACK_CONTEXT_BEGIN. */
+ * the point when the context was saved by STACK_CONTEXT_SAVE. */
extern Addr *StackContextStackTop(StackContext sc);
@@ -63,15 +63,15 @@ extern Res StackContextScan(ScanState ss, StackContext sc);
* See _setjmp(2). */
#define STACK_CONTEXT_SAVE(sc) BEGIN \
- int _set = _setjmp((sc)->jumpBuffer); \
- AVER(_set == 0); \
+ int _rc = _setjmp((sc)->jumpBuffer); \
+ AVER(_rc == 0); \
END
#else /* other platforms */
#define STACK_CONTEXT_SAVE(sc) BEGIN \
- int _set = setjmp((sc)->jumpBuffer); \
- AVER(_set == 0); \
+ int _rc = setjmp((sc)->jumpBuffer); \
+ AVER(_rc == 0); \
END
#endif /* platform defines */
diff --git a/mps/code/ssan.c b/mps/code/ssan.c
index 8f5fa47934b..00299a9d632 100644
--- a/mps/code/ssan.c
+++ b/mps/code/ssan.c
@@ -14,12 +14,12 @@ SRCID(ssan, "$Id$");
/* StackContextStackTop -- return the "top" of the mutator's stack at
- * the point when the context was saved by STACK_CONTEXT_BEGIN.
+ * the point when the context was saved by STACK_CONTEXT_SAVE.
*
* .assume: This assumes that the structure pointed to by sc is
* stack-allocated "above" the mutator's stack, and so its address is
* a conservative approximation to the top of the mutator's stack. The
- * use of STACK_CONTEXT_BEGIN in mpsi.c assures this.
+ * use of STACK_CONTEXT_SAVE in mpsi.c assures this.
*/
Addr *StackContextStackTop(StackContext sc)
diff --git a/mps/code/ssw3i3mv.c b/mps/code/ssw3i3mv.c
index 6cf6525da9d..218af5da8f5 100644
--- a/mps/code/ssw3i3mv.c
+++ b/mps/code/ssw3i3mv.c
@@ -26,7 +26,7 @@ SRCID(ssw3i3mv, "$Id$");
/* StackContextStackTop -- return the "top" of the mutator's stack at
- * the point when the context was saved by STACK_CONTEXT_BEGIN. */
+ * the point when the context was saved by STACK_CONTEXT_SAVE. */
Addr *StackContextStackTop(StackContext sc)
{
diff --git a/mps/code/ssw3i3pc.c b/mps/code/ssw3i3pc.c
index 9b5b6a46464..6f04b286b4c 100644
--- a/mps/code/ssw3i3pc.c
+++ b/mps/code/ssw3i3pc.c
@@ -51,7 +51,7 @@ typedef struct __JUMP_BUFFER {
/* StackContextStackTop -- return the "top" of the mutator's stack at
- * the point when the context was saved by STACK_CONTEXT_BEGIN. */
+ * the point when the context was saved by STACK_CONTEXT_SAVE. */
Addr *StackContextStackTop(StackContext sc)
{
diff --git a/mps/code/ssw3i6mv.c b/mps/code/ssw3i6mv.c
index bfc5793d5ab..0d45f86eded 100644
--- a/mps/code/ssw3i6mv.c
+++ b/mps/code/ssw3i6mv.c
@@ -33,7 +33,7 @@ SRCID(ssw3i6mv, "$Id$");
/* StackContextStackTop -- return the "top" of the mutator's stack at
- * the point when the context was saved by STACK_CONTEXT_BEGIN. */
+ * the point when the context was saved by STACK_CONTEXT_SAVE. */
Addr *StackContextStackTop(StackContext sc)
{
diff --git a/mps/code/ssw3i6pc.c b/mps/code/ssw3i6pc.c
index adbc1a68aa0..a5342431b12 100644
--- a/mps/code/ssw3i6pc.c
+++ b/mps/code/ssw3i6pc.c
@@ -73,7 +73,7 @@ typedef struct _JUMP_BUFFER {
/* StackContextStackTop -- return the "top" of the mutator's stack at
- * the point when the context was saved by STACK_CONTEXT_BEGIN. */
+ * the point when the context was saved by STACK_CONTEXT_SAVE. */
Addr *StackContextStackTop(StackContext sc)
{
diff --git a/mps/code/ssxci3.c b/mps/code/ssxci3.c
index a5893f31f8c..21e6db80156 100644
--- a/mps/code/ssxci3.c
+++ b/mps/code/ssxci3.c
@@ -24,7 +24,7 @@ SRCID(ssxci3, "$Id$");
/* StackContextStackTop -- return the "top" of the mutator's stack at
- * the point when the context was saved by STACK_CONTEXT_BEGIN. */
+ * the point when the context was saved by STACK_CONTEXT_SAVE. */
Addr *StackContextStackTop(StackContext sc)
{
diff --git a/mps/code/ssxci6.c b/mps/code/ssxci6.c
index 1deb5c8153f..c8caf51baa7 100644
--- a/mps/code/ssxci6.c
+++ b/mps/code/ssxci6.c
@@ -24,7 +24,7 @@ SRCID(ssxci6, "$Id$");
/* StackContextStackTop -- return the "top" of the mutator's stack at
- * the point when the context was saved by STACK_CONTEXT_BEGIN. */
+ * the point when the context was saved by STACK_CONTEXT_SAVE. */
Addr *StackContextStackTop(StackContext sc)
{
From 161659fc80db922bdc8cb7bb3304634b14a8c77d Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 31 Oct 2014 15:34:11 +0000
Subject: [PATCH 037/759] Make sure we satisfy design.mps.sc.req.setjmp!
Improve organization of design.
Copied from Perforce
Change: 187434
ServerID: perforce.ravenbrook.com
---
mps/code/ss.h | 10 ++--------
mps/design/ss.txt | 14 +++++++-------
2 files changed, 9 insertions(+), 15 deletions(-)
diff --git a/mps/code/ss.h b/mps/code/ss.h
index 87cbf85e539..2eca1104d45 100644
--- a/mps/code/ss.h
+++ b/mps/code/ss.h
@@ -62,17 +62,11 @@ extern Res StackContextScan(ScanState ss, StackContext sc);
* register set and the stack while setjmp also saves the signal mask.
* See _setjmp(2). */
-#define STACK_CONTEXT_SAVE(sc) BEGIN \
- int _rc = _setjmp((sc)->jumpBuffer); \
- AVER(_rc == 0); \
- END
+#define STACK_CONTEXT_SAVE(sc) ((void)_setjmp((sc)->jumpBuffer))
#else /* other platforms */
-#define STACK_CONTEXT_SAVE(sc) BEGIN \
- int _rc = setjmp((sc)->jumpBuffer); \
- AVER(_rc == 0); \
- END
+#define STACK_CONTEXT_SAVE(sc) ((void)setjmp((sc)->jumpBuffer))
#endif /* platform defines */
diff --git a/mps/design/ss.txt b/mps/design/ss.txt
index 4765a0dd080..b9f5dcae4d9 100644
--- a/mps/design/ss.txt
+++ b/mps/design/ss.txt
@@ -30,6 +30,11 @@ design.mps.thread-manager.if.scan_.
.. _design.mps.thread-manager.if.scan: thread-manager#if.scan
+_`.origin`: This design was originally proposed in
+mail.richard.2012-08-03.14-36_.
+
+.. _mail.richard.2012-08-03.14-36: https://info.ravenbrook.com/mail/2012/08/03/14-36-35/0/
+
Requirements
------------
@@ -38,8 +43,6 @@ _`.req.stack.top`: Must locate the top of the mutator's stack. (This
is needed for conservative garbage collection of uncooperative code,
where references might be stored by mutator on its stack, to work.)
-.. _job003525: http://www.ravenbrook.com/project/mps/issue/job003525/
-
_`.req.stack.bottom.not`: There is no requirement to locate the bottom
of the stack. (The mutator supplies this as an argument to
``mps_root_create_reg()``.)
@@ -55,6 +58,8 @@ at the point where it enters the MPS. (This avoids scanning registers
and stack that belong to the MPS rather than the mutator, leading to
unnecessary pinning and zone pollution; see job003525_.)
+.. _job003525: http://www.ravenbrook.com/project/mps/issue/job003525/
+
_`.req.setjmp`: The implementation must follow the C Standard in its
use of the ``setjmp`` macro. (So that it is reliable and portable.)
@@ -66,11 +71,6 @@ that don't support this.)
Design
------
-_`.origin`: The design was originally proposed in
-mail.richard.2012-08-03.14-36_.
-
-.. _mail.richard.2012-08-03.14-36: https://info.ravenbrook.com/mail/2012/08/03/14-36-35/0/
-
_`.sol.entry-points`: To meet `.req.stack.entry`_, the mutator's
registers and stack must be recorded when the mutator enters the MPS.
From 316fa21d88393c17167af6c66268282bc0d78eb2 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 31 Oct 2014 21:42:06 +0000
Subject: [PATCH 038/759] Update xcode project to include added files
(ssxci3.c, ssxci6.c) and excluded deleted files (sc.h).
Copied from Perforce
Change: 187441
ServerID: perforce.ravenbrook.com
---
mps/code/mps.xcodeproj/project.pbxproj | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj
index c83a1026d6e..1a06b811a6e 100644
--- a/mps/code/mps.xcodeproj/project.pbxproj
+++ b/mps/code/mps.xcodeproj/project.pbxproj
@@ -1453,6 +1453,8 @@
22FACEDE18880933000FDBC1 /* pooln.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pooln.c; sourceTree = ""; };
22FACEDF18880933000FDBC1 /* pooln.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pooln.h; sourceTree = ""; };
22FACEED18880983000FDBC1 /* airtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = airtest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 22FAF76C1A04394B006660FD /* ssxci3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ssxci3.c; sourceTree = ""; };
+ 22FAF76D1A04394B006660FD /* ssxci6.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ssxci6.c; sourceTree = ""; };
2D07B96C1636FC7200DB751B /* eventsql.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = eventsql.c; sourceTree = ""; };
2D07B9711636FC9900DB751B /* mpseventsql */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mpseventsql; sourceTree = BUILT_PRODUCTS_DIR; };
2D07B97B163705E400DB751B /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
@@ -1610,7 +1612,6 @@
311F2F7217398B7100C15B6A /* pthrdext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pthrdext.h; sourceTree = ""; };
311F2F7317398B7100C15B6A /* ring.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ring.h; sourceTree = ""; };
311F2F7417398B7100C15B6A /* sac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sac.h; sourceTree = ""; };
- 311F2F7517398B8E00C15B6A /* sc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sc.h; sourceTree = ""; };
311F2F7617398B8E00C15B6A /* splay.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = splay.h; sourceTree = ""; };
311F2F7717398B8E00C15B6A /* ss.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ss.h; sourceTree = ""; };
311F2F7817398B8E00C15B6A /* th.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = th.h; sourceTree = ""; };
@@ -2442,13 +2443,14 @@
3112ED3A18ABC57F00CC531A /* sa.h */,
31EEAC31156AB2F200714D05 /* sac.c */,
311F2F7417398B7100C15B6A /* sac.h */,
- 311F2F7517398B8E00C15B6A /* sc.h */,
31EEAC1D156AB2B200714D05 /* seg.c */,
31EEAC32156AB2F200714D05 /* shield.c */,
31EEAC43156AB32500714D05 /* splay.c */,
311F2F7617398B8E00C15B6A /* splay.h */,
22FACEDA1888088A000FDBC1 /* ss.c */,
311F2F7717398B8E00C15B6A /* ss.h */,
+ 22FAF76C1A04394B006660FD /* ssxci3.c */,
+ 22FAF76D1A04394B006660FD /* ssxci6.c */,
311F2F7817398B8E00C15B6A /* th.h */,
311F2F7917398B8E00C15B6A /* thw3.h */,
31EEAC1E156AB2B200714D05 /* trace.c */,
From 085310c68b8ff87aa396e3d3f86bced36a41215e Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sat, 1 Nov 2014 11:07:55 +0000
Subject: [PATCH 039/759] Documentation improvements after review.
Copied from Perforce
Change: 187447
ServerID: perforce.ravenbrook.com
---
mps/code/sncss.c | 2 +-
mps/code/walkt0.c | 2 +-
mps/design/alloc-frame.txt | 6 +++---
mps/manual/source/release.rst | 5 +++--
4 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/mps/code/sncss.c b/mps/code/sncss.c
index e6f62e30911..e77e3fd2cd5 100644
--- a/mps/code/sncss.c
+++ b/mps/code/sncss.c
@@ -1,4 +1,4 @@
-/* framess.c: ALLOCATION FRAME STRESS TEST
+/* sncss.c: SNC STRESS TEST
*
* $Id$
* Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
diff --git a/mps/code/walkt0.c b/mps/code/walkt0.c
index 332202bfd86..3c0ef5d5c25 100644
--- a/mps/code/walkt0.c
+++ b/mps/code/walkt0.c
@@ -91,7 +91,7 @@ static mps_addr_t make(void)
* pool
* fmt
*
- * .. 3: accumulating the count and size of objects found
+ * ...3: accumulating the count and size of objects found
*/
struct stepper_data {
mps_arena_t arena;
diff --git a/mps/design/alloc-frame.txt b/mps/design/alloc-frame.txt
index 2275c09746d..ac6b41ea158 100644
--- a/mps/design/alloc-frame.txt
+++ b/mps/design/alloc-frame.txt
@@ -200,7 +200,7 @@ 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 *FrameHasAddr()* 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.
@@ -251,7 +251,7 @@ 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
-*FrameHasAddr()* operation.
+*FrameHasAddr* operation.
``mps_res_t mps_ap_set_frame_class(mps_ap_t buf, mps_frame_class_t class)``
@@ -298,7 +298,7 @@ _`.fn.select-addr`: A pool method of this type is called to invoke the
``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
-*FrameHasAddr()* operation.
+*FrameHasAddr* operation.
``typedef Res (*PoolSetFrameClassMethod)(Pool pool, Buffer buf, AllocFrameClass class)``
diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst
index 3f4271e14a3..349af09b3f0 100644
--- a/mps/manual/source/release.rst
+++ b/mps/manual/source/release.rst
@@ -23,8 +23,9 @@ Interface changes
Other changes
.............
-#. Objects in :ref:`pool-snc` pools now die immediately when their
- :term:`allocation frame` is popped. See job003883_.
+#. 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/
From d701aaab914e87b8f775b83757c004814441d925 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 6 Nov 2014 22:53:52 +0000
Subject: [PATCH 040/759] Allocation points no longer have private fields.
Copied from Perforce
Change: 187478
ServerID: perforce.ravenbrook.com
---
mps/manual/source/topic/allocation.rst | 1 -
1 file changed, 1 deletion(-)
diff --git a/mps/manual/source/topic/allocation.rst b/mps/manual/source/topic/allocation.rst
index 41c59190690..62575e0f36a 100644
--- a/mps/manual/source/topic/allocation.rst
+++ b/mps/manual/source/topic/allocation.rst
@@ -659,7 +659,6 @@ branch prediction should work well since the test almost 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.
From ac8f9c6fb9e07c77f2a97bad82261fd5acce3fb3 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 5 Feb 2015 23:07:35 +0000
Subject: [PATCH 041/759] Now that all the private members of mps_ap_s are
gone, there are no more "derived types" in the mps interface.
Copied from Perforce
Change: 187680
ServerID: perforce.ravenbrook.com
---
mps/manual/source/glossary/d.rst | 10 ----------
mps/manual/source/glossary/index.rst | 1 -
mps/manual/source/glossary/o.rst | 2 +-
mps/manual/source/glossary/t.rst | 2 +-
mps/manual/source/topic/interface.rst | 11 ++---------
5 files changed, 4 insertions(+), 22 deletions(-)
diff --git a/mps/manual/source/glossary/d.rst b/mps/manual/source/glossary/d.rst
index 80d41072bbc..95abb12cfd3 100644
--- a/mps/manual/source/glossary/d.rst
+++ b/mps/manual/source/glossary/d.rst
@@ -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
diff --git a/mps/manual/source/glossary/index.rst b/mps/manual/source/glossary/index.rst
index a0484b3c5ee..758b5ba0db7 100644
--- a/mps/manual/source/glossary/index.rst
+++ b/mps/manual/source/glossary/index.rst
@@ -168,7 +168,6 @@ All
:term:`deferred reference counting`
:term:`dependent object`
:term:`derived pointer `
-:term:`derived type`
:term:`destructor (1)`
:term:`destructor (2)`
:term:`DGC `
diff --git a/mps/manual/source/glossary/o.rst b/mps/manual/source/glossary/o.rst
index 6a22abfed26..c58f9bf32c6 100644
--- a/mps/manual/source/glossary/o.rst
+++ b/mps/manual/source/glossary/o.rst
@@ -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
diff --git a/mps/manual/source/glossary/t.rst b/mps/manual/source/glossary/t.rst
index a91b656d89f..5b0d274e535 100644
--- a/mps/manual/source/glossary/t.rst
+++ b/mps/manual/source/glossary/t.rst
@@ -257,7 +257,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
diff --git a/mps/manual/source/topic/interface.rst b/mps/manual/source/topic/interface.rst
index 54637557f60..5122a760c4a 100644
--- a/mps/manual/source/topic/interface.rst
+++ b/mps/manual/source/topic/interface.rst
@@ -111,8 +111,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
@@ -134,13 +134,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
From 3459d9db48871e39b62bd358efa8b62614966f68 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 10 Aug 2015 17:22:31 +0100
Subject: [PATCH 042/759] Address review comments from rb in
Copied from Perforce
Change: 188112
ServerID: perforce.ravenbrook.com
---
mps/code/ss.c | 17 +++++++-----
mps/code/ss.h | 16 ++++++++---
mps/design/ss.txt | 71 ++++++++++++++++++++++++++++++++---------------
3 files changed, 71 insertions(+), 33 deletions(-)
diff --git a/mps/code/ss.c b/mps/code/ss.c
index efdad8eda34..c3f61d2d1c4 100644
--- a/mps/code/ss.c
+++ b/mps/code/ss.c
@@ -8,12 +8,15 @@
*
* This is a generic implementation, but it makes assumptions that,
* while true on all the platforms we currently (version 1.115)
- * support, may not be true on all platforms.
+ * support, may not be true on all platforms. See
+ * .
*
- * .assume.down: The stack grows downwards.
+ * .assume.desc: The stack is descending (and so stackTop is a lower
+ * address than stackBot).
*
- * .assume.bottom: There is no need to scan the word pointed to by
- * stackBot.
+ * .assume.empty: The stack convention is "full" (and so we must scan
+ * the word pointed to by stackTop but not the word pointed to by
+ * stackBot).
*
* .assume.align: Addresses on the stack are aligned to sizeof(Addr).
*/
@@ -57,12 +60,12 @@ Res StackScan(ScanState ss, Addr *stackBot)
AVERT(ScanState, ss);
arena = ss->arena;
- /* See */
- AVER(arena->scAtArenaEnter);
+ AVER(arena->scAtArenaEnter != NULL);
if (arena->scAtArenaEnter) {
res = stackScanInner(arena, ss, stackBot, arena->scAtArenaEnter);
} else {
- /* Somehow missed saving the context at the entry point: do it now. */
+ /* Somehow missed saving the context at the entry point (see
+ * ): do it now. */
StackContextStruct sc;
STACK_CONTEXT_SAVE(&sc);
res = stackScanInner(arena, ss, stackBot, &sc);
diff --git a/mps/code/ss.h b/mps/code/ss.h
index 2eca1104d45..ad7ead0c751 100644
--- a/mps/code/ss.h
+++ b/mps/code/ss.h
@@ -38,6 +38,7 @@ typedef struct StackContextStruct {
/* STACK_CONTEXT_END -- clear context and leave arena */
#define STACK_CONTEXT_END(arena) END; \
+ AVER(arena->scAtArenaEnter != NULL); \
arena->scAtArenaEnter = NULL; \
ArenaLeave(arena); \
END
@@ -58,9 +59,12 @@ extern Res StackContextScan(ScanState ss, StackContext sc);
#if defined(MPS_OS_XC)
-/* We call _setjmp rather than setjmp because _setjmp saves only the
- * register set and the stack while setjmp also saves the signal mask.
- * See _setjmp(2). */
+/* We call _setjmp rather than setjmp because we can be confident what
+ * it does via the source code at
+ * ,
+ * and because _setjmp saves only the register set and the stack while
+ * setjmp also saves the signal mask, which we don't care about. See
+ * _setjmp(2). */
#define STACK_CONTEXT_SAVE(sc) ((void)_setjmp((sc)->jumpBuffer))
@@ -71,7 +75,11 @@ extern Res StackContextScan(ScanState ss, StackContext sc);
#endif /* platform defines */
-/* StackScan -- scan the mutator's stack and registers */
+/* StackScan -- scan the mutator's stack and registers
+ *
+ * This must be called between STACK_CONTEXT_BEGIN and
+ * STACK_CONTEXT_END.
+ */
extern Res StackScan(ScanState ss, Addr *stackBot);
diff --git a/mps/design/ss.txt b/mps/design/ss.txt
index b9f5dcae4d9..4786deff432 100644
--- a/mps/design/ss.txt
+++ b/mps/design/ss.txt
@@ -41,17 +41,30 @@ Requirements
_`.req.stack.top`: Must locate the top of the mutator's stack. (This
is needed for conservative garbage collection of uncooperative code,
-where references might be stored by mutator on its stack, to work.)
+where references might be stored by mutator on its stack.)
_`.req.stack.bottom.not`: There is no requirement to locate the bottom
of the stack. (The mutator supplies this as an argument to
``mps_root_create_reg()``.)
+_`.req.stack.platform`: Must implement the platform's stack
+conventions.
+
+_`.req.stack.platform.full-empty`: The implementation must take into
+account whether the stack is *full* (the stack pointer points to the
+last full location) or *empty* (the stack pointer points to the
+first empty location).
+
+_`.req.stack.platform.desc-asc`: The implementation must take into
+account whether the stack is *descending* (top of stack is at a lower
+address than bottom of stack) or *ascending* (top of stack is at a
+higher address than bottom of stack).
+
_`.req.registers`: Must locate and scan all references in the
mutator's *root registers*, the subset of registers which might
contain references that do not also appear on the stack. (This is
needed for conservative garbage collection of uncooperative code,
-where references might appear in registers, to work.)
+where references might appear in registers.)
_`.req.entry`: Should save the mutator's context (stack and registers)
at the point where it enters the MPS. (This avoids scanning registers
@@ -72,7 +85,9 @@ Design
------
_`.sol.entry-points`: To meet `.req.stack.entry`_, the mutator's
-registers and stack must be recorded when the mutator enters the MPS.
+registers and stack must be recorded when the mutator enters the MPS,
+if there is a possibility that the MPS might need to know the mutator
+context.
_`.sol.entry-points.fragile`: The analysis of which entry points might
need to save the context (see `.anal.entry-points`_ below) is fragile.
@@ -93,25 +108,34 @@ been spilled onto the stack by the time the MPS is entered, so will be
scanned by the stack scan. Floating-point registers and debugging
registers do not, as far as we are aware, contain pointers.
-_`.sol.setjmp`: The C standard specifies that ``jmp_buf``
-"is an array type suitable for holding the information needed to
-restore a calling environment. The environment of a call to the
-``setjmp`` macro consists of information sufficient for a call to the
-``longjmp`` function to return execution to the correct block and
-invocation of that block, were it called recursively." This is what we
-need: the jump buffer needs to include the root registers in order to
-work as described. (A sufficiently perverse implementation could
-defeat this, but it works on all our supported platforms.)
+_`.sol.setjmp`: The values in callee-save registers can be found by
+calling ``setjmp`` and scanning the ``jmp_buf``.
-_`.sol.setjmp.scan`: An implementation can decode the jump
-buffer and scan just the root registers, or it can conservatively scan
-the whole of the jump buffer.
+_`.sol.setjmp.scan`: An implementation can decode the jump buffer and
+scan just the root registers, or it can conservatively scan the whole
+of the jump buffer.
+
+_`.sol.setjmp.justify`: The C standard specifies that ``jmp_buf`` "is
+an array type suitable for holding the information needed to restore a
+calling environment. The environment of a call to the ``setjmp`` macro
+consists of information sufficient for a call to the ``longjmp``
+function to return execution to the correct block and invocation of
+that block, were it called recursively." We believe that any
+reasonable implementation of ``setjmp`` must copy the callee-save
+registers into the ``jmp_buf`` in order to work as described.
+Otherwise, once the callee-save registers have been overwritten by
+other function calls, a ``longjmp`` would result in the callee-save
+registers having the wrong values.
_`.sol.stack.top`: Similarly, an implementation can decode the jump
buffer and get the top of the mutator's stack from the stack pointer
register, or it can conservatively use the address of a local variable
in the entry point to the MPS.
+_`.sol.stack.platform`: As of version 1.115, all supported platforms
+are *full* and *descending* so the implementation in ``StackScan``
+assumes this. New platforms must check this assumption.
+
_`.sol.xc.alternative`: On OS X, we could use ``getcontext()`` from
libunwind (see here_), but that produces deprecation warnings and
introduces a dependency on that library.
@@ -176,9 +200,9 @@ sources at changelevel 187410) showing which entry points might call
│ └ArenaCollect
│ └mps_arena_collect
└TraceStartCollectAll
- ├ArenaStep ⤴
- ├ArenaStartCollect ⤴
- └TracePoll ⤴
+ ├ArenaStep [see above]
+ ├ArenaStartCollect [see above]
+ └TracePoll [see above]
So the entry points that need to save the stack context are
``mps_arena_step()``, ``mps_alloc()``, ``mps_ap_fill()``,
@@ -212,6 +236,8 @@ Return ``ResOK`` if successful, or another result code if not. See the
platform-specific implementation of ``StackContextScan()`` for the
exact registers which are scanned.
+_`.if.scan.begin-end`: This function must be called between ``STACK_CONTEXT_BEGIN()`` and ``STACK_CONTEXT_END()``.
+
``STACK_CONTEXT_SAVE(StackContext sc)``
_`.if.save`: Store the mutator context in the structure ``sc``.
@@ -227,8 +253,8 @@ violation of design.mps.config.no-spaghetti_.
``STACK_CONTEXT_BEGIN(Arena arena)``
-_`.if.begin`: Start an MPS operation that needs to know the mutator
-context. This macro must be used like this::
+_`.if.begin`: Start an MPS operation that may need to know the mutator
+context (see .sol.entry-points). This macro must be used like this::
Res res;
STACK_CONTEXT_BEGIN(arena) {
@@ -257,8 +283,9 @@ Implementations
_`.impl.an`: Generic implementation in ``ssan.c``. Since the C
standard does not specify where the callee-save registers appear in
-the jump buffer, the whole buffer must be scanned, and the top of the
-stack must be taken conservatively from a local variable.
+the jump buffer, the whole buffer must be scanned (see
+`.sol.setjmp.scan`_), and the top of the stack must be taken
+conservatively from a local variable.
_`.impl.w3`: Windows implementation in ``ssw3i3mv.c`` and
``ssw3i6mv.c``. We know the layout of the jump buffer used by the
From 76967eeb7a008a02d2ca0bf8dd156265b2d3f743 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 10 Aug 2015 20:01:37 +0100
Subject: [PATCH 043/759] Fix tags.
Copied from Perforce
Change: 188117
ServerID: perforce.ravenbrook.com
---
mps/code/ss.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/mps/code/ss.c b/mps/code/ss.c
index c3f61d2d1c4..61b7af4f204 100644
--- a/mps/code/ss.c
+++ b/mps/code/ss.c
@@ -14,7 +14,7 @@
* .assume.desc: The stack is descending (and so stackTop is a lower
* address than stackBot).
*
- * .assume.empty: The stack convention is "full" (and so we must scan
+ * .assume.full: The stack convention is "full" (and so we must scan
* the word pointed to by stackTop but not the word pointed to by
* stackBot).
*
@@ -38,10 +38,10 @@ static Res stackScanInner(Arena arena, ScanState ss, Addr *stackBot,
AVERT(ScanState, ss);
stackTop = StackContextStackTop(sc);
- AVER(stackTop < stackBot); /* .assume.down */
+ AVER(stackTop < stackBot); /* .assume.desc */
AVER(AddrIsAligned((Addr)stackTop, sizeof(Addr))); /* .assume.align */
- res = TraceScanAreaTagged(ss, stackTop, stackBot); /* .assume.bottom */
+ res = TraceScanAreaTagged(ss, stackTop, stackBot); /* .assume.full */
if (res != ResOK)
return res;
From d2213f7986122f05a95093672c300d81b9e840d8 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 11 Aug 2015 08:22:33 +0100
Subject: [PATCH 044/759] Explain which registers are callee-save, with
references. fix some minor errors in comments and design.
Copied from Perforce
Change: 188121
ServerID: perforce.ravenbrook.com
---
mps/code/ssw3i3mv.c | 4 ++--
mps/code/ssw3i3pc.c | 4 ++--
mps/code/ssw3i6mv.c | 4 ++--
mps/code/ssw3i6pc.c | 4 ++--
mps/design/ss.txt | 46 ++++++++++++++++++++++++++++++++++++++-------
5 files changed, 47 insertions(+), 15 deletions(-)
diff --git a/mps/code/ssw3i3mv.c b/mps/code/ssw3i3mv.c
index 218af5da8f5..aff444d049b 100644
--- a/mps/code/ssw3i3mv.c
+++ b/mps/code/ssw3i3mv.c
@@ -12,8 +12,8 @@
* .
*
* "Calling conventions for different C++ compilers and operating systems";
- * Agner Fog; Copenhagen University College of Engineering; 2012-02-29;
- * .
+ * Agner Fog; Copenhagen University College of Engineering; 2014-08-07;
+ * .
*/
#include "mpm.h"
diff --git a/mps/code/ssw3i3pc.c b/mps/code/ssw3i3pc.c
index 6f04b286b4c..24d88b5c14f 100644
--- a/mps/code/ssw3i3pc.c
+++ b/mps/code/ssw3i3pc.c
@@ -18,8 +18,8 @@
* .
*
* "Calling conventions for different C++ compilers and operating systems";
- * Agner Fog; Copenhagen University College of Engineering; 2012-02-29;
- * .
+ * Agner Fog; Copenhagen University College of Engineering; 2014-08-07;
+ * .
*/
#include "mpm.h"
diff --git a/mps/code/ssw3i6mv.c b/mps/code/ssw3i6mv.c
index 0d45f86eded..a1d6962b595 100644
--- a/mps/code/ssw3i6mv.c
+++ b/mps/code/ssw3i6mv.c
@@ -18,8 +18,8 @@
* .
*
* "Calling conventions for different C++ compilers and operating systems";
- * Agner Fog; Copenhagen University College of Engineering; 2012-02-29;
- * .
+ * Agner Fog; Copenhagen University College of Engineering; 2014-08-07;
+ * .
*/
#include "mpm.h"
diff --git a/mps/code/ssw3i6pc.c b/mps/code/ssw3i6pc.c
index a5342431b12..f77bd806e1c 100644
--- a/mps/code/ssw3i6pc.c
+++ b/mps/code/ssw3i6pc.c
@@ -24,8 +24,8 @@
* .
*
* "Calling conventions for different C++ compilers and operating systems";
- * Agner Fog; Copenhagen University College of Engineering; 2012-02-29;
- * .
+ * Agner Fog; Copenhagen University College of Engineering; 2014-08-07;
+ * .
*/
#include "mpm.h"
diff --git a/mps/design/ss.txt b/mps/design/ss.txt
index 4786deff432..c78e11db1a7 100644
--- a/mps/design/ss.txt
+++ b/mps/design/ss.txt
@@ -230,13 +230,14 @@ actually the lowest stack address.
_`.if.scan`: Scan the stack of the current thread, between
``stackBot`` and the "top" of the mutator's stack that was recorded by
-``STACK_CONTEXT_BEGIN()`` when the arena was entered. Also scan any
+``STACK_CONTEXT_SAVE()`` when the arena was entered. Also scan any
roots which were in the mutator's callee-save registers at that point.
Return ``ResOK`` if successful, or another result code if not. See the
platform-specific implementation of ``StackContextScan()`` for the
exact registers which are scanned.
-_`.if.scan.begin-end`: This function must be called between ``STACK_CONTEXT_BEGIN()`` and ``STACK_CONTEXT_END()``.
+_`.if.scan.begin-end`: This function must be called between
+``STACK_CONTEXT_BEGIN()`` and ``STACK_CONTEXT_END()``.
``STACK_CONTEXT_SAVE(StackContext sc)``
@@ -247,7 +248,7 @@ needs to run in the stack frame of the entry point (if it runs in some
other function it does not necessarily get the mutator's registers).
This necessity to have the definition in scope in ``mpsi.c``, while
also having different definitions on different platforms, requires a
-violation of design.mps.config.no-spaghetti_.
+violation of design.mps.config.no-spaghetti_ in ss.h.
.. _design.mps.config.no-spaghetti: config#no-spaghetti
@@ -267,14 +268,14 @@ must be no ``return`` between the two macro invocations.
This macro takes the arena lock, stores the mutator context in a
``StackContext`` structure allocated on the stack, and sets
-``arena->stackAtArenaEnter`` to the address of the top of the
-mutator's stack.
+``arena->scAtArenaEnter`` to the address of this structure.
``STACK_CONTEXT_END(Arena arena)``
-_`.if.end`: Finish the MPS operation that was started by ``STACK_CONTEXT_BEGIN()``.
+_`.if.end`: Finish the MPS operation that was started by
+``STACK_CONTEXT_BEGIN()``.
-This macro sets ``arena->stackAtArenaEnter`` to ``NULL`` and releases
+This macro sets ``arena->scAtArenaEnter`` to ``NULL`` and releases
the arena lock.
@@ -292,10 +293,41 @@ _`.impl.w3`: Windows implementation in ``ssw3i3mv.c`` and
compiler, and so can scan exactly the subset of registers we need, and
decode the stack pointer from ESP (on IA-32) or RSP (on x86-64).
+_`.impl.w3.i3`: On Windows on IA-32, the callee-save registers are
+EBX, ESI, EDI, and EBP. See [Fog]_.
+
+_`.impl.w3.i6`: On Windows on x86-64, the callee-save registers are
+RBX, RBP, RDI, RSI, R12, R13, R14, and R15. See
+[x86_64_registers]_. In theory the lowest 128 bits of the vector
+registers XMM6 to XMM15 are also callee-save, but we assume that
+references do not appear in these registers.
+
_`.impl.xc`: OS X implementation in ``ssxci3.c`` and ``ssxci6.c``.
Scans the jump buffer conservatively as for `.impl.an`_, but decodes
the stack pointer from ESP (on IA-32) or RSP (on x86-64).
+_`.impl.xc.i3`: On OS X on IA-32, the callee-save registers are EBX,
+ESI, EDI and EBP. See [Fog]_.
+
+_`.impl.xc.i6`: On OS X on x86-64, the callee-save registers are RBX,
+RBP, R12, R13, R14, and R15. See [Fog]_.
+
+
+References
+----------
+
+.. [Fog]
+ "Calling conventions for different C++ compilers and operating systems";
+ Agner Fog;
+ Copenhagen University College of Engineering;
+ 2014-08-07;
+
+
+.. [x86_64_registers]
+ "Caller/Callee Saved Registers";
+ Microsoft Corporation;
+
+
Document History
----------------
From 9e293fa1f9013ea202eced6b0780eef126b7f240 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 11 Aug 2015 08:34:50 +0100
Subject: [PATCH 045/759] Fix typo.
Copied from Perforce
Change: 188122
ServerID: perforce.ravenbrook.com
---
mps/manual/source/release.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst
index 349af09b3f0..b17a2c4c023 100644
--- a/mps/manual/source/release.rst
+++ b/mps/manual/source/release.rst
@@ -16,7 +16,7 @@ Interface changes
name :c:type:`mps_class_t` is still available via a ``typedef``,
but is deprecated.
-#. The :ref:`pool-snc` pool class now implements the
+#. The :ref:`pool-snc` pool class now implements
:c:func:`mps_pool_total_size` and :c:func:`mps_pool_free_size`.
From 5f888f8087415b6eeae39dd2059d227f5bb804a9 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 11 Aug 2015 10:49:59 +0100
Subject: [PATCH 046/759] Branching master to branch/2015-08-11/compact.
Copied from Perforce
Change: 188128
ServerID: perforce.ravenbrook.com
From c7a49cf109cb80222cb468c3cacd068fca43a625 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 11 Aug 2015 12:03:45 +0100
Subject: [PATCH 047/759] New macro arenachunkring encapsulates getting the
chunk ring for an arena.
RingLength now returns Count, not Size.
New test case checks that chunks are added and removed from the arena as memory is allocated and freed.
Copied from Perforce
Change: 188133
ServerID: perforce.ravenbrook.com
---
mps/code/arena.c | 14 +++++-----
mps/code/gcbench.c | 3 +-
mps/code/mpm.h | 1 +
mps/code/ring.c | 8 +++---
mps/code/ring.h | 2 +-
mps/design/ring.txt | 2 +-
mps/test/function/232.c | 59 +++++++++++++++++++++++++++++++++++++++
mps/test/testsets/passing | 3 +-
8 files changed, 76 insertions(+), 16 deletions(-)
create mode 100644 mps/test/function/232.c
diff --git a/mps/code/arena.c b/mps/code/arena.c
index fee56d6378a..e4e7c5e1973 100644
--- a/mps/code/arena.c
+++ b/mps/code/arena.c
@@ -164,7 +164,7 @@ Bool ArenaCheck(Arena arena)
if (arena->primary != NULL) {
CHECKD(Chunk, arena->primary);
}
- CHECKD_NOSIG(Ring, &arena->chunkRing);
+ CHECKD_NOSIG(Ring, ArenaChunkRing(arena));
/* Can't use CHECKD_NOSIG because TreeEMPTY is NULL. */
CHECKL(TreeCheck(ArenaChunkTree(arena)));
/* TODO: check that the chunkRing and chunkTree have identical members */
@@ -225,7 +225,7 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args)
arena->zoned = zoned;
arena->primary = NULL;
- RingInit(&arena->chunkRing);
+ RingInit(ArenaChunkRing(arena));
arena->chunkTree = TreeEMPTY;
arena->chunkSerial = (Serial)0;
@@ -372,7 +372,7 @@ void ArenaFinish(Arena arena)
arena->sig = SigInvalid;
GlobalsFinish(ArenaGlobals(arena));
LocusFinish(arena);
- RingFinish(&arena->chunkRing);
+ RingFinish(ArenaChunkRing(arena));
AVER(ArenaChunkTree(arena) == TreeEMPTY);
}
@@ -587,7 +587,7 @@ Res ArenaDescribeTracts(Arena arena, mps_lib_FILE *stream, Count depth)
if (stream == NULL)
return ResFAIL;
- RING_FOR(node, &arena->chunkRing, next) {
+ RING_FOR(node, ArenaChunkRing(arena), next) {
Chunk chunk = RING_ELT(Chunk, arenaRing, node);
res = arenaDescribeTractsInChunk(chunk, stream, depth);
if (res != ResOK)
@@ -678,7 +678,7 @@ void ArenaChunkInsert(Arena arena, Chunk chunk) {
AVER(updatedTree);
TreeBalance(&updatedTree);
arena->chunkTree = updatedTree;
- RingAppend(&arena->chunkRing, &chunk->arenaRing);
+ RingAppend(ArenaChunkRing(arena), &chunk->arenaRing);
arena->reserved += ChunkReserved(chunk);
@@ -707,7 +707,7 @@ void ArenaChunkRemoved(Arena arena, Chunk chunk)
if (chunk == arena->primary) {
/* The primary chunk must be the last chunk to be removed. */
- AVER(RingIsSingle(&arena->chunkRing));
+ AVER(RingIsSingle(ArenaChunkRing(arena)));
AVER(arena->reserved == 0);
arena->primary = NULL;
}
@@ -762,7 +762,7 @@ static Res arenaAllocPage(Addr *baseReturn, Arena arena, Pool pool)
res = arenaAllocPageInChunk(baseReturn, arena->primary, pool);
if (res != ResOK) {
Ring node, next;
- RING_FOR(node, &arena->chunkRing, next) {
+ RING_FOR(node, ArenaChunkRing(arena), next) {
Chunk chunk = RING_ELT(Chunk, arenaRing, node);
if (chunk != arena->primary) {
res = arenaAllocPageInChunk(baseReturn, chunk, pool);
diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c
index 2ae97104930..7aa28eb4561 100644
--- a/mps/code/gcbench.c
+++ b/mps/code/gcbench.c
@@ -248,8 +248,7 @@ static void arena_setup(gcthread_fn_t fn,
} MPS_ARGS_END(args);
watch(fn, name);
mps_arena_park(arena);
- printf("%u chunks\n", (unsigned)TreeDebugCount(ArenaChunkTree(arena),
- ChunkCompare, ChunkKey));
+ printf("%u chunks\n", (unsigned)RingLength(ArenaChunkRing(arena)));
mps_pool_destroy(pool);
mps_fmt_destroy(format);
if (ngen > 0)
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index a5ac16b41a2..6f34cd4e020 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -528,6 +528,7 @@ extern Ring GlobalsRememberedSummaryRing(Globals);
#define ArenaGreyRing(arena, rank) (&(arena)->greyRing[rank])
#define ArenaPoolRing(arena) (&ArenaGlobals(arena)->poolRing)
#define ArenaChunkTree(arena) RVALUE((arena)->chunkTree)
+#define ArenaChunkRing(arena) RVALUE(&(arena)->chunkRing)
extern Bool ArenaGrainSizeCheck(Size size);
#define AddrArenaGrainUp(addr, arena) AddrAlignUp(addr, ArenaGrainSize(arena))
diff --git a/mps/code/ring.c b/mps/code/ring.c
index 2f4be5066f2..9ceeecfa232 100644
--- a/mps/code/ring.c
+++ b/mps/code/ring.c
@@ -65,14 +65,14 @@ Bool RingIsSingle(Ring ring)
* See
*/
-Size RingLength(Ring ring)
+Count RingLength(Ring ring)
{
- Size size = 0;
+ Count length = 0;
Ring node, next;
AVERT(Ring, ring);
RING_FOR(node, ring, next)
- ++ size;
- return size;
+ ++ length;
+ return length;
}
diff --git a/mps/code/ring.h b/mps/code/ring.h
index 9cb915f4bf4..c7d154dbe5c 100644
--- a/mps/code/ring.h
+++ b/mps/code/ring.h
@@ -30,7 +30,7 @@ typedef struct RingStruct { /* double-ended queue structure */
extern Bool RingCheck(Ring ring);
extern Bool RingCheckSingle(Ring ring);
extern Bool RingIsSingle(Ring ring);
-extern Size RingLength(Ring ring);
+extern Count RingLength(Ring ring);
/* .ring.init: See */
extern void (RingInit)(Ring ring);
diff --git a/mps/design/ring.txt b/mps/design/ring.txt
index c0f4d9adfd4..1935cd02b29 100644
--- a/mps/design/ring.txt
+++ b/mps/design/ring.txt
@@ -112,7 +112,7 @@ additionally checks that ``ring`` is a singleton (see
_`.is.single`: Return ``TRUE`` if ``ring`` is a singleton (see
`.def.singleton`_).
-``Size RingLength(Ring ring)``
+``Count RingLength(Ring ring)``
_`.length`: Return the number of elements in the ring, not counting
``ring`` itself. This therefore returns 0 for singleton rings, and for
diff --git a/mps/test/function/232.c b/mps/test/function/232.c
new file mode 100644
index 00000000000..398f1586dd9
--- /dev/null
+++ b/mps/test/function/232.c
@@ -0,0 +1,59 @@
+/*
+TEST_HEADER
+ id = $Id: //info.ravenbrook.com/project/mps/branch/2015-08-11/compact/test/function/229.c#1 $
+ summary = test arena extension and compaction
+ language = c
+ link = testlib.o
+ parameters = SIZE=1024*1024 ITERATIONS=100
+END_HEADER
+*/
+
+#include "mpm.h"
+#include "mpscmvff.h"
+#include "testlib.h"
+
+static void check_chunks(mps_arena_t arena, unsigned expected)
+{
+ unsigned chunks = (unsigned)RingLength(ArenaChunkRing((Arena)arena));
+ asserts(chunks == expected, "expected %u chunks, got %u", expected, chunks);
+}
+
+static void test(void)
+{
+ mps_arena_t arena;
+ mps_pool_t pool;
+ mps_addr_t block[ITERATIONS];
+ unsigned i;
+
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, SIZE);
+ die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create");
+ } MPS_ARGS_END(args);
+
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_SPARE, 0);
+ die(mps_pool_create_k(&pool, arena, mps_class_mvff(), args), "pool_create");
+ } MPS_ARGS_END(args);
+ check_chunks(arena, 1);
+
+ for (i = 0; i < ITERATIONS; ++i) {
+ die(mps_alloc(&block[i], pool, SIZE), "mps_alloc");
+ check_chunks(arena, i + 2);
+ }
+
+ for (i = ITERATIONS; i > 0; --i) {
+ mps_free(pool, block[i - 1], SIZE);
+ mps_arena_collect(arena); /* ensure ArenaCompact called via TraceReclaim */
+ check_chunks(arena, i);
+ }
+
+ mps_pool_destroy(pool);
+ mps_arena_destroy(arena);
+}
+
+int main(void)
+{
+ easy_tramp(test);
+ pass();
+ return 0;
+}
diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing
index fde2ca5de8d..b29ffc686cd 100644
--- a/mps/test/testsets/passing
+++ b/mps/test/testsets/passing
@@ -168,4 +168,5 @@ function/224.c
% 225 -- no such test
function/226.c
function/227.c
-function/229.c
\ No newline at end of file
+function/229.c
+function/232.c
From ed2c117138090aafad6c70f0a63ab4b42a670b8a Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 25 Aug 2015 19:28:43 +0100
Subject: [PATCH 048/759] Branching master to branch/2015-08-25/tradeoff.
Copied from Perforce
Change: 188173
ServerID: perforce.ravenbrook.com
From f1441b58d151ebb3960f328fa45ea9f7638e5185 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Wed, 2 Sep 2015 21:55:24 +0100
Subject: [PATCH 049/759] Don't start a trace unless there's work to do.
Copied from Perforce
Change: 188204
ServerID: perforce.ravenbrook.com
---
mps/code/mpm.h | 3 ++-
mps/code/policy.c | 2 +-
mps/code/trace.c | 31 +++++++++++++++++++++++++++----
mps/code/traceanc.c | 2 +-
mps/code/walk.c | 2 +-
5 files changed, 32 insertions(+), 8 deletions(-)
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index a5ca0a5c300..21eb9d9f5ea 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -393,7 +393,8 @@ extern Bool TraceIdCheck(TraceId id);
extern Bool TraceSetCheck(TraceSet ts);
extern Bool TraceCheck(Trace trace);
extern Res TraceCreate(Trace *traceReturn, Arena arena, int why);
-extern void TraceDestroy(Trace trace);
+extern void TraceDestroyInit(Trace trace);
+extern void TraceDestroyFinished(Trace trace);
extern Res TraceAddWhite(Trace trace, Seg seg);
extern Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet);
diff --git a/mps/code/policy.c b/mps/code/policy.c
index 64611a31d11..1052c67f2dc 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -258,7 +258,7 @@ Bool PolicyStartTrace(Trace *traceReturn, Arena arena)
return FALSE;
failCondemn:
- TraceDestroy(trace);
+ TraceDestroyInit(trace);
/* This is an unlikely case, but clear the emergency flag so the next attempt
starts normally. */
ArenaSetEmergency(arena, FALSE);
diff --git a/mps/code/trace.c b/mps/code/trace.c
index 005cee87fb2..2896d1af8cb 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -158,6 +158,7 @@ Bool TraceCheck(Trace trace)
/* Use trace->state to check more invariants. */
switch(trace->state) {
case TraceINIT:
+ CHECKL(!TraceSetIsMember(trace->arena->flippedTraces, trace));
/* @@@@ What can be checked here? */
break;
@@ -422,6 +423,9 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet)
} while (SegNext(&seg, arena, seg));
}
+ if (!haveWhiteSegs)
+ return ResFAIL;
+
EVENT3(TraceCondemnZones, trace, condemnedSet, trace->white);
/* The trace's white set must be a subset of the condemned set */
@@ -755,7 +759,22 @@ Res TraceCreate(Trace *traceReturn, Arena arena, int why)
}
-/* TraceDestroy -- destroy a trace object
+/* TraceDestroyInit -- destroy a trace object in state INIT */
+
+void TraceDestroyInit(Trace trace)
+{
+ AVERT(Trace, trace);
+ AVER(trace->state == TraceINIT);
+ AVER(trace->condemned == 0);
+
+ EVENT1(TraceDestroy, trace);
+
+ trace->sig = SigInvalid;
+ trace->arena->busyTraces = TraceSetDel(trace->arena->busyTraces, trace);
+}
+
+
+/* TraceDestroyFinished -- destroy a trace object in state FINISHED
*
* Finish and deallocate a Trace object, freeing up a TraceId.
*
@@ -764,7 +783,7 @@ Res TraceCreate(Trace *traceReturn, Arena arena, int why)
* etc. would need to be reset to black. This also means the error
* paths in this file don't work. @@@@ */
-void TraceDestroy(Trace trace)
+void TraceDestroyFinished(Trace trace)
{
AVERT(Trace, trace);
AVER(trace->state == TraceFINISHED);
@@ -1555,6 +1574,9 @@ static Res traceCondemnAll(Trace trace)
}
}
+ if (!haveWhiteSegs)
+ return ResFAIL;
+
/* Notify all the chains. */
RING_FOR(chainNode, &arena->chainRing, nextChainNode) {
Chain chain = RING_ELT(Chain, chainRing, chainNode);
@@ -1630,6 +1652,7 @@ Res TraceStart(Trace trace, double mortality, double finishingTime)
AVER(0.0 <= mortality);
AVER(mortality <= 1.0);
AVER(finishingTime >= 0.0);
+ AVER(trace->condemned > 0);
arena = trace->arena;
@@ -1794,7 +1817,7 @@ Res TraceStartCollectAll(Trace *traceReturn, Arena arena, int why)
if the assertion isn't hit, so drop through anyway. */
NOTREACHED;
failCondemn:
- TraceDestroy(trace);
+ TraceDestroyInit(trace);
/* We don't know how long it'll be before another collection. Make sure
the next one starts in normal mode. */
ArenaSetEmergency(arena, FALSE);
@@ -1841,7 +1864,7 @@ Size TracePoll(Globals globals)
&& (ArenaEmergency(arena) || traceWorkClock(trace) < pollEnd));
scannedSize = traceWorkClock(trace) - oldScannedSize;
if (trace->state == TraceFINISHED) {
- TraceDestroy(trace);
+ TraceDestroyFinished(trace);
/* A trace finished, and hopefully reclaimed some memory, so clear any
* emergency. */
ArenaSetEmergency(arena, FALSE);
diff --git a/mps/code/traceanc.c b/mps/code/traceanc.c
index c57500c0b65..aef049ab230 100644
--- a/mps/code/traceanc.c
+++ b/mps/code/traceanc.c
@@ -583,7 +583,7 @@ void ArenaPark(Globals globals)
TRACE_SET_ITER(ti, trace, arena->busyTraces, arena)
TraceAdvance(trace);
if(trace->state == TraceFINISHED) {
- TraceDestroy(trace);
+ TraceDestroyFinished(trace);
}
TRACE_SET_ITER_END(ti, trace, arena->busyTraces, arena);
}
diff --git a/mps/code/walk.c b/mps/code/walk.c
index 38278cce1ad..e4542359469 100644
--- a/mps/code/walk.c
+++ b/mps/code/walk.c
@@ -359,7 +359,7 @@ static Res ArenaRootsWalk(Globals arenaGlobals, mps_roots_stepper_t f,
rootsStepClosureFinish(rsc);
/* Make this trace look like any other finished trace. */
trace->state = TraceFINISHED;
- TraceDestroy(trace);
+ TraceDestroyFinished(trace);
AVER(!ArenaEmergency(arena)); /* There was no allocation. */
return res;
From 2979b99c64e884754baad8eddea152746023aa13 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 10:12:18 +0100
Subject: [PATCH 050/759] Aver that results of arenaavail, arenacollectable and
arenascannable are non-negative.
Copied from Perforce
Change: 188207
ServerID: perforce.ravenbrook.com
---
mps/code/arena.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/mps/code/arena.c b/mps/code/arena.c
index 084a223f4a4..9dbcb2ebfc3 100644
--- a/mps/code/arena.c
+++ b/mps/code/arena.c
@@ -1335,6 +1335,7 @@ Size ArenaAvail(Arena arena)
this information from the operating system. It also depends on the
arena class, of course. */
+ AVER(sSwap >= arena->committed);
return sSwap - arena->committed + arena->spareCommitted;
}
@@ -1344,7 +1345,7 @@ Size ArenaAvail(Arena arena)
Size ArenaCollectable(Arena arena)
{
/* Conservative estimate -- see job003929. */
- return ArenaCommitted(arena) - ArenaSpareCommitted(arena);
+ return ArenaScannable(arena);
}
@@ -1353,7 +1354,10 @@ Size ArenaCollectable(Arena arena)
Size ArenaScannable(Arena arena)
{
/* Conservative estimate -- see job003929. */
- return ArenaCommitted(arena) - ArenaSpareCommitted(arena);
+ Size committed = ArenaCommitted(arena);
+ Size spareCommitted = ArenaSpareCommitted(arena);
+ AVER(committed >= spareCommitted);
+ return committed - spareCommitted;
}
From 85595290d37ff9edce748517d5021202ac1fe982 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 11:50:28 +0100
Subject: [PATCH 051/759] Accumulate trace metrics in arenapark.
Copied from Perforce
Change: 188208
ServerID: perforce.ravenbrook.com
---
mps/code/global.c | 6 ++----
mps/code/mpm.h | 1 +
mps/code/trace.c | 20 +++++++++++++-------
mps/code/traceanc.c | 4 ++++
4 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/mps/code/global.c b/mps/code/global.c
index cd072951e87..d92d9b403a5 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -729,13 +729,12 @@ void (ArenaPoll)(Globals globals)
tracedSize = TracePoll(globals);
if (tracedSize > 0) {
quanta += 1;
- arena->tracedSize += tracedSize;
}
} while (PolicyPollAgain(arena, start, tracedSize));
/* Don't count time spent checking for work, if there was no work to do. */
if(quanta > 0) {
- arena->tracedTime += (ClockNow() - start) / (double) ClocksPerSec();
+ ArenaAccumulateTime(arena, start);
}
AVER(!PolicyPoll(arena));
@@ -817,12 +816,11 @@ Bool ArenaStep(Globals globals, double interval, double multiplier)
now = ClockNow();
if (scanned > 0) {
stepped = TRUE;
- arena->tracedSize += scanned;
}
} while ((scanned > 0) && (now < end));
if (stepped) {
- arena->tracedTime += (now - start) / (double) clocks_per_sec;
+ ArenaAccumulateTime(arena, start);
}
return stepped;
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index 21eb9d9f5ea..ba7e85f2f65 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -537,6 +537,7 @@ extern Bool ArenaGrainSizeCheck(Size size);
#define AddrIsArenaGrain(addr, arena) AddrIsAligned(addr, ArenaGrainSize(arena))
#define SizeArenaGrains(size, arena) SizeAlignUp(size, ArenaGrainSize(arena))
#define SizeIsArenaGrains(size, arena) SizeIsAligned(size, ArenaGrainSize(arena))
+#define ArenaAccumulateTime(arena, start) ((arena)->tracedTime += (ClockNow() - (start)) / (double) ClocksPerSec())
extern void ArenaEnterLock(Arena arena, Bool recursive);
extern void ArenaLeaveLock(Arena arena, Bool recursive);
diff --git a/mps/code/trace.c b/mps/code/trace.c
index 2896d1af8cb..9e7d880f2b6 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -1737,14 +1737,23 @@ Res TraceStart(Trace trace, double mortality, double finishingTime)
}
+/* traceWorkClock -- a measure of the work done for this trace
+ *
+ * .workclock: Segment and root scanning work is the regulator. */
+
+#define traceWorkClock(trace) ((trace)->segScanSize + (trace)->rootScanSize)
+
+
/* TraceAdvance -- progress a trace by one step */
void TraceAdvance(Trace trace)
{
Arena arena;
+ Size oldWork, newWork;
AVERT(Trace, trace);
arena = trace->arena;
+ oldWork = traceWorkClock(trace);
switch (trace->state) {
case TraceUNFLIPPED:
@@ -1773,6 +1782,10 @@ void TraceAdvance(Trace trace)
NOTREACHED;
break;
}
+
+ newWork = traceWorkClock(trace);
+ AVER(newWork >= oldWork);
+ arena->tracedSize += newWork - oldWork;
}
@@ -1825,13 +1838,6 @@ Res TraceStartCollectAll(Trace *traceReturn, Arena arena, int why)
}
-/* traceWorkClock -- a measure of the work done for this trace
- *
- * .workclock: Segment and root scanning work is the regulator. */
-
-#define traceWorkClock(trace) ((trace)->segScanSize + (trace)->rootScanSize)
-
-
/* TracePoll -- Check if there's any tracing work to be done
*
* Consider starting a trace if none is running; advance the running
diff --git a/mps/code/traceanc.c b/mps/code/traceanc.c
index aef049ab230..c3743b6dc29 100644
--- a/mps/code/traceanc.c
+++ b/mps/code/traceanc.c
@@ -572,11 +572,13 @@ void ArenaPark(Globals globals)
TraceId ti;
Trace trace;
Arena arena;
+ Clock start;
AVERT(Globals, globals);
arena = GlobalsArena(globals);
globals->clamped = TRUE;
+ start = ClockNow();
while(arena->busyTraces != TraceSetEMPTY) {
/* Advance all active traces. */
@@ -587,6 +589,8 @@ void ArenaPark(Globals globals)
}
TRACE_SET_ITER_END(ti, trace, arena->busyTraces, arena);
}
+
+ ArenaAccumulateTime(arena, start);
/* Clear any emergency flag so that the next collection starts normally.
Any traces that have been finished may have reclaimed memory. */
From 7c83105da92460a6e69ae3e80675ec4fc8655fcf Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 11:54:55 +0100
Subject: [PATCH 052/759] Accumulate scannedsize in mrg pool.
Copied from Perforce
Change: 188209
ServerID: perforce.ravenbrook.com
---
mps/code/poolmrg.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/mps/code/poolmrg.c b/mps/code/poolmrg.c
index f329b87f110..3bd3655a94c 100644
--- a/mps/code/poolmrg.c
+++ b/mps/code/poolmrg.c
@@ -620,6 +620,7 @@ static Res MRGRefSegScan(ScanState ss, MRGRefSeg refseg, MRG mrg)
MRGFinalize(arena, linkseg, i);
}
}
+ ss->scannedSize += sizeof *refPart;
}
}
} TRACE_SCAN_END(ss);
From 61bae42d439a1196acce9a87414317c02b8b7590 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 13:01:55 +0100
Subject: [PATCH 053/759] Introduce new type work representing a measure of
work done by the collector. use this systematically to make the code clearer.
Copied from Perforce
Change: 188210
ServerID: perforce.ravenbrook.com
---
mps/code/config.h | 5 +++--
mps/code/eventdef.h | 6 +++---
mps/code/global.c | 20 +++++++++---------
mps/code/mpm.h | 4 ++--
mps/code/mpmst.h | 4 ++--
mps/code/mpmtypes.h | 1 +
mps/code/policy.c | 11 +++++-----
mps/code/trace.c | 50 ++++++++++++++++++++++++---------------------
mps/design/type.txt | 9 ++++++++
9 files changed, 62 insertions(+), 48 deletions(-)
diff --git a/mps/code/config.h b/mps/code/config.h
index 1c1df84f751..cf39d861457 100644
--- a/mps/code/config.h
+++ b/mps/code/config.h
@@ -422,8 +422,9 @@
#define ARENA_MINIMUM_COLLECTABLE_SIZE ((Size)1000000)
/* ARENA_DEFAULT_COLLECTION_RATE is an estimate of the MPS's
- * collection rate (in bytes per second), for use in the case where
- * there isn't enough data to use a measured value. */
+ * collection rate (in work per second; see ), for
+ * use in the case where there isn't enough data to use a measured
+ * value. */
#define ARENA_DEFAULT_COLLECTION_RATE (25000000.0)
diff --git a/mps/code/eventdef.h b/mps/code/eventdef.h
index 081b45de7c2..225c21f5f65 100644
--- a/mps/code/eventdef.h
+++ b/mps/code/eventdef.h
@@ -36,7 +36,7 @@
*/
#define EVENT_VERSION_MAJOR ((unsigned)1)
-#define EVENT_VERSION_MEDIAN ((unsigned)4)
+#define EVENT_VERSION_MEDIAN ((unsigned)5)
#define EVENT_VERSION_MINOR ((unsigned)0)
@@ -447,7 +447,7 @@
PARAM(X, 1, W, condemned) \
PARAM(X, 2, W, notCondemned) \
PARAM(X, 3, W, foundation) \
- PARAM(X, 4, W, rate) \
+ PARAM(X, 4, W, quantumWork) \
PARAM(X, 5, D, mortality) \
PARAM(X, 6, D, finishingTime)
@@ -674,7 +674,7 @@
PARAM(X, 4, W, notCondemned) /* collectible but not condemned bytes */ \
PARAM(X, 5, W, foundation) /* foundation size */ \
PARAM(X, 6, W, white) /* white reference set */ \
- PARAM(X, 7, W, rate) /* segs to scan per increment */
+ PARAM(X, 7, W, quantumWork) /* work constituting a quantum */
#define EVENT_VMCompact_PARAMS(PARAM, X) \
PARAM(X, 0, W, vmem0) /* pre-collection reserved size */ \
diff --git a/mps/code/global.c b/mps/code/global.c
index d92d9b403a5..d15e5cd0da7 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -189,7 +189,7 @@ Bool GlobalsCheck(Globals arenaGlobals)
CHECKD_NOSIG(Ring, &arena->greyRing[rank]);
CHECKD_NOSIG(Ring, &arena->chainRing);
- CHECKL(arena->tracedSize >= 0.0);
+ CHECKL(arena->tracedWork >= 0.0);
CHECKL(arena->tracedTime >= 0.0);
/* no check for arena->lastWorldCollect (Clock) */
@@ -287,7 +287,7 @@ Res GlobalsInit(Globals arenaGlobals)
arena->finalPool = NULL;
arena->busyTraces = TraceSetEMPTY; /* */
arena->flippedTraces = TraceSetEMPTY; /* */
- arena->tracedSize = 0.0;
+ arena->tracedWork = 0.0;
arena->tracedTime = 0.0;
arena->lastWorldCollect = ClockNow();
arena->insideShield = FALSE; /* */
@@ -705,7 +705,7 @@ void (ArenaPoll)(Globals globals)
Arena arena;
Clock start;
Count quanta;
- Size tracedSize;
+ Work tracedWork;
AVERT(Globals, globals);
@@ -726,11 +726,11 @@ void (ArenaPoll)(Globals globals)
EVENT3(ArenaPoll, arena, start, 0);
do {
- tracedSize = TracePoll(globals);
- if (tracedSize > 0) {
+ tracedWork = TracePoll(globals);
+ if (tracedWork > 0) {
quanta += 1;
}
- } while (PolicyPollAgain(arena, start, tracedSize));
+ } while (PolicyPollAgain(arena, start, tracedWork));
/* Don't count time spent checking for work, if there was no work to do. */
if(quanta > 0) {
@@ -779,7 +779,7 @@ static Bool arenaShouldCollectWorld(Arena arena,
Bool ArenaStep(Globals globals, double interval, double multiplier)
{
- Size scanned;
+ Work work;
Bool stepped;
Clock start, end, now;
Clock clocks_per_sec;
@@ -812,12 +812,12 @@ Bool ArenaStep(Globals globals, double interval, double multiplier)
/* loop while there is work to do and time on the clock. */
do {
- scanned = TracePoll(globals);
+ work = TracePoll(globals);
now = ClockNow();
- if (scanned > 0) {
+ if (work > 0) {
stepped = TRUE;
}
- } while ((scanned > 0) && (now < end));
+ } while ((work > 0) && (now < end));
if (stepped) {
ArenaAccumulateTime(arena, start);
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index ba7e85f2f65..3e888ad28de 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -399,7 +399,7 @@ extern void TraceDestroyFinished(Trace trace);
extern Res TraceAddWhite(Trace trace, Seg seg);
extern Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet);
extern Res TraceStart(Trace trace, double mortality, double finishingTime);
-extern Size TracePoll(Globals globals);
+extern Work TracePoll(Globals globals);
extern Rank TraceRankForAccess(Arena arena, Seg seg);
extern void TraceSegAccess(Arena arena, Seg seg, AccessSet mode);
@@ -667,7 +667,7 @@ extern Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
extern Bool PolicyStartTrace(Trace *traceReturn, Arena arena);
extern double PolicyCollectionTime(Arena arena);
extern Bool PolicyPoll(Arena arena);
-extern Bool PolicyPollAgain(Arena arena, Clock start, Size tracedSize);
+extern Bool PolicyPollAgain(Arena arena, Clock start, Work tracedWork);
/* Locus interface */
diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h
index ac5c12c1498..86b6ec94890 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -486,7 +486,7 @@ typedef struct TraceStruct {
Size condemned; /* condemned bytes */
Size notCondemned; /* collectable but not condemned */
Size foundation; /* initial grey set size */
- Size rate; /* segs to scan per increment */
+ Work quantumWork; /* collection work constituting a quantum */
STATISTIC_DECL(Count greySegCount); /* number of grey segs */
STATISTIC_DECL(Count greySegMax); /* max number of grey segs */
STATISTIC_DECL(Count rootScanCount); /* number of roots scanned */
@@ -777,7 +777,7 @@ typedef struct mps_arena_s {
TraceMessage tMessage[TraceLIMIT]; /* */
/* policy fields */
- double tracedSize;
+ double tracedWork;
double tracedTime;
Clock lastWorldCollect;
diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h
index 3a494760cb6..c744fb41fb6 100644
--- a/mps/code/mpmtypes.h
+++ b/mps/code/mpmtypes.h
@@ -38,6 +38,7 @@ typedef Word Size; /* */
typedef Word Count; /* */
typedef Word Index; /* */
typedef Word Align; /* */
+typedef Word Work; /* */
typedef unsigned Shift; /* */
typedef unsigned Serial; /* */
typedef Addr Ref; /* */
diff --git a/mps/code/policy.c b/mps/code/policy.c
index 1052c67f2dc..ff570e4899b 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -280,9 +280,8 @@ double PolicyCollectionTime(Arena arena)
collectableSize = ArenaCollectable(arena);
/* The condition arena->tracedTime >= 1.0 ensures that the division
* can't overflow. */
- if (arena->tracedSize >= ARENA_MINIMUM_COLLECTABLE_SIZE
- && arena->tracedTime >= 1.0)
- collectionRate = arena->tracedSize / arena->tracedTime;
+ if (arena->tracedTime >= 1.0)
+ collectionRate = arena->tracedWork / arena->tracedTime;
else
collectionRate = ARENA_DEFAULT_COLLECTION_RATE;
collectionTime = collectableSize / collectionRate;
@@ -313,10 +312,10 @@ Bool PolicyPoll(Arena arena)
* should return to the mutator.
*
* start is the clock time when the MPS was entered.
- * tracedSize is the amount of work done by the last call to TracePoll.
+ * tracedWork is the amount of work done by the last call to TracePoll.
*/
-Bool PolicyPollAgain(Arena arena, Clock start, Size tracedSize)
+Bool PolicyPollAgain(Arena arena, Clock start, Work tracedWork)
{
Globals globals;
double nextPollThreshold;
@@ -325,7 +324,7 @@ Bool PolicyPollAgain(Arena arena, Clock start, Size tracedSize)
globals = ArenaGlobals(arena);
UNUSED(start);
- if (tracedSize == 0) {
+ if (tracedWork == 0) {
/* No work was done. Sleep until NOW + a bit. */
nextPollThreshold = globals->fillMutatorSize + ArenaPollALLOCTIME;
} else {
diff --git a/mps/code/trace.c b/mps/code/trace.c
index 9e7d880f2b6..d34d953bf40 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -109,7 +109,7 @@ void ScanStateInit(ScanState ss, TraceSet ts, Arena arena,
STATISTIC(ss->preservedInPlaceCount = (Count)0);
ss->preservedInPlaceSize = (Size)0; /* see .message.data */
STATISTIC(ss->copiedSize = (Size)0);
- ss->scannedSize = (Size)0; /* see .workclock */
+ ss->scannedSize = (Size)0; /* see .work */
ss->sig = ScanStateSig;
AVERT(ScanState, ss);
@@ -277,7 +277,7 @@ static void traceUpdateCounts(Trace trace, ScanState ss,
break;
}
case traceAccountingPhaseSegScan: {
- trace->segScanSize += ss->scannedSize; /* see .workclock */
+ trace->segScanSize += ss->scannedSize; /* see .work */
trace->segCopiedSize += ss->copiedSize;
STATISTIC(++trace->segScanCount);
break;
@@ -697,14 +697,14 @@ Res TraceCreate(Trace *traceReturn, Arena arena, int why)
trace->condemned = (Size)0; /* nothing condemned yet */
trace->notCondemned = (Size)0;
trace->foundation = (Size)0; /* nothing grey yet */
- trace->rate = (Size)0; /* no scanning to be done yet */
+ trace->quantumWork = (Work)0; /* no work done yet */
STATISTIC(trace->greySegCount = (Count)0);
STATISTIC(trace->greySegMax = (Count)0);
STATISTIC(trace->rootScanCount = (Count)0);
trace->rootScanSize = (Size)0;
trace->rootCopiedSize = (Size)0;
STATISTIC(trace->segScanCount = (Count)0);
- trace->segScanSize = (Size)0; /* see .workclock */
+ trace->segScanSize = (Size)0; /* see .work */
trace->segCopiedSize = (Size)0;
STATISTIC(trace->singleScanCount = (Count)0);
STATISTIC(trace->singleScanSize = (Size)0);
@@ -1713,8 +1713,10 @@ Res TraceStart(Trace trace, double mortality, double finishingTime)
/* integer, so try to make sure it fits. */
if(nPolls >= (double)LONG_MAX)
nPolls = (double)LONG_MAX;
- /* rate equals scanning work per number of polls available */
- trace->rate = (trace->foundation + sSurvivors) / (unsigned long)nPolls + 1;
+ /* One quantum of work equals scanning work divided by number of
+ * polls, plus one to ensure it's not zero. */
+ trace->quantumWork
+ = (trace->foundation + sSurvivors) / (unsigned long)nPolls + 1;
}
/* TODO: compute rate of scanning here. */
@@ -1722,11 +1724,11 @@ Res TraceStart(Trace trace, double mortality, double finishingTime)
EVENT8(TraceStart, trace, mortality, finishingTime,
trace->condemned, trace->notCondemned,
trace->foundation, trace->white,
- trace->rate);
+ trace->quantumWork);
STATISTIC_STAT(EVENT7(TraceStatCondemn, trace,
trace->condemned, trace->notCondemned,
- trace->foundation, trace->rate,
+ trace->foundation, trace->quantumWork,
mortality, finishingTime));
trace->state = TraceUNFLIPPED;
@@ -1737,11 +1739,11 @@ Res TraceStart(Trace trace, double mortality, double finishingTime)
}
-/* traceWorkClock -- a measure of the work done for this trace
+/* traceWork -- a measure of the work done for this trace
*
- * .workclock: Segment and root scanning work is the regulator. */
+ * .work: Segment and root scanning work is the measure. */
-#define traceWorkClock(trace) ((trace)->segScanSize + (trace)->rootScanSize)
+#define traceWork(trace) ((Work)((trace)->segScanSize + (trace)->rootScanSize))
/* TraceAdvance -- progress a trace by one step */
@@ -1749,11 +1751,11 @@ Res TraceStart(Trace trace, double mortality, double finishingTime)
void TraceAdvance(Trace trace)
{
Arena arena;
- Size oldWork, newWork;
+ Work oldWork, newWork;
AVERT(Trace, trace);
arena = trace->arena;
- oldWork = traceWorkClock(trace);
+ oldWork = traceWork(trace);
switch (trace->state) {
case TraceUNFLIPPED:
@@ -1783,9 +1785,9 @@ void TraceAdvance(Trace trace)
break;
}
- newWork = traceWorkClock(trace);
+ newWork = traceWork(trace);
AVER(newWork >= oldWork);
- arena->tracedSize += newWork - oldWork;
+ arena->tracedWork += newWork - oldWork;
}
@@ -1844,11 +1846,11 @@ Res TraceStartCollectAll(Trace *traceReturn, Arena arena, int why)
* trace (if any) by one quantum. Return a measure of the work done.
*/
-Size TracePoll(Globals globals)
+Work TracePoll(Globals globals)
{
Trace trace;
Arena arena;
- Size oldScannedSize, scannedSize, pollEnd;
+ Work oldWork, newWork, work, endWork;
AVERT(Globals, globals);
arena = GlobalsArena(globals);
@@ -1862,20 +1864,22 @@ Size TracePoll(Globals globals)
}
AVER(arena->busyTraces == TraceSetSingle(trace));
- oldScannedSize = traceWorkClock(trace);
- pollEnd = oldScannedSize + trace->rate;
+ oldWork = traceWork(trace);
+ endWork = oldWork + trace->quantumWork;
do {
TraceAdvance(trace);
} while (trace->state != TraceFINISHED
- && (ArenaEmergency(arena) || traceWorkClock(trace) < pollEnd));
- scannedSize = traceWorkClock(trace) - oldScannedSize;
+ && (ArenaEmergency(arena) || traceWork(trace) < endWork));
+ newWork = traceWork(trace);
+ AVER(newWork >= oldWork);
+ work = newWork - oldWork;
if (trace->state == TraceFINISHED) {
TraceDestroyFinished(trace);
/* A trace finished, and hopefully reclaimed some memory, so clear any
* emergency. */
ArenaSetEmergency(arena, FALSE);
}
- return scannedSize;
+ return work;
}
@@ -1913,7 +1917,7 @@ Res TraceDescribe(Trace trace, mps_lib_FILE *stream, Count depth)
" condemned $U\n", (WriteFU)trace->condemned,
" notCondemned $U\n", (WriteFU)trace->notCondemned,
" foundation $U\n", (WriteFU)trace->foundation,
- " rate $U\n", (WriteFU)trace->rate,
+ " quantumWork $U\n", (WriteFU)trace->quantumWork,
" rootScanSize $U\n", (WriteFU)trace->rootScanSize,
" rootCopiedSize $U\n", (WriteFU)trace->rootCopiedSize,
" segScanSize $U\n", (WriteFU)trace->segScanSize,
diff --git a/mps/design/type.txt b/mps/design/type.txt
index 25943f41a4b..dc3c3b8cf99 100644
--- a/mps/design/type.txt
+++ b/mps/design/type.txt
@@ -664,6 +664,15 @@ _`.word.ops`: ``WordIsAligned()``, ``WordAlignUp()``,
``WordAlignDown()`` and ``WordRoundUp()``.
+``typedef MPS_T_WORD Work``
+
+_`.work`: ``Work`` is an unsigned integral type representing
+accumulated work done by the collector.
+
+_`.work.impl`: Work is currently implemented as a count of bytes
+scanned by the collector.
+
+
``typedef Word ZoneSet``
_`.zoneset`: ``ZoneSet`` is a conservative approximation to a set of
From 68489eec1ecf51fa421e63b6cd5e420bda38e0c9 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 15:35:38 +0100
Subject: [PATCH 054/759] Move the clearing of the emergency flag down into
tracedestroy{init,finish}.
Copied from Perforce
Change: 188216
ServerID: perforce.ravenbrook.com
---
mps/code/policy.c | 3 ---
mps/code/trace.c | 15 +++++++--------
mps/code/traceanc.c | 7 +++----
3 files changed, 10 insertions(+), 15 deletions(-)
diff --git a/mps/code/policy.c b/mps/code/policy.c
index ff570e4899b..3cba467a2c7 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -259,9 +259,6 @@ Bool PolicyStartTrace(Trace *traceReturn, Arena arena)
failCondemn:
TraceDestroyInit(trace);
- /* This is an unlikely case, but clear the emergency flag so the next attempt
- starts normally. */
- ArenaSetEmergency(arena, FALSE);
failStart:
return FALSE;
}
diff --git a/mps/code/trace.c b/mps/code/trace.c
index d34d953bf40..5786c677a51 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -771,6 +771,9 @@ void TraceDestroyInit(Trace trace)
trace->sig = SigInvalid;
trace->arena->busyTraces = TraceSetDel(trace->arena->busyTraces, trace);
+
+ /* Clear the emergency flag so the next trace starts normally. */
+ ArenaSetEmergency(trace->arena, FALSE);
}
@@ -828,6 +831,9 @@ void TraceDestroyFinished(Trace trace)
trace->sig = SigInvalid;
trace->arena->busyTraces = TraceSetDel(trace->arena->busyTraces, trace);
trace->arena->flippedTraces = TraceSetDel(trace->arena->flippedTraces, trace);
+
+ /* Hopefully the trace reclaimed some memory, so clear any emergency. */
+ ArenaSetEmergency(trace->arena, FALSE);
}
@@ -1833,9 +1839,6 @@ Res TraceStartCollectAll(Trace *traceReturn, Arena arena, int why)
NOTREACHED;
failCondemn:
TraceDestroyInit(trace);
- /* We don't know how long it'll be before another collection. Make sure
- the next one starts in normal mode. */
- ArenaSetEmergency(arena, FALSE);
return res;
}
@@ -1873,12 +1876,8 @@ Work TracePoll(Globals globals)
newWork = traceWork(trace);
AVER(newWork >= oldWork);
work = newWork - oldWork;
- if (trace->state == TraceFINISHED) {
+ if (trace->state == TraceFINISHED)
TraceDestroyFinished(trace);
- /* A trace finished, and hopefully reclaimed some memory, so clear any
- * emergency. */
- ArenaSetEmergency(arena, FALSE);
- }
return work;
}
diff --git a/mps/code/traceanc.c b/mps/code/traceanc.c
index c3743b6dc29..e60f8ffcdb3 100644
--- a/mps/code/traceanc.c
+++ b/mps/code/traceanc.c
@@ -591,10 +591,9 @@ void ArenaPark(Globals globals)
}
ArenaAccumulateTime(arena, start);
-
- /* Clear any emergency flag so that the next collection starts normally.
- Any traces that have been finished may have reclaimed memory. */
- ArenaSetEmergency(arena, FALSE);
+
+ /* All traces have finished so there must not be an emergency. */
+ AVER(!ArenaEmergency(arena));
}
/* ArenaStartCollect -- start a collection of everything in the
From 1437590cb3f758ba32ea8bf3d6eb01c15982d682 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 15:39:39 +0100
Subject: [PATCH 055/759] Move the arenaemergency test up to policypollagain.
Copied from Perforce
Change: 188217
ServerID: perforce.ravenbrook.com
---
mps/code/policy.c | 2 +-
mps/code/trace.c | 3 +--
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/mps/code/policy.c b/mps/code/policy.c
index 3cba467a2c7..e3c09c8d6d7 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -333,7 +333,7 @@ Bool PolicyPollAgain(Arena arena, Clock start, Work tracedWork)
AVER(nextPollThreshold > globals->pollThreshold);
globals->pollThreshold = nextPollThreshold;
- return PolicyPoll(arena);
+ return ArenaEmergency(arena) || PolicyPoll(arena);
}
diff --git a/mps/code/trace.c b/mps/code/trace.c
index 5786c677a51..378b6bed9a1 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -1871,8 +1871,7 @@ Work TracePoll(Globals globals)
endWork = oldWork + trace->quantumWork;
do {
TraceAdvance(trace);
- } while (trace->state != TraceFINISHED
- && (ArenaEmergency(arena) || traceWork(trace) < endWork));
+ } while (trace->state != TraceFINISHED && traceWork(trace) < endWork);
newWork = traceWork(trace);
AVER(newWork >= oldWork);
work = newWork - oldWork;
From 0ff67113aedaac4dd4c6b46ec91a94077e0ec26e Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 15:51:37 +0100
Subject: [PATCH 056/759] Separate the values "more work to do?" and "amount of
work done" in tracepoll. previously, the code used "amount of work done > 0"
when it needed "more work to do?" but that's not right, because on the last
two calls to traceadvance, no "work" is done (because reclaim work is not
measured), but there may still be more work to do.
Copied from Perforce
Change: 188218
ServerID: perforce.ravenbrook.com
---
mps/code/eventdef.h | 2 +-
mps/code/global.c | 35 ++++++++++++++++-------------------
mps/code/mpm.h | 4 ++--
mps/code/policy.c | 10 +++++-----
mps/code/trace.c | 11 +++++++----
5 files changed, 31 insertions(+), 31 deletions(-)
diff --git a/mps/code/eventdef.h b/mps/code/eventdef.h
index 225c21f5f65..cb7b590274c 100644
--- a/mps/code/eventdef.h
+++ b/mps/code/eventdef.h
@@ -655,7 +655,7 @@
#define EVENT_ArenaPoll_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, start) \
- PARAM(X, 2, W, quanta)
+ PARAM(X, 2, B, workWasDone)
#define EVENT_ArenaSetEmergency_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
diff --git a/mps/code/global.c b/mps/code/global.c
index d15e5cd0da7..d9a5bf9c6c7 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -704,7 +704,7 @@ void (ArenaPoll)(Globals globals)
{
Arena arena;
Clock start;
- Count quanta;
+ Bool moreWork, workWasDone = FALSE;
Work tracedWork;
AVERT(Globals, globals);
@@ -721,25 +721,24 @@ void (ArenaPoll)(Globals globals)
/* fillMutatorSize has advanced; call TracePoll enough to catch up. */
start = ClockNow();
- quanta = 0;
- EVENT3(ArenaPoll, arena, start, 0);
+ EVENT3(ArenaPoll, arena, start, FALSE);
do {
- tracedWork = TracePoll(globals);
- if (tracedWork > 0) {
- quanta += 1;
+ moreWork = TracePoll(&tracedWork, globals);
+ if (moreWork) {
+ workWasDone = TRUE;
}
- } while (PolicyPollAgain(arena, start, tracedWork));
+ } while (PolicyPollAgain(arena, moreWork, tracedWork));
/* Don't count time spent checking for work, if there was no work to do. */
- if(quanta > 0) {
+ if (workWasDone) {
ArenaAccumulateTime(arena, start);
}
AVER(!PolicyPoll(arena));
- EVENT3(ArenaPoll, arena, start, quanta);
+ EVENT3(ArenaPoll, arena, start, BOOLOF(workWasDone));
globals->insidePoll = FALSE;
}
@@ -780,7 +779,7 @@ static Bool arenaShouldCollectWorld(Arena arena,
Bool ArenaStep(Globals globals, double interval, double multiplier)
{
Work work;
- Bool stepped;
+ Bool moreWork, workWasDone = FALSE;
Clock start, end, now;
Clock clocks_per_sec;
Arena arena;
@@ -796,8 +795,6 @@ Bool ArenaStep(Globals globals, double interval, double multiplier)
end = start + (Clock)(interval * clocks_per_sec);
AVER(end >= start);
- stepped = FALSE;
-
if (arenaShouldCollectWorld(arena, interval, multiplier,
start, clocks_per_sec))
{
@@ -806,24 +803,24 @@ Bool ArenaStep(Globals globals, double interval, double multiplier)
res = TraceStartCollectAll(&trace, arena, TraceStartWhyOPPORTUNISM);
if (res == ResOK) {
arena->lastWorldCollect = start;
- stepped = TRUE;
+ workWasDone = TRUE;
}
}
/* loop while there is work to do and time on the clock. */
do {
- work = TracePoll(globals);
+ moreWork = TracePoll(&work, globals);
now = ClockNow();
- if (work > 0) {
- stepped = TRUE;
+ if (moreWork) {
+ workWasDone = TRUE;
}
- } while ((work > 0) && (now < end));
+ } while (moreWork && now < end);
- if (stepped) {
+ if (workWasDone) {
ArenaAccumulateTime(arena, start);
}
- return stepped;
+ return workWasDone;
}
/* ArenaFinalize -- registers an object for finalization
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index 3e888ad28de..ad8620b800f 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -399,7 +399,7 @@ extern void TraceDestroyFinished(Trace trace);
extern Res TraceAddWhite(Trace trace, Seg seg);
extern Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet);
extern Res TraceStart(Trace trace, double mortality, double finishingTime);
-extern Work TracePoll(Globals globals);
+extern Bool TracePoll(Work *workReturn, Globals globals);
extern Rank TraceRankForAccess(Arena arena, Seg seg);
extern void TraceSegAccess(Arena arena, Seg seg, AccessSet mode);
@@ -667,7 +667,7 @@ extern Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
extern Bool PolicyStartTrace(Trace *traceReturn, Arena arena);
extern double PolicyCollectionTime(Arena arena);
extern Bool PolicyPoll(Arena arena);
-extern Bool PolicyPollAgain(Arena arena, Clock start, Work tracedWork);
+extern Bool PolicyPollAgain(Arena arena, Bool moreWork, Work tracedWork);
/* Locus interface */
diff --git a/mps/code/policy.c b/mps/code/policy.c
index e3c09c8d6d7..77f91ebacd0 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -309,20 +309,20 @@ Bool PolicyPoll(Arena arena)
* should return to the mutator.
*
* start is the clock time when the MPS was entered.
- * tracedWork is the amount of work done by the last call to TracePoll.
+ * moreWork and tracedWork are the results of the last call to TracePoll.
*/
-Bool PolicyPollAgain(Arena arena, Clock start, Work tracedWork)
+Bool PolicyPollAgain(Arena arena, Bool moreWork, Work tracedWork)
{
Globals globals;
double nextPollThreshold;
AVERT(Arena, arena);
globals = ArenaGlobals(arena);
- UNUSED(start);
+ UNUSED(tracedWork);
- if (tracedWork == 0) {
- /* No work was done. Sleep until NOW + a bit. */
+ if (!moreWork) {
+ /* No more work to do. Sleep until NOW + a bit. */
nextPollThreshold = globals->fillMutatorSize + ArenaPollALLOCTIME;
} else {
/* We did one quantum of work; consume one unit of 'time'. */
diff --git a/mps/code/trace.c b/mps/code/trace.c
index 378b6bed9a1..47bd74b8283 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -1846,10 +1846,12 @@ Res TraceStartCollectAll(Trace *traceReturn, Arena arena, int why)
/* TracePoll -- Check if there's any tracing work to be done
*
* Consider starting a trace if none is running; advance the running
- * trace (if any) by one quantum. Return a measure of the work done.
+ * trace (if any) by one quantum. If there may be more work to do,
+ * update *workReturn with a measure of the work done and return TRUE.
+ * Otherwise return FALSE.
*/
-Work TracePoll(Globals globals)
+Bool TracePoll(Work *workReturn, Globals globals)
{
Trace trace;
Arena arena;
@@ -1863,7 +1865,7 @@ Work TracePoll(Globals globals)
} else {
/* No traces are running: consider starting one now. */
if (!PolicyStartTrace(&trace, arena))
- return (Size)0;
+ return FALSE;
}
AVER(arena->busyTraces == TraceSetSingle(trace));
@@ -1877,7 +1879,8 @@ Work TracePoll(Globals globals)
work = newWork - oldWork;
if (trace->state == TraceFINISHED)
TraceDestroyFinished(trace);
- return work;
+ *workReturn = work;
+ return TRUE;
}
From 6f0c939e2f3ed4c173622b840f12f3df2c68fdf4 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 19:11:49 +0100
Subject: [PATCH 057/759] Arenastep considers collecting the world after
finishing a trace (not just on entry if no traces are busy).
ArenaStep does not care about quanta, so call TraceAdvance instead of TracePoll.
Copied from Perforce
Change: 188219
ServerID: perforce.ravenbrook.com
---
mps/code/global.c | 85 ++++++++++++++++++++++++-----------------------
1 file changed, 44 insertions(+), 41 deletions(-)
diff --git a/mps/code/global.c b/mps/code/global.c
index d9a5bf9c6c7..a6ab23572f7 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -747,39 +747,37 @@ void (ArenaPoll)(Globals globals)
* and whether much time has passed since the last time we did that
* opportunistically. */
static Bool arenaShouldCollectWorld(Arena arena,
- double interval,
- double multiplier,
+ double availableTime,
Clock now,
Clock clocks_per_sec)
{
- /* don't collect the world if we're not given any time */
- if ((interval > 0.0) && (multiplier > 0.0)) {
- /* don't collect the world if we're already collecting. */
- if (arena->busyTraces == TraceSetEMPTY) {
- /* don't collect the world if it's very small */
- Size collectableSize = ArenaCollectable(arena);
- if (collectableSize > ARENA_MINIMUM_COLLECTABLE_SIZE) {
- /* how long would it take to collect the world? */
- double collectionTime = PolicyCollectionTime(arena);
+ AVERT(Arena, arena);
+ /* Can't collect the world if we're not given any time. */
+ AVER(availableTime > 0.0);
+ /* Can't collect the world if we're already collecting. */
+ AVER(arena->busyTraces == TraceSetEMPTY);
- /* how long since we last collected the world? */
- double sinceLastWorldCollect = ((now - arena->lastWorldCollect) /
- (double) clocks_per_sec);
- /* have to be offered enough time, and it has to be a long time
- * since we last did it. */
- if ((interval * multiplier > collectionTime) &&
- sinceLastWorldCollect > collectionTime / ARENA_MAX_COLLECT_FRACTION)
- return TRUE;
- }
- }
+ /* Don't collect the world if it's very small. */
+ Size collectableSize = ArenaCollectable(arena);
+ if (collectableSize > ARENA_MINIMUM_COLLECTABLE_SIZE) {
+ /* How long would it take to collect the world? */
+ double collectionTime = PolicyCollectionTime(arena);
+
+ /* How long since we last collected the world? */
+ double sinceLastWorldCollect = ((now - arena->lastWorldCollect) /
+ (double) clocks_per_sec);
+ /* have to be offered enough time, and it has to be a long time
+ * since we last did it. */
+ if ((availableTime > collectionTime) &&
+ sinceLastWorldCollect > collectionTime / ARENA_MAX_COLLECT_FRACTION)
+ return TRUE;
}
return FALSE;
}
Bool ArenaStep(Globals globals, double interval, double multiplier)
{
- Work work;
- Bool moreWork, workWasDone = FALSE;
+ Bool workWasDone = FALSE;
Clock start, end, now;
Clock clocks_per_sec;
Arena arena;
@@ -791,30 +789,35 @@ Bool ArenaStep(Globals globals, double interval, double multiplier)
arena = GlobalsArena(globals);
clocks_per_sec = ClocksPerSec();
- start = ClockNow();
+ start = now = ClockNow();
end = start + (Clock)(interval * clocks_per_sec);
AVER(end >= start);
- if (arenaShouldCollectWorld(arena, interval, multiplier,
- start, clocks_per_sec))
- {
- Res res;
- Trace trace;
- res = TraceStartCollectAll(&trace, arena, TraceStartWhyOPPORTUNISM);
- if (res == ResOK) {
- arena->lastWorldCollect = start;
- workWasDone = TRUE;
- }
- }
-
/* loop while there is work to do and time on the clock. */
do {
- moreWork = TracePoll(&work, globals);
- now = ClockNow();
- if (moreWork) {
- workWasDone = TRUE;
+ Trace trace;
+ if (arena->busyTraces != TraceSetEMPTY) {
+ trace = ArenaTrace(arena, (TraceId)0);
+ } else {
+ /* No traces are running: consider collecting the world. */
+ if (arenaShouldCollectWorld(arena, end - now, now, clocks_per_sec)) {
+ Res res;
+ res = TraceStartCollectAll(&trace, arena, TraceStartWhyOPPORTUNISM);
+ if (res != ResOK)
+ break;
+ arena->lastWorldCollect = now;
+ } else {
+ /* Not worth collecting the world; consider starting a trace. */
+ if (!PolicyStartTrace(&trace, arena))
+ break;
+ }
}
- } while (moreWork && now < end);
+ TraceAdvance(trace);
+ if (trace->state == TraceFINISHED)
+ TraceDestroyFinished(trace);
+ workWasDone = TRUE;
+ now = ClockNow();
+ } while (now < end);
if (workWasDone) {
ArenaAccumulateTime(arena, start);
From c2488346e73d8c119e229b9c03b5189fbccc605d Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 20:14:06 +0100
Subject: [PATCH 058/759] There can only be an emergency when a trace is busy,
so check this.
Copied from Perforce
Change: 188220
ServerID: perforce.ravenbrook.com
---
mps/code/global.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/mps/code/global.c b/mps/code/global.c
index a6ab23572f7..3e33b2e507a 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -214,6 +214,8 @@ Bool GlobalsCheck(Globals arenaGlobals)
CHECKL(RingCheck(&arenaRing));
CHECKL(BoolCheck(arena->emergency));
+ /* There can only be an emergency when a trace is busy. */
+ CHECKL(!arena->emergency || arena->busyTraces != TraceSetEMPTY);
if (arenaGlobals->defaultChain != NULL)
CHECKD(Chain, arenaGlobals->defaultChain);
From 49635c2e8632a125fd2929d11c49e246b9dbfa13 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 08:53:23 +0100
Subject: [PATCH 059/759] Fix bug introduced by change 188219: the end of the
interval is not the same as the available collection time.
Copied from Perforce
Change: 188223
ServerID: perforce.ravenbrook.com
---
mps/code/global.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/mps/code/global.c b/mps/code/global.c
index 3e33b2e507a..48c9c01ec98 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -780,7 +780,7 @@ static Bool arenaShouldCollectWorld(Arena arena,
Bool ArenaStep(Globals globals, double interval, double multiplier)
{
Bool workWasDone = FALSE;
- Clock start, end, now;
+ Clock start, intervalEnd, availableEnd, now;
Clock clocks_per_sec;
Arena arena;
@@ -792,8 +792,10 @@ Bool ArenaStep(Globals globals, double interval, double multiplier)
clocks_per_sec = ClocksPerSec();
start = now = ClockNow();
- end = start + (Clock)(interval * clocks_per_sec);
- AVER(end >= start);
+ intervalEnd = start + (Clock)(interval * clocks_per_sec);
+ AVER(intervalEnd >= start);
+ availableEnd = start + (Clock)(interval * multiplier * clocks_per_sec);
+ AVER(availableEnd >= start);
/* loop while there is work to do and time on the clock. */
do {
@@ -802,7 +804,9 @@ Bool ArenaStep(Globals globals, double interval, double multiplier)
trace = ArenaTrace(arena, (TraceId)0);
} else {
/* No traces are running: consider collecting the world. */
- if (arenaShouldCollectWorld(arena, end - now, now, clocks_per_sec)) {
+ if (arenaShouldCollectWorld(arena, availableEnd - now, now,
+ clocks_per_sec))
+ {
Res res;
res = TraceStartCollectAll(&trace, arena, TraceStartWhyOPPORTUNISM);
if (res != ResOK)
@@ -819,7 +823,7 @@ Bool ArenaStep(Globals globals, double interval, double multiplier)
TraceDestroyFinished(trace);
workWasDone = TRUE;
now = ClockNow();
- } while (now < end);
+ } while (now < intervalEnd);
if (workWasDone) {
ArenaAccumulateTime(arena, start);
From 38b52d7a0556d17ef871d204f4c820a6befd65e1 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 22:28:40 +0100
Subject: [PATCH 060/759] Avoid "iso c90 forbids mixed declarations and code"
error from gcc.
Copied from Perforce
Change: 188257
ServerID: perforce.ravenbrook.com
---
mps/code/policy.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/mps/code/policy.c b/mps/code/policy.c
index b172405ab6b..b207910afbf 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -160,6 +160,8 @@ static double policyCollectionTime(Arena arena)
Bool PolicyShouldCollectWorld(Arena arena, double availableTime,
Clock now, Clock clocks_per_sec)
{
+ Size collectableSize;
+
AVERT(Arena, arena);
/* Can't collect the world if we're not given any time. */
AVER(availableTime > 0.0);
@@ -167,7 +169,7 @@ Bool PolicyShouldCollectWorld(Arena arena, double availableTime,
AVER(arena->busyTraces == TraceSetEMPTY);
/* Don't collect the world if it's very small. */
- Size collectableSize = ArenaCollectable(arena);
+ collectableSize = ArenaCollectable(arena);
if (collectableSize > ARENA_MINIMUM_COLLECTABLE_SIZE) {
/* How long would it take to collect the world? */
double collectionTime = policyCollectionTime(arena);
From b8df4963ee2b0a6906bb193c9c2995ae2d3c3f10 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 22:35:03 +0100
Subject: [PATCH 061/759] Can't assume that the caller will give us any
available time.
Copied from Perforce
Change: 188259
ServerID: perforce.ravenbrook.com
---
mps/code/policy.c | 34 ++++++++++++++++++----------------
1 file changed, 18 insertions(+), 16 deletions(-)
diff --git a/mps/code/policy.c b/mps/code/policy.c
index b207910afbf..a2ef85dea80 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -161,29 +161,31 @@ Bool PolicyShouldCollectWorld(Arena arena, double availableTime,
Clock now, Clock clocks_per_sec)
{
Size collectableSize;
+ double collectionTime, sinceLastWorldCollect;
AVERT(Arena, arena);
- /* Can't collect the world if we're not given any time. */
- AVER(availableTime > 0.0);
/* Can't collect the world if we're already collecting. */
AVER(arena->busyTraces == TraceSetEMPTY);
+ if (availableTime <= 0.0)
+ /* Can't collect the world if we're not given any time. */
+ return FALSE;
+
/* Don't collect the world if it's very small. */
collectableSize = ArenaCollectable(arena);
- if (collectableSize > ARENA_MINIMUM_COLLECTABLE_SIZE) {
- /* How long would it take to collect the world? */
- double collectionTime = policyCollectionTime(arena);
-
- /* How long since we last collected the world? */
- double sinceLastWorldCollect = ((now - arena->lastWorldCollect) /
- (double) clocks_per_sec);
- /* have to be offered enough time, and it has to be a long time
- * since we last did it. */
- if ((availableTime > collectionTime) &&
- sinceLastWorldCollect > collectionTime / ARENA_MAX_COLLECT_FRACTION)
- return TRUE;
- }
- return FALSE;
+ if (collectableSize < ARENA_MINIMUM_COLLECTABLE_SIZE)
+ return FALSE;
+
+ /* How long would it take to collect the world? */
+ collectionTime = policyCollectionTime(arena);
+
+ /* How long since we last collected the world? */
+ sinceLastWorldCollect = ((now - arena->lastWorldCollect) /
+ (double) clocks_per_sec);
+
+ /* Offered enough time, and long enough since we last did it? */
+ return availableTime > collectionTime
+ && sinceLastWorldCollect > collectionTime / ARENA_MAX_COLLECT_FRACTION;
}
From 0eaa42ef7abb32da4d9016d2c9ef51fd44ac58cb Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Wed, 16 Sep 2015 20:01:22 +0100
Subject: [PATCH 062/759] Demote fixme to todo with reference to job003947.
Copied from Perforce
Change: 188336
ServerID: perforce.ravenbrook.com
---
mps/code/mpsi.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index 4ce28a48626..0339e517475 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -996,7 +996,8 @@ mps_res_t (mps_ap_frame_pop)(mps_ap_t mps_ap, mps_frame_t frame)
buf = BufferOfAP(mps_ap);
AVER(TESTT(Buffer, buf));
- /* FIXME: is it thread-safe to read BufferBase here? */
+ /* TODO: it's not thread-safe to read BufferBase here in an
+ * automatically managed pool; see job003947. */
if (BufferBase(buf) <= (Addr)frame
&& (mps_addr_t)frame < mps_ap->init)
{
From b4955a5c9a9da129aa30df072b471b622720969c Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Wed, 16 Sep 2015 20:02:23 +0100
Subject: [PATCH 063/759] "supports allocation frames?" is a useless property
to include in the table, since it doesn't mean they do anything. replace with
"manages memory using allocation frames?"
Copied from Perforce
Change: 188337
ServerID: perforce.ravenbrook.com
---
mps/manual/source/pool/intro.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mps/manual/source/pool/intro.rst b/mps/manual/source/pool/intro.rst
index 17b97cb06a4..16b44b1adf7 100644
--- a/mps/manual/source/pool/intro.rst
+++ b/mps/manual/source/pool/intro.rst
@@ -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
From ad18e7dc1da27d4922ec74964d7352a2177e3f0a Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 22 Sep 2015 19:52:42 +0100
Subject: [PATCH 064/759] Remove fixme, reviewed by rb
Copied from Perforce
Change: 188348
ServerID: perforce.ravenbrook.com
---
mps/code/poolsnc.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c
index 873547bd0ca..93420e55c26 100644
--- a/mps/code/poolsnc.c
+++ b/mps/code/poolsnc.c
@@ -290,7 +290,6 @@ static void sncRecordFreeSeg(Arena arena, SNC snc, Seg seg)
SegSetRankAndSummary(seg, RankSetEMPTY, RefSetEMPTY);
/* Pad the whole segment so we don't try to walk it. */
- /* FIXME: are the Expose and Cover calls necessary here? */
ShieldExpose(arena, seg);
(*SNCPool(snc)->format->pad)(SegBase(seg), SegSize(seg));
ShieldCover(arena, seg);
From 2da2650d9e5142765cfdf086e604e5f6e541c3c9 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 22 Sep 2015 21:11:58 +0100
Subject: [PATCH 065/759] New function segbufferscanlimit replaces sncscanlimit
and can also be used in amc. suggested by rb in review
Copied from Perforce
Change: 188350
ServerID: perforce.ravenbrook.com
---
mps/code/mpm.h | 1 +
mps/code/poolamc.c | 15 ++-------------
mps/code/poolsnc.c | 22 ++--------------------
mps/code/seg.c | 21 +++++++++++++++++++++
4 files changed, 26 insertions(+), 33 deletions(-)
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index eb52f275de8..662046cee7c 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -684,6 +684,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);
diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c
index 4e9ed70396d..efc20138288 100644
--- a/mps/code/poolamc.c
+++ b/mps/code/poolamc.c
@@ -1980,11 +1980,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);
p1 = p;
padBase = p;
padLength = 0;
@@ -2198,14 +2194,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. */
diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c
index 93420e55c26..ce307b104fe 100644
--- a/mps/code/poolsnc.c
+++ b/mps/code/poolsnc.c
@@ -498,24 +498,6 @@ static void SNCBufferEmpty(Pool pool, Buffer buffer,
}
-/* SNCScanLimit -- limit of scannable objects in segment */
-
-static Addr SNCScanLimit(Seg seg)
-{
- Addr limit;
- Buffer buf;
- 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;
-}
-
-
static Res SNCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
{
Addr base, limit;
@@ -532,7 +514,7 @@ static Res SNCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
format = pool->format;
base = SegBase(seg);
- limit = SNCScanLimit(seg);
+ limit = SegBufferScanLimit(seg);
if (base < limit) {
res = (*format->scan)(&ss->ss_s, base, limit);
@@ -645,7 +627,7 @@ static void SNCWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
snc = PoolSNC(pool);
AVERT(SNC, snc);
format = pool->format;
- limit = SNCScanLimit(seg);
+ limit = SegBufferScanLimit(seg);
while(object < limit) {
(*f)(object, format, pool, p, s);
diff --git a/mps/code/seg.c b/mps/code/seg.c
index ab7414eaf4a..7beb8975910 100644
--- a/mps/code/seg.c
+++ b/mps/code/seg.c
@@ -355,6 +355,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)
From ff29aac90b820c40d9ef0953c19179ad7e3ecbb7 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 22 Sep 2015 21:24:50 +0100
Subject: [PATCH 066/759] When pushing a stack frame, the frame pointer should
be buffergetinit, not bufferscanlimit. spotted by rb in review
.
Copied from Perforce
Change: 188351
ServerID: perforce.ravenbrook.com
---
mps/code/poolsnc.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c
index ce307b104fe..1d694998cdd 100644
--- a/mps/code/poolsnc.c
+++ b/mps/code/poolsnc.c
@@ -544,13 +544,13 @@ static Res SNCFramePush(AllocFrame *frameReturn, Pool pool, Buffer buf)
AVER(sncBufferTopSeg(buf) == NULL); /* The stack must be empty */
/* Use NULL to indicate an empty stack. .lw-frame-null */
*frameReturn = NULL;
- } else if (BufferScanLimit(buf) < SegLimit(BufferSeg(buf))) {
- /* Use the scan limit as the lightweight frame pointer */
- *frameReturn = (AllocFrame)BufferScanLimit(buf);
+ } else if (BufferGetInit(buf) < SegLimit(BufferSeg(buf))) {
+ /* Frame pointer is limit of initialized objects in buffer. */
+ *frameReturn = (AllocFrame)BufferGetInit(buf);
} else {
- /* Can't use the scan limit as the lightweight frame pointer as
- * it's not in the segment (see job003882). Instead, refill the
- * buffer and put the frame pointer at the beginning. */
+ /* 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);
@@ -558,8 +558,8 @@ static Res SNCFramePush(AllocFrame *frameReturn, Pool pool, Buffer buf)
if (res != ResOK)
return res;
BufferAttach(buf, base, limit, base, 0);
- AVER(BufferScanLimit(buf) < SegLimit(BufferSeg(buf)));
- *frameReturn = (AllocFrame)BufferScanLimit(buf);
+ AVER(BufferGetInit(buf) < SegLimit(BufferSeg(buf)));
+ *frameReturn = (AllocFrame)BufferGetInit(buf);
}
return ResOK;
}
From ab2f7570acbcb07dd0d3114f4635b182eec9d65b Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 22 Sep 2015 21:32:14 +0100
Subject: [PATCH 067/759] Only snc supports allocation frames. notes by rb in
review .
Allocation frames and SNC are no longer deprecated.
Copied from Perforce
Change: 188352
ServerID: perforce.ravenbrook.com
---
mps/manual/source/pool/snc.rst | 5 -----
mps/manual/source/release.rst | 4 ++++
mps/manual/source/topic/frame.rst | 11 ++---------
3 files changed, 6 insertions(+), 14 deletions(-)
diff --git a/mps/manual/source/pool/snc.rst b/mps/manual/source/pool/snc.rst
index 2e82d055e7c..5eb26bdcfe7 100644
--- a/mps/manual/source/pool/snc.rst
+++ b/mps/manual/source/pool/snc.rst
@@ -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 `.
-
**SNC** is a :term:`manually managed `
:term:`pool class` that supports a stack-like protocol for allocation
and deallocation using :term:`allocation frames` on :term:`allocation
diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst
index b17a2c4c023..7bd33255fb6 100644
--- a/mps/manual/source/release.rst
+++ b/mps/manual/source/release.rst
@@ -19,6 +19,10 @@ Interface changes
#. The :ref:`pool-snc` pool class now implements
:c:func:`mps_pool_total_size` and :c:func:`mps_pool_free_size`.
+#. The pool class :ref:`pool-snc` is no longer deprecated.
+
+#. Allocation frames are no longer deprecated. See :ref:`topic-frame`.
+
Other changes
.............
diff --git a/mps/manual/source/topic/frame.rst b/mps/manual/source/topic/frame.rst
index aa98e204d92..4a308c9a960 100644
--- a/mps/manual/source/topic/frame.rst
+++ b/mps/manual/source/topic/frame.rst
@@ -13,11 +13,6 @@
Allocation frames
=================
-.. deprecated:: starting with version 1.111.
-
- If you need special handling of stack-like allocation,
- :ref:`contact us `.
-
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
@@ -31,10 +26,8 @@ efficiently implement stack-like patterns of allocation.
.. 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
From 49ef7fe55248561d1d9e1d0a894860888383c82e Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Mon, 18 Jan 2016 15:16:41 +0000
Subject: [PATCH 068/759] Catch up merge from master sources.
Adding instructions for running tests on OS X.
Copied from Perforce
Change: 188917
ServerID: perforce.ravenbrook.com
---
mps/code/arena.c | 144 +++++++++++++++----------
mps/code/arenacl.c | 2 +-
mps/code/cbs.c | 6 +-
mps/code/djbench.c | 7 +-
mps/code/gcbench.c | 7 +-
mps/code/land.c | 16 +--
mps/code/mpm.c | 14 ++-
mps/code/mpm.h | 5 +-
mps/code/mps.xcodeproj/project.pbxproj | 8 --
mps/code/mpsi.c | 2 +-
mps/code/pool.c | 6 +-
mps/code/poolabs.c | 10 +-
mps/code/poolawl.c | 5 +-
mps/code/protan.c | 7 +-
mps/code/protix.c | 5 +-
mps/code/protw3.c | 5 +-
mps/code/root.c | 4 +-
mps/code/seg.c | 14 +--
mps/code/shield.c | 7 +-
mps/code/trace.c | 5 +-
mps/design/bootstrap.txt | 127 ++++++++++++++++++++++
mps/design/guide.hex.trans.txt | 40 +++++--
mps/design/guide.review.txt | 96 +++++++++++++++++
mps/design/index.txt | 4 +
mps/manual/source/design/index.rst | 2 +
mps/manual/source/pool/snc.rst | 10 +-
mps/manual/source/release.rst | 2 +-
mps/manual/source/topic/error.rst | 53 +++++++--
mps/manual/source/topic/format.rst | 14 +++
mps/manual/source/topic/scanning.rst | 17 +--
mps/test/README | 17 ++-
mps/test/function/121.c | 50 +++++----
32 files changed, 552 insertions(+), 159 deletions(-)
create mode 100644 mps/design/bootstrap.txt
create mode 100644 mps/design/guide.review.txt
diff --git a/mps/code/arena.c b/mps/code/arena.c
index e4e7c5e1973..34bfef3ba75 100644
--- a/mps/code/arena.c
+++ b/mps/code/arena.c
@@ -41,6 +41,7 @@ Bool ArenaGrainSizeCheck(Size size)
static void ArenaTrivCompact(Arena arena, Trace trace);
static void arenaFreePage(Arena arena, Addr base, Pool pool);
+static void arenaFreeLandFinish(Arena arena);
/* ArenaTrivDescribe -- produce trivial description of an arena */
@@ -238,10 +239,11 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args)
arena->sig = ArenaSig;
AVERT(Arena, arena);
- /* Initialise a pool to hold the arena's CBS blocks. This pool can't be
- allowed to extend itself using ArenaAlloc because it is used during
- ArenaAlloc, so MFSExtendSelf is set to FALSE. Failures to extend are
- handled where the Land is used. */
+ /* Initialise a pool to hold the CBS blocks for the arena's free
+ * land. This pool can't be allowed to extend itself using
+ * ArenaAlloc because it is used to implement ArenaAlloc, so
+ * MFSExtendSelf is set to FALSE. Failures to extend are handled
+ * where the free land is used: see arenaFreeLandInsertExtend. */
MPS_ARGS_BEGIN(piArgs) {
MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSZonedBlockStruct));
@@ -253,18 +255,6 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args)
if (res != ResOK)
goto failMFSInit;
- /* Initialise the freeLand. */
- MPS_ARGS_BEGIN(liArgs) {
- MPS_ARGS_ADD(liArgs, CBSBlockPool, ArenaCBSBlockPool(arena));
- res = LandInit(ArenaFreeLand(arena), CBSZonedLandClassGet(), arena,
- ArenaGrainSize(arena), arena, liArgs);
- } MPS_ARGS_END(liArgs);
- AVER(res == ResOK); /* no allocation, no failure expected */
- if (res != ResOK)
- goto failLandInit;
- /* Note that although freeLand is initialised, it doesn't have any memory
- for its blocks, so hasFreeLand remains FALSE until later. */
-
/* initialize the reservoir, */
res = ReservoirInit(&arena->reservoirStruct, arena);
if (res != ResOK)
@@ -274,8 +264,6 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args)
return ResOK;
failReservoirInit:
- LandFinish(ArenaFreeLand(arena));
-failLandInit:
PoolFinish(ArenaCBSBlockPool(arena));
failMFSInit:
GlobalsFinish(ArenaGlobals(arena));
@@ -301,6 +289,43 @@ ARG_DEFINE_KEY(ARENA_SIZE, Size);
ARG_DEFINE_KEY(ARENA_GRAIN_SIZE, Size);
ARG_DEFINE_KEY(ARENA_ZONED, Bool);
+static Res arenaFreeLandInit(Arena arena)
+{
+ Res res;
+
+ AVERT(Arena, arena);
+ AVER(!arena->hasFreeLand);
+ AVER(arena->primary != NULL);
+
+ /* Initialise the free land. */
+ MPS_ARGS_BEGIN(liArgs) {
+ MPS_ARGS_ADD(liArgs, CBSBlockPool, ArenaCBSBlockPool(arena));
+ res = LandInit(ArenaFreeLand(arena), CBSZonedLandClassGet(), arena,
+ ArenaGrainSize(arena), arena, liArgs);
+ } MPS_ARGS_END(liArgs);
+ AVER(res == ResOK); /* no allocation, no failure expected */
+ if (res != ResOK)
+ goto failLandInit;
+
+ /* With the primary chunk initialised we can add page memory to the
+ * free land that describes the free address space in the primary
+ * chunk. */
+ res = ArenaFreeLandInsert(arena,
+ PageIndexBase(arena->primary,
+ arena->primary->allocBase),
+ arena->primary->limit);
+ if (res != ResOK)
+ goto failFreeLandInsert;
+
+ arena->hasFreeLand = TRUE;
+ return ResOK;
+
+failFreeLandInsert:
+ LandFinish(ArenaFreeLand(arena));
+failLandInit:
+ return res;
+}
+
Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
{
Arena arena;
@@ -326,15 +351,9 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
goto failStripeSize;
}
- /* With the primary chunk initialised we can add page memory to the freeLand
- that describes the free address space in the primary chunk. */
- res = ArenaFreeLandInsert(arena,
- PageIndexBase(arena->primary,
- arena->primary->allocBase),
- arena->primary->limit);
+ res = arenaFreeLandInit(arena);
if (res != ResOK)
- goto failPrimaryLand;
- arena->hasFreeLand = TRUE;
+ goto failFreeLandInit;
res = ControlInit(arena);
if (res != ResOK)
@@ -351,7 +370,8 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
failGlobalsCompleteCreate:
ControlFinish(arena);
failControlInit:
-failPrimaryLand:
+ arenaFreeLandFinish(arena);
+failFreeLandInit:
failStripeSize:
(*class->finish)(arena);
failInit:
@@ -392,6 +412,20 @@ static void arenaMFSPageFreeVisitor(Pool pool, Addr base, Size size,
arenaFreePage(PoolArena(pool), base, pool);
}
+static void arenaFreeLandFinish(Arena arena)
+{
+ AVERT(Arena, arena);
+ AVER(arena->hasFreeLand);
+
+ /* The CBS block pool can't free its own memory via ArenaFree because
+ * that would use the free land. */
+ MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor,
+ UNUSED_POINTER, UNUSED_SIZE);
+
+ arena->hasFreeLand = FALSE;
+ LandFinish(ArenaFreeLand(arena));
+}
+
void ArenaDestroy(Arena arena)
{
AVERT(Arena, arena);
@@ -401,19 +435,11 @@ void ArenaDestroy(Arena arena)
/* Empty the reservoir - see */
ReservoirSetLimit(ArenaReservoir(arena), 0);
- arena->poolReady = FALSE;
ControlFinish(arena);
- /* We must tear down the freeLand before the chunks, because pages
- containing CBS blocks might be allocated in those chunks. */
- AVER(arena->hasFreeLand);
- arena->hasFreeLand = FALSE;
- LandFinish(ArenaFreeLand(arena));
-
- /* The CBS block pool can't free its own memory via ArenaFree because
- that would use the freeLand. */
- MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor,
- UNUSED_POINTER, UNUSED_SIZE);
+ /* We must tear down the free land before the chunks, because pages
+ * containing CBS blocks might be allocated in those chunks. */
+ arenaFreeLandFinish(arena);
/* Call class-specific finishing. This will call ArenaFinish. */
(*arena->class->finish)(arena);
@@ -429,6 +455,7 @@ Res ControlInit(Arena arena)
Res res;
AVERT(Arena, arena);
+ AVER(!arena->poolReady);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, CONTROL_EXTEND_BY);
res = PoolInit(MVPool(&arena->controlPoolStruct), arena,
@@ -446,6 +473,7 @@ Res ControlInit(Arena arena)
void ControlFinish(Arena arena)
{
AVERT(Arena, arena);
+ AVER(arena->poolReady);
arena->poolReady = FALSE;
PoolFinish(MVPool(&arena->controlPoolStruct));
}
@@ -801,7 +829,7 @@ static Res arenaExtendCBSBlockPool(Range pageRangeReturn, Arena arena)
return res;
MFSExtend(ArenaCBSBlockPool(arena), pageBase, ArenaGrainSize(arena));
- RangeInit(pageRangeReturn, pageBase, AddrAdd(pageBase, ArenaGrainSize(arena)));
+ RangeInitSize(pageRangeReturn, pageBase, ArenaGrainSize(arena));
return ResOK;
}
@@ -821,15 +849,19 @@ static void arenaExcludePage(Arena arena, Range pageRange)
}
-/* arenaLandInsert -- add range to arena's land, maybe extending block pool
+/* arenaFreeLandInsertExtend -- add range to arena's free land, maybe
+ * extending block pool
*
- * The arena's land can't get memory in the usual way because it is
- * used in the basic allocator, so we allocate pages specially.
+ * The arena's free land can't get memory for its block pool in the
+ * usual way (via ArenaAlloc), because it is the mechanism behind
+ * ArenaAlloc! So we extend the block pool via a back door (see
+ * arenaExtendCBSBlockPool).
*
* Only fails if it can't get a page for the block pool.
*/
-static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range)
+static Res arenaFreeLandInsertExtend(Range rangeReturn, Arena arena,
+ Range range)
{
Res res;
@@ -855,16 +887,18 @@ static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range)
}
-/* ArenaFreeLandInsert -- add range to arena's land, maybe stealing memory
+/* arenaFreeLandInsertSteal -- add range to arena's free land, maybe
+ * stealing memory
*
- * See arenaLandInsert. This function may only be applied to mapped
- * pages and may steal them to store Land nodes if it's unable to
- * allocate space for CBS blocks.
+ * See arenaFreeLandInsertExtend. This function may only be applied to
+ * mapped pages and may steal them to store Land nodes if it's unable
+ * to allocate space for CBS blocks.
*
* IMPORTANT: May update rangeIO.
*/
-static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO)
+static void arenaFreeLandInsertSteal(Range rangeReturn, Arena arena,
+ Range rangeIO)
{
Res res;
@@ -872,7 +906,7 @@ static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO)
AVERT(Arena, arena);
AVERT(Range, rangeIO);
- res = arenaLandInsert(rangeReturn, arena, rangeIO);
+ res = arenaFreeLandInsertExtend(rangeReturn, arena, rangeIO);
if (res != ResOK) {
Addr pageBase;
@@ -901,7 +935,8 @@ static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO)
}
-/* ArenaFreeLandInsert -- add range to arena's land, maybe extending block pool
+/* ArenaFreeLandInsert -- add range to arena's free land, maybe extending
+ * block pool
*
* The inserted block of address space may not abut any existing block.
* This restriction ensures that we don't coalesce chunks and allocate
@@ -916,7 +951,7 @@ Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit)
AVERT(Arena, arena);
RangeInit(&range, base, limit);
- res = arenaLandInsert(&oldRange, arena, &range);
+ res = arenaFreeLandInsertExtend(&oldRange, arena, &range);
if (res != ResOK)
return res;
@@ -931,7 +966,8 @@ Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit)
}
-/* ArenaFreeLandDelete -- remove range from arena's land, maybe extending block pool
+/* ArenaFreeLandDelete -- remove range from arena's free land, maybe
+ * extending block pool
*
* This is called from ChunkFinish in order to remove address space from
* the arena.
@@ -1023,7 +1059,7 @@ static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high,
failMark:
{
- Res insertRes = arenaLandInsert(&oldRange, arena, &range);
+ Res insertRes = arenaFreeLandInsertExtend(&oldRange, arena, &range);
AVER(insertRes == ResOK); /* We only just deleted it. */
/* If the insert does fail, we lose some address space permanently. */
}
@@ -1235,7 +1271,7 @@ void ArenaFree(Addr base, Size size, Pool pool)
RangeInit(&range, base, limit);
- arenaLandInsertSteal(&oldRange, arena, &range); /* may update range */
+ arenaFreeLandInsertSteal(&oldRange, arena, &range); /* may update range */
(*arena->class->free)(RangeBase(&range), RangeSize(&range), pool);
diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c
index 2a639c99baf..cd5c24fe46a 100644
--- a/mps/code/arenacl.c
+++ b/mps/code/arenacl.c
@@ -274,7 +274,7 @@ static Res ClientArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
AVER(base != (Addr)0);
AVERT(ArenaGrainSize, grainSize);
- if (size < grainSize * MPS_WORD_SHIFT)
+ if (size < grainSize * MPS_WORD_WIDTH)
/* Not enough room for a full complement of zones. */
return ResMEMORY;
diff --git a/mps/code/cbs.c b/mps/code/cbs.c
index d98a92cb8c4..0b30b68acb1 100644
--- a/mps/code/cbs.c
+++ b/mps/code/cbs.c
@@ -1,7 +1,7 @@
/* cbs.c: COALESCING BLOCK STRUCTURE IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
* .intro: This is a portable implementation of coalescing block
* structures.
@@ -1069,7 +1069,7 @@ static Res cbsFindInZones(Bool *foundReturn, Range rangeReturn,
AVERT(CBS, cbs);
AVER(IsLandSubclass(CBSLand(cbs), CBSZonedLandClass));
/* AVERT(ZoneSet, zoneSet); */
- AVER(BoolCheck(high));
+ AVERT(Bool, high);
landFind = high ? cbsFindLast : cbsFindFirst;
splayFind = high ? SplayFindLast : SplayFindFirst;
@@ -1208,7 +1208,7 @@ DEFINE_LAND_CLASS(CBSZonedLandClass, class)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/djbench.c b/mps/code/djbench.c
index 33cf1d4bdb9..fbc6dcabc1c 100644
--- a/mps/code/djbench.c
+++ b/mps/code/djbench.c
@@ -13,10 +13,15 @@
#include "mps.c"
-#include "getopt.h"
#include "testlib.h"
#include "testthr.h"
+#ifdef MPS_OS_W3
+#include "getopt.h"
+#else
+#include
+#endif
+
#include /* fprintf, stderr */
#include /* alloca, exit, EXIT_SUCCESS, EXIT_FAILURE */
#include /* CLOCKS_PER_SEC, clock */
diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c
index 7aa28eb4561..da8a4f88c8b 100644
--- a/mps/code/gcbench.c
+++ b/mps/code/gcbench.c
@@ -7,13 +7,18 @@
*/
#include "mps.c"
-#include "getopt.h"
#include "testlib.h"
#include "testthr.h"
#include "fmtdy.h"
#include "fmtdytst.h"
#include "mpm.h"
+#ifdef MPS_OS_W3
+#include "getopt.h"
+#else
+#include
+#endif
+
#include /* fprintf, printf, putchars, sscanf, stderr, stdout */
#include /* alloca, exit, EXIT_FAILURE, EXIT_SUCCESS, strtoul */
#include /* clock, CLOCKS_PER_SEC */
diff --git a/mps/code/land.c b/mps/code/land.c
index 7dbc7845b5b..18d446288f8 100644
--- a/mps/code/land.c
+++ b/mps/code/land.c
@@ -1,7 +1,7 @@
/* land.c: LAND (COLLECTION OF ADDRESS RANGES) IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2014-2015 Ravenbrook Limited. See end of file for license.
*
* .design:
*/
@@ -282,7 +282,7 @@ Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size
AVER(oldRangeReturn != NULL);
AVERT(Land, land);
AVER(SizeIsAligned(size, land->alignment));
- AVER(FindDeleteCheck(findDelete));
+ AVERT(FindDelete, findDelete);
landEnter(land);
b = (*land->class->findFirst)(rangeReturn, oldRangeReturn, land, size,
@@ -306,7 +306,7 @@ Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size,
AVER(oldRangeReturn != NULL);
AVERT(Land, land);
AVER(SizeIsAligned(size, land->alignment));
- AVER(FindDeleteCheck(findDelete));
+ AVERT(FindDelete, findDelete);
landEnter(land);
b = (*land->class->findLast)(rangeReturn, oldRangeReturn, land, size,
@@ -330,7 +330,7 @@ Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size si
AVER(oldRangeReturn != NULL);
AVERT(Land, land);
AVER(SizeIsAligned(size, land->alignment));
- AVER(FindDeleteCheck(findDelete));
+ AVERT(FindDelete, findDelete);
landEnter(land);
b = (*land->class->findLargest)(rangeReturn, oldRangeReturn, land, size,
@@ -470,7 +470,7 @@ Bool LandClassCheck(LandClass class)
static Res landTrivInit(Land land, ArgList args)
{
AVERT(Land, land);
- AVER(ArgListCheck(args));
+ AVERT(ArgList, args);
UNUSED(args);
return ResOK;
}
@@ -555,7 +555,7 @@ static Bool landNoFind(Range rangeReturn, Range oldRangeReturn, Land land, Size
AVER(oldRangeReturn != NULL);
AVERT(Land, land);
UNUSED(size);
- AVER(FindDeleteCheck(findDelete));
+ AVERT(FindDelete, findDelete);
return ResUNIMPL;
}
@@ -567,7 +567,7 @@ static Res landNoFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRang
AVERT(Land, land);
UNUSED(size);
UNUSED(zoneSet);
- AVER(BoolCheck(high));
+ AVERT(Bool, high);
return ResUNIMPL;
}
@@ -606,7 +606,7 @@ DEFINE_CLASS(LandClass, class)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2014 Ravenbrook Limited .
+ * Copyright (C) 2014-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/mpm.c b/mps/code/mpm.c
index d3c32a66daf..aba1ac2f5cb 100644
--- a/mps/code/mpm.c
+++ b/mps/code/mpm.c
@@ -1,7 +1,7 @@
/* mpm.c: GENERAL MPM SUPPORT
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
* .purpose: Miscellaneous support for the implementation of the MPM
* and pool classes.
@@ -137,6 +137,16 @@ Bool AlignCheck(Align align)
}
+/* AccessSetCheck -- check that an access set is valid */
+
+Bool AccessSetCheck(AccessSet mode)
+{
+ CHECKL(mode < ((ULongest)1 << AccessLIMIT));
+ UNUSED(mode); /* see .check.unused */
+ return TRUE;
+}
+
+
#endif /* defined(AVER_AND_CHECK) */
@@ -638,7 +648,7 @@ Bool StringEqual(const char *s1, const char *s2)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index 6f34cd4e020..915f8d9b1f5 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -1,7 +1,7 @@
/* mpm.h: MEMORY POOL MANAGER DEFINITIONS
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
* .trans.bufferinit: The Buffer data structure has an Init field and
@@ -46,6 +46,7 @@ extern Bool FunCheck(Fun f);
extern Bool ShiftCheck(Shift shift);
extern Bool AttrCheck(Attr attr);
extern Bool RootVarCheck(RootVar rootVar);
+extern Bool AccessSetCheck(AccessSet mode);
/* Address/Size Interface -- see */
@@ -1053,7 +1054,7 @@ extern LandClass LandClassGet(void);
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj
index 21abc599f2c..30aad557d3b 100644
--- a/mps/code/mps.xcodeproj/project.pbxproj
+++ b/mps/code/mps.xcodeproj/project.pbxproj
@@ -285,7 +285,6 @@
3124CAFB156BE82000753214 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
3124CAFC156BE82900753214 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
3150AE53156ABA2500A6E22A /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
- 318DA8D21892B13B0089718C /* getoptl.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8D11892B13B0089718C /* getoptl.c */; };
318DA8D31892B27E0089718C /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
31A47BA4156C1E130039B1C2 /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; };
31D60007156D3C6200337B26 /* segsmss.c in Sources */ = {isa = PBXBuildFile; fileRef = 31D60006156D3C5F00337B26 /* segsmss.c */; };
@@ -327,7 +326,6 @@
31FCAE161769244F008C034C /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; };
31FCAE19176924D4008C034C /* scheme.c in Sources */ = {isa = PBXBuildFile; fileRef = 31FCAE18176924D4008C034C /* scheme.c */; };
6313D46918A400B200EB03EF /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
- 6313D46A18A400B200EB03EF /* getoptl.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8D11892B13B0089718C /* getoptl.c */; };
6313D47318A4028E00EB03EF /* djbench.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8CE1892B1210089718C /* djbench.c */; };
6313D47418A4029200EB03EF /* gcbench.c in Sources */ = {isa = PBXBuildFile; fileRef = 6313D46618A3FDC900EB03EF /* gcbench.c */; };
6313D47518A40C6300EB03EF /* fmtdytst.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAC7156BE48D00753214 /* fmtdytst.c */; };
@@ -1635,8 +1633,6 @@
317B3C2A1731830100F9A469 /* arg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arg.c; sourceTree = ""; };
318DA8CD1892B0F30089718C /* djbench */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = djbench; sourceTree = BUILT_PRODUCTS_DIR; };
318DA8CE1892B1210089718C /* djbench.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = djbench.c; sourceTree = ""; };
- 318DA8D01892B13B0089718C /* getopt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = getopt.h; sourceTree = ""; };
- 318DA8D11892B13B0089718C /* getoptl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = getoptl.c; sourceTree = ""; };
31A47BA3156C1E130039B1C2 /* mps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mps.c; sourceTree = ""; };
31A47BA5156C1E5E0039B1C2 /* ssixi3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ssixi3.c; sourceTree = ""; };
31C83ADD1786281C0031A0DB /* protxc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = protxc.h; sourceTree = ""; };
@@ -2267,8 +2263,6 @@
318DA8C21892B0B20089718C /* Benchmarks */ = {
isa = PBXGroup;
children = (
- 318DA8D01892B13B0089718C /* getopt.h */,
- 318DA8D11892B13B0089718C /* getoptl.c */,
318DA8CE1892B1210089718C /* djbench.c */,
6313D46618A3FDC900EB03EF /* gcbench.c */,
);
@@ -3909,7 +3903,6 @@
files = (
318DA8D31892B27E0089718C /* testlib.c in Sources */,
6313D47318A4028E00EB03EF /* djbench.c in Sources */,
- 318DA8D21892B13B0089718C /* getoptl.c in Sources */,
22561A9A18F426BB00372C66 /* testthrix.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -4018,7 +4011,6 @@
6313D47418A4029200EB03EF /* gcbench.c in Sources */,
6313D47518A40C6300EB03EF /* fmtdytst.c in Sources */,
6313D47618A40C7B00EB03EF /* fmtdy.c in Sources */,
- 6313D46A18A400B200EB03EF /* getoptl.c in Sources */,
22561A9B18F426F300372C66 /* testthrix.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index a7dec7495c1..283fbc6123e 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -8,7 +8,7 @@
* , and the internal MPM interfaces, as defined by
* . .purpose.check: It performs checking of the C client's
* usage of the MPS Interface. .purpose.thread: It excludes multiple
- * threads from the MPM by locking the Arena (see .thread-safety).
+ * threads from the MPM by locking the Arena (see ).
*
* .design:
*
diff --git a/mps/code/pool.c b/mps/code/pool.c
index 945a846edcb..f939bca84e9 100644
--- a/mps/code/pool.c
+++ b/mps/code/pool.c
@@ -1,7 +1,7 @@
/* pool.c: POOL IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2001 Global Graphics Software.
*
* DESIGN
@@ -328,7 +328,7 @@ Res PoolAccess(Pool pool, Seg seg, Addr addr,
AVERT(Seg, seg);
AVER(SegBase(seg) <= addr);
AVER(addr < SegLimit(seg));
- /* Can't check mode as there is no check method */
+ AVERT(AccessSet, mode);
/* Can't check MutatorFaultContext as there is no check method */
return (*pool->class->access)(pool, seg, addr, mode, context);
@@ -694,7 +694,7 @@ Bool PoolHasRange(Pool pool, Addr base, Addr limit)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/poolabs.c b/mps/code/poolabs.c
index 712f24152e5..30f5d0f999e 100644
--- a/mps/code/poolabs.c
+++ b/mps/code/poolabs.c
@@ -1,7 +1,7 @@
/* poolabs.c: ABSTRACT POOL CLASSES
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
* PURPOSE
@@ -334,7 +334,7 @@ Res PoolNoAccess(Pool pool, Seg seg, Addr addr,
AVERT(Seg, seg);
AVER(SegBase(seg) <= addr);
AVER(addr < SegLimit(seg));
- /* can't check AccessSet as there is no Check method */
+ AVERT(AccessSet, mode);
/* can't check context as there is no Check method */
UNUSED(mode);
UNUSED(context);
@@ -360,7 +360,7 @@ Res PoolSegAccess(Pool pool, Seg seg, Addr addr,
AVER(SegBase(seg) <= addr);
AVER(addr < SegLimit(seg));
AVER(SegPool(seg) == pool);
- /* can't check AccessSet as there is no Check method */
+ AVERT(AccessSet, mode);
/* can't check context as there is no Check method */
UNUSED(addr);
@@ -396,7 +396,7 @@ Res PoolSingleAccess(Pool pool, Seg seg, Addr addr,
AVER(SegBase(seg) <= addr);
AVER(addr < SegLimit(seg));
AVER(SegPool(seg) == pool);
- /* can't check AccessSet as there is no Check method */
+ AVERT(AccessSet, mode);
/* can't check context as there is no Check method */
arena = PoolArena(pool);
@@ -691,7 +691,7 @@ Size PoolNoSize(Pool pool)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c
index 01ca12ea46f..5bb0e6b9025 100644
--- a/mps/code/poolawl.c
+++ b/mps/code/poolawl.c
@@ -1,7 +1,7 @@
/* poolawl.c: AUTOMATIC WEAK LINKED POOL CLASS
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
*
* DESIGN
@@ -1206,6 +1206,7 @@ static Res AWLAccess(Pool pool, Seg seg, Addr addr,
AVER(SegBase(seg) <= addr);
AVER(addr < SegLimit(seg));
AVER(SegPool(seg) == pool);
+ AVERT(AccessSet, mode);
/* Attempt scanning a single reference if permitted */
if(AWLCanTrySingleAccess(PoolArena(pool), awl, seg, addr)) {
@@ -1375,7 +1376,7 @@ static Bool AWLCheck(AWL awl)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/protan.c b/mps/code/protan.c
index 1959e42395b..0e4771f18da 100644
--- a/mps/code/protan.c
+++ b/mps/code/protan.c
@@ -1,7 +1,7 @@
/* protan.c: ANSI MEMORY PROTECTION
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
*
* DESIGN
@@ -36,8 +36,7 @@ Size ProtGranularity(void)
void ProtSet(Addr base, Addr limit, AccessSet pm)
{
AVER(base < limit);
- /* .improve.protset.check: There is nor AccessSetCheck, so we */
- /* don't check it. */
+ AVERT(AccessSet, pm);
UNUSED(pm);
NOOP;
}
@@ -74,7 +73,7 @@ void ProtSync(Arena arena)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/protix.c b/mps/code/protix.c
index ea674ae53d5..a243b009491 100644
--- a/mps/code/protix.c
+++ b/mps/code/protix.c
@@ -1,7 +1,7 @@
/* protix.c: PROTECTION FOR UNIX
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
* Somewhat generic across different Unix systems. Shared between
* OS X, FreeBSD, and Linux.
@@ -66,6 +66,7 @@ void ProtSet(Addr base, Addr limit, AccessSet mode)
AVER(base < limit);
AVER(base != 0);
AVER(AddrOffset(base, limit) <= INT_MAX); /* should be redundant */
+ AVERT(AccessSet, mode);
/* Convert between MPS AccessSet and UNIX PROT thingies.
In this function, AccessREAD means protect against read accesses
@@ -122,7 +123,7 @@ Size ProtGranularity(void)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/protw3.c b/mps/code/protw3.c
index 30c3edc0975..a8dddd74fe2 100644
--- a/mps/code/protw3.c
+++ b/mps/code/protw3.c
@@ -1,7 +1,7 @@
/* protw3.c: PROTECTION FOR WIN32
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*/
#include "mpm.h"
@@ -26,6 +26,7 @@ void ProtSet(Addr base, Addr limit, AccessSet mode)
AVER(base < limit);
AVER(base != 0);
+ AVERT(AccessSet, mode);
newProtect = PAGE_EXECUTE_READWRITE;
if((mode & AccessWRITE) != 0)
@@ -140,7 +141,7 @@ void ProtSync(Arena arena)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/root.c b/mps/code/root.c
index 02f48b38e44..7a3e1205be2 100644
--- a/mps/code/root.c
+++ b/mps/code/root.c
@@ -139,7 +139,7 @@ Bool RootCheck(Root root)
CHECKL(root->protBase != (Addr)0);
CHECKL(root->protLimit != (Addr)0);
CHECKL(root->protBase < root->protLimit);
- /* there is no AccessSetCheck */
+ CHECKL(AccessSetCheck(root->pm));
} else {
CHECKL(root->protBase == (Addr)0);
CHECKL(root->protLimit == (Addr)0);
@@ -558,7 +558,7 @@ Bool RootOfAddr(Root *rootReturn, Arena arena, Addr addr)
void RootAccess(Root root, AccessSet mode)
{
AVERT(Root, root);
- /* Can't AVERT mode. */
+ AVERT(AccessSet, mode);
AVER((root->pm & mode) != AccessSetEMPTY);
AVER(mode == AccessWRITE); /* only write protection supported */
diff --git a/mps/code/seg.c b/mps/code/seg.c
index ab7414eaf4a..7007bca62b7 100644
--- a/mps/code/seg.c
+++ b/mps/code/seg.c
@@ -1,7 +1,7 @@
/* seg.c: SEGMENTS
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
* .design: The design for this module is .
*
@@ -529,7 +529,7 @@ Bool SegNextOfRing(Seg *segReturn, Arena arena, Pool pool, Ring next)
AVER_CRITICAL(segReturn != NULL); /* .seg.critical */
AVERT_CRITICAL(Arena, arena);
AVERT_CRITICAL(Pool, pool);
- AVER_CRITICAL(RingCheck(next));
+ AVERT_CRITICAL(Ring, next);
if (next == PoolSegRing(pool)) {
if (!PoolNext(&pool, arena, pool) ||
@@ -1224,7 +1224,7 @@ static void gcSegSetGrey(Seg seg, TraceSet grey)
Arena arena;
AVERT_CRITICAL(Seg, seg); /* .seg.method.check */
- AVER_CRITICAL(TraceSetCheck(grey)); /* .seg.method.check */
+ AVERT_CRITICAL(TraceSet, grey); /* .seg.method.check */
AVER(seg->rankSet != RankSetEMPTY);
gcseg = SegGCSeg(seg);
AVERT_CRITICAL(GCSeg, gcseg);
@@ -1264,7 +1264,7 @@ static void gcSegSetWhite(Seg seg, TraceSet white)
Addr addr, limit;
AVERT_CRITICAL(Seg, seg); /* .seg.method.check */
- AVER_CRITICAL(TraceSetCheck(white)); /* .seg.method.check */
+ AVERT_CRITICAL(TraceSet, white); /* .seg.method.check */
gcseg = SegGCSeg(seg);
AVERT_CRITICAL(GCSeg, gcseg);
AVER_CRITICAL(&gcseg->segStruct == seg);
@@ -1307,7 +1307,7 @@ static void gcSegSetRankSet(Seg seg, RankSet rankSet)
Arena arena;
AVERT_CRITICAL(Seg, seg); /* .seg.method.check */
- AVER_CRITICAL(RankSetCheck(rankSet)); /* .seg.method.check */
+ AVERT_CRITICAL(RankSet, rankSet); /* .seg.method.check */
AVER_CRITICAL(rankSet == RankSetEMPTY
|| RankSetIsSingle(rankSet)); /* .seg.method.check */
gcseg = SegGCSeg(seg);
@@ -1378,7 +1378,7 @@ static void gcSegSetRankSummary(Seg seg, RankSet rankSet, RefSet summary)
Arena arena;
AVERT_CRITICAL(Seg, seg); /* .seg.method.check */
- AVER_CRITICAL(RankSetCheck(rankSet)); /* .seg.method.check */
+ AVERT_CRITICAL(RankSet, rankSet); /* .seg.method.check */
AVER_CRITICAL(rankSet == RankSetEMPTY
|| RankSetIsSingle(rankSet)); /* .seg.method.check */
gcseg = SegGCSeg(seg);
@@ -1701,7 +1701,7 @@ void SegClassMixInNoSplitMerge(SegClass class)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/shield.c b/mps/code/shield.c
index 55625664ca7..8b73f8f488c 100644
--- a/mps/code/shield.c
+++ b/mps/code/shield.c
@@ -1,7 +1,7 @@
/* shield.c: SHIELD IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
*
* See: idea.shield, design.mps.shield.
*
@@ -105,6 +105,7 @@ static void protLower(Arena arena, Seg seg, AccessSet mode)
AVERT_CRITICAL(Arena, arena);
UNUSED(arena);
AVERT_CRITICAL(Seg, seg);
+ AVERT_CRITICAL(AccessSet, mode);
if (SegPM(seg) & mode) {
SegSetPM(seg, SegPM(seg) & ~mode);
@@ -191,6 +192,7 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode)
/* can't check seg. Nor can we check arena as that checks the */
/* segs in the cache. */
+ AVERT(AccessSet, mode);
AVER((SegSM(seg) & mode) == AccessSetEMPTY);
SegSetSM(seg, SegSM(seg) | mode); /* inv.prot.shield preserved */
@@ -204,6 +206,7 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode)
void (ShieldLower)(Arena arena, Seg seg, AccessSet mode)
{
/* Don't check seg or arena, see .seg.broken */
+ AVERT(AccessSet, mode);
AVER((SegSM(seg) & mode) == mode);
/* synced(seg) is not changed by the following
* preserving inv.unsynced.suspended
@@ -336,7 +339,7 @@ void (ShieldCover)(Arena arena, Seg seg)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * Copyright (C) 2001-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/trace.c b/mps/code/trace.c
index 7aeb70305c7..7e918513279 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -1,7 +1,7 @@
/* trace.c: GENERIC TRACER IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited.
+ * Copyright (c) 2001-2015 Ravenbrook Limited.
* See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
@@ -1188,6 +1188,7 @@ void TraceSegAccess(Arena arena, Seg seg, AccessSet mode)
AVERT(Arena, arena);
AVERT(Seg, seg);
+ AVERT(AccessSet, mode);
/* If it's a read access, then the segment must be grey for a trace */
/* which is flipped. */
@@ -1962,7 +1963,7 @@ Res TraceDescribe(Trace trace, mps_lib_FILE *stream, Count depth)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2014 Ravenbrook Limited
+ * Copyright (C) 2001-2015 Ravenbrook Limited
* .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
diff --git a/mps/design/bootstrap.txt b/mps/design/bootstrap.txt
new file mode 100644
index 00000000000..7eb79df1475
--- /dev/null
+++ b/mps/design/bootstrap.txt
@@ -0,0 +1,127 @@
+.. mode: -*- rst -*-
+
+Bootstrapping
+=============
+
+:Tag: design.mps.bootstrap
+:Author: Gareth Rees
+:Date: 2015-09-01
+:Status: incomplete design
+:Revision: $Id$
+:Copyright: See section `Copyright and License`_.
+:Index terms: pair: bootsrap; design
+
+
+Introduction
+------------
+
+_`.intro`: This explains how the MPS gets started.
+
+_`.readership`: Any MPS developer.
+
+_`.overview`: The job of the MPS is to allocate memory to a program.
+Before it can allocate memory, the MPS needs to create data structures
+to represent its internal state. But before it can create those data
+structures, it needs to allocate memory to store them in. This
+bootstrapping problem affects the MPS at several points, which are
+listed here, together with their solutions.
+
+
+Bootstrapping problems
+----------------------
+
+Virtual memory descriptor
+.........................
+
+_`.vm`: Before address space can be mapped into main memory, the
+virtual memory descriptor must be initialized. But before the virtual
+memory descriptor can be initialized, some address space must be
+mapped into main memory in order to store it. See
+`design.vm.req.bootstrap`_.
+
+_`.vm.sol`: The virtual memory descriptor is allocated initially on
+the stack, and then copied into its place in the chunk after the
+memory for it has been mapped. See `design.vm.sol.bootstrap`_.
+
+.. _design.vm.req.bootstrap: vm#req.bootstrap
+.. _design.vm.sol.bootstrap: vm#sol.bootstrap
+
+
+Arena descriptor
+................
+
+_`.arena`: Before chunks of address space can be reserved and mapped,
+the virtual memory arena descriptor must be initialized (so that the
+chunks can be added to the arena's chunk tree). But before a virtual
+memory arena descriptor can be initialized, address space must be
+reserved and mapped in order to store it.
+
+_`.arena.sol`: A small amount of address space is reserved and mapped
+directly via ``VMInit()`` and ``VMMap()`` (not via the chunk system)
+in order to provide enough memory for the arena descriptor.
+
+
+Arena's free land
+.................
+
+_`.land`: Before the arena can allocate memory, a range of addresses
+must be inserted into the arena's free land (so that the free land can
+hand out memory from this range). But before addresses can be inserted
+into the arena's free land, the arena must be able to allocate memory
+(to store the nodes in the tree representing those addresses).
+
+_`.land.sol`: The arena has two "back door" mechanisms and uses them
+in combination. First, there is a mechanism for allocating a block of
+memory directly from a chunk, bypassing the free land; second, the MFS
+pool class has a mechanism for extending it with a block of memory.
+
+
+Document History
+----------------
+
+- 2015-09-01 GDR_ Initial draft.
+
+.. _GDR: http://www.ravenbrook.com/consultants/gdr/
+
+
+Copyright and License
+---------------------
+
+Copyright © 2015 Ravenbrook Limited. 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:
+
+#. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+#. 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.
+
+#. 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.**
diff --git a/mps/design/guide.hex.trans.txt b/mps/design/guide.hex.trans.txt
index 95c533f6bc8..8120f6e53e5 100644
--- a/mps/design/guide.hex.trans.txt
+++ b/mps/design/guide.hex.trans.txt
@@ -22,10 +22,11 @@ hexadecimal digits.
_`.readership`: This document is intended for anyone devising
arbitrary constants which may appear in hex-dumps.
-_`.sources`: This transliteration was supplied by RHSK in
-`mail.richardk.1997-04-07.13-44`_.
-
-.. _mail.richardk.1997-04-07.13-44: https://info.ravenbrook.com/project/mps/mail/1997/04/07/13-44/0.txt
+_`.sources`: This transliteration was supplied by Richard Kistruck
+[RHSK-1997-04-07]_ based on magic number encodings for object signatures
+used by Richard Brooksby [RB-1996-02-12]_, the existence of which was
+inspired by the structure marking used in the Multics operating system
+[THVV-1995]_.
Transliteration
@@ -78,8 +79,8 @@ _`.trans.t`: T is an exception to `.numbers`_, but is such a common
letter that it deserves it.
-4. Notes
---------
+Notes
+-----
_`.change`: This transliteration differs from the old transliteration
used for signatures (see design.mps.sig_), as follows: J:6->1;
@@ -106,6 +107,33 @@ selected (by capitalisation), e.g.::
#define SpaceSig ((Sig)0x5195BACE) /* SIGnature SPACE */
+References
+----------
+
+.. [RB-1996-02-12]
+ "Signature magic numbers" (e-mail message);
+ `Richard Brooksby`_;
+ Harlequin;
+ 1996-12-02 12:05:30Z.
+
+.. _`Richard Brooksby`: mailto:rb@ravenbrook.com
+
+.. [RHSK-1997-04-07]
+ "Alpha-to-Hex v1.0 beta";
+ Richard Kistruck;
+ Ravenbrook;
+ 1997-04-07 14:42:02+0100;
+ .
+
+.. [THVV-1995]
+ "Structure Marking";
+ Tom Van Vleck;
+ multicians.org_;
+ .
+
+.. _multicians.org: http://www.multicians.org/
+
+
Document History
----------------
2013-05-10 RB_ Converted to reStructuredText and imported to MPS design.
diff --git a/mps/design/guide.review.txt b/mps/design/guide.review.txt
new file mode 100644
index 00000000000..b1298b26b90
--- /dev/null
+++ b/mps/design/guide.review.txt
@@ -0,0 +1,96 @@
+.. mode: -*- rst -*-
+
+Review checklist
+================
+
+:Tag: guide.review
+:Status: incomplete documentation
+:Author: Gareth Rees
+:Organization: Ravenbrook Limited
+:Date: 2015-08-10
+:Revision: $Id$
+:Copyright: See section `Copyright and License`_.
+:Index terms: pair: review; checklist
+
+
+Introduction
+------------
+
+_`.scope`: This document contains a list of checks to apply when
+reviewing code or other documents in the Memory Pool System.
+
+_`.readership`: This document is intended for reviewers.
+
+_`.example`: The "example" links are issues caused by a failure to
+apply the checklist item.
+
+_`.diff`: Some items in the checklist are particularly susceptible to
+being ignored if one reviews only via the version control diff. These
+items refer to this tag.
+
+
+Checklist
+---------
+
+_`.test`: If a new feature has been added to the code, is there a test
+case? Example: job003923_.
+
+.. _job003923: http://www.ravenbrook.com/project/mps/issue/job003923/
+
+_`.unwind`: If code has been updated in a function that unwinds its
+state in failure cases, have the failure cases been updated to
+correspond? Example: job003922_. See `.diff`_.
+
+.. _job003922: http://www.ravenbrook.com/project/mps/issue/job003922/
+
+
+
+Document History
+----------------
+
+2015-08-10 GDR_ Created.
+
+.. _GDR: http://www.ravenbrook.com/consultants/gdr/
+
+
+Copyright and License
+---------------------
+
+Copyright © 2015 Ravenbrook Limited. 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:
+
+#. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+#. 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.
+
+#. 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.**
diff --git a/mps/design/index.txt b/mps/design/index.txt
index bc08dbc476e..7e48b625319 100644
--- a/mps/design/index.txt
+++ b/mps/design/index.txt
@@ -44,6 +44,7 @@ alloc-frame_ Allocation frame protocol
an_ Generic modules
arena_ Arena
arenavm_ Virtual memory arena
+bootstrap_ Bootstrapping
bt_ Bit tables
buffer_ Allocation buffers and allocation points
cbs_ Coalescing block structures
@@ -61,6 +62,7 @@ freelist_ Free list allocator
guide.hex.trans_ Transliterating the alphabet into hexadecimal
guide.impl.c.format_ Coding standard: conventions for the general format of C source code in the MPS
guide.impl.c.naming_ Coding standard: conventions for internal names
+guide.review_ Review checklist
interface-c_ C interface
io_ I/O subsystem
keyword-arguments_ Keyword arguments
@@ -121,6 +123,7 @@ writef_ The WriteF function
.. _an: an
.. _arena: arena
.. _arenavm: arenavm
+.. _bootstrap: bootstrap
.. _bt: bt
.. _buffer: buffer
.. _cbs: cbs
@@ -138,6 +141,7 @@ writef_ The WriteF function
.. _guide.hex.trans: guide.hex.trans
.. _guide.impl.c.format: guide.impl.c.format
.. _guide.impl.c.naming: guide.impl.c.naming
+.. _guide.review: guide.review
.. _interface-c: interface-c
.. _io: io
.. _keyword-arguments: keyword-arguments
diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst
index e6b2adbd61a..b8da67a4333 100644
--- a/mps/manual/source/design/index.rst
+++ b/mps/manual/source/design/index.rst
@@ -8,6 +8,7 @@ Design
abq
an
+ bootstrap
cbs
config
critical-path
@@ -17,6 +18,7 @@ Design
guide.hex.trans
guide.impl.c.format
guide.impl.c.naming
+ guide.review
interface-c
keyword-arguments
land
diff --git a/mps/manual/source/pool/snc.rst b/mps/manual/source/pool/snc.rst
index 49a43fe37ab..d39a392c614 100644
--- a/mps/manual/source/pool/snc.rst
+++ b/mps/manual/source/pool/snc.rst
@@ -39,7 +39,7 @@ SNC properties
* Supports allocation via :term:`allocation points` only. If an
allocation point is created in an SNC pool, the call to
- :c:func:`mps_ap_create_k` requires one keyword argument,
+ :c:func:`mps_ap_create_k` accepts one optional keyword argument,
:c:macro:`MPS_KEY_RANK`.
* Does not support deallocation via :c:func:`mps_free`.
@@ -112,11 +112,11 @@ SNC interface
} MPS_ARGS_END(args);
When creating an :term:`allocation point` on an SNC pool,
- :c:func:`mps_ap_create_k` requires one keyword argument:
+ :c:func:`mps_ap_create_k` accepts one optional keyword argument:
- * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`) specifies
- the :term:`rank` of references in objects allocated on this
- allocation point. It must be :c:func:`mps_rank_exact`.
+ * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default
+ :c:func:`mps_rank_exact`) specifies the :term:`rank` of references
+ in objects allocated on this allocation point.
For example::
diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst
index b9007932dae..cb820397281 100644
--- a/mps/manual/source/release.rst
+++ b/mps/manual/source/release.rst
@@ -217,7 +217,7 @@ Other changes
:c:func:`mps_lib_assert_fail`.
#. Garbage collection performance is substantially improved in the
- situation where the arena has been extended many time. Critical
+ situation where the arena has been extended many times. Critical
operations now take time logarithmic in the number of times the
arena has been extended (rather than linear, as in version 1.113
and earlier). See job003554_.
diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst
index e13e79a9735..1120b868897 100644
--- a/mps/manual/source/topic/error.rst
+++ b/mps/manual/source/topic/error.rst
@@ -265,6 +265,41 @@ this documentation.
:c:type:`mps_fmt_t` for this argument.
+``global.c: RingIsSingle(&arena->chainRing)``
+
+ The client program called :c:func:`mps_arena_destroy` without
+ destroying all the :term:`generation chains` belonging to the
+ arena. It is necessary to call :c:func:`mps_chain_destroy` first.
+
+
+``global.c: RingIsSingle(&arena->formatRing)``
+
+ The client program called :c:func:`mps_arena_destroy` without
+ destroying all the :term:`object formats` belonging to the arena.
+ It is necessary to call :c:func:`mps_fmt_destroy` first.
+
+
+``global.c: RingIsSingle(&arena->rootRing)``
+
+ The client program called :c:func:`mps_arena_destroy` without
+ destroying all the :term:`roots` belonging to the arena.
+ It is necessary to call :c:func:`mps_root_destroy` first.
+
+
+``global.c: RingIsSingle(&arena->threadRing)``
+
+ The client program called :c:func:`mps_arena_destroy` without
+ deregistering all the :term:`threads` belonging to the arena.
+ It is necessary to call :c:func:`mps_thread_dereg` first.
+
+
+``global.c: RingLength(&arenaGlobals->poolRing) == 5``
+
+ The client program called :c:func:`mps_arena_destroy` without
+ destroying all the :term:`pools` belonging to the arena.
+ It is necessary to call :c:func:`mps_pool_destroy` first.
+
+
``lockix.c: res == 0``
``lockw3.c: lock->claims == 0``
@@ -299,13 +334,19 @@ this documentation.
condition?
-``ring.c: ring->next == ring``
+``poolsnc.c: foundSeg``
- The client program destroyed an MPS data structure without having
- destroyed all the data structures that it owns first. For example,
- it destroyed an arena without first destroying all pools in that
- arena, or it destroyed a pool without first destroying all
- allocation points created on that pool.
+ The client program passed an incorrect ``frame`` argument to
+ :c:func:`mps_ap_frame_pop`. This argument must be the result from
+ a previous call to :c:func:`mps_ap_frame_push` on the same
+ allocation point.
+
+
+``seg.c: gcseg->buffer == NULL``
+
+ The client program destroyed pool without first destroying all the
+ allocation points created on that pool. The allocation points must
+ be destroyed first.
``trace.c: ss->rank < RankEXACT``
diff --git a/mps/manual/source/topic/format.rst b/mps/manual/source/topic/format.rst
index 2fe2b4a4e30..7db5c8a1178 100644
--- a/mps/manual/source/topic/format.rst
+++ b/mps/manual/source/topic/format.rst
@@ -179,6 +179,20 @@ There are some cautions to be observed when using in-band headers:
#. Not all :term:`pool classes` support objects with in-band headers.
See the documentation for the pool class.
+.. note::
+
+ A :term:`client program` that allocates objects with
+ :term:`in-band headers` has to make a choice about how to
+ represent references to those objects. It can represent them using
+ :term:`base pointers` (which is convenient for allocation, since
+ :c:func:`mps_reserve` returns a base pointer, but requires
+ decoding when scanning) or using :term:`client pointers` (which is
+ convenient for scanning, since the :term:`scan method` takes a
+ client pointer, but requires encoding on allocation). Either
+ approach will work, but :term:`client pointers` are normally the
+ better choice, since scanning is normally more
+ performance-critical than allocation.
+
.. index::
pair: object format; cautions
diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst
index c9f71e3b503..6b4c4a1d396 100644
--- a/mps/manual/source/topic/scanning.rst
+++ b/mps/manual/source/topic/scanning.rst
@@ -361,9 +361,9 @@ Scanning interface
.. c:function:: MPS_FIX_CALL(ss, call)
- Call a function from within a :term:`scan method`, between
- :c:func:`MPS_SCAN_BEGIN` and :c:func:`MPS_SCAN_END`, passing
- the :term:`scan state` correctly.
+ Call a function to do some scanning, from within a :term:`scan
+ method`, between :c:func:`MPS_SCAN_BEGIN` and
+ :c:func:`MPS_SCAN_END`, passing the :term:`scan state` correctly.
``ss`` is the scan state that was passed to the scan method.
@@ -377,6 +377,9 @@ Scanning interface
must wrap the call with :c:func:`MPS_FIX_CALL` to ensure that the
scan state is passed correctly.
+ The function being called must use :c:func:`MPS_SCAN_BEGIN` and
+ :c:func:`MPS_SCAN_END` appropriately.
+
In example below, the scan method ``obj_scan`` fixes the object's
``left`` and ``right`` references, but delegates the scanning of
references inside the object's ``data`` member to the function
@@ -406,9 +409,11 @@ Scanning interface
.. warning::
- Use of :c:func:`MPS_FIX_CALL` is best avoided, as it forces
- values out of registers. The gains in simplicity of the code
- need to be measured against the loss in performance.
+ Use of :c:func:`MPS_FIX_CALL` is best avoided, as it may
+ force values out of registers (depending on compiler
+ optimisations such as inlining). The gains in simplicity of
+ the code ought to be measured against the loss in
+ performance.
.. index::
diff --git a/mps/test/README b/mps/test/README
index 18bc2ed675e..214186d7fe0 100644
--- a/mps/test/README
+++ b/mps/test/README
@@ -13,7 +13,7 @@ From the test directory::
PLATFORM=lii6ll # substitute your platform
CODE=../code # code directory of the branch you are testing
- make -C $CODE -f $PLATFORM.gmk VARIETY=cool $PLATFORM/cool/mps.o
+ make -B -C $CODE -f $PLATFORM.gmk VARIETY=cool $PLATFORM/cool/mps.o
alias qa="perl test/qa -i $CODE -l $CODE/$PLATFORM/cool/mps.o"
qa clib
qa run function/5.c
@@ -27,3 +27,18 @@ so you can debug it with::
Or ``gdb`` instead of ``lldb``. MMQA sets its own assertion handler,
so you'll probably want to set a breakpoint on mmqa_assert_handler.
+
+
+Testing on OS X
+---------------
+
+From the test directory, build mpslib.a using the Xcode project::
+
+ xcodebuild -project ../code/mps.xcodeproj -target mps
+
+(You can also use "make" from the project root.) Then::
+
+ perl test/qa -i ../code -l ../code/xc/Debug/libmps.a clib
+ perl test/qa -i ../code -l ../code/xc/Debug/libmps.a run function/232.c
+
+etc. See "Testing on Unix" above.
diff --git a/mps/test/function/121.c b/mps/test/function/121.c
index 263fa705594..c5780e23ee7 100644
--- a/mps/test/function/121.c
+++ b/mps/test/function/121.c
@@ -11,50 +11,56 @@ END_HEADER
#include "testlib.h"
#include "mpsavm.h"
-#include "mpscmv.h"
-
-
-void *stackpointer;
+#include "mpsacl.h"
mps_arena_t arena;
-mps_thr_t thread;
-mps_pool_t pool;
-mps_pool_t pools[100];
+static char buffer[1024 * 1024];
static void test(void)
{
+ mps_res_t res, prev_res = MPS_RES_OK;
int i;
- for (i = 64; i >= 0; i--) {
- mps_res_t res;
+
+ /* VM arenas round up small sizes and so creation must succeed. */
+ for (i = 1024; i >= 0; i -= i/17 + 1) {
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 1024 * i);
+ die(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
+ "mps_arena_create");
+ } MPS_ARGS_END(args);
+ mps_arena_destroy(arena);
+ }
- comment("Trying arena of %d kB.", i);
- res = mps_arena_create(&arena, mps_arena_class_vm(), (size_t)(1024*i));
+ /* Client arenas have to work within the memory they are given and
+ * so must fail at some point. */
+ for (i = 1024; i >= 0; i -= i/17 + 1) {
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_CL_BASE, buffer);
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 1024 * i);
+ res = mps_arena_create_k(&arena, mps_arena_class_cl(), args);
+ } MPS_ARGS_END(args);
if (res == MPS_RES_OK) {
- res = mps_thread_reg(&thread, arena);
- if (res == MPS_RES_OK) {
- mps_thread_dereg(thread);
- } else {
- if (res != MPS_RES_MEMORY) {
- error("Wrong error code, %d, for mps_thread_reg.", res);
- }
+ if (prev_res != MPS_RES_OK) {
+ error("Success with smaller size.");
}
mps_arena_destroy(arena);
} else {
- report_res("arena_create", res);
if (res != MPS_RES_MEMORY) {
+ report_res("arena_create", res);
error("Wrong error code.");
}
}
+ prev_res = res;
+ }
+ if (res != MPS_RES_MEMORY) {
+ error("Wrong error code.");
}
}
int main(void)
{
- void *m;
- stackpointer=&m; /* hack to get stack pointer */
-
easy_tramp(test);
pass();
return 0;
From 46b1f31fee37df3aa235864cbdde2e8b44aac903 Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Fri, 12 Feb 2016 15:22:34 +0000
Subject: [PATCH 069/759] Separating arenaenter from stack_context_begin and
arenaleave from stack_context_end as they are not conceptually nested that
way.
Copied from Perforce
Change: 189446
ServerID: perforce.ravenbrook.com
---
mps/code/mpsi.c | 18 ++++++++++++++++++
mps/code/ss.h | 24 ++++++++++++------------
2 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index eb4bc63a42c..b27f26adafd 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -231,9 +231,11 @@ void mps_arena_clamp(mps_arena_t arena)
void mps_arena_release(mps_arena_t arena)
{
+ ArenaEnter(arena);
STACK_CONTEXT_BEGIN(arena) {
ArenaRelease(ArenaGlobals(arena));
} STACK_CONTEXT_END(arena);
+ ArenaLeave(arena);
}
@@ -271,19 +273,23 @@ void mps_arena_unsafe_restore_protection(mps_arena_t arena)
mps_res_t mps_arena_start_collect(mps_arena_t arena)
{
Res res;
+ ArenaEnter(arena);
STACK_CONTEXT_BEGIN(arena) {
res = ArenaStartCollect(ArenaGlobals(arena),
TraceStartWhyCLIENTFULL_INCREMENTAL);
} STACK_CONTEXT_END(arena);
+ ArenaLeave(arena);
return (mps_res_t)res;
}
mps_res_t mps_arena_collect(mps_arena_t arena)
{
Res res;
+ ArenaEnter(arena);
STACK_CONTEXT_BEGIN(arena) {
res = ArenaCollect(ArenaGlobals(arena), TraceStartWhyCLIENTFULL_BLOCK);
} STACK_CONTEXT_END(arena);
+ ArenaLeave(arena);
return (mps_res_t)res;
}
@@ -292,9 +298,11 @@ mps_bool_t mps_arena_step(mps_arena_t arena,
double multiplier)
{
Bool b;
+ ArenaEnter(arena);
STACK_CONTEXT_BEGIN(arena) {
b = ArenaStep(ArenaGlobals(arena), interval, multiplier);
} STACK_CONTEXT_END(arena);
+ ArenaLeave(arena);
return b;
}
@@ -734,6 +742,7 @@ mps_res_t mps_alloc(mps_addr_t *p_o, mps_pool_t pool, size_t size)
AVER(TESTT(Pool, pool));
arena = PoolArena(pool);
+ ArenaEnter(arena);
STACK_CONTEXT_BEGIN(arena) {
ArenaPoll(ArenaGlobals(arena)); /* .poll */
@@ -750,6 +759,7 @@ mps_res_t mps_alloc(mps_addr_t *p_o, mps_pool_t pool, size_t size)
res = PoolAlloc(&p, pool, size, FALSE);
} STACK_CONTEXT_END(arena);
+ ArenaLeave(arena);
if (res != ResOK)
return (mps_res_t)res;
@@ -1041,6 +1051,7 @@ mps_res_t mps_ap_fill(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size)
AVER(TESTT(Buffer, buf));
arena = BufferArena(buf);
+ ArenaEnter(arena);
STACK_CONTEXT_BEGIN(arena) {
ArenaPoll(ArenaGlobals(arena)); /* .poll */
@@ -1053,6 +1064,7 @@ mps_res_t mps_ap_fill(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size)
res = BufferFill(&p, buf, size, FALSE);
} STACK_CONTEXT_END(arena);
+ ArenaLeave(arena);
if (res != ResOK)
return (mps_res_t)res;
@@ -1073,6 +1085,7 @@ mps_res_t mps_ap_fill_with_reservoir_permit(mps_addr_t *p_o, mps_ap_t mps_ap,
AVER(TESTT(Buffer, buf));
arena = BufferArena(buf);
+ ArenaEnter(arena);
STACK_CONTEXT_BEGIN(arena) {
ArenaPoll(ArenaGlobals(arena)); /* .poll */
@@ -1085,6 +1098,7 @@ mps_res_t mps_ap_fill_with_reservoir_permit(mps_addr_t *p_o, mps_ap_t mps_ap,
res = BufferFill(&p, buf, size, TRUE);
} STACK_CONTEXT_END(arena);
+ ArenaLeave(arena);
if (res != ResOK)
return (mps_res_t)res;
@@ -1874,10 +1888,12 @@ mps_res_t mps_ap_alloc_pattern_end(mps_ap_t mps_ap,
arena = BufferArena(BufferOfAP(mps_ap));
+ ArenaEnter(arena);
STACK_CONTEXT_BEGIN(arena) {
res = BufferRampEnd(BufferOfAP(mps_ap));
ArenaPoll(ArenaGlobals(arena)); /* .poll */
} STACK_CONTEXT_END(arena);
+ ArenaLeave(arena);
return (mps_res_t)res;
}
@@ -1892,10 +1908,12 @@ mps_res_t mps_ap_alloc_pattern_reset(mps_ap_t mps_ap)
arena = BufferArena(BufferOfAP(mps_ap));
+ ArenaEnter(arena);
STACK_CONTEXT_BEGIN(arena) {
BufferRampReset(BufferOfAP(mps_ap));
ArenaPoll(ArenaGlobals(arena)); /* .poll */
} STACK_CONTEXT_END(arena);
+ ArenaLeave(arena);
return MPS_RES_OK;
}
diff --git a/mps/code/ss.h b/mps/code/ss.h
index ad7ead0c751..7e20c8aac8e 100644
--- a/mps/code/ss.h
+++ b/mps/code/ss.h
@@ -24,23 +24,23 @@ typedef struct StackContextStruct {
} StackContextStruct;
-/* STACK_CONTEXT_BEGIN -- enter arena and save context */
+/* STACK_CONTEXT_BEGIN -- save context */
-#define STACK_CONTEXT_BEGIN(arena) BEGIN \
- StackContextStruct _sc; \
- ArenaEnter(arena); \
- STACK_CONTEXT_SAVE(&_sc); \
- AVER(arena->scAtArenaEnter == NULL); \
- arena->scAtArenaEnter = &_sc; \
- BEGIN
+#define STACK_CONTEXT_BEGIN(arena) \
+ BEGIN \
+ StackContextStruct _sc; \
+ STACK_CONTEXT_SAVE(&_sc); \
+ AVER(arena->scAtArenaEnter == NULL); \
+ arena->scAtArenaEnter = &_sc; \
+ BEGIN
/* STACK_CONTEXT_END -- clear context and leave arena */
-#define STACK_CONTEXT_END(arena) END; \
- AVER(arena->scAtArenaEnter != NULL); \
- arena->scAtArenaEnter = NULL; \
- ArenaLeave(arena); \
+#define STACK_CONTEXT_END(arena) \
+ END; \
+ AVER(arena->scAtArenaEnter != NULL); \
+ arena->scAtArenaEnter = NULL; \
END
From 407f25aa504311a9965234f134f717c4689d56ca Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Tue, 1 Mar 2016 01:34:08 +0000
Subject: [PATCH 070/759] Branching master to branch/2016-03-01/mvff-control.
Copied from Perforce
Change: 189452
ServerID: perforce.ravenbrook.com
From be60ead78fa0c5c3e5b97a755b0597107dc0e595 Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Tue, 1 Mar 2016 01:38:28 +0000
Subject: [PATCH 071/759] Replacing mv with mvff as the arena control pool.
Copied from Perforce
Change: 189459
ServerID: perforce.ravenbrook.com
---
mps/code/arena.c | 12 ++++----
mps/code/global.c | 5 ++--
mps/code/mpmst.h | 59 +++++++++++++++++++++----------------
mps/code/poolmv.c | 27 +++++++++++++++--
mps/code/poolmv.h | 3 ++
mps/code/poolmvff.c | 38 +++++-------------------
mps/code/poolmvff.h | 72 +++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 147 insertions(+), 69 deletions(-)
create mode 100644 mps/code/poolmvff.h
diff --git a/mps/code/arena.c b/mps/code/arena.c
index 519a85d735b..10985ad9ab6 100644
--- a/mps/code/arena.c
+++ b/mps/code/arena.c
@@ -6,7 +6,7 @@
* .sources: is the main design document. */
#include "tract.h"
-#include "poolmv.h"
+#include "poolmvff.h"
#include "mpm.h"
#include "cbs.h"
#include "bt.h"
@@ -17,7 +17,7 @@
SRCID(arena, "$Id$");
-#define ArenaControlPool(arena) MVPool(&(arena)->controlPoolStruct)
+#define ArenaControlPool(arena) MVFFPool(&(arena)->controlPoolStruct)
#define ArenaCBSBlockPool(arena) MFSPool(&(arena)->freeCBSBlockPoolStruct)
#define ArenaFreeLand(arena) CBSLand(&(arena)->freeLandStruct)
@@ -137,7 +137,7 @@ Bool ArenaCheck(Arena arena)
CHECKL(BoolCheck(arena->poolReady));
if (arena->poolReady) { /* */
- CHECKD(MV, &arena->controlPoolStruct);
+ CHECKD(MVFF, &arena->controlPoolStruct);
CHECKD(Reservoir, &arena->reservoirStruct);
}
@@ -469,8 +469,8 @@ Res ControlInit(Arena arena)
AVER(!arena->poolReady);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, CONTROL_EXTEND_BY);
- res = PoolInit(MVPool(&arena->controlPoolStruct), arena,
- PoolClassMV(), args);
+ res = PoolInit(ArenaControlPool(arena), arena,
+ PoolClassMVFF(), args);
} MPS_ARGS_END(args);
if (res != ResOK)
return res;
@@ -486,7 +486,7 @@ void ControlFinish(Arena arena)
AVERT(Arena, arena);
AVER(arena->poolReady);
arena->poolReady = FALSE;
- PoolFinish(MVPool(&arena->controlPoolStruct));
+ PoolFinish(ArenaControlPool(arena));
}
diff --git a/mps/code/global.c b/mps/code/global.c
index 354adb54a9a..b7070ec77da 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -507,10 +507,9 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals)
* 0. arena->freeCBSBlockPoolStruct
* 1. arena->reservoirStruct
* 2. arena->controlPoolStruct
- * 3. arena->controlPoolStruct.blockPoolStruct
- * 4. arena->controlPoolStruct.spanPoolStruct
+ * 3. arena->controlPoolStruct.cbsBlockPoolStruct
*/
- AVER(RingLength(&arenaGlobals->poolRing) == 5);
+ AVER(RingLength(&arenaGlobals->poolRing) == 4);
}
diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h
index a798cc71fc4..6cfa15b15ff 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -141,30 +141,6 @@ typedef struct MFSStruct { /* MFS outer structure */
} MFSStruct;
-/* MVStruct -- MV (Manual Variable) pool outer structure
- *
- * .mv: See , .
- *
- * The MV pool outer structure is declared here because it is the
- * control pool structure which is inlined in the arena. Normally,
- * pool outer structures are declared with the pools. */
-
-#define MVSig ((Sig)0x5193B999) /* SIGnature MV */
-
-typedef struct MVStruct { /* MV pool outer structure */
- PoolStruct poolStruct; /* generic structure */
- MFSStruct blockPoolStruct; /* for managing block descriptors */
- MFSStruct spanPoolStruct; /* for managing span descriptors */
- Size extendBy; /* segment size to extend pool by */
- Size avgSize; /* client estimate of allocation size */
- Size maxSize; /* client estimate of maximum size */
- Size free; /* free space in pool */
- Size lost; /* */
- RingStruct spans; /* span chain */
- Sig sig; /* */
-} MVStruct;
-
-
/* ReservoirStruct -- Reservoir structure
*
* .reservoir: See , .
@@ -696,9 +672,40 @@ typedef struct FreelistStruct {
} FreelistStruct;
+/* MVFFStruct -- MVFF (Manual Variable First Fit) pool outer structure
+ *
+ * The signature is placed at the end, see
+ *
+ *
+ * The MVFF pool outer structure is declared here because it is the
+ * control pool structure which is inlined in the arena. Normally,
+ * pool outer structures are declared with the pools.
+ */
+
+#define MVFFSig ((Sig)0x5193FFF9) /* SIGnature MVFF */
+
+typedef struct MVFFStruct *MVFF;
+typedef struct MVFFStruct { /* MVFF pool outer structure */
+ PoolStruct poolStruct; /* generic structure */
+ LocusPrefStruct locusPrefStruct; /* the preferences for allocation */
+ Size extendBy; /* size to extend pool by */
+ Size avgSize; /* client estimate of allocation size */
+ double spare; /* spare space fraction, see MVFFReduce */
+ MFSStruct cbsBlockPoolStruct; /* stores blocks for CBSs */
+ CBSStruct totalCBSStruct; /* all memory allocated from the arena */
+ CBSStruct freeCBSStruct; /* free memory (primary) */
+ FreelistStruct flStruct; /* free memory (secondary, for emergencies) */
+ FailoverStruct foStruct; /* free memory (fail-over mechanism) */
+ Bool firstFit; /* as opposed to last fit */
+ Bool slotHigh; /* prefers high part of large block */
+ Sig sig; /* */
+} MVFFStruct;
+
+
/* ArenaStruct -- generic arena
*
- * See . */
+ * See .
+ */
#define ArenaSig ((Sig)0x519A6E4A) /* SIGnature ARENA */
@@ -709,7 +716,7 @@ typedef struct mps_arena_s {
ArenaClass class; /* arena class structure */
Bool poolReady; /* */
- MVStruct controlPoolStruct; /* */
+ MVFFStruct controlPoolStruct; /* */
ReservoirStruct reservoirStruct; /* */
diff --git a/mps/code/poolmv.c b/mps/code/poolmv.c
index 19b3c2bb443..2190e03e198 100644
--- a/mps/code/poolmv.c
+++ b/mps/code/poolmv.c
@@ -4,9 +4,6 @@
* Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
- * **** RESTRICTION: This pool may not allocate from the arena control
- * pool, since it is used to implement that pool.
- *
* An observation: Freeing memory introduces more information
* into the system than allocating it. This causes the problem
* described in note 2.
@@ -34,6 +31,30 @@
SRCID(poolmv, "$Id$");
+/* MVStruct -- MV (Manual Variable) pool outer structure
+ *
+ * .mv: See , .
+ *
+ * The signature is placed at the end, see
+ *
+ */
+
+#define MVSig ((Sig)0x5193B999) /* SIGnature MV */
+
+typedef struct MVStruct { /* MV pool outer structure */
+ PoolStruct poolStruct; /* generic structure */
+ MFSStruct blockPoolStruct; /* for managing block descriptors */
+ MFSStruct spanPoolStruct; /* for managing span descriptors */
+ Size extendBy; /* segment size to extend pool by */
+ Size avgSize; /* client estimate of allocation size */
+ Size maxSize; /* client estimate of maximum size */
+ Size free; /* free space in pool */
+ Size lost; /* */
+ RingStruct spans; /* span chain */
+ Sig sig; /* */
+} MVStruct;
+
+
#define mvBlockPool(mv) MFSPool(&(mv)->blockPoolStruct)
#define mvSpanPool(mv) MFSPool(&(mv)->spanPoolStruct)
diff --git a/mps/code/poolmv.h b/mps/code/poolmv.h
index 01c5b9ebd73..5229726583e 100644
--- a/mps/code/poolmv.h
+++ b/mps/code/poolmv.h
@@ -4,6 +4,9 @@
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
+ * FIXME: This header is no longer necessary since MV is no longer
+ * used internally.
+ *
* .purpose: This is the interface to the manual-variable pool class.
*
* .mv: Manual-variable pools manage variably-sized blocks of memory
diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c
index 22b6d004f68..cc7b59fe6a6 100644
--- a/mps/code/poolmvff.c
+++ b/mps/code/poolmvff.c
@@ -4,6 +4,9 @@
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
+ * **** RESTRICTION: This pool may not allocate from the arena control
+ * pool, since it is used to implement that pool.
+ *
* .purpose: This is a pool class for manually managed objects of
* variable size where address-ordered first fit is an appropriate
* policy. Provision is made to allocate in reverse.
@@ -24,6 +27,7 @@
#include "freelist.h"
#include "mpm.h"
#include "mpscmvff.h"
+#include "poolmvff.h"
#include "mpscmfs.h"
#include "poolmfs.h"
@@ -33,35 +37,10 @@ SRCID(poolmvff, "$Id$");
/* Would go in poolmvff.h if the class had any MPS-internal clients. */
extern PoolClass PoolClassMVFF(void);
-
-/* MVFFStruct -- MVFF (Manual Variable First Fit) pool outer structure
- *
- * The signature is placed at the end, see
- *
- */
-
-#define MVFFSig ((Sig)0x5193FFF9) /* SIGnature MVFF */
-
-typedef struct MVFFStruct *MVFF;
-typedef struct MVFFStruct { /* MVFF pool outer structure */
- PoolStruct poolStruct; /* generic structure */
- LocusPrefStruct locusPrefStruct; /* the preferences for allocation */
- Size extendBy; /* size to extend pool by */
- Size avgSize; /* client estimate of allocation size */
- double spare; /* spare space fraction, see MVFFReduce */
- MFSStruct cbsBlockPoolStruct; /* stores blocks for CBSs */
- CBSStruct totalCBSStruct; /* all memory allocated from the arena */
- CBSStruct freeCBSStruct; /* free memory (primary) */
- FreelistStruct flStruct; /* free memory (secondary, for emergencies) */
- FailoverStruct foStruct; /* free memory (fail-over mechanism) */
- Bool firstFit; /* as opposed to last fit */
- Bool slotHigh; /* prefers high part of large block */
- Sig sig; /* */
-} MVFFStruct;
-
+/* Note: MVFFStruct is declared in mpmst.h rather than here because it
+ is the control pool and is inlined in the arena globals. */
#define PoolMVFF(pool) PARENT(MVFFStruct, poolStruct, pool)
-#define MVFFPool(mvff) (&(mvff)->poolStruct)
#define MVFFTotalLand(mvff) CBSLand(&(mvff)->totalCBSStruct)
#define MVFFFreePrimary(mvff) CBSLand(&(mvff)->freeCBSStruct)
#define MVFFFreeSecondary(mvff) FreelistLand(&(mvff)->flStruct)
@@ -69,8 +48,6 @@ typedef struct MVFFStruct { /* MVFF pool outer structure */
#define MVFFLocusPref(mvff) (&(mvff)->locusPrefStruct)
#define MVFFBlockPool(mvff) MFSPool(&(mvff)->cbsBlockPoolStruct)
-static Bool MVFFCheck(MVFF mvff);
-
/* MVFFDebug -- MVFFDebug class */
@@ -777,8 +754,7 @@ mps_pool_class_t mps_class_mvff_debug(void)
/* MVFFCheck -- check the consistency of an MVFF structure */
-ATTRIBUTE_UNUSED
-static Bool MVFFCheck(MVFF mvff)
+Bool MVFFCheck(MVFF mvff)
{
CHECKS(MVFF, mvff);
CHECKD(Pool, MVFFPool(mvff));
diff --git a/mps/code/poolmvff.h b/mps/code/poolmvff.h
new file mode 100644
index 00000000000..c823a4587c7
--- /dev/null
+++ b/mps/code/poolmvff.h
@@ -0,0 +1,72 @@
+/* poolmvff.h: First Fit Manual Variable Pool
+ *
+ * $Id$
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
+ * Portions copyright (C) 2002 Global Graphics Software.
+ *
+ * .purpose: This is a pool class for manually managed objects of
+ * variable size where address-ordered first fit is an appropriate
+ * policy. Provision is made to allocate in reverse.
+ *
+ * .design: See
+ */
+
+#ifndef poolmvff_h
+#define poolmvff_h
+
+
+#include "mpmtypes.h"
+#include "mpscmvff.h"
+
+typedef struct MVFFStruct *MVFF;
+
+extern PoolClass PoolClassMVFF(void);
+
+extern Bool MVFFCheck(MVFF mvff);
+
+#define MVFFPool(mvff) (&(mvff)->poolStruct)
+
+
+#endif /* poolmvff_h */
+
+
+/* C. COPYRIGHT AND LICENSE
+ *
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
+ * 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.
+ */
From 95b76e440708ad04035e83ff7048d688076288c2 Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Tue, 1 Mar 2016 01:45:12 +0000
Subject: [PATCH 072/759] Enabling keyword expansion for poolmvff.h.
Copied from Perforce
Change: 189462
ServerID: perforce.ravenbrook.com
From 888e5214d45a10e9ab7d7df330917ecdcdba0437 Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Tue, 1 Mar 2016 01:55:39 +0000
Subject: [PATCH 073/759] Removing poolmv.h and redundant code now that mv has
no internal clients.
Copied from Perforce
Change: 189465
ServerID: perforce.ravenbrook.com
---
mps/code/arenacv.c | 4 +--
mps/code/global.c | 1 -
mps/code/mpmst.h | 1 -
mps/code/poolmv.c | 15 ++++-----
mps/code/poolmv.h | 77 ---------------------------------------------
mps/code/poolmvff.c | 3 --
6 files changed, 8 insertions(+), 93 deletions(-)
delete mode 100644 mps/code/poolmv.h
diff --git a/mps/code/arenacv.c b/mps/code/arenacv.c
index 7b02c11bcc2..5aeb8b75361 100644
--- a/mps/code/arenacv.c
+++ b/mps/code/arenacv.c
@@ -15,7 +15,7 @@
*/
#include "mpm.h"
-#include "poolmv.h"
+#include "poolmvff.h"
#include "testlib.h"
#include "mpslib.h"
#include "mpsavm.h"
@@ -415,7 +415,7 @@ static void testPageTable(ArenaClass class, Size size, Addr addr, Bool zoned)
die(ArenaCreate(&arena, class, args), "ArenaCreate");
} MPS_ARGS_END(args);
- die(PoolCreate(&pool, arena, PoolClassMV(), argsNone), "PoolCreate");
+ die(PoolCreate(&pool, arena, PoolClassMVFF(), argsNone), "PoolCreate");
pageSize = ArenaGrainSize(arena);
tractsPerPage = pageSize / sizeof(TractStruct);
diff --git a/mps/code/global.c b/mps/code/global.c
index b7070ec77da..a6883c7e113 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -24,7 +24,6 @@
#include "bt.h"
#include "poolmrg.h"
#include "mps.h" /* finalization */
-#include "poolmv.h"
#include "mpm.h"
SRCID(global, "$Id$");
diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h
index 6cfa15b15ff..26e45151155 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -684,7 +684,6 @@ typedef struct FreelistStruct {
#define MVFFSig ((Sig)0x5193FFF9) /* SIGnature MVFF */
-typedef struct MVFFStruct *MVFF;
typedef struct MVFFStruct { /* MVFF pool outer structure */
PoolStruct poolStruct; /* generic structure */
LocusPrefStruct locusPrefStruct; /* the preferences for allocation */
diff --git a/mps/code/poolmv.c b/mps/code/poolmv.c
index 2190e03e198..b102c7366dc 100644
--- a/mps/code/poolmv.c
+++ b/mps/code/poolmv.c
@@ -24,7 +24,6 @@
#include "mpscmv.h"
#include "dbgpool.h"
-#include "poolmv.h"
#include "poolmfs.h"
#include "mpm.h"
@@ -41,6 +40,7 @@ SRCID(poolmv, "$Id$");
#define MVSig ((Sig)0x5193B999) /* SIGnature MV */
+typedef struct MVStruct *MV;
typedef struct MVStruct { /* MV pool outer structure */
PoolStruct poolStruct; /* generic structure */
MFSStruct blockPoolStruct; /* for managing block descriptors */
@@ -58,7 +58,7 @@ typedef struct MVStruct { /* MV pool outer structure */
#define mvBlockPool(mv) MFSPool(&(mv)->blockPoolStruct)
#define mvSpanPool(mv) MFSPool(&(mv)->spanPoolStruct)
-
+#define MVPool(mv) (&(mv)->poolStruct)
#define PoolMV(pool) PARENT(MVStruct, poolStruct, pool)
@@ -150,6 +150,9 @@ typedef struct MVSpanStruct {
AddrOffset((span)->base.limit, (span)->limit.base)
+static Bool MVCheck(MV mv);
+
+
/* MVSpanCheck -- check the consistency of a span structure */
ATTRIBUTE_UNUSED
@@ -884,12 +887,6 @@ DEFINE_POOL_CLASS(MVPoolClass, this)
}
-MVPoolClass PoolClassMV(void)
-{
- return EnsureMVPoolClass();
-}
-
-
/* Pool class MVDebug */
DEFINE_POOL_CLASS(MVDebugPoolClass, this)
@@ -922,7 +919,7 @@ mps_pool_class_t mps_class_mv_debug(void)
/* MVCheck -- check the consistency of an MV structure */
-Bool MVCheck(MV mv)
+static Bool MVCheck(MV mv)
{
CHECKS(MV, mv);
CHECKD(Pool, MVPool(mv));
diff --git a/mps/code/poolmv.h b/mps/code/poolmv.h
deleted file mode 100644
index 5229726583e..00000000000
--- a/mps/code/poolmv.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* poolmv.h: MANUAL VARIABLE POOL
- *
- * $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
- * Portions copyright (C) 2002 Global Graphics Software.
- *
- * FIXME: This header is no longer necessary since MV is no longer
- * used internally.
- *
- * .purpose: This is the interface to the manual-variable pool class.
- *
- * .mv: Manual-variable pools manage variably-sized blocks of memory
- * in a flexible manner. They have higher overheads than a fixed-size
- * pool.
- *
- * .design: See
- */
-
-#ifndef poolmv_h
-#define poolmv_h
-
-
-#include "mpmtypes.h"
-#include "mpscmv.h"
-
-typedef struct MVStruct *MV;
-
-extern PoolClass PoolClassMV(void);
-
-extern Bool MVCheck(MV mv);
-
-#define MVPool(mv) (&(mv)->poolStruct)
-
-
-#endif /* poolmv_h */
-
-
-/* C. COPYRIGHT AND LICENSE
- *
- * Copyright (C) 2001-2014 Ravenbrook Limited .
- * 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.
- */
diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c
index cc7b59fe6a6..022f15f24c4 100644
--- a/mps/code/poolmvff.c
+++ b/mps/code/poolmvff.c
@@ -34,9 +34,6 @@
SRCID(poolmvff, "$Id$");
-/* Would go in poolmvff.h if the class had any MPS-internal clients. */
-extern PoolClass PoolClassMVFF(void);
-
/* Note: MVFFStruct is declared in mpmst.h rather than here because it
is the control pool and is inlined in the arena globals. */
From 4135743082a0e25df47107687240a266a633c952 Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Tue, 1 Mar 2016 17:09:56 +0000
Subject: [PATCH 074/759] Branching master to branch/2016-03-01/closure-size.
Copied from Perforce
Change: 189498
ServerID: perforce.ravenbrook.com
From 804f15deadca3a8a03392e648a2ca66217de2aa7 Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Tue, 1 Mar 2016 17:20:50 +0000
Subject: [PATCH 075/759] Removing the mostly unused size component of the
closure convention.
Copied from Perforce
Change: 189503
ServerID: perforce.ravenbrook.com
---
mps/code/abq.c | 4 +-
mps/code/abq.h | 4 +-
mps/code/abqtest.c | 8 ++--
mps/code/arena.c | 10 ++---
mps/code/arenacl.c | 10 ++---
mps/code/arenavm.c | 21 ++++-----
mps/code/cbs.c | 102 +++++++++++++++++++++-----------------------
mps/code/failover.c | 6 +--
mps/code/fbmtest.c | 18 ++++----
mps/code/freelist.c | 33 ++++++++------
mps/code/land.c | 40 ++++++++---------
mps/code/landtest.c | 7 ++-
mps/code/mpm.h | 4 +-
mps/code/mpmtypes.h | 8 ++--
mps/code/poolmfs.c | 14 +++---
mps/code/poolmfs.h | 4 +-
mps/code/poolmv2.c | 32 ++++++--------
mps/code/poolmvff.c | 11 ++---
mps/code/splay.c | 79 ++++++++++++++++------------------
mps/code/splay.h | 10 ++---
mps/code/tree.c | 22 +++++-----
mps/code/tree.h | 8 ++--
22 files changed, 210 insertions(+), 245 deletions(-)
diff --git a/mps/code/abq.c b/mps/code/abq.c
index 0e9b808a277..7a3df81408e 100644
--- a/mps/code/abq.c
+++ b/mps/code/abq.c
@@ -232,7 +232,7 @@ Count ABQDepth(ABQ abq)
/* ABQIterate -- call 'visitor' for each element in an ABQ */
-void ABQIterate(ABQ abq, ABQVisitor visitor, void *closureP, Size closureS)
+void ABQIterate(ABQ abq, ABQVisitor visitor, void *closure)
{
Index copy, index, in;
@@ -247,7 +247,7 @@ void ABQIterate(ABQ abq, ABQVisitor visitor, void *closureP, Size closureS)
void *element = ABQElement(abq, index);
Bool delete = FALSE;
Bool cont;
- cont = (*visitor)(&delete, element, closureP, closureS);
+ cont = (*visitor)(&delete, element, closure);
AVERT(Bool, cont);
AVERT(Bool, delete);
if (!delete) {
diff --git a/mps/code/abq.h b/mps/code/abq.h
index 85cdfcd5756..e781d00e156 100644
--- a/mps/code/abq.h
+++ b/mps/code/abq.h
@@ -24,7 +24,7 @@
typedef struct ABQStruct *ABQ;
typedef Res (*ABQDescribeElement)(void *element, mps_lib_FILE *stream, Count depth);
-typedef Bool (*ABQVisitor)(Bool *deleteReturn, void *element, void *closureP, Size closureS);
+typedef Bool (*ABQVisitor)(Bool *deleteReturn, void *element, void *closure);
extern Res ABQInit(Arena arena, ABQ abq, void *owner, Count elements, Size elementSize);
extern Bool ABQCheck(ABQ abq);
@@ -36,7 +36,7 @@ extern Res ABQDescribe(ABQ abq, ABQDescribeElement describeElement, mps_lib_FILE
extern Bool ABQIsEmpty(ABQ abq);
extern Bool ABQIsFull(ABQ abq);
extern Count ABQDepth(ABQ abq);
-extern void ABQIterate(ABQ abq, ABQVisitor visitor, void *closureP, Size closureS);
+extern void ABQIterate(ABQ abq, ABQVisitor visitor, void *closure);
/* Types */
diff --git a/mps/code/abqtest.c b/mps/code/abqtest.c
index 9aad3351cb6..b9618b2ff60 100644
--- a/mps/code/abqtest.c
+++ b/mps/code/abqtest.c
@@ -92,12 +92,10 @@ typedef struct TestClosureStruct {
} TestClosureStruct;
static Bool TestDeleteCallback(Bool *deleteReturn, void *element,
- void *closureP, Size closureS)
+ void *closure)
{
TestBlock *a = (TestBlock *)element;
- TestClosure cl = (TestClosure)closureP;
- AVER(closureS == UNUSED_SIZE);
- UNUSED(closureS);
+ TestClosure cl = (TestClosure)closure;
if (*a == cl->b) {
*deleteReturn = TRUE;
cl->res = ResOK;
@@ -145,7 +143,7 @@ static void step(void)
cdie(b != NULL, "found to delete");
cl.b = b;
cl.res = ResFAIL;
- ABQIterate(&abq, TestDeleteCallback, &cl, UNUSED_SIZE);
+ ABQIterate(&abq, TestDeleteCallback, &cl);
cdie(cl.res == ResOK, "ABQIterate");
}
}
diff --git a/mps/code/arena.c b/mps/code/arena.c
index 519a85d735b..860715c5059 100644
--- a/mps/code/arena.c
+++ b/mps/code/arena.c
@@ -406,13 +406,11 @@ void ArenaFinish(Arena arena)
/* ArenaDestroy -- destroy the arena */
static void arenaMFSPageFreeVisitor(Pool pool, Addr base, Size size,
- void *closureP, Size closureS)
+ void *closure)
{
AVERT(Pool, pool);
- AVER(closureP == UNUSED_POINTER);
- AVER(closureS == UNUSED_SIZE);
- UNUSED(closureP);
- UNUSED(closureS);
+ AVER(closure == UNUSED_POINTER);
+ UNUSED(closure);
UNUSED(size);
AVER(size == ArenaGrainSize(PoolArena(pool)));
arenaFreePage(PoolArena(pool), base, pool);
@@ -431,7 +429,7 @@ static void arenaFreeLandFinish(Arena arena)
/* The CBS block pool can't free its own memory via ArenaFree because
* that would use the free land. */
MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor,
- UNUSED_POINTER, UNUSED_SIZE);
+ UNUSED_POINTER);
arena->hasFreeLand = FALSE;
LandFinish(ArenaFreeLand(arena));
diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c
index cd5c24fe46a..ff5a0d8e462 100644
--- a/mps/code/arenacl.c
+++ b/mps/code/arenacl.c
@@ -182,7 +182,7 @@ static Res ClientChunkInit(Chunk chunk, BootBlock boot)
/* clientChunkDestroy -- destroy a ClientChunk */
-static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS)
+static Bool clientChunkDestroy(Tree tree, void *closure)
{
Arena arena;
Chunk chunk;
@@ -190,10 +190,8 @@ static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS)
Size size;
AVERT(Tree, tree);
- AVER(closureP == UNUSED_POINTER);
- UNUSED(closureP);
- AVER(closureS == UNUSED_SIZE);
- UNUSED(closureS);
+ AVER(closure == UNUSED_POINTER);
+ UNUSED(closure);
chunk = ChunkOfTree(tree);
AVERT(Chunk, chunk);
@@ -337,7 +335,7 @@ static void ClientArenaFinish(Arena arena)
* */
arena->primary = NULL;
TreeTraverseAndDelete(&arena->chunkTree, clientChunkDestroy,
- UNUSED_POINTER, UNUSED_SIZE);
+ UNUSED_POINTER);
clientArena->sig = SigInvalid;
diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c
index f5666a1e7e6..4b5f9f73cd0 100644
--- a/mps/code/arenavm.c
+++ b/mps/code/arenavm.c
@@ -409,16 +409,14 @@ static Res VMChunkInit(Chunk chunk, BootBlock boot)
/* vmChunkDestroy -- destroy a VMChunk */
-static Bool vmChunkDestroy(Tree tree, void *closureP, Size closureS)
+static Bool vmChunkDestroy(Tree tree, void *closure)
{
Chunk chunk;
VMChunk vmChunk;
AVERT(Tree, tree);
- AVER(closureP == UNUSED_POINTER);
- UNUSED(closureP);
- AVER(closureS == UNUSED_SIZE);
- UNUSED(closureS);
+ AVER(closure == UNUSED_POINTER);
+ UNUSED(closure);
chunk = ChunkOfTree(tree);
AVERT(Chunk, chunk);
@@ -636,7 +634,7 @@ static void VMArenaFinish(Arena arena)
* */
arena->primary = NULL;
TreeTraverseAndDelete(&arena->chunkTree, vmChunkDestroy,
- UNUSED_POINTER, UNUSED_SIZE);
+ UNUSED_POINTER);
/* Destroying the chunks should have purged and removed all spare pages. */
RingFinish(&vmArena->spareRing);
@@ -1094,16 +1092,14 @@ static void VMFree(Addr base, Size size, Pool pool)
/* vmChunkCompact -- delete chunk if empty and not primary */
-static Bool vmChunkCompact(Tree tree, void *closureP, Size closureS)
+static Bool vmChunkCompact(Tree tree, void *closure)
{
Chunk chunk;
- Arena arena = closureP;
+ Arena arena = closure;
VMArena vmArena;
AVERT(Tree, tree);
AVERT(Arena, arena);
- AVER(closureS == UNUSED_SIZE);
- UNUSED(closureS);
vmArena = Arena2VMArena(arena);
AVERT(VMArena, vmArena);
@@ -1117,7 +1113,7 @@ static Bool vmChunkCompact(Tree tree, void *closureP, Size closureS)
/* Callback before destroying the chunk, as the arena is (briefly)
invalid afterwards. See job003893. */
(*vmArena->contracted)(arena, base, size);
- vmChunkDestroy(tree, UNUSED_POINTER, UNUSED_SIZE);
+ vmChunkDestroy(tree, UNUSED_POINTER);
return TRUE;
} else {
/* Keep this chunk. */
@@ -1140,8 +1136,7 @@ static void VMCompact(Arena arena, Trace trace)
/* Destroy chunks that are completely free, but not the primary
* chunk. See
* TODO: add hysteresis here. See job003815. */
- TreeTraverseAndDelete(&arena->chunkTree, vmChunkCompact, arena,
- UNUSED_SIZE);
+ TreeTraverseAndDelete(&arena->chunkTree, vmChunkCompact, arena);
{
Size vmem0 = trace->preTraceArenaReserved;
diff --git a/mps/code/cbs.c b/mps/code/cbs.c
index 0b30b68acb1..6fb96b6940f 100644
--- a/mps/code/cbs.c
+++ b/mps/code/cbs.c
@@ -117,36 +117,37 @@ static TreeKey cbsKey(Tree tree)
/* cbsTestNode, cbsTestTree -- test for nodes larger than the S parameter */
-static Bool cbsTestNode(SplayTree splay, Tree tree,
- void *closureP, Size size)
+static Bool cbsTestNode(SplayTree splay, Tree tree, void *closure)
{
CBSBlock block;
+ Size *sizeP = closure;
AVERT(SplayTree, splay);
AVERT(Tree, tree);
- AVER(closureP == NULL);
- AVER(size > 0);
+ AVER(sizeP != NULL);
+ AVER(*sizeP > 0);
AVER(IsLandSubclass(CBSLand(cbsOfSplay(splay)), CBSFastLandClass));
block = cbsBlockOfTree(tree);
- return CBSBlockSize(block) >= size;
+ return CBSBlockSize(block) >= *sizeP;
}
static Bool cbsTestTree(SplayTree splay, Tree tree,
- void *closureP, Size size)
+ void *closure)
{
CBSFastBlock block;
+ Size *sizeP = closure;
AVERT(SplayTree, splay);
AVERT(Tree, tree);
- AVER(closureP == NULL);
- AVER(size > 0);
+ AVER(sizeP != NULL);
+ AVER(*sizeP > 0);
AVER(IsLandSubclass(CBSLand(cbsOfSplay(splay)), CBSFastLandClass));
block = cbsFastBlockOfTree(tree);
- return block->maxSize >= size;
+ return block->maxSize >= *sizeP;
}
@@ -726,25 +727,24 @@ static Res cbsZonedSplayNodeDescribe(Tree tree, mps_lib_FILE *stream)
typedef struct CBSIterateClosure {
Land land;
LandVisitor visitor;
- void *closureP;
+ void *visitorClosure;
} CBSIterateClosure;
-static Bool cbsIterateVisit(Tree tree, void *closureP, Size closureS)
+static Bool cbsIterateVisit(Tree tree, void *closure)
{
- CBSIterateClosure *closure = closureP;
- Land land = closure->land;
+ CBSIterateClosure *my = closure;
+ Land land = my->land;
CBSBlock cbsBlock = cbsBlockOfTree(tree);
RangeStruct range;
RangeInit(&range, CBSBlockBase(cbsBlock), CBSBlockLimit(cbsBlock));
- return (*closure->visitor)(land, &range, closure->closureP, closureS);
+ return my->visitor(land, &range, my->visitorClosure);
}
-static Bool cbsIterate(Land land, LandVisitor visitor,
- void *closureP, Size closureS)
+static Bool cbsIterate(Land land, LandVisitor visitor, void *visitorClosure)
{
CBS cbs;
SplayTree splay;
- CBSIterateClosure closure;
+ CBSIterateClosure iterateClosure;
AVERT(Land, land);
cbs = cbsOfLand(land);
@@ -756,11 +756,11 @@ static Bool cbsIterate(Land land, LandVisitor visitor,
/* searches and meter it. */
METER_ACC(cbs->treeSearch, cbs->treeSize);
- closure.land = land;
- closure.visitor = visitor;
- closure.closureP = closureP;
+ iterateClosure.land = land;
+ iterateClosure.visitor = visitor;
+ iterateClosure.visitorClosure = visitorClosure;
return TreeTraverse(SplayTreeRoot(splay), splay->compare, splay->nodeKey,
- cbsIterateVisit, &closure, closureS);
+ cbsIterateVisit, &iterateClosure);
}
@@ -773,33 +773,33 @@ typedef struct CBSIterateAndDeleteClosure {
Land land;
LandDeleteVisitor visitor;
Bool cont;
- void *closureP;
+ void *visitorClosure;
} CBSIterateAndDeleteClosure;
-static Bool cbsIterateAndDeleteVisit(Tree tree, void *closureP, Size closureS)
+static Bool cbsIterateAndDeleteVisit(Tree tree, void *closure)
{
- CBSIterateAndDeleteClosure *closure = closureP;
- Land land = closure->land;
+ CBSIterateAndDeleteClosure *my = closure;
+ Land land = my->land;
CBS cbs = cbsOfLand(land);
CBSBlock cbsBlock = cbsBlockOfTree(tree);
Bool deleteNode = FALSE;
RangeStruct range;
RangeInit(&range, CBSBlockBase(cbsBlock), CBSBlockLimit(cbsBlock));
- if (closure->cont)
- closure->cont = (*closure->visitor)(&deleteNode, land, &range,
- closure->closureP, closureS);
+ if (my->cont)
+ my->cont = my->visitor(&deleteNode, land, &range,
+ my->visitorClosure);
if (deleteNode)
cbsBlockDestroy(cbs, cbsBlock);
return deleteNode;
}
static Bool cbsIterateAndDelete(Land land, LandDeleteVisitor visitor,
- void *closureP, Size closureS)
+ void *visitorClosure)
{
CBS cbs;
SplayTree splay;
- CBSIterateAndDeleteClosure closure;
+ CBSIterateAndDeleteClosure iterateClosure;
AVERT(Land, land);
cbs = cbsOfLand(land);
@@ -811,13 +811,13 @@ static Bool cbsIterateAndDelete(Land land, LandDeleteVisitor visitor,
/* searches and meter it. */
METER_ACC(cbs->treeSearch, cbs->treeSize);
- closure.land = land;
- closure.visitor = visitor;
- closure.closureP = closureP;
- closure.cont = TRUE;
+ iterateClosure.land = land;
+ iterateClosure.visitor = visitor;
+ iterateClosure.visitorClosure = visitorClosure;
+ iterateClosure.cont = TRUE;
TreeTraverseAndDelete(&splay->root, cbsIterateAndDeleteVisit,
- &closure, closureS);
- return closure.cont;
+ &iterateClosure);
+ return iterateClosure.cont;
}
@@ -904,7 +904,7 @@ static Bool cbsFindFirst(Range rangeReturn, Range oldRangeReturn,
METER_ACC(cbs->treeSearch, cbs->treeSize);
found = SplayFindFirst(&tree, cbsSplay(cbs), &cbsTestNode,
- &cbsTestTree, NULL, size);
+ &cbsTestTree, &size);
if (found) {
CBSBlock block;
RangeStruct range;
@@ -934,36 +934,32 @@ typedef struct cbsTestNodeInZonesClosureStruct {
} cbsTestNodeInZonesClosureStruct, *cbsTestNodeInZonesClosure;
static Bool cbsTestNodeInZones(SplayTree splay, Tree tree,
- void *closureP, Size closureS)
+ void *closure)
{
CBSBlock block = cbsBlockOfTree(tree);
- cbsTestNodeInZonesClosure closure = closureP;
+ cbsTestNodeInZonesClosure my = closure;
RangeInZoneSet search;
UNUSED(splay);
- AVER(closureS == UNUSED_SIZE);
- UNUSED(closureS);
- search = closure->high ? RangeInZoneSetLast : RangeInZoneSetFirst;
+ search = my->high ? RangeInZoneSetLast : RangeInZoneSetFirst;
- return search(&closure->base, &closure->limit,
+ return search(&my->base, &my->limit,
CBSBlockBase(block), CBSBlockLimit(block),
- closure->arena, closure->zoneSet, closure->size);
+ my->arena, my->zoneSet, my->size);
}
static Bool cbsTestTreeInZones(SplayTree splay, Tree tree,
- void *closureP, Size closureS)
+ void *closure)
{
CBSFastBlock fastBlock = cbsFastBlockOfTree(tree);
CBSZonedBlock zonedBlock = cbsZonedBlockOfTree(tree);
- cbsTestNodeInZonesClosure closure = closureP;
+ cbsTestNodeInZonesClosure my = closure;
UNUSED(splay);
- AVER(closureS == UNUSED_SIZE);
- UNUSED(closureS);
- return fastBlock->maxSize >= closure->size
- && ZoneSetInter(zonedBlock->zones, closure->zoneSet) != ZoneSetEMPTY;
+ return fastBlock->maxSize >= my->size
+ && ZoneSetInter(zonedBlock->zones, my->zoneSet) != ZoneSetEMPTY;
}
@@ -989,7 +985,7 @@ static Bool cbsFindLast(Range rangeReturn, Range oldRangeReturn,
METER_ACC(cbs->treeSearch, cbs->treeSize);
found = SplayFindLast(&tree, cbsSplay(cbs), &cbsTestNode,
- &cbsTestTree, NULL, size);
+ &cbsTestTree, &size);
if (found) {
CBSBlock block;
RangeStruct range;
@@ -1033,7 +1029,7 @@ static Bool cbsFindLargest(Range rangeReturn, Range oldRangeReturn,
CBSBlock block;
METER_ACC(cbs->treeSearch, cbs->treeSize);
found = SplayFindFirst(&tree, cbsSplay(cbs), &cbsTestNode,
- &cbsTestTree, NULL, maxSize);
+ &cbsTestTree, &maxSize);
AVER(found); /* maxSize is exact, so we will find it. */
block = cbsBlockOfTree(tree);
AVER(CBSBlockSize(block) >= maxSize);
@@ -1093,7 +1089,7 @@ static Res cbsFindInZones(Bool *foundReturn, Range rangeReturn,
closure.high = high;
if (!(*splayFind)(&tree, cbsSplay(cbs),
cbsTestNodeInZones, cbsTestTreeInZones,
- &closure, UNUSED_SIZE))
+ &closure))
goto fail;
block = cbsBlockOfTree(tree);
diff --git a/mps/code/failover.c b/mps/code/failover.c
index 750c6b1b17b..eba8737ec33 100644
--- a/mps/code/failover.c
+++ b/mps/code/failover.c
@@ -177,7 +177,7 @@ static Res failoverDelete(Range rangeReturn, Land land, Range range)
}
-static Bool failoverIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
+static Bool failoverIterate(Land land, LandVisitor visitor, void *closure)
{
Failover fo;
@@ -186,8 +186,8 @@ static Bool failoverIterate(Land land, LandVisitor visitor, void *closureP, Size
AVERT(Failover, fo);
AVER(visitor != NULL);
- return LandIterate(fo->primary, visitor, closureP, closureS)
- && LandIterate(fo->secondary, visitor, closureP, closureS);
+ return LandIterate(fo->primary, visitor, closure)
+ && LandIterate(fo->secondary, visitor, closure);
}
diff --git a/mps/code/fbmtest.c b/mps/code/fbmtest.c
index f5aa6831db8..0ef954d071d 100644
--- a/mps/code/fbmtest.c
+++ b/mps/code/fbmtest.c
@@ -94,13 +94,11 @@ static void describe(FBMState state) {
}
-static Bool checkCallback(Range range, void *closureP, Size closureS)
+static Bool checkCallback(Range range, void *closure)
{
Addr base, limit;
- CheckFBMClosure cl = (CheckFBMClosure)closureP;
+ CheckFBMClosure cl = (CheckFBMClosure)closure;
- AVER(closureS == UNUSED_SIZE);
- UNUSED(closureS);
Insist(cl != NULL);
base = RangeBase(range);
@@ -126,18 +124,18 @@ static Bool checkCallback(Range range, void *closureP, Size closureS)
static Bool checkCBSCallback(CBS cbs, Range range,
- void *closureP, Size closureS)
+ void *closure)
{
UNUSED(cbs);
- return checkCallback(range, closureP, closureS);
+ return checkCallback(range, closure);
}
static Bool checkFLCallback(Bool *deleteReturn, Range range,
- void *closureP, Size closureS)
+ void *closure)
{
*deleteReturn = FALSE;
- return checkCallback(range, closureP, closureS);
+ return checkCallback(range, closure);
}
@@ -151,10 +149,10 @@ static void check(FBMState state)
switch (state->type) {
case FBMTypeCBS:
- CBSIterate(state->the.cbs, checkCBSCallback, &closure, UNUSED_SIZE);
+ CBSIterate(state->the.cbs, checkCBSCallback, &closure);
break;
case FBMTypeFreelist:
- FreelistIterate(state->the.fl, checkFLCallback, &closure, UNUSED_SIZE);
+ FreelistIterate(state->the.fl, checkFLCallback, &closure);
break;
default:
cdie(0, "invalid state->type");
diff --git a/mps/code/freelist.c b/mps/code/freelist.c
index 6eddc3dff83..14e02f58e40 100644
--- a/mps/code/freelist.c
+++ b/mps/code/freelist.c
@@ -444,7 +444,7 @@ static Res freelistDelete(Range rangeReturn, Land land, Range range)
static Bool freelistIterate(Land land, LandVisitor visitor,
- void *closureP, Size closureS)
+ void *closure)
{
Freelist fl;
FreelistBlock cur, next;
@@ -453,7 +453,7 @@ static Bool freelistIterate(Land land, LandVisitor visitor,
fl = freelistOfLand(land);
AVERT(Freelist, fl);
AVER(FUNCHECK(visitor));
- /* closureP and closureS are arbitrary */
+ /* closure arbitrary */
for (cur = fl->list; cur != freelistEND; cur = next) {
RangeStruct range;
@@ -462,7 +462,7 @@ static Bool freelistIterate(Land land, LandVisitor visitor,
* visitor touches the block. */
next = freelistBlockNext(cur);
RangeInit(&range, freelistBlockBase(cur), freelistBlockLimit(fl, cur));
- cont = (*visitor)(land, &range, closureP, closureS);
+ cont = (*visitor)(land, &range, closure);
if (!cont)
return FALSE;
}
@@ -471,7 +471,7 @@ static Bool freelistIterate(Land land, LandVisitor visitor,
static Bool freelistIterateAndDelete(Land land, LandDeleteVisitor visitor,
- void *closureP, Size closureS)
+ void *closure)
{
Freelist fl;
FreelistBlock prev, cur, next;
@@ -480,7 +480,7 @@ static Bool freelistIterateAndDelete(Land land, LandDeleteVisitor visitor,
fl = freelistOfLand(land);
AVERT(Freelist, fl);
AVER(FUNCHECK(visitor));
- /* closureP and closureS are arbitrary */
+ /* closure arbitrary */
prev = freelistEND;
cur = fl->list;
@@ -492,7 +492,7 @@ static Bool freelistIterateAndDelete(Land land, LandDeleteVisitor visitor,
next = freelistBlockNext(cur); /* See .next.first. */
size = freelistBlockSize(fl, cur);
RangeInit(&range, freelistBlockBase(cur), freelistBlockLimit(fl, cur));
- cont = (*visitor)(&delete, land, &range, closureP, closureS);
+ cont = (*visitor)(&delete, land, &range, closure);
if (delete) {
freelistBlockSetPrevNext(fl, prev, next, -1);
AVER(fl->size >= size);
@@ -746,24 +746,28 @@ static Res freelistFindInZones(Bool *foundReturn, Range rangeReturn,
/* freelistDescribeVisitor -- visitor method for freelistDescribe
*
* Writes a decription of the range into the stream pointed to by
- * closureP.
+ * closure.
*/
+typedef struct FreelistDescribeClosureStruct {
+ mps_lib_FILE *stream;
+ Count depth;
+} FreelistDescribeClosureStruct, *FreelistDescribeClosure;
+
static Bool freelistDescribeVisitor(Land land, Range range,
- void *closureP, Size closureS)
+ void *closure)
{
Res res;
- mps_lib_FILE *stream = closureP;
- Count depth = closureS;
+ FreelistDescribeClosure my = closure;
if (!TESTT(Land, land))
return FALSE;
if (!RangeCheck(range))
return FALSE;
- if (stream == NULL)
+ if (my->stream == NULL)
return FALSE;
- res = WriteF(stream, depth,
+ res = WriteF(my->stream, my->depth,
"[$P,", (WriteFP)RangeBase(range),
"$P)", (WriteFP)RangeLimit(range),
" {$U}\n", (WriteFU)RangeSize(range),
@@ -778,6 +782,7 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream, Count depth)
Freelist fl;
Res res;
Bool b;
+ FreelistDescribeClosureStruct closure;
if (!TESTT(Land, land))
return ResFAIL;
@@ -793,7 +798,9 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream, Count depth)
" size = $U\n", (WriteFU)fl->size,
NULL);
- b = LandIterate(land, freelistDescribeVisitor, stream, depth + 2);
+ closure.stream = stream;
+ closure.depth = depth + 2;
+ b = LandIterate(land, freelistDescribeVisitor, &closure);
if (!b)
return ResFAIL;
diff --git a/mps/code/land.c b/mps/code/land.c
index 18d446288f8..1853b4a6ad5 100644
--- a/mps/code/land.c
+++ b/mps/code/land.c
@@ -235,14 +235,14 @@ Res LandDelete(Range rangeReturn, Land land, Range range)
* See
*/
-Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
+Bool LandIterate(Land land, LandVisitor visitor, void *closure)
{
Bool b;
AVERT(Land, land);
AVER(FUNCHECK(visitor));
landEnter(land);
- b = (*land->class->iterate)(land, visitor, closureP, closureS);
+ b = (*land->class->iterate)(land, visitor, closure);
landLeave(land);
return b;
@@ -255,14 +255,14 @@ Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
* See
*/
-Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS)
+Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closure)
{
Bool b;
AVERT(Land, land);
AVER(FUNCHECK(visitor));
landEnter(land);
- b = (*land->class->iterateAndDelete)(land, visitor, closureP, closureS);
+ b = (*land->class->iterateAndDelete)(land, visitor, closure);
landLeave(land);
return b;
@@ -403,11 +403,11 @@ Res LandDescribe(Land land, mps_lib_FILE *stream, Count depth)
/* landFlushVisitor -- visitor for LandFlush.
*
- * closureP argument is the destination Land. Attempt to insert the
+ * closure argument is the destination Land. Attempt to insert the
* range into the destination.
*/
static Bool landFlushVisitor(Bool *deleteReturn, Land land, Range range,
- void *closureP, Size closureS)
+ void *closure)
{
Res res;
RangeStruct newRange;
@@ -416,11 +416,9 @@ static Bool landFlushVisitor(Bool *deleteReturn, Land land, Range range,
AVER(deleteReturn != NULL);
AVERT(Land, land);
AVERT(Range, range);
- AVER(closureP != NULL);
- AVER(closureS == UNUSED_SIZE);
- UNUSED(closureS);
+ AVER(closure != NULL);
- dest = closureP;
+ dest = closure;
res = LandInsert(&newRange, dest, range);
if (res == ResOK) {
*deleteReturn = TRUE;
@@ -442,7 +440,7 @@ Bool LandFlush(Land dest, Land src)
AVERT(Land, dest);
AVERT(Land, src);
- return LandIterateAndDelete(src, landFlushVisitor, dest, UNUSED_SIZE);
+ return LandIterateAndDelete(src, landFlushVisitor, dest);
}
@@ -491,17 +489,15 @@ static Size landNoSize(Land land)
/* LandSlowSize -- generic size method but slow */
static Bool landSizeVisitor(Land land, Range range,
- void *closureP, Size closureS)
+ void *closure)
{
Size *size;
AVERT(Land, land);
AVERT(Range, range);
- AVER(closureP != NULL);
- AVER(closureS == UNUSED_SIZE);
- UNUSED(closureS);
+ AVER(closure != NULL);
- size = closureP;
+ size = closure;
*size += RangeSize(range);
return TRUE;
@@ -510,7 +506,7 @@ static Bool landSizeVisitor(Land land, Range range,
Size LandSlowSize(Land land)
{
Size size = 0;
- Bool b = LandIterate(land, landSizeVisitor, &size, UNUSED_SIZE);
+ Bool b = LandIterate(land, landSizeVisitor, &size);
AVER(b);
return size;
}
@@ -531,21 +527,19 @@ static Res landNoDelete(Range rangeReturn, Land land, Range range)
return ResUNIMPL;
}
-static Bool landNoIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
+static Bool landNoIterate(Land land, LandVisitor visitor, void *closure)
{
AVERT(Land, land);
AVER(visitor != NULL);
- UNUSED(closureP);
- UNUSED(closureS);
+ UNUSED(closure);
return FALSE;
}
-static Bool landNoIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS)
+static Bool landNoIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closure)
{
AVERT(Land, land);
AVER(visitor != NULL);
- UNUSED(closureP);
- UNUSED(closureS);
+ UNUSED(closure);
return FALSE;
}
diff --git a/mps/code/landtest.c b/mps/code/landtest.c
index eb4229f65e8..7ec55461d1e 100644
--- a/mps/code/landtest.c
+++ b/mps/code/landtest.c
@@ -67,13 +67,12 @@ static void describe(TestState state) {
}
-static Bool checkVisitor(Land land, Range range, void *closureP, Size closureS)
+static Bool checkVisitor(Land land, Range range, void *closure)
{
Addr base, limit;
- CheckTestClosure cl = closureP;
+ CheckTestClosure cl = closure;
testlib_unused(land);
- Insist(closureS == UNUSED_SIZE);
Insist(cl != NULL);
base = RangeBase(range);
@@ -106,7 +105,7 @@ static void check(TestState state)
closure.limit = addrOfIndex(state, state->size);
closure.oldLimit = state->block;
- b = LandIterate(state->land, checkVisitor, &closure, UNUSED_SIZE);
+ b = LandIterate(state->land, checkVisitor, &closure);
Insist(b);
if (closure.oldLimit == state->block)
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index 8efa22c155d..8a3984a6233 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -1009,8 +1009,8 @@ extern void LandDestroy(Land land);
extern void LandFinish(Land land);
extern Res LandInsert(Range rangeReturn, Land land, Range range);
extern Res LandDelete(Range rangeReturn, Land land, Range range);
-extern Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS);
-extern Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS);
+extern Bool LandIterate(Land land, LandVisitor visitor, void *closure);
+extern Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closure);
extern Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);
extern Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);
extern Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);
diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h
index a6030e4c1e5..3545021f50f 100644
--- a/mps/code/mpmtypes.h
+++ b/mps/code/mpmtypes.h
@@ -270,10 +270,10 @@ typedef void (*LandFinishMethod)(Land land);
typedef Size (*LandSizeMethod)(Land land);
typedef Res (*LandInsertMethod)(Range rangeReturn, Land land, Range range);
typedef Res (*LandDeleteMethod)(Range rangeReturn, Land land, Range range);
-typedef Bool (*LandVisitor)(Land land, Range range, void *closureP, Size closureS);
-typedef Bool (*LandDeleteVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS);
-typedef Bool (*LandIterateMethod)(Land land, LandVisitor visitor, void *closureP, Size closureS);
-typedef Bool (*LandIterateAndDeleteMethod)(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS);
+typedef Bool (*LandVisitor)(Land land, Range range, void *closure);
+typedef Bool (*LandDeleteVisitor)(Bool *deleteReturn, Land land, Range range, void *closure);
+typedef Bool (*LandIterateMethod)(Land land, LandVisitor visitor, void *closure);
+typedef Bool (*LandIterateAndDeleteMethod)(Land land, LandDeleteVisitor visitor, void *closure);
typedef Bool (*LandFindMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);
typedef Res (*LandFindInZonesMethod)(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high);
typedef Res (*LandDescribeMethod)(Land land, mps_lib_FILE *stream, Count depth);
diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c
index 90232621c25..4ce6e66ed1c 100644
--- a/mps/code/poolmfs.c
+++ b/mps/code/poolmfs.c
@@ -126,7 +126,7 @@ static Res MFSInit(Pool pool, ArgList args)
void MFSFinishTracts(Pool pool, MFSTractVisitor visitor,
- void *closureP, Size closureS)
+ void *closure)
{
MFS mfs;
@@ -136,19 +136,17 @@ void MFSFinishTracts(Pool pool, MFSTractVisitor visitor,
while (mfs->tractList != NULL) {
Tract nextTract = (Tract)TractP(mfs->tractList); /* .tract.chain */
- visitor(pool, TractBase(mfs->tractList), mfs->extendBy, closureP, closureS);
+ visitor(pool, TractBase(mfs->tractList), mfs->extendBy, closure);
mfs->tractList = nextTract;
}
}
static void MFSTractFreeVisitor(Pool pool, Addr base, Size size,
- void *closureP, Size closureS)
+ void *closure)
{
- AVER(closureP == UNUSED_POINTER);
- AVER(closureS == UNUSED_SIZE);
- UNUSED(closureP);
- UNUSED(closureS);
+ AVER(closure == UNUSED_POINTER);
+ UNUSED(closure);
ArenaFree(base, size, pool);
}
@@ -161,7 +159,7 @@ static void MFSFinish(Pool pool)
mfs = PoolPoolMFS(pool);
AVERT(MFS, mfs);
- MFSFinishTracts(pool, MFSTractFreeVisitor, UNUSED_POINTER, UNUSED_SIZE);
+ MFSFinishTracts(pool, MFSTractFreeVisitor, UNUSED_POINTER);
mfs->sig = SigInvalid;
}
diff --git a/mps/code/poolmfs.h b/mps/code/poolmfs.h
index ac4122a9f02..70d4124cb42 100644
--- a/mps/code/poolmfs.h
+++ b/mps/code/poolmfs.h
@@ -46,9 +46,9 @@ extern const struct mps_key_s _mps_key_MFSExtendSelf;
extern void MFSExtend(Pool pool, Addr base, Size size);
typedef void MFSTractVisitor(Pool pool, Addr base, Size size,
- void *closureP, Size closureS);
+ void *closure);
extern void MFSFinishTracts(Pool pool, MFSTractVisitor visitor,
- void *closureP, Size closureS);
+ void *closure);
#endif /* poolmfs_h */
diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c
index 95c3e9ecc9a..1189f7d73e1 100644
--- a/mps/code/poolmv2.c
+++ b/mps/code/poolmv2.c
@@ -751,23 +751,21 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn,
/* MVTDeleteOverlapping -- ABQIterate callback used by MVTInsert and
- * MVTDelete. It receives a Range in its closureP argument, and sets
+ * MVTDelete. It receives a Range in its closure argument, and sets
* *deleteReturn to TRUE for ranges in the ABQ that overlap with it,
* and FALSE for ranges that do not.
*/
static Bool MVTDeleteOverlapping(Bool *deleteReturn, void *element,
- void *closureP, Size closureS)
+ void *closure)
{
Range oldRange, newRange;
AVER(deleteReturn != NULL);
AVER(element != NULL);
- AVER(closureP != NULL);
- AVER(closureS == UNUSED_SIZE);
- UNUSED(closureS);
+ AVER(closure != NULL);
oldRange = element;
- newRange = closureP;
+ newRange = closure;
*deleteReturn = RangesOverlap(oldRange, newRange);
return TRUE;
@@ -830,7 +828,7 @@ static Res MVTInsert(MVT mvt, Addr base, Addr limit)
* with ranges on the ABQ, so ensure that the corresponding ranges
* are coalesced on the ABQ.
*/
- ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &newRange, UNUSED_SIZE);
+ ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &newRange);
(void)MVTReserve(mvt, &newRange);
}
@@ -859,7 +857,7 @@ static Res MVTDelete(MVT mvt, Addr base, Addr limit)
* might be on the ABQ, so ensure it is removed.
*/
if (RangeSize(&rangeOld) >= mvt->reuseSize)
- ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &rangeOld, UNUSED_SIZE);
+ ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &rangeOld);
/* There might be fragments at the left or the right of the deleted
* range, and either might be big enough to go back on the ABQ.
@@ -1210,15 +1208,13 @@ static Bool MVTReturnSegs(MVT mvt, Range range, Arena arena)
*/
static Bool MVTRefillVisitor(Land land, Range range,
- void *closureP, Size closureS)
+ void *closure)
{
MVT mvt;
AVERT(Land, land);
- mvt = closureP;
+ mvt = closure;
AVERT(MVT, mvt);
- AVER(closureS == UNUSED_SIZE);
- UNUSED(closureS);
if (RangeSize(range) < mvt->reuseSize)
return TRUE;
@@ -1241,7 +1237,7 @@ static void MVTRefillABQIfEmpty(MVT mvt, Size size)
mvt->abqOverflow = FALSE;
METER_ACC(mvt->refills, size);
/* The iteration stops if the ABQ overflows, so may finish or not. */
- (void)LandIterate(MVTFreeLand(mvt), MVTRefillVisitor, mvt, UNUSED_SIZE);
+ (void)LandIterate(MVTFreeLand(mvt), MVTRefillVisitor, mvt);
}
}
@@ -1260,7 +1256,7 @@ typedef struct MVTContigencyClosureStruct
} MVTContigencyClosureStruct, *MVTContigencyClosure;
static Bool MVTContingencyVisitor(Land land, Range range,
- void *closureP, Size closureS)
+ void *closure)
{
MVT mvt;
Size size;
@@ -1269,12 +1265,10 @@ static Bool MVTContingencyVisitor(Land land, Range range,
AVERT(Land, land);
AVERT(Range, range);
- AVER(closureP != NULL);
- cl = closureP;
+ AVER(closure != NULL);
+ cl = closure;
mvt = cl->mvt;
AVERT(MVT, mvt);
- AVER(closureS == UNUSED_SIZE);
- UNUSED(closureS);
base = RangeBase(range);
limit = RangeLimit(range);
@@ -1312,7 +1306,7 @@ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn,
cls.steps = 0;
cls.hardSteps = 0;
- if (LandIterate(MVTFreeLand(mvt), MVTContingencyVisitor, &cls, UNUSED_SIZE))
+ if (LandIterate(MVTFreeLand(mvt), MVTContingencyVisitor, &cls))
return FALSE;
AVER(RangeSize(&cls.range) >= min);
diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c
index 22b6d004f68..1125f018a07 100644
--- a/mps/code/poolmvff.c
+++ b/mps/code/poolmvff.c
@@ -585,18 +585,16 @@ static Res MVFFInit(Pool pool, ArgList args)
/* MVFFFinish -- finish method for MVFF */
static Bool mvffFinishVisitor(Bool *deleteReturn, Land land, Range range,
- void *closureP, Size closureS)
+ void *closure)
{
Pool pool;
AVER(deleteReturn != NULL);
AVERT(Land, land);
AVERT(Range, range);
- AVER(closureP != NULL);
- pool = closureP;
+ AVER(closure != NULL);
+ pool = closure;
AVERT(Pool, pool);
- AVER(closureS == UNUSED_SIZE);
- UNUSED(closureS);
ArenaFree(RangeBase(range), RangeSize(range), pool);
*deleteReturn = TRUE;
@@ -613,8 +611,7 @@ static void MVFFFinish(Pool pool)
AVERT(MVFF, mvff);
mvff->sig = SigInvalid;
- b = LandIterateAndDelete(MVFFTotalLand(mvff), mvffFinishVisitor, pool,
- UNUSED_SIZE);
+ b = LandIterateAndDelete(MVFFTotalLand(mvff), mvffFinishVisitor, pool);
AVER(b);
AVER(LandSize(MVFFTotalLand(mvff)) == 0);
diff --git a/mps/code/splay.c b/mps/code/splay.c
index ed46c7a4ba4..0030b4aee65 100644
--- a/mps/code/splay.c
+++ b/mps/code/splay.c
@@ -1088,19 +1088,17 @@ static Res SplayNodeDescribe(Tree node, mps_lib_FILE *stream,
typedef struct SplayFindClosureStruct {
SplayTestNodeFunction testNode;
SplayTestTreeFunction testTree;
- void *p;
- Size s;
+ void *testClosure;
SplayTree splay;
Bool found;
} SplayFindClosureStruct, *SplayFindClosure;
static Compare SplayFindFirstCompare(Tree node, TreeKey key)
{
- SplayFindClosure closure;
- void *closureP;
- Size closureS;
+ SplayFindClosure my;
SplayTestNodeFunction testNode;
SplayTestTreeFunction testTree;
+ void *testClosure;
SplayTree splay;
AVERT(Tree, node);
@@ -1108,18 +1106,17 @@ static Compare SplayFindFirstCompare(Tree node, TreeKey key)
/* Lift closure values into variables so that they aren't aliased by
calls to the test functions. */
- closure = (SplayFindClosure)key;
- closureP = closure->p;
- closureS = closure->s;
- testNode = closure->testNode;
- testTree = closure->testTree;
- splay = closure->splay;
+ my = (SplayFindClosure)key;
+ testClosure = my->testClosure;
+ testNode = my->testNode;
+ testTree = my->testTree;
+ splay = my->splay;
if (TreeHasLeft(node) &&
- (*testTree)(splay, TreeLeft(node), closureP, closureS)) {
+ (*testTree)(splay, TreeLeft(node), testClosure)) {
return CompareLESS;
- } else if ((*testNode)(splay, node, closureP, closureS)) {
- closure->found = TRUE;
+ } else if ((*testNode)(splay, node, testClosure)) {
+ my->found = TRUE;
return CompareEQUAL;
} else {
/* If there's a right subtree but it doesn't satisfy the tree test
@@ -1127,8 +1124,8 @@ static Compare SplayFindFirstCompare(Tree node, TreeKey key)
return TRUE, so the caller must check closure->found to find out
whether the result node actually satisfies testNode. */
if (TreeHasRight(node) &&
- !(*testTree)(splay, TreeRight(node), closureP, closureS)) {
- closure->found = FALSE;
+ !(*testTree)(splay, TreeRight(node), testClosure)) {
+ my->found = FALSE;
return CompareEQUAL;
}
return CompareGREATER;
@@ -1137,11 +1134,10 @@ static Compare SplayFindFirstCompare(Tree node, TreeKey key)
static Compare SplayFindLastCompare(Tree node, TreeKey key)
{
- SplayFindClosure closure;
- void *closureP;
- Size closureS;
+ SplayFindClosure my;
SplayTestNodeFunction testNode;
SplayTestTreeFunction testTree;
+ void *testClosure;
SplayTree splay;
AVERT(Tree, node);
@@ -1149,24 +1145,23 @@ static Compare SplayFindLastCompare(Tree node, TreeKey key)
/* Lift closure values into variables so that they aren't aliased by
calls to the test functions. */
- closure = (SplayFindClosure)key;
- closureP = closure->p;
- closureS = closure->s;
- testNode = closure->testNode;
- testTree = closure->testTree;
- splay = closure->splay;
+ my = (SplayFindClosure)key;
+ testClosure = my->testClosure;
+ testNode = my->testNode;
+ testTree = my->testTree;
+ splay = my->splay;
if (TreeHasRight(node) &&
- (*testTree)(splay, TreeRight(node), closureP, closureS)) {
- return CompareGREATER;
- } else if ((*testNode)(splay, node, closureP, closureS)) {
- closure->found = TRUE;
+ (*testTree)(splay, TreeRight(node), testClosure)) {
+ return CompareGREATER;
+ } else if ((*testNode)(splay, node, testClosure)) {
+ my->found = TRUE;
return CompareEQUAL;
} else {
/* See SplayFindFirstCompare. */
if (TreeHasLeft(node) &&
- !(*testTree)(splay, TreeLeft(node), closureP, closureS)) {
- closure->found = FALSE;
+ !(*testTree)(splay, TreeLeft(node), testClosure)) {
+ my->found = FALSE;
return CompareEQUAL;
}
return CompareLESS;
@@ -1184,8 +1179,8 @@ static Compare SplayFindLastCompare(Tree node, TreeKey key)
* ``*nodeReturn`` is set to the node.
*
* The given callbacks testNode and testTree detect this property in
- * a single node or a sub-tree rooted at a node, and both receive the
- * arbitrary closures closureP and closureS.
+ * a single node or a sub-tree rooted at a node, and both receive an
+ * arbitrary closure.
*
* TODO: This repeatedly splays failed matches to the root and rotates
* them, so it could have quite an unbalancing effect if size is small.
@@ -1195,7 +1190,7 @@ static Compare SplayFindLastCompare(Tree node, TreeKey key)
Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay,
SplayTestNodeFunction testNode,
SplayTestTreeFunction testTree,
- void *closureP, Size closureS)
+ void *testClosure)
{
SplayFindClosureStruct closureStruct;
Bool found;
@@ -1206,11 +1201,10 @@ Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay,
AVER(FUNCHECK(testTree));
if (SplayTreeIsEmpty(splay) ||
- !testTree(splay, SplayTreeRoot(splay), closureP, closureS))
+ !testTree(splay, SplayTreeRoot(splay), testClosure))
return FALSE; /* no suitable nodes in tree */
- closureStruct.p = closureP;
- closureStruct.s = closureS;
+ closureStruct.testClosure = testClosure;
closureStruct.testNode = testNode;
closureStruct.testTree = testTree;
closureStruct.splay = splay;
@@ -1227,7 +1221,7 @@ Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay,
oldRoot = SplayTreeRoot(splay);
newRoot = TreeRight(oldRoot);
- if (newRoot == TreeEMPTY || !(*testTree)(splay, newRoot, closureP, closureS))
+ if (newRoot == TreeEMPTY || !(*testTree)(splay, newRoot, testClosure))
return FALSE; /* no suitable nodes in the rest of the tree */
/* Temporarily chop off the left half-tree, inclusive of root,
@@ -1259,7 +1253,7 @@ Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay,
Bool SplayFindLast(Tree *nodeReturn, SplayTree splay,
SplayTestNodeFunction testNode,
SplayTestTreeFunction testTree,
- void *closureP, Size closureS)
+ void *testClosure)
{
SplayFindClosureStruct closureStruct;
Bool found;
@@ -1270,11 +1264,10 @@ Bool SplayFindLast(Tree *nodeReturn, SplayTree splay,
AVER(FUNCHECK(testTree));
if (SplayTreeIsEmpty(splay) ||
- !testTree(splay, SplayTreeRoot(splay), closureP, closureS))
+ !testTree(splay, SplayTreeRoot(splay), testClosure))
return FALSE; /* no suitable nodes in tree */
- closureStruct.p = closureP;
- closureStruct.s = closureS;
+ closureStruct.testClosure = testClosure;
closureStruct.testNode = testNode;
closureStruct.testTree = testTree;
closureStruct.splay = splay;
@@ -1289,7 +1282,7 @@ Bool SplayFindLast(Tree *nodeReturn, SplayTree splay,
oldRoot = SplayTreeRoot(splay);
newRoot = TreeLeft(oldRoot);
- if (newRoot == TreeEMPTY || !(*testTree)(splay, newRoot, closureP, closureS))
+ if (newRoot == TreeEMPTY || !(*testTree)(splay, newRoot, testClosure))
return FALSE; /* no suitable nodes in the rest of the tree */
/* Temporarily chop off the right half-tree, inclusive of root,
diff --git a/mps/code/splay.h b/mps/code/splay.h
index c1b109e64a7..d9cf821eb90 100644
--- a/mps/code/splay.h
+++ b/mps/code/splay.h
@@ -16,9 +16,9 @@
typedef struct SplayTreeStruct *SplayTree;
typedef Bool (*SplayTestNodeFunction)(SplayTree splay, Tree node,
- void *closureP, Size closureS);
+ void *closure);
typedef Bool (*SplayTestTreeFunction)(SplayTree splay, Tree node,
- void *closureP, Size closureS);
+ void *closure);
typedef void (*SplayUpdateNodeFunction)(SplayTree splay, Tree node);
extern void SplayTrivUpdate(SplayTree splay, Tree node);
@@ -58,15 +58,15 @@ extern Tree SplayTreeNext(SplayTree splay, TreeKey oldKey);
typedef Bool (*SplayFindFunction)(Tree *nodeReturn, SplayTree splay,
SplayTestNodeFunction testNode,
SplayTestTreeFunction testTree,
- void *closureP, Size closureS);
+ void *closure);
extern Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay,
SplayTestNodeFunction testNode,
SplayTestTreeFunction testTree,
- void *closureP, Size closureS);
+ void *closure);
extern Bool SplayFindLast(Tree *nodeReturn, SplayTree splay,
SplayTestNodeFunction testNode,
SplayTestTreeFunction testTree,
- void *closureP, Size closureS);
+ void *closure);
extern void SplayNodeRefresh(SplayTree splay, Tree node);
extern void SplayNodeInit(SplayTree splay, Tree node);
diff --git a/mps/code/tree.c b/mps/code/tree.c
index f87e8364ea7..3afea83bca3 100644
--- a/mps/code/tree.c
+++ b/mps/code/tree.c
@@ -230,20 +230,20 @@ Bool TreeInsert(Tree *treeReturn, Tree root, Tree node,
*/
Bool TreeTraverseMorris(Tree tree, TreeVisitor visit,
- void *closureP, Size closureS)
+ void *closure)
{
Tree node;
Bool visiting = TRUE;
AVERT(Tree, tree);
AVER(FUNCHECK(visit));
- /* closureP, closureS arbitrary */
+ /* closure arbitrary */
node = tree;
while (node != TreeEMPTY) {
if (node->left == TreeEMPTY) {
if (visiting)
- visiting = visit(node, closureP, closureS);
+ visiting = visit(node, closure);
node = node->right;
} else {
Tree pre = node->left;
@@ -256,7 +256,7 @@ Bool TreeTraverseMorris(Tree tree, TreeVisitor visit,
if (pre->right == node) {
pre->right = TreeEMPTY;
if (visiting)
- visiting = visit(node, closureP, closureS);
+ visiting = visit(node, closure);
else if (node == tree)
return FALSE;
node = node->right;
@@ -323,13 +323,13 @@ static Tree stepUpLeft(Tree node, Tree *parentIO)
Bool TreeTraverse(Tree tree,
TreeCompareFunction compare,
TreeKeyFunction key,
- TreeVisitor visit, void *closureP, Size closureS)
+ TreeVisitor visit, void *closure)
{
Tree parent, node;
AVERT(Tree, tree);
AVER(FUNCHECK(visit));
- /* closureP, closureS arbitrary */
+ /* closure arbitrary */
parent = TreeEMPTY;
node = tree;
@@ -343,7 +343,7 @@ Bool TreeTraverse(Tree tree,
AVER(compare(parent, key(node)) == CompareLESS);
goto down;
}
- if (!visit(node, closureP, closureS))
+ if (!visit(node, closure))
goto abort;
if (TreeHasRight(node)) {
node = stepDownRight(node, &parent);
@@ -359,7 +359,7 @@ Bool TreeTraverse(Tree tree,
goto up;
}
node = stepUpRight(node, &parent);
- if (!visit(node, closureP, closureS))
+ if (!visit(node, closure))
goto abort;
if (!TreeHasRight(node))
goto up;
@@ -539,14 +539,14 @@ void TreeBalance(Tree *treeIO)
* See .
*/
void TreeTraverseAndDelete(Tree *treeIO, TreeVisitor visitor,
- void *closureP, Size closureS)
+ void *closure)
{
Tree *treeref = treeIO;
AVER(treeIO != NULL);
AVERT(Tree, *treeIO);
AVER(FUNCHECK(visitor));
- /* closureP and closureS are arbitrary */
+ /* closure arbitrary */
TreeToVine(treeIO);
@@ -554,7 +554,7 @@ void TreeTraverseAndDelete(Tree *treeIO, TreeVisitor visitor,
Tree tree = *treeref; /* Current node. */
Tree *nextref = &tree->right; /* Location of pointer to next node. */
Tree next = *nextref; /* Next node. */
- if ((*visitor)(tree, closureP, closureS)) {
+ if ((*visitor)(tree, closure)) {
/* Delete current node. */
*treeref = next;
} else {
diff --git a/mps/code/tree.h b/mps/code/tree.h
index 7b463067f0e..a4f883c48cf 100644
--- a/mps/code/tree.h
+++ b/mps/code/tree.h
@@ -123,13 +123,13 @@ extern Bool TreeFindNext(Tree *treeReturn, Tree root,
extern Bool TreeInsert(Tree *treeReturn, Tree root, Tree node,
TreeKey key, TreeCompareFunction compare);
-typedef Bool TreeVisitor(Tree tree, void *closureP, Size closureS);
+typedef Bool TreeVisitor(Tree tree, void *closure);
extern Bool TreeTraverse(Tree tree,
TreeCompareFunction compare,
TreeKeyFunction key,
- TreeVisitor visit, void *closureP, Size closureS);
+ TreeVisitor visit, void *closure);
extern Bool TreeTraverseMorris(Tree tree, TreeVisitor visit,
- void *closureP, Size closureS);
+ void *closure);
extern void TreeRotateLeft(Tree *nodeIO);
extern void TreeRotateRight(Tree *nodeIO);
@@ -139,7 +139,7 @@ extern Count TreeToVine(Tree *treeIO);
extern void TreeBalance(Tree *treeIO);
extern void TreeTraverseAndDelete(Tree *treeIO, TreeVisitor visitor,
- void *closureP, Size closureS);
+ void *closure);
#endif /* tree_h */
From 08f74131de373abd5e2b3eca1500525215ab0e46 Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Wed, 2 Mar 2016 19:36:58 +0000
Subject: [PATCH 076/759] Fixing build on w3i6mv.
Copied from Perforce
Change: 189550
ServerID: perforce.ravenbrook.com
---
mps/code/commpre.nmk | 2 ++
mps/code/scan.c | 8 ++++++++
mps/code/ssw3i6mv.c | 4 ++--
3 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk
index eaaa46c84a0..c6738c64c02 100644
--- a/mps/code/commpre.nmk
+++ b/mps/code/commpre.nmk
@@ -146,6 +146,7 @@ MPMCOMMON=\
[mpm] \
[mpsi] \
[nailboard] \
+ [policy] \
[pool] \
[poolabs] \
[poolmfs] \
@@ -160,6 +161,7 @@ MPMCOMMON=\
[root] \
[sa] \
[sac] \
+ [scan] \
[seg] \
[shield] \
[splay] \
diff --git a/mps/code/scan.c b/mps/code/scan.c
index 59bda4ba583..d1d2e8b1bf8 100644
--- a/mps/code/scan.c
+++ b/mps/code/scan.c
@@ -13,6 +13,7 @@
*/
#include "mps.h"
+#include "mpstd.h"
#define MPS_SCAN_AREA(test) \
@@ -35,6 +36,13 @@
} MPS_SCAN_END(ss);
+#ifdef MPS_BUILD_MV
+/* MSVC warning 4127 = conditional expression is constant */
+/* Objects to deliberate constant conditions in MPS_SCAN_AREA. */
+#pragma warning( disable : 4127 )
+#endif
+
+
/* mps_scan_area -- scan contiguous area of references
*
* This is a convenience function for scanning the contiguous area
diff --git a/mps/code/ssw3i6mv.c b/mps/code/ssw3i6mv.c
index 43dbbdcf6ad..47360a71f8e 100644
--- a/mps/code/ssw3i6mv.c
+++ b/mps/code/ssw3i6mv.c
@@ -41,7 +41,7 @@ SRCID(ssw3i6mv, "$Id$");
Word *StackContextStackHot(StackContext sc)
{
_JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
- Addr **p_rsp = (void *)&jb->Rsp;
+ Word **p_rsp = (void *)&jb->Rsp;
return *p_rsp;
}
@@ -52,7 +52,7 @@ Res StackContextScan(ScanState ss, StackContext sc,
mps_area_scan_t scan_area, void *closure)
{
_JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
- Addr *p_rbx = (void *)&jb->Rbx;
+ Word *p_rbx = (void *)&jb->Rbx;
/* These checks will just serve to warn us at compile-time if the
setjmp.h header changes to indicate that the registers we want aren't
From 41f082c075bb05dbb9d1998a17c4137d598a8424 Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Wed, 2 Mar 2016 19:37:54 +0000
Subject: [PATCH 077/759] Enabling perforce keyword expansion in scan.c.
Copied from Perforce
Change: 189551
ServerID: perforce.ravenbrook.com
From 9cec81e1a5b5dbafc3c6750c5b0dacf8efa35a9e Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Wed, 2 Mar 2016 20:42:30 +0000
Subject: [PATCH 078/759] Fixing build on w3i3mv.
Copied from Perforce
Change: 189554
ServerID: perforce.ravenbrook.com
---
mps/code/commpost.nmk | 3 +++
mps/code/ssw3i3mv.c | 4 ++--
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk
index 201094905bd..35b26ee19f3 100644
--- a/mps/code/commpost.nmk
+++ b/mps/code/commpost.nmk
@@ -291,6 +291,9 @@ $(PFM)\$(VARIETY)\segsmss.exe: $(PFM)\$(VARIETY)\segsmss.obj \
$(PFM)\$(VARIETY)\steptest.exe: $(PFM)\$(VARIETY)\steptest.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
+$(PFM)\$(VARIETY)\tagtest.exe: $(PFM)\$(VARIETY)\tagtest.obj \
+ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
+
$(PFM)\$(VARIETY)\teletest.exe: $(PFM)\$(VARIETY)\teletest.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
diff --git a/mps/code/ssw3i3mv.c b/mps/code/ssw3i3mv.c
index f38b6c5873b..df09d9b648d 100644
--- a/mps/code/ssw3i3mv.c
+++ b/mps/code/ssw3i3mv.c
@@ -34,7 +34,7 @@ SRCID(ssw3i3mv, "$Id$");
Word *StackContextStackHot(StackContext sc)
{
_JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
- Addr **p_esp = (void *)&jb->Esp;
+ Word **p_esp = (void *)&jb->Esp;
return *p_esp;
}
@@ -45,7 +45,7 @@ Res StackContextScan(ScanState ss, StackContext sc,
mps_area_scan_t scan_area, void *closure)
{
_JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
- Addr *p_ebx = (void *)&jb->Ebx;
+ Word *p_ebx = (void *)&jb->Ebx;
/* These checks will just serve to warn us at compile-time if the
setjmp.h header changes to indicate that the registers we want aren't
From 134bfc5303f40d507240298b52fe215269274d2b Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Wed, 2 Mar 2016 21:15:45 +0000
Subject: [PATCH 079/759] Removing files accidentally recreated by merge from
master sources in changelist 189545.
Copied from Perforce
Change: 189557
ServerID: perforce.ravenbrook.com
---
mps/code/ssixi3.c | 111 ----------------------------------------------
mps/code/ssixi6.c | 111 ----------------------------------------------
2 files changed, 222 deletions(-)
delete mode 100644 mps/code/ssixi3.c
delete mode 100644 mps/code/ssixi6.c
diff --git a/mps/code/ssixi3.c b/mps/code/ssixi3.c
deleted file mode 100644
index a922cabc5a6..00000000000
--- a/mps/code/ssixi3.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/* ssixi3.c: UNIX/INTEL STACK SCANNING
- *
- * $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
- *
- * This scans the stack and fixes the registers which may contain
- * roots. See
- *
- * This code was originally developed and tested on Linux, and then
- * copied to the FreeBSD and Darwin (OS X) operating systems where it
- * also seems to work. Note that on FreeBSD and Darwin it has not
- * been indepently verified with respect to any ABI documentation.
- *
- * This code is common to more than one Unix implementation on
- * Intel hardware (but is not portable Unix code).
- *
- * The registers edi, esi, ebx are the registers defined to be preserved
- * across function calls and therefore may contain roots.
- * These are pushed on the stack for scanning.
- *
- * SOURCES
- *
- * .source.callees.saves: Set of callee-saved registers taken from
- * CALL_USED_REGISTERS in /config/i386/i386.h.
- * ebp added to the list because gcc now doesn't always use it as
- * a frame pointer so it could contain a root.
- *
- * ASSUMPTIONS
- *
- * .assume.align: The stack pointer is assumed to be aligned on a word
- * boundary.
- *
- * .assume.asm.stack: The compiler must not do wacky things with the
- * stack pointer around a call since we need to ensure that the
- * callee-save regs are visible during TraceScanArea.
- *
- * .assume.asm.order: The volatile modifier should prevent movement
- * of code, which might break .assume.asm.stack.
- *
- */
-
-
-#include "mpm.h"
-
-SRCID(ssixi3, "$Id$");
-
-
-/* .assume.asm.order */
-#define ASMV(x) __asm__ volatile (x)
-
-
-Res StackScan(ScanState ss, Word *stackCold,
- mps_area_scan_t scan_area,
- void *closure)
-{
- Word calleeSaveRegs[4];
-
- /* .assume.asm.stack */
- /* Store the callee save registers on the stack so they get scanned
- * as they may contain roots.
- */
- ASMV("mov %%ebx, %0" : "=m" (calleeSaveRegs[0]));
- ASMV("mov %%esi, %0" : "=m" (calleeSaveRegs[1]));
- ASMV("mov %%edi, %0" : "=m" (calleeSaveRegs[2]));
- ASMV("mov %%ebp, %0" : "=m" (calleeSaveRegs[3]));
-
- return StackScanInner(ss, stackCold, calleeSaveRegs, NELEMS(calleeSaveRegs),
- scan_area, closure);
-}
-
-
-/* C. COPYRIGHT AND LICENSE
- *
- * Copyright (C) 2001-2002 Ravenbrook Limited .
- * 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.
- */
diff --git a/mps/code/ssixi6.c b/mps/code/ssixi6.c
deleted file mode 100644
index 2d70d62697c..00000000000
--- a/mps/code/ssixi6.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/* ssixi6.c: UNIX/x64 STACK SCANNING
- *
- * $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
- *
- * This scans the stack and fixes the registers which may contain
- * roots. See
- *
- * This code was branched from ssixi3.c (32-bit Intel) initially for the
- * port to XCI6LL (Mac OS X on x86_64 with Clang).
- *
- * This code is common to more than one Unix implementation on
- * Intel hardware (but is not portable Unix code). According to Wikipedia,
- * all the non-Windows platforms use the System V AMD64 ABI. See
- * .sources.callees.saves.
- *
- * SOURCES
- *
- * .sources.callees.saves:
- * "Registers %rbp, %rbx and %r12 through %r15 "belong" to the calling
- * function and the called function is required to preserve their values.
- * In other words, a called function must preserve these registers’ values
- * for its caller." -- System V AMD64 ABI
- *
- *
- * ASSUMPTIONS
- *
- * .assume.align: The stack pointer is assumed to be aligned on a word
- * boundary.
- *
- * .assume.asm.stack: The compiler must not do wacky things with the
- * stack pointer around a call since we need to ensure that the
- * callee-save regs are visible during TraceScanArea.
- *
- * .assume.asm.order: The volatile modifier should prevent movement
- * of code, which might break .assume.asm.stack.
- *
- */
-
-
-#include "mpm.h"
-
-SRCID(ssixi6, "$Id$");
-
-
-/* .assume.asm.order */
-#define ASMV(x) __asm__ volatile (x)
-
-
-Res StackScan(ScanState ss, Word *stackCold,
- mps_area_scan_t scan_area,
- void *closure)
-{
- Word calleeSaveRegs[6];
-
- /* .assume.asm.stack */
- /* Store the callee save registers on the stack so they get scanned
- * as they may contain roots.
- */
- ASMV("mov %%rbp, %0" : "=m" (calleeSaveRegs[0]));
- ASMV("mov %%rbx, %0" : "=m" (calleeSaveRegs[1]));
- ASMV("mov %%r12, %0" : "=m" (calleeSaveRegs[2]));
- ASMV("mov %%r13, %0" : "=m" (calleeSaveRegs[3]));
- ASMV("mov %%r14, %0" : "=m" (calleeSaveRegs[4]));
- ASMV("mov %%r15, %0" : "=m" (calleeSaveRegs[5]));
-
- return StackScanInner(ss, stackCold, calleeSaveRegs, NELEMS(calleeSaveRegs),
- scan_area, closure);
-}
-
-
-/* C. COPYRIGHT AND LICENSE
- *
- * Copyright (C) 2001-2014 Ravenbrook Limited .
- * 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.
- */
From adef302394d6162e074996cca5c616c36072f9cf Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Wed, 2 Mar 2016 22:24:48 +0000
Subject: [PATCH 080/759] Integrating build changes from fri6gc.gmk to
fri6ll.gmk to fix build on fri6ll.
Copied from Perforce
Change: 189564
ServerID: perforce.ravenbrook.com
---
mps/code/fri6ll.gmk | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/mps/code/fri6ll.gmk b/mps/code/fri6ll.gmk
index 6595410c9a3..f5c5acbf6f3 100644
--- a/mps/code/fri6ll.gmk
+++ b/mps/code/fri6ll.gmk
@@ -7,8 +7,17 @@
PFM = fri6ll
-MPMPF = lockix.c thix.c pthrdext.c vmix.c \
- protix.c protsgix.c prmcan.c prmci6fr.c ssixi6.c span.c
+MPMPF = \
+ lockix.c \
+ prmcan.c \
+ prmci6fr.c \
+ protix.c \
+ protsgix.c \
+ pthrdext.c \
+ span.c \
+ ssan.c \
+ thix.c \
+ vmix.c
LIBS = -lm -pthread
@@ -22,8 +31,6 @@ include ll.gmk
LINKFLAGS += -L/usr/local/lib
CFLAGSCOMPILER += -I/usr/local/include
-CC = cc
-
include comm.gmk
From 91cdd1c02e74fadaf94bffa577a773554d08ea9a Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Thu, 3 Mar 2016 02:10:58 +0000
Subject: [PATCH 081/759] Scanning the whole stack context on every platform
using portable code, because on no platform can we assume that any registers
never contain references.
Copied from Perforce
Change: 189570
ServerID: perforce.ravenbrook.com
---
mps/code/fri3gc.gmk | 1 -
mps/code/fri6gc.gmk | 1 -
mps/code/fri6ll.gmk | 1 -
mps/code/lii3gc.gmk | 1 -
mps/code/lii6gc.gmk | 1 -
mps/code/lii6ll.gmk | 1 -
mps/code/mps.c | 11 ---
mps/code/ss.c | 57 ++++++----------
mps/code/ss.h | 15 -----
mps/code/ssan.c | 87 ------------------------
mps/code/ssw3i3mv.c | 106 -----------------------------
mps/code/ssw3i3pc.c | 132 ------------------------------------
mps/code/ssw3i6mv.c | 121 ---------------------------------
mps/code/ssw3i6pc.c | 161 --------------------------------------------
mps/code/ssxci3.c | 88 ------------------------
mps/code/ssxci6.c | 98 ---------------------------
mps/code/w3i3mv.nmk | 1 -
mps/code/w3i3pc.nmk | 1 -
mps/code/w3i6mv.nmk | 1 -
mps/code/w3i6pc.nmk | 1 -
mps/code/xci3gc.gmk | 1 -
mps/code/xci6ll.gmk | 1 -
mps/design/ss.txt | 3 +-
23 files changed, 21 insertions(+), 870 deletions(-)
delete mode 100644 mps/code/ssan.c
delete mode 100644 mps/code/ssw3i3mv.c
delete mode 100644 mps/code/ssw3i3pc.c
delete mode 100644 mps/code/ssw3i6mv.c
delete mode 100644 mps/code/ssw3i6pc.c
delete mode 100644 mps/code/ssxci3.c
delete mode 100644 mps/code/ssxci6.c
diff --git a/mps/code/fri3gc.gmk b/mps/code/fri3gc.gmk
index 2a4f6893012..2c87fd64750 100644
--- a/mps/code/fri3gc.gmk
+++ b/mps/code/fri3gc.gmk
@@ -15,7 +15,6 @@ MPMPF = \
protsgix.c \
pthrdext.c \
span.c \
- ssan.c \
thix.c \
vmix.c
diff --git a/mps/code/fri6gc.gmk b/mps/code/fri6gc.gmk
index 5e58bf4e931..deeb9218d64 100644
--- a/mps/code/fri6gc.gmk
+++ b/mps/code/fri6gc.gmk
@@ -15,7 +15,6 @@ MPMPF = \
protsgix.c \
pthrdext.c \
span.c \
- ssan.c \
thix.c \
vmix.c
diff --git a/mps/code/fri6ll.gmk b/mps/code/fri6ll.gmk
index f5c5acbf6f3..6a32fd0961d 100644
--- a/mps/code/fri6ll.gmk
+++ b/mps/code/fri6ll.gmk
@@ -15,7 +15,6 @@ MPMPF = \
protsgix.c \
pthrdext.c \
span.c \
- ssan.c \
thix.c \
vmix.c
diff --git a/mps/code/lii3gc.gmk b/mps/code/lii3gc.gmk
index 9ecf05d148b..7dbd7ef6dae 100644
--- a/mps/code/lii3gc.gmk
+++ b/mps/code/lii3gc.gmk
@@ -15,7 +15,6 @@ MPMPF = \
protli.c \
pthrdext.c \
span.c \
- ssan.c \
thix.c \
vmix.c
diff --git a/mps/code/lii6gc.gmk b/mps/code/lii6gc.gmk
index b5df73fe7f7..8b479a08476 100644
--- a/mps/code/lii6gc.gmk
+++ b/mps/code/lii6gc.gmk
@@ -15,7 +15,6 @@ MPMPF = \
protli.c \
pthrdext.c \
span.c \
- ssan.c \
thix.c \
vmix.c
diff --git a/mps/code/lii6ll.gmk b/mps/code/lii6ll.gmk
index 4e4811e3204..64325194025 100644
--- a/mps/code/lii6ll.gmk
+++ b/mps/code/lii6ll.gmk
@@ -15,7 +15,6 @@ MPMPF = \
protli.c \
pthrdext.c \
span.c \
- ssan.c \
thix.c \
vmix.c
diff --git a/mps/code/mps.c b/mps/code/mps.c
index 4e113d0ec24..48b82ae675c 100644
--- a/mps/code/mps.c
+++ b/mps/code/mps.c
@@ -110,7 +110,6 @@
#include "protan.c" /* generic memory protection */
#include "prmcan.c" /* generic protection mutator context */
#include "span.c" /* generic stack probe */
-#include "ssan.c" /* generic stack scanner */
/* Mac OS X on 32-bit Intel built with Clang or GCC */
@@ -124,7 +123,6 @@
#include "proti3.c" /* 32-bit Intel mutator context decoding */
#include "prmci3xc.c" /* 32-bit Intel for Mac OS X mutator context */
#include "span.c" /* generic stack probe */
-#include "ssxci3.c" /* OS X on 32-bit Intel stack scan */
/* Mac OS X on 64-bit Intel build with Clang or GCC */
@@ -138,7 +136,6 @@
#include "proti6.c" /* 64-bit Intel mutator context decoding */
#include "prmci6xc.c" /* 64-bit Intel for Mac OS X mutator context */
#include "span.c" /* generic stack probe */
-#include "ssxci6.c" /* OS X on 64-bit Intel stack scan */
/* FreeBSD on 32-bit Intel built with GCC */
@@ -153,7 +150,6 @@
#include "prmcan.c" /* generic mutator context */
#include "prmci3fr.c" /* 32-bit Intel for FreeBSD mutator context */
#include "span.c" /* generic stack probe */
-#include "ssan.c" /* generic stack scan */
/* FreeBSD on 64-bit Intel built with GCC */
@@ -168,7 +164,6 @@
#include "prmcan.c" /* generic mutator context */
#include "prmci6fr.c" /* 64-bit Intel for FreeBSD mutator context */
#include "span.c" /* generic stack probe */
-#include "ssan.c" /* generic stack scan */
/* Linux on 32-bit Intel with GCC */
@@ -183,7 +178,6 @@
#include "proti3.c" /* 32-bit Intel mutator context */
#include "prmci3li.c" /* 32-bit Intel for Linux mutator context */
#include "span.c" /* generic stack probe */
-#include "ssan.c" /* generic stack scan */
/* Linux on 64-bit Intel with GCC or Clang */
@@ -198,7 +192,6 @@
#include "proti6.c" /* 64-bit Intel mutator context */
#include "prmci6li.c" /* 64-bit Intel for Linux mutator context */
#include "span.c" /* generic stack probe */
-#include "ssan.c" /* generic stack scan */
/* Windows on 32-bit Intel with Microsoft Visual Studio */
@@ -211,7 +204,6 @@
#include "protw3.c" /* Windows protection */
#include "proti3.c" /* 32-bit Intel mutator context decoding */
#include "prmci3w3.c" /* Windows on 32-bit Intel mutator context */
-#include "ssw3i3mv.c" /* Windows on 32-bit Intel stack scan for Microsoft C */
#include "spw3i3.c" /* Windows on 32-bit Intel stack probe */
#include "mpsiw3.c" /* Windows interface layer extras */
@@ -226,7 +218,6 @@
#include "protw3.c" /* Windows protection */
#include "proti6.c" /* 64-bit Intel mutator context decoding */
#include "prmci6w3.c" /* Windows on 64-bit Intel mutator context */
-#include "ssw3i6mv.c" /* Windows on 64-bit Intel stack scan for Microsoft C */
#include "spw3i6.c" /* Windows on 64-bit Intel stack probe */
#include "mpsiw3.c" /* Windows interface layer extras */
@@ -241,7 +232,6 @@
#include "protw3.c" /* Windows protection */
#include "proti3.c" /* 32-bit Intel mutator context decoding */
#include "prmci3w3.c" /* Windows on 32-bit Intel mutator context */
-#include "ssw3i3pc.c" /* Windows on 32-bit stack scan for Pelles C */
#include "spw3i3.c" /* 32-bit Intel stack probe */
#include "mpsiw3.c" /* Windows interface layer extras */
@@ -256,7 +246,6 @@
#include "protw3.c" /* Windows protection */
#include "proti6.c" /* 64-bit Intel mutator context decoding */
#include "prmci6w3.c" /* Windows on 64-bit Intel mutator context */
-#include "ssw3i6pc.c" /* Windows on 64-bit stack scan for Pelles C */
#include "spw3i6.c" /* 64-bit Intel stack probe */
#include "mpsiw3.c" /* Windows interface layer extras */
diff --git a/mps/code/ss.c b/mps/code/ss.c
index 2c57dec0a32..7d8d8d7dd96 100644
--- a/mps/code/ss.c
+++ b/mps/code/ss.c
@@ -11,14 +11,15 @@
* support, may not be true on all platforms. See
* .
*
- * .assume.desc: The stack is descending (and so stackTop is a lower
- * address than stackBot).
+ * .assume.desc: The stack is descending (and so stackHot is a lower
+ * address than stackCold).
*
* .assume.full: The stack convention is "full" (and so we must scan
- * the word pointed to by stackTop but not the word pointed to by
- * stackBot).
+ * the word pointed to by stackHot but not the word pointed to by
+ * stackCold).
*
- * .assume.align: Addresses on the stack are aligned to sizeof(Addr).
+ * .assume.align: Addresses on the stack are word-aligned. TODO: It's
+ * not clear why we assume this, since it depends on the area scanner.
*/
#include "mpm.h"
@@ -28,36 +29,13 @@ SRCID(ss, "$Id$");
/* StackScan -- scan the mutator's stack and registers */
-static Res stackScanInner(ScanState ss, Word *stackCold,
- StackContext sc,
- mps_area_scan_t scan_area, void *closure)
-{
- Word *stackHot;
- Res res;
-
- AVERT(ScanState, ss);
-
- stackHot = StackContextStackHot(sc);
- AVER(stackHot < stackCold); /* .assume.desc */
- AVER(AddrIsAligned((Addr)stackHot, sizeof(Addr))); /* .assume.align */
-
- res = TraceScanArea(ss, stackHot, stackCold,
- scan_area, closure); /* .assume.full */
- if (res != ResOK)
- return res;
-
- res = StackContextScan(ss, sc, scan_area, closure);
- if (res != ResOK)
- return res;
-
- return ResOK;
-}
-
Res StackScan(ScanState ss, Word *stackCold,
mps_area_scan_t scan_area, void *closure)
{
+ StackContextStruct scStruct;
+ StackContext sc;
Arena arena;
- Res res;
+ Word *stackHot;
AVERT(ScanState, ss);
@@ -65,16 +43,19 @@ Res StackScan(ScanState ss, Word *stackCold,
AVER(arena->scAtArenaEnter != NULL);
if (arena->scAtArenaEnter) {
- res = stackScanInner(ss, stackCold, arena->scAtArenaEnter,
- scan_area, closure);
+ sc = arena->scAtArenaEnter;
} else {
/* Somehow missed saving the context at the entry point (see
- * ): do it now. */
- StackContextStruct sc;
- STACK_CONTEXT_SAVE(&sc);
- res = stackScanInner(ss, stackCold, &sc, scan_area, closure);
+ ): do it now. */
+ sc = &scStruct;
+ STACK_CONTEXT_SAVE(sc);
}
- return res;
+
+ stackHot = (void *)sc;
+ AVER(stackHot < stackCold); /* .assume.desc */
+ AVER(AddrIsAligned((Addr)stackHot, sizeof(Word))); /* .assume.align */
+
+ return TraceScanArea(ss, stackHot, stackCold, scan_area, closure);
}
diff --git a/mps/code/ss.h b/mps/code/ss.h
index 8dacef0db1c..09eea92cecd 100644
--- a/mps/code/ss.h
+++ b/mps/code/ss.h
@@ -44,21 +44,6 @@ typedef struct StackContextStruct {
END
-/* StackContextStackHot -- hot end of the mutator's stack
- *
- * Retrieves the stacl pointer at the point when the context was saved by
- * STACK_CONTEXT_SAVE.
- */
-
-extern Word *StackContextStackHot(StackContext sc);
-
-
-/* StackContextScan -- scan references in the stack context */
-
-extern Res StackContextScan(ScanState ss, StackContext sc,
- mps_area_scan_t scan_area, void *closure);
-
-
/* STACK_CONTEXT_SAVE -- save the callee-saves and stack pointer */
#if defined(MPS_OS_XC)
diff --git a/mps/code/ssan.c b/mps/code/ssan.c
deleted file mode 100644
index 7cd7c15c7c9..00000000000
--- a/mps/code/ssan.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/* ssan.c: GENERIC STACK SCANNING
- *
- * $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
- *
- * This makes a best effort to decode the stack context and scan the
- * registers which may contain roots, using only the features of the
- * Standard C library. See .
- */
-
-#include "ss.h"
-
-SRCID(ssan, "$Id$");
-
-
-/* StackContextStackHot -- top" of the mutator's stack
- *
- * Retrieves the stack pointer at the point when the context was
- * saved by STACK_CONTEXT_SAVE.
- *
- * .assume: This assumes that the structure pointed to by sc is
- * stack-allocated "above" the mutator's stack, and so its address is
- * a conservative approximation to the top of the mutator's stack. The
- * use of STACK_CONTEXT_SAVE in mpsi.c assures this.
- */
-
-Word *StackContextStackHot(StackContext sc)
-{
- return (void *)sc;
-}
-
-
-/* StackContextScan -- scan references in the stack context
- *
- * This conservatively scans the whole of the StackContext. The
- * PointerAlignDown is necessary in case the size of the jump buffer
- * is not a multiple of sizeof(Word).
- */
-
-Res StackContextScan(ScanState ss, StackContext sc,
- mps_area_scan_t scan_area, void *closure)
-{
- return TraceScanArea(ss, (void *)sc, PointerAlignDown(sc + 1, sizeof(Word)),
- scan_area, closure);
-}
-
-
-/* C. COPYRIGHT AND LICENSE
- *
- * Copyright (C) 2001-2014 Ravenbrook Limited .
- * 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.
- */
diff --git a/mps/code/ssw3i3mv.c b/mps/code/ssw3i3mv.c
deleted file mode 100644
index df09d9b648d..00000000000
--- a/mps/code/ssw3i3mv.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/* ssw3i3mv.c: STACK SCANNING FOR WINDOWS ON IA-32 WITH MICROSOFT VISUAL C
- *
- * $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
- *
- * This decodes the stack context and scans the registers which may
- * contain roots. See .
- *
- * REFERENCES
- *
- * "Argument Passing and Naming Conventions"; MSDN; Microsoft Corporation;
- * .
- *
- * "Calling conventions for different C++ compilers and operating systems";
- * Agner Fog; Copenhagen University College of Engineering; 2014-08-07;
- * .
- */
-
-#include "mpm.h"
-
-SRCID(ssw3i3mv, "$Id$");
-
-#if !defined(MPS_PF_W3I3MV)
-#error "ssw3i3mv.c is specific to MPS_PF_W3I3MV."
-#endif
-
-
-/* StackContextStackHot -- hot end of the mutator's stack
- *
- * Retrieves the stack pointer at the point when the context was saved
- * by STACK_CONTEXT_SAVE.
- */
-
-Word *StackContextStackHot(StackContext sc)
-{
- _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
- Word **p_esp = (void *)&jb->Esp;
- return *p_esp;
-}
-
-
-/* StackContextScan -- scan references in the stack context */
-
-Res StackContextScan(ScanState ss, StackContext sc,
- mps_area_scan_t scan_area, void *closure)
-{
- _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
- Word *p_ebx = (void *)&jb->Ebx;
-
- /* These checks will just serve to warn us at compile-time if the
- setjmp.h header changes to indicate that the registers we want aren't
- saved any more. */
- AVER(sizeof jb->Edi == sizeof(Word));
- AVER(sizeof jb->Esi == sizeof(Word));
- AVER(sizeof jb->Ebx == sizeof(Word));
-
- /* Ensure that the callee-save registers will be found by
- TraceScanArea when it's passed the address of the Ebx
- field. */
- AVER(offsetof(_JUMP_BUFFER, Edi) == offsetof(_JUMP_BUFFER, Ebx) + 4);
- AVER(offsetof(_JUMP_BUFFER, Esi) == offsetof(_JUMP_BUFFER, Ebx) + 8);
-
- return TraceScanArea(ss, p_ebx, p_ebx + 3, scan_area, closure);
-}
-
-
-/* C. COPYRIGHT AND LICENSE
- *
- * Copyright (C) 2001-2002 Ravenbrook Limited .
- * 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.
- */
diff --git a/mps/code/ssw3i3pc.c b/mps/code/ssw3i3pc.c
deleted file mode 100644
index d351c8b67bc..00000000000
--- a/mps/code/ssw3i3pc.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/* ssw3i3pc.c: STACK SCANNING FOR WINDOWS ON IA-32 WITH PELLES C
- *
- * $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
- *
- * This decodes the stack context and scans the registers which may
- * contain roots. See .
- *
- * .assume.ms-compat: We rely on the fact that Pelles C's setjmp stores
- * the callee-save registers in the jmp_buf and is compatible with Microsoft
- * C. The Pelles C 7.00 setjmp.h header has a comment "MS compatible". See
- * also "Is Pelles C's jmp_buf compatible with Microsoft C's?"
- *
- *
- * REFERENCES
- *
- * "Argument Passing and Naming Conventions"; MSDN; Microsoft Corporation;
- * .
- *
- * "Calling conventions for different C++ compilers and operating systems";
- * Agner Fog; Copenhagen University College of Engineering; 2014-08-07;
- * .
- */
-
-#include "mpm.h"
-#include
-
-SRCID(ssw3i3pc, "$Id$");
-
-#if !defined(MPS_PF_W3I3PC)
-#error "ssw3i3pc.c is specific to MPS_PF_W3I3PC."
-#endif
-
-
-/* This definition isn't in the Pelles C headers, so we reproduce it here.
- * See .assume.ms-compat. */
-
-typedef struct __JUMP_BUFFER {
- unsigned long Ebp;
- unsigned long Ebx;
- unsigned long Edi;
- unsigned long Esi;
- unsigned long Esp;
- unsigned long Eip;
- unsigned long Registration;
- unsigned long TryLevel;
- unsigned long Cookie;
- unsigned long UnwindFunc;
- unsigned long UnwindData[6];
-} _JUMP_BUFFER;
-
-
-/* StackContextStackHot -- tho end of the mutator's stack
- *
- * Retrieves the stack pointer at the point when the context was saved
- * by STACK_CONTEXT_SAVE.
- */
-
-Word *StackContextStackHot(StackContext sc)
-{
- _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
- Addr **p_esp = (void *)&jb->Esp;
- return *p_esp;
-}
-
-
-/* StackContextScan -- scan references in the stack context */
-
-Res StackContextScan(ScanState ss, StackContext sc,
- mps_area_scan_t scan_area, void *closure)
-{
- /* .assume.ms-compat */
- _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
- Addr *p_ebx = (void *)&jb->Ebx;
-
- /* These checks, on the _JUMP_BUFFER defined above, are mainly here
- * to maintain similarity to the matching code on the MPS_BUILD_MV
- * version of this code. */
- AVER(sizeof(((_JUMP_BUFFER *)jb)->Ebx) == sizeof(Word));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->Edi) == sizeof(Word));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->Esi) == sizeof(Word));
-
- /* Ensure that the callee-save registers will be found by
- TraceScanArea when it's passed the address of the Ebx
- field. */
- AVER(offsetof(_JUMP_BUFFER, Edi) == offsetof(_JUMP_BUFFER, Ebx) + 4);
- AVER(offsetof(_JUMP_BUFFER, Esi) == offsetof(_JUMP_BUFFER, Ebx) + 8);
-
- return TraceScanArea(ss, p_ebx, p_ebx + 3, scan_area, closure);
-}
-
-
-/* C. COPYRIGHT AND LICENSE
- *
- * Copyright (C) 2001-2014 Ravenbrook Limited .
- * 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.
- */
diff --git a/mps/code/ssw3i6mv.c b/mps/code/ssw3i6mv.c
deleted file mode 100644
index 47360a71f8e..00000000000
--- a/mps/code/ssw3i6mv.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/* ssw3i6mv.c: STACK SCANNING FOR WIN64 WITH MICROSOFT C
- *
- * $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
- *
- * This decodes the stack context and scans the registers which may
- * contain roots. See .
- *
- * REFERENCES
- *
- * "Overview of x64 Calling Conventions"; MSDN; Microsoft Corporation;
- * .
- *
- * "Caller/Callee Saved Registers"; MSDN; Microsoft Corporation;
- * .
- *
- * "Register Usage"; MSDN; Microsoft Corporation;
- * .
- *
- * "Calling conventions for different C++ compilers and operating systems";
- * Agner Fog; Copenhagen University College of Engineering; 2014-08-07;
- * .
- */
-
-#include "mpm.h"
-#include
-
-SRCID(ssw3i6mv, "$Id$");
-
-#if !defined(MPS_PF_W3I6MV)
-#error "ssw3i6mv.c is specific to MPS_PF_W3I6MV."
-#endif
-
-
-/* StackContextStackHot -- hot end of the mutator's stack
- *
- * Retrieves the stack pointer at the point when the context was saved
- * by STACK_CONTEXT_SAVE.
- */
-
-Word *StackContextStackHot(StackContext sc)
-{
- _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
- Word **p_rsp = (void *)&jb->Rsp;
- return *p_rsp;
-}
-
-
-/* StackContextScan -- scan references in the stack context */
-
-Res StackContextScan(ScanState ss, StackContext sc,
- mps_area_scan_t scan_area, void *closure)
-{
- _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
- Word *p_rbx = (void *)&jb->Rbx;
-
- /* These checks will just serve to warn us at compile-time if the
- setjmp.h header changes to indicate that the registers we want aren't
- saved any more. */
- AVER(sizeof jb->Rdi == sizeof(Word));
- AVER(sizeof jb->Rsi == sizeof(Word));
- AVER(sizeof jb->Rbp == sizeof(Word));
- AVER(sizeof jb->R12 == sizeof(Word));
- AVER(sizeof jb->R13 == sizeof(Word));
- AVER(sizeof jb->R14 == sizeof(Word));
- AVER(sizeof jb->R15 == sizeof(Word));
-
- /* The layout of the jmp_buf forces us to harmlessly scan Rsp as well. */
- AVER(offsetof(_JUMP_BUFFER, Rsp) == offsetof(_JUMP_BUFFER, Rbx) + 8);
- AVER(offsetof(_JUMP_BUFFER, Rbp) == offsetof(_JUMP_BUFFER, Rbx) + 16);
- AVER(offsetof(_JUMP_BUFFER, Rsi) == offsetof(_JUMP_BUFFER, Rbx) + 24);
- AVER(offsetof(_JUMP_BUFFER, Rdi) == offsetof(_JUMP_BUFFER, Rbx) + 32);
- AVER(offsetof(_JUMP_BUFFER, R12) == offsetof(_JUMP_BUFFER, Rbx) + 40);
- AVER(offsetof(_JUMP_BUFFER, R13) == offsetof(_JUMP_BUFFER, Rbx) + 48);
- AVER(offsetof(_JUMP_BUFFER, R14) == offsetof(_JUMP_BUFFER, Rbx) + 56);
- AVER(offsetof(_JUMP_BUFFER, R15) == offsetof(_JUMP_BUFFER, Rbx) + 64);
-
- return TraceScanArea(ss, p_rbx, p_rbx + 9, scan_area, closure);
-}
-
-
-/* C. COPYRIGHT AND LICENSE
- *
- * Copyright (C) 2001-2014 Ravenbrook Limited .
- * 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.
- */
diff --git a/mps/code/ssw3i6pc.c b/mps/code/ssw3i6pc.c
deleted file mode 100644
index 6229338f7b4..00000000000
--- a/mps/code/ssw3i6pc.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/* ssw3i6pc.c: STACK SCANNING FOR WIN64 WITH PELLES C
- *
- * $Id$
- * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
- *
- * This decodes the stack context and scans the registers which may
- * contain roots. See .
- *
- * .assume.ms-compat: We rely on the fact that Pelles C's setjmp stores
- * the callee-save registers in the jmp_buf and is compatible with Microsoft
- * C. The Pelles C 7.00 setjmp.h header has a comment "MS compatible". See
- * also "Is Pelles C's jmp_buf compatible with Microsoft C's?"
- *
- *
- * REFERENCES
- *
- * "Overview of x64 Calling Conventions"; MSDN; Microsoft Corporation;
- * .
- *
- * "Caller/Callee Saved Registers"; MSDN; Microsoft Corporation;
- * .
- *
- * "Register Usage"; MSDN; Microsoft Corporation;
- * .
- *
- * "Calling conventions for different C++ compilers and operating systems";
- * Agner Fog; Copenhagen University College of Engineering; 2014-08-07;
- * .
- */
-
-#include "mpm.h"
-#include
-
-SRCID(ssw3i6pc, "$Id$");
-
-#if !defined(MPS_PF_W3I6PC)
-#error "ssw3i6pc.c is specific to MPS_PF_W3I6PC."
-#endif
-
-
-/* This definition isn't in the Pelles C headers, so we reproduce it here.
- * See .assume.ms-compat. */
-
-typedef /* _CRT_ALIGN(16) */ struct _SETJMP_FLOAT128 {
- unsigned __int64 Part[2];
-} SETJMP_FLOAT128;
-
-typedef struct _JUMP_BUFFER {
- unsigned __int64 Frame;
- unsigned __int64 Rbx;
- unsigned __int64 Rsp;
- unsigned __int64 Rbp;
- unsigned __int64 Rsi;
- unsigned __int64 Rdi;
- unsigned __int64 R12;
- unsigned __int64 R13;
- unsigned __int64 R14;
- unsigned __int64 R15;
- unsigned __int64 Rip;
- unsigned __int64 Spare;
-
- SETJMP_FLOAT128 Xmm6;
- SETJMP_FLOAT128 Xmm7;
- SETJMP_FLOAT128 Xmm8;
- SETJMP_FLOAT128 Xmm9;
- SETJMP_FLOAT128 Xmm10;
- SETJMP_FLOAT128 Xmm11;
- SETJMP_FLOAT128 Xmm12;
- SETJMP_FLOAT128 Xmm13;
- SETJMP_FLOAT128 Xmm14;
- SETJMP_FLOAT128 Xmm15;
-} _JUMP_BUFFER;
-
-
-/* StackContextStackHot -- hot end of the mutator's stack
- *
- * Retrieves the stack pointer at the point when the context was saved
- * by STACK_CONTEXT_SAVE.
- */
-
-Word *StackContextStackHot(StackContext sc)
-{
- _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
- Addr **p_rsp = (void *)&jb->Rsp;
- return *p_rsp;
-}
-
-
-/* StackContextScan -- scan references in the stack context */
-
-Res StackContextScan(ScanState ss, StackContext sc,
- mps_area_scan_t scan_area, void *closure)
-{
- _JUMP_BUFFER *jb = (_JUMP_BUFFER *)&sc->jumpBuffer;
- Addr *p_rbx = (void *)&jb->Rbx;
-
- /* These checks will just serve to warn us at compile-time if the
- setjmp.h header changes to indicate that the registers we want aren't
- saved any more. */
- AVER(sizeof jb->Rdi == sizeof(Word));
- AVER(sizeof jb->Rsi == sizeof(Word));
- AVER(sizeof jb->Rbp == sizeof(Word));
- AVER(sizeof jb->R12 == sizeof(Word));
- AVER(sizeof jb->R13 == sizeof(Word));
- AVER(sizeof jb->R14 == sizeof(Word));
- AVER(sizeof jb->R15 == sizeof(Word));
-
- /* The layout of the jmp_buf forces us to harmlessly scan Rsp as well. */
- AVER(offsetof(_JUMP_BUFFER, Rsp) == offsetof(_JUMP_BUFFER, Rbx) + 8);
- AVER(offsetof(_JUMP_BUFFER, Rbp) == offsetof(_JUMP_BUFFER, Rbx) + 16);
- AVER(offsetof(_JUMP_BUFFER, Rsi) == offsetof(_JUMP_BUFFER, Rbx) + 24);
- AVER(offsetof(_JUMP_BUFFER, Rdi) == offsetof(_JUMP_BUFFER, Rbx) + 32);
- AVER(offsetof(_JUMP_BUFFER, R12) == offsetof(_JUMP_BUFFER, Rbx) + 40);
- AVER(offsetof(_JUMP_BUFFER, R13) == offsetof(_JUMP_BUFFER, Rbx) + 48);
- AVER(offsetof(_JUMP_BUFFER, R14) == offsetof(_JUMP_BUFFER, Rbx) + 56);
- AVER(offsetof(_JUMP_BUFFER, R15) == offsetof(_JUMP_BUFFER, Rbx) + 64);
-
- return TraceScanArea(ss, p_rbx, p_rbx + 9, scan_area, closure);
-}
-
-
-/* C. COPYRIGHT AND LICENSE
- *
- * Copyright (C) 2001-2014 Ravenbrook Limited .
- * 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.
- */
diff --git a/mps/code/ssxci3.c b/mps/code/ssxci3.c
deleted file mode 100644
index 081b35e4726..00000000000
--- a/mps/code/ssxci3.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/* ssxci3.c: STACK SCANNING FOR OS X ON IA-32
- *
- * $Id$
- * Copyright (c) 2012-2014 Ravenbrook Limited. See end of file for license.
- *
- * This decodes the stack context and scans the registers which may
- * contain roots. See .
- */
-
-#include "mpm.h"
-
-SRCID(ssxci3, "$Id$");
-
-#if !defined(MPS_OS_XC) || !defined(MPS_ARCH_I3)
-#error "ssxci3.c is specific to MPS_OS_XC and MPS_ARCH_I3."
-#endif
-
-
-/* Offset of ESP in the jmp_buf in bytes, as defined in _setjmp.s.
- * See the implementation of _setjmp in
- * */
-
-#define JB_ESP 36
-
-
-/* StackContextStackHot -- hot end of the mutator's stack
- *
- * Retrieve the stack pointer at the point when the context was saved
- * by STACK_CONTEXT_SAVE.
- */
-
-Word *StackContextStackHot(StackContext sc)
-{
- Word **p_esp = PointerAdd(&sc->jumpBuffer, JB_ESP);
- return *p_esp;
-}
-
-
-/* StackContextScan -- scan references in the stack context */
-
-Res StackContextScan(ScanState ss, StackContext sc,
- mps_area_scan_t scan_area, void *closure)
-{
- return TraceScanArea(ss, (void *)sc, (void *)(sc + 1),
- scan_area, closure);
-}
-
-
-/* C. COPYRIGHT AND LICENSE
- *
- * Copyright (C) 2012-2014 Ravenbrook Limited .
- * 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.
- */
diff --git a/mps/code/ssxci6.c b/mps/code/ssxci6.c
deleted file mode 100644
index 2511d275993..00000000000
--- a/mps/code/ssxci6.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/* ssxci6.c: STACK SCANNING FOR OS X ON x86-64
- *
- * $Id$
- * Copyright (c) 2012-2014 Ravenbrook Limited. See end of file for license.
- *
- * This decodes the stack context and scans the registers which may
- * contain roots. See .
- */
-
-#include "mpm.h"
-
-SRCID(ssxci6, "$Id$");
-
-#if !defined(MPS_OS_XC) || !defined(MPS_ARCH_I6)
-#error "ssxci6.c is specific to MPS_OS_XC and MPS_ARCH_I6."
-#endif
-
-
-/* Offset of RSP in the jmp_buf in bytes, as defined in _setjmp.s.
- * See the implementation of _setjmp in
- * */
-
-#define JB_RSP 16
-
-
-/* StackContextStackHot -- hot end of the mutator's stack
- *
- * Retrieve the stack pointer at the point when the context was saved
- * by STACK_CONTEXT_SAVE.
- */
-
-Word *StackContextStackHot(StackContext sc)
-{
- Word **p_rsp = PointerAdd(&(sc)->jumpBuffer, JB_RSP);
- return *p_rsp;
-}
-
-
-/* StackContextScan -- scan references in the stack context
- *
- * We conservatively scan the whole of the jump buffer, assuming that
- * all references are stored at aligned positions.
- *
- * The PointerAlignDown is necessary because the size of the jump
- * buffer is not a multiple of sizeof(Addr) on this platform: see
- * setjmp.h, where _JBLEN is 37.
- *
- */
-
-Res StackContextScan(ScanState ss, StackContext sc,
- mps_area_scan_t scan_area, void *closure)
-{
- return TraceScanArea(ss, (void *)sc,
- PointerAlignDown(sc + 1, sizeof(Addr)),
- scan_area, closure);
-}
-
-
-/* C. COPYRIGHT AND LICENSE
- *
- * Copyright (C) 2012-2014 Ravenbrook Limited .
- * 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.
- */
diff --git a/mps/code/w3i3mv.nmk b/mps/code/w3i3mv.nmk
index eb8bacce7cb..6d1b8beaacc 100644
--- a/mps/code/w3i3mv.nmk
+++ b/mps/code/w3i3mv.nmk
@@ -12,7 +12,6 @@ MPMPF = \
[proti3] \
[protw3] \
[spw3i3] \
- [ssw3i3mv] \
[thw3] \
[thw3i3] \
[vmw3]
diff --git a/mps/code/w3i3pc.nmk b/mps/code/w3i3pc.nmk
index 82be17e4057..1d4e5a00141 100644
--- a/mps/code/w3i3pc.nmk
+++ b/mps/code/w3i3pc.nmk
@@ -12,7 +12,6 @@ MPMPF = \
[proti3] \
[protw3] \
[spw3i3] \
- [ssw3i3pc] \
[thw3] \
[thw3i3] \
[vmw3]
diff --git a/mps/code/w3i6mv.nmk b/mps/code/w3i6mv.nmk
index 2353d4cddab..445bae82457 100644
--- a/mps/code/w3i6mv.nmk
+++ b/mps/code/w3i6mv.nmk
@@ -12,7 +12,6 @@ MPMPF = \
[proti6] \
[protw3] \
[spw3i6] \
- [ssw3i6mv] \
[thw3] \
[thw3i6] \
[vmw3]
diff --git a/mps/code/w3i6pc.nmk b/mps/code/w3i6pc.nmk
index 272b96e5a2c..7e73040b02a 100644
--- a/mps/code/w3i6pc.nmk
+++ b/mps/code/w3i6pc.nmk
@@ -16,7 +16,6 @@ MPMPF = \
[proti6] \
[protw3] \
[spw3i6] \
- [ssw3i6pc] \
[thw3] \
[thw3i6] \
[vmw3]
diff --git a/mps/code/xci3gc.gmk b/mps/code/xci3gc.gmk
index 1540fe1ddc1..3cea6750696 100644
--- a/mps/code/xci3gc.gmk
+++ b/mps/code/xci3gc.gmk
@@ -16,7 +16,6 @@ MPMPF = \
protix.c \
protxc.c \
span.c \
- ssxci3.c \
thxc.c \
vmix.c
diff --git a/mps/code/xci6ll.gmk b/mps/code/xci6ll.gmk
index 8849e4d4b58..ab26bfdbc3a 100644
--- a/mps/code/xci6ll.gmk
+++ b/mps/code/xci6ll.gmk
@@ -20,7 +20,6 @@ MPMPF = \
protix.c \
protxc.c \
span.c \
- ssxci6.c \
thxc.c \
vmix.c
diff --git a/mps/design/ss.txt b/mps/design/ss.txt
index 44be9547f76..f1403f81667 100644
--- a/mps/design/ss.txt
+++ b/mps/design/ss.txt
@@ -22,7 +22,8 @@ _`.readership`: Any MPS developer; anyone porting the MPS to a new
platform.
_`.overview`: This module locates and scans references in the control
-stack and registers of the *current* thread.
+stack and registers of the *current* thread (the one that has called
+in to the MPS).
_`.other`: The thread manager module is responsible for scanning the
control stack and registers of *other* threads. See
From 29616c7063afae52298a105549d2255e7e8f57fd Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Thu, 3 Mar 2016 02:39:57 +0000
Subject: [PATCH 082/759] Explaining reasons for simplified (and portable)
stack scanner.
Copied from Perforce
Change: 189575
ServerID: perforce.ravenbrook.com
---
mps/design/ss.txt | 77 +++++++++++++++++------------------------------
1 file changed, 28 insertions(+), 49 deletions(-)
diff --git a/mps/design/ss.txt b/mps/design/ss.txt
index f1403f81667..1d3271b4677 100644
--- a/mps/design/ss.txt
+++ b/mps/design/ss.txt
@@ -40,7 +40,7 @@ mail.richard.2012-08-03.14-36_.
Requirements
------------
-_`.req.stack.top`: Must locate the top of the mutator's stack. (This
+_`.req.stack.hot`: Must locate the hot end of the mutator's stack. (This
is needed for conservative garbage collection of uncooperative code,
where references might be stored by mutator on its stack.)
@@ -123,15 +123,23 @@ consists of information sufficient for a call to the ``longjmp``
function to return execution to the correct block and invocation of
that block, were it called recursively." We believe that any
reasonable implementation of ``setjmp`` must copy the callee-save
-registers into the ``jmp_buf`` in order to work as described.
-Otherwise, once the callee-save registers have been overwritten by
-other function calls, a ``longjmp`` would result in the callee-save
-registers having the wrong values.
+registers either into the ``jmp_buf`` or into the stack frame that
+invokes it in order to work as described. Otherwise, once the
+callee-save registers have been overwritten by other function calls, a
+``longjmp`` would result in the callee-save registers having the wrong
+values. A ``longjmp`` can come from anywhere, and so the function
+using ``setjmp`` can't rely on callee-save registers being saved by
+callees.
-_`.sol.stack.top`: Similarly, an implementation can decode the jump
-buffer and get the top of the mutator's stack from the stack pointer
-register, or it can conservatively use the address of a local variable
-in the entry point to the MPS.
+_`.sol.setjmp.scramble`: However, we can't be sure *where* the
+mutator's callee-save registers will be stored, either in the
+``jmp_buf`` or the stack frame of the function that invokes it.
+
+_`.sol.stack.hot`: Similarly, an implementation can decode the jump
+buffer and get the hot end of the mutator's stack from the stack
+pointer register, or it can conservatively use the address of a local
+variable in the entry point to the MPS. (But see
+.sol.setjmp.sramble.)
_`.sol.stack.platform`: As of version 1.115, all supported platforms
are *full* and *descending* so the implementation in ``StackScan``
@@ -220,13 +228,6 @@ Interface
_`.if.sc`: A structure encapsulating the mutator context.
-``Addr StackContextStackTop(StackContext sc)``
-
-_`.if.stack.hot`: Return (a conservative approximation to) the address
-of the hot end of the mutator's stack at the point where ``sc`` was
-stored. In the common case, where the stack grows downwards, this is
-actually the lowest stack address.
-
``Res StackScan(ScanState ss, Addr *stackCold,
mps_area_scan_t scan_area,
void *closure)``
@@ -235,9 +236,7 @@ _`.if.scan`: Scan the stack of the current thread, between
``stackCold`` and the hot end of the mutator's stack that was recorded by
``STACK_CONTEXT_SAVE()`` when the arena was entered. Also scan any
roots which were in the mutator's callee-save registers at that point.
-Return ``ResOK`` if successful, or another result code if not. See the
-platform-specific implementation of ``StackContextScan()`` for the
-exact registers which are scanned.
+Return ``ResOK`` if successful, or another result code if not.
_`.if.scan.begin-end`: This function must be called between
``STACK_CONTEXT_BEGIN()`` and ``STACK_CONTEXT_END()``.
@@ -285,35 +284,12 @@ the arena lock.
Implementations
---------------
-_`.impl.an`: Generic implementation in ``ssan.c``. Since the C
-standard does not specify where the callee-save registers appear in
-the jump buffer, the whole buffer must be scanned (see
-`.sol.setjmp.scan`_), and the top of the stack must be taken
-conservatively from a local variable.
-
-_`.impl.w3`: Windows implementation in ``ssw3i3mv.c`` and
-``ssw3i6mv.c``. We know the layout of the jump buffer used by the
-compiler, and so can scan exactly the subset of registers we need, and
-decode the stack pointer from ESP (on IA-32) or RSP (on x86-64).
-
-_`.impl.w3.i3`: On Windows on IA-32, the callee-save registers are
-EBX, ESI, EDI, and EBP. See [Fog]_.
-
-_`.impl.w3.i6`: On Windows on x86-64, the callee-save registers are
-RBX, RBP, RDI, RSI, R12, R13, R14, and R15. See
-[x86_64_registers]_. In theory the lowest 128 bits of the vector
-registers XMM6 to XMM15 are also callee-save, but we assume that
-references do not appear in these registers.
-
-_`.impl.xc`: OS X implementation in ``ssxci3.c`` and ``ssxci6.c``.
-Scans the jump buffer conservatively as for `.impl.an`_, but decodes
-the stack pointer from ESP (on IA-32) or RSP (on x86-64).
-
-_`.impl.xc.i3`: On OS X on IA-32, the callee-save registers are EBX,
-ESI, EDI and EBP. See [Fog]_.
-
-_`.impl.xc.i6`: On OS X on x86-64, the callee-save registers are RBX,
-RBP, R12, R13, R14, and R15. See [Fog]_.
+_`.impl`: Generic implementation in ``ss.c``. We scan the whole
+jump buffer and use the address of the buffer as a marker of the hot
+end of the mutator's stack, since it is declared in the entry
+function. A sufficiently perverse compiler might still store
+callee-save registers outside the scanned area (see
+.sol.setjmp.scramble).
References
@@ -337,13 +313,16 @@ Document History
- 2014-10-22 GDR_ Initial draft.
+- 2016-03-03 RB_ Simplified implementation due to .sol.setjmp.scramble.
+
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
+.. _RB: http://www.ravenbrook.com/consultants/rb/
Copyright and License
---------------------
-Copyright © 2014 Ravenbrook Limited. All rights reserved.
+Copyright © 2014-2016 Ravenbrook Limited. All rights reserved.
. This is an open source license. Contact
Ravenbrook for commercial licensing options.
From fd46d0f507a3428e1870d61267f6798db5396f97 Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Thu, 3 Mar 2016 16:36:43 +0000
Subject: [PATCH 083/759] Removing dead references from the xcode project.
Copied from Perforce
Change: 189580
ServerID: perforce.ravenbrook.com
---
mps/code/mps.xcodeproj/project.pbxproj | 134 ++++++++++++++++++++++---
1 file changed, 122 insertions(+), 12 deletions(-)
diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj
index d350c591bdf..a3235447ac6 100644
--- a/mps/code/mps.xcodeproj/project.pbxproj
+++ b/mps/code/mps.xcodeproj/project.pbxproj
@@ -1478,14 +1478,11 @@
22FACEDE18880933000FDBC1 /* pooln.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pooln.c; sourceTree = ""; };
22FACEDF18880933000FDBC1 /* pooln.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pooln.h; sourceTree = ""; };
22FACEED18880983000FDBC1 /* airtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = airtest; sourceTree = BUILT_PRODUCTS_DIR; };
- 22FAF76C1A04394B006660FD /* ssxci3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ssxci3.c; sourceTree = ""; };
- 22FAF76D1A04394B006660FD /* ssxci6.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ssxci6.c; sourceTree = ""; };
2D07B96C1636FC7200DB751B /* eventsql.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = eventsql.c; sourceTree = ""; };
2D07B9711636FC9900DB751B /* mpseventsql */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mpseventsql; sourceTree = BUILT_PRODUCTS_DIR; };
2D07B97B163705E400DB751B /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
2D604B9C16514B1A003AAF46 /* mpseventtxt */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mpseventtxt; sourceTree = BUILT_PRODUCTS_DIR; };
2D604BA416514C4F003AAF46 /* eventtxt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eventtxt.c; sourceTree = ""; };
- 3104AFA5156D27E7000A585A /* ssixi6.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ssixi6.c; sourceTree = ""; };
3104AFB3156D357B000A585A /* apss */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = apss; sourceTree = BUILT_PRODUCTS_DIR; };
3104AFBE156D3591000A585A /* apss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = apss.c; sourceTree = ""; };
3104AFC8156D35E2000A585A /* sacss */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sacss; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -1498,6 +1495,50 @@
3104B02F156D39F2000A585A /* amssshe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = amssshe.c; sourceTree = ""; };
3104B03D156D3AD7000A585A /* segsmss */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = segsmss; sourceTree = BUILT_PRODUCTS_DIR; };
3107DC4E173B03D100F705C8 /* arg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = arg.h; sourceTree = ""; };
+ 310EA5E21C889F4C004FE6B7 /* abq.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = abq.txt; path = ../design/abq.txt; sourceTree = ""; };
+ 310EA5E41C889F4C004FE6B7 /* an.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = an.txt; path = ../design/an.txt; sourceTree = "