From e05a3f745513b6b5b85d50c798e67dde294c5074 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 23174c0d801ba8c64a0bf9bf775009696d7bebf5 Mon Sep 17 00:00:00 2001
From: David Lovemore
Date: Thu, 21 Aug 2014 14:03:09 +0100
Subject: [PATCH 004/337] 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 46d723c9dcf134336fa6557a2995de82b26b5350 Mon Sep 17 00:00:00 2001
From: David Lovemore
Date: Thu, 21 Aug 2014 15:53:57 +0100
Subject: [PATCH 005/337] 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 b4460043e6a9f0fcc6b513094c68c3835a7b8b0d Mon Sep 17 00:00:00 2001
From: David Lovemore
Date: Wed, 27 Aug 2014 11:21:18 +0100
Subject: [PATCH 006/337] 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 6be8f3c087f4ccc7fd5ed447b0cb4e32b0fe898f Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Wed, 1 Oct 2014 08:04:12 +0100
Subject: [PATCH 007/337] Branching master to branch/2014-10-01/finalize.
Copied from Perforce
Change: 187098
ServerID: perforce.ravenbrook.com
From 62b29ca9cd0fe0d10c0fb15216e6d8260ea0016e Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Wed, 1 Oct 2014 17:39:37 +0100
Subject: [PATCH 008/337] Test cases for mps_arena_has_addr.
Copied from Perforce
Change: 187102
ServerID: perforce.ravenbrook.com
---
mps/code/apss.c | 8 ++++++++
mps/code/mpsicv.c | 4 ++++
2 files changed, 12 insertions(+)
diff --git a/mps/code/apss.c b/mps/code/apss.c
index 89604831dcf..0d198cb7573 100644
--- a/mps/code/apss.c
+++ b/mps/code/apss.c
@@ -87,6 +87,14 @@ static mps_res_t stress(mps_arena_t arena, mps_pool_debug_option_s *options,
check_allocated_size(pool, ap, allocated);
}
+ /* Check introspection functions */
+ for (i = 0; i < NELEMS(ps); ++i) {
+ mps_pool_t addr_pool = NULL;
+ Insist(mps_arena_has_addr(arena, ps[i]));
+ Insist(mps_addr_pool(&addr_pool, arena, ps[i]));
+ Insist(addr_pool == pool);
+ }
+
mps_pool_check_fenceposts(pool);
for (k=0; k
Date: Thu, 2 Oct 2014 08:30:55 +0100
Subject: [PATCH 009/337] Extend finalcv test to check all the automatically
managed pool classes.
Check that you can't register objects for finalization in manually managed pools.
Remove design.mps.poolmrg.test.promise.ut.not -- this is tested by finaltest.c.
Copied from Perforce
Change: 187107
ServerID: perforce.ravenbrook.com
---
mps/code/finalcv.c | 76 +++++++++++++++++++++++++++++-------------
mps/design/poolmrg.txt | 4 ---
2 files changed, 52 insertions(+), 28 deletions(-)
diff --git a/mps/code/finalcv.c b/mps/code/finalcv.c
index 9f22226dc17..18ea0339e1c 100644
--- a/mps/code/finalcv.c
+++ b/mps/code/finalcv.c
@@ -24,6 +24,12 @@
#include "mps.h"
#include "mpsavm.h"
#include "mpscamc.h"
+#include "mpscams.h"
+#include "mpscawl.h"
+#include "mpsclo.h"
+#include "mpscmfs.h"
+#include "mpscmv.h"
+#include "mpscmvff.h"
#include "mpslib.h"
#include "mpstd.h"
#include "testlib.h"
@@ -36,7 +42,7 @@
#define churnFACTOR 10
#define finalizationRATE 6
#define gcINTERVAL ((size_t)150 * 1024)
-#define collectionCOUNT 3
+#define messageCOUNT 3
/* 3 words: wrapper | vector-len | first-slot */
#define vectorSIZE (3*sizeof(mps_word_t))
@@ -95,35 +101,37 @@ enum {
};
-static void *test(void *arg, size_t s)
+static void test(mps_arena_t arena, mps_pool_class_t pool_class)
{
- unsigned i; /* index */
+ size_t i; /* index */
mps_ap_t ap;
mps_fmt_t fmt;
mps_chain_t chain;
- mps_pool_t amc;
+ mps_pool_t pool;
mps_res_t e;
mps_root_t mps_root[2];
mps_addr_t nullref = NULL;
int state[rootCOUNT];
- mps_arena_t arena;
- void *p = NULL;
mps_message_t message;
+ size_t messages = 0;
+ void *p;
- arena = (mps_arena_t)arg;
- (void)s;
+ printf("---- finalcv: pool class %s ----\n", pool_class->name);
die(mps_fmt_create_A(&fmt, arena, dylan_fmt_A()), "fmt_create\n");
die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
- die(mps_pool_create(&amc, arena, mps_class_amc(), fmt, chain),
- "pool_create amc\n");
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain);
+ MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt);
+ die(mps_pool_create_k(&pool, arena, pool_class, args), "pool_create\n");
+ } MPS_ARGS_END(args);
die(mps_root_create_table(&mps_root[0], arena, mps_rank_exact(), (mps_rm_t)0,
root, (size_t)rootCOUNT),
"root_create\n");
die(mps_root_create_table(&mps_root[1], arena, mps_rank_exact(), (mps_rm_t)0,
&p, (size_t)1),
"root_create\n");
- die(mps_ap_create(&ap, amc, mps_rank_exact()), "ap_create\n");
+ die(mps_ap_create(&ap, pool, mps_rank_exact()), "ap_create\n");
/* Make registered-for-finalization objects. */
/* */
@@ -142,12 +150,10 @@ static void *test(void *arg, size_t s)
}
p = NULL;
- die(ArenaDescribe(arena, mps_lib_get_stdout(), 0), "ArenaDescribe");
-
mps_message_type_enable(arena, mps_message_type_finalization());
/* */
- while (mps_collections(arena) < collectionCOUNT) {
+ while (messages < messageCOUNT) {
/* Perhaps cause (minor) collection */
churn(ap);
@@ -197,36 +203,58 @@ static void *test(void *arg, size_t s)
if (rnd() % 2 == 0)
root[objind] = objaddr;
mps_message_discard(arena, message);
+ ++ messages;
}
}
- /* @@@@ missing */
-
- mps_arena_park(arena);
mps_ap_destroy(ap);
mps_root_destroy(mps_root[1]);
mps_root_destroy(mps_root[0]);
- mps_pool_destroy(amc);
+ mps_pool_destroy(pool);
mps_chain_destroy(chain);
mps_fmt_destroy(fmt);
+}
- return NULL;
+
+/* test_fail -- check that you can't register objects for finalization
+ * in manually managed pools
+ */
+
+static void test_fail(mps_arena_t arena, mps_pool_class_t pool_class)
+{
+ size_t size = 4096;
+ mps_pool_t pool;
+ mps_addr_t p;
+
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, size);
+ die(mps_pool_create_k(&pool, arena, pool_class, args), "pool_create\n");
+ } MPS_ARGS_END(args);
+ die(mps_alloc(&p, pool, size), "mps_alloc");
+ Insist(mps_finalize(arena, &p) == MPS_RES_UNIMPL);
+ mps_pool_destroy(pool);
}
int main(int argc, char *argv[])
{
mps_arena_t arena;
- mps_thr_t thread;
- void *r;
testlib_init(argc, argv);
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"arena_create\n");
- die(mps_thread_reg(&thread, arena), "thread_reg\n");
- mps_tramp(&r, test, arena, 0);
- mps_thread_dereg(thread);
+
+ test_fail(arena, mps_class_mfs());
+ test_fail(arena, mps_class_mv());
+ test_fail(arena, mps_class_mvff());
+
+ test(arena, mps_class_amc());
+ test(arena, mps_class_amcz());
+ test(arena, mps_class_awl());
+ test(arena, mps_class_ams());
+ test(arena, mps_class_lo());
+
mps_arena_destroy(arena);
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
diff --git a/mps/design/poolmrg.txt b/mps/design/poolmrg.txt
index 9f01ad3bca7..1460b39117c 100644
--- a/mps/design/poolmrg.txt
+++ b/mps/design/poolmrg.txt
@@ -619,10 +619,6 @@ All objects from the MRG pool will then be freed (thus dropping all
references to the AMC objects). This will test `.promise.faithful`_
and `.promise.live`_.
-_`.test.promise.ut.not`: The following part of the test has not
-implemented. This is because the messaging system has not yet been
-implemented.
-
_`.test.promise.ut.alloc`: A number of objects will be allocated in
the AMC pool.
From 3ecf3d50c6122b2d34837b13dddbe6d2a35f370e Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 2 Oct 2014 09:13:21 +0100
Subject: [PATCH 010/337] Make arenahasaddr work for all pools (not just for
pools with segments).
Copied from Perforce
Change: 187108
ServerID: perforce.ravenbrook.com
---
mps/code/arena.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mps/code/arena.c b/mps/code/arena.c
index 30a65479f9b..67c053e42e8 100644
--- a/mps/code/arena.c
+++ b/mps/code/arena.c
@@ -1394,10 +1394,10 @@ static void ArenaTrivCompact(Arena arena, Trace trace)
Bool ArenaHasAddr(Arena arena, Addr addr)
{
- Seg seg;
+ Tract tract;
AVERT(Arena, arena);
- return SegOfAddr(&seg, arena, addr);
+ return TractOfAddr(&tract, arena, addr);
}
From 0048f341e022c12f27eeb6577c65501340fd5b8e Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 2 Oct 2014 10:27:57 +0100
Subject: [PATCH 011/337] Arenafinalize now asserts that the object belongs to
a finalizable (attrgc) pool. (it's a programming error to try to register a
non-finalizable object for finalization.)
Can't test this behaviour via the smoke tests, unfortunately.
Document the performance problem with mps_definalize, so that users aren't tempted into using it inappropriately.
Copied from Perforce
Change: 187109
ServerID: perforce.ravenbrook.com
---
mps/code/finalcv.c | 27 --------------------
mps/code/global.c | 10 +++++---
mps/manual/source/guide/advanced.rst | 32 +++++++++++++-----------
mps/manual/source/topic/finalization.rst | 13 +++++++---
4 files changed, 33 insertions(+), 49 deletions(-)
diff --git a/mps/code/finalcv.c b/mps/code/finalcv.c
index 18ea0339e1c..f31065edd92 100644
--- a/mps/code/finalcv.c
+++ b/mps/code/finalcv.c
@@ -27,9 +27,6 @@
#include "mpscams.h"
#include "mpscawl.h"
#include "mpsclo.h"
-#include "mpscmfs.h"
-#include "mpscmv.h"
-#include "mpscmvff.h"
#include "mpslib.h"
#include "mpstd.h"
#include "testlib.h"
@@ -216,26 +213,6 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class)
}
-/* test_fail -- check that you can't register objects for finalization
- * in manually managed pools
- */
-
-static void test_fail(mps_arena_t arena, mps_pool_class_t pool_class)
-{
- size_t size = 4096;
- mps_pool_t pool;
- mps_addr_t p;
-
- MPS_ARGS_BEGIN(args) {
- MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, size);
- die(mps_pool_create_k(&pool, arena, pool_class, args), "pool_create\n");
- } MPS_ARGS_END(args);
- die(mps_alloc(&p, pool, size), "mps_alloc");
- Insist(mps_finalize(arena, &p) == MPS_RES_UNIMPL);
- mps_pool_destroy(pool);
-}
-
-
int main(int argc, char *argv[])
{
mps_arena_t arena;
@@ -245,10 +222,6 @@ int main(int argc, char *argv[])
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"arena_create\n");
- test_fail(arena, mps_class_mfs());
- test_fail(arena, mps_class_mv());
- test_fail(arena, mps_class_mvff());
-
test(arena, mps_class_amc());
test(arena, mps_class_amcz());
test(arena, mps_class_awl());
diff --git a/mps/code/global.c b/mps/code/global.c
index 0a36ed18b2f..efffd564ad4 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -857,17 +857,19 @@ Bool ArenaStep(Globals globals, double interval, double multiplier)
Res ArenaFinalize(Arena arena, Ref obj)
{
Res res;
+ Pool refpool;
AVERT(Arena, arena);
- AVER(ArenaHasAddr(arena, (Addr)obj));
+ AVER(PoolOfAddr(&refpool, arena, (Addr)obj));
+ AVER(PoolHasAttr(refpool, AttrGC));
if (!arena->isFinalPool) {
- Pool pool;
+ Pool finalpool;
- res = PoolCreate(&pool, arena, PoolClassMRG(), argsNone);
+ res = PoolCreate(&finalpool, arena, PoolClassMRG(), argsNone);
if (res != ResOK)
return res;
- arena->finalPool = pool;
+ arena->finalPool = finalpool;
arena->isFinalPool = TRUE;
}
diff --git a/mps/manual/source/guide/advanced.rst b/mps/manual/source/guide/advanced.rst
index 0535b9b3f18..7dd4b20b63d 100644
--- a/mps/manual/source/guide/advanced.rst
+++ b/mps/manual/source/guide/advanced.rst
@@ -28,14 +28,6 @@ call ``close-input-file``, then the underlying file handle should still
be closed when the port object :term:`dies `. This procedure is
known as :term:`finalization`.
-.. note::
-
- It's generally a bad idea to depend on finalization to release your
- resources (see the :ref:`topic-finalization-cautions` section in
- :ref:`topic-finalization`). Treat it as a last resort when more
- reliable mechanisms for releasing resources (like Scheme's
- ``with-open-input-file``) aren't available.
-
Any block in an :term:`automatically managed ` :term:`pool` can be registered for finalization by calling
:c:func:`mps_finalize`. In the toy Scheme interpreter, this can be done
@@ -138,11 +130,20 @@ Here's an example session showing finalization taking place:
not_condemned 0
clock: 3807
-The toy Scheme interpreter :dfn:`definalizes` ports by calling
-:c:func:`mps_definalize` when they are closed. This is purely an
-optimization: setting ``stream`` to ``NULL`` ensures that the file
-handle wouldn't be closed more than once, even if the port object were
-later finalized.
+It's wise not to depend on finalization as the only method for
+releasing resources (see the :ref:`topic-finalization-cautions`
+section in :ref:`topic-finalization`), because the garbage collector
+does not promise to collect particular objects at particular times,
+and in any case it does so only when it can prove that the object is
+:term:`dead`. So it is best to provide a reliable mechanism for
+releasing the resource (here, the Scheme function
+``close-input-port``), and use finalization as a backup strategy.
+
+But this raises the possibility that a port will be closed twice: once
+via ``close-input-port`` and a second time via finalization. So it's
+necessary to make ports robust against be closed multiple times. The
+toy Scheme interpreter does so by setting ``stream`` to ``NULL``: this
+ensures that the file handle won't be closed more than once.
.. code-block:: c
:emphasize-lines: 8
@@ -154,10 +155,13 @@ later finalized.
mps_addr_t port_ref = port;
fclose(port->port.stream);
port->port.stream = NULL;
- mps_definalize(arena, &port_ref);
}
}
+Note that because finalization messages are processed synchronously
+via the message queue (and the Scheme interpreter is single-threaded)
+there is no need for a lock here.
+
It's still possible that the toy Scheme interpreter might run out of
open file handles despite having some or all of its port objects being
finalizable. That's because the arena's message queue is only polled
diff --git a/mps/manual/source/topic/finalization.rst b/mps/manual/source/topic/finalization.rst
index 5b65d9945dd..7edadb9e3cc 100644
--- a/mps/manual/source/topic/finalization.rst
+++ b/mps/manual/source/topic/finalization.rst
@@ -221,10 +221,8 @@ Finalization interface
:term:`result code` if not.
This function registers the block pointed to by ``*ref_p`` for
- finalization. This block must have been allocated from a
- :term:`pool` in ``arena``. Violations of this constraint may not
- be checked by the MPS, and may be unsafe, causing the MPS to crash
- in undefined ways.
+ finalization. This block must have been allocated from an
+ automatically managed :term:`pool` in ``arena``.
.. note::
@@ -252,6 +250,13 @@ Finalization interface
avoid placing the restriction on the :term:`client program`
that the C call stack be a :term:`root`.
+ .. warning::
+
+ Definalization is not yet efficient: the current
+ implementation just loops over all finalized objects. If you
+ need efficient definalization, please :ref:`contact us
+ `.
+
.. index::
pair: finalization; message
From 2a9e74ef82e0d15d9eb64bb2b06d3e02c87249e1 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 2 Oct 2014 11:08:37 +0100
Subject: [PATCH 012/337] Add test case for registering an unfinalizable object
for finalization.
Copied from Perforce
Change: 187110
ServerID: perforce.ravenbrook.com
---
mps/test/function/228.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
create mode 100644 mps/test/function/228.c
diff --git a/mps/test/function/228.c b/mps/test/function/228.c
new file mode 100644
index 00000000000..3b6e817a040
--- /dev/null
+++ b/mps/test/function/228.c
@@ -0,0 +1,40 @@
+/*
+TEST_HEADER
+ id = $Id$
+ summary = can't register unfinalizable objects for finalization
+ language = c
+ link = testlib.o
+OUTPUT_SPEC
+ assert = true
+ assertfile P= global.c
+END_HEADER
+*/
+
+#include "testlib.h"
+#include "mpscmvff.h"
+#include "mpsavm.h"
+
+static void test(void)
+{
+ mps_arena_t arena;
+ mps_pool_t pool;
+ mps_addr_t p;
+
+ die(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none),
+ "arena_create");
+ die(mps_pool_create_k(&pool, arena, mps_class_mvff(), mps_args_none),
+ "pool_create");
+ die(mps_alloc(&p, pool, 4096), "alloc");
+ die(mps_finalize(arena, &p), "finalize");
+
+ mps_pool_destroy(pool);
+ mps_arena_destroy(arena);
+}
+
+
+int main(void)
+{
+ test();
+ pass();
+ return 0;
+}
From 0292613b0cce2bd9a350178c206266f29197f803 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 2 Oct 2014 11:20:43 +0100
Subject: [PATCH 013/337] Release notes for job003865 and job003866.
Copied from Perforce
Change: 187112
ServerID: perforce.ravenbrook.com
---
mps/manual/source/release.rst | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst
index fc9cc438c55..e7718a1cbf1 100644
--- a/mps/manual/source/release.rst
+++ b/mps/manual/source/release.rst
@@ -17,6 +17,22 @@ Interface changes
but is deprecated.
+Other changes
+-------------
+
+#. Unfinalizable objects can no longer be registered for finalization.
+ Previously the objects would be registered but never finalized. See
+ job003865_.
+
+ .. _job003865: https://www.ravenbrook.com/project/mps/issue/job003865/
+
+#. :c:func:`mps_arena_has_addr` now returns the correct result for
+ objects allocated from the :ref:`pool-mfs`, :ref:`pool-mv`, and
+ :ref:`pool-mvff` pools. See job003866_.
+
+ .. _job003866: https://www.ravenbrook.com/project/mps/issue/job003866/
+
+
.. _release-notes-1.114:
Release 1.114.0
From 0aa611f22c467ca190b207bc7b2136df81a9efec Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 2 Oct 2014 13:49:28 +0100
Subject: [PATCH 014/337] Don't call mps_definalize in the example scheme
interpreter: it's not actually an optimization because of the inefficient
implementation.
Copied from Perforce
Change: 187123
ServerID: perforce.ravenbrook.com
---
mps/example/scheme/scheme-advanced.c | 10 ----------
mps/example/scheme/scheme.c | 10 ----------
mps/manual/source/guide/advanced.rst | 1 -
3 files changed, 21 deletions(-)
diff --git a/mps/example/scheme/scheme-advanced.c b/mps/example/scheme/scheme-advanced.c
index 82b541256d5..f73bf06512a 100644
--- a/mps/example/scheme/scheme-advanced.c
+++ b/mps/example/scheme/scheme-advanced.c
@@ -991,22 +991,12 @@ static char *symbol_name(obj_t symbol)
}
-/* port_close -- close and definalize a port %%MPS
- *
- * Ports objects are registered for finalization when they are created
- * (see make_port). When closed, we definalize them. This is purely an
- * optimization: it would be harmless to finalize them because setting
- * 'stream' to NULL prevents the stream from being closed multiple
- * times. See topic/finalization.
- */
static void port_close(obj_t port)
{
assert(TYPE(port) == TYPE_PORT);
if(port->port.stream != NULL) {
- mps_addr_t port_ref = port;
fclose(port->port.stream);
port->port.stream = NULL;
- mps_definalize(arena, &port_ref);
}
}
diff --git a/mps/example/scheme/scheme.c b/mps/example/scheme/scheme.c
index 66112f8be5e..794fdfa77d4 100644
--- a/mps/example/scheme/scheme.c
+++ b/mps/example/scheme/scheme.c
@@ -1017,22 +1017,12 @@ static void table_delete(obj_t tbl, obj_t key)
}
-/* port_close -- close and definalize a port %%MPS
- *
- * Ports objects are registered for finalization when they are created
- * (see make_port). When closed, we definalize them. This is purely an
- * optimization: it would be harmless to finalize them because setting
- * 'stream' to NULL prevents the stream from being closed multiple
- * times. See topic/finalization.
- */
static void port_close(obj_t port)
{
assert(TYPE(port) == TYPE_PORT);
if(port->port.stream != NULL) {
- mps_addr_t port_ref = port;
fclose(port->port.stream);
port->port.stream = NULL;
- mps_definalize(arena, &port_ref);
}
}
diff --git a/mps/manual/source/guide/advanced.rst b/mps/manual/source/guide/advanced.rst
index 7dd4b20b63d..4b6331a2234 100644
--- a/mps/manual/source/guide/advanced.rst
+++ b/mps/manual/source/guide/advanced.rst
@@ -152,7 +152,6 @@ ensures that the file handle won't be closed more than once.
{
assert(TYPE(port) == TYPE_PORT);
if(port->port.stream != NULL) {
- mps_addr_t port_ref = port;
fclose(port->port.stream);
port->port.stream = NULL;
}
From 6e4cf0ad4714db0c2cbdf69828c81480244fd18c Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 2 Oct 2014 13:51:31 +0100
Subject: [PATCH 015/337] Restore condition on collections so that test will
terminate even if finalization messages are not delivered.
Copied from Perforce
Change: 187124
ServerID: perforce.ravenbrook.com
---
mps/code/finalcv.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/mps/code/finalcv.c b/mps/code/finalcv.c
index f31065edd92..2be7f083735 100644
--- a/mps/code/finalcv.c
+++ b/mps/code/finalcv.c
@@ -39,6 +39,7 @@
#define churnFACTOR 10
#define finalizationRATE 6
#define gcINTERVAL ((size_t)150 * 1024)
+#define collectionCOUNT 3
#define messageCOUNT 3
/* 3 words: wrapper | vector-len | first-slot */
@@ -150,7 +151,7 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class)
mps_message_type_enable(arena, mps_message_type_finalization());
/* */
- while (messages < messageCOUNT) {
+ while (messages < messageCOUNT && mps_collections(arena) < collectionCOUNT) {
/* Perhaps cause (minor) collection */
churn(ap);
From 71c23bb40aa1d8a5a4492aa0808f3849c9b80f2a Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 7 Oct 2014 22:16:11 +0100
Subject: [PATCH 016/337] Need to call easy_tramp to get correct assertion
handling.
Copied from Perforce
Change: 187154
ServerID: perforce.ravenbrook.com
---
mps/test/function/228.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/mps/test/function/228.c b/mps/test/function/228.c
index 3b6e817a040..baa69a7cd7e 100644
--- a/mps/test/function/228.c
+++ b/mps/test/function/228.c
@@ -7,6 +7,7 @@ TEST_HEADER
OUTPUT_SPEC
assert = true
assertfile P= global.c
+ assertcond = PoolHasAttr(refpool, AttrGC)
END_HEADER
*/
@@ -34,7 +35,7 @@ static void test(void)
int main(void)
{
- test();
+ easy_tramp(test);
pass();
return 0;
}
From 5e2ff95048440e954176020318d71978518f569f Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sat, 11 Oct 2014 13:38:51 +0100
Subject: [PATCH 017/337] Branching master to branch/2014-10-11/snc.
Copied from Perforce
Change: 187210
ServerID: perforce.ravenbrook.com
From 87d334ee07413bb717e9f0c6c6396b8479f1591f Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sat, 11 Oct 2014 17:56:27 +0100
Subject: [PATCH 018/337] 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 64d9eb5d2c5daee592ab723effbdeb81db02b3d1 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sat, 11 Oct 2014 18:04:05 +0100
Subject: [PATCH 019/337] 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 33aeb61e5927bdc538ca953b81f82915eaecbb52 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 13 Oct 2014 21:57:41 +0100
Subject: [PATCH 020/337] Branching master to branch/2014-10-13/format.
Copied from Perforce
Change: 187249
ServerID: perforce.ravenbrook.com
From f65f1db83e44fe5b0f8e8bae0df0c05d52a53e2c Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 13 Oct 2014 22:44:20 +0100
Subject: [PATCH 021/337] 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 ae805ce16e4a9545b4a1e40c83776ea4ceef61ed Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 14 Oct 2014 10:07:41 +0100
Subject: [PATCH 022/337] 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 4ce030ad1305fcbcd82124ae47b89c547120bc6e Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 16 Oct 2014 22:59:00 +0100
Subject: [PATCH 023/337] 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 d0ba77de474c3abac3e8ad14bda2b2cdbfcf6709 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sat, 25 Oct 2014 11:24:29 +0100
Subject: [PATCH 024/337] Branching master to branch/2014-10-25/thread.
Copied from Perforce
Change: 187391
ServerID: perforce.ravenbrook.com
From abbdcfc59f91b23ef34e1c92d71d2020f63e8991 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sat, 25 Oct 2014 17:41:42 +0100
Subject: [PATCH 025/337] Assert if a thread dies while registered, but make a
best effort to continue working after the assertion, by marking the thread as
dead and moving it to a ring of dead threads.
Copied from Perforce
Change: 187393
ServerID: perforce.ravenbrook.com
---
mps/code/global.c | 4 ++
mps/code/mpm.h | 1 +
mps/code/mpmst.h | 1 +
mps/code/shield.c | 4 +-
mps/code/th.h | 11 ++--
mps/code/than.c | 6 +-
mps/code/thix.c | 91 +++++++++++++++++-------------
mps/code/thw3.c | 66 ++++++++++++----------
mps/code/thw3.h | 1 +
mps/code/thw3i3.c | 13 +++--
mps/code/thw3i6.c | 13 +++--
mps/code/thxc.c | 46 ++++++++++-----
mps/design/thread-manager.txt | 35 ++++++++++--
mps/manual/source/topic/thread.rst | 4 ++
14 files changed, 187 insertions(+), 109 deletions(-)
diff --git a/mps/code/global.c b/mps/code/global.c
index df0095d3195..d60e925fdb3 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -153,6 +153,7 @@ Bool GlobalsCheck(Globals arenaGlobals)
}
CHECKD_NOSIG(Ring, &arena->threadRing);
+ CHECKD_NOSIG(Ring, &arena->deadRing);
CHECKL(BoolCheck(arena->insideShield));
CHECKL(arena->shCacheLimit <= ShieldCacheSIZE);
@@ -277,6 +278,7 @@ Res GlobalsInit(Globals arenaGlobals)
arenaGlobals->rememberedSummaryIndex = 0;
RingInit(&arena->threadRing);
+ RingInit(&arena->deadRing);
arena->threadSerial = (Serial)0;
RingInit(&arena->formatRing);
arena->formatSerial = (Serial)0;
@@ -405,6 +407,7 @@ void GlobalsFinish(Globals arenaGlobals)
RingFinish(&arena->chainRing);
RingFinish(&arena->messageRing);
RingFinish(&arena->threadRing);
+ RingFinish(&arena->deadRing);
for(rank = RankMIN; rank < RankLIMIT; ++rank)
RingFinish(&arena->greyRing[rank]);
RingFinish(&arenaGlobals->rootRing);
@@ -495,6 +498,7 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals)
AVER(RingIsSingle(&arena->chainRing));
AVER(RingIsSingle(&arena->messageRing));
AVER(RingIsSingle(&arena->threadRing));
+ AVER(RingIsSingle(&arena->deadRing));
AVER(RingIsSingle(&arenaGlobals->rootRing));
for(rank = RankMIN; rank < RankLIMIT; ++rank)
AVER(RingIsSingle(&arena->greyRing[rank]));
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index 6b3730495d6..a3c5a8bbf6c 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -520,6 +520,7 @@ extern Ring GlobalsRememberedSummaryRing(Globals);
#define GlobalsArena(glob) PARENT(ArenaStruct, globals, glob)
#define ArenaThreadRing(arena) (&(arena)->threadRing)
+#define ArenaDeadRing(arena) (&(arena)->deadRing)
#define ArenaEpoch(arena) ((arena)->epoch) /* .epoch.ts */
#define ArenaTrace(arena, ti) (&(arena)->trace[ti])
#define ArenaZoneShift(arena) ((arena)->zoneShift)
diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h
index a7749aa738d..01dbf16b732 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -755,6 +755,7 @@ typedef struct mps_arena_s {
/* thread fields () */
RingStruct threadRing; /* ring of attached threads */
+ RingStruct deadRing; /* ring of dead threads */
Serial threadSerial; /* serial of next thread */
/* shield fields () */
diff --git a/mps/code/shield.c b/mps/code/shield.c
index 55625664ca7..88ee8751331 100644
--- a/mps/code/shield.c
+++ b/mps/code/shield.c
@@ -83,7 +83,7 @@ void (ShieldSuspend)(Arena arena)
AVER(arena->insideShield);
if (!arena->suspended) {
- ThreadRingSuspend(ArenaThreadRing(arena));
+ ThreadRingSuspend(ArenaThreadRing(arena), ArenaDeadRing(arena));
arena->suspended = TRUE;
}
}
@@ -263,7 +263,7 @@ void (ShieldLeave)(Arena arena)
/* Ensuring the mutator is running at this point
* guarantees inv.outside.running */
if (arena->suspended) {
- ThreadRingResume(ArenaThreadRing(arena));
+ ThreadRingResume(ArenaThreadRing(arena), ArenaDeadRing(arena));
arena->suspended = FALSE;
}
arena->insideShield = FALSE;
diff --git a/mps/code/th.h b/mps/code/th.h
index 8c7da150fd0..8f7996cc0b5 100644
--- a/mps/code/th.h
+++ b/mps/code/th.h
@@ -47,13 +47,14 @@ extern void ThreadDeregister(Thread thread, Arena arena);
/* ThreadRingSuspend/Resume
*
- * These functions suspend/resume the threads on the ring.
- * If the current thread is among them, it is not suspended,
- * nor is any attempt to resume it made.
+ * These functions suspend/resume the threads on the ring. If the
+ * current thread is among them, it is not suspended, nor is any
+ * attempt to resume it made. Threads that can't be suspended/resumed
+ * because they are dead are moved to deadRing.
*/
-extern void ThreadRingSuspend(Ring threadRing);
-extern void ThreadRingResume(Ring threadRing);
+extern void ThreadRingSuspend(Ring threadRing, Ring deadRing);
+extern void ThreadRingResume(Ring threadRing, Ring deadRing);
/* ThreadRingThread
diff --git a/mps/code/than.c b/mps/code/than.c
index 8c5af222898..f1fb21006d8 100644
--- a/mps/code/than.c
+++ b/mps/code/than.c
@@ -86,14 +86,16 @@ void ThreadDeregister(Thread thread, Arena arena)
}
-void ThreadRingSuspend(Ring threadRing)
+void ThreadRingSuspend(Ring threadRing, Ring deadRing)
{
AVERT(Ring, threadRing);
+ AVERT(Ring, deadRing);
}
-void ThreadRingResume(Ring threadRing)
+void ThreadRingResume(Ring threadRing, Ring deadRing)
{
AVERT(Ring, threadRing);
+ AVERT(Ring, deadRing);
}
Thread ThreadRingThread(Ring threadRing)
diff --git a/mps/code/thix.c b/mps/code/thix.c
index d32a7dd6601..be1b1f770ae 100644
--- a/mps/code/thix.c
+++ b/mps/code/thix.c
@@ -12,10 +12,10 @@
*
* ASSUMPTIONS
*
- * .error.resume: PThreadextResume is assumed to succeed unless the thread
- * has been destroyed.
- * .error.suspend: PThreadextSuspend is assumed to succeed unless the thread
- * has been destroyed. In this case, the suspend context is set to NULL;
+ * .error.resume: PThreadextResume is assumed to succeed unless the
+ * thread has been terminated.
+ * .error.suspend: PThreadextSuspend is assumed to succeed unless the
+ * thread has been terminated.
*
* .stack.full-descend: assumes full descending stack.
* i.e. stack pointer points to the last allocated location;
@@ -48,9 +48,10 @@ typedef struct mps_thr_s { /* PThreads thread structure */
Serial serial; /* from arena->threadSerial */
Arena arena; /* owning arena */
RingStruct arenaRing; /* threads attached to arena */
+ Bool alive; /* thread believed to be alive? */
PThreadextStruct thrextStruct; /* PThreads extension */
pthread_t id; /* Pthread object of thread */
- MutatorFaultContext mfc; /* Context if thread is suspended */
+ MutatorFaultContext mfc; /* Context if suspended, NULL if not */
} ThreadStruct;
@@ -62,6 +63,7 @@ Bool ThreadCheck(Thread thread)
CHECKU(Arena, thread->arena);
CHECKL(thread->serial < thread->arena->threadSerial);
CHECKD_NOSIG(Ring, &thread->arenaRing);
+ CHECKL(BoolCheck(thread->alive));
CHECKD(PThreadext, &thread->thrextStruct);
return TRUE;
}
@@ -98,6 +100,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena)
thread->serial = arena->threadSerial;
++arena->threadSerial;
thread->arena = arena;
+ thread->alive = TRUE;
thread->mfc = NULL;
PThreadextInit(&thread->thrextStruct, thread->id);
@@ -130,69 +133,80 @@ void ThreadDeregister(Thread thread, Arena arena)
}
-/* mapThreadRing -- map over threads on ring calling a function on each one
- * except the current thread
+/* mapThreadRing -- map over threads on ring calling a function on
+ * each one except the current thread.
+ *
+ * Threads that are found to be dead (that is, if func returns FALSE)
+ * are moved to deadRing.
*/
-static void mapThreadRing(Ring threadRing, void (*func)(Thread))
+static void mapThreadRing(Ring threadRing, Ring deadRing, Res (*func)(Thread))
{
Ring node, next;
pthread_t self;
AVERT(Ring, threadRing);
+ AVERT(Ring, deadRing);
+ AVER(FUNCHECK(func));
self = pthread_self();
RING_FOR(node, threadRing, next) {
Thread thread = RING_ELT(Thread, arenaRing, node);
AVERT(Thread, thread);
- if(! pthread_equal(self, thread->id)) /* .thread.id */
- (*func)(thread);
+ AVER(thread->alive);
+ if (!pthread_equal(self, thread->id) /* .thread.id */
+ && !(*func)(thread))
+ {
+ thread->alive = FALSE;
+ RingRemove(&thread->arenaRing);
+ RingAppend(deadRing, &thread->arenaRing);
+ }
}
}
-/* ThreadRingSuspend -- suspend all threads on a ring, expect the current one */
+/* ThreadRingSuspend -- suspend all threads on a ring, except the
+ * current one.
+ */
-
-static void threadSuspend(Thread thread)
+static Bool threadSuspend(Thread thread)
{
- /* .error.suspend */
- /* In the error case (PThreadextSuspend returning ResFAIL), we */
- /* assume the thread has been destroyed. */
- /* In which case we simply continue. */
+ /* .error.suspend: if PThreadextSuspend fails, we assume the thread
+ * has been terminated. */
Res res;
+ AVER(thread->mfc == NULL);
res = PThreadextSuspend(&thread->thrextStruct, &thread->mfc);
- if(res != ResOK)
- thread->mfc = NULL;
+ AVER(res == ResOK);
+ AVER(thread->mfc != NULL);
+ return res == ResOK;
}
-void ThreadRingSuspend(Ring threadRing)
+void ThreadRingSuspend(Ring threadRing, Ring deadRing)
{
- mapThreadRing(threadRing, threadSuspend);
+ mapThreadRing(threadRing, deadRing, threadSuspend);
}
/* ThreadRingResume -- resume all threads on a ring (expect the current one) */
-static void threadResume(Thread thread)
+static Bool threadResume(Thread thread)
{
- /* .error.resume */
- /* If the previous suspend failed (thread->mfc == NULL), */
- /* or in the error case (PThreadextResume returning ResFAIL), */
- /* assume the thread has been destroyed. */
- /* In which case we simply continue. */
- if(thread->mfc != NULL) {
- (void)PThreadextResume(&thread->thrextStruct);
- thread->mfc = NULL;
- }
+ Res res;
+ /* .error.resume: If PThreadextResume fails, we assume the thread
+ * has been terminated. */
+ AVER(thread->mfc != NULL);
+ res = PThreadextResume(&thread->thrextStruct);
+ AVER(res == ResOK);
+ thread->mfc = NULL;
+ return res == ResOK;
}
-void ThreadRingResume(Ring threadRing)
+void ThreadRingResume(Ring threadRing, Ring deadRing)
{
- mapThreadRing(threadRing, threadResume);
+ mapThreadRing(threadRing, deadRing, threadResume);
}
@@ -231,20 +245,16 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
self = pthread_self();
if(pthread_equal(self, thread->id)) {
/* scan this thread's stack */
+ AVER(thread->alive);
res = StackScan(ss, stackBot);
if(res != ResOK)
return res;
- } else {
+ } else if (thread->alive) {
MutatorFaultContext mfc;
Addr *stackBase, *stackLimit, stackPtr;
mfc = thread->mfc;
- if(mfc == NULL) {
- /* .error.suspend */
- /* We assume that the thread must have been destroyed. */
- /* We ignore the situation by returning immediately. */
- return ResOK;
- }
+ AVER(mfc != NULL);
stackPtr = MutatorFaultContextSP(mfc);
/* .stack.align */
@@ -280,6 +290,7 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
"Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial,
" arena $P ($U)\n",
(WriteFP)thread->arena, (WriteFU)thread->arena->serial,
+ " alive $S\n", WriteFYesNo(thread->alive),
" id $U\n", (WriteFU)thread->id,
"} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial,
NULL);
diff --git a/mps/code/thw3.c b/mps/code/thw3.c
index eda4c139b19..b8b8b106680 100644
--- a/mps/code/thw3.c
+++ b/mps/code/thw3.c
@@ -109,6 +109,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena)
thread->serial = arena->threadSerial;
++arena->threadSerial;
thread->arena = arena;
+ thread->alive = TRUE;
AVERT(Thread, thread);
@@ -138,60 +139,66 @@ void ThreadDeregister(Thread thread, Arena arena)
}
-/* Map over threads on ring calling f on each one except the
- * current thread.
+/* mapThreadRing -- map over threads on ring calling a function on
+ * each one except the current thread.
+ *
+ * Threads that are found to be dead (that is, if func returns FALSE)
+ * are moved to deadRing.
*/
-static void mapThreadRing(Ring ring, void (*f)(Thread thread))
+
+static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread))
{
- Ring node;
+ Ring node, next;
DWORD id;
+ AVERT(Ring, threadRing);
+ AVERT(Ring, deadRing);
+ AVER(FUNCHECK(func));
+
id = GetCurrentThreadId();
- node = RingNext(ring);
- while(node != ring) {
- Ring next = RingNext(node);
- Thread thread;
-
- thread = RING_ELT(Thread, arenaRing, node);
+ RING_FOR(node, threadRing, next) {
+ Thread thread = RING_ELT(Thread, arenaRing, node);
AVERT(Thread, thread);
- if(id != thread->id) /* .thread.id */
- (*f)(thread);
-
- node = next;
+ AVER(thread->alive);
+ if (id != thread->id /* .thread.id */
+ && !(*func)(thread))
+ {
+ thread->alive = FALSE;
+ RingRemove(&thread->arenaRing);
+ RingAppend(deadRing, &thread->arenaRing);
+ }
}
}
-static void suspend(Thread thread)
+static Bool suspendThread(Thread thread)
{
/* .thread.handle.susp-res */
/* .error.suspend */
- /* In the error case (SuspendThread returning 0xFFFFFFFF), we */
- /* assume the thread has been destroyed (as part of process shutdown). */
- /* In which case we simply continue. */
+ /* In the error case (SuspendThread returning -1), we */
+ /* assume the thread has been terminated. */
/* [GetLastError appears to return 5 when SuspendThread is called */
- /* on a destroyed thread, but I'm not sufficiently confident of this */
+ /* on a terminated thread, but I'm not sufficiently confident of this */
/* to check -- drj 1998-04-09] */
- (void)SuspendThread(thread->handle);
+ return SuspendThread(thread->handle) != (DWORD)-1;
}
-void ThreadRingSuspend(Ring ring)
+void ThreadRingSuspend(Ring threadRing, Ring deadRing)
{
- mapThreadRing(ring, suspend);
+ mapThreadRing(threadRing, deadRing, suspendThread);
}
-static void resume(Thread thread)
+static Bool resumeThread(Thread thread)
{
/* .thread.handle.susp-res */
/* .error.resume */
- /* In the error case (ResumeThread returning 0xFFFFFFFF), we */
- /* assume the thread has been destroyed (as part of process shutdown). */
- /* In which case we simply continue. */
- (void)ResumeThread(thread->handle);
+ /* In the error case (ResumeThread returning -1), we */
+ /* assume the thread has been terminated. */
+ return ResumeThread(thread->handle) != (DWORD)-1;
}
-void ThreadRingResume(Ring ring)
+void ThreadRingResume(Ring threadRing, Ring deadRing)
{
- mapThreadRing(ring, resume);
+ mapThreadRing(threadRing, deadRing, resumeThread);
}
@@ -220,6 +227,7 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
"Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial,
" arena $P ($U)\n",
(WriteFP)thread->arena, (WriteFU)thread->arena->serial,
+ " alive $S\n", WriteFYesNo(thread->alive),
" handle $W\n", (WriteFW)thread->handle,
" id $U\n", (WriteFU)thread->id,
"} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial,
diff --git a/mps/code/thw3.h b/mps/code/thw3.h
index 7e3cd68e2f1..b19bfccadba 100644
--- a/mps/code/thw3.h
+++ b/mps/code/thw3.h
@@ -26,6 +26,7 @@ typedef struct mps_thr_s { /* Win32 thread structure */
Serial serial; /* from arena->threadSerial */
Arena arena; /* owning arena */
RingStruct arenaRing; /* threads attached to arena */
+ Bool alive; /* thread believed to be alive? */
HANDLE handle; /* Handle of thread, see
* */
DWORD id; /* Thread id of thread */
diff --git a/mps/code/thw3i3.c b/mps/code/thw3i3.c
index 33424b6cf54..20e694ddc82 100644
--- a/mps/code/thw3i3.c
+++ b/mps/code/thw3i3.c
@@ -74,7 +74,13 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
id = GetCurrentThreadId();
- if(id != thread->id) { /* .thread.id */
+ if (id == thread->id) { /* .thread.id */
+ /* scan this thread's stack */
+ AVER(thread->alive);
+ res = StackScan(ss, stackBot);
+ if(res != ResOK)
+ return res;
+ } else if (thread->alive) {
CONTEXT context;
BOOL success;
Addr *stackBase, *stackLimit, stackPtr;
@@ -116,11 +122,6 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
(Addr *)((char *)&context + sizeof(CONTEXT)));
if(res != ResOK)
return res;
-
- } else { /* scan this thread's stack */
- res = StackScan(ss, stackBot);
- if(res != ResOK)
- return res;
}
return ResOK;
diff --git a/mps/code/thw3i6.c b/mps/code/thw3i6.c
index 9b0eae55db6..a13a031ec22 100644
--- a/mps/code/thw3i6.c
+++ b/mps/code/thw3i6.c
@@ -74,7 +74,13 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
id = GetCurrentThreadId();
- if(id != thread->id) { /* .thread.id */
+ if (id == thread->id) { /* .thread.id */
+ /* scan this thread's stack */
+ AVER(thread->alive);
+ res = StackScan(ss, stackBot);
+ if(res != ResOK)
+ return res;
+ } else if (thread->alive) {
CONTEXT context;
BOOL success;
Addr *stackBase, *stackLimit, stackPtr;
@@ -116,11 +122,6 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
(Addr *)((char *)&context + sizeof(CONTEXT)));
if(res != ResOK)
return res;
-
- } else { /* scan this thread's stack */
- res = StackScan(ss, stackBot);
- if(res != ResOK)
- return res;
}
return ResOK;
diff --git a/mps/code/thxc.c b/mps/code/thxc.c
index 6aeffef6568..b4d7c4188f0 100644
--- a/mps/code/thxc.c
+++ b/mps/code/thxc.c
@@ -36,6 +36,7 @@ typedef struct mps_thr_s { /* OS X / Mach thread structure */
Serial serial; /* from arena->threadSerial */
Arena arena; /* owning arena */
RingStruct arenaRing; /* attaches to arena */
+ Bool alive; /* thread believed to be alive? */
thread_port_t port; /* thread kernel port */
} ThreadStruct;
@@ -46,6 +47,7 @@ Bool ThreadCheck(Thread thread)
CHECKU(Arena, thread->arena);
CHECKL(thread->serial < thread->arena->threadSerial);
CHECKD_NOSIG(Ring, &thread->arenaRing);
+ CHECKL(BoolCheck(thread->alive));
CHECKL(MACH_PORT_VALID(thread->port));
return TRUE;
}
@@ -78,6 +80,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena)
thread->serial = arena->threadSerial;
++arena->threadSerial;
+ thread->alive = TRUE;
thread->port = mach_thread_self();
thread->sig = ThreadSig;
AVERT(Thread, thread);
@@ -108,62 +111,73 @@ void ThreadDeregister(Thread thread, Arena arena)
}
-/* mapThreadRing -- map over threads on ring calling a function on each one
- * except the current thread
+/* mapThreadRing -- map over threads on ring calling a function on
+ * each one except the current thread.
+ *
+ * Threads that are found to be dead (that is, if func returns FALSE)
+ * are marked as dead and moved to deadRing.
*/
-static void mapThreadRing(Ring threadRing, void (*func)(Thread))
+static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread))
{
Ring node, next;
mach_port_t self;
AVERT(Ring, threadRing);
+ AVERT(Ring, deadRing);
+ AVER(FUNCHECK(func));
self = mach_thread_self();
AVER(MACH_PORT_VALID(self));
RING_FOR(node, threadRing, next) {
Thread thread = RING_ELT(Thread, arenaRing, node);
AVERT(Thread, thread);
- if(thread->port != self)
- (*func)(thread);
+ AVER(thread->alive);
+ if (thread->port != self
+ && !(*func)(thread))
+ {
+ thread->alive = FALSE;
+ RingRemove(&thread->arenaRing);
+ RingAppend(deadRing, &thread->arenaRing);
+ }
}
}
-static void threadSuspend(Thread thread)
+static Bool threadSuspend(Thread thread)
{
kern_return_t kern_return;
kern_return = thread_suspend(thread->port);
/* No rendezvous is necessary: thread_suspend "prevents the thread
* from executing any more user-level instructions" */
AVER(kern_return == KERN_SUCCESS);
+ return kern_return == KERN_SUCCESS;
}
-static void threadResume(Thread thread)
+static Bool threadResume(Thread thread)
{
kern_return_t kern_return;
kern_return = thread_resume(thread->port);
/* Mach has no equivalent of EAGAIN. */
AVER(kern_return == KERN_SUCCESS);
+ return kern_return == KERN_SUCCESS;
}
/* ThreadRingSuspend -- suspend all threads on a ring, except the
* current one.
*/
-void ThreadRingSuspend(Ring threadRing)
+void ThreadRingSuspend(Ring threadRing, Ring deadRing)
{
- AVERT(Ring, threadRing);
- mapThreadRing(threadRing, threadSuspend);
+ mapThreadRing(threadRing, deadRing, threadSuspend);
}
/* ThreadRingResume -- resume all threads on a ring, except the
* current one.
*/
-void ThreadRingResume(Ring threadRing)
+void ThreadRingResume(Ring threadRing, Ring deadRing)
{
- AVERT(Ring, threadRing);
- mapThreadRing(threadRing, threadResume);
+ mapThreadRing(threadRing, deadRing, threadResume);
}
Thread ThreadRingThread(Ring threadRing)
@@ -199,17 +213,18 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
AVER(MACH_PORT_VALID(self));
if (thread->port == self) {
/* scan this thread's stack */
+ AVER(thread->alive);
res = StackScan(ss, stackBot);
if(res != ResOK)
return res;
- } else {
+ } else if (thread->alive) {
MutatorFaultContextStruct mfcStruct;
THREAD_STATE_S threadState;
Addr *stackBase, *stackLimit, stackPtr;
mach_msg_type_number_t count;
kern_return_t kern_return;
- /* Note: We could get the thread state and check the suspend cound in
+ /* Note: We could get the thread state and check the suspend count in
order to assert that the thread is suspended, but it's probably
unnecessary and is a lot of work to check a static condition. */
@@ -257,6 +272,7 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
"Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial,
" arena $P ($U)\n",
(WriteFP)thread->arena, (WriteFU)thread->arena->serial,
+ " alive $S\n", WriteFYesNo(thread->alive),
" port $U\n", (WriteFU)thread->port,
"} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial,
NULL);
diff --git a/mps/design/thread-manager.txt b/mps/design/thread-manager.txt
index efe6bcee9e9..48cbb912533 100644
--- a/mps/design/thread-manager.txt
+++ b/mps/design/thread-manager.txt
@@ -54,6 +54,15 @@ which might provoke a collection. See request.dylan.160252_.)
.. _request.dylan.160252: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160252/
+_`.req.thread.die`: It would be nice if the MPS coped with threads
+that die while registered. (This makes it easier for a client program
+to interface with foreign code that terminates threads without the
+client program being given an opportunity to deregister them. See
+request.dylan.160022_ and request.mps.160093_.)
+
+.. _request.dylan.160022: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160022
+.. _request.mps.160093: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/mps/160093/
+
Design
------
@@ -70,6 +79,22 @@ thread that might refer to, read from, or write to memory in
automatically managed pool classes is registered with the MPS. This is
documented in the manual under ``mps_thread_reg()``.
+_`.sol.thread.term`: The thread manager cannot reliably detect that a
+thread has terminated. The reason is that threading systems do not
+guarantee behaviour in this case. For example, POSIX_ says, "A
+conforming implementation is free to reuse a thread ID after its
+lifetime has ended. If an application attempts to use a thread ID
+whose lifetime has ended, the behavior is undefined." For this reason,
+the documentation for ``mps_thread_dereg()`` specifies that it is an
+error if a thread dies while registered.
+
+.. _POSIX: http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_02
+
+_`.sol.thread.term.attempt`: Nonetheless, the thread manager makes a
+"best effort" to continue running after detecting a terminated thread,
+by moving the thread to a ring of dead threads, and avoiding scanning
+it. This might allow a malfunctioning client program to limp along.
+
Interface
---------
@@ -112,14 +137,16 @@ Otherwise, return a result code indicating the cause of the error.
_`.if.deregister`: Remove ``thread`` from the list of threads managed
by the arena and free it.
-``void ThreadRingSuspend(Ring threadRing)``
+``void ThreadRingSuspend(Ring threadRing, Ring deadRing)``
_`.if.ring.suspend`: Suspend all the threads on ``threadRing``, except
-for the current thread.
+for the current thread. If any threads are discovered to have
+terminated, move them to ``deadRing``.
-``void ThreadRingResume(Ring threadRing)``
+``void ThreadRingResume(Ring threadRing, Ring deadRing)``
-_`.if.ring.resume`: Resume all the threads on ``threadRing``.
+_`.if.ring.resume`: Resume all the threads on ``threadRing``. If any
+threads are discovered to have terminated, move them to ``deadRing``.
``Thread ThreadRingThread(Ring threadRing)``
diff --git a/mps/manual/source/topic/thread.rst b/mps/manual/source/topic/thread.rst
index fe16b1e450d..0a4156613ac 100644
--- a/mps/manual/source/topic/thread.rst
+++ b/mps/manual/source/topic/thread.rst
@@ -100,6 +100,7 @@ Signal and exception handling issues
for co-operating: if you are in this situation, please :ref:`contact
us `.
+
.. index::
single: thread; interface
@@ -142,6 +143,9 @@ Thread interface
It is recommended that all threads be registered with all
arenas.
+ It is an error if a thread terminates while it is registered. The
+ client program must call :c:func:`mps_thread_dereg` first.
+
.. c:function:: void mps_thread_dereg(mps_thr_t thr)
From b1ab5ec2dcbe615c3750ea61e26796c2ea030e40 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sat, 25 Oct 2014 19:45:48 +0100
Subject: [PATCH 026/337] 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 3fdbf1deb55341f717debc696e18f4bb7cec5a25 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 6 Nov 2014 11:01:11 +0000
Subject: [PATCH 027/337] Emphasize the right line in the finalization example.
Copied from Perforce
Change: 187466
ServerID: perforce.ravenbrook.com
---
mps/manual/source/guide/advanced.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mps/manual/source/guide/advanced.rst b/mps/manual/source/guide/advanced.rst
index 4b6331a2234..c40db2d0774 100644
--- a/mps/manual/source/guide/advanced.rst
+++ b/mps/manual/source/guide/advanced.rst
@@ -146,7 +146,7 @@ toy Scheme interpreter does so by setting ``stream`` to ``NULL``: this
ensures that the file handle won't be closed more than once.
.. code-block:: c
- :emphasize-lines: 8
+ :emphasize-lines: 6
static void port_close(obj_t port)
{
From 89baddefe801bb6ddc72330c8c31927bbd456108 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 19 Jun 2015 12:08:35 +0100
Subject: [PATCH 028/337] Document the assertion failure for an attempt to
finalize an unfinalizable reference.
Copied from Perforce
Change: 187966
ServerID: perforce.ravenbrook.com
---
mps/manual/source/topic/error.rst | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst
index e65f6eafebd..fe515c9ca40 100644
--- a/mps/manual/source/topic/error.rst
+++ b/mps/manual/source/topic/error.rst
@@ -260,6 +260,13 @@ this documentation.
:c:type:`mps_fmt_t` for this argument.
+``global.c: PoolHasAttr(pool, AttrGC)``
+
+ The client program called :c:func:`mps_finalize` on a reference
+ that does not belong to an :term:`automatically managed ` :term:`pool`.
+
+
``lockix.c: res == 0``
``lockw3.c: lock->claims == 0``
From fae47566c017830cc964b38e52140a20df49a78a Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 6 Aug 2015 13:55:07 +0100
Subject: [PATCH 029/337] Branching master to branch/2015-08-06/config.
Copied from Perforce
Change: 188083
ServerID: perforce.ravenbrook.com
From 703c1ee5f56f4687d626d02f780355c6612fdb43 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 6 Aug 2015 17:02:51 +0100
Subject: [PATCH 030/337] New function mps_arena_configure provides keyword
argument interface to changing the properties of an arena.
New keyword arguments MPS_KEY_ARENA_COMMIT_LIMIT and MPS_KEY_SPARE_ARENA_COMMIT_LIMIT can be passed to mps_arena_create_k or mps_arena_configure.
Deprecate mps_arena_commit_limit_set and mps_arena_spare_commit_limit_set.
Copied from Perforce
Change: 188085
ServerID: perforce.ravenbrook.com
---
mps/code/amcss.c | 2 +-
mps/code/amcsshe.c | 2 +-
mps/code/amcssth.c | 4 +-
mps/code/amsss.c | 2 +-
mps/code/apss.c | 31 +++--
mps/code/arena.c | 39 +++++-
mps/code/arenacl.c | 11 ++
mps/code/arenavm.c | 11 ++
mps/code/config.h | 12 +-
mps/code/locusss.c | 4 +-
mps/code/mpm.h | 1 +
mps/code/mpmst.h | 1 +
mps/code/mpmtypes.h | 1 +
mps/code/mps.h | 13 +-
mps/code/mpsi.c | 14 +++
mps/code/mpsicv.c | 6 +-
mps/manual/source/glossary/c.rst | 3 +-
mps/manual/source/glossary/s.rst | 3 +-
mps/manual/source/release.rst | 18 +++
mps/manual/source/topic/arena.rst | 163 ++++++++++++++-----------
mps/manual/source/topic/deprecated.rst | 35 ++++++
mps/manual/source/topic/keyword.rst | 76 ++++++------
mps/test/function/165.c | 32 +++--
23 files changed, 324 insertions(+), 160 deletions(-)
diff --git a/mps/code/amcss.c b/mps/code/amcss.c
index 3b15f7fb967..83d67dcba58 100644
--- a/mps/code/amcss.c
+++ b/mps/code/amcss.c
@@ -312,11 +312,11 @@ int main(int argc, char *argv[])
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, scale * testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, grainSize);
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, scale * testArenaSIZE);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create");
} MPS_ARGS_END(args);
mps_message_type_enable(arena, mps_message_type_gc());
mps_message_type_enable(arena, mps_message_type_gc_start());
- die(mps_arena_commit_limit_set(arena, scale * testArenaSIZE), "set limit");
die(mps_thread_reg(&thread, arena), "thread_reg");
test(arena, mps_class_amc(), exactRootsCOUNT);
test(arena, mps_class_amcz(), 0);
diff --git a/mps/code/amcsshe.c b/mps/code/amcsshe.c
index fec9fb3a677..adfad3729e5 100644
--- a/mps/code/amcsshe.c
+++ b/mps/code/amcsshe.c
@@ -251,10 +251,10 @@ int main(int argc, char *argv[])
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE));
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, testArenaSIZE);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create");
} MPS_ARGS_END(args);
mps_message_type_enable(arena, mps_message_type_gc());
- die(mps_arena_commit_limit_set(arena, testArenaSIZE), "set limit");
die(mps_thread_reg(&thread, arena), "thread_reg");
test(arena, mps_class_amc(), exactRootsCOUNT);
test(arena, mps_class_amcz(), 0);
diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c
index c6e2d214b5d..043330ebb74 100644
--- a/mps/code/amcssth.c
+++ b/mps/code/amcssth.c
@@ -291,10 +291,10 @@ static void test_arena(int mode)
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE));
+ if (mode == ModeCOMMIT)
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 2 * testArenaSIZE);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create");
} MPS_ARGS_END(args);
- if (mode == ModeCOMMIT)
- die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit");
mps_message_type_enable(arena, mps_message_type_gc());
mps_message_type_enable(arena, mps_message_type_gc_start());
diff --git a/mps/code/amsss.c b/mps/code/amsss.c
index 4e1e15814f7..15686e5d15d 100644
--- a/mps/code/amsss.c
+++ b/mps/code/amsss.c
@@ -209,9 +209,9 @@ int main(int argc, char *argv[])
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE));
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 2 * testArenaSIZE);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create");
} MPS_ARGS_END(args);
- die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "commit_limit_set");
mps_message_type_enable(arena, mps_message_type_gc_start());
mps_message_type_enable(arena, mps_message_type_gc());
diff --git a/mps/code/apss.c b/mps/code/apss.c
index 48a21e1d3fd..e1317b3fb73 100644
--- a/mps/code/apss.c
+++ b/mps/code/apss.c
@@ -156,10 +156,16 @@ static mps_pool_debug_option_s fenceOptions = {
};
-/* testInArena -- test all the pool classes in the given arena */
+/* test -- create arena using given class and arguments; test all the
+ * pool classes in this arena
+ */
-static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options)
+static void test(mps_arena_class_t arena_class, mps_arg_s arena_args[],
+ mps_pool_debug_option_s *options)
{
+ mps_arena_t arena;
+ die(mps_arena_create_k(&arena, arena_class, arena_args), "mps_arena_create");
+
MPS_ARGS_BEGIN(args) {
mps_align_t align = sizeof(void *) << (rnd() % 4);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
@@ -195,45 +201,36 @@ static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options)
die(stress(arena, NULL, align, randomSizeAligned, "MVT",
mps_class_mvt(), args), "stress MVT");
} MPS_ARGS_END(args);
+
+ mps_arena_destroy(arena);
}
int main(int argc, char *argv[])
{
- mps_arena_t arena;
-
testlib_init(argc, argv);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 2 * testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(2*testArenaSIZE));
- die(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
- "mps_arena_create");
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, testArenaSIZE);
+ test(mps_arena_class_vm(), args, &fenceOptions);
} MPS_ARGS_END(args);
- die(mps_arena_commit_limit_set(arena, testArenaSIZE), "commit limit");
- testInArena(arena, &fenceOptions);
- mps_arena_destroy(arena);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 2 * testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, FALSE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(2*testArenaSIZE));
- die(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
- "mps_arena_create");
+ test(mps_arena_class_vm(), args, &bothOptions);
} MPS_ARGS_END(args);
- testInArena(arena, &bothOptions);
- mps_arena_destroy(arena);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, FALSE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_CL_BASE, malloc(testArenaSIZE));
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE));
- die(mps_arena_create_k(&arena, mps_arena_class_cl(), args),
- "mps_arena_create");
+ test(mps_arena_class_cl(), args, &bothOptions);
} MPS_ARGS_END(args);
- testInArena(arena, &bothOptions);
- mps_arena_destroy(arena);
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
return 0;
diff --git a/mps/code/arena.c b/mps/code/arena.c
index 6c6b5220229..042fc6e01c9 100644
--- a/mps/code/arena.c
+++ b/mps/code/arena.c
@@ -209,9 +209,9 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args)
arena->committed = (Size)0;
/* commitLimit may be overridden by init (but probably not */
/* as there's not much point) */
- arena->commitLimit = (Size)-1;
+ arena->commitLimit = ARENA_DEFAULT_COMMIT_LIMIT;
arena->spareCommitted = (Size)0;
- arena->spareCommitLimit = ARENA_INIT_SPARE_COMMIT_LIMIT;
+ arena->spareCommitLimit = ARENA_DEFAULT_SPARE_COMMIT_LIMIT;
arena->grainSize = grainSize;
/* zoneShift is usually overridden by init */
arena->zoneShift = ARENA_ZONESHIFT;
@@ -295,8 +295,10 @@ ARG_DEFINE_KEY(VMW3_TOP_DOWN, Bool);
/* ArenaCreate -- create the arena and call initializers */
-ARG_DEFINE_KEY(ARENA_SIZE, Size);
+ARG_DEFINE_KEY(ARENA_COMMIT_LIMIT, Size);
ARG_DEFINE_KEY(ARENA_GRAIN_SIZE, Size);
+ARG_DEFINE_KEY(ARENA_SIZE, Size);
+ARG_DEFINE_KEY(ARENA_SPARE_COMMIT_LIMIT, Size);
ARG_DEFINE_KEY(ARENA_ZONED, Bool);
Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
@@ -343,9 +345,15 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
goto failGlobalsCompleteCreate;
AVERT(Arena, arena);
+
+ res = ArenaConfigure(arena, args);
+ if (res != ResOK)
+ goto failConfigure;
+
*arenaReturn = arena;
return ResOK;
+failConfigure:
failGlobalsCompleteCreate:
ControlFinish(arena);
failControlInit:
@@ -357,6 +365,31 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
}
+/* ArenaConfigure -- configure an arena */
+
+Res ArenaConfigure(Arena arena, ArgList args)
+{
+ Res res;
+ mps_arg_s arg;
+
+ AVERT(Arena, arena);
+ AVERT(ArgList, args);
+
+ if (ArgPick(&arg, args, MPS_KEY_ARENA_COMMIT_LIMIT)) {
+ Size limit = arg.val.size;
+ res = ArenaSetCommitLimit(arena, limit);
+ if (res != ResOK)
+ return res;
+ }
+ if (ArgPick(&arg, args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT)) {
+ Size limit = arg.val.size;
+ (void)ArenaSetSpareCommitLimit(arena, limit);
+ }
+
+ return (*arena->class->configure)(arena, args);
+}
+
+
/* ArenaFinish -- finish the generic part of the arena
*
* .finish.caller: Unlike PoolFinish, this is called by the class finish
diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c
index 857c4608e11..0f118422dfb 100644
--- a/mps/code/arenacl.c
+++ b/mps/code/arenacl.c
@@ -307,6 +307,16 @@ static Res ClientArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
}
+/* ClientArenaConfigure -- configure the arena */
+
+static Res ClientArenaConfigure(Arena arena, ArgList args)
+{
+ UNUSED(arena);
+ UNUSED(args);
+ return ResOK;
+}
+
+
/* ClientArenaFinish -- finish the arena */
static void ClientArenaFinish(Arena arena)
@@ -450,6 +460,7 @@ DEFINE_ARENA_CLASS(ClientArenaClass, this)
this->offset = offsetof(ClientArenaStruct, arenaStruct);
this->varargs = ClientArenaVarargs;
this->init = ClientArenaInit;
+ this->configure = ClientArenaConfigure;
this->finish = ClientArenaFinish;
this->reserved = ClientArenaReserved;
this->extend = ClientArenaExtend;
diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c
index 77abf295e0b..fa57cfdfa5c 100644
--- a/mps/code/arenavm.c
+++ b/mps/code/arenavm.c
@@ -617,6 +617,16 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
}
+/* VMArenaConfigure -- configure the arena */
+
+static Res VMArenaConfigure(Arena arena, ArgList args)
+{
+ UNUSED(arena);
+ UNUSED(args);
+ return ResOK;
+}
+
+
/* VMArenaFinish -- finish the arena */
static void VMArenaFinish(Arena arena)
@@ -1203,6 +1213,7 @@ DEFINE_ARENA_CLASS(VMArenaClass, this)
this->offset = offsetof(VMArenaStruct, arenaStruct);
this->varargs = VMArenaVarargs;
this->init = VMArenaInit;
+ this->configure = VMArenaConfigure;
this->finish = VMArenaFinish;
this->reserved = VMArenaReserved;
this->purgeSpare = VMPurgeSpare;
diff --git a/mps/code/config.h b/mps/code/config.h
index 8fbd251a220..0fded6a291d 100644
--- a/mps/code/config.h
+++ b/mps/code/config.h
@@ -405,6 +405,13 @@
#define ARENA_CLIENT_GRAIN_SIZE ((Size)8192)
+#define ARENA_DEFAULT_COMMIT_LIMIT ((Size)-1)
+
+/* TODO: This should be proportional to the memory usage of the MPS, not
+ * a constant. That will require design, and then some interface and
+ * documenation changes. */
+#define ARENA_DEFAULT_SPARE_COMMIT_LIMIT ((Size)10uL*1024uL*1024uL)
+
#define ARENA_DEFAULT_ZONED TRUE
#define ArenaDefaultZONESET (ZoneSetUNIV << (MPS_WORD_WIDTH / 2))
@@ -611,11 +618,6 @@
#define MPS_PROD_STRING "mps"
#define MPS_PROD_MPS
-/* TODO: This should be proportional to the memory usage of the MPS, not
- a constant. That will require design, and then some interface and
- documenation changes. */
-#define ARENA_INIT_SPARE_COMMIT_LIMIT ((Size)10uL*1024uL*1024uL)
-
/* Default chain for GC pools
*
diff --git a/mps/code/locusss.c b/mps/code/locusss.c
index 70cf313ed45..742e5ee779b 100644
--- a/mps/code/locusss.c
+++ b/mps/code/locusss.c
@@ -219,13 +219,11 @@ static void runArenaTest(size_t size,
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, size);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, FALSE);
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, size - chunkSize);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
"mps_arena_create");
} MPS_ARGS_END(args);
- die(mps_arena_commit_limit_set(arena, size - chunkSize),
- "mps_arena_commit_limit_set");
-
testInArena(arena, failcase, usefulFailcase);
mps_arena_destroy(arena);
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index 30c1089e0ce..458f8be6658 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -497,6 +497,7 @@ extern Bool ArenaClassCheck(ArenaClass class);
extern Bool ArenaCheck(Arena arena);
extern Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args);
+extern Res ArenaConfigure(Arena arena, ArgList args);
extern void ArenaDestroy(Arena arena);
extern Res ArenaInit(Arena arena, ArenaClass class, Size grainSize,
ArgList args);
diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h
index a7749aa738d..44a641018eb 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -525,6 +525,7 @@ typedef struct mps_arena_class_s {
size_t offset; /* offset of generic struct in outer struct */
ArenaVarargsMethod varargs;
ArenaInitMethod init;
+ ArenaConfigureMethod configure;
ArenaFinishMethod finish;
ArenaReservedMethod reserved;
ArenaPurgeSpareMethod purgeSpare;
diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h
index a69b2b79ebe..b52c8e7dfd4 100644
--- a/mps/code/mpmtypes.h
+++ b/mps/code/mpmtypes.h
@@ -119,6 +119,7 @@ typedef unsigned FindDelete; /* */
typedef void (*ArenaVarargsMethod)(ArgStruct args[], va_list varargs);
typedef Res (*ArenaInitMethod)(Arena *arenaReturn,
ArenaClass class, ArgList args);
+typedef Res (*ArenaConfigureMethod)(Arena arena, ArgList args);
typedef void (*ArenaFinishMethod)(Arena arena);
typedef Size (*ArenaReservedMethod)(Arena arena);
typedef Size (*ArenaPurgeSpareMethod)(Arena arena, Size size);
diff --git a/mps/code/mps.h b/mps/code/mps.h
index 4e75d49b73a..b8882335581 100644
--- a/mps/code/mps.h
+++ b/mps/code/mps.h
@@ -155,12 +155,18 @@ extern const struct mps_key_s _mps_key_ARGS_END;
#define MPS_KEY_ARGS_END (&_mps_key_ARGS_END)
extern mps_arg_s mps_args_none[];
-extern const struct mps_key_s _mps_key_ARENA_SIZE;
-#define MPS_KEY_ARENA_SIZE (&_mps_key_ARENA_SIZE)
-#define MPS_KEY_ARENA_SIZE_FIELD size
+extern const struct mps_key_s _mps_key_ARENA_COMMIT_LIMIT;
+#define MPS_KEY_ARENA_COMMIT_LIMIT (&_mps_key_ARENA_COMMIT_LIMIT)
+#define MPS_KEY_ARENA_COMMIT_LIMIT_FIELD size
extern const struct mps_key_s _mps_key_ARENA_GRAIN_SIZE;
#define MPS_KEY_ARENA_GRAIN_SIZE (&_mps_key_ARENA_GRAIN_SIZE)
#define MPS_KEY_ARENA_GRAIN_SIZE_FIELD size
+extern const struct mps_key_s _mps_key_ARENA_SIZE;
+#define MPS_KEY_ARENA_SIZE (&_mps_key_ARENA_SIZE)
+#define MPS_KEY_ARENA_SIZE_FIELD size
+extern const struct mps_key_s _mps_key_ARENA_SPARE_COMMIT_LIMIT;
+#define MPS_KEY_ARENA_SPARE_COMMIT_LIMIT (&_mps_key_ARENA_SPARE_COMMIT_LIMIT)
+#define MPS_KEY_ARENA_SPARE_COMMIT_LIMIT_FIELD 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
@@ -433,6 +439,7 @@ extern mps_res_t mps_arena_create(mps_arena_t *, mps_arena_class_t, ...);
extern mps_res_t mps_arena_create_v(mps_arena_t *, mps_arena_class_t, va_list);
extern mps_res_t mps_arena_create_k(mps_arena_t *, mps_arena_class_t,
mps_arg_s []);
+extern mps_res_t mps_arena_configure(mps_arena_t, mps_arg_s []);
extern void mps_arena_destroy(mps_arena_t);
extern size_t mps_arena_reserved(mps_arena_t);
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index a7dec7495c1..8ee89ac3923 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -350,6 +350,20 @@ mps_res_t mps_arena_create_k(mps_arena_t *mps_arena_o,
}
+/* mps_arena_configure -- configure an arena object */
+
+mps_res_t mps_arena_configure(mps_arena_t arena, mps_arg_s args[])
+{
+ Res res;
+
+ ArenaEnter(arena);
+ res = ArenaConfigure(arena, args);
+ ArenaLeave(arena);
+
+ return (mps_res_t)res;
+}
+
+
/* mps_arena_destroy -- destroy an arena object */
void mps_arena_destroy(mps_arena_t arena)
diff --git a/mps/code/mpsicv.c b/mps/code/mpsicv.c
index a6b23f00578..9f546c8678c 100644
--- a/mps/code/mpsicv.c
+++ b/mps/code/mpsicv.c
@@ -320,6 +320,7 @@ static mps_res_t root_single(mps_ss_t ss, void *p, size_t s)
* mps_arena_reserved
* incidentally tests:
* mps_alloc
+ * mps_arena_configure
* mps_class_mv
* mps_pool_create
* mps_pool_destroy
@@ -346,7 +347,10 @@ static void arena_commit_test(mps_arena_t arena)
res = mps_alloc(&p, pool, FILLER_OBJECT_SIZE);
} while (res == MPS_RES_OK);
die_expect(res, MPS_RES_COMMIT_LIMIT, "Commit limit allocation");
- die(mps_arena_commit_limit_set(arena, limit), "commit_limit_set after");
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, limit);
+ die(mps_arena_configure(arena, args), "commit_limit_set after");
+ } MPS_ARGS_END(args);
res = mps_alloc(&p, pool, FILLER_OBJECT_SIZE);
die_expect(res, MPS_RES_OK, "Allocation failed after raising commit_limit");
mps_pool_destroy(pool);
diff --git a/mps/manual/source/glossary/c.rst b/mps/manual/source/glossary/c.rst
index ffdf1899243..23b2d960048 100644
--- a/mps/manual/source/glossary/c.rst
+++ b/mps/manual/source/glossary/c.rst
@@ -354,7 +354,8 @@ Memory Management Glossary: C
The commit limit is a limit on the :term:`committed
` :term:`memory (2)` that the :term:`arena` will
obtain from the operating system. It can be changed by
- calling :c:func:`mps_arena_commit_limit_set`.
+ passing the :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT`
+ :term:`keyword argument` to :c:func:`mps_arena_configure`.
committed (1)
diff --git a/mps/manual/source/glossary/s.rst b/mps/manual/source/glossary/s.rst
index dc9355f2a0f..b18c186fd23 100644
--- a/mps/manual/source/glossary/s.rst
+++ b/mps/manual/source/glossary/s.rst
@@ -467,7 +467,8 @@ Memory Management Glossary: S
committed memory` that the MPS will obtain from the
operating system. It can be retrieved by calling
:c:func:`mps_arena_spare_commit_limit` and changed by
- calling :c:func:`mps_arena_spare_commit_limit_set`.
+ passing the :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT`
+ :term:`keyword argument` to :c:func:`mps_arena_configure`.
spare committed memory
diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst
index 1c1a3ef01f6..1d4e1e3405c 100644
--- a/mps/manual/source/release.rst
+++ b/mps/manual/source/release.rst
@@ -9,6 +9,20 @@ Release notes
Release 1.115.0
---------------
+New features
+............
+
+#. The function :c:func:`mps_arena_create_k` accepts two new
+ :term:`keyword arguments`. :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT`
+ sets the :term:`commit limit` for the arena, and
+ :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` sets the :term:`spare
+ commit limit` for the arena.
+
+#. The new function :c:func:`mps_arena_configure` provides a
+ :term:`keyword argument` interface for changing the properties of
+ an arena.
+
+
Interface changes
.................
@@ -22,6 +36,10 @@ Interface changes
deprecated in favour of the generic functions
:c:func:`mps_pool_free_size` and :c:func:`mps_pool_total_size`.
+#. The functions :c:func:`mps_arena_commit_limit_set` and
+ :c:func:`mps_arena_spare_commit_limit_set` are deprecated in favour
+ of :c:func:`mps_arena_configure`.
+
.. _release-notes-1.114:
diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst
index 3ab5ad8c7bd..dc612c9f2a0 100644
--- a/mps/manual/source/topic/arena.rst
+++ b/mps/manual/source/topic/arena.rst
@@ -92,6 +92,19 @@ the way that they acquire the memory to be managed.
:c:func:`mps_arena_destroy`.
+.. c:function:: mps_res_t mps_arena_configure(mps_arena_t arena, mps_arg_s args[])
+
+ Configure an :term:`arena`.
+
+ ``arena`` is the arena to configure.
+
+ ``args`` are :term:`keyword arguments` specifying configuration
+ parameters. See the documentation for the arena class.
+
+ Returns :c:macro:`MPS_RES_OK` if the arena was configured
+ successfully, or another :term:`result code` otherwise.
+
+
.. c:function:: void mps_arena_destroy(mps_arena_t arena)
Destroy an :term:`arena`.
@@ -139,7 +152,12 @@ Client arenas
* :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type:`size_t`) is its
size.
- It also accepts one optional keyword argument:
+ It also accepts two optional keyword arguments:
+
+ * :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` (type :c:type:`size_t`) is
+ the commit limit in :term:`bytes (1)`. See
+ :c:func:`mps_arena_commit_limit` for details. The default commit
+ limit is the maximum value of the :c:type:`size_t` type.
* :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` (type :c:type:`size_t`,
default 8192) is the granularity with which the arena will
@@ -166,6 +184,10 @@ Client arenas
Client arenas have no mechanism for returning unused memory.
+ When configuring a client arena, :c:func:`mps_arena_configure`
+ accepts the :term:`keyword argument`
+ :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` as described above.
+
.. c:function:: mps_res_t mps_arena_extend(mps_arena_t arena, mps_addr_t base, size_t size)
@@ -206,7 +228,7 @@ Virtual memory arenas
more efficient.
When creating a virtual memory arena, :c:func:`mps_arena_create_k`
- accepts two optional :term:`keyword arguments` on all platforms:
+ accepts four optional :term:`keyword arguments` on all platforms:
* :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type:`size_t`, default
256 :term:`megabytes`) is the initial amount of virtual address
@@ -233,6 +255,11 @@ Virtual memory arenas
more times it has to extend its address space, the less
efficient garbage collection will become.
+ * :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` (type :c:type:`size_t`) is
+ the commit limit in :term:`bytes (1)`. See
+ :c:func:`mps_arena_commit_limit` for details. The default commit
+ limit is the maximum value of the :c:type:`size_t` type.
+
* :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` (type :c:type:`size_t`) is
the granularity with which the arena will manage memory
internally. It must be a power of 2. If not provided, the
@@ -244,12 +271,18 @@ Virtual memory arenas
that's smaller than the operating system page size, the MPS
rounds it up to the page size and continues.
- A third optional :term:`keyword argument` may be passed, but it
+ * :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` (type
+ :c:type:`size_t`, default 0) is the spare commit limit in
+ :term:`bytes (1)`. See :c:func:`mps_arena_spare_commit_limit`
+ for details.
+
+ A fifth optional :term:`keyword argument` may be passed, but it
only has any effect on the Windows operating system:
- * :c:macro:`MPS_KEY_VMW3_TOP_DOWN` (type :c:type:`mps_bool_t`). If
- true, the arena will allocate address space starting at the
- highest possible address and working downwards through memory.
+ * :c:macro:`MPS_KEY_VMW3_TOP_DOWN` (type :c:type:`mps_bool_t`,
+ default false). If true, the arena will allocate address space
+ starting at the highest possible address and working downwards
+ through memory.
.. note::
@@ -276,6 +309,11 @@ Virtual memory arenas
res = mps_arena_create_k(&arena, mps_arena_class_vm(), args);
} MPS_ARGS_END(args);
+ When configuring a virtual memory arena,
+ :c:func:`mps_arena_configure` accepts the :term:`keyword
+ arguments` :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` and
+ :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` as described above.
+
.. index::
single: arena; properties
@@ -299,45 +337,36 @@ Arena properties
``arena`` is the arena to return the commit limit for.
Returns the commit limit in :term:`bytes (1)`. The commit limit
- controls how much memory the MPS can obtain from the operating
- system, and can be changed by calling
- :c:func:`mps_arena_commit_limit_set`.
+ controls how much main memory the MPS will obtain from the
+ operating system. The function :c:func:`mps_arena_committed`
+ returns the current committed memory; this never exceeds the
+ commit limit.
-
-.. c:function:: mps_res_t mps_arena_commit_limit_set(mps_arena_t arena, size_t limit)
-
- Change the :term:`commit limit` for an :term:`arena`.
-
- ``arena`` is the arena to change the commit limit for.
-
- ``limit`` is the new commit limit in :term:`bytes (1)`.
-
- Returns :c:macro:`MPS_RES_OK` if successful, or another
- :term:`result code` if not.
-
- If successful, the commit limit for ``arena`` is set to ``limit``. The
- commit limit controls how much memory the MPS will obtain from the
- operating system. The commit limit cannot be set to a value that
- is lower than the number of bytes that the MPS is using. If an
- attempt is made to set the commit limit to a value greater than or
- equal to that returned by :c:func:`mps_arena_committed` then it
- will succeed. If an attempt is made to set the commit limit to a
- value less than that returned by :c:func:`mps_arena_committed`
- then it will succeed only if the amount committed by the MPS can
- be reduced by reducing the amount of spare committed memory; in
- such a case the spare committed memory will be reduced
- appropriately and the attempt will succeed.
+ The commit limit can be changed by passing the
+ :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` :term:`keyword argument` to
+ :c:func:`mps_arena_create_k` or :c:func:`mps_arena_configure`. The
+ commit limit cannot be set to a value that is lower than the
+ number of bytes that the MPS is using. If an attempt is made to
+ set the commit limit to a value greater than or equal to that
+ returned by :c:func:`mps_arena_committed` then it will succeed. If
+ an attempt is made to set the commit limit to a value less than
+ that returned by :c:func:`mps_arena_committed` then it will
+ succeed only if the amount committed by the MPS can be reduced by
+ reducing the amount of spare committed memory; in such a case the
+ spare committed memory will be reduced appropriately and the
+ attempt will succeed.
.. note::
- :c:func:`mps_arena_commit_limit_set` puts a limit on all
- memory committed by the MPS. The :term:`spare committed
- memory` can be limited separately with
- :c:func:`mps_arena_spare_commit_limit_set`. Note that "spare
- committed" memory is subject to both limits; there cannot be
- more spare committed memory than the spare commit limit, and
- there can't be so much spare committed memory that there is
- more committed memory than the commit limit.
+ The commit limit puts a limit on all memory committed by the
+ MPS. The :term:`spare committed memory` (that is, memory
+ committed by the MPS but not currently in use, neither by the
+ :term:`client program`, or by the MPS itself) can be limited
+ separately; see :c:func:`mps_arena_spare_committed`. Note that
+ "spare committed" memory is subject to both limits; there
+ cannot be more spare committed memory than the spare commit
+ limit, and there can't be so much spare committed memory that
+ there is more committed memory than the commit limit.
.. c:function:: size_t mps_arena_committed(mps_arena_t arena)
@@ -379,7 +408,7 @@ Arena properties
estimate the size of the heap.
If you want to know how much memory the MPS is using then you're
- probably interested in the value :c:func:`mps_arena_committed()` −
+ probably interested in the value :c:func:`mps_arena_committed` −
:c:func:`mps_arena_spare_committed`.
The amount of committed memory can be limited with the function
@@ -419,32 +448,19 @@ Arena properties
``arena`` is the arena to return the spare commit limit for.
Returns the spare commit limit in :term:`bytes (1)`. The spare
- commit limit can be changed by calling
- :c:func:`mps_arena_spare_commit_limit_set`.
+ commit limit is the maximum amount of :term:`spare committed
+ memory` (that is, memory committed by the MPS but not currently in
+ use, neither by the :term:`client program`, or by the MPS itself)
+ the MPS is allowed to have.
-
-.. c:function:: void mps_arena_spare_commit_limit_set(mps_arena_t arena, size_t limit)
-
- Change the :term:`spare commit limit` for an :term:`arena`.
-
- ``arena`` is the arena to change the spare commit limit for.
-
- ``limit`` is the new spare commit limit in :term:`bytes (1)`.
-
- The spare commit limit is the maximum amount of :term:`spare
- committed memory` the MPS is allowed to have. Setting it to a
- value lower than the current amount of spare committed memory
- causes spare committed memory to be uncommitted so as to bring the
- value under the limit. In particular, setting it to 0 will mean
- that the MPS will have no spare committed memory.
-
- Non-virtual-memory arena classes (for example, a :term:`client
- arena`) do not have spare committed memory. For these arenas, this
- function sets a value but has no other effect.
-
- Initially the spare commit limit is a configuration-dependent
- value. The value of the limit can be retrieved by the function
- :c:func:`mps_arena_spare_commit_limit`.
+ The spare commit limit can be changed by passing the
+ :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` :term:`keyword
+ argument` to :c:func:`mps_arena_create_k` or
+ :c:func:`mps_arena_configure`. Setting it to a value lower than
+ the current amount of spare committed memory causes spare
+ committed memory to be uncommitted so as to bring the value under
+ the limit. In particular, setting it to 0 will mean that the MPS
+ will have no spare committed memory.
.. c:function:: size_t mps_arena_spare_committed(mps_arena_t arena)
@@ -466,12 +482,13 @@ Arena properties
memory by :c:func:`mps_arena_committed` and is restricted by
:c:func:`mps_arena_commit_limit`.
- The amount of "spare committed" memory can be limited by calling
- :c:func:`mps_arena_spare_commit_limit_set`, and the value of that
- limit can be retrieved with
- :c:func:`mps_arena_spare_commit_limit`. This is analogous to the
- functions for limiting the amount of :term:`committed `
- memory.
+ The amount of "spare committed" memory can be limited passing the
+ :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` :term:`keyword
+ argument` to :c:func:`mps_arena_create_k` or
+ :c:func:`mps_arena_configure`. The value of the limit can be
+ retrieved with :c:func:`mps_arena_spare_commit_limit`. This is
+ analogous to the functions for limiting the amount of
+ :term:`committed ` memory.
.. index::
diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst
index dfd4d8d74cb..329f90d48dc 100644
--- a/mps/manual/source/topic/deprecated.rst
+++ b/mps/manual/source/topic/deprecated.rst
@@ -25,6 +25,41 @@ supported interface.
Deprecated in version 1.115
...........................
+.. c:function:: mps_res_t mps_arena_commit_limit_set(mps_arena_t arena, size_t limit)
+
+ .. deprecated::
+
+ Pass the :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` :term:`keyword
+ argument` to :c:func:`mps_arena_create_k` or
+ :c:func:`mps_arena_configure`.
+
+ Change the :term:`commit limit` for an :term:`arena`.
+
+ ``arena`` is the arena to change the commit limit for.
+
+ ``limit`` is the new commit limit in :term:`bytes (1)`.
+
+ Returns :c:macro:`MPS_RES_OK` if successful, or another
+ :term:`result code` if not.
+
+
+.. c:function:: void mps_arena_spare_commit_limit_set(mps_arena_t arena, size_t limit)
+
+ Change the :term:`spare commit limit` for an :term:`arena`.
+
+ ``arena`` is the arena to change the spare commit limit for.
+
+ ``limit`` is the new spare commit limit in :term:`bytes (1)`.
+
+ Non-virtual-memory arena classes (for example, a :term:`client
+ arena`) do not have spare committed memory. For these arenas, this
+ function sets a value but has no other effect.
+
+ Initially the spare commit limit is a configuration-dependent
+ value. The value of the limit can be retrieved by the function
+ :c:func:`mps_arena_spare_commit_limit`.
+
+
.. c:type:: typedef mps_pool_class_t mps_class_t
.. deprecated::
diff --git a/mps/manual/source/topic/keyword.rst b/mps/manual/source/topic/keyword.rst
index ac80333ba36..6d321eab491 100644
--- a/mps/manual/source/topic/keyword.rst
+++ b/mps/manual/source/topic/keyword.rst
@@ -82,43 +82,45 @@ now :c:macro:`MPS_KEY_ARGS_END`.
The type of :term:`keyword argument` keys. Must take one of the
following values:
- ======================================== ========================================================= ==========================================================
- Keyword Type & field in ``arg.val`` See
- ======================================== ========================================================= ==========================================================
- :c:macro:`MPS_KEY_ARGS_END` *none* *see above*
- :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt`
- :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams`
- :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl`
- :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
- :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
- :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl`
- :c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo`
- :c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_FWD` :c:type:`mps_fmt_fwd_t` ``fmt_fwd`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_HEADER_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_ISFWD` :c:type:`mps_fmt_isfwd_t` ``fmt_isfwd`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_PAD` :c:type:`mps_fmt_pad_t` ``fmt_pad`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_SCAN` :c:type:`mps_fmt_scan_t` ``fmt_scan`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_SKIP` :c:type:`mps_fmt_skip_t` ``fmt_skip`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FORMAT` :c:type:`mps_fmt_t` ``format`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` , :c:func:`mps_class_snc`
- :c:macro:`MPS_KEY_GEN` :c:type:`unsigned` ``u`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo`
- :c:macro:`MPS_KEY_INTERIOR` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`
- :c:macro:`MPS_KEY_MAX_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`
- :c:macro:`MPS_KEY_MEAN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvt`, :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_MFS_UNIT_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mfs`
- :c:macro:`MPS_KEY_MIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mvt`
- :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_MVFF_FIRST_FIT` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt`
- :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt`
- :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` :c:type:`mps_pool_debug_option_s` ``*pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug`
- :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc`
- :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm`
- ======================================== ========================================================= ==========================================================
+ =========================================== ========================================================= ==========================================================
+ Keyword Type & field in ``arg.val`` See
+ =========================================== ========================================================= ==========================================================
+ :c:macro:`MPS_KEY_ARGS_END` *none* *see above*
+ :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt`
+ :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams`
+ :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl`
+ :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
+ :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
+ :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
+ :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
+ :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl`
+ :c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo`
+ :c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_FWD` :c:type:`mps_fmt_fwd_t` ``fmt_fwd`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_HEADER_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_ISFWD` :c:type:`mps_fmt_isfwd_t` ``fmt_isfwd`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_PAD` :c:type:`mps_fmt_pad_t` ``fmt_pad`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_SCAN` :c:type:`mps_fmt_scan_t` ``fmt_scan`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_SKIP` :c:type:`mps_fmt_skip_t` ``fmt_skip`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FORMAT` :c:type:`mps_fmt_t` ``format`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` , :c:func:`mps_class_snc`
+ :c:macro:`MPS_KEY_GEN` :c:type:`unsigned` ``u`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo`
+ :c:macro:`MPS_KEY_INTERIOR` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`
+ :c:macro:`MPS_KEY_MAX_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`
+ :c:macro:`MPS_KEY_MEAN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvt`, :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_MFS_UNIT_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mfs`
+ :c:macro:`MPS_KEY_MIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mvt`
+ :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_MVFF_FIRST_FIT` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt`
+ :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt`
+ :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` :c:type:`mps_pool_debug_option_s` ``*pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug`
+ :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc`
+ :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm`
+ =========================================== ========================================================= ==========================================================
.. c:function:: MPS_ARGS_BEGIN(args)
diff --git a/mps/test/function/165.c b/mps/test/function/165.c
index 087d5e08f8d..e542cc111a7 100644
--- a/mps/test/function/165.c
+++ b/mps/test/function/165.c
@@ -1,7 +1,7 @@
/*
TEST_HEADER
id = $Id$
- summary = simple spare_commit_limit test
+ summary = simple spare commit limit test
language = c
link = testlib.o rankfmt.o
harness = 2.0
@@ -32,14 +32,15 @@ static void test(void)
unsigned long com0, com1, com2;
-/* create a VM arena of 40MB */
+/* create a VM arena of 40MB with commit limit of 100MB, i.e. let the
+ arena do the limiting. */
- cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t)(1024*1024*40)),
- "create arena");
-
-/* set the commit limit to 100MB, i.e. let the arena do the limiting */
-
- mps_arena_commit_limit_set(arena, (size_t) (1024ul*1024ul*100ul));
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 1024*1024*40);
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 1024ul*1024ul*100ul);
+ cdie(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
+ "create arena");
+ } MPS_ARGS_END(args);
cdie(mps_thread_reg(&thread, arena), "register thread");
@@ -58,7 +59,10 @@ static void test(void)
/* Set the spare commit limit to 0MB */
- mps_arena_spare_commit_limit_set(arena, (size_t) 0);
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT, 0);
+ cdie(mps_arena_configure(arena, args), "mps_arena_configure");
+ } MPS_ARGS_END(args);
die(mps_alloc(&objs[0], pool, BIGSIZE), "alloc");
com0 = mps_arena_committed(arena);
mps_free(pool, objs[0], BIGSIZE);
@@ -70,7 +74,10 @@ static void test(void)
/* Try again but with arena hysteresis */
/* nb. size_t unsigned, therefore (size_t)-1 is the maximum limit */
- mps_arena_spare_commit_limit_set(arena, (size_t)-1);
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT, -1);
+ cdie(mps_arena_configure(arena, args), "mps_arena_configure");
+ } MPS_ARGS_END(args);
die(mps_alloc(&objs[0], pool, BIGSIZE), "alloc");
com0 = mps_arena_committed(arena);
mps_free(pool, objs[0], BIGSIZE);
@@ -80,7 +87,10 @@ static void test(void)
report("reduce2", "%ld", com0-com1);
/* Reducing the spare committed limit should return most of the spare */
- mps_arena_spare_commit_limit_set(arena, (size_t)(1024*1024));
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT, 1024*1024);
+ cdie(mps_arena_configure(arena, args), "mps_arena_configure");
+ } MPS_ARGS_END(args);
com2 = mps_arena_committed(arena);
report("reduce3", "%ld", com0-com2);
From c84a68b2ef1c26f4385a31b55c83f28d5c552848 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 10 Aug 2015 10:57:39 +0100
Subject: [PATCH 031/337] Branching master to branch/2015-08-10/arena-create.
Copied from Perforce
Change: 188096
ServerID: perforce.ravenbrook.com
From afb5ff33c1071b9af4d10b7c1e6e72496567a602 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 10 Aug 2015 11:41:58 +0100
Subject: [PATCH 032/337] Correct the test for too-small client arena sizes.
Add automated test case for client arenas with small sizes.
Copied from Perforce
Change: 188099
ServerID: perforce.ravenbrook.com
---
mps/code/arenacl.c | 2 +-
mps/test/function/121.c | 50 +++++++++++++++++++++++------------------
2 files changed, 29 insertions(+), 23 deletions(-)
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/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 66c2645e03ddcf9636a953e7c9a5f8b6a3f59b4f Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 10 Aug 2015 11:43:17 +0100
Subject: [PATCH 033/337] Tear down arena correctly if controlinit fails.
Copied from Perforce
Change: 188100
ServerID: perforce.ravenbrook.com
---
mps/code/arena.c | 62 ++++++++++++++++++++++++++++++++----------------
1 file changed, 42 insertions(+), 20 deletions(-)
diff --git a/mps/code/arena.c b/mps/code/arena.c
index fee56d6378a..31d98251f96 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 */
@@ -301,6 +302,26 @@ 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);
+
+ /* 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);
+ if (res != ResOK)
+ return res;
+ arena->hasFreeLand = TRUE;
+ return ResOK;
+}
+
Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
{
Arena arena;
@@ -326,15 +347,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 +366,8 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
failGlobalsCompleteCreate:
ControlFinish(arena);
failControlInit:
-failPrimaryLand:
+ arenaFreeLandFinish(arena);
+failFreeLandInit:
failStripeSize:
(*class->finish)(arena);
failInit:
@@ -392,6 +408,20 @@ static void arenaMFSPageFreeVisitor(Pool pool, Addr base, Size size,
arenaFreePage(PoolArena(pool), base, pool);
}
+static void arenaFreeLandFinish(Arena 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);
+}
+
void ArenaDestroy(Arena arena)
{
AVERT(Arena, arena);
@@ -401,19 +431,9 @@ 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);
+ arenaFreeLandFinish(arena);
/* Call class-specific finishing. This will call ArenaFinish. */
(*arena->class->finish)(arena);
@@ -429,6 +449,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 +467,7 @@ Res ControlInit(Arena arena)
void ControlFinish(Arena arena)
{
AVERT(Arena, arena);
+ AVER(arena->poolReady);
arena->poolReady = FALSE;
PoolFinish(MVPool(&arena->controlPoolStruct));
}
From 844cc628390eeb0508063311308256f6cc75a246 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 10 Aug 2015 12:15:05 +0100
Subject: [PATCH 034/337] Start review checklist.
Copied from Perforce
Change: 188101
ServerID: perforce.ravenbrook.com
---
mps/design/guide.review.txt | 96 ++++++++++++++++++++++++++++++
mps/design/index.txt | 2 +
mps/manual/source/design/index.rst | 1 +
3 files changed, 99 insertions(+)
create mode 100644 mps/design/guide.review.txt
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..9f4abf7b4f4 100644
--- a/mps/design/index.txt
+++ b/mps/design/index.txt
@@ -61,6 +61,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
@@ -138,6 +139,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..907c9986bb1 100644
--- a/mps/manual/source/design/index.rst
+++ b/mps/manual/source/design/index.rst
@@ -17,6 +17,7 @@ Design
guide.hex.trans
guide.impl.c.format
guide.impl.c.naming
+ guide.review
interface-c
keyword-arguments
land
From 8d2ed2290895d2872f275a2db957ae61a4638884 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 10 Aug 2015 15:27:26 +0100
Subject: [PATCH 035/337] Apply commit limit (and spare commit limit) during
arena creation, to avoid exceeding the limit and then discovering that we've
done so.
Add test case for arena hitting commit limit during creation.
Copied from Perforce
Change: 188106
ServerID: perforce.ravenbrook.com
---
mps/code/arena.c | 18 ++++++++----------
mps/test/function/120.c | 11 ++++++++++-
2 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/mps/code/arena.c b/mps/code/arena.c
index 9d359808c50..3d843cc7bde 100644
--- a/mps/code/arena.c
+++ b/mps/code/arena.c
@@ -197,6 +197,8 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args)
{
Res res;
Bool zoned = ARENA_DEFAULT_ZONED;
+ Size commitLimit = ARENA_DEFAULT_COMMIT_LIMIT;
+ Size spareCommitLimit = ARENA_DEFAULT_SPARE_COMMIT_LIMIT;
mps_arg_s arg;
AVER(arena != NULL);
@@ -205,16 +207,18 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args)
if (ArgPick(&arg, args, MPS_KEY_ARENA_ZONED))
zoned = arg.val.b;
+ if (ArgPick(&arg, args, MPS_KEY_ARENA_COMMIT_LIMIT))
+ commitLimit = arg.val.size;
+ if (ArgPick(&arg, args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT))
+ spareCommitLimit = arg.val.size;
arena->class = class;
arena->reserved = (Size)0;
arena->committed = (Size)0;
- /* commitLimit may be overridden by init (but probably not */
- /* as there's not much point) */
- arena->commitLimit = ARENA_DEFAULT_COMMIT_LIMIT;
+ arena->commitLimit = commitLimit;
arena->spareCommitted = (Size)0;
- arena->spareCommitLimit = ARENA_DEFAULT_SPARE_COMMIT_LIMIT;
+ arena->spareCommitLimit = spareCommitLimit;
arena->grainSize = grainSize;
/* zoneShift is usually overridden by init */
arena->zoneShift = ARENA_ZONESHIFT;
@@ -362,15 +366,9 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
goto failGlobalsCompleteCreate;
AVERT(Arena, arena);
-
- res = ArenaConfigure(arena, args);
- if (res != ResOK)
- goto failConfigure;
-
*arenaReturn = arena;
return ResOK;
-failConfigure:
failGlobalsCompleteCreate:
ControlFinish(arena);
failControlInit:
diff --git a/mps/test/function/120.c b/mps/test/function/120.c
index 4bd55205998..77609e3e37f 100644
--- a/mps/test/function/120.c
+++ b/mps/test/function/120.c
@@ -5,6 +5,7 @@ TEST_HEADER
language = c
link = testlib.o
OUTPUT_SPEC
+ create = COMMIT_LIMIT
commit0 = FAIL
commit10 = OK
com_less = FAIL
@@ -33,8 +34,16 @@ static void test(void) {
int i;
mps_addr_t a;
mps_res_t res;
+ size_t committed;
+
+ /* Create an arena with a commit limit that's too small for the
+ * essential MPS internal data structures -- this must fail with
+ * RES_COMMIT_LIMIT. */
-/* create an arena that can't grow beyond 20 M */
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 16 * 1024);
+ report_res("create", mps_arena_create_k(&arena, mps_arena_class_vm(), args));
+ } MPS_ARGS_END(args);
cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*20)),
"create arena");
From 7dee7f10ea097837203429bf916e1ee4abefd514 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 10 Aug 2015 20:29:21 +0100
Subject: [PATCH 036/337] New test case 231: create/configure arena with
too-small commit limit.
Copied from Perforce
Change: 188118
ServerID: perforce.ravenbrook.com
---
mps/test/function/231.c | 43 +++++++++++++++++++++++++++++++++++++++
mps/test/testsets/passing | 3 ++-
2 files changed, 45 insertions(+), 1 deletion(-)
create mode 100644 mps/test/function/231.c
diff --git a/mps/test/function/231.c b/mps/test/function/231.c
new file mode 100644
index 00000000000..e0620fd09b3
--- /dev/null
+++ b/mps/test/function/231.c
@@ -0,0 +1,43 @@
+/*
+TEST_HEADER
+ id = $Id$
+ summary = create/configure arena with too-small commit limit
+ language = c
+ link = testlib.o
+OUTPUT_SPEC
+ create1 = COMMIT_LIMIT
+ create2 = OK
+ configure = FAIL
+END_HEADER
+*/
+
+#include "testlib.h"
+#include "newfmt.h"
+
+static void test(void)
+{
+ mps_arena_t arena;
+
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 16 * 1024);
+ report_res("create1",
+ mps_arena_create_k(&arena, mps_arena_class_vm(), args));
+ } MPS_ARGS_END(args);
+
+ report_res("create2",
+ mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none));
+
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 16 * 1024);
+ report_res("configure", mps_arena_configure(arena, args));
+ } MPS_ARGS_END(args);
+
+ 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..d19cce41070 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/231.c
From e84a0670d75397265025e925f9b900d3c6bce6f3 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 11 Aug 2015 08:35:53 +0100
Subject: [PATCH 037/337] Test case function/228.c is passing.
Copied from Perforce
Change: 188123
ServerID: perforce.ravenbrook.com
---
mps/test/testsets/passing | 1 +
1 file changed, 1 insertion(+)
diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing
index 4b0a0cbe1b5..e3de6f383f3 100644
--- a/mps/test/testsets/passing
+++ b/mps/test/testsets/passing
@@ -167,3 +167,4 @@ function/223.c
function/224.c
% 225 -- no such test
function/226.c
+function/228.c
From de8c913bd2e1ef1e88455c16b8fce12611afb97f Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 11 Aug 2015 11:24:43 +0100
Subject: [PATCH 038/337] Fix typo (spotted by bruce mitchener).
Copied from Perforce
Change: 188130
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 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_.
From 510c0740517f3d18adefb8e0682010edfa200007 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 11 Aug 2015 12:01:53 +0100
Subject: [PATCH 039/337] Make -b ensures that mps.o gets rebuilt.
Copied from Perforce
Change: 188132
ServerID: perforce.ravenbrook.com
---
mps/test/README | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mps/test/README b/mps/test/README
index 18bc2ed675e..90edaf8857f 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
From 7742bd4d8d31672126d56a5a89a47da14b9bbb87 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 11 Aug 2015 12:40:18 +0100
Subject: [PATCH 040/337] Branching master to branch/2015-08-11/policy.
Copied from Perforce
Change: 188138
ServerID: perforce.ravenbrook.com
From 5f578c7d8a83c7782642395619ed10c69ff68991 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 14 Aug 2015 10:30:16 +0100
Subject: [PATCH 041/337] Improve organization and naming of arena's free land
initialization and finish code, following review by nb
.
Copied from Perforce
Change: 188143
ServerID: perforce.ravenbrook.com
---
mps/code/arena.c | 100 +++++++++++++++++++++++++++--------------------
1 file changed, 57 insertions(+), 43 deletions(-)
diff --git a/mps/code/arena.c b/mps/code/arena.c
index 31d98251f96..a54cae0cb60 100644
--- a/mps/code/arena.c
+++ b/mps/code/arena.c
@@ -239,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));
@@ -254,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)
@@ -275,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));
@@ -310,16 +297,33 @@ static Res arenaFreeLandInit(Arena arena)
AVER(!arena->hasFreeLand);
AVER(arena->primary != NULL);
- /* With the primary chunk initialised we can add page memory to the freeLand
- * that describes the free address space in the primary chunk. */
+ /* 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)
- return res;
+ goto failFreeLandInsert;
+
arena->hasFreeLand = TRUE;
return ResOK;
+
+failFreeLandInsert:
+ LandFinish(ArenaFreeLand(arena));
+failLandInit:
+ return res;
}
Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
@@ -410,16 +414,16 @@ static void arenaMFSPageFreeVisitor(Pool pool, Addr base, Size size,
static void arenaFreeLandFinish(Arena arena)
{
- /* We must tear down the freeLand before the chunks, because pages
- * containing CBS blocks might be allocated in those chunks. */
+ AVERT(Arena, arena);
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. */
+ * that would use the free land. */
MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor,
UNUSED_POINTER, UNUSED_SIZE);
+
+ arena->hasFreeLand = FALSE;
+ LandFinish(ArenaFreeLand(arena));
}
void ArenaDestroy(Arena arena)
@@ -433,6 +437,8 @@ void ArenaDestroy(Arena arena)
ControlFinish(arena);
+ /* 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. */
@@ -823,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;
}
@@ -843,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;
@@ -877,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;
@@ -894,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;
@@ -923,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
@@ -938,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;
@@ -953,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.
@@ -1045,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. */
}
@@ -1257,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);
From b3056139c85e6b3d9204299b0f8f7290a607c588 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Wed, 19 Aug 2015 15:03:47 +0100
Subject: [PATCH 042/337] New module policy.c.
Copied from Perforce
Change: 188152
ServerID: perforce.ravenbrook.com
---
mps/code/arena.c | 119 +++++------------------------------
mps/code/comm.gmk | 1 +
mps/code/comm.nmk | 1 +
mps/code/mpm.h | 8 +++
mps/code/mps.c | 1 +
mps/code/policy.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 180 insertions(+), 104 deletions(-)
create mode 100644 mps/code/policy.c
diff --git a/mps/code/arena.c b/mps/code/arena.c
index fee56d6378a..023d4efd1a8 100644
--- a/mps/code/arena.c
+++ b/mps/code/arena.c
@@ -957,10 +957,19 @@ void ArenaFreeLandDelete(Arena arena, Addr base, Addr limit)
}
-static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high,
- Size size, Pool pool)
+/* ArenaFreeLandAlloc -- allocate a continguous range of tracts of
+ * size bytes from the arena's free land.
+ *
+ * size, zones, and high are as for LandFindInZones.
+ *
+ * If successful, mark the allocated tracts as belonging to pool, set
+ * *tractReturn to point to the first tract in the range, and return
+ * ResOK.
+ */
+
+Res ArenaFreeLandAlloc(Tract *tractReturn, Arena arena, ZoneSet zones,
+ Bool high, Size size, Pool pool)
{
- Arena arena;
RangeStruct range, oldRange;
Chunk chunk;
Bool found, b;
@@ -969,10 +978,11 @@ static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high,
Res res;
AVER(tractReturn != NULL);
+ AVERT(Arena, arena);
/* ZoneSet is arbitrary */
AVER(size > (Size)0);
AVERT(Pool, pool);
- arena = PoolArena(pool);
+ AVER(arena == PoolArena(pool));
AVER(SizeIsArenaGrains(size, arena));
if (!arena->zoned)
@@ -1031,105 +1041,6 @@ static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high,
}
-/* arenaAllocPolicy -- arena allocation policy implementation
- *
- * This is the code responsible for making decisions about where to allocate
- * memory. Avoid distributing code for doing this elsewhere, so that policy
- * can be maintained and adjusted.
- *
- * TODO: This currently duplicates the policy from VMAllocPolicy in
- * //info.ravenbrook.com/project/mps/master/code/arenavm.c#36 in order
- * to avoid disruption to clients, but needs revision.
- */
-
-static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, LocusPref pref,
- Size size, Pool pool)
-{
- Res res;
- Tract tract;
- ZoneSet zones, moreZones, evenMoreZones;
-
- AVER(tractReturn != NULL);
- AVERT(LocusPref, pref);
- AVER(size > (Size)0);
- AVERT(Pool, pool);
-
- /* Don't attempt to allocate if doing so would definitely exceed the
- commit limit. */
- if (arena->spareCommitted < size) {
- Size necessaryCommitIncrease = size - arena->spareCommitted;
- if (arena->committed + necessaryCommitIncrease > arena->commitLimit
- || arena->committed + necessaryCommitIncrease < arena->committed) {
- return ResCOMMIT_LIMIT;
- }
- }
-
- /* Plan A: allocate from the free Land in the requested zones */
- zones = ZoneSetDiff(pref->zones, pref->avoid);
- if (zones != ZoneSetEMPTY) {
- res = arenaAllocFromLand(&tract, zones, pref->high, size, pool);
- if (res == ResOK)
- goto found;
- }
-
- /* Plan B: add free zones that aren't blacklisted */
- /* TODO: Pools without ambiguous roots might not care about the blacklist. */
- /* TODO: zones are precious and (currently) never deallocated, so we
- should consider extending the arena first if address space is plentiful.
- See also job003384. */
- moreZones = ZoneSetUnion(pref->zones, ZoneSetDiff(arena->freeZones, pref->avoid));
- if (moreZones != zones) {
- res = arenaAllocFromLand(&tract, moreZones, pref->high, size, pool);
- if (res == ResOK)
- goto found;
- }
-
- /* Plan C: Extend the arena, then try A and B again. */
- if (moreZones != ZoneSetEMPTY) {
- res = arena->class->grow(arena, pref, size);
- if (res != ResOK)
- return res;
- if (zones != ZoneSetEMPTY) {
- res = arenaAllocFromLand(&tract, zones, pref->high, size, pool);
- if (res == ResOK)
- goto found;
- }
- if (moreZones != zones) {
- zones = ZoneSetUnion(zones, ZoneSetDiff(arena->freeZones, pref->avoid));
- res = arenaAllocFromLand(&tract, moreZones, pref->high, size, pool);
- if (res == ResOK)
- goto found;
- }
- }
-
- /* Plan D: add every zone that isn't blacklisted. This might mix GC'd
- objects with those from other generations, causing the zone check
- to give false positives and slowing down the collector. */
- /* TODO: log an event for this */
- evenMoreZones = ZoneSetDiff(ZoneSetUNIV, pref->avoid);
- if (evenMoreZones != moreZones) {
- res = arenaAllocFromLand(&tract, evenMoreZones, pref->high, size, pool);
- if (res == ResOK)
- goto found;
- }
-
- /* Last resort: try anywhere. This might put GC'd objects in zones where
- common ambiguous bit patterns pin them down, causing the zone check
- to give even more false positives permanently, and possibly retaining
- garbage indefinitely. */
- res = arenaAllocFromLand(&tract, ZoneSetUNIV, pref->high, size, pool);
- if (res == ResOK)
- goto found;
-
- /* Uh oh. */
- return res;
-
-found:
- *tractReturn = tract;
- return ResOK;
-}
-
-
/* ArenaAlloc -- allocate some tracts from the arena */
Res ArenaAlloc(Addr *baseReturn, LocusPref pref, Size size, Pool pool,
@@ -1162,7 +1073,7 @@ Res ArenaAlloc(Addr *baseReturn, LocusPref pref, Size size, Pool pool,
}
}
- res = arenaAllocPolicy(&tract, arena, pref, size, pool);
+ res = PolicyAlloc(&tract, arena, pref, size, pool);
if (res != ResOK) {
if (withReservoirPermit) {
Res resRes = ReservoirWithdraw(&base, &tract, reservoir, size, pool);
diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk
index c82caa4576e..dbd11f70d3b 100644
--- a/mps/code/comm.gmk
+++ b/mps/code/comm.gmk
@@ -187,6 +187,7 @@ MPMCOMMON = \
mpm.c \
mpsi.c \
nailboard.c \
+ policy.c \
pool.c \
poolabs.c \
poolmfs.c \
diff --git a/mps/code/comm.nmk b/mps/code/comm.nmk
index a59132ff354..1851fed90dc 100644
--- a/mps/code/comm.nmk
+++ b/mps/code/comm.nmk
@@ -145,6 +145,7 @@ MPMCOMMON=\
[mpm] \
[mpsi] \
[nailboard] \
+ [policy] \
[pool] \
[poolabs] \
[poolmfs] \
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index a5ac16b41a2..8fa04cc22b6 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -649,11 +649,19 @@ extern Res ReservoirWithdraw(Addr *baseReturn, Tract *baseTractReturn,
extern Res ArenaAlloc(Addr *baseReturn, LocusPref pref,
Size size, Pool pool, Bool withReservoirPermit);
+extern Res ArenaFreeLandAlloc(Tract *tractReturn, Arena arena, ZoneSet zones,
+ Bool high, Size size, Pool pool);
extern void ArenaFree(Addr base, Size size, Pool pool);
extern Res ArenaNoExtend(Arena arena, Addr base, Size size);
+/* Policy interface */
+
+extern Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
+ Size size, Pool pool);
+
+
/* Locus interface */
extern Bool LocusPrefCheck(LocusPref pref);
diff --git a/mps/code/mps.c b/mps/code/mps.c
index 95919d9680c..2f2e4f248e3 100644
--- a/mps/code/mps.c
+++ b/mps/code/mps.c
@@ -79,6 +79,7 @@
#include "land.c"
#include "failover.c"
#include "vm.c"
+#include "policy.c"
/* Additional pool classes */
diff --git a/mps/code/policy.c b/mps/code/policy.c
new file mode 100644
index 00000000000..8a34484eeb4
--- /dev/null
+++ b/mps/code/policy.c
@@ -0,0 +1,154 @@
+/* policy.c: POLICY DECISIONS
+ *
+ * $Id$
+ * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
+ *
+ * This module collects the decision-making code for the MPS, so that
+ * policy can be maintained and adjusted.
+ *
+ * .sources: .
+ */
+
+#include "mpm.h"
+
+SRCID(policy, "$Id$");
+
+
+/* PolicyAlloc -- allocation policy
+ *
+ * This is the code responsible for making decisions about where to allocate
+ * memory.
+ */
+
+Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
+ Size size, Pool pool)
+{
+ Res res;
+ Tract tract;
+ ZoneSet zones, moreZones, evenMoreZones;
+
+ AVER(tractReturn != NULL);
+ AVERT(Arena, arena);
+ AVERT(LocusPref, pref);
+ AVER(size > (Size)0);
+ AVERT(Pool, pool);
+ AVER(arena == PoolArena(pool));
+
+ /* Don't attempt to allocate if doing so would definitely exceed the
+ * commit limit. */
+ if (arena->spareCommitted < size) {
+ Size necessaryCommitIncrease = size - arena->spareCommitted;
+ if (arena->committed + necessaryCommitIncrease > arena->commitLimit
+ || arena->committed + necessaryCommitIncrease < arena->committed) {
+ return ResCOMMIT_LIMIT;
+ }
+ }
+
+ /* Plan A: allocate from the free Land in the requested zones */
+ zones = ZoneSetDiff(pref->zones, pref->avoid);
+ if (zones != ZoneSetEMPTY) {
+ res = ArenaFreeLandAlloc(&tract, arena, zones, pref->high, size, pool);
+ if (res == ResOK)
+ goto found;
+ }
+
+ /* Plan B: add free zones that aren't blacklisted */
+ /* TODO: Pools without ambiguous roots might not care about the blacklist. */
+ /* TODO: zones are precious and (currently) never deallocated, so we
+ * should consider extending the arena first if address space is plentiful.
+ * See also job003384. */
+ moreZones = ZoneSetUnion(pref->zones, ZoneSetDiff(arena->freeZones, pref->avoid));
+ if (moreZones != zones) {
+ res = ArenaFreeLandAlloc(&tract, arena, moreZones, pref->high, size, pool);
+ if (res == ResOK)
+ goto found;
+ }
+
+ /* Plan C: Extend the arena, then try A and B again. */
+ if (moreZones != ZoneSetEMPTY) {
+ res = arena->class->grow(arena, pref, size);
+ if (res != ResOK)
+ return res;
+ if (zones != ZoneSetEMPTY) {
+ res = ArenaFreeLandAlloc(&tract, arena, zones, pref->high, size, pool);
+ if (res == ResOK)
+ goto found;
+ }
+ if (moreZones != zones) {
+ zones = ZoneSetUnion(zones, ZoneSetDiff(arena->freeZones, pref->avoid));
+ res = ArenaFreeLandAlloc(&tract, arena, moreZones, pref->high,
+ size, pool);
+ if (res == ResOK)
+ goto found;
+ }
+ }
+
+ /* Plan D: add every zone that isn't blacklisted. This might mix GC'd
+ * objects with those from other generations, causing the zone check
+ * to give false positives and slowing down the collector. */
+ /* TODO: log an event for this */
+ evenMoreZones = ZoneSetDiff(ZoneSetUNIV, pref->avoid);
+ if (evenMoreZones != moreZones) {
+ res = ArenaFreeLandAlloc(&tract, arena, evenMoreZones, pref->high,
+ size, pool);
+ if (res == ResOK)
+ goto found;
+ }
+
+ /* Last resort: try anywhere. This might put GC'd objects in zones where
+ * common ambiguous bit patterns pin them down, causing the zone check
+ * to give even more false positives permanently, and possibly retaining
+ * garbage indefinitely. */
+ res = ArenaFreeLandAlloc(&tract, arena, ZoneSetUNIV, pref->high, size, pool);
+ if (res == ResOK)
+ goto found;
+
+ /* Uh oh. */
+ return res;
+
+found:
+ *tractReturn = tract;
+ return ResOK;
+}
+
+
+/* C. COPYRIGHT AND LICENSE
+ *
+ * Copyright (C) 2001-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:
+ *
+ * 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 eee7ccb60c9b9f5c470319428f171148ecf202da Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 20 Aug 2015 16:57:33 +0100
Subject: [PATCH 043/337] New function policystarttrace decides whether to
start a trace.
Copied from Perforce
Change: 188154
ServerID: perforce.ravenbrook.com
---
mps/code/mpm.h | 1 +
mps/code/policy.c | 81 +++++++++++++++++++++++++++++++++++
mps/code/trace.c | 107 ++++++++++------------------------------------
3 files changed, 104 insertions(+), 85 deletions(-)
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index 8fa04cc22b6..a0138bee857 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -660,6 +660,7 @@ extern Res ArenaNoExtend(Arena arena, Addr base, Size size);
extern Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
Size size, Pool pool);
+extern Bool PolicyStartTrace(Trace *traceReturn, Arena arena);
/* Locus interface */
diff --git a/mps/code/policy.c b/mps/code/policy.c
index 8a34484eeb4..992057b5ccd 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -112,6 +112,87 @@ Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
}
+/* PolicyStartTrace -- consider starting a trace
+ *
+ * If a trace was started, update *traceReturn and return TRUE.
+ * Otherwise, leave *traceReturn unchanged and return FALSE.
+ */
+
+Bool PolicyStartTrace(Trace *traceReturn, Arena arena)
+{
+ Res res;
+ Trace trace;
+ Size sFoundation, sCondemned, sSurvivors, sConsTrace;
+ double tTracePerScan; /* tTrace/cScan */
+ double dynamicDeferral;
+
+ /* Compute dynamic criterion. See strategy.lisp-machine. */
+ AVER(arena->topGen.mortality >= 0.0);
+ AVER(arena->topGen.mortality <= 1.0);
+ sFoundation = (Size)0; /* condemning everything, only roots @@@@ */
+ /* @@@@ sCondemned should be scannable only */
+ sCondemned = ArenaCommitted(arena) - ArenaSpareCommitted(arena);
+ sSurvivors = (Size)(sCondemned * (1 - arena->topGen.mortality));
+ tTracePerScan = sFoundation + (sSurvivors * (1 + TraceCopyScanRATIO));
+ AVER(TraceWorkFactor >= 0);
+ AVER(sSurvivors + tTracePerScan * TraceWorkFactor <= (double)SizeMAX);
+ sConsTrace = (Size)(sSurvivors + tTracePerScan * TraceWorkFactor);
+ dynamicDeferral = (double)ArenaAvail(arena) - (double)sConsTrace;
+
+ if (dynamicDeferral < 0.0) {
+ /* Start full collection. */
+ res = TraceStartCollectAll(&trace, arena, TraceStartWhyDYNAMICCRITERION);
+ if (res != ResOK)
+ goto failStart;
+ *traceReturn = trace;
+ return TRUE;
+ } else {
+ /* Find the chain most over its capacity. */
+ Ring node, nextNode;
+ double firstTime = 0.0;
+ Chain firstChain = NULL;
+
+ RING_FOR(node, &arena->chainRing, nextNode) {
+ Chain chain = RING_ELT(Chain, chainRing, node);
+ double time;
+
+ AVERT(Chain, chain);
+ time = ChainDeferral(chain);
+ if (time < firstTime) {
+ firstTime = time; firstChain = chain;
+ }
+ }
+
+ /* If one was found, start collection on that chain. */
+ if(firstTime < 0) {
+ double mortality;
+
+ res = TraceCreate(&trace, arena, TraceStartWhyCHAIN_GEN0CAP);
+ AVER(res == ResOK);
+ res = ChainCondemnAuto(&mortality, firstChain, trace);
+ if (res != ResOK) /* should try some other trace, really @@@@ */
+ goto failCondemn;
+ trace->chain = firstChain;
+ ChainStartGC(firstChain, trace);
+ res = TraceStart(trace, mortality, trace->condemned * TraceWorkFactor);
+ /* We don't expect normal GC traces to fail to start. */
+ AVER(res == ResOK);
+ *traceReturn = trace;
+ return TRUE;
+ }
+ } /* (dynamicDeferral > 0.0) */
+ return FALSE;
+
+failCondemn:
+ TraceDestroy(trace);
+ /* This is an unlikely case, but clear the emergency flag so the next attempt
+ starts normally. */
+ ArenaSetEmergency(arena, FALSE);
+failStart:
+ return FALSE;
+}
+
+
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2015 Ravenbrook Limited .
diff --git a/mps/code/trace.c b/mps/code/trace.c
index 7aeb70305c7..b7cb171365b 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -1813,103 +1813,40 @@ Res TraceStartCollectAll(Trace *traceReturn, Arena arena, int why)
}
-/* TracePoll -- Check if there's any tracing work to be done */
+/* 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.
+ */
Size TracePoll(Globals globals)
{
Trace trace;
- Res res;
Arena arena;
- Size scannedSize;
+ Size oldScannedSize, scannedSize;
AVERT(Globals, globals);
arena = GlobalsArena(globals);
- scannedSize = (Size)0;
- if(arena->busyTraces == TraceSetEMPTY) {
- /* If no traces are going on, see if we need to start one. */
- Size sFoundation, sCondemned, sSurvivors, sConsTrace;
- double tTracePerScan; /* tTrace/cScan */
- double dynamicDeferral;
-
- /* Compute dynamic criterion. See strategy.lisp-machine. */
- AVER(arena->topGen.mortality >= 0.0);
- AVER(arena->topGen.mortality <= 1.0);
- sFoundation = (Size)0; /* condemning everything, only roots @@@@ */
- /* @@@@ sCondemned should be scannable only */
- sCondemned = ArenaCommitted(arena) - ArenaSpareCommitted(arena);
- sSurvivors = (Size)(sCondemned * (1 - arena->topGen.mortality));
- tTracePerScan = sFoundation + (sSurvivors * (1 + TraceCopyScanRATIO));
- AVER(TraceWorkFactor >= 0);
- AVER(sSurvivors + tTracePerScan * TraceWorkFactor <= (double)SizeMAX);
- sConsTrace = (Size)(sSurvivors + tTracePerScan * TraceWorkFactor);
- dynamicDeferral = (double)ArenaAvail(arena) - (double)sConsTrace;
-
- if(dynamicDeferral < 0.0) { /* start full GC */
- res = TraceStartCollectAll(&trace, arena, TraceStartWhyDYNAMICCRITERION);
- if(res != ResOK)
- goto failStart;
- scannedSize = traceWorkClock(trace);
- } else { /* Find the nursery most over its capacity. */
- Ring node, nextNode;
- double firstTime = 0.0;
- Chain firstChain = NULL;
-
- RING_FOR(node, &arena->chainRing, nextNode) {
- Chain chain = RING_ELT(Chain, chainRing, node);
- double time;
-
- AVERT(Chain, chain);
- time = ChainDeferral(chain);
- if(time < firstTime) {
- firstTime = time; firstChain = chain;
- }
- }
-
- /* If one was found, start collection on that chain. */
- if(firstTime < 0) {
- double mortality;
-
- res = TraceCreate(&trace, arena, TraceStartWhyCHAIN_GEN0CAP);
- AVER(res == ResOK);
- res = ChainCondemnAuto(&mortality, firstChain, trace);
- if(res != ResOK) /* should try some other trace, really @@@@ */
- goto failCondemn;
- trace->chain = firstChain;
- ChainStartGC(firstChain, trace);
- res = TraceStart(trace, mortality, trace->condemned * TraceWorkFactor);
- /* We don't expect normal GC traces to fail to start. */
- AVER(res == ResOK);
- scannedSize = traceWorkClock(trace);
- }
- } /* (dynamicDeferral > 0.0) */
- } /* (arena->busyTraces == TraceSetEMPTY) */
-
- /* If there is a trace, do one quantum of work. */
- if(arena->busyTraces != TraceSetEMPTY) {
- Size oldScanned;
-
+ if (arena->busyTraces != TraceSetEMPTY) {
trace = ArenaTrace(arena, (TraceId)0);
- AVER(arena->busyTraces == TraceSetSingle(trace));
- oldScanned = traceWorkClock(trace);
- TraceQuantum(trace);
- scannedSize = traceWorkClock(trace) - oldScanned;
- if(trace->state == TraceFINISHED) {
- TraceDestroy(trace);
- /* A trace finished, and hopefully reclaimed some memory, so clear any
- emergency. */
- ArenaSetEmergency(arena, FALSE);
- }
+ } else {
+ /* No traces are running: consider starting one now. */
+ if (!PolicyStartTrace(&trace, arena))
+ return (Size)0;
+ }
+
+ AVER(arena->busyTraces == TraceSetSingle(trace));
+ oldScannedSize = traceWorkClock(trace);
+ TraceQuantum(trace);
+ scannedSize = traceWorkClock(trace) - oldScannedSize;
+ if (trace->state == TraceFINISHED) {
+ TraceDestroy(trace);
+ /* A trace finished, and hopefully reclaimed some memory, so clear any
+ * emergency. */
+ ArenaSetEmergency(arena, FALSE);
}
return scannedSize;
-
-failCondemn:
- TraceDestroy(trace);
- /* This is an unlikely case, but clear the emergency flag so the next attempt
- starts normally. */
- ArenaSetEmergency(arena, FALSE);
-failStart:
- return (Size)0;
}
From b41d6be0e494e7a90b4830eefe338ac6ef24c6db Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 21 Aug 2015 11:01:00 +0100
Subject: [PATCH 044/337] New function policycondemnchain.
Copied from Perforce
Change: 188156
ServerID: perforce.ravenbrook.com
---
mps/code/chain.h | 4 ++-
mps/code/locus.c | 73 +++++------------------------------------------
mps/code/policy.c | 67 ++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 76 insertions(+), 68 deletions(-)
diff --git a/mps/code/chain.h b/mps/code/chain.h
index 7279af2842f..6dddf0f5e2f 100644
--- a/mps/code/chain.h
+++ b/mps/code/chain.h
@@ -75,6 +75,9 @@ typedef struct mps_chain_s {
} ChainStruct;
+extern Bool GenDescCheck(GenDesc gen);
+extern Size GenDescNewSize(GenDesc gen);
+extern Size GenDescTotalSize(GenDesc gen);
extern Res GenDescDescribe(GenDesc gen, mps_lib_FILE *stream, Count depth);
extern Res ChainCreate(Chain *chainReturn, Arena arena, size_t genCount,
@@ -83,7 +86,6 @@ extern void ChainDestroy(Chain chain);
extern Bool ChainCheck(Chain chain);
extern double ChainDeferral(Chain chain);
-extern Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace);
extern void ChainStartGC(Chain chain, Trace trace);
extern void ChainEndGC(Chain chain, Trace trace);
extern size_t ChainGens(Chain chain);
diff --git a/mps/code/locus.c b/mps/code/locus.c
index d6df60633cb..e17ec3137c1 100644
--- a/mps/code/locus.c
+++ b/mps/code/locus.c
@@ -103,7 +103,7 @@ Res LocusPrefDescribe(LocusPref pref, mps_lib_FILE *stream, Count depth)
/* GenDescCheck -- check a GenDesc */
ATTRIBUTE_UNUSED
-static Bool GenDescCheck(GenDesc gen)
+Bool GenDescCheck(GenDesc gen)
{
CHECKS(GenDesc, gen);
/* nothing to check for zones */
@@ -117,11 +117,13 @@ static Bool GenDescCheck(GenDesc gen)
/* GenDescNewSize -- return effective size of generation */
-static Size GenDescNewSize(GenDesc gen)
+Size GenDescNewSize(GenDesc gen)
{
Size size = 0;
Ring node, nextNode;
+ AVERT(GenDesc, gen);
+
RING_FOR(node, &gen->locusRing, nextNode) {
PoolGen pgen = RING_ELT(PoolGen, genRing, node);
AVERT(PoolGen, pgen);
@@ -133,11 +135,13 @@ static Size GenDescNewSize(GenDesc gen)
/* GenDescTotalSize -- return total size of generation */
-static Size GenDescTotalSize(GenDesc gen)
+Size GenDescTotalSize(GenDesc gen)
{
Size size = 0;
Ring node, nextNode;
+ AVERT(GenDesc, gen);
+
RING_FOR(node, &gen->locusRing, nextNode) {
PoolGen pgen = RING_ELT(PoolGen, genRing, node);
AVERT(PoolGen, pgen);
@@ -381,69 +385,6 @@ double ChainDeferral(Chain chain)
}
-/* ChainCondemnAuto -- condemn approriate parts of this chain
- *
- * This is only called if ChainDeferral returned a value sufficiently
- * low that the tracer decided to start the collection. (Usually
- * such values are less than zero; see )
- */
-Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace)
-{
- Res res;
- size_t topCondemnedGen, i;
- GenDesc gen;
- ZoneSet condemnedSet = ZoneSetEMPTY;
- Size condemnedSize = 0, survivorSize = 0, genNewSize, genTotalSize;
-
- AVERT(Chain, chain);
- AVERT(Trace, trace);
-
- /* Find the highest generation that's over capacity. We will condemn
- * this and all lower generations in the chain. */
- topCondemnedGen = chain->genCount;
- for (;;) {
- /* It's an error to call this function unless some generation is
- * over capacity as reported by ChainDeferral. */
- AVER(topCondemnedGen > 0);
- if (topCondemnedGen == 0)
- return ResFAIL;
- -- topCondemnedGen;
- gen = &chain->gens[topCondemnedGen];
- AVERT(GenDesc, gen);
- genNewSize = GenDescNewSize(gen);
- if (genNewSize >= gen->capacity * (Size)1024)
- break;
- }
-
- /* At this point, we've decided to condemn topCondemnedGen and all
- * lower generations. */
- for (i = 0; i <= topCondemnedGen; ++i) {
- gen = &chain->gens[i];
- AVERT(GenDesc, gen);
- condemnedSet = ZoneSetUnion(condemnedSet, gen->zones);
- genTotalSize = GenDescTotalSize(gen);
- genNewSize = GenDescNewSize(gen);
- condemnedSize += genTotalSize;
- survivorSize += (Size)(genNewSize * (1.0 - gen->mortality))
- /* predict survivors will survive again */
- + (genTotalSize - genNewSize);
- }
-
- AVER(condemnedSet != ZoneSetEMPTY || condemnedSize == 0);
- EVENT3(ChainCondemnAuto, chain, topCondemnedGen, chain->genCount);
-
- /* Condemn everything in these zones. */
- if (condemnedSet != ZoneSetEMPTY) {
- res = TraceCondemnZones(trace, condemnedSet);
- if (res != ResOK)
- return res;
- }
-
- *mortalityReturn = 1.0 - (double)survivorSize / condemnedSize;
- return ResOK;
-}
-
-
/* ChainStartGC -- called to notify start of GC for this chain */
void ChainStartGC(Chain chain, Trace trace)
diff --git a/mps/code/policy.c b/mps/code/policy.c
index 992057b5ccd..ceb5d74368d 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -9,6 +9,7 @@
* .sources: .
*/
+#include "chain.h"
#include "mpm.h"
SRCID(policy, "$Id$");
@@ -112,6 +113,70 @@ Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
}
+/* policyCondemnChain -- condemn approriate parts of this chain
+ *
+ * This is only called if ChainDeferral returned a value sufficiently
+ * low that the tracer decided to start the collection. (Usually
+ * such values are less than zero; see )
+ */
+
+static Res policyCondemnChain(double *mortalityReturn, Chain chain, Trace trace)
+{
+ Res res;
+ size_t topCondemnedGen, i;
+ GenDesc gen;
+ ZoneSet condemnedSet = ZoneSetEMPTY;
+ Size condemnedSize = 0, survivorSize = 0, genNewSize, genTotalSize;
+
+ AVERT(Chain, chain);
+ AVERT(Trace, trace);
+
+ /* Find the highest generation that's over capacity. We will condemn
+ * this and all lower generations in the chain. */
+ topCondemnedGen = chain->genCount;
+ for (;;) {
+ /* It's an error to call this function unless some generation is
+ * over capacity as reported by ChainDeferral. */
+ AVER(topCondemnedGen > 0);
+ if (topCondemnedGen == 0)
+ return ResFAIL;
+ -- topCondemnedGen;
+ gen = &chain->gens[topCondemnedGen];
+ AVERT(GenDesc, gen);
+ genNewSize = GenDescNewSize(gen);
+ if (genNewSize >= gen->capacity * (Size)1024)
+ break;
+ }
+
+ /* At this point, we've decided to condemn topCondemnedGen and all
+ * lower generations. */
+ for (i = 0; i <= topCondemnedGen; ++i) {
+ gen = &chain->gens[i];
+ AVERT(GenDesc, gen);
+ condemnedSet = ZoneSetUnion(condemnedSet, gen->zones);
+ genTotalSize = GenDescTotalSize(gen);
+ genNewSize = GenDescNewSize(gen);
+ condemnedSize += genTotalSize;
+ survivorSize += (Size)(genNewSize * (1.0 - gen->mortality))
+ /* predict survivors will survive again */
+ + (genTotalSize - genNewSize);
+ }
+
+ AVER(condemnedSet != ZoneSetEMPTY || condemnedSize == 0);
+ EVENT3(ChainCondemnAuto, chain, topCondemnedGen, chain->genCount);
+
+ /* Condemn everything in these zones. */
+ if (condemnedSet != ZoneSetEMPTY) {
+ res = TraceCondemnZones(trace, condemnedSet);
+ if (res != ResOK)
+ return res;
+ }
+
+ *mortalityReturn = 1.0 - (double)survivorSize / condemnedSize;
+ return ResOK;
+}
+
+
/* PolicyStartTrace -- consider starting a trace
*
* If a trace was started, update *traceReturn and return TRUE.
@@ -169,7 +234,7 @@ Bool PolicyStartTrace(Trace *traceReturn, Arena arena)
res = TraceCreate(&trace, arena, TraceStartWhyCHAIN_GEN0CAP);
AVER(res == ResOK);
- res = ChainCondemnAuto(&mortality, firstChain, trace);
+ res = policyCondemnChain(&mortality, firstChain, trace);
if (res != ResOK) /* should try some other trace, really @@@@ */
goto failCondemn;
trace->chain = firstChain;
From 1710a3bb97f3158b57acc330e3e6b3b4edc92ea6 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 21 Aug 2015 11:14:27 +0100
Subject: [PATCH 045/337] Prefer avert(type, value) to aver(typecheck(value)).
Copied from Perforce
Change: 188157
ServerID: perforce.ravenbrook.com
---
mps/code/cbs.c | 6 +++---
mps/code/land.c | 16 ++++++++--------
mps/code/seg.c | 14 +++++++-------
3 files changed, 18 insertions(+), 18 deletions(-)
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/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/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.
*
From 38f07daa3d486110b20f4a8f89e76c0021d105bb Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 21 Aug 2015 11:20:20 +0100
Subject: [PATCH 046/337] Fix broken link to design/thread-safety
Copied from Perforce
Change: 188158
ServerID: perforce.ravenbrook.com
---
mps/code/mpsi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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:
*
From d506458eea8b5346d4b11cfa02cbbb0b7af41749 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 21 Aug 2015 15:27:14 +0100
Subject: [PATCH 047/337] New function policycollectiontime estimates the time
needed to collect the arena. mysterious constants are given names and moved
to config.h.
Copied from Perforce
Change: 188160
ServerID: perforce.ravenbrook.com
---
mps/code/arena.c | 18 ++++++++++++++++++
mps/code/config.h | 35 +++++++++++++++++++++++++++++------
mps/code/global.c | 26 +++++++-------------------
mps/code/mpm.h | 4 +++-
mps/code/policy.c | 23 +++++++++++++++++++++++
5 files changed, 80 insertions(+), 26 deletions(-)
diff --git a/mps/code/arena.c b/mps/code/arena.c
index 023d4efd1a8..3a501a747ad 100644
--- a/mps/code/arena.c
+++ b/mps/code/arena.c
@@ -1272,6 +1272,24 @@ Size ArenaAvail(Arena arena)
}
+/* ArenaCollectable -- return estimate of collectable memory in arena */
+
+Size ArenaCollectable(Arena arena)
+{
+ /* Conservative estimate -- see job003929. */
+ return ArenaCommitted(arena) - ArenaSpareCommitted(arena);
+}
+
+
+/* ArenaScannable -- return estimate of scannable memory in arena */
+
+Size ArenaScannable(Arena arena)
+{
+ /* Conservative estimate -- see job003929. */
+ return ArenaCommitted(arena) - ArenaSpareCommitted(arena);
+}
+
+
/* ArenaExtend -- Add a new chunk in the arena */
Res ArenaExtend(Arena arena, Addr base, Size size)
diff --git a/mps/code/config.h b/mps/code/config.h
index 8fbd251a220..589fbc20c6b 100644
--- a/mps/code/config.h
+++ b/mps/code/config.h
@@ -392,22 +392,45 @@
#define MVT_FRAG_LIMIT_DEFAULT 30
-/* Arena Configuration -- see
- *
- * .client.seg-size: ARENA_CLIENT_GRAIN_SIZE is the minimum size, in
- * bytes, of a grain in the client arena. It's set at 8192 with no
- * particular justification.
- */
+/* Arena Configuration -- see */
#define ArenaPollALLOCTIME (65536.0)
#define ARENA_ZONESHIFT ((Shift)20)
+/* .client.seg-size: ARENA_CLIENT_GRAIN_SIZE is the minimum size, in
+ * bytes, of a grain in the client arena. It's set at 8192 with no
+ * particular justification. */
+
#define ARENA_CLIENT_GRAIN_SIZE ((Size)8192)
#define ARENA_DEFAULT_ZONED TRUE
#define ArenaDefaultZONESET (ZoneSetUNIV << (MPS_WORD_WIDTH / 2))
+
+/* ARENA_MINIMUM_COLLECTABLE_SIZE is the minimum size (in bytes) of
+ * collectable memory that might be considered worthwhile to run a
+ * full garbage collection. */
+
+#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. */
+
+#define ARENA_DEFAULT_COLLECTION_RATE (25000000.0)
+
+/* ARENA_DEFAULT_COLLECTION_OVERHEAD is an estimate of the MPS's
+ * collection overhead (in seconds), for use in the case where there
+ * isn't enough data to use a measured value. */
+
+#define ARENA_DEFAULT_COLLECTION_OVERHEAD (0.1)
+
+/* ARENA_MAX_COLLECT_FRACTION is the maximum fraction of runtime that
+ * ArenaStep is prepared to spend in collections. */
+
+#define ARENA_MAX_COLLECT_FRACTION (0.1)
+
/* TODO: This is left over from before the branch/2014-01-29/mps-chain-zones
and 2014-01-17/cbs-tract-alloc reformed allocation, and may now be doing
more harm than good. Experiment with setting to ZoneSetUNIV. */
diff --git a/mps/code/global.c b/mps/code/global.c
index 05a941b1c4f..39be9279d6c 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -765,36 +765,24 @@ static Bool arenaShouldCollectWorld(Arena arena,
Clock now,
Clock clocks_per_sec)
{
- double scanRate;
- Size arenaSize;
- double arenaScanTime;
- double sinceLastWorldCollect;
-
/* 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 */
- arenaSize = ArenaCommitted(arena) - ArenaSpareCommitted(arena);
- if (arenaSize > 1000000) {
+ Size collectableSize = ArenaCollectable(arena);
+ if (collectableSize > ARENA_MINIMUM_COLLECTABLE_SIZE) {
/* how long would it take to collect the world? */
- if ((arena->tracedSize > 1000000.0) &&
- (arena->tracedTime > 1.0))
- scanRate = arena->tracedSize / arena->tracedTime;
- else
- scanRate = 25000000.0; /* a reasonable default. */
- arenaScanTime = arenaSize / scanRate;
- arenaScanTime += 0.1; /* for overheads. */
+ double collectionTime = PolicyCollectionTime(arena);
/* how long since we last collected the world? */
- sinceLastWorldCollect = ((now - arena->lastWorldCollect) /
- (double) clocks_per_sec);
+ 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 > arenaScanTime) &&
- sinceLastWorldCollect > arenaScanTime * 10.0) {
+ if ((interval * multiplier > collectionTime) &&
+ sinceLastWorldCollect > collectionTime / ARENA_MAX_COLLECT_FRACTION)
return TRUE;
- }
}
}
}
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index a0138bee857..2d23d1e316e 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -623,8 +623,9 @@ extern void ArenaSetSpareCommitLimit(Arena arena, Size limit);
extern Size ArenaNoPurgeSpare(Arena arena, Size size);
extern Res ArenaNoGrow(Arena arena, LocusPref pref, Size size);
-extern double ArenaMutatorAllocSize(Arena arena);
extern Size ArenaAvail(Arena arena);
+extern Size ArenaCollectable(Arena arena);
+extern Size ArenaScannable(Arena arena);
extern Res ArenaExtend(Arena, Addr base, Size size);
@@ -661,6 +662,7 @@ extern Res ArenaNoExtend(Arena arena, Addr base, Size size);
extern Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
Size size, Pool pool);
extern Bool PolicyStartTrace(Trace *traceReturn, Arena arena);
+extern double PolicyCollectionTime(Arena arena);
/* Locus interface */
diff --git a/mps/code/policy.c b/mps/code/policy.c
index ceb5d74368d..b33dc85193d 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -258,6 +258,29 @@ Bool PolicyStartTrace(Trace *traceReturn, Arena arena)
}
+/* PolicyCollectionTime -- estimate time to collect the world, in seconds */
+
+double PolicyCollectionTime(Arena arena)
+{
+ Size collectableSize;
+ double collectionRate;
+ double collectionTime;
+
+ AVERT(Arena, arena);
+
+ collectableSize = ArenaCollectable(arena);
+ if (arena->tracedSize >= ARENA_MINIMUM_COLLECTABLE_SIZE
+ && arena->tracedTime > 0)
+ collectionRate = arena->tracedSize / arena->tracedTime;
+ else
+ collectionRate = ARENA_DEFAULT_COLLECTION_RATE;
+ collectionTime = collectableSize / collectionRate;
+ collectionTime += ARENA_DEFAULT_COLLECTION_OVERHEAD;
+
+ return collectionTime;
+}
+
+
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2015 Ravenbrook Limited .
From 9dd49aa48e629e6fbdbf2347f2b7acf8ae81bfe1 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 25 Aug 2015 13:27:17 +0100
Subject: [PATCH 048/337] New functions policypoll and policypollagain.
Update design.strategy.
Copied from Perforce
Change: 188165
ServerID: perforce.ravenbrook.com
---
mps/code/global.c | 23 ++++--------
mps/code/mpm.h | 2 ++
mps/code/policy.c | 60 ++++++++++++++++++++++++++++++-
mps/design/strategy.txt | 79 ++++++++++++++++++++++++++++++++++++++---
4 files changed, 142 insertions(+), 22 deletions(-)
diff --git a/mps/code/global.c b/mps/code/global.c
index 39be9279d6c..cd072951e87 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -706,7 +706,6 @@ void (ArenaPoll)(Globals globals)
Clock start;
Count quanta;
Size tracedSize;
- double nextPollThreshold = 0.0;
AVERT(Globals, globals);
@@ -714,42 +713,32 @@ void (ArenaPoll)(Globals globals)
return;
if (globals->insidePoll)
return;
- if(globals->fillMutatorSize < globals->pollThreshold)
+ arena = GlobalsArena(globals);
+ if (!PolicyPoll(arena))
return;
globals->insidePoll = TRUE;
/* fillMutatorSize has advanced; call TracePoll enough to catch up. */
- arena = GlobalsArena(globals);
start = ClockNow();
quanta = 0;
EVENT3(ArenaPoll, arena, start, 0);
- while(globals->pollThreshold <= globals->fillMutatorSize) {
+ do {
tracedSize = TracePoll(globals);
-
- if(tracedSize == 0) {
- /* No work to do. Sleep until NOW + a bit. */
- nextPollThreshold = globals->fillMutatorSize + ArenaPollALLOCTIME;
- } else {
- /* We did one quantum of work; consume one unit of 'time'. */
+ if (tracedSize > 0) {
quanta += 1;
arena->tracedSize += tracedSize;
- nextPollThreshold = globals->pollThreshold + ArenaPollALLOCTIME;
}
-
- /* Advance pollThreshold; check: enough precision? */
- AVER(nextPollThreshold > globals->pollThreshold);
- globals->pollThreshold = nextPollThreshold;
- }
+ } 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();
}
- AVER(globals->fillMutatorSize < globals->pollThreshold);
+ AVER(!PolicyPoll(arena));
EVENT3(ArenaPoll, arena, start, quanta);
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index 2d23d1e316e..78a572e6cde 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -663,6 +663,8 @@ extern Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
Size size, Pool pool);
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);
/* Locus interface */
diff --git a/mps/code/policy.c b/mps/code/policy.c
index b33dc85193d..87a8ed360c5 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -19,6 +19,14 @@ SRCID(policy, "$Id$");
*
* This is the code responsible for making decisions about where to allocate
* memory.
+ *
+ * pref describes the address space preferences for the allocation.
+ * size is the amount of memory requested to be allocated, in bytes.
+ * pool is the pool that is requresting the memory.
+ *
+ * If successful, update *tractReturn to point to the initial tract of
+ * the allocated memory and return ResOK. Otherwise return a result
+ * code describing the problem.
*/
Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
@@ -32,6 +40,7 @@ Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
AVERT(Arena, arena);
AVERT(LocusPref, pref);
AVER(size > (Size)0);
+ AVER(SizeIsAligned(size, ArenaGrainSize(arena)));
AVERT(Pool, pool);
AVER(arena == PoolArena(pool));
@@ -45,7 +54,7 @@ Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
}
}
- /* Plan A: allocate from the free Land in the requested zones */
+ /* Plan A: allocate from the free land in the requested zones */
zones = ZoneSetDiff(pref->zones, pref->avoid);
if (zones != ZoneSetEMPTY) {
res = ArenaFreeLandAlloc(&tract, arena, zones, pref->high, size, pool);
@@ -281,6 +290,55 @@ double PolicyCollectionTime(Arena arena)
}
+/* PolicyPoll -- do some tracing work?
+ *
+ * Return TRUE if the MPS should do some tracing work; FALSE if it
+ * should return to the mutator.
+ */
+
+Bool PolicyPoll(Arena arena)
+{
+ Globals globals;
+ AVERT(Arena, arena);
+ globals = ArenaGlobals(arena);
+ return globals->pollThreshold <= globals->fillMutatorSize;
+}
+
+
+/* PolicyPollAgain -- do another unit of work?
+ *
+ * Return TRUE if the MPS should do another unit of work; FALSE if it
+ * 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.
+ */
+
+Bool PolicyPollAgain(Arena arena, Clock start, Size tracedSize)
+{
+ Globals globals;
+ double nextPollThreshold;
+
+ AVERT(Arena, arena);
+ globals = ArenaGlobals(arena);
+ UNUSED(start);
+
+ if (tracedSize == 0) {
+ /* No work was done. Sleep until NOW + a bit. */
+ nextPollThreshold = globals->fillMutatorSize + ArenaPollALLOCTIME;
+ } else {
+ /* We did one quantum of work; consume one unit of 'time'. */
+ nextPollThreshold = globals->pollThreshold + ArenaPollALLOCTIME;
+ }
+
+ /* Advance pollThreshold; check: enough precision? */
+ AVER(nextPollThreshold > globals->pollThreshold);
+ globals->pollThreshold = nextPollThreshold;
+
+ return PolicyPoll(arena);
+}
+
+
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2015 Ravenbrook Limited .
diff --git a/mps/design/strategy.txt b/mps/design/strategy.txt
index 6f3028455bd..2a50b4f25f0 100644
--- a/mps/design/strategy.txt
+++ b/mps/design/strategy.txt
@@ -430,14 +430,85 @@ other uses of that:
from ``poolGen.newSize`` and new is set to FALSE.
-Starting a Trace
+Policy
+------
+
+_`.policy`: Functions that make decisions about what action to take
+are collected into the policy module (policy.c). The purpose of doing
+so is to make it easier to understand this set of decisions and how
+they interact, and to make it easier to maintain and update the policy.
+
+
+Assignment of zones
+...................
+
+``Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref, Size size, Pool pool)``
+
+_`.policy.alloc`: Allocate ``size`` bytes of memory on behalf of
+``pool``, based on the preferences described by ``pref``. If
+successful, update ``*tractReturn`` to point to the first tract in the
+allocated memory and return ``ResOK``. Otherwise, return a result code
+describing the problem, for example ``ResCOMMIT_LIMIT``.
+
+_`.policy.alloc.plan`: This tries various plans in succession until
+one succeeds. First, it tries to allocate from the arena's free land
+in the requested zones. Second, it tries allocating from free zones.
+Third, it tries extending the arena and then trying the first two
+plans again. Fourth, it tries allocating from any zone that is not
+blacklisted. Fifth, it tries allocating from any zone at all.
+
+_`.policy.alloc.issue`: This plan performs poorly under stress. See
+for example job003898_.
+
+.. _job003898: http://www.ravenbrook.com/project/mps/issue/job003898/
+
+
+
+Starting a trace
................
-TODO: Why do we start a trace? How do we choose what to condemn?
+
+``Bool PolicyStartTrace(Trace *traceReturn, Arena arena)``
+
+_`.policy.start`: Consider starting a trace. If a trace was started,
+update ``*traceReturn`` to point to the trace and return TRUE.
+Otherwise, leave ``*traceReturn`` unchanged and return FALSE.
+
+_`.policy.start.impl`: This uses the "Lisp Machine" strategy, which
+tries to schedule collections so that the collector just keeps pace
+with the mutator: that is, it starts a collection when the predicted
+completion time of the collection is around the time when the mutator
+is predicted to reach the current memory limit. See [Pirinen]_.
-Trace Progress
+Trace progress
..............
-TODO: When do we do some tracing work? How much tracing work do we do?
+
+``Bool PolicyPoll(Arena arena)``
+
+_`.policy.poll`: Return TRUE if the MPS should do some tracing work;
+FALSE if it should return to the mutator.
+
+``Bool PolicyPollAgain(Arena arena, Clock start, Size tracedSize)``
+
+_`.policy.poll.again`: Return TRUE if the MPS should do another unit
+of work; FALSE if it 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()``.
+
+_`.policy.poll.impl`: The implementation balances collection work
+against mutator allocation so that there is approximately one call to
+``TraceQuantum()`` for every ``ArenaPollALLOCTIME`` bytes of
+allocation.
+
+
+References
+----------
+
+.. [Pirinen]
+ "The Lisp Machine Strategy";
+ Pekka Pirinin;
+ 1998-04-27;
+
Document History
From af993a09d2ec92bca7729fc64c1a1309b84cc8be Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 25 Aug 2015 13:39:11 +0100
Subject: [PATCH 049/337] Chaincondemnauto is now policycondemnchain.
Copied from Perforce
Change: 188167
ServerID: perforce.ravenbrook.com
---
mps/design/strategy.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mps/design/strategy.txt b/mps/design/strategy.txt
index 2a50b4f25f0..4e641148f52 100644
--- a/mps/design/strategy.txt
+++ b/mps/design/strategy.txt
@@ -153,7 +153,7 @@ Collections in the MPS start in one of two ways:
indicates if the chain needs collecting, and if so, how urgent it
is to collect that chain. The most urgent chain in need of
collection (if any) is then condemned by calling
- ``ChainCondemnAuto()``.
+ ``policyCondemnChain()``.
This function chooses the set of generations to condemn, computes
the zoneset corresponding to the union those generations, and
@@ -220,7 +220,7 @@ _`.accounting.poll`: ``ChainDeferral()`` uses the *new size* of each
generation to determine which generations in the chain are over
capacity and so might need to be collected via ``TracePoll()``.
-_`.accounting.condemn`: ``ChainCondemnAuto()`` uses the *new size* of
+_`.accounting.condemn`: ``policyCondemnChain()`` uses the *new size* of
each generation to determine which generations in the chain will be
collected; it also uses the *total size* of the generation to compute
the mortality.
From 517ffb934462f27498ea60a59e261bc0c278cd44 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 25 Aug 2015 13:50:19 +0100
Subject: [PATCH 050/337] Condition >= 1.0 is needed to ensure division can't
overflow.
Copied from Perforce
Change: 188170
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 87a8ed360c5..ad4876747a9 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -278,8 +278,10 @@ double PolicyCollectionTime(Arena arena)
AVERT(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 > 0)
+ && arena->tracedTime >= 1.0)
collectionRate = arena->tracedSize / arena->tracedTime;
else
collectionRate = ARENA_DEFAULT_COLLECTION_RATE;
From b0e9c660940a8a42f4aac0df6b60ed44f514b345 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 25 Aug 2015 15:03:35 +0100
Subject: [PATCH 051/337] Use sizeisarenagrains macro.
Copied from Perforce
Change: 188172
ServerID: perforce.ravenbrook.com
---
mps/code/policy.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mps/code/policy.c b/mps/code/policy.c
index ad4876747a9..64611a31d11 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -40,7 +40,7 @@ Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
AVERT(Arena, arena);
AVERT(LocusPref, pref);
AVER(size > (Size)0);
- AVER(SizeIsAligned(size, ArenaGrainSize(arena)));
+ AVER(SizeIsArenaGrains(size, arena));
AVERT(Pool, pool);
AVER(arena == PoolArena(pool));
From c7a1d9891ef84580245d64cb3d801f909737b2c4 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 25 Aug 2015 19:28:43 +0100
Subject: [PATCH 052/337] Branching master to branch/2015-08-25/tradeoff.
Copied from Perforce
Change: 188173
ServerID: perforce.ravenbrook.com
From ce822c30f90681d6bddfc04bd0834805de2d8f78 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Wed, 26 Aug 2015 12:31:03 +0100
Subject: [PATCH 053/337] Keyword argument mps_key_rank is optional when
creating an allocation point for an snc pool.
Copied from Perforce
Change: 188178
ServerID: perforce.ravenbrook.com
---
mps/manual/source/pool/snc.rst | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/mps/manual/source/pool/snc.rst b/mps/manual/source/pool/snc.rst
index 49a43fe37ab..1138bf5375b 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::
From 1b58d72cf9fa9b69e863df96e3c00169d5c89758 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 1 Sep 2015 13:05:33 +0100
Subject: [PATCH 054/337] Correct rest syntax for bulleted list.
Copied from Perforce
Change: 188192
ServerID: perforce.ravenbrook.com
---
mps/manual/source/pool/snc.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mps/manual/source/pool/snc.rst b/mps/manual/source/pool/snc.rst
index 1138bf5375b..d39a392c614 100644
--- a/mps/manual/source/pool/snc.rst
+++ b/mps/manual/source/pool/snc.rst
@@ -115,8 +115,8 @@ SNC interface
:c:func:`mps_ap_create_k` accepts one optional keyword argument:
* :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.
+ :c:func:`mps_rank_exact`) specifies the :term:`rank` of references
+ in objects allocated on this allocation point.
For example::
From 01bdf07d1a19519529c5faf29d3edbe8c01cbc4e Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 1 Sep 2015 13:06:05 +0100
Subject: [PATCH 055/337] Add note about choice of base/client pointer
representation.
Copied from Perforce
Change: 188193
ServerID: perforce.ravenbrook.com
---
mps/manual/source/topic/format.rst | 14 ++++++++++++++
1 file changed, 14 insertions(+)
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
From eab8b05a85c96f42253854a5b28b8de723be792b Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 1 Sep 2015 14:00:44 +0100
Subject: [PATCH 056/337] Design.mps.bootstrap
Copied from Perforce
Change: 188195
ServerID: perforce.ravenbrook.com
---
mps/design/bootstrap.txt | 127 +++++++++++++++++++++++++++++
mps/design/index.txt | 2 +
mps/manual/source/design/index.rst | 1 +
3 files changed, 130 insertions(+)
create mode 100644 mps/design/bootstrap.txt
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/index.txt b/mps/design/index.txt
index 9f4abf7b4f4..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
@@ -122,6 +123,7 @@ writef_ The WriteF function
.. _an: an
.. _arena: arena
.. _arenavm: arenavm
+.. _bootstrap: bootstrap
.. _bt: bt
.. _buffer: buffer
.. _cbs: cbs
diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst
index 907c9986bb1..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
From 9a303f6935ad9d53c94a49a470ce7d79ebe59006 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Wed, 2 Sep 2015 10:50:00 +0100
Subject: [PATCH 057/337] Refactor tracequantum into tracepoll and
traceadvance. (tracequantum was formerly called from arenapark, but that
doesn't care about the quantum size.)
Copied from Perforce
Change: 188198
ServerID: perforce.ravenbrook.com
---
mps/code/mpm.h | 2 +-
mps/code/trace.c | 82 ++++++++++++++++++++++-----------------------
mps/code/traceanc.c | 4 +--
3 files changed, 44 insertions(+), 44 deletions(-)
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index 78a572e6cde..6c0978d0dba 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -403,7 +403,7 @@ extern Size TracePoll(Globals globals);
extern Rank TraceRankForAccess(Arena arena, Seg seg);
extern void TraceSegAccess(Arena arena, Seg seg, AccessSet mode);
-extern void TraceQuantum(Trace trace);
+extern void TraceAdvance(Trace trace);
extern Res TraceStartCollectAll(Trace *traceReturn, Arena arena, int why);
extern Res TraceDescribe(Trace trace, mps_lib_FILE *stream, Count depth);
diff --git a/mps/code/trace.c b/mps/code/trace.c
index b7cb171365b..005cee87fb2 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -1714,56 +1714,45 @@ 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. */
+/* TraceAdvance -- progress a trace by one step */
-#define traceWorkClock(trace) ((trace)->segScanSize + (trace)->rootScanSize)
-
-
-/* TraceQuantum -- progresses a trace by one quantum */
-
-void TraceQuantum(Trace trace)
+void TraceAdvance(Trace trace)
{
- Size pollEnd;
Arena arena;
AVERT(Trace, trace);
arena = trace->arena;
- pollEnd = traceWorkClock(trace) + trace->rate;
- do {
- switch(trace->state) {
- case TraceUNFLIPPED:
- /* all traces are flipped in TraceStart at the moment */
- NOTREACHED;
- break;
- case TraceFLIPPED: {
- Seg seg;
- Rank rank;
+ switch (trace->state) {
+ case TraceUNFLIPPED:
+ /* all traces are flipped in TraceStart at the moment */
+ NOTREACHED;
+ break;
+ case TraceFLIPPED: {
+ Seg seg;
+ Rank rank;
- if(traceFindGrey(&seg, &rank, arena, trace->ti)) {
- Res res;
- res = traceScanSeg(TraceSetSingle(trace), rank, arena, seg);
- /* Allocation failures should be handled by emergency mode, and we
- don't expect any other error in a normal GC trace. */
- AVER(res == ResOK);
- } else {
- trace->state = TraceRECLAIM;
- }
- break;
- }
- case TraceRECLAIM:
- traceReclaim(trace);
- break;
- default:
- NOTREACHED;
- break;
+ if (traceFindGrey(&seg, &rank, arena, trace->ti)) {
+ Res res;
+ res = traceScanSeg(TraceSetSingle(trace), rank, arena, seg);
+ /* Allocation failures should be handled by emergency mode, and we
+ * don't expect any other error in a normal GC trace. */
+ AVER(res == ResOK);
+ } else {
+ trace->state = TraceRECLAIM;
}
- } while(trace->state != TraceFINISHED
- && (ArenaEmergency(arena) || traceWorkClock(trace) < pollEnd));
+ break;
+ }
+ case TraceRECLAIM:
+ traceReclaim(trace);
+ break;
+ default:
+ NOTREACHED;
+ break;
+ }
}
+
/* TraceStartCollectAll: start a trace which condemns everything in
* the arena.
*
@@ -1813,6 +1802,13 @@ 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
@@ -1823,7 +1819,7 @@ Size TracePoll(Globals globals)
{
Trace trace;
Arena arena;
- Size oldScannedSize, scannedSize;
+ Size oldScannedSize, scannedSize, pollEnd;
AVERT(Globals, globals);
arena = GlobalsArena(globals);
@@ -1838,7 +1834,11 @@ Size TracePoll(Globals globals)
AVER(arena->busyTraces == TraceSetSingle(trace));
oldScannedSize = traceWorkClock(trace);
- TraceQuantum(trace);
+ pollEnd = oldScannedSize + trace->rate;
+ do {
+ TraceAdvance(trace);
+ } while (trace->state != TraceFINISHED
+ && (ArenaEmergency(arena) || traceWorkClock(trace) < pollEnd));
scannedSize = traceWorkClock(trace) - oldScannedSize;
if (trace->state == TraceFINISHED) {
TraceDestroy(trace);
diff --git a/mps/code/traceanc.c b/mps/code/traceanc.c
index ede8d012fe8..c57500c0b65 100644
--- a/mps/code/traceanc.c
+++ b/mps/code/traceanc.c
@@ -579,9 +579,9 @@ void ArenaPark(Globals globals)
globals->clamped = TRUE;
while(arena->busyTraces != TraceSetEMPTY) {
- /* Poll active traces to make progress. */
+ /* Advance all active traces. */
TRACE_SET_ITER(ti, trace, arena->busyTraces, arena)
- TraceQuantum(trace);
+ TraceAdvance(trace);
if(trace->state == TraceFINISHED) {
TraceDestroy(trace);
}
From 465741d8923fb04fb67b46c1644a97e5524c770e Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Wed, 2 Sep 2015 10:53:44 +0100
Subject: [PATCH 058/337] Update design.
Copied from Perforce
Change: 188199
ServerID: perforce.ravenbrook.com
---
mps/design/strategy.txt | 3 +--
mps/design/trace.txt | 8 ++++----
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/mps/design/strategy.txt b/mps/design/strategy.txt
index 4e641148f52..f96aaae17cb 100644
--- a/mps/design/strategy.txt
+++ b/mps/design/strategy.txt
@@ -497,8 +497,7 @@ work done by the last call to ``TracePoll()``.
_`.policy.poll.impl`: The implementation balances collection work
against mutator allocation so that there is approximately one call to
-``TraceQuantum()`` for every ``ArenaPollALLOCTIME`` bytes of
-allocation.
+``TracePoll()`` for every ``ArenaPollALLOCTIME`` bytes of allocation.
References
diff --git a/mps/design/trace.txt b/mps/design/trace.txt
index 76ed0fa954c..236a0cae5d9 100644
--- a/mps/design/trace.txt
+++ b/mps/design/trace.txt
@@ -201,9 +201,9 @@ Some segments get condemned (made white).
- Immediately calls ``traceFlip`` which flips the trace and moves
it into state ``TraceFLIPPED``.
-Whilst a trace is alive every so often its ``traceQuantum`` method
-gets invoked (via ``TracePoll()``) in order to do a quantum of tracing
-work. ``traceQuantum`` is responsible for ticking through the trace's
+Whilst a trace is alive every so often its ``TraceAdvance()`` method
+gets invoked (via ``TracePoll()``) in order to do a step of tracing
+work. ``TraceAdvance()`` is responsible for ticking through the trace's
top-level state machine. Most of the interesting work, the tracing,
happens in the ``TraceFLIPPED`` state.
@@ -217,7 +217,7 @@ in this state; all traces are immediately flipped to be in the
Once the trace is in the ``TraceFINISHED`` state it performs no more
work and it can be safely destroyed. Generally the callers of
-``traceQuantum`` will destroy the trace.
+``TraceAdvance()`` will destroy the trace.
Making progress: scanning grey segments
From 3b0e0c2aa5f6305f6d8899ed933245e077a5704b Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Wed, 2 Sep 2015 21:55:24 +0100
Subject: [PATCH 059/337] 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 e131ab2c8b35f1c1524675a94c4335057d08499c Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 10:12:18 +0100
Subject: [PATCH 060/337] 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 bea6e91d73e409ec7aade81171711d509a7e3506 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 11:50:28 +0100
Subject: [PATCH 061/337] 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 ffbe7beaa5a83a3e066cfa1c8fd6c18c4cd994c1 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 11:54:55 +0100
Subject: [PATCH 062/337] 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 b4db3bd09f247d89e0bfe4ef873adc08afd80268 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 13:01:55 +0100
Subject: [PATCH 063/337] 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 ef62affc6d31f42456673b04558460baffaa8dd2 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 15:35:38 +0100
Subject: [PATCH 064/337] 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 851e35bcff4db18993ddd9e8a7ed5eba3d627861 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 15:39:39 +0100
Subject: [PATCH 065/337] 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 7bf1664f5e087c8e185b86192d4f7dc5ea883af7 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 15:51:37 +0100
Subject: [PATCH 066/337] 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 158c7758d711922d3a48a3dd3ae4ce9e769e2c67 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 19:11:49 +0100
Subject: [PATCH 067/337] 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 b9cd26b30a30d3c4666bd0e1c0ef8af16796b69f Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Thu, 3 Sep 2015 20:14:06 +0100
Subject: [PATCH 068/337] 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 30a7fa542d316613a298089ecd0e219449537767 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 08:53:23 +0100
Subject: [PATCH 069/337] 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 3e9433f28f4595c0983704c978dace45fd0c8f5f Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 09:37:20 +0100
Subject: [PATCH 070/337] Branching master to branch/2015-09-04/stack.
Copied from Perforce
Change: 188224
ServerID: perforce.ravenbrook.com
From edf30c06b4a69a8c0da35fc42c1b56c2f4d0388a Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 12:22:03 +0100
Subject: [PATCH 071/337] New function mps_root_create_reg_masked applies a
mask and pattern test to all words in registers and on the stack when
scanning them. this supports tagged references in these locations.
Consistently use the type "Word *" for pointers into the stack or into saved registers.
Remove TraceScanAreaTagged.
Copied from Perforce
Change: 188231
ServerID: perforce.ravenbrook.com
---
mps/code/mpm.h | 15 +++---
mps/code/mpmst.h | 2 +-
mps/code/mpmtypes.h | 1 +
mps/code/mps.h | 4 ++
mps/code/mpsi.c | 37 +++++++++++++--
mps/code/prmci3fr.c | 10 ++--
mps/code/prmci3li.c | 10 ++--
mps/code/prmci3xc.c | 10 ++--
mps/code/prmci6fr.c | 10 ++--
mps/code/prmci6li.c | 8 ++--
mps/code/prmci6xc.c | 10 ++--
mps/code/prot.h | 3 +-
mps/code/root.c | 66 ++++++++++++++++++++++----
mps/code/ss.c | 14 +++---
mps/code/ss.h | 10 ++--
mps/code/ssan.c | 9 ++--
mps/code/ssixi3.c | 7 +--
mps/code/ssixi6.c | 7 +--
mps/code/ssw3i3mv.c | 11 +++--
mps/code/ssw3i3pc.c | 5 +-
mps/code/ssw3i6mv.c | 19 ++++----
mps/code/ssw3i6pc.c | 19 ++++----
mps/code/th.h | 3 +-
mps/code/than.c | 5 +-
mps/code/thix.c | 16 ++++---
mps/code/thw3i3.c | 19 ++++----
mps/code/thw3i6.c | 19 ++++----
mps/code/thxc.c | 16 ++++---
mps/code/trace.c | 61 ++++++++----------------
mps/manual/source/release.rst | 4 ++
mps/manual/source/topic/root.rst | 79 +++++++++++++++++++++++++++++---
31 files changed, 335 insertions(+), 174 deletions(-)
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index a5ac16b41a2..256940d4d5a 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -472,10 +472,9 @@ extern double TraceWorkFactor;
} \
END
-extern Res TraceScanArea(ScanState ss, Addr *base, Addr *limit);
-extern Res TraceScanAreaTagged(ScanState ss, Addr *base, Addr *limit);
-extern Res TraceScanAreaMasked(ScanState ss,
- Addr *base, Addr *limit, Word mask);
+extern Res TraceScanArea(ScanState ss, Word *base, Word *limit);
+extern Res TraceScanAreaMasked(ScanState ss, Word *base, Word *limit,
+ Word mask, Word value);
extern void TraceScanSingleRef(TraceSet ts, Rank rank, Arena arena,
Seg seg, Ref *refIO);
@@ -948,15 +947,19 @@ extern void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from);
extern Res RootCreateTable(Root *rootReturn, Arena arena,
Rank rank, RootMode mode,
- Addr *base, Addr *limit);
+ Word *base, Word *limit);
extern Res RootCreateTableMasked(Root *rootReturn, Arena arena,
Rank rank, RootMode mode,
- Addr *base, Addr *limit,
+ Word *base, Word *limit,
Word mask);
extern Res RootCreateReg(Root *rootReturn, Arena arena,
Rank rank, Thread thread,
mps_reg_scan_t scan,
void *p, size_t s);
+extern Res RootCreateRegMasked(Root *rootReturn, Arena arena,
+ Rank rank, Thread thread,
+ Word mask, Word pattern,
+ Addr stackBot);
extern Res RootCreateFmt(Root *rootReturn, Arena arena,
Rank rank, RootMode mode,
mps_fmt_scan_t scan,
diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h
index d212e0e3307..c5bf54bdc2b 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -791,7 +791,7 @@ typedef struct mps_arena_s {
Bool emergency; /* garbage collect in emergency mode? */
- Addr *stackAtArenaEnter; /* NULL or top of client stack, in the thread */
+ Word *stackAtArenaEnter; /* NULL or top of client stack, in the thread */
/* that then entered the MPS. */
Sig sig;
diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h
index a6030e4c1e5..c241a04c64a 100644
--- a/mps/code/mpmtypes.h
+++ b/mps/code/mpmtypes.h
@@ -362,6 +362,7 @@ enum {
RootTABLE,
RootTABLE_MASKED,
RootREG,
+ RootREG_MASKED,
RootFMT,
RootLIMIT
};
diff --git a/mps/code/mps.h b/mps/code/mps.h
index 4e75d49b73a..515edbbe5e0 100644
--- a/mps/code/mps.h
+++ b/mps/code/mps.h
@@ -672,6 +672,10 @@ extern mps_res_t mps_root_create_fmt(mps_root_t *, mps_arena_t,
extern mps_res_t mps_root_create_reg(mps_root_t *, mps_arena_t,
mps_rank_t, mps_rm_t, mps_thr_t,
mps_reg_scan_t, void *, size_t);
+extern mps_res_t mps_root_create_reg_masked(mps_root_t *, mps_arena_t,
+ mps_rank_t, mps_rm_t, mps_thr_t,
+ mps_word_t, mps_word_t,
+ void *);
extern void mps_root_destroy(mps_root_t);
extern mps_res_t mps_stack_scan_ambig(mps_ss_t, mps_thr_t,
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index 283fbc6123e..67f23e00859 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -1304,7 +1304,7 @@ mps_res_t mps_root_create_table(mps_root_t *mps_root_o, mps_arena_t arena,
/* limit pointers. Be careful. */
res = RootCreateTable(&root, arena, rank, mode,
- (Addr *)base, (Addr *)base + size);
+ (Word *)base, (Word *)base + size);
ArenaLeave(arena);
@@ -1335,7 +1335,7 @@ mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o,
/* See .root.table-size. */
res = RootCreateTableMasked(&root, arena, rank, mode,
- (Addr *)base, (Addr *)base + size,
+ (Word *)base, (Word *)base + size,
mask);
ArenaLeave(arena);
@@ -1401,6 +1401,37 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena,
}
+mps_res_t mps_root_create_reg_masked(mps_root_t *mps_root_o, mps_arena_t arena,
+ mps_rank_t mps_rank, mps_rm_t mps_rm,
+ mps_thr_t thread, mps_word_t mask,
+ mps_word_t pattern, void *reg_scan_p)
+{
+ Rank rank = (Rank)mps_rank;
+ Root root;
+ Res res;
+
+ ArenaEnter(arena);
+
+ AVER(mps_root_o != NULL);
+ AVER(reg_scan_p != NULL); /* stackBot */
+ AVER(AddrIsAligned(reg_scan_p, sizeof(Word)));
+ AVER(rank == mps_rank_ambig());
+ AVER(mps_rm == (mps_rm_t)0);
+ AVER((~mask & pattern) == 0);
+
+ /* See .root-mode. */
+ res = RootCreateRegMasked(&root, arena, rank, thread,
+ mask, pattern, (Addr)reg_scan_p);
+
+ ArenaLeave(arena);
+
+ if (res != ResOK)
+ return (mps_res_t)res;
+ *mps_root_o = (mps_root_t)root;
+ return MPS_RES_OK;
+}
+
+
/* mps_stack_scan_ambig -- scan the thread state ambiguously
*
* See .reg-scan. */
@@ -1410,7 +1441,7 @@ mps_res_t mps_stack_scan_ambig(mps_ss_t mps_ss,
{
ScanState ss = PARENT(ScanStateStruct, ss_s, mps_ss);
UNUSED(s);
- return ThreadScan(ss, thread, p);
+ return ThreadScan(ss, thread, (Word *)p, sizeof(mps_word_t) - 1, 0);
}
diff --git a/mps/code/prmci3fr.c b/mps/code/prmci3fr.c
index 75cf94e871f..2625559564c 100644
--- a/mps/code/prmci3fr.c
+++ b/mps/code/prmci3fr.c
@@ -38,17 +38,19 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
-Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
+Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
+ Word mask, Word pattern)
{
Res res;
/* This scans the root registers (.context.regroots). It also unnecessarily
scans the rest of the context. The optimisation to scan only relevant
parts would be machine dependent. */
- res = TraceScanAreaTagged(
+ res = TraceScanAreaMasked(
ss,
- (Addr *)mfc->ucontext,
- (Addr *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext)))
+ (Word *)mfc->ucontext,
+ (Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))),
+ mask, pattern
);
return res;
diff --git a/mps/code/prmci3li.c b/mps/code/prmci3li.c
index 08737d363c3..7f6400943f1 100644
--- a/mps/code/prmci3li.c
+++ b/mps/code/prmci3li.c
@@ -101,7 +101,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
-Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
+Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
+ Word mask, Word pattern)
{
mcontext_t *mc;
Res res;
@@ -110,9 +111,10 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
unnecessarily scans the rest of the context. The optimisation
to scan only relevant parts would be machine dependent. */
mc = &mfc->ucontext->uc_mcontext;
- res = TraceScanAreaTagged(ss,
- (Addr *)mc,
- (Addr *)((char *)mc + sizeof(*mc)));
+ res = TraceScanAreaMasked(ss,
+ (Word *)mc,
+ (Word *)((char *)mc + sizeof(*mc)),
+ mask, pattern);
return res;
}
diff --git a/mps/code/prmci3xc.c b/mps/code/prmci3xc.c
index 67f3f5822df..036550ae3e0 100644
--- a/mps/code/prmci3xc.c
+++ b/mps/code/prmci3xc.c
@@ -96,7 +96,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
-Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
+Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
+ Word mask, Word pattern)
{
x86_thread_state32_t *mc;
Res res;
@@ -105,9 +106,10 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
unnecessarily scans the rest of the context. The optimisation
to scan only relevant parts would be machine dependent. */
mc = mfc->threadState;
- res = TraceScanAreaTagged(ss,
- (Addr *)mc,
- (Addr *)((char *)mc + sizeof(*mc)));
+ res = TraceScanAreaMasked(ss,
+ (Word *)mc,
+ (Word *)((char *)mc + sizeof(*mc)),
+ mask, pattern);
return res;
}
diff --git a/mps/code/prmci6fr.c b/mps/code/prmci6fr.c
index db20d01216b..debc9c760bf 100644
--- a/mps/code/prmci6fr.c
+++ b/mps/code/prmci6fr.c
@@ -32,17 +32,19 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
-Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
+Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
+ Word mask, Word pattern)
{
Res res;
/* This scans the root registers (.context.regroots). It also unnecessarily
scans the rest of the context. The optimisation to scan only relevant
parts would be machine dependent. */
- res = TraceScanAreaTagged(
+ res = TraceScanAreaMasked(
ss,
- (Addr *)mfc->ucontext,
- (Addr *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext)))
+ (Word *)mfc->ucontext,
+ (Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))),
+ mask, pattern
);
return res;
diff --git a/mps/code/prmci6li.c b/mps/code/prmci6li.c
index 38b11c3a627..6a9379209f9 100644
--- a/mps/code/prmci6li.c
+++ b/mps/code/prmci6li.c
@@ -105,7 +105,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
-Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
+Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
+ Word mask, Word pattern)
{
mcontext_t *mc;
Res res;
@@ -115,8 +116,9 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
to scan only relevant parts would be machine dependent. */
mc = &mfc->ucontext->uc_mcontext;
res = TraceScanAreaTagged(ss,
- (Addr *)mc,
- (Addr *)((char *)mc + sizeof(*mc)));
+ (Word *)mc,
+ (Word *)((char *)mc + sizeof(*mc)),
+ mask, pattern);
return res;
}
diff --git a/mps/code/prmci6xc.c b/mps/code/prmci6xc.c
index 4d3a5afe156..61e57728473 100644
--- a/mps/code/prmci6xc.c
+++ b/mps/code/prmci6xc.c
@@ -99,7 +99,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
-Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
+Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
+ Word mask, Word pattern)
{
x86_thread_state64_t *mc;
Res res;
@@ -108,9 +109,10 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
unnecessarily scans the rest of the context. The optimisation
to scan only relevant parts would be machine dependent. */
mc = mfc->threadState;
- res = TraceScanAreaTagged(ss,
- (Addr *)mc,
- (Addr *)((char *)mc + sizeof(*mc)));
+ res = TraceScanAreaMasked(ss,
+ (Word *)mc,
+ (Word *)((char *)mc + sizeof(*mc)),
+ mask, pattern);
return res;
}
diff --git a/mps/code/prot.h b/mps/code/prot.h
index 7191cd01e86..733c26c707b 100644
--- a/mps/code/prot.h
+++ b/mps/code/prot.h
@@ -30,7 +30,8 @@ extern void ProtSync(Arena arena);
extern Bool ProtCanStepInstruction(MutatorFaultContext context);
extern Res ProtStepInstruction(MutatorFaultContext context);
extern Addr MutatorFaultContextSP(MutatorFaultContext mfc);
-extern Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc);
+extern Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
+ Word mask, Word pattern);
#endif /* prot_h */
diff --git a/mps/code/root.c b/mps/code/root.c
index 02f48b38e44..0815543c5be 100644
--- a/mps/code/root.c
+++ b/mps/code/root.c
@@ -38,13 +38,14 @@ typedef struct RootStruct {
size_t s; /* environment for scan */
} fun;
struct {
- Addr *base; /* beginning of table */
- Addr *limit; /* one off end of table */
+ Word *base; /* beginning of table */
+ Word *limit; /* one off end of table */
} table;
struct {
- Addr *base; /* beginning of table */
- Addr *limit; /* one off end of table */
+ Word *base; /* beginning of table */
+ Word *limit; /* one off end of table */
Word mask; /* tag mask for scanning */
+ Word pattern; /* tag pattern for scanning */
} tableMasked;
struct {
mps_reg_scan_t scan; /* function for scanning registers */
@@ -52,6 +53,12 @@ typedef struct RootStruct {
void *p; /* passed to scan */
size_t s; /* passed to scan */
} reg;
+ struct {
+ Thread thread; /* passed to scan */
+ Word mask; /* tag mask for scanning */
+ Word pattern; /* tag pattern for scanning */
+ Word *stackBot; /* bottom of stack */
+ } regMasked;
struct {
mps_fmt_scan_t scan; /* format-like scanner */
Addr base, limit; /* passed to scan */
@@ -67,7 +74,8 @@ typedef struct RootStruct {
Bool RootVarCheck(RootVar rootVar)
{
CHECKL(rootVar == RootTABLE || rootVar == RootTABLE_MASKED
- || rootVar == RootFUN || rootVar == RootFMT || rootVar == RootREG);
+ || rootVar == RootFUN || rootVar == RootFMT || rootVar == RootREG
+ || rootVar == RootREG_MASKED);
UNUSED(rootVar);
return TRUE;
}
@@ -112,7 +120,7 @@ Bool RootCheck(Root root)
case RootTABLE_MASKED:
CHECKL(root->the.tableMasked.base != 0);
CHECKL(root->the.tableMasked.base < root->the.tableMasked.limit);
- /* Can't check anything about the mask. */
+ CHECKL((~root->the.tableMasked.mask & root->the.tableMasked.pattern) == 0);
break;
case RootFUN:
@@ -122,6 +130,13 @@ Bool RootCheck(Root root)
case RootREG:
CHECKL(root->the.reg.scan != NULL);
CHECKD_NOSIG(Thread, root->the.reg.thread); /* */
+ /* Can't check anything about p or s. */
+ break;
+
+ case RootREG_MASKED:
+ CHECKD_NOSIG(Thread, root->the.regMasked.thread); /* */
+ CHECKL((~root->the.regMasked.mask & root->the.regMasked.pattern) == 0);
+ /* Can't check anything about stackBot. */
break;
case RootFMT:
@@ -254,7 +269,7 @@ static Res rootCreateProtectable(Root *rootReturn, Arena arena,
}
Res RootCreateTable(Root *rootReturn, Arena arena,
- Rank rank, RootMode mode, Addr *base, Addr *limit)
+ Rank rank, RootMode mode, Word *base, Word *limit)
{
Res res;
union RootUnion theUnion;
@@ -276,7 +291,7 @@ Res RootCreateTable(Root *rootReturn, Arena arena,
}
Res RootCreateTableMasked(Root *rootReturn, Arena arena,
- Rank rank, RootMode mode, Addr *base, Addr *limit,
+ Rank rank, RootMode mode, Word *base, Word *limit,
Word mask)
{
union RootUnion theUnion;
@@ -291,6 +306,7 @@ Res RootCreateTableMasked(Root *rootReturn, Arena arena,
theUnion.tableMasked.base = base;
theUnion.tableMasked.limit = limit;
theUnion.tableMasked.mask = mask;
+ theUnion.tableMasked.pattern = 0;
return rootCreateProtectable(rootReturn, arena, rank, mode, RootTABLE_MASKED,
(Addr)base, (Addr)limit, &theUnion);
@@ -317,6 +333,28 @@ Res RootCreateReg(Root *rootReturn, Arena arena,
return rootCreate(rootReturn, arena, rank, (RootMode)0, RootREG, &theUnion);
}
+Res RootCreateRegMasked(Root *rootReturn, Arena arena,
+ Rank rank, Thread thread,
+ Word mask, Word pattern, Addr stackBot)
+{
+ union RootUnion theUnion;
+
+ AVER(rootReturn != NULL);
+ AVERT(Arena, arena);
+ AVERT(Rank, rank);
+ AVERT(Thread, thread);
+ AVER(ThreadArena(thread) == arena);
+ AVER((~mask & pattern) == 0);
+
+ theUnion.regMasked.thread = thread;
+ theUnion.regMasked.mask = mask;
+ theUnion.regMasked.pattern = pattern;
+ theUnion.regMasked.stackBot = stackBot;
+
+ return rootCreate(rootReturn, arena, rank, (RootMode)0, RootREG_MASKED,
+ &theUnion);
+}
+
/* RootCreateFmt -- create root from block of formatted objects
*
* .fmt.no-align-check: Note that we don't check the alignment of base
@@ -481,7 +519,8 @@ Res RootScan(ScanState ss, Root root)
res = TraceScanAreaMasked(ss,
root->the.tableMasked.base,
root->the.tableMasked.limit,
- root->the.tableMasked.mask);
+ root->the.tableMasked.mask,
+ root->the.tableMasked.pattern);
ss->scannedSize += AddrOffset(root->the.table.base, root->the.table.limit);
if (res != ResOK)
goto failScan;
@@ -500,6 +539,15 @@ Res RootScan(ScanState ss, Root root)
goto failScan;
break;
+ case RootREG_MASKED:
+ res = ThreadScan(ss, root->the.regMasked.thread,
+ root->the.regMasked.stackBot,
+ root->the.regMasked.mask,
+ root->the.regMasked.pattern);
+ if (res != ResOK)
+ goto failScan;
+ break;
+
case RootFMT:
res = (*root->the.fmt.scan)(&ss->ss_s, root->the.fmt.base, root->the.fmt.limit);
ss->scannedSize += AddrOffset(root->the.fmt.base, root->the.fmt.limit);
diff --git a/mps/code/ss.c b/mps/code/ss.c
index 8c5bc44b022..7078c59d204 100644
--- a/mps/code/ss.c
+++ b/mps/code/ss.c
@@ -24,10 +24,8 @@ SRCID(ss, "$Id$");
* scanning.
*/
-Res StackScanInner(ScanState ss,
- Addr *stackBot,
- Addr *stackTop,
- Count nSavedRegs)
+Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop,
+ Count nSavedRegs, Word mask, Word pattern)
{
Arena arena;
Res res;
@@ -49,14 +47,16 @@ Res StackScanInner(ScanState ss,
if (arena->stackAtArenaEnter != NULL) {
AVER(stackTop < arena->stackAtArenaEnter);
AVER(arena->stackAtArenaEnter < stackBot);
- res = TraceScanAreaTagged(ss, stackTop, stackTop + nSavedRegs);
+ res = TraceScanAreaMasked(ss, stackTop, stackTop + nSavedRegs,
+ mask, pattern);
if (res != ResOK)
return res;
- res = TraceScanAreaTagged(ss, arena->stackAtArenaEnter, stackBot);
+ res = TraceScanAreaMasked(ss, arena->stackAtArenaEnter, stackBot,
+ mask, pattern);
if (res != ResOK)
return res;
} else {
- res = TraceScanAreaTagged(ss, stackTop, stackBot);
+ res = TraceScanAreaMasked(ss, stackTop, stackBot, mask, pattern);
if (res != ResOK)
return res;
}
diff --git a/mps/code/ss.h b/mps/code/ss.h
index 831ad98aea8..c4045bbfe47 100644
--- a/mps/code/ss.h
+++ b/mps/code/ss.h
@@ -32,13 +32,9 @@
* stack itself.
*/
-extern Res StackScan(ScanState ss, Addr *stackBot);
-
-
-extern Res StackScanInner(ScanState ss,
- Addr *stackBot,
- Addr *stackTop,
- Count nSavedRegs);
+extern Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern);
+extern Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop,
+ Count nSavedRegs, Word mask, Word pattern);
#endif /* ss_h */
diff --git a/mps/code/ssan.c b/mps/code/ssan.c
index 27233e7b9f6..b746b28bb1d 100644
--- a/mps/code/ssan.c
+++ b/mps/code/ssan.c
@@ -21,21 +21,22 @@
SRCID(ssan, "$Id$");
-Res StackScan(ScanState ss, Addr *stackBot)
+Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
{
jmp_buf jb;
- void *stackTop = &jb;
+ Word *stackTop = (Word *)&jb;
/* .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);
+ AVER(stackTop < stackBot);
(void)setjmp(jb);
- return StackScanInner(ss, stackBot, stackTop, sizeof jb / sizeof(Addr*));
+ return StackScanInner(ss, stackBot, stackTop, sizeof jb / sizeof(Word*),
+ mask, pattern);
}
diff --git a/mps/code/ssixi3.c b/mps/code/ssixi3.c
index 8cc1f8cbd45..db67d0e61e4 100644
--- a/mps/code/ssixi3.c
+++ b/mps/code/ssixi3.c
@@ -49,9 +49,9 @@ SRCID(ssixi3, "$Id$");
#define ASMV(x) __asm__ volatile (x)
-Res StackScan(ScanState ss, Addr *stackBot)
+Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
{
- Addr calleeSaveRegs[4];
+ Word calleeSaveRegs[4];
/* .assume.asm.stack */
/* Store the callee save registers on the stack so they get scanned
@@ -62,7 +62,8 @@ Res StackScan(ScanState ss, Addr *stackBot)
ASMV("mov %%edi, %0" : "=m" (calleeSaveRegs[2]));
ASMV("mov %%ebp, %0" : "=m" (calleeSaveRegs[3]));
- return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs));
+ return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs),
+ mask, pattern);
}
diff --git a/mps/code/ssixi6.c b/mps/code/ssixi6.c
index e61af2ee961..9fd9e8a1811 100644
--- a/mps/code/ssixi6.c
+++ b/mps/code/ssixi6.c
@@ -47,9 +47,9 @@ SRCID(ssixi6, "$Id$");
#define ASMV(x) __asm__ volatile (x)
-Res StackScan(ScanState ss, Addr *stackBot)
+Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
{
- Addr calleeSaveRegs[6];
+ Word calleeSaveRegs[6];
/* .assume.asm.stack */
/* Store the callee save registers on the stack so they get scanned
@@ -62,7 +62,8 @@ Res StackScan(ScanState ss, Addr *stackBot)
ASMV("mov %%r14, %0" : "=m" (calleeSaveRegs[4]));
ASMV("mov %%r15, %0" : "=m" (calleeSaveRegs[5]));
- return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs));
+ return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs),
+ mask, pattern);
}
diff --git a/mps/code/ssw3i3mv.c b/mps/code/ssw3i3mv.c
index d879780734a..feffdf3e7a3 100644
--- a/mps/code/ssw3i3mv.c
+++ b/mps/code/ssw3i3mv.c
@@ -22,7 +22,7 @@
SRCID(ssw3i3mv, "$Id$");
-Res StackScan(ScanState ss, Addr *stackBot)
+Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
{
jmp_buf jb;
@@ -33,16 +33,17 @@ Res StackScan(ScanState ss, Addr *stackBot)
/* 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(((_JUMP_BUFFER *)jb)->Edi) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->Esi) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->Ebx) == sizeof(Word));
/* 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 StackScanInner(ss, stackBot, (Word *)&((_JUMP_BUFFER *)jb)->Ebx, 3,
+ mask, pattern);
}
/* C. COPYRIGHT AND LICENSE
diff --git a/mps/code/ssw3i3pc.c b/mps/code/ssw3i3pc.c
index e03754c7eba..9c42fa6207f 100644
--- a/mps/code/ssw3i3pc.c
+++ b/mps/code/ssw3i3pc.c
@@ -46,7 +46,7 @@ typedef struct __JUMP_BUFFER {
} _JUMP_BUFFER;
-Res StackScan(ScanState ss, Addr *stackBot)
+Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
{
jmp_buf jb;
@@ -58,7 +58,8 @@ Res StackScan(ScanState ss, Addr *stackBot)
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 StackScanInner(ss, stackBot, (Word *)&((_JUMP_BUFFER *)jb)->Ebx, 3,
+ mask, pattern);
}
diff --git a/mps/code/ssw3i6mv.c b/mps/code/ssw3i6mv.c
index 16c33e3fb74..7af35054d30 100644
--- a/mps/code/ssw3i6mv.c
+++ b/mps/code/ssw3i6mv.c
@@ -30,7 +30,7 @@
SRCID(ssw3i6mv, "$Id$");
-Res StackScan(ScanState ss, Addr *stackBot)
+Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
{
jmp_buf jb;
@@ -41,13 +41,13 @@ Res StackScan(ScanState ss, Addr *stackBot)
/* 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(((_JUMP_BUFFER *)jb)->Rdi) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->Rbp) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->R12) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->R13) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->R14) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)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);
@@ -59,7 +59,8 @@ 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 StackScanInner(ss, stackBot, (Word *)&((_JUMP_BUFFER *)jb)->Rbx, 9,
+ mask, pattern);
}
/* C. COPYRIGHT AND LICENSE
diff --git a/mps/code/ssw3i6pc.c b/mps/code/ssw3i6pc.c
index 89fbbeac420..4b22d72b0d9 100644
--- a/mps/code/ssw3i6pc.c
+++ b/mps/code/ssw3i6pc.c
@@ -68,7 +68,7 @@ typedef struct _JUMP_BUFFER {
} _JUMP_BUFFER;
-Res StackScan(ScanState ss, Addr *stackBot)
+Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
{
jmp_buf jb;
@@ -79,13 +79,13 @@ Res StackScan(ScanState ss, Addr *stackBot)
/* 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(((_JUMP_BUFFER *)jb)->Rdi) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->Rbp) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->R12) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->R13) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->R14) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)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);
@@ -97,7 +97,8 @@ 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 StackScanInner(ss, stackBot, (Word *)&((_JUMP_BUFFER *)jb)->Rbx, 9,
+ mask, pattern);
}
diff --git a/mps/code/th.h b/mps/code/th.h
index 8c7da150fd0..ea56be2dd42 100644
--- a/mps/code/th.h
+++ b/mps/code/th.h
@@ -67,7 +67,8 @@ extern Thread ThreadRingThread(Ring threadRing);
extern Arena ThreadArena(Thread thread);
-extern Res ThreadScan(ScanState ss, Thread thread, void *stackBot);
+extern Res ThreadScan(ScanState ss, Thread thread, Word *stackBot,
+ Word mask, Word pattern);
#endif /* th_h */
diff --git a/mps/code/than.c b/mps/code/than.c
index 8c5af222898..f9b0e51e148 100644
--- a/mps/code/than.c
+++ b/mps/code/than.c
@@ -115,10 +115,11 @@ Arena ThreadArena(Thread thread)
}
-Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
+Res ThreadScan(ScanState ss, Thread thread, Word *stackBot,
+ Word mask, Word pattern)
{
UNUSED(thread);
- return StackScan(ss, stackBot);
+ return StackScan(ss, stackBot, mask, pattern);
}
diff --git a/mps/code/thix.c b/mps/code/thix.c
index d32a7dd6601..6da41e572d6 100644
--- a/mps/code/thix.c
+++ b/mps/code/thix.c
@@ -222,7 +222,8 @@ Arena ThreadArena(Thread thread)
/* ThreadScan -- scan the state of a thread (stack and regs) */
-Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
+Res ThreadScan(ScanState ss, Thread thread, Word *stackBot,
+ Word mask, Word pattern)
{
pthread_t self;
Res res;
@@ -231,12 +232,13 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
self = pthread_self();
if(pthread_equal(self, thread->id)) {
/* scan this thread's stack */
- res = StackScan(ss, stackBot);
+ res = StackScan(ss, stackBot, mask, pattern);
if(res != ResOK)
return res;
} else {
MutatorFaultContext mfc;
- Addr *stackBase, *stackLimit, stackPtr;
+ Word *stackBase, *stackLimit;
+ Addr stackPtr;
mfc = thread->mfc;
if(mfc == NULL) {
@@ -248,20 +250,20 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
stackPtr = MutatorFaultContextSP(mfc);
/* .stack.align */
- stackBase = (Addr *)AddrAlignUp(stackPtr, sizeof(Addr));
- stackLimit = (Addr *)stackBot;
+ stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr));
+ stackLimit = stackBot;
if (stackBase >= stackLimit)
return ResOK; /* .stack.below-bottom */
/* scan stack inclusive of current sp and exclusive of
* stackBot (.stack.full-descend)
*/
- res = TraceScanAreaTagged(ss, stackBase, stackLimit);
+ res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern);
if(res != ResOK)
return res;
/* scan the registers in the mutator fault context */
- res = MutatorFaultContextScan(ss, mfc);
+ res = MutatorFaultContextScan(ss, mfc, mask, pattern);
if(res != ResOK)
return res;
}
diff --git a/mps/code/thw3i3.c b/mps/code/thw3i3.c
index 33424b6cf54..030319c3350 100644
--- a/mps/code/thw3i3.c
+++ b/mps/code/thw3i3.c
@@ -67,7 +67,8 @@
SRCID(thw3i3, "$Id$");
-Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
+Res ThreadScan(ScanState ss, Thread thread, Word *stackBot,
+ Word mask, Word pattern)
{
DWORD id;
Res res;
@@ -77,7 +78,8 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
if(id != thread->id) { /* .thread.id */
CONTEXT context;
BOOL success;
- Addr *stackBase, *stackLimit, stackPtr;
+ Word *stackBase, *stackLimit;
+ Addr stackPtr;
/* scan stack and register roots in other threads */
@@ -95,15 +97,15 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
stackPtr = (Addr)context.Esp; /* .i3.sp */
/* .stack.align */
- stackBase = (Addr *)AddrAlignUp(stackPtr, sizeof(Addr));
- stackLimit = (Addr *)stackBot;
+ stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr));
+ stackLimit = stackBot;
if (stackBase >= stackLimit)
return ResOK; /* .stack.below-bottom */
/* scan stack inclusive of current sp and exclusive of
* stackBot (.stack.full-descend)
*/
- res = TraceScanAreaTagged(ss, stackBase, stackLimit);
+ res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern);
if(res != ResOK)
return res;
@@ -112,13 +114,14 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
* unnecessarily scans the rest of the context. The optimisation
* to scan only relevant parts would be machine dependent.
*/
- res = TraceScanAreaTagged(ss, (Addr *)&context,
- (Addr *)((char *)&context + sizeof(CONTEXT)));
+ res = TraceScanAreaMasked(ss, (Word *)&context,
+ (Word *)((char *)&context + sizeof(CONTEXT)),
+ mask, pattern);
if(res != ResOK)
return res;
} else { /* scan this thread's stack */
- res = StackScan(ss, stackBot);
+ res = StackScan(ss, stackBot, mask, pattern);
if(res != ResOK)
return res;
}
diff --git a/mps/code/thw3i6.c b/mps/code/thw3i6.c
index 9b0eae55db6..77a7aefe425 100644
--- a/mps/code/thw3i6.c
+++ b/mps/code/thw3i6.c
@@ -67,7 +67,8 @@
SRCID(thw3i6, "$Id$");
-Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
+Res ThreadScan(ScanState ss, Thread thread, Word *stackBot,
+ Word mask, Word pattern)
{
DWORD id;
Res res;
@@ -77,7 +78,8 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
if(id != thread->id) { /* .thread.id */
CONTEXT context;
BOOL success;
- Addr *stackBase, *stackLimit, stackPtr;
+ Word *stackBase, *stackLimit;
+ Addr stackPtr;
/* scan stack and register roots in other threads */
@@ -95,15 +97,15 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
stackPtr = (Addr)context.Rsp; /* .i6.sp */
/* .stack.align */
- stackBase = (Addr *)AddrAlignUp(stackPtr, sizeof(Addr));
- stackLimit = (Addr *)stackBot;
+ stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr));
+ stackLimit = stackBot;
if (stackBase >= stackLimit)
return ResOK; /* .stack.below-bottom */
/* scan stack inclusive of current sp and exclusive of
* stackBot (.stack.full-descend)
*/
- res = TraceScanAreaTagged(ss, stackBase, stackLimit);
+ res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern);
if(res != ResOK)
return res;
@@ -112,13 +114,14 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
* unnecessarily scans the rest of the context. The optimisation
* to scan only relevant parts would be machine dependent.
*/
- res = TraceScanAreaTagged(ss, (Addr *)&context,
- (Addr *)((char *)&context + sizeof(CONTEXT)));
+ res = TraceScanAreaMasked(ss, (Word *)&context,
+ (Word *)((char *)&context + sizeof(CONTEXT)),
+ mask, pattern);
if(res != ResOK)
return res;
} else { /* scan this thread's stack */
- res = StackScan(ss, stackBot);
+ res = StackScan(ss, stackBot, mask, pattern);
if(res != ResOK)
return res;
}
diff --git a/mps/code/thxc.c b/mps/code/thxc.c
index 6aeffef6568..8beaea1930e 100644
--- a/mps/code/thxc.c
+++ b/mps/code/thxc.c
@@ -189,7 +189,8 @@ Arena ThreadArena(Thread thread)
#include "prmcxc.h"
-Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
+Res ThreadScan(ScanState ss, Thread thread, Word *stackBot,
+ Word mask, Word pattern)
{
mach_port_t self;
Res res;
@@ -199,13 +200,14 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
AVER(MACH_PORT_VALID(self));
if (thread->port == self) {
/* scan this thread's stack */
- res = StackScan(ss, stackBot);
+ res = StackScan(ss, stackBot, mask, pattern);
if(res != ResOK)
return res;
} else {
MutatorFaultContextStruct mfcStruct;
THREAD_STATE_S threadState;
- Addr *stackBase, *stackLimit, stackPtr;
+ Word *stackBase, *stackLimit;
+ Addr stackPtr;
mach_msg_type_number_t count;
kern_return_t kern_return;
@@ -227,20 +229,20 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
stackPtr = MutatorFaultContextSP(&mfcStruct);
/* .stack.align */
- stackBase = (Addr *)AddrAlignUp(stackPtr, sizeof(Addr));
- stackLimit = (Addr *)stackBot;
+ stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr));
+ stackLimit = stackBot;
if (stackBase >= stackLimit)
return ResOK; /* .stack.below-bottom */
/* scan stack inclusive of current sp and exclusive of
* stackBot (.stack.full-descend)
*/
- res = TraceScanAreaTagged(ss, stackBase, stackLimit);
+ res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern);
if(res != ResOK)
return res;
/* scan the registers in the mutator fault context */
- res = MutatorFaultContextScan(ss, &mfcStruct);
+ res = MutatorFaultContextScan(ss, &mfcStruct, mask, pattern);
if(res != ResOK)
return res;
}
diff --git a/mps/code/trace.c b/mps/code/trace.c
index 7aeb70305c7..6f44f724846 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -1425,11 +1425,10 @@ void TraceScanSingleRef(TraceSet ts, Rank rank, Arena arena,
* [base, limit). I.e., it calls Fix on all words from base up to
* limit, inclusive of base and exclusive of limit. */
-Res TraceScanArea(ScanState ss, Addr *base, Addr *limit)
+Res TraceScanArea(ScanState ss, Word *base, Word *limit)
{
Res res;
- Addr *p;
- Ref ref;
+ Word word, *p;
AVER(base != NULL);
AVER(limit != NULL);
@@ -1442,10 +1441,10 @@ Res TraceScanArea(ScanState ss, Addr *base, Addr *limit)
loop:
if (p >= limit)
goto out;
- ref = *p++;
- if(!TRACE_FIX1(ss, ref))
+ word = *p++;
+ if(!TRACE_FIX1(ss, (Ref)word))
goto loop;
- res = TRACE_FIX2(ss, p-1);
+ res = TRACE_FIX2(ss, (Ref *)(p-1));
if(res == ResOK)
goto loop;
return res;
@@ -1457,43 +1456,21 @@ Res TraceScanArea(ScanState ss, Addr *base, Addr *limit)
}
-/* TraceScanAreaTagged -- scan contiguous area of tagged references
- *
- * .tagging: This is as TraceScanArea except words are only fixed they are
- * tagged as zero according to the alignment of a Word.
- *
- * See also PoolSingleAccess .
- *
- * TODO: Generalise the handling of tags so that pools can decide how
- * their objects are tagged. This may use the user defined format
- * to describe how tags are done */
-Res TraceScanAreaTagged(ScanState ss, Addr *base, Addr *limit)
-{
- Word mask;
-
- /* NOTE: An optimisation that maybe worth considering is setting some of the
- * top bits in the mask as an early catch of addresses outside the arena.
- * This might help slightly on 64-bit windows. However these are picked up
- * soon afterwards by later checks. The bottom bits are more important
- * to check as we ignore them in AMCFix, so the non-reference could
- * otherwise end up pinning an object. */
- mask = sizeof(Word) - 1;
- AVER(WordIsP2(mask + 1));
- return TraceScanAreaMasked(ss, base, limit, mask);
-}
-
-
/* TraceScanAreaMasked -- scan contiguous area of filtered references
*
- * This is as TraceScanArea except words are only fixed if they are zero
- * when masked with a mask. */
+ * This is as TraceScanArea except words are only fixed if they have
+ * the given value when masked with a mask.
+ *
+ * This has ATTRIBUTE_NO_SANITIZE_ADDRESS otherwise Clang's address
+ * sanitizer will think we have run off the end of an array.
+ */
ATTRIBUTE_NO_SANITIZE_ADDRESS
-Res TraceScanAreaMasked(ScanState ss, Addr *base, Addr *limit, Word mask)
+Res TraceScanAreaMasked(ScanState ss, Word *base, Word *limit, Word mask,
+ Word pattern)
{
Res res;
- Addr *p;
- Ref ref;
+ Word word, *p;
AVERT(ScanState, ss);
AVER(base != NULL);
@@ -1507,12 +1484,12 @@ Res TraceScanAreaMasked(ScanState ss, Addr *base, Addr *limit, Word mask)
loop:
if (p >= limit)
goto out;
- ref = *p++;
- if (((Word)ref & mask)
- != 0) goto loop;
- if (!TRACE_FIX1(ss, ref))
+ word = *p++;
+ if ((word & mask) != pattern)
goto loop;
- res = TRACE_FIX2(ss, p-1);
+ if (!TRACE_FIX1(ss, (Ref)word))
+ goto loop;
+ res = TRACE_FIX2(ss, (Ref *)(p-1));
if(res == ResOK)
goto loop;
return res;
diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst
index cb820397281..a9881375159 100644
--- a/mps/manual/source/release.rst
+++ b/mps/manual/source/release.rst
@@ -17,6 +17,10 @@ New features
specifying the minimum size of the memory segments that the pool
requests from the :term:`arena`.
+#. New function :c:func:`mps_root_create_reg_masked` applies a mask
+ and pattern test to all words in registers and on the stack when
+ scanning them. This supports tagged references in these locations.
+
Interface changes
.................
diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst
index 4a1e06686ae..0089b26e728 100644
--- a/mps/manual/source/topic/root.rst
+++ b/mps/manual/source/topic/root.rst
@@ -393,10 +393,12 @@ Root interface
The registered root description persists until it is destroyed by
calling :c:func:`mps_root_destroy`.
+
.. c:function:: mps_res_t mps_root_create_reg(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thr, mps_reg_scan_t reg_scan, void *p, size_t s)
Register a :term:`root` that consists of the :term:`references`
- fixed in a :term:`thread's ` stack by a scanning function.
+ fixed in a :term:`thread's ` registers and stack by a
+ scanning function.
``root_o`` points to a location that will hold the address of the
new root description.
@@ -427,7 +429,10 @@ Root interface
It is not supported for :term:`client programs` to pass their
own scanning functions to this function. The built-in MPS
- function :c:func:`mps_stack_scan_ambig` must be used.
+ function :c:func:`mps_stack_scan_ambig` must be used. In this
+ case the ``p`` argument must be a pointer into the thread's
+ stack, as described for :c:func:`mps_root_create_reg_masked`
+ below, and the ``s`` argument is ignored.
This function is intended as a hook should we ever need to
allow client-specific extension or customization of stack and
@@ -483,11 +488,14 @@ Root interface
It scans all integer registers and everything on the stack of the
thread given, and can therefore only be used with :term:`ambiguous
- roots`. It only scans locations that are at, or higher on the
- stack (that is, more recently added), the stack bottom that was
- passed to :c:func:`mps_thread_reg`. References are assumed to be
- represented as machine words, and are required to be
- 4-byte-aligned; unaligned values are ignored.
+ roots`. It scans locations that are more recently added than the
+ stack bottom that was passed in the ``p`` argument to
+ :c:func:`mps_root_create_reg`.
+
+ References are assumed to be represented as machine words, and are
+ required to be word-aligned; unaligned values are ignored. If
+ references are tagged, use :c:func:`mps_root_create_reg_masked`
+ instead.
.. note::
@@ -496,6 +504,63 @@ Root interface
and in some cases on the compiler.
+.. c:function:: mps_res_t mps_root_create_reg_masked(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thr, mps_word_t mask, mps_word_t pattern, void *stack)
+
+ Register a :term:`root` that consists of the :term:`references` in
+ a :term:`thread's ` registers and stack that match a
+ binary pattern.
+
+ ``root_o`` points to a location that will hold the address of the
+ new root description.
+
+ ``arena`` is the arena.
+
+ ``rank`` is the :term:`rank` of references in the root.
+
+ ``rm`` is the :term:`root mode`.
+
+ ``thr`` is the thread.
+
+ ``mask`` is an arbitrary mask that is applied to each word in the
+ thread's registers and stack.
+
+ ``pattern`` is an arbitrary pattern; any word that is unequal to
+ this (after masking with ``mask``) is not considered to be a
+ reference.
+
+ ``stack`` is a pointer into the thread's stack. On platforms where
+ the stack grows downwards (currently, all supported platforms),
+ locations below this address will be scanned.
+
+ Returns :c:macro:`MPS_RES_OK` if the root was registered
+ successfully, :c:macro:`MPS_RES_MEMORY` if the new root
+ description could not be allocated, or another :term:`result code`
+ if there was another error.
+
+ The registered root description persists until it is destroyed by
+ calling :c:func:`mps_root_destroy`.
+
+ .. warning::
+
+ A risk of using tagged pointers in registers and on the stack
+ is that in some circumstances, an optimizing compiler might
+ optimize away the tagged pointer, keeping only the untagged
+ version of the pointer. In this situation the pointer would be
+ ignored and if it was the last reference to the object the MPS
+ might incorrectly determine that it was dead.
+
+ You can avoid this risk by setting ``mask`` and ``pattern`` to
+ zero: in this case all words in registers and on the stack are
+ scanned, leading to possible additional scanning and retention.
+
+ .. note::
+
+ An optimization that may be worth considering is setting some
+ of the top bits in ``mask`` so that addresses that cannot be
+ allocated by the MPS are rejected quickly. This requires
+ expertise with the platform's virtual memory interface.
+
+
.. c:function:: mps_res_t mps_root_create_table(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_addr_t *base, size_t count)
Register a :term:`root` that consists of a vector of
From 881c594458aeede4b44ecfcbc711858cf8b1c34f Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 12:28:49 +0100
Subject: [PATCH 072/337] Correct type for rootcreateregmasked.
Copied from Perforce
Change: 188233
ServerID: perforce.ravenbrook.com
---
mps/code/mpm.h | 2 +-
mps/code/mpsi.c | 2 +-
mps/code/root.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index 256940d4d5a..a2ceae76bef 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -959,7 +959,7 @@ extern Res RootCreateReg(Root *rootReturn, Arena arena,
extern Res RootCreateRegMasked(Root *rootReturn, Arena arena,
Rank rank, Thread thread,
Word mask, Word pattern,
- Addr stackBot);
+ Word *stackBot);
extern Res RootCreateFmt(Root *rootReturn, Arena arena,
Rank rank, RootMode mode,
mps_fmt_scan_t scan,
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index 67f23e00859..0ae717a2ef2 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -1421,7 +1421,7 @@ mps_res_t mps_root_create_reg_masked(mps_root_t *mps_root_o, mps_arena_t arena,
/* See .root-mode. */
res = RootCreateRegMasked(&root, arena, rank, thread,
- mask, pattern, (Addr)reg_scan_p);
+ mask, pattern, (Word *)reg_scan_p);
ArenaLeave(arena);
diff --git a/mps/code/root.c b/mps/code/root.c
index 0815543c5be..25780a562f9 100644
--- a/mps/code/root.c
+++ b/mps/code/root.c
@@ -335,7 +335,7 @@ Res RootCreateReg(Root *rootReturn, Arena arena,
Res RootCreateRegMasked(Root *rootReturn, Arena arena,
Rank rank, Thread thread,
- Word mask, Word pattern, Addr stackBot)
+ Word mask, Word pattern, Word *stackBot)
{
union RootUnion theUnion;
From 2255eabfda08c218ff739684948d57e8aa396daa Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 12:35:34 +0100
Subject: [PATCH 073/337] Fix compilation on lii6.
Copied from Perforce
Change: 188235
ServerID: perforce.ravenbrook.com
---
mps/code/prmci6li.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mps/code/prmci6li.c b/mps/code/prmci6li.c
index 6a9379209f9..304cfdc38d3 100644
--- a/mps/code/prmci6li.c
+++ b/mps/code/prmci6li.c
@@ -115,7 +115,7 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
unnecessarily scans the rest of the context. The optimisation
to scan only relevant parts would be machine dependent. */
mc = &mfc->ucontext->uc_mcontext;
- res = TraceScanAreaTagged(ss,
+ res = TraceScanAreaMasked(ss,
(Word *)mc,
(Word *)((char *)mc + sizeof(*mc)),
mask, pattern);
From b43a56f9b50d4bcffdefb6179d2ca3d1a8fb1dbf Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 15:24:14 +0100
Subject: [PATCH 074/337] Move arenadefaultzoneset to be adjacent to its todo.
Add comments for ArenaDefaultZONESET and LocusPrefDEFAULT.
Copied from Perforce
Change: 188237
ServerID: perforce.ravenbrook.com
---
mps/code/config.h | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/mps/code/config.h b/mps/code/config.h
index 589fbc20c6b..d545b3ec0b4 100644
--- a/mps/code/config.h
+++ b/mps/code/config.h
@@ -406,8 +406,6 @@
#define ARENA_DEFAULT_ZONED TRUE
-#define ArenaDefaultZONESET (ZoneSetUNIV << (MPS_WORD_WIDTH / 2))
-
/* ARENA_MINIMUM_COLLECTABLE_SIZE is the minimum size (in bytes) of
* collectable memory that might be considered worthwhile to run a
* full garbage collection. */
@@ -431,9 +429,16 @@
#define ARENA_MAX_COLLECT_FRACTION (0.1)
-/* TODO: This is left over from before the branch/2014-01-29/mps-chain-zones
- and 2014-01-17/cbs-tract-alloc reformed allocation, and may now be doing
- more harm than good. Experiment with setting to ZoneSetUNIV. */
+/* ArenaDefaultZONESET is the zone set used by LocusPrefDEFAULT.
+ *
+ * TODO: This is left over from before branches 2014-01-29/mps-chain-zones
+ * and 2014-01-17/cbs-tract-alloc reformed allocation, and may now be
+ * doing more harm than good. Experiment with setting to ZoneSetUNIV. */
+
+#define ArenaDefaultZONESET (ZoneSetUNIV << (MPS_WORD_WIDTH / 2))
+
+/* LocusPrefDEFAULT is the allocation preference used by manual pool
+ * classes (these don't care where they allocate). */
#define LocusPrefDEFAULT { \
LocusPrefSig, /* sig */ \
From 2514663693e01b546601ef6bd3ffcec56dd34173 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 15:25:37 +0100
Subject: [PATCH 075/337] Move policy for mps_arena_step to policy module.
Copied from Perforce
Change: 188238
ServerID: perforce.ravenbrook.com
---
mps/code/global.c | 37 ++-----------------------------------
mps/code/mpm.h | 3 +++
mps/code/policy.c | 39 +++++++++++++++++++++++++++++++++++++++
3 files changed, 44 insertions(+), 35 deletions(-)
diff --git a/mps/code/global.c b/mps/code/global.c
index cd072951e87..40c3aa44e69 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -745,39 +745,6 @@ void (ArenaPoll)(Globals globals)
globals->insidePoll = FALSE;
}
-/* Work out whether we have enough time here to collect the world,
- * and whether much time has passed since the last time we did that
- * opportunistically. */
-static Bool arenaShouldCollectWorld(Arena arena,
- double interval,
- double multiplier,
- 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);
-
- /* 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;
- }
- }
- }
- return FALSE;
-}
-
Bool ArenaStep(Globals globals, double interval, double multiplier)
{
Size scanned;
@@ -799,8 +766,8 @@ Bool ArenaStep(Globals globals, double interval, double multiplier)
stepped = FALSE;
- if (arenaShouldCollectWorld(arena, interval, multiplier,
- start, clocks_per_sec))
+ if (PolicyShouldCollectWorld(arena, interval, multiplier,
+ start, clocks_per_sec))
{
Res res;
Trace trace;
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index 6c0978d0dba..2ca05d279e3 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -661,6 +661,9 @@ extern Res ArenaNoExtend(Arena arena, Addr base, Size size);
extern Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
Size size, Pool pool);
+extern Bool PolicyShouldCollectWorld(Arena arena, double interval,
+ double multiplier, Clock now,
+ Clock clocks_per_sec);
extern Bool PolicyStartTrace(Trace *traceReturn, Arena arena);
extern double PolicyCollectionTime(Arena arena);
extern Bool PolicyPoll(Arena arena);
diff --git a/mps/code/policy.c b/mps/code/policy.c
index 64611a31d11..48cd3d722c1 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -122,6 +122,45 @@ Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
}
+/* PolicyShouldCollectWorld -- should we collect the world now?
+ *
+ * Return TRUE if we should try collecting the world now, FALSE if
+ * not.
+ *
+ * This is the policy behind mps_arena_step, and so there the client
+ * must have provided us with be enough time to collect the world, and
+ * enough time must have passed since the last time we did that
+ * opportunistically.
+ */
+
+Bool PolicyShouldCollectWorld(Arena arena, double interval, double multiplier,
+ 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);
+
+ /* 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;
+ }
+ }
+ }
+ return FALSE;
+}
+
+
/* policyCondemnChain -- condemn approriate parts of this chain
*
* This is only called if ChainDeferral returned a value sufficiently
From 0a927608dc6bbf4141bcc81e2d768b923767048d Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 16:02:46 +0100
Subject: [PATCH 076/337] Policycollectiontime is now local to policy.c.
Improve comment for policyCondemnChain (document the mortalityReturn parameter to; fix design reference).
Copied from Perforce
Change: 188240
ServerID: perforce.ravenbrook.com
---
mps/code/mpm.h | 1 -
mps/code/policy.c | 59 +++++++++++++++++++++++++----------------------
2 files changed, 31 insertions(+), 29 deletions(-)
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index 2ca05d279e3..94184413647 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -665,7 +665,6 @@ extern Bool PolicyShouldCollectWorld(Arena arena, double interval,
double multiplier, Clock now,
Clock clocks_per_sec);
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);
diff --git a/mps/code/policy.c b/mps/code/policy.c
index 48cd3d722c1..a71ce120307 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -122,6 +122,31 @@ Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
}
+/* policyCollectionTime -- estimate time to collect the world, in seconds */
+
+static double policyCollectionTime(Arena arena)
+{
+ Size collectableSize;
+ double collectionRate;
+ double collectionTime;
+
+ AVERT(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;
+ else
+ collectionRate = ARENA_DEFAULT_COLLECTION_RATE;
+ collectionTime = collectableSize / collectionRate;
+ collectionTime += ARENA_DEFAULT_COLLECTION_OVERHEAD;
+
+ return collectionTime;
+}
+
+
/* PolicyShouldCollectWorld -- should we collect the world now?
*
* Return TRUE if we should try collecting the world now, FALSE if
@@ -144,7 +169,7 @@ Bool PolicyShouldCollectWorld(Arena arena, double interval, double multiplier,
Size collectableSize = ArenaCollectable(arena);
if (collectableSize > ARENA_MINIMUM_COLLECTABLE_SIZE) {
/* how long would it take to collect the world? */
- double collectionTime = PolicyCollectionTime(arena);
+ double collectionTime = policyCollectionTime(arena);
/* how long since we last collected the world? */
double sinceLastWorldCollect = ((now - arena->lastWorldCollect) /
@@ -162,10 +187,13 @@ Bool PolicyShouldCollectWorld(Arena arena, double interval, double multiplier,
/* policyCondemnChain -- condemn approriate parts of this chain
+ *
+ * If successful, set *mortalityReturn to an estimate of the mortality
+ * of the condemned parts of this chain and return ResOK.
*
* This is only called if ChainDeferral returned a value sufficiently
- * low that the tracer decided to start the collection. (Usually
- * such values are less than zero; see )
+ * low that we decided to start the collection. (Usually such values
+ * are less than zero; see .)
*/
static Res policyCondemnChain(double *mortalityReturn, Chain chain, Trace trace)
@@ -306,31 +334,6 @@ Bool PolicyStartTrace(Trace *traceReturn, Arena arena)
}
-/* PolicyCollectionTime -- estimate time to collect the world, in seconds */
-
-double PolicyCollectionTime(Arena arena)
-{
- Size collectableSize;
- double collectionRate;
- double collectionTime;
-
- AVERT(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;
- else
- collectionRate = ARENA_DEFAULT_COLLECTION_RATE;
- collectionTime = collectableSize / collectionRate;
- collectionTime += ARENA_DEFAULT_COLLECTION_OVERHEAD;
-
- return collectionTime;
-}
-
-
/* PolicyPoll -- do some tracing work?
*
* Return TRUE if the MPS should do some tracing work; FALSE if it
From 3e84e14f00f714e64addf4a9bbfabc53bf2da1c0 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 16:04:42 +0100
Subject: [PATCH 077/337] Improve design.mps.strategy based on nb's review
comments
Copied from Perforce
Change: 188242
ServerID: perforce.ravenbrook.com
---
mps/design/strategy.txt | 81 ++++++++++++++++++++++++++++-------------
1 file changed, 55 insertions(+), 26 deletions(-)
diff --git a/mps/design/strategy.txt b/mps/design/strategy.txt
index f96aaae17cb..695813bed87 100644
--- a/mps/design/strategy.txt
+++ b/mps/design/strategy.txt
@@ -145,23 +145,11 @@ Collections
Collections in the MPS start in one of two ways:
-1. A collection of the world starts via ``traceCondemnAll()``. This
- simply condemns all segments in all automatic pools.
+1. A collection of the world starts via ``TraceStartCollectAll()``.
+ This simply condemns all segments in all automatic pools.
-2. A collection of some set of generations starts via ``TracePoll()``.
- This calls ``ChainDeferral()`` for each chain; this function
- indicates if the chain needs collecting, and if so, how urgent it
- is to collect that chain. The most urgent chain in need of
- collection (if any) is then condemned by calling
- ``policyCondemnChain()``.
-
- This function chooses the set of generations to condemn, computes
- the zoneset corresponding to the union those generations, and
- condemns those zones by calling ``TraceCondemnZones()``.
-
- Note that the condemnation is of every segment in an automatic pool
- in any zone in the zoneset. It is not limited to the segments
- actually associated with the condemned generations.
+2. A collection of some set of generations starts via
+ ``PolicyStartTrace()``. See `.policy.start`_.
Zones
@@ -216,11 +204,11 @@ categories of data allocated in that generation for that pool. This
accounting information is reported via the event system, but also used
in two places:
-_`.accounting.poll`: ``ChainDeferral()`` uses the *new size* of each
-generation to determine which generations in the chain are over
-capacity and so might need to be collected via ``TracePoll()``.
+_`.accounting.poll`: ``ChainDeferral()`` uses the *new size* of
+each generation to determine which generations in the chain are over
+capacity and so might need to be collected by ``PolicyStartTrace()``.
-_`.accounting.condemn`: ``policyCondemnChain()`` uses the *new size* of
+_`.accounting.condemn`: ``PolicyStartTrace()`` uses the *new size* of
each generation to determine which generations in the chain will be
collected; it also uses the *total size* of the generation to compute
the mortality.
@@ -450,11 +438,11 @@ successful, update ``*tractReturn`` to point to the first tract in the
allocated memory and return ``ResOK``. Otherwise, return a result code
describing the problem, for example ``ResCOMMIT_LIMIT``.
-_`.policy.alloc.plan`: This tries various plans in succession until
+_`.policy.alloc.impl`: This tries various methods in succession until
one succeeds. First, it tries to allocate from the arena's free land
in the requested zones. Second, it tries allocating from free zones.
Third, it tries extending the arena and then trying the first two
-plans again. Fourth, it tries allocating from any zone that is not
+methods again. Fourth, it tries allocating from any zone that is not
blacklisted. Fifth, it tries allocating from any zone at all.
_`.policy.alloc.issue`: This plan performs poorly under stress. See
@@ -464,6 +452,28 @@ for example job003898_.
+Deciding whether to collect the world
+.....................................
+
+``Bool PolicyShouldCollectWorld(Arena arena, double interval, double multiplier, Clock now, Clock clocks_per_sec)``
+
+_`.policy.world`: Determine whether now is a good time for
+``mps_arena_step()`` to start a collection of the world. Return
+``TRUE`` if so, ``FALSE`` if not. The ``interval`` and ``multiplier``
+arguments are the ones the client program passed to
+``mps_arena_step()``, ``now`` is the current time as returned by
+``ClockNow()``, and ``clocks_per_sec`` is the result of calling
+``ClocksPerSec()``.
+
+_`.policy.world.impl`: There are two conditions: the client program's
+estimate of the available time must be enough to complete the
+collection, and the last collection of the world must be long enough
+in the past that the ``mps_arena_step()`` won't be spending more than
+a certain fraction of runtime in collections. (This fraction is given
+by the ``ARENA_MAX_COLLECT_FRACTION`` configuration parameter.)
+
+
+
Starting a trace
................
@@ -474,10 +484,29 @@ update ``*traceReturn`` to point to the trace and return TRUE.
Otherwise, leave ``*traceReturn`` unchanged and return FALSE.
_`.policy.start.impl`: This uses the "Lisp Machine" strategy, which
-tries to schedule collections so that the collector just keeps pace
-with the mutator: that is, it starts a collection when the predicted
-completion time of the collection is around the time when the mutator
-is predicted to reach the current memory limit. See [Pirinen]_.
+tries to schedule collections of the world so that the collector just
+keeps pace with the mutator: that is, it starts a collection when the
+predicted completion time of the collection is around the time when
+the mutator is predicted to reach the current memory limit. See
+[Pirinen]_.
+
+_`.policy.start.chain`: If it is not yet time to schedule a collection
+of the world, ``PolicyStartTrace()`` considers collecting a set of
+zones corresponding to a set of generations on a chain.
+
+It picks these generations by calling ``ChainDeferral()`` for each
+chain; this function indicates if the chain needs collecting, and if
+so, how urgent it is to collect that chain. The most urgent chain in
+need of collection (if any) is then condemned by calling
+``policyCondemnChain()``, which chooses the set of generations to
+condemn, computes the zoneset corresponding to the union those
+generations, and condemns those zones by calling
+``TraceCondemnZones()``.
+
+Note that the resulting condemned set includes every segment in an
+automatic pool in any zone in the zoneset. It is not limited to the
+segments actually associated with the condemned generations.
+
Trace progress
From 87fabe9ef036575a796b5fa9d0ae75c44a7bd90a Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 16:51:33 +0100
Subject: [PATCH 078/337] Correct the manual about the assertion you get when
destroying a pool without destroying all the allocation points first.
Copied from Perforce
Change: 188243
ServerID: perforce.ravenbrook.com
---
mps/manual/source/topic/error.rst | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst
index e13e79a9735..784533d66fa 100644
--- a/mps/manual/source/topic/error.rst
+++ b/mps/manual/source/topic/error.rst
@@ -304,8 +304,15 @@ this documentation.
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.
+ arena, or it destroyed a thread without first destroying all
+ roots using that thread.
+
+
+``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``
From bf57e7bc11163838051a812f221c795183595acc Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 16:51:59 +0100
Subject: [PATCH 079/337] First draft of tagged pointer test case (runs, but
doesn't test anything yet).
Copied from Perforce
Change: 188244
ServerID: perforce.ravenbrook.com
---
mps/code/comm.gmk | 4 +
mps/code/comm.nmk | 4 +
mps/code/mpsicv.c | 17 ++--
mps/code/tagtest.c | 197 +++++++++++++++++++++++++++++++++++++++++
mps/tool/testcases.txt | 1 +
5 files changed, 218 insertions(+), 5 deletions(-)
create mode 100644 mps/code/tagtest.c
diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk
index c82caa4576e..f00e636ea08 100644
--- a/mps/code/comm.gmk
+++ b/mps/code/comm.gmk
@@ -283,6 +283,7 @@ TEST_TARGETS=\
sacss \
segsmss \
steptest \
+ tagtest \
teletest \
walkt0 \
zcoll \
@@ -510,6 +511,9 @@ $(PFM)/$(VARIETY)/sacss: $(PFM)/$(VARIETY)/sacss.o \
$(PFM)/$(VARIETY)/segsmss: $(PFM)/$(VARIETY)/segsmss.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
+$(PFM)/$(VARIETY)/tagtest: $(PFM)/$(VARIETY)/tagtest.o \
+ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
+
$(PFM)/$(VARIETY)/teletest: $(PFM)/$(VARIETY)/teletest.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
diff --git a/mps/code/comm.nmk b/mps/code/comm.nmk
index a59132ff354..523a6831ec5 100644
--- a/mps/code/comm.nmk
+++ b/mps/code/comm.nmk
@@ -94,6 +94,7 @@ TEST_TARGETS=\
sacss.exe \
segsmss.exe \
steptest.exe \
+ tagtest.exe \
teletest.exe \
walkt0.exe \
zcoll.exe \
@@ -610,6 +611,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/mpsicv.c b/mps/code/mpsicv.c
index a6b23f00578..80085d2f8ad 100644
--- a/mps/code/mpsicv.c
+++ b/mps/code/mpsicv.c
@@ -591,11 +591,18 @@ int main(int argc, char *argv[])
"arena_create");
die(mps_thread_reg(&thread, arena), "thread_reg");
- die(mps_root_create_reg(®_root, arena,
- mps_rank_ambig(), (mps_rm_t)0,
- thread, &mps_stack_scan_ambig,
- marker, (size_t)0),
- "root_create_reg");
+ if (rnd() % 2) {
+ die(mps_root_create_reg(®_root, arena,
+ mps_rank_ambig(), (mps_rm_t)0,
+ thread, &mps_stack_scan_ambig,
+ marker, (size_t)0),
+ "root_create_reg");
+ } else {
+ die(mps_root_create_reg_masked(®_root, arena,
+ mps_rank_ambig(), (mps_rm_t)0,
+ thread, 0, 0, marker),
+ "root_create_reg_masked");
+ }
mps_tramp(&r, test, arena, 0);
mps_root_destroy(reg_root);
diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c
new file mode 100644
index 00000000000..4da62f01c80
--- /dev/null
+++ b/mps/code/tagtest.c
@@ -0,0 +1,197 @@
+/* tagtest.c: TAGGED POINTER TEST
+ *
+ * $Id$
+ * Copyright (c) 2015 Ravenbrook Limited. See end of file for license.
+ *
+ * .overview: This test case checks that the MPS correctly handles
+ * tagged pointers via the object format and via stack and register
+ * scanning.
+ */
+
+#include /* printf */
+
+#include "mps.h"
+#include "mpsavm.h"
+#include "mpscamc.h"
+#include "testlib.h"
+
+typedef struct cons_s {
+ mps_word_t car, cdr;
+} cons_s, *cons_t;
+
+typedef mps_word_t imm_t; /* Immediate value. */
+typedef mps_word_t fwd_t; /* Fowarding pointer. */
+
+static size_t tag_bits = 3; /* Number of tag bits */
+static mps_word_t tag_cons = 5; /* Tag bits indicating pointer to cons */
+static mps_word_t tag_fwd = 2; /* Tag bits indicating forwarding pointer */
+static mps_word_t tag_imm = 6; /* Tag bits indicating immediate value */
+
+#define TAG_MASK ((((mps_word_t)1 << tag_bits) - 1))
+#define TAG(word) ((mps_word_t)(word) & TAG_MASK)
+#define TAGGED(value, type) (((mps_word_t)(value) & ~TAG_MASK) + tag_ ## type)
+#define UNTAGGED(word, type) ((type ## _t)((mps_word_t)(word) & ~TAG_MASK))
+
+static mps_word_t cons(mps_ap_t ap, mps_word_t car, mps_word_t cdr)
+{
+ cons_t obj;
+ mps_addr_t addr;
+ size_t size = sizeof(cons_s);
+ do {
+ mps_res_t res = mps_reserve(&addr, ap, size);
+ if (res != MPS_RES_OK) error("out of memory in cons");
+ obj = addr;
+ obj->car = car;
+ obj->cdr = cdr;
+ } while (!mps_commit(ap, addr, size));
+ return TAGGED(obj, cons);
+}
+
+static void fwd(mps_addr_t old, mps_addr_t new)
+{
+ cons_t cons;
+ Insist(TAG(old) == tag_cons);
+ cons = UNTAGGED(old, cons);
+ cons->car = TAGGED(0, fwd);
+ cons->cdr = (mps_word_t)new;
+}
+
+static mps_addr_t isfwd(mps_addr_t addr)
+{
+ cons_t cons;
+ if (TAG(addr) != tag_cons)
+ return NULL;
+ cons = UNTAGGED(addr, cons);
+ if (TAG(cons->car) != tag_fwd)
+ return NULL;
+ return (mps_addr_t)cons->cdr;
+}
+
+static void pad(mps_addr_t addr, size_t size)
+{
+ mps_word_t *word = addr;
+ mps_word_t *limit = (mps_word_t *)((char *)addr + size);
+ while (word < limit) {
+ *word = TAGGED(0, imm);
+ ++ word;
+ }
+}
+
+static mps_res_t scan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
+{
+ MPS_SCAN_BEGIN(ss) {
+ while (base < limit) {
+ mps_word_t *word = base;
+ if (MPS_FIX1(ss, *word)) {
+ mps_word_t tag = TAG(*word);
+ if (tag == tag_cons) {
+ mps_addr_t addr = UNTAGGED(*word, cons);
+ mps_res_t res = MPS_FIX2(ss, &addr);
+ if (res != MPS_RES_OK)
+ return res;
+ *word = TAGGED(addr, cons);
+ }
+ base = (mps_addr_t)((char *)base + sizeof(cons_s));
+ }
+ }
+ } MPS_SCAN_END(ss);
+ return MPS_RES_OK;
+}
+
+static mps_addr_t skip(mps_addr_t addr)
+{
+ return (mps_addr_t)((char *)addr + sizeof(cons_s));
+}
+
+int main(int argc, char *argv[])
+{
+ void *marker = ▮
+ mps_arena_t arena;
+ mps_thr_t thread;
+ mps_root_t root;
+ mps_fmt_t fmt;
+ mps_pool_t pool;
+ mps_ap_t ap;
+ mps_word_t nil = TAGGED(NULL, cons);
+
+ testlib_init(argc, argv);
+
+ die(mps_arena_create(&arena, mps_arena_class_vm(), mps_args_none), "arena");
+ die(mps_thread_reg(&thread, arena), "thread");
+
+ die(mps_root_create_reg_masked(&root, arena, mps_rank_ambig(), 0, thread,
+ TAG_MASK, tag_cons, marker), "root");
+
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_FMT_HEADER_SIZE, tag_cons);
+ MPS_ARGS_ADD(args, MPS_KEY_FMT_ALIGN, sizeof(cons_s));
+ MPS_ARGS_ADD(args, MPS_KEY_FMT_SCAN, scan);
+ MPS_ARGS_ADD(args, MPS_KEY_FMT_SKIP, skip);
+ MPS_ARGS_ADD(args, MPS_KEY_FMT_FWD, fwd);
+ MPS_ARGS_ADD(args, MPS_KEY_FMT_ISFWD, isfwd);
+ MPS_ARGS_ADD(args, MPS_KEY_FMT_PAD, pad);
+ die(mps_fmt_create_k(&fmt, arena, args), "fmt");
+ } MPS_ARGS_END(args);
+
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt);
+ die(mps_pool_create_k(&pool, arena, mps_class_amc(), args), "pool");
+ } MPS_ARGS_END(args);
+
+ die(mps_ap_create_k(&ap, pool, mps_args_none), "ap");
+
+ cons(ap, nil, nil);
+
+ mps_arena_park(arena);
+ mps_ap_destroy(ap);
+ mps_pool_destroy(pool);
+ mps_fmt_destroy(fmt);
+ mps_root_destroy(root);
+ mps_thread_dereg(thread);
+ mps_arena_destroy(arena);
+
+ printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
+ return 0;
+}
+
+
+/* C. COPYRIGHT AND LICENSE
+ *
+ * Copyright (c) 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:
+ *
+ * 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..b867b67acfc 100644
--- a/mps/tool/testcases.txt
+++ b/mps/tool/testcases.txt
@@ -38,6 +38,7 @@ qs
sacss
segsmss
steptest =P
+tagtest
teletest =N interactive
walkt0
zcoll =L
From 9b247d33ce3dd2b9610d8d1cd086e398d1f85401 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 18:47:16 +0100
Subject: [PATCH 080/337] Avoid "declaration of 'cons' shadows a global
declaration" error from gcc.
Copied from Perforce
Change: 188248
ServerID: perforce.ravenbrook.com
---
mps/code/tagtest.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c
index 4da62f01c80..e1dfb5d5e8a 100644
--- a/mps/code/tagtest.c
+++ b/mps/code/tagtest.c
@@ -32,7 +32,7 @@ static mps_word_t tag_imm = 6; /* Tag bits indicating immediate value */
#define TAGGED(value, type) (((mps_word_t)(value) & ~TAG_MASK) + tag_ ## type)
#define UNTAGGED(word, type) ((type ## _t)((mps_word_t)(word) & ~TAG_MASK))
-static mps_word_t cons(mps_ap_t ap, mps_word_t car, mps_word_t cdr)
+static mps_word_t make_cons(mps_ap_t ap, mps_word_t car, mps_word_t cdr)
{
cons_t obj;
mps_addr_t addr;
@@ -140,7 +140,7 @@ int main(int argc, char *argv[])
die(mps_ap_create_k(&ap, pool, mps_args_none), "ap");
- cons(ap, nil, nil);
+ make_cons(ap, nil, nil);
mps_arena_park(arena);
mps_ap_destroy(ap);
From 6521d927eb562923349731311ed2a2dde115e434 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 20:15:36 +0100
Subject: [PATCH 081/337] Add accesssetcheck and check accessset arguments.
Copied from Perforce
Change: 188251
ServerID: perforce.ravenbrook.com
---
mps/code/mpm.c | 14 ++++++++++++--
mps/code/mpm.h | 5 +++--
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/shield.c | 7 +++++--
mps/code/trace.c | 5 +++--
11 files changed, 45 insertions(+), 28 deletions(-)
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 a5ac16b41a2..b8cb8c250ee 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 */
@@ -1052,7 +1053,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/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/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.
From 3ef063c80fcc44fd8a67c75ef96c2587fafc8e66 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 22:28:40 +0100
Subject: [PATCH 082/337] 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 2435b9949a56aaaec5125e5f14507b815b3533d8 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Fri, 4 Sep 2015 22:35:03 +0100
Subject: [PATCH 083/337] 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 48465209a2db2a0acfc43ba8a6c2dc83c84906ba Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 7 Sep 2015 12:40:10 +0100
Subject: [PATCH 084/337] Complete test case.
Copied from Perforce
Change: 188264
ServerID: perforce.ravenbrook.com
---
mps/code/tagtest.c | 134 +++++++++++++++++++++++++++++++++++++--------
1 file changed, 110 insertions(+), 24 deletions(-)
diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c
index e1dfb5d5e8a..ed8e6deea60 100644
--- a/mps/code/tagtest.c
+++ b/mps/code/tagtest.c
@@ -15,19 +15,30 @@
#include "mpscamc.h"
#include "testlib.h"
+#define OBJCOUNT (1000) /* Number of conses to allocate */
+
+enum {
+ MODE_DEFAULT, /* Use default scanner (tagged with 0). */
+ MODE_CONS, /* Scan words tagged "cons". */
+ MODE_INVALID, /* Scan words tagged "invalid". */
+ MODE_LIMIT
+};
+
typedef struct cons_s {
mps_word_t car, cdr;
} cons_s, *cons_t;
-typedef mps_word_t imm_t; /* Immediate value. */
-typedef mps_word_t fwd_t; /* Fowarding pointer. */
+typedef mps_word_t imm_t; /* Immediate value. */
+typedef mps_word_t fwd_t; /* Fowarding pointer. */
-static size_t tag_bits = 3; /* Number of tag bits */
-static mps_word_t tag_cons = 5; /* Tag bits indicating pointer to cons */
-static mps_word_t tag_fwd = 2; /* Tag bits indicating forwarding pointer */
-static mps_word_t tag_imm = 6; /* Tag bits indicating immediate value */
+static mps_word_t tag_cons; /* Tag bits indicating pointer to cons */
+static mps_word_t tag_fwd; /* Tag bits indicating forwarding pointer */
+static mps_word_t tag_imm; /* Tag bits indicating immediate value */
+static mps_word_t tag_invalid; /* Invalid tag bits */
-#define TAG_MASK ((((mps_word_t)1 << tag_bits) - 1))
+#define TAG_BITS (3) /* Number of tag bits */
+#define TAG_COUNT ((mps_word_t)1 << TAG_BITS) /* Number of distinct tags */
+#define TAG_MASK (TAG_COUNT - 1) /* Tag mask */
#define TAG(word) ((mps_word_t)(word) & TAG_MASK)
#define TAGGED(value, type) (((mps_word_t)(value) & ~TAG_MASK) + tag_ ## type)
#define UNTAGGED(word, type) ((type ## _t)((mps_word_t)(word) & ~TAG_MASK))
@@ -58,7 +69,7 @@ static void fwd(mps_addr_t old, mps_addr_t new)
static mps_addr_t isfwd(mps_addr_t addr)
{
- cons_t cons;
+ cons_t cons;
if (TAG(addr) != tag_cons)
return NULL;
cons = UNTAGGED(addr, cons);
@@ -77,22 +88,27 @@ static void pad(mps_addr_t addr, size_t size)
}
}
-static mps_res_t scan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
+static mps_res_t scan(mps_ss_t ss, mps_addr_t client_base,
+ mps_addr_t client_limit)
{
+ mps_addr_t *base, *limit;
+ Insist(TAG(client_base) == tag_cons);
+ Insist(TAG(client_limit) == tag_cons);
+ base = (mps_addr_t *)UNTAGGED(client_base, cons);
+ limit = (mps_addr_t *)UNTAGGED(client_limit, cons);
MPS_SCAN_BEGIN(ss) {
while (base < limit) {
- mps_word_t *word = base;
- if (MPS_FIX1(ss, *word)) {
- mps_word_t tag = TAG(*word);
+ if (MPS_FIX1(ss, *base)) {
+ mps_addr_t addr = *base;
+ mps_word_t tag = TAG(addr);
if (tag == tag_cons) {
- mps_addr_t addr = UNTAGGED(*word, cons);
mps_res_t res = MPS_FIX2(ss, &addr);
if (res != MPS_RES_OK)
return res;
- *word = TAGGED(addr, cons);
+ *base = addr;
}
- base = (mps_addr_t)((char *)base + sizeof(cons_s));
}
+ ++base;
}
} MPS_SCAN_END(ss);
return MPS_RES_OK;
@@ -103,9 +119,8 @@ static mps_addr_t skip(mps_addr_t addr)
return (mps_addr_t)((char *)addr + sizeof(cons_s));
}
-int main(int argc, char *argv[])
+static void test(int mode, void *marker)
{
- void *marker = ▮
mps_arena_t arena;
mps_thr_t thread;
mps_root_t root;
@@ -113,14 +128,37 @@ int main(int argc, char *argv[])
mps_pool_t pool;
mps_ap_t ap;
mps_word_t nil = TAGGED(NULL, cons);
-
- testlib_init(argc, argv);
+ mps_word_t i, p;
+ size_t finalized = 0;
+ size_t expected_finalized;
die(mps_arena_create(&arena, mps_arena_class_vm(), mps_args_none), "arena");
+ mps_message_type_enable(arena, mps_message_type_finalization());
die(mps_thread_reg(&thread, arena), "thread");
- die(mps_root_create_reg_masked(&root, arena, mps_rank_ambig(), 0, thread,
- TAG_MASK, tag_cons, marker), "root");
+ switch (mode) {
+ case MODE_DEFAULT:
+ /* Default stack scanner only recognizes words tagged with 0. */
+ die(mps_root_create_reg(&root, arena, mps_rank_ambig(), 0, thread,
+ mps_stack_scan_ambig, marker, 0), "root");
+ expected_finalized = (tag_cons != 0) * OBJCOUNT;
+ break;
+ case MODE_CONS:
+ /* Scan words tagged "cons" -- everything will live. */
+ die(mps_root_create_reg_masked(&root, arena, mps_rank_ambig(), 0, thread,
+ TAG_MASK, tag_cons, marker), "root");
+ expected_finalized = 0;
+ break;
+ case MODE_INVALID:
+ /* Scan words tagged "invalid" -- everything will die. */
+ die(mps_root_create_reg_masked(&root, arena, mps_rank_ambig(), 0, thread,
+ TAG_MASK, tag_invalid, marker), "root");
+ expected_finalized = OBJCOUNT;
+ break;
+ default:
+ Insist(0);
+ break;
+ }
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_FMT_HEADER_SIZE, tag_cons);
@@ -139,9 +177,28 @@ int main(int argc, char *argv[])
} MPS_ARGS_END(args);
die(mps_ap_create_k(&ap, pool, mps_args_none), "ap");
-
- make_cons(ap, nil, nil);
-
+
+ p = nil;
+ for (i = 0; i < OBJCOUNT; ++i) {
+ mps_addr_t addr;
+ p = make_cons(ap, TAGGED(i << TAG_BITS, imm), p);
+ Insist(TAG(p) == tag_cons);
+ addr = (mps_addr_t)p;
+ die(mps_finalize(arena, &addr), "finalize");
+ }
+
+ mps_arena_collect(arena);
+ while (mps_message_poll(arena)) {
+ mps_message_t message;
+ mps_addr_t objaddr;
+ cdie(mps_message_get(&message, arena, mps_message_type_finalization()),
+ "message_get");
+ mps_message_finalization_ref(&objaddr, arena, message);
+ mps_message_discard(arena, message);
+ ++ finalized;
+ }
+ Insist(finalized == expected_finalized);
+
mps_arena_park(arena);
mps_ap_destroy(ap);
mps_pool_destroy(pool);
@@ -149,6 +206,35 @@ int main(int argc, char *argv[])
mps_root_destroy(root);
mps_thread_dereg(thread);
mps_arena_destroy(arena);
+}
+
+int main(int argc, char *argv[])
+{
+ void *marker = ▮
+ mps_word_t tags[TAG_COUNT];
+ size_t i;
+ int mode;
+
+ testlib_init(argc, argv);
+
+ /* Shuffle the tags. */
+ for (i = 0; i < NELEMS(tags); ++i) {
+ tags[i] = i;
+ }
+ for (i = 0; i < NELEMS(tags); ++i) {
+ size_t j = i + rnd() % (NELEMS(tags) - i);
+ mps_word_t t = tags[i];
+ tags[i] = tags[j];
+ tags[j] = t;
+ }
+ tag_cons = tags[0];
+ tag_fwd = tags[1];
+ tag_imm = tags[2];
+ tag_invalid = tags[3];
+
+ for (mode = 0; mode < MODE_LIMIT; ++mode) {
+ test(mode, marker);
+ }
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
return 0;
From ee40fbe0342f1ce735185b7563ccb5f7e2dbc2df Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 7 Sep 2015 14:23:55 +0100
Subject: [PATCH 085/337] Prevent compiler inlining which defeats the test.
Copied from Perforce
Change: 188268
ServerID: perforce.ravenbrook.com
---
mps/code/tagtest.c | 66 +++++++++++++++++++++++++++++++++-------------
mps/code/testlib.h | 4 +++
2 files changed, 52 insertions(+), 18 deletions(-)
diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c
index ed8e6deea60..d2dc556a851 100644
--- a/mps/code/tagtest.c
+++ b/mps/code/tagtest.c
@@ -17,13 +17,6 @@
#define OBJCOUNT (1000) /* Number of conses to allocate */
-enum {
- MODE_DEFAULT, /* Use default scanner (tagged with 0). */
- MODE_CONS, /* Scan words tagged "cons". */
- MODE_INVALID, /* Scan words tagged "invalid". */
- MODE_LIMIT
-};
-
typedef struct cons_s {
mps_word_t car, cdr;
} cons_s, *cons_t;
@@ -119,6 +112,44 @@ static mps_addr_t skip(mps_addr_t addr)
return (mps_addr_t)((char *)addr + sizeof(cons_s));
}
+
+/* alloc_list -- Allocate a linked list with 'count' entries. The
+ * attribute prevents the compiler from inlining this function into
+ * test, which might leave untagged temporaries on the stack,
+ * confusing the test logic.
+ */
+
+ATTRIBUTE_NOINLINE
+static mps_word_t alloc_list(mps_arena_t arena, mps_ap_t ap, size_t count)
+{
+ mps_word_t nil = TAGGED(NULL, cons);
+ mps_word_t p = nil;
+ size_t i;
+ for (i = 0; i < count; ++i) {
+ mps_addr_t addr;
+ p = make_cons(ap, TAGGED(i << TAG_BITS, imm), p);
+ Insist(TAG(p) == tag_cons);
+ addr = (mps_addr_t)p;
+ die(mps_finalize(arena, &addr), "finalize");
+ }
+ return p;
+}
+
+
+/* test -- Run the test case in the specified mode. The attribute
+ * prevents the compiler from inlining this function into main, which
+ * might end up with stack slots like 'p' being above 'marker' and so
+ * not scanned.
+ */
+
+enum {
+ MODE_DEFAULT, /* Use default scanner (tagged with 0). */
+ MODE_CONS, /* Scan words tagged "cons". */
+ MODE_INVALID, /* Scan words tagged "invalid". */
+ MODE_LIMIT
+};
+
+ATTRIBUTE_NOINLINE
static void test(int mode, void *marker)
{
mps_arena_t arena;
@@ -127,10 +158,10 @@ static void test(int mode, void *marker)
mps_fmt_t fmt;
mps_pool_t pool;
mps_ap_t ap;
- mps_word_t nil = TAGGED(NULL, cons);
- mps_word_t i, p;
+ mps_word_t p;
+ size_t i;
size_t finalized = 0;
- size_t expected_finalized;
+ size_t expected_finalized = 0;
die(mps_arena_create(&arena, mps_arena_class_vm(), mps_args_none), "arena");
mps_message_type_enable(arena, mps_message_type_finalization());
@@ -178,14 +209,7 @@ static void test(int mode, void *marker)
die(mps_ap_create_k(&ap, pool, mps_args_none), "ap");
- p = nil;
- for (i = 0; i < OBJCOUNT; ++i) {
- mps_addr_t addr;
- p = make_cons(ap, TAGGED(i << TAG_BITS, imm), p);
- Insist(TAG(p) == tag_cons);
- addr = (mps_addr_t)p;
- die(mps_finalize(arena, &addr), "finalize");
- }
+ p = alloc_list(arena, ap, OBJCOUNT);
mps_arena_collect(arena);
while (mps_message_poll(arena)) {
@@ -194,10 +218,16 @@ static void test(int mode, void *marker)
cdie(mps_message_get(&message, arena, mps_message_type_finalization()),
"message_get");
mps_message_finalization_ref(&objaddr, arena, message);
+ Insist(TAG(objaddr) == tag_cons);
mps_message_discard(arena, message);
++ finalized;
}
+
Insist(finalized == expected_finalized);
+ for (i = 0; i < OBJCOUNT - expected_finalized; ++i) {
+ Insist(TAG(p) == tag_cons);
+ p = UNTAGGED(p, cons)->cdr;
+ }
mps_arena_park(arena);
mps_ap_destroy(ap);
diff --git a/mps/code/testlib.h b/mps/code/testlib.h
index 6f059abcbb9..0b5b7160165 100644
--- a/mps/code/testlib.h
+++ b/mps/code/testlib.h
@@ -47,9 +47,13 @@
*/
#define ATTRIBUTE_FORMAT(ARGLIST) __attribute__((__format__ ARGLIST))
+/* GCC: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html */
+#define ATTRIBUTE_NOINLINE __attribute__((__noinline__))
+
#else
#define ATTRIBUTE_FORMAT(ARGLIST)
+#define ATTRIBUTE_NOINLINE
#endif
From 0af0dc11ba8f758dc25cf169a0061a90aa3b71fb Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 7 Sep 2015 15:00:28 +0100
Subject: [PATCH 086/337] Number of tag bits has to depend on the word size.
Copied from Perforce
Change: 188270
ServerID: perforce.ravenbrook.com
---
mps/code/tagtest.c | 36 ++++++++++++++++++++++--------------
1 file changed, 22 insertions(+), 14 deletions(-)
diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c
index d2dc556a851..c1c74052cf4 100644
--- a/mps/code/tagtest.c
+++ b/mps/code/tagtest.c
@@ -8,8 +8,10 @@
* scanning.
*/
-#include /* printf */
+#include /* CHAR_BIT */
+#include /* printf */
+#include "mpm.h"
#include "mps.h"
#include "mpsavm.h"
#include "mpscamc.h"
@@ -24,13 +26,13 @@ typedef struct cons_s {
typedef mps_word_t imm_t; /* Immediate value. */
typedef mps_word_t fwd_t; /* Fowarding pointer. */
+static mps_word_t tag_bits; /* Number of tag bits */
static mps_word_t tag_cons; /* Tag bits indicating pointer to cons */
static mps_word_t tag_fwd; /* Tag bits indicating forwarding pointer */
static mps_word_t tag_imm; /* Tag bits indicating immediate value */
static mps_word_t tag_invalid; /* Invalid tag bits */
-#define TAG_BITS (3) /* Number of tag bits */
-#define TAG_COUNT ((mps_word_t)1 << TAG_BITS) /* Number of distinct tags */
+#define TAG_COUNT ((mps_word_t)1 << tag_bits) /* Number of distinct tags */
#define TAG_MASK (TAG_COUNT - 1) /* Tag mask */
#define TAG(word) ((mps_word_t)(word) & TAG_MASK)
#define TAGGED(value, type) (((mps_word_t)(value) & ~TAG_MASK) + tag_ ## type)
@@ -127,7 +129,7 @@ static mps_word_t alloc_list(mps_arena_t arena, mps_ap_t ap, size_t count)
size_t i;
for (i = 0; i < count; ++i) {
mps_addr_t addr;
- p = make_cons(ap, TAGGED(i << TAG_BITS, imm), p);
+ p = make_cons(ap, TAGGED(i << tag_bits, imm), p);
Insist(TAG(p) == tag_cons);
addr = (mps_addr_t)p;
die(mps_finalize(arena, &addr), "finalize");
@@ -161,7 +163,7 @@ static void test(int mode, void *marker)
mps_word_t p;
size_t i;
size_t finalized = 0;
- size_t expected_finalized = 0;
+ size_t expected = 0;
die(mps_arena_create(&arena, mps_arena_class_vm(), mps_args_none), "arena");
mps_message_type_enable(arena, mps_message_type_finalization());
@@ -172,19 +174,19 @@ static void test(int mode, void *marker)
/* Default stack scanner only recognizes words tagged with 0. */
die(mps_root_create_reg(&root, arena, mps_rank_ambig(), 0, thread,
mps_stack_scan_ambig, marker, 0), "root");
- expected_finalized = (tag_cons != 0) * OBJCOUNT;
+ expected = (tag_cons != 0) * OBJCOUNT;
break;
case MODE_CONS:
/* Scan words tagged "cons" -- everything will live. */
die(mps_root_create_reg_masked(&root, arena, mps_rank_ambig(), 0, thread,
TAG_MASK, tag_cons, marker), "root");
- expected_finalized = 0;
+ expected = 0;
break;
case MODE_INVALID:
/* Scan words tagged "invalid" -- everything will die. */
die(mps_root_create_reg_masked(&root, arena, mps_rank_ambig(), 0, thread,
TAG_MASK, tag_invalid, marker), "root");
- expected_finalized = OBJCOUNT;
+ expected = OBJCOUNT;
break;
default:
Insist(0);
@@ -210,6 +212,8 @@ static void test(int mode, void *marker)
die(mps_ap_create_k(&ap, pool, mps_args_none), "ap");
p = alloc_list(arena, ap, OBJCOUNT);
+ printf("tag_cons=%lu &p=%p expected=%lu\n",
+ (unsigned long)tag_cons, (void*)&p, (unsigned long)expected);
mps_arena_collect(arena);
while (mps_message_poll(arena)) {
@@ -223,8 +227,8 @@ static void test(int mode, void *marker)
++ finalized;
}
- Insist(finalized == expected_finalized);
- for (i = 0; i < OBJCOUNT - expected_finalized; ++i) {
+ Insist(finalized == expected);
+ for (i = 0; i < OBJCOUNT - expected; ++i) {
Insist(TAG(p) == tag_cons);
p = UNTAGGED(p, cons)->cdr;
}
@@ -241,18 +245,22 @@ static void test(int mode, void *marker)
int main(int argc, char *argv[])
{
void *marker = ▮
- mps_word_t tags[TAG_COUNT];
+ mps_word_t tags[MPS_WORD_WIDTH / CHAR_BIT];
size_t i;
int mode;
testlib_init(argc, argv);
+ /* Work out how many tags to use. */
+ tag_bits = SizeLog2(MPS_WORD_WIDTH / CHAR_BIT);
+ Insist(TAG_COUNT <= NELEMS(tags));
+
/* Shuffle the tags. */
- for (i = 0; i < NELEMS(tags); ++i) {
+ for (i = 0; i < TAG_COUNT; ++i) {
tags[i] = i;
}
- for (i = 0; i < NELEMS(tags); ++i) {
- size_t j = i + rnd() % (NELEMS(tags) - i);
+ for (i = 0; i < TAG_COUNT; ++i) {
+ size_t j = i + rnd() % (TAG_COUNT - i);
mps_word_t t = tags[i];
tags[i] = tags[j];
tags[j] = t;
From 394e052f92c05a0eed62b0a9acb90348b421b07c Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 7 Sep 2015 21:47:49 +0100
Subject: [PATCH 087/337] Avoid char_bit by using sizeof.
Copied from Perforce
Change: 188279
ServerID: perforce.ravenbrook.com
---
mps/code/tagtest.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c
index c1c74052cf4..fa606fe85d7 100644
--- a/mps/code/tagtest.c
+++ b/mps/code/tagtest.c
@@ -8,7 +8,6 @@
* scanning.
*/
-#include /* CHAR_BIT */
#include /* printf */
#include "mpm.h"
@@ -245,14 +244,14 @@ static void test(int mode, void *marker)
int main(int argc, char *argv[])
{
void *marker = ▮
- mps_word_t tags[MPS_WORD_WIDTH / CHAR_BIT];
+ mps_word_t tags[sizeof(mps_word_t)];
size_t i;
int mode;
testlib_init(argc, argv);
/* Work out how many tags to use. */
- tag_bits = SizeLog2(MPS_WORD_WIDTH / CHAR_BIT);
+ tag_bits = SizeLog2(sizeof(mps_word_t));
Insist(TAG_COUNT <= NELEMS(tags));
/* Shuffle the tags. */
From 000df4fd79e46e365b57cfb2c9e6d5c874c6d883 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 8 Sep 2015 16:13:29 +0100
Subject: [PATCH 088/337] Improve documentation of commit limit for a client
arena.
Copied from Perforce
Change: 188285
ServerID: perforce.ravenbrook.com
---
mps/manual/source/topic/arena.rst | 25 ++++++++++++++++---------
1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst
index 106a1a40de2..29d942a29f2 100644
--- a/mps/manual/source/topic/arena.rst
+++ b/mps/manual/source/topic/arena.rst
@@ -155,9 +155,11 @@ Client arenas
It also accepts two optional keyword arguments:
* :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` (type :c:type:`size_t`) is
- the commit limit in :term:`bytes (1)`. See
- :c:func:`mps_arena_commit_limit` for details. The default commit
- limit is the maximum value of the :c:type:`size_t` type.
+ the maximum amount of memory, in :term:`bytes (1)`, that the MPS
+ will use out of the provided chunk (or chunks, if the arena is
+ extended). See :c:func:`mps_arena_commit_limit` for details. The
+ default commit limit is the maximum value of the
+ :c:type:`size_t` type.
* :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` (type :c:type:`size_t`,
default 8192) is the granularity with which the arena will
@@ -256,7 +258,8 @@ Virtual memory arenas
efficient garbage collection will become.
* :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` (type :c:type:`size_t`) is
- the commit limit in :term:`bytes (1)`. See
+ the maximum amount of main memory, in :term:`bytes (1)`, that
+ the MPS will obtain from the operating system. See
:c:func:`mps_arena_commit_limit` for details. The default commit
limit is the maximum value of the :c:type:`size_t` type.
@@ -336,11 +339,15 @@ Arena properties
``arena`` is the arena to return the commit limit for.
- Returns the commit limit in :term:`bytes (1)`. The commit limit
- controls how much main memory the MPS will obtain from the
- operating system. The function :c:func:`mps_arena_committed`
- returns the current committed memory; this never exceeds the
- commit limit.
+ Returns the commit limit in :term:`bytes (1)`.
+
+ For a :term:`client arena`, this this the maximum amount of
+ memory, in :term:`bytes (1)`, that the MPS will use out of the
+ chunks provided by the client to the arena.
+
+ For a :term:`virtual memory arena`, this is the maximum amount of
+ memory that the MPS will map to RAM via the operating system's
+ virtual memory interface.
The commit limit can be changed by passing the
:c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` :term:`keyword argument` to
From 537af4b0dcb4aeb87c90f7b7fec1ea90d07b62d9 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 8 Sep 2015 16:21:27 +0100
Subject: [PATCH 089/337] Rename mps_key_arena_commit_limit and
mps_key_arena_spare_commit_limit as mps_key_commit_limit and
mps_key_spare_commit_limit respectively, as suggested by nb in review.
Copied from Perforce
Change: 188286
ServerID: perforce.ravenbrook.com
---
mps/code/amcss.c | 2 +-
mps/code/amcsshe.c | 2 +-
mps/code/amcssth.c | 2 +-
mps/code/amsss.c | 2 +-
mps/code/apss.c | 2 +-
mps/code/arena.c | 12 ++--
mps/code/locusss.c | 2 +-
mps/code/mps.h | 12 ++--
mps/code/mpsicv.c | 2 +-
mps/manual/source/release.rst | 4 +-
mps/manual/source/topic/arena.rst | 18 +++---
mps/manual/source/topic/deprecated.rst | 2 +-
mps/manual/source/topic/keyword.rst | 78 +++++++++++++-------------
mps/test/function/120.c | 2 +-
mps/test/function/165.c | 8 +--
mps/test/function/231.c | 4 +-
16 files changed, 77 insertions(+), 77 deletions(-)
diff --git a/mps/code/amcss.c b/mps/code/amcss.c
index 83d67dcba58..294ce224b15 100644
--- a/mps/code/amcss.c
+++ b/mps/code/amcss.c
@@ -312,7 +312,7 @@ int main(int argc, char *argv[])
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, scale * testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, grainSize);
- MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, scale * testArenaSIZE);
+ MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, scale * testArenaSIZE);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create");
} MPS_ARGS_END(args);
mps_message_type_enable(arena, mps_message_type_gc());
diff --git a/mps/code/amcsshe.c b/mps/code/amcsshe.c
index adfad3729e5..bd3ea73d068 100644
--- a/mps/code/amcsshe.c
+++ b/mps/code/amcsshe.c
@@ -251,7 +251,7 @@ int main(int argc, char *argv[])
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE));
- MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, testArenaSIZE);
+ MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, testArenaSIZE);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create");
} MPS_ARGS_END(args);
mps_message_type_enable(arena, mps_message_type_gc());
diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c
index 043330ebb74..3eea28df075 100644
--- a/mps/code/amcssth.c
+++ b/mps/code/amcssth.c
@@ -292,7 +292,7 @@ static void test_arena(int mode)
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE));
if (mode == ModeCOMMIT)
- MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 2 * testArenaSIZE);
+ MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 2 * testArenaSIZE);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create");
} MPS_ARGS_END(args);
mps_message_type_enable(arena, mps_message_type_gc());
diff --git a/mps/code/amsss.c b/mps/code/amsss.c
index 15686e5d15d..223bd205aea 100644
--- a/mps/code/amsss.c
+++ b/mps/code/amsss.c
@@ -209,7 +209,7 @@ int main(int argc, char *argv[])
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE));
- MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 2 * testArenaSIZE);
+ MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 2 * testArenaSIZE);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create");
} MPS_ARGS_END(args);
diff --git a/mps/code/apss.c b/mps/code/apss.c
index e1317b3fb73..1fe460df9ba 100644
--- a/mps/code/apss.c
+++ b/mps/code/apss.c
@@ -213,7 +213,7 @@ int main(int argc, char *argv[])
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 2 * testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(2*testArenaSIZE));
- MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, testArenaSIZE);
+ MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, testArenaSIZE);
test(mps_arena_class_vm(), args, &fenceOptions);
} MPS_ARGS_END(args);
diff --git a/mps/code/arena.c b/mps/code/arena.c
index e5d2901683e..4206ec9ab72 100644
--- a/mps/code/arena.c
+++ b/mps/code/arena.c
@@ -207,9 +207,9 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args)
if (ArgPick(&arg, args, MPS_KEY_ARENA_ZONED))
zoned = arg.val.b;
- if (ArgPick(&arg, args, MPS_KEY_ARENA_COMMIT_LIMIT))
+ if (ArgPick(&arg, args, MPS_KEY_COMMIT_LIMIT))
commitLimit = arg.val.size;
- if (ArgPick(&arg, args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT))
+ if (ArgPick(&arg, args, MPS_KEY_SPARE_COMMIT_LIMIT))
spareCommitLimit = arg.val.size;
arena->class = class;
@@ -289,11 +289,11 @@ ARG_DEFINE_KEY(VMW3_TOP_DOWN, Bool);
/* ArenaCreate -- create the arena and call initializers */
-ARG_DEFINE_KEY(ARENA_COMMIT_LIMIT, Size);
ARG_DEFINE_KEY(ARENA_GRAIN_SIZE, Size);
ARG_DEFINE_KEY(ARENA_SIZE, Size);
-ARG_DEFINE_KEY(ARENA_SPARE_COMMIT_LIMIT, Size);
ARG_DEFINE_KEY(ARENA_ZONED, Bool);
+ARG_DEFINE_KEY(COMMIT_LIMIT, Size);
+ARG_DEFINE_KEY(SPARE_COMMIT_LIMIT, Size);
static Res arenaFreeLandInit(Arena arena)
{
@@ -395,13 +395,13 @@ Res ArenaConfigure(Arena arena, ArgList args)
AVERT(Arena, arena);
AVERT(ArgList, args);
- if (ArgPick(&arg, args, MPS_KEY_ARENA_COMMIT_LIMIT)) {
+ if (ArgPick(&arg, args, MPS_KEY_COMMIT_LIMIT)) {
Size limit = arg.val.size;
res = ArenaSetCommitLimit(arena, limit);
if (res != ResOK)
return res;
}
- if (ArgPick(&arg, args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT)) {
+ if (ArgPick(&arg, args, MPS_KEY_SPARE_COMMIT_LIMIT)) {
Size limit = arg.val.size;
(void)ArenaSetSpareCommitLimit(arena, limit);
}
diff --git a/mps/code/locusss.c b/mps/code/locusss.c
index 742e5ee779b..b3769dd674a 100644
--- a/mps/code/locusss.c
+++ b/mps/code/locusss.c
@@ -219,7 +219,7 @@ static void runArenaTest(size_t size,
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, size);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, FALSE);
- MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, size - chunkSize);
+ MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, size - chunkSize);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
"mps_arena_create");
} MPS_ARGS_END(args);
diff --git a/mps/code/mps.h b/mps/code/mps.h
index b8882335581..10207eb6e94 100644
--- a/mps/code/mps.h
+++ b/mps/code/mps.h
@@ -155,18 +155,12 @@ extern const struct mps_key_s _mps_key_ARGS_END;
#define MPS_KEY_ARGS_END (&_mps_key_ARGS_END)
extern mps_arg_s mps_args_none[];
-extern const struct mps_key_s _mps_key_ARENA_COMMIT_LIMIT;
-#define MPS_KEY_ARENA_COMMIT_LIMIT (&_mps_key_ARENA_COMMIT_LIMIT)
-#define MPS_KEY_ARENA_COMMIT_LIMIT_FIELD size
extern const struct mps_key_s _mps_key_ARENA_GRAIN_SIZE;
#define MPS_KEY_ARENA_GRAIN_SIZE (&_mps_key_ARENA_GRAIN_SIZE)
#define MPS_KEY_ARENA_GRAIN_SIZE_FIELD size
extern const struct mps_key_s _mps_key_ARENA_SIZE;
#define MPS_KEY_ARENA_SIZE (&_mps_key_ARENA_SIZE)
#define MPS_KEY_ARENA_SIZE_FIELD size
-extern const struct mps_key_s _mps_key_ARENA_SPARE_COMMIT_LIMIT;
-#define MPS_KEY_ARENA_SPARE_COMMIT_LIMIT (&_mps_key_ARENA_SPARE_COMMIT_LIMIT)
-#define MPS_KEY_ARENA_SPARE_COMMIT_LIMIT_FIELD 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
@@ -182,6 +176,12 @@ extern const struct mps_key_s _mps_key_GEN;
extern const struct mps_key_s _mps_key_RANK;
#define MPS_KEY_RANK (&_mps_key_RANK)
#define MPS_KEY_RANK_FIELD rank
+extern const struct mps_key_s _mps_key_COMMIT_LIMIT;
+#define MPS_KEY_COMMIT_LIMIT (&_mps_key_COMMIT_LIMIT)
+#define MPS_KEY_COMMIT_LIMIT_FIELD size
+extern const struct mps_key_s _mps_key_SPARE_COMMIT_LIMIT;
+#define MPS_KEY_SPARE_COMMIT_LIMIT (&_mps_key_SPARE_COMMIT_LIMIT)
+#define MPS_KEY_SPARE_COMMIT_LIMIT_FIELD size
extern const struct mps_key_s _mps_key_EXTEND_BY;
#define MPS_KEY_EXTEND_BY (&_mps_key_EXTEND_BY)
diff --git a/mps/code/mpsicv.c b/mps/code/mpsicv.c
index 9f546c8678c..c1ea620c810 100644
--- a/mps/code/mpsicv.c
+++ b/mps/code/mpsicv.c
@@ -348,7 +348,7 @@ static void arena_commit_test(mps_arena_t arena)
} while (res == MPS_RES_OK);
die_expect(res, MPS_RES_COMMIT_LIMIT, "Commit limit allocation");
MPS_ARGS_BEGIN(args) {
- MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, limit);
+ MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, limit);
die(mps_arena_configure(arena, args), "commit_limit_set after");
} MPS_ARGS_END(args);
res = mps_alloc(&p, pool, FILLER_OBJECT_SIZE);
diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst
index b7f580c7286..5a862a6bc47 100644
--- a/mps/manual/source/release.rst
+++ b/mps/manual/source/release.rst
@@ -18,9 +18,9 @@ New features
requests from the :term:`arena`.
#. The function :c:func:`mps_arena_create_k` accepts two new
- :term:`keyword arguments`. :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT`
+ :term:`keyword arguments`. :c:macro:`MPS_KEY_COMMIT_LIMIT`
sets the :term:`commit limit` for the arena, and
- :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` sets the :term:`spare
+ :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` sets the :term:`spare
commit limit` for the arena.
#. The new function :c:func:`mps_arena_configure` provides a
diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst
index 29d942a29f2..7c9f580adde 100644
--- a/mps/manual/source/topic/arena.rst
+++ b/mps/manual/source/topic/arena.rst
@@ -154,7 +154,7 @@ Client arenas
It also accepts two optional keyword arguments:
- * :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` (type :c:type:`size_t`) is
+ * :c:macro:`MPS_KEY_COMMIT_LIMIT` (type :c:type:`size_t`) is
the maximum amount of memory, in :term:`bytes (1)`, that the MPS
will use out of the provided chunk (or chunks, if the arena is
extended). See :c:func:`mps_arena_commit_limit` for details. The
@@ -188,7 +188,7 @@ Client arenas
When configuring a client arena, :c:func:`mps_arena_configure`
accepts the :term:`keyword argument`
- :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` as described above.
+ :c:macro:`MPS_KEY_COMMIT_LIMIT` as described above.
.. c:function:: mps_res_t mps_arena_extend(mps_arena_t arena, mps_addr_t base, size_t size)
@@ -257,7 +257,7 @@ Virtual memory arenas
more times it has to extend its address space, the less
efficient garbage collection will become.
- * :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` (type :c:type:`size_t`) is
+ * :c:macro:`MPS_KEY_COMMIT_LIMIT` (type :c:type:`size_t`) is
the maximum amount of main memory, in :term:`bytes (1)`, that
the MPS will obtain from the operating system. See
:c:func:`mps_arena_commit_limit` for details. The default commit
@@ -274,7 +274,7 @@ Virtual memory arenas
that's smaller than the operating system page size, the MPS
rounds it up to the page size and continues.
- * :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` (type
+ * :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` (type
:c:type:`size_t`, default 0) is the spare commit limit in
:term:`bytes (1)`. See :c:func:`mps_arena_spare_commit_limit`
for details.
@@ -314,8 +314,8 @@ Virtual memory arenas
When configuring a virtual memory arena,
:c:func:`mps_arena_configure` accepts the :term:`keyword
- arguments` :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` and
- :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` as described above.
+ arguments` :c:macro:`MPS_KEY_COMMIT_LIMIT` and
+ :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` as described above.
.. index::
@@ -350,7 +350,7 @@ Arena properties
virtual memory interface.
The commit limit can be changed by passing the
- :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` :term:`keyword argument` to
+ :c:macro:`MPS_KEY_COMMIT_LIMIT` :term:`keyword argument` to
:c:func:`mps_arena_create_k` or :c:func:`mps_arena_configure`. The
commit limit cannot be set to a value that is lower than the
number of bytes that the MPS is using. If an attempt is made to
@@ -470,7 +470,7 @@ Arena properties
the MPS is allowed to have.
The spare commit limit can be changed by passing the
- :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` :term:`keyword
+ :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` :term:`keyword
argument` to :c:func:`mps_arena_create_k` or
:c:func:`mps_arena_configure`. Setting it to a value lower than
the current amount of spare committed memory causes spare
@@ -499,7 +499,7 @@ Arena properties
:c:func:`mps_arena_commit_limit`.
The amount of "spare committed" memory can be limited passing the
- :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` :term:`keyword
+ :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` :term:`keyword
argument` to :c:func:`mps_arena_create_k` or
:c:func:`mps_arena_configure`. The value of the limit can be
retrieved with :c:func:`mps_arena_spare_commit_limit`. This is
diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst
index 329f90d48dc..5a3f9900bf1 100644
--- a/mps/manual/source/topic/deprecated.rst
+++ b/mps/manual/source/topic/deprecated.rst
@@ -29,7 +29,7 @@ Deprecated in version 1.115
.. deprecated::
- Pass the :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` :term:`keyword
+ Pass the :c:macro:`MPS_KEY_COMMIT_LIMIT` :term:`keyword
argument` to :c:func:`mps_arena_create_k` or
:c:func:`mps_arena_configure`.
diff --git a/mps/manual/source/topic/keyword.rst b/mps/manual/source/topic/keyword.rst
index 6d321eab491..a2d100d1672 100644
--- a/mps/manual/source/topic/keyword.rst
+++ b/mps/manual/source/topic/keyword.rst
@@ -82,45 +82,45 @@ now :c:macro:`MPS_KEY_ARGS_END`.
The type of :term:`keyword argument` keys. Must take one of the
following values:
- =========================================== ========================================================= ==========================================================
- Keyword Type & field in ``arg.val`` See
- =========================================== ========================================================= ==========================================================
- :c:macro:`MPS_KEY_ARGS_END` *none* *see above*
- :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt`
- :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams`
- :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl`
- :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
- :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
- :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
- :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
- :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl`
- :c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo`
- :c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_FWD` :c:type:`mps_fmt_fwd_t` ``fmt_fwd`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_HEADER_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_ISFWD` :c:type:`mps_fmt_isfwd_t` ``fmt_isfwd`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_PAD` :c:type:`mps_fmt_pad_t` ``fmt_pad`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_SCAN` :c:type:`mps_fmt_scan_t` ``fmt_scan`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_SKIP` :c:type:`mps_fmt_skip_t` ``fmt_skip`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FORMAT` :c:type:`mps_fmt_t` ``format`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` , :c:func:`mps_class_snc`
- :c:macro:`MPS_KEY_GEN` :c:type:`unsigned` ``u`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo`
- :c:macro:`MPS_KEY_INTERIOR` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`
- :c:macro:`MPS_KEY_MAX_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`
- :c:macro:`MPS_KEY_MEAN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvt`, :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_MFS_UNIT_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mfs`
- :c:macro:`MPS_KEY_MIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mvt`
- :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_MVFF_FIRST_FIT` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt`
- :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt`
- :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` :c:type:`mps_pool_debug_option_s` ``*pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug`
- :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc`
- :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm`
- =========================================== ========================================================= ==========================================================
+ ======================================== ========================================================= ==========================================================
+ Keyword Type & field in ``arg.val`` See
+ ======================================== ========================================================= ==========================================================
+ :c:macro:`MPS_KEY_ARGS_END` *none* *see above*
+ :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt`
+ :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams`
+ :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl`
+ :c:macro:`MPS_KEY_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
+ :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
+ :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
+ :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
+ :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl`
+ :c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo`
+ :c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_FWD` :c:type:`mps_fmt_fwd_t` ``fmt_fwd`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_HEADER_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_ISFWD` :c:type:`mps_fmt_isfwd_t` ``fmt_isfwd`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_PAD` :c:type:`mps_fmt_pad_t` ``fmt_pad`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_SCAN` :c:type:`mps_fmt_scan_t` ``fmt_scan`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_SKIP` :c:type:`mps_fmt_skip_t` ``fmt_skip`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FORMAT` :c:type:`mps_fmt_t` ``format`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` , :c:func:`mps_class_snc`
+ :c:macro:`MPS_KEY_GEN` :c:type:`unsigned` ``u`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo`
+ :c:macro:`MPS_KEY_INTERIOR` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`
+ :c:macro:`MPS_KEY_MAX_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`
+ :c:macro:`MPS_KEY_MEAN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvt`, :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_MFS_UNIT_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mfs`
+ :c:macro:`MPS_KEY_MIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mvt`
+ :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_MVFF_FIRST_FIT` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt`
+ :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt`
+ :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` :c:type:`mps_pool_debug_option_s` ``*pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug`
+ :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc`
+ :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm`
+ ======================================== ========================================================= ==========================================================
.. c:function:: MPS_ARGS_BEGIN(args)
diff --git a/mps/test/function/120.c b/mps/test/function/120.c
index 77609e3e37f..032fa722c3f 100644
--- a/mps/test/function/120.c
+++ b/mps/test/function/120.c
@@ -41,7 +41,7 @@ static void test(void) {
* RES_COMMIT_LIMIT. */
MPS_ARGS_BEGIN(args) {
- MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 16 * 1024);
+ MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 16 * 1024);
report_res("create", mps_arena_create_k(&arena, mps_arena_class_vm(), args));
} MPS_ARGS_END(args);
diff --git a/mps/test/function/165.c b/mps/test/function/165.c
index e542cc111a7..da0734ba279 100644
--- a/mps/test/function/165.c
+++ b/mps/test/function/165.c
@@ -37,7 +37,7 @@ static void test(void)
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 1024*1024*40);
- MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 1024ul*1024ul*100ul);
+ MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 1024ul*1024ul*100ul);
cdie(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
"create arena");
} MPS_ARGS_END(args);
@@ -60,7 +60,7 @@ static void test(void)
/* Set the spare commit limit to 0MB */
MPS_ARGS_BEGIN(args) {
- MPS_ARGS_ADD(args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT, 0);
+ MPS_ARGS_ADD(args, MPS_KEY_SPARE_COMMIT_LIMIT, 0);
cdie(mps_arena_configure(arena, args), "mps_arena_configure");
} MPS_ARGS_END(args);
die(mps_alloc(&objs[0], pool, BIGSIZE), "alloc");
@@ -75,7 +75,7 @@ static void test(void)
/* nb. size_t unsigned, therefore (size_t)-1 is the maximum limit */
MPS_ARGS_BEGIN(args) {
- MPS_ARGS_ADD(args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT, -1);
+ MPS_ARGS_ADD(args, MPS_KEY_SPARE_COMMIT_LIMIT, -1);
cdie(mps_arena_configure(arena, args), "mps_arena_configure");
} MPS_ARGS_END(args);
die(mps_alloc(&objs[0], pool, BIGSIZE), "alloc");
@@ -88,7 +88,7 @@ static void test(void)
/* Reducing the spare committed limit should return most of the spare */
MPS_ARGS_BEGIN(args) {
- MPS_ARGS_ADD(args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT, 1024*1024);
+ MPS_ARGS_ADD(args, MPS_KEY_SPARE_COMMIT_LIMIT, 1024*1024);
cdie(mps_arena_configure(arena, args), "mps_arena_configure");
} MPS_ARGS_END(args);
com2 = mps_arena_committed(arena);
diff --git a/mps/test/function/231.c b/mps/test/function/231.c
index e0620fd09b3..ac13e02d4a1 100644
--- a/mps/test/function/231.c
+++ b/mps/test/function/231.c
@@ -19,7 +19,7 @@ static void test(void)
mps_arena_t arena;
MPS_ARGS_BEGIN(args) {
- MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 16 * 1024);
+ MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 16 * 1024);
report_res("create1",
mps_arena_create_k(&arena, mps_arena_class_vm(), args));
} MPS_ARGS_END(args);
@@ -28,7 +28,7 @@ static void test(void)
mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none));
MPS_ARGS_BEGIN(args) {
- MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 16 * 1024);
+ MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 16 * 1024);
report_res("configure", mps_arena_configure(arena, args));
} MPS_ARGS_END(args);
From 5d3379f84c44cf7a723ac2fac9353766bda77553 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 8 Sep 2015 16:36:48 +0100
Subject: [PATCH 090/337] Add a return value to arenasetsparecommitlimit, as
suggested by nb in review.
Copied from Perforce
Change: 188287
ServerID: perforce.ravenbrook.com
---
mps/code/arena.c | 8 +++++---
mps/code/mpm.h | 2 +-
mps/code/mpsi.c | 2 +-
3 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/mps/code/arena.c b/mps/code/arena.c
index 4206ec9ab72..a317f16343e 100644
--- a/mps/code/arena.c
+++ b/mps/code/arena.c
@@ -403,7 +403,9 @@ Res ArenaConfigure(Arena arena, ArgList args)
}
if (ArgPick(&arg, args, MPS_KEY_SPARE_COMMIT_LIMIT)) {
Size limit = arg.val.size;
- (void)ArenaSetSpareCommitLimit(arena, limit);
+ res = ArenaSetSpareCommitLimit(arena, limit);
+ if (res != ResOK)
+ return res;
}
return (*arena->class->configure)(arena, args);
@@ -1339,7 +1341,7 @@ Size ArenaSpareCommitLimit(Arena arena)
return arena->spareCommitLimit;
}
-void ArenaSetSpareCommitLimit(Arena arena, Size limit)
+Res ArenaSetSpareCommitLimit(Arena arena, Size limit)
{
AVERT(Arena, arena);
/* Can't check limit, as all possible values are allowed. */
@@ -1351,7 +1353,7 @@ void ArenaSetSpareCommitLimit(Arena arena, Size limit)
}
EVENT2(SpareCommitLimitSet, arena, limit);
- return;
+ return ResOK;
}
/* Used by arenas which don't use spare committed memory */
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index ae528e784d8..2a8482ad95e 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -620,7 +620,7 @@ extern Size ArenaSpareCommitted(Arena arena);
extern Size ArenaCommitLimit(Arena arena);
extern Res ArenaSetCommitLimit(Arena arena, Size limit);
extern Size ArenaSpareCommitLimit(Arena arena);
-extern void ArenaSetSpareCommitLimit(Arena arena, Size limit);
+extern Res ArenaSetSpareCommitLimit(Arena arena, Size limit);
extern Size ArenaNoPurgeSpare(Arena arena, Size size);
extern Res ArenaNoGrow(Arena arena, LocusPref pref, Size size);
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index 8ee89ac3923..d9bdc80da8d 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -204,7 +204,7 @@ mps_res_t mps_arena_commit_limit_set(mps_arena_t arena, size_t limit)
void mps_arena_spare_commit_limit_set(mps_arena_t arena, size_t limit)
{
ArenaEnter(arena);
- ArenaSetSpareCommitLimit(arena, limit);
+ (void)ArenaSetSpareCommitLimit(arena, limit);
ArenaLeave(arena);
return;
From 012de550deb8f277cf77080c8f6d4adbf14dfbe8 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Tue, 8 Sep 2015 16:38:55 +0100
Subject: [PATCH 091/337] Alphabetize list of keywords; spare commit limit does
not do anything for the client arena.
Copied from Perforce
Change: 188288
ServerID: perforce.ravenbrook.com
---
mps/design/arena.txt | 14 +++++++-------
mps/manual/source/topic/keyword.rst | 4 ++--
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/mps/design/arena.txt b/mps/design/arena.txt
index a72bfbcb09c..2a94bb05b39 100644
--- a/mps/design/arena.txt
+++ b/mps/design/arena.txt
@@ -432,13 +432,13 @@ bytes; ``spareCommitLimit`` records the limit (set by the user) on the
amount of spare committed memory. ``spareCommitted`` is modified by
the arena class but its value is used by the generic arena code. There
are two uses: a getter function for this value is provided through the
-MPS interface (``mps_arena_spare_commit_limit_set()``), and by the
-``SetSpareCommitLimit()`` function to determine whether the amount of
-spare committed memory needs to be reduced. ``spareCommitLimit`` is
-manipulated by generic arena code, however the associated semantics
-are the responsibility of the class. It is the class's responsibility
-to ensure that it doesn't use more spare committed bytes than the
-value in ``spareCommitLimit``.
+MPS interface (``mps_arena_spare_commit_limit()``), and by the
+``ArenaSetSpareCommitLimit()`` function to determine whether the
+amount of spare committed memory needs to be reduced.
+``spareCommitLimit`` is manipulated by generic arena code, however the
+associated semantics are the responsibility of the class. It is the
+class's responsibility to ensure that it doesn't use more spare
+committed bytes than the value in ``spareCommitLimit``.
_`.spare-commit-limit`: The function ``ArenaSetSpareCommitLimit()`` sets
the ``spareCommitLimit`` field. If the limit is set to a value lower
diff --git a/mps/manual/source/topic/keyword.rst b/mps/manual/source/topic/keyword.rst
index a2d100d1672..ddbfbfd57ac 100644
--- a/mps/manual/source/topic/keyword.rst
+++ b/mps/manual/source/topic/keyword.rst
@@ -89,12 +89,11 @@ now :c:macro:`MPS_KEY_ARGS_END`.
:c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt`
:c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams`
:c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl`
- :c:macro:`MPS_KEY_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
:c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
:c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
- :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
:c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl`
:c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo`
+ :c:macro:`MPS_KEY_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
:c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`
:c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k`
:c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k`
@@ -119,6 +118,7 @@ now :c:macro:`MPS_KEY_ARGS_END`.
:c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` :c:type:`mps_pool_debug_option_s` ``*pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug`
:c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc`
:c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`
:c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm`
======================================== ========================================================= ==========================================================
From 75aab3b943a8dc0f0f86763240b0f791b81e84fa Mon Sep 17 00:00:00 2001
From: Nick Barnes
Date: Wed, 9 Sep 2015 15:20:01 +0100
Subject: [PATCH 092/337] Remove redundant assignment.
Copied from Perforce
Change: 188292
ServerID: perforce.ravenbrook.com
---
mps/code/policy.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/mps/code/policy.c b/mps/code/policy.c
index a71ce120307..dbcb33e278f 100644
--- a/mps/code/policy.c
+++ b/mps/code/policy.c
@@ -85,7 +85,6 @@ Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
goto found;
}
if (moreZones != zones) {
- zones = ZoneSetUnion(zones, ZoneSetDiff(arena->freeZones, pref->avoid));
res = ArenaFreeLandAlloc(&tract, arena, moreZones, pref->high,
size, pool);
if (res == ResOK)
From 3623e32059c3dc7efb04402c8b6339f5635e1ffe Mon Sep 17 00:00:00 2001
From: Nick Barnes
Date: Wed, 9 Sep 2015 17:13:00 +0100
Subject: [PATCH 093/337] Minor review fixes.
Copied from Perforce
Change: 188293
ServerID: perforce.ravenbrook.com
---
mps/code/ssan.c | 2 +-
mps/code/ssw3i3mv.c | 2 +-
mps/code/ssw3i3pc.c | 7 +++++++
mps/code/ssw3i6mv.c | 6 ++++--
mps/code/ssw3i6pc.c | 12 +++++++-----
mps/manual/source/topic/root.rst | 19 ++++++++++++-------
6 files changed, 32 insertions(+), 16 deletions(-)
diff --git a/mps/code/ssan.c b/mps/code/ssan.c
index b746b28bb1d..922f15f397c 100644
--- a/mps/code/ssan.c
+++ b/mps/code/ssan.c
@@ -35,7 +35,7 @@ Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
(void)setjmp(jb);
- return StackScanInner(ss, stackBot, stackTop, sizeof jb / sizeof(Word*),
+ return StackScanInner(ss, stackBot, stackTop, sizeof jb / sizeof(Word),
mask, pattern);
}
diff --git a/mps/code/ssw3i3mv.c b/mps/code/ssw3i3mv.c
index feffdf3e7a3..85d3d750322 100644
--- a/mps/code/ssw3i3mv.c
+++ b/mps/code/ssw3i3mv.c
@@ -33,9 +33,9 @@ Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
/* 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)->Ebx) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Edi) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Esi) == sizeof(Word));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->Ebx) == sizeof(Word));
/* Ensure that the callee-save registers will be found by
StackScanInner when it's passed the address of the Ebx field. */
diff --git a/mps/code/ssw3i3pc.c b/mps/code/ssw3i3pc.c
index 9c42fa6207f..88d4d2a70cf 100644
--- a/mps/code/ssw3i3pc.c
+++ b/mps/code/ssw3i3pc.c
@@ -53,6 +53,13 @@ Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
/* .assume.ms-compat */
(void)setjmp(jb);
+ /* 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
StackScanInner when it's passed the address of the Ebx field. */
AVER(offsetof(_JUMP_BUFFER, Edi) == offsetof(_JUMP_BUFFER, Ebx) + 4);
diff --git a/mps/code/ssw3i6mv.c b/mps/code/ssw3i6mv.c
index 7af35054d30..62c7b023cb1 100644
--- a/mps/code/ssw3i6mv.c
+++ b/mps/code/ssw3i6mv.c
@@ -41,9 +41,11 @@ Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
/* 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(Word));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->Rbx) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsp) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rbp) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->Rdi) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R12) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R13) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R14) == sizeof(Word));
diff --git a/mps/code/ssw3i6pc.c b/mps/code/ssw3i6pc.c
index 4b22d72b0d9..7ae89fb85ea 100644
--- a/mps/code/ssw3i6pc.c
+++ b/mps/code/ssw3i6pc.c
@@ -76,12 +76,14 @@ Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
registers in the jmp_buf. */
(void)setjmp(jb);
- /* 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(Word));
- AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Word));
+ /* 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)->Rbx) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsp) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rbp) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Word));
+ AVER(sizeof(((_JUMP_BUFFER *)jb)->Rdi) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R12) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R13) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R14) == sizeof(Word));
diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst
index 0089b26e728..78641fc69a9 100644
--- a/mps/manual/source/topic/root.rst
+++ b/mps/manual/source/topic/root.rst
@@ -83,7 +83,7 @@ Roots can be deregistered at any time by calling
:c:func:`mps_root_destroy`. All roots registered in an :term:`arena`
must be deregistered before the arena is destroyed.
-There are five ways to register a root, depending on how you need to
+There are six ways to register a root, depending on how you need to
scan it for references:
#. :c:func:`mps_root_create` if you need a custom root scanning
@@ -104,6 +104,10 @@ scan it for references:
:term:`registers` and :term:`control stack` of a thread. See
:ref:`topic-root-thread` below.
+#. :c:func:`mps_root_create_reg_masked` if the root consists of the
+ :term:`registers` and :term:`control stack` of a thread, and that
+ thread keeps tagged references in registers or on the stack. See
+ :ref:`topic-root-thread` below.
.. index::
pair: root; cautions
@@ -147,11 +151,12 @@ Thread roots
Every thread's registers and control stack potentially contain
references to allocated objects, so should be registered as a root by
-calling :c:func:`mps_root_create_reg`. It's not easy to write a
-scanner for the registers and the stack: it depends on the operating
-system, the processor architecture, and in some cases on the compiler.
-For this reason, the MPS provides :c:func:`mps_stack_scan_ambig` (and
-in fact, this is the only supported stack scanner).
+calling :c:func:`mps_root_create_reg` or
+:c:func:`mps_root_create_reg_masked`. It's not easy to write a scanner
+for the registers and the stack: it depends on the operating system,
+the processor architecture, and in some cases on the compiler. For
+this reason, the MPS provides :c:func:`mps_stack_scan_ambig` (and in
+fact, this is the only supported stack scanner).
A stack scanner needs to know how to find the bottom of the part of the
stack to scan. The bottom of the relevant part of stack can be found by
@@ -508,7 +513,7 @@ Root interface
Register a :term:`root` that consists of the :term:`references` in
a :term:`thread's ` registers and stack that match a
- binary pattern.
+ binary pattern, for instance tagged as pointers.
``root_o`` points to a location that will hold the address of the
new root description.
From ffc148c00814b83cbb4d4c1e92d92b9fd233b4a5 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Sat, 12 Sep 2015 20:59:10 +0100
Subject: [PATCH 094/337] Add more assertions.
Copied from Perforce
Change: 188304
ServerID: perforce.ravenbrook.com
---
mps/manual/source/topic/error.rst | 46 +++++++++++++++++++++++++++----
1 file changed, 40 insertions(+), 6 deletions(-)
diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst
index 784533d66fa..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,12 @@ 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 thread without first destroying all
- roots using that thread.
+ 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``
From 7d43cfa380071d2088323f1511b4be15f6598496 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 14 Sep 2015 20:16:14 +0100
Subject: [PATCH 095/337] Rename mps_root_create_reg_masked to
mps_root_create_stack, and deprecate mps_root_create_reg, as suggested in
review by nb .
Copied from Perforce
Change: 188312
ServerID: perforce.ravenbrook.com
---
mps/code/airtest.c | 4 +-
mps/code/amcssth.c | 8 +-
mps/code/awlut.c | 3 +-
mps/code/awluthe.c | 3 +-
mps/code/awlutth.c | 3 +-
mps/code/gcbench.c | 7 +-
mps/code/mps.h | 8 +-
mps/code/mpsi.c | 8 +-
mps/code/mpsicv.c | 8 +-
mps/code/tagtest.c | 8 +-
mps/code/zcoll.c | 12 +-
mps/code/zmess.c | 6 +-
mps/example/scheme/scheme-advanced.c | 10 +-
mps/example/scheme/scheme.c | 10 +-
mps/manual/source/glossary/c.rst | 19 +++
mps/manual/source/glossary/h.rst | 10 ++
mps/manual/source/glossary/t.rst | 6 +-
mps/manual/source/guide/lang.rst | 29 ++---
mps/manual/source/guide/vector.rst | 4 +-
mps/manual/source/release.rst | 10 +-
mps/manual/source/topic/allocation.rst | 10 +-
mps/manual/source/topic/deprecated.rst | 109 +++++++++++++++++
mps/manual/source/topic/root.rst | 156 +++----------------------
mps/manual/source/topic/thread.rst | 9 +-
24 files changed, 227 insertions(+), 233 deletions(-)
diff --git a/mps/code/airtest.c b/mps/code/airtest.c
index c262cb31268..53537ea4c35 100644
--- a/mps/code/airtest.c
+++ b/mps/code/airtest.c
@@ -127,8 +127,8 @@ static void test_main(void *marker, int interior, int stack)
error("Couldn't register thread");
if (stack) {
- res = mps_root_create_reg(®_root, scheme_arena, mps_rank_ambig(), 0,
- thread, mps_stack_scan_ambig, marker, 0);
+ res = mps_root_create_stack(®_root, scheme_arena, mps_rank_ambig(),
+ 0, thread, 0, 0, marker);
if (res != MPS_RES_OK)
error("Couldn't create root");
}
diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c
index c6e2d214b5d..51f1a12b9cb 100644
--- a/mps/code/amcssth.c
+++ b/mps/code/amcssth.c
@@ -139,8 +139,8 @@ static void *kid_thread(void *arg)
closure_t cl = arg;
die(mps_thread_reg(&thread, (mps_arena_t)arena), "thread_reg");
- die(mps_root_create_reg(®_root, arena, mps_rank_ambig(), 0, thread,
- mps_stack_scan_ambig, marker, 0), "root_create");
+ die(mps_root_create_stack(®_root, arena, mps_rank_ambig(),
+ 0, thread, 0, 0, marker), "root_create");
die(mps_ap_create(&ap, cl->pool, mps_rank_exact()), "BufferCreate(fooey)");
while(mps_collections(arena) < collectionsCOUNT) {
@@ -316,8 +316,8 @@ static void test_arena(int mode)
&ambigRoots[0], ambigRootsCOUNT),
"root_create_table(ambig)");
die(mps_thread_reg(&thread, arena), "thread_reg");
- die(mps_root_create_reg(®_root, arena, mps_rank_ambig(), 0, thread,
- mps_stack_scan_ambig, marker, 0), "root_create");
+ die(mps_root_create_stack(®_root, arena, mps_rank_ambig(),
+ 0, thread, 0, 0, marker), "root_create");
die(mps_pool_create(&amc_pool, arena, mps_class_amc(), format, chain),
"pool_create(amc)");
diff --git a/mps/code/awlut.c b/mps/code/awlut.c
index 464a2dba91f..eeaa788ae5f 100644
--- a/mps/code/awlut.c
+++ b/mps/code/awlut.c
@@ -267,8 +267,7 @@ static void *setup(void *v, size_t s)
arena = guff->arena;
thr = guff->thr;
- die(mps_root_create_reg(&stack, arena, mps_rank_ambig(), 0, thr,
- mps_stack_scan_ambig, v, 0),
+ die(mps_root_create_stack(&stack, arena, mps_rank_ambig(), 0, thr, 0, 0, v),
"Root Create\n");
die(mps_fmt_create_A(&dylanfmt, arena, dylan_fmt_A()),
"Format Create\n");
diff --git a/mps/code/awluthe.c b/mps/code/awluthe.c
index 6ea468977f1..18b8347e1fd 100644
--- a/mps/code/awluthe.c
+++ b/mps/code/awluthe.c
@@ -271,8 +271,7 @@ static void *setup(void *v, size_t s)
arena = guff->arena;
thr = guff->thr;
- die(mps_root_create_reg(&stack, arena, mps_rank_ambig(), 0, thr,
- mps_stack_scan_ambig, v, 0),
+ die(mps_root_create_stack(&stack, arena, mps_rank_ambig(), 0, thr, 0, 0, v),
"Root Create\n");
die(EnsureHeaderFormat(&dylanfmt, arena), "EnsureHeaderFormat");
die(EnsureHeaderWeakFormat(&dylanweakfmt, arena), "EnsureHeaderWeakFormat");
diff --git a/mps/code/awlutth.c b/mps/code/awlutth.c
index 2bfaddc3813..1d73a98f29f 100644
--- a/mps/code/awlutth.c
+++ b/mps/code/awlutth.c
@@ -254,8 +254,7 @@ static void *setup(void *v, size_t s)
arena = guff->arena;
thr = guff->thr;
- die(mps_root_create_reg(&stack, arena, mps_rank_ambig(), 0, thr,
- mps_stack_scan_ambig, v, 0),
+ die(mps_root_create_stack(&stack, arena, mps_rank_ambig(), 0, thr, 0, 0, v),
"Root Create\n");
die(mps_fmt_create_A(&dylanfmt, arena, dylan_fmt_A()),
"Format Create\n");
diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c
index 2ae97104930..2220ea3ffc8 100644
--- a/mps/code/gcbench.c
+++ b/mps/code/gcbench.c
@@ -171,10 +171,9 @@ static void *start(void *p) {
gcthread_t thread = p;
void *marker;
RESMUST(mps_thread_reg(&thread->mps_thread, arena));
- RESMUST(mps_root_create_reg(&thread->reg_root, arena,
- mps_rank_ambig(), (mps_rm_t)0,
- thread->mps_thread, &mps_stack_scan_ambig,
- &marker, (size_t)0));
+ RESMUST(mps_root_create_stack(&thread->reg_root, arena,
+ mps_rank_ambig(), (mps_rm_t)0,
+ thread->mps_thread, 0, 0, &marker));
RESMUST(mps_ap_create_k(&thread->ap, pool, mps_args_none));
thread->fn(thread);
mps_ap_destroy(thread->ap);
diff --git a/mps/code/mps.h b/mps/code/mps.h
index 515edbbe5e0..45f9543e8da 100644
--- a/mps/code/mps.h
+++ b/mps/code/mps.h
@@ -672,10 +672,10 @@ extern mps_res_t mps_root_create_fmt(mps_root_t *, mps_arena_t,
extern mps_res_t mps_root_create_reg(mps_root_t *, mps_arena_t,
mps_rank_t, mps_rm_t, mps_thr_t,
mps_reg_scan_t, void *, size_t);
-extern mps_res_t mps_root_create_reg_masked(mps_root_t *, mps_arena_t,
- mps_rank_t, mps_rm_t, mps_thr_t,
- mps_word_t, mps_word_t,
- void *);
+extern mps_res_t mps_root_create_stack(mps_root_t *, mps_arena_t,
+ mps_rank_t, mps_rm_t, mps_thr_t,
+ mps_word_t, mps_word_t,
+ void *);
extern void mps_root_destroy(mps_root_t);
extern mps_res_t mps_stack_scan_ambig(mps_ss_t, mps_thr_t,
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index 0ae717a2ef2..3b403fa3450 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -1401,10 +1401,10 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena,
}
-mps_res_t mps_root_create_reg_masked(mps_root_t *mps_root_o, mps_arena_t arena,
- mps_rank_t mps_rank, mps_rm_t mps_rm,
- mps_thr_t thread, mps_word_t mask,
- mps_word_t pattern, void *reg_scan_p)
+mps_res_t mps_root_create_stack(mps_root_t *mps_root_o, mps_arena_t arena,
+ mps_rank_t mps_rank, mps_rm_t mps_rm,
+ mps_thr_t thread, mps_word_t mask,
+ mps_word_t pattern, void *reg_scan_p)
{
Rank rank = (Rank)mps_rank;
Root root;
diff --git a/mps/code/mpsicv.c b/mps/code/mpsicv.c
index 80085d2f8ad..2d3caac8dd8 100644
--- a/mps/code/mpsicv.c
+++ b/mps/code/mpsicv.c
@@ -598,10 +598,10 @@ int main(int argc, char *argv[])
marker, (size_t)0),
"root_create_reg");
} else {
- die(mps_root_create_reg_masked(®_root, arena,
- mps_rank_ambig(), (mps_rm_t)0,
- thread, 0, 0, marker),
- "root_create_reg_masked");
+ die(mps_root_create_stack(®_root, arena,
+ mps_rank_ambig(), (mps_rm_t)0,
+ thread, 0, 0, marker),
+ "root_create_stack");
}
mps_tramp(&r, test, arena, 0);
diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c
index fa606fe85d7..96f4605546d 100644
--- a/mps/code/tagtest.c
+++ b/mps/code/tagtest.c
@@ -177,14 +177,14 @@ static void test(int mode, void *marker)
break;
case MODE_CONS:
/* Scan words tagged "cons" -- everything will live. */
- die(mps_root_create_reg_masked(&root, arena, mps_rank_ambig(), 0, thread,
- TAG_MASK, tag_cons, marker), "root");
+ die(mps_root_create_stack(&root, arena, mps_rank_ambig(), 0, thread,
+ TAG_MASK, tag_cons, marker), "root");
expected = 0;
break;
case MODE_INVALID:
/* Scan words tagged "invalid" -- everything will die. */
- die(mps_root_create_reg_masked(&root, arena, mps_rank_ambig(), 0, thread,
- TAG_MASK, tag_invalid, marker), "root");
+ die(mps_root_create_stack(&root, arena, mps_rank_ambig(), 0, thread,
+ TAG_MASK, tag_invalid, marker), "root");
expected = OBJCOUNT;
break;
default:
diff --git a/mps/code/zcoll.c b/mps/code/zcoll.c
index a5d7a0e0d22..307cc215c7a 100644
--- a/mps/code/zcoll.c
+++ b/mps/code/zcoll.c
@@ -574,9 +574,9 @@ static void StackScan(mps_arena_t arena, int on)
{
if(on) {
Insist(root_stackreg == NULL);
- die(mps_root_create_reg(&root_stackreg, arena,
- mps_rank_ambig(), (mps_rm_t)0, stack_thr,
- mps_stack_scan_ambig, stack_start, 0),
+ die(mps_root_create_stack(&root_stackreg, arena,
+ mps_rank_ambig(), (mps_rm_t)0, stack_thr,
+ 0, 0, stack_start),
"root_stackreg");
Insist(root_stackreg != NULL);
} else {
@@ -762,9 +762,9 @@ static void *testscriptB(void *arg, size_t s)
/* root_stackreg: stack & registers are ambiguous roots = mutator's workspace */
stack_start = &stack_starts_here;
stack_thr = thr;
- die(mps_root_create_reg(&root_stackreg, arena,
- mps_rank_ambig(), (mps_rm_t)0, stack_thr,
- mps_stack_scan_ambig, stack_start, 0),
+ die(mps_root_create_stack(&root_stackreg, arena,
+ mps_rank_ambig(), (mps_rm_t)0, stack_thr,
+ 0, 0, stack_start),
"root_stackreg");
diff --git a/mps/code/zmess.c b/mps/code/zmess.c
index 53aea545801..e6efe7a702d 100644
--- a/mps/code/zmess.c
+++ b/mps/code/zmess.c
@@ -330,9 +330,9 @@ static void *testscriptB(void *arg, size_t s)
die(mps_ap_create(&ap, amc, mps_rank_exact()), "ap_create");
/* root_stackreg: stack & registers are ambiguous roots = mutator's workspace */
- die(mps_root_create_reg(&root_stackreg, arena,
- mps_rank_ambig(), (mps_rm_t)0, thr,
- mps_stack_scan_ambig, &stack_starts_here, 0),
+ die(mps_root_create_stack(&root_stackreg, arena,
+ mps_rank_ambig(), (mps_rm_t)0, thr,
+ 0, 0, &stack_starts_here),
"root_stackreg");
/* Make myrootCOUNT registered-for-finalization objects. */
diff --git a/mps/example/scheme/scheme-advanced.c b/mps/example/scheme/scheme-advanced.c
index 993c1aad9f9..2b5bb6c30be 100644
--- a/mps/example/scheme/scheme-advanced.c
+++ b/mps/example/scheme/scheme-advanced.c
@@ -4592,14 +4592,8 @@ int main(int argc, char *argv[])
need to be scanned by the MPS because we are passing references to
objects around in C parameters, return values, and keeping them in
automatic local variables. See topic/root. */
- res = mps_root_create_reg(®_root,
- arena,
- mps_rank_ambig(),
- 0,
- thread,
- mps_stack_scan_ambig,
- marker,
- 0);
+ res = mps_root_create_stack(®_root, arena, mps_rank_ambig(),
+ 0, thread, 0, 0, marker);
if (res != MPS_RES_OK) error("Couldn't create root");
/* Make sure we can pick up finalization messages. */
diff --git a/mps/example/scheme/scheme.c b/mps/example/scheme/scheme.c
index a2825ad6e78..f088e655f14 100644
--- a/mps/example/scheme/scheme.c
+++ b/mps/example/scheme/scheme.c
@@ -4487,14 +4487,8 @@ int main(int argc, char *argv[])
need to be scanned by the MPS because we are passing references to
objects around in C parameters, return values, and keeping them in
automatic local variables. See topic/root. */
- res = mps_root_create_reg(®_root,
- arena,
- mps_rank_ambig(),
- 0,
- thread,
- mps_stack_scan_ambig,
- marker,
- 0);
+ res = mps_root_create_stack(®_root, arena, mps_rank_ambig(),
+ 0, thread, 0, 0, marker);
if (res != MPS_RES_OK) error("Couldn't create root");
/* Make sure we can pick up finalization messages. */
diff --git a/mps/manual/source/glossary/c.rst b/mps/manual/source/glossary/c.rst
index ffdf1899243..afa39c9e437 100644
--- a/mps/manual/source/glossary/c.rst
+++ b/mps/manual/source/glossary/c.rst
@@ -285,6 +285,25 @@ Memory Management Glossary: C
fragmentation, and which coalescing strategies are effective
under what circumstances.
+ cold end
+
+ .. opposite:: :term:`hot end`
+
+ A :term:`control stack` has two ends: the oldest items are at
+ the *cold end* and the newest items are at the *hot end*.
+ Sometimes the cold end is called the "bottom" of the stack,
+ but that is misleading when the stack grows downwards, as it
+ does on common computing platforms.
+
+ .. mps:specific::
+
+ In order for the MPS to be able to :term:`scan`
+ :term:`references` on the stack, the :term:`client
+ program` must pass the location of the cold end of the
+ stack (or the part of the stack that might contain
+ references to memory managed by the MPS) to
+ :c:func:`mps_root_create_stack`.
+
collect
An :term:`object` is collected when it is :term:`reclaimed` by
diff --git a/mps/manual/source/glossary/h.rst b/mps/manual/source/glossary/h.rst
index 8d292f98379..fa76ad7add7 100644
--- a/mps/manual/source/glossary/h.rst
+++ b/mps/manual/source/glossary/h.rst
@@ -118,6 +118,16 @@ Memory Management Glossary: H
Select it by defining :c:macro:`CONFIG_VAR_HOT`. Compare
:term:`cool` and :term:`rash`.
+ hot end
+
+ .. opposite:: :term:`cold end`
+
+ A :term:`control stack` has two ends: the oldest items are at
+ the *cold end* and the newest items are at the *hot end*.
+ Sometimes the hot end is called the "top" of the stack, but
+ that is misleading when the stack grows downwards, as it does
+ on common computing platforms.
+
huge page
.. aka:: *large page*, *superpage*.
diff --git a/mps/manual/source/glossary/t.rst b/mps/manual/source/glossary/t.rst
index a91b656d89f..222a3cbb512 100644
--- a/mps/manual/source/glossary/t.rst
+++ b/mps/manual/source/glossary/t.rst
@@ -181,9 +181,9 @@ Memory Management Glossary: T
Threads are represented by values of type
:c:type:`mps_thr_t`, created by calling
:c:func:`mps_thread_reg`. In order for the MPS to find
- references on the control of the thread, the thread must
- be also be registered as a root by calling
- :c:func:`mps_root_create_reg`. See :ref:`topic-thread`.
+ references on the control stack of the thread, the thread
+ must be also be registered as a :term:`root` by calling
+ :c:func:`mps_root_create_stack`. See :ref:`topic-thread`.
threatened set
diff --git a/mps/manual/source/guide/lang.rst b/mps/manual/source/guide/lang.rst
index 88c7ec93eb5..9a864e47414 100644
--- a/mps/manual/source/guide/lang.rst
+++ b/mps/manual/source/guide/lang.rst
@@ -971,29 +971,22 @@ You register a thread with an :term:`arena` by calling
res = mps_thread_reg(&thread, arena);
if (res != MPS_RES_OK) error("Couldn't register thread");
-You register the thread's registers and control stack as a root by
-calling :c:func:`mps_root_create_reg` and passing
-:c:func:`mps_stack_scan_ambig`::
+You register the thread's :term:`registers` and :term:`control stack`
+as a root by calling :c:func:`mps_root_create_stack`::
void *marker = ▮
- mps_root_t reg_root;
- res = mps_root_create_reg(®_root,
- arena,
- mps_rank_ambig(),
- 0,
- thread,
- mps_stack_scan_ambig,
- marker,
- 0);
+ mps_root_t stack_root;
+ res = mps_root_create_stack(®_root, arena, mps_rank_ambig(),
+ 0, thread, 0, 0, marker);
if (res != MPS_RES_OK) error("Couldn't create root");
In order to scan the control stack, the MPS needs to know where the
-bottom of the stack is, and that's the role of the ``marker``
-variable: the compiler places it on the stack, so its address is a
-position within the stack. As long as you don't exit from this
-function while the MPS is running, your program's active local
-variables will always be higher up on the stack than ``marker``, and
-so will be scanned for references by the MPS.
+:term:`cold end` of the stack is, and that's the role of the
+``marker`` variable: the compiler places it on the stack, so its
+address is a position within the stack. As long as you don't exit from
+this function while the MPS is running, your program's active local
+variables will always be placed on the stack after ``marker``, and so
+will be scanned for references by the MPS.
.. topics::
diff --git a/mps/manual/source/guide/vector.rst b/mps/manual/source/guide/vector.rst
index 8b9452ac1f6..b6336e23569 100644
--- a/mps/manual/source/guide/vector.rst
+++ b/mps/manual/source/guide/vector.rst
@@ -64,8 +64,8 @@ solved:
This can solved by storing the new array in a :term:`root` until
the header has been updated. If the thread's stack has been
- registered as a root by calling :c:func:`mps_root_create_reg` then
- any local variable will do.
+ registered as a root by calling :c:func:`mps_root_create_stack`
+ then any local variable will do.
2. References in the new array must not be scanned until they have been
copied or cleared. (Otherwise they will be invalid.)
diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst
index a9881375159..2dfdab79555 100644
--- a/mps/manual/source/release.rst
+++ b/mps/manual/source/release.rst
@@ -17,9 +17,10 @@ New features
specifying the minimum size of the memory segments that the pool
requests from the :term:`arena`.
-#. New function :c:func:`mps_root_create_reg_masked` applies a mask
- and pattern test to all words in registers and on the stack when
- scanning them. This supports tagged references in these locations.
+#. New function :c:func:`mps_root_create_stack` applies a mask and
+ pattern test to all words in the :term:`control stack` and
+ :term:`registers` of a :term:`thread` when scanning them. This
+ supports :term:`tagged references` in these locations.
Interface changes
@@ -35,6 +36,9 @@ Interface changes
deprecated in favour of the generic functions
:c:func:`mps_pool_free_size` and :c:func:`mps_pool_total_size`.
+#. The function :c:func:`mps_root_create_reg` is deprecated in favour
+ of :c:func:`mps_root_create_stack`.
+
Other changes
.............
diff --git a/mps/manual/source/topic/allocation.rst b/mps/manual/source/topic/allocation.rst
index 4075cfe006a..e473cded0f7 100644
--- a/mps/manual/source/topic/allocation.rst
+++ b/mps/manual/source/topic/allocation.rst
@@ -151,11 +151,11 @@ least) two steps, a *reserve* followed by a *commit*.
The description of the protocol assumes that you have declared
your threads' :term:`control stacks` and :term:`registers` to be
- :term:`ambiguous roots`, by passing :c:func:`mps_stack_scan_ambig`
- to :c:func:`mps_root_create_reg`. This is the simplest way to
- write a client, but other scenarios are possible. Please
- :ref:`contact us ` if your use case is not covered here
- (for example, if you need an exact collector).
+ :term:`ambiguous roots`, by calling
+ :c:func:`mps_root_create_stack`. This is the simplest way to write
+ a client, but other scenarios are possible. Please :ref:`contact
+ us ` if your use case is not covered here (for example,
+ if you need an exact collector).
When the client program is initializing a newly allocated object, you
can think of it as being "in a race" with the MPS. Until the object is
diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst
index dfd4d8d74cb..77594d4c020 100644
--- a/mps/manual/source/topic/deprecated.rst
+++ b/mps/manual/source/topic/deprecated.rst
@@ -118,6 +118,115 @@ Deprecated in version 1.115
is the sum of allocated space and free space.
+.. c:function:: mps_res_t mps_root_create_reg(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thr, mps_reg_scan_t reg_scan, void *p, size_t s)
+
+ .. deprecated::
+
+ Use :c:func:`mps_root_create_stack` instead.
+
+ Register a :term:`root` that consists of the :term:`references`
+ fixed in a :term:`thread's ` registers and stack by a
+ scanning function.
+
+ ``root_o`` points to a location that will hold the address of the
+ new root description.
+
+ ``arena`` is the arena.
+
+ ``rank`` is the :term:`rank` of references in the root.
+
+ ``rm`` is the :term:`root mode`.
+
+ ``thr`` is the thread.
+
+ ``reg_scan`` is a scanning function. See :c:type:`mps_reg_scan_t`.
+
+ ``p`` and ``s`` are arguments that will be passed to ``reg_scan`` each
+ time it is called. This is intended to make it easy to pass, for
+ example, an array and its size as parameters.
+
+ Returns :c:macro:`MPS_RES_OK` if the root was registered
+ successfully, :c:macro:`MPS_RES_MEMORY` if the new root
+ description could not be allocated, or another :term:`result code`
+ if there was another error.
+
+ The registered root description persists until it is destroyed by
+ calling :c:func:`mps_root_destroy`.
+
+ .. note::
+
+ It is not supported for :term:`client programs` to pass their
+ own scanning functions to this function. The built-in MPS
+ function :c:func:`mps_stack_scan_ambig` must be used. In this
+ case the ``p`` argument must be a pointer to the :term:`cold
+ end` of the thread's stack (or the part of the stack
+ containing references to memory managed by the MPS). The ``s``
+ argument is ignored.
+
+
+.. c:type:: mps_res_t (*mps_reg_scan_t)(mps_ss_t ss, mps_thr_t thr, void *p, size_t s)
+
+ .. deprecated::
+
+ Use :c:func:`mps_root_create_stack` instead.
+
+ The type of a root scanning function for roots created with
+ :c:func:`mps_root_create_reg`.
+
+ ``ss`` is the :term:`scan state`. It must be passed to
+ :c:func:`MPS_SCAN_BEGIN` and :c:func:`MPS_SCAN_END` to delimit a
+ sequence of fix operations, and to the functions
+ :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2` when fixing a
+ :term:`reference`.
+
+ ``thr`` is the :term:`thread`.
+
+ ``p`` and ``s`` are the corresponding values that were passed to
+ :c:func:`mps_root_create_reg`.
+
+ Returns a :term:`result code`. If a fix function returns a value
+ other than :c:macro:`MPS_RES_OK`, the scan method must return that
+ value, and may return without fixing any further references.
+ Generally, it is better if it returns as soon as possible. If the
+ scanning is completed successfully, the function should return
+ :c:macro:`MPS_RES_OK`.
+
+ A root scan method is called whenever the MPS needs to scan the
+ root. It must then indicate references within the root by calling
+ :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2`.
+
+ .. seealso::
+
+ :ref:`topic-scanning`.
+
+ .. note::
+
+ :term:`Client programs` are not expected to
+ write scanning functions of this type. The built-in MPS
+ function :c:func:`mps_stack_scan_ambig` must be used.
+
+
+.. c:function:: mps_reg_scan_t mps_stack_scan_ambig
+
+ .. deprecated::
+
+ Use :c:func:`mps_root_create_stack` instead, passing ``0`` for
+ the ``mask`` and ``pattern`` parameters.
+
+ A root scanning function for :term:`ambiguous ` scanning of :term:`threads`, suitable for
+ passing to :c:func:`mps_root_create_reg`.
+
+ It scans all integer registers and everything on the stack of the
+ thread given, and can therefore only be used with :term:`ambiguous
+ roots`. It scans locations that are more recently added to the
+ stack than the location that was passed in the ``p`` argument to
+ :c:func:`mps_root_create_reg`.
+
+ References are assumed to be represented as machine words, and are
+ required to be word-aligned; unaligned values are ignored.
+
+
.. index::
single: deprecated interfaces; in version 1.113
diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst
index 78641fc69a9..e120aa7e925 100644
--- a/mps/manual/source/topic/root.rst
+++ b/mps/manual/source/topic/root.rst
@@ -100,15 +100,10 @@ scan it for references:
#. :c:func:`mps_root_create_table_masked` if the root consists of a
table of :term:`tagged references`;
-#. :c:func:`mps_root_create_reg` if the root consists of the
+#. :c:func:`mps_root_create_stack` if the root consists of the
:term:`registers` and :term:`control stack` of a thread. See
:ref:`topic-root-thread` below.
-#. :c:func:`mps_root_create_reg_masked` if the root consists of the
- :term:`registers` and :term:`control stack` of a thread, and that
- thread keeps tagged references in registers or on the stack. See
- :ref:`topic-root-thread` below.
-
.. index::
pair: root; cautions
@@ -149,21 +144,16 @@ So the typical sequence of operations when creating a root is:
Thread roots
------------
-Every thread's registers and control stack potentially contain
-references to allocated objects, so should be registered as a root by
-calling :c:func:`mps_root_create_reg` or
-:c:func:`mps_root_create_reg_masked`. It's not easy to write a scanner
-for the registers and the stack: it depends on the operating system,
-the processor architecture, and in some cases on the compiler. For
-this reason, the MPS provides :c:func:`mps_stack_scan_ambig` (and in
-fact, this is the only supported stack scanner).
+Every thread's :term:`registers` and :term:`control stack` potentially
+contain references to allocated objects, so should be registered as a
+root by calling :c:func:`mps_root_create_stack`.
-A stack scanner needs to know how to find the bottom of the part of the
-stack to scan. The bottom of the relevant part of stack can be found by
-taking the address of a local variable in the function that calls the
-main work function of your thread. You should take care to ensure that
-the work function is not inlined so that the address is definitely in
-the stack frame below any potential roots.
+The MPS's stack scanner needs to know how to find the bottom of the
+part of the stack to scan. The bottom of the relevant part of stack
+can be found by taking the address of a local variable in the function
+that calls the main work function of your thread. You should take care
+to ensure that the work function is not inlined so that the address is
+definitely in the stack frame below any potential roots.
.. index::
single: Scheme; thread root
@@ -172,26 +162,20 @@ For example, here's the code from the toy Scheme interpreter that
registers a thread root and then calls the program::
mps_thr_t thread;
- mps_root_t reg_root;
+ mps_root_t stack_root;
int exit_code;
void *marker = ▮
res = mps_thread_reg(&thread, arena);
if (res != MPS_RES_OK) error("Couldn't register thread");
- res = mps_root_create_reg(®_root,
- arena,
- mps_rank_ambig(),
- 0,
- thread,
- mps_stack_scan_ambig,
- marker,
- 0);
+ res = mps_root_create_stack(&stack_root, arena, mps_rank_ambig(),
+ 0, thread, 0, 0, marker);
if (res != MPS_RES_OK) error("Couldn't create root");
exit_code = start(argc, argv);
- mps_root_destroy(reg_root);
+ mps_root_destroy(stack_root);
mps_thread_dereg(thread);
@@ -399,117 +383,7 @@ Root interface
calling :c:func:`mps_root_destroy`.
-.. c:function:: mps_res_t mps_root_create_reg(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thr, mps_reg_scan_t reg_scan, void *p, size_t s)
-
- Register a :term:`root` that consists of the :term:`references`
- fixed in a :term:`thread's ` registers and stack by a
- scanning function.
-
- ``root_o`` points to a location that will hold the address of the
- new root description.
-
- ``arena`` is the arena.
-
- ``rank`` is the :term:`rank` of references in the root.
-
- ``rm`` is the :term:`root mode`.
-
- ``thr`` is the thread.
-
- ``reg_scan`` is a scanning function. See :c:type:`mps_reg_scan_t`.
-
- ``p`` and ``s`` are arguments that will be passed to ``reg_scan`` each
- time it is called. This is intended to make it easy to pass, for
- example, an array and its size as parameters.
-
- Returns :c:macro:`MPS_RES_OK` if the root was registered
- successfully, :c:macro:`MPS_RES_MEMORY` if the new root
- description could not be allocated, or another :term:`result code`
- if there was another error.
-
- The registered root description persists until it is destroyed by
- calling :c:func:`mps_root_destroy`.
-
- .. note::
-
- It is not supported for :term:`client programs` to pass their
- own scanning functions to this function. The built-in MPS
- function :c:func:`mps_stack_scan_ambig` must be used. In this
- case the ``p`` argument must be a pointer into the thread's
- stack, as described for :c:func:`mps_root_create_reg_masked`
- below, and the ``s`` argument is ignored.
-
- This function is intended as a hook should we ever need to
- allow client-specific extension or customization of stack and
- register scanning. If you're in a position where you need
- this, for example, if you're writing a compiler and have
- control over what goes in the registers, :ref:`contact us
- `.
-
-
-.. c:type:: mps_res_t (*mps_reg_scan_t)(mps_ss_t ss, mps_thr_t thr, void *p, size_t s)
-
- The type of a root scanning function for roots created with
- :c:func:`mps_root_create_reg`.
-
- ``ss`` is the :term:`scan state`. It must be passed to
- :c:func:`MPS_SCAN_BEGIN` and :c:func:`MPS_SCAN_END` to delimit a
- sequence of fix operations, and to the functions
- :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2` when fixing a
- :term:`reference`.
-
- ``thr`` is the :term:`thread`.
-
- ``p`` and ``s`` are the corresponding values that were passed to
- :c:func:`mps_root_create_reg`.
-
- Returns a :term:`result code`. If a fix function returns a value
- other than :c:macro:`MPS_RES_OK`, the scan method must return that
- value, and may return without fixing any further references.
- Generally, it is better if it returns as soon as possible. If the
- scanning is completed successfully, the function should return
- :c:macro:`MPS_RES_OK`.
-
- A root scan method is called whenever the MPS needs to scan the
- root. It must then indicate references within the root by calling
- :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2`.
-
- .. seealso::
-
- :ref:`topic-scanning`.
-
- .. note::
-
- :term:`Client programs` are not expected to
- write scanning functions of this type. The built-in MPS
- function :c:func:`mps_stack_scan_ambig` must be used.
-
-
-.. c:function:: mps_reg_scan_t mps_stack_scan_ambig
-
- A root scanning function for :term:`ambiguous ` scanning of :term:`threads`, suitable for
- passing to :c:func:`mps_root_create_reg`.
-
- It scans all integer registers and everything on the stack of the
- thread given, and can therefore only be used with :term:`ambiguous
- roots`. It scans locations that are more recently added than the
- stack bottom that was passed in the ``p`` argument to
- :c:func:`mps_root_create_reg`.
-
- References are assumed to be represented as machine words, and are
- required to be word-aligned; unaligned values are ignored. If
- references are tagged, use :c:func:`mps_root_create_reg_masked`
- instead.
-
- .. note::
-
- The MPS provides this function because it's hard to write: it
- depends on the operating system, the processor architecture,
- and in some cases on the compiler.
-
-
-.. c:function:: mps_res_t mps_root_create_reg_masked(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thr, mps_word_t mask, mps_word_t pattern, void *stack)
+.. c:function:: mps_res_t mps_root_create_stack(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thr, mps_word_t mask, mps_word_t pattern, void *stack)
Register a :term:`root` that consists of the :term:`references` in
a :term:`thread's ` registers and stack that match a
diff --git a/mps/manual/source/topic/thread.rst b/mps/manual/source/topic/thread.rst
index a470dedf420..86a54d36ebe 100644
--- a/mps/manual/source/topic/thread.rst
+++ b/mps/manual/source/topic/thread.rst
@@ -47,8 +47,8 @@ see :ref:`topic-root-thread`).
For simplicity, we recommend that a thread must be registered with an
:term:`arena` if:
-* its registers and control stack form a root (this is enforced by
- :c:func:`mps_root_create_reg`); or
+* its :term:`control stack` and :term:`registers` form a root (this is
+ enforced by :c:func:`mps_root_create_stack`); or
* it reads or writes from a location in an :term:`automatically managed
` :term:`pool` in the arena.
@@ -116,8 +116,9 @@ Thread interface
as necessary in order to have exclusive access to their state.
Even in a single-threaded environment it may be necessary to
- register a thread with the MPS so that its stack can be registered
- as a :term:`root` by calling :c:func:`mps_root_create_reg`.
+ register a thread with the MPS so that its :term:`control stack`
+ and :term:`registers` can be registered as a :term:`root` by
+ calling :c:func:`mps_root_create_stack`.
.. c:function:: mps_res_t mps_thread_reg(mps_thr_t *thr_o, mps_arena_t arena)
From 400c2ab8d153ee003a18e14afc4d97976d6701d3 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 14 Sep 2015 20:40:49 +0100
Subject: [PATCH 096/337] Test the stack scanning more thoroughly, as suggested
by nb in point 4 of
Copied from Perforce
Change: 188315
ServerID: perforce.ravenbrook.com
---
mps/code/tagtest.c | 98 +++++++++++++++++++++++-----------------------
1 file changed, 48 insertions(+), 50 deletions(-)
diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c
index 96f4605546d..76299f6cbce 100644
--- a/mps/code/tagtest.c
+++ b/mps/code/tagtest.c
@@ -114,35 +114,57 @@ static mps_addr_t skip(mps_addr_t addr)
}
-/* alloc_list -- Allocate a linked list with 'count' entries. The
- * attribute prevents the compiler from inlining this function into
- * test, which might leave untagged temporaries on the stack,
- * confusing the test logic.
- */
-
-ATTRIBUTE_NOINLINE
-static mps_word_t alloc_list(mps_arena_t arena, mps_ap_t ap, size_t count)
+static void collect(mps_arena_t arena, size_t expected)
{
- mps_word_t nil = TAGGED(NULL, cons);
- mps_word_t p = nil;
- size_t i;
- for (i = 0; i < count; ++i) {
- mps_addr_t addr;
- p = make_cons(ap, TAGGED(i << tag_bits, imm), p);
- Insist(TAG(p) == tag_cons);
- addr = (mps_addr_t)p;
- die(mps_finalize(arena, &addr), "finalize");
+ size_t finalized = 0;
+ mps_arena_collect(arena);
+ while (mps_message_poll(arena)) {
+ mps_message_t message;
+ mps_addr_t objaddr;
+ cdie(mps_message_get(&message, arena, mps_message_type_finalization()),
+ "message_get");
+ mps_message_finalization_ref(&objaddr, arena, message);
+ Insist(TAG(objaddr) == tag_cons);
+ mps_message_discard(arena, message);
+ ++ finalized;
}
- return p;
+ printf("tag_cons=%lu finalized=%lu expected=%lu\n",
+ (unsigned long)tag_cons, (unsigned long)finalized, (unsigned long)expected);
+ Insist(finalized == expected);
}
-/* test -- Run the test case in the specified mode. The attribute
- * prevents the compiler from inlining this function into main, which
- * might end up with stack slots like 'p' being above 'marker' and so
- * not scanned.
+/* alloc_recursively -- Allocate 'count' objects and remember pointers
+ * to those objects on the stack.
*/
+static void alloc_recursively(mps_arena_t arena, mps_ap_t ap,
+ size_t expected, size_t count)
+{
+ mps_word_t p, r;
+ mps_word_t q = TAGGED(count << tag_bits, imm);
+ mps_addr_t addr;
+ p = make_cons(ap, q, q);
+ Insist(TAG(p) == tag_cons);
+ r = TAGGED(p, imm);
+ UNTAGGED(p, cons)->cdr = r;
+ addr = (mps_addr_t)p;
+ die(mps_finalize(arena, &addr), "finalize");
+ if (count > 1) {
+ alloc_recursively(arena, ap, expected, count - 1);
+ } else {
+ collect(arena, expected);
+ }
+ if (expected == 0) {
+ Insist(TAG(p) == tag_cons);
+ Insist(UNTAGGED(p, cons)->car == q);
+ Insist(UNTAGGED(p, cons)->cdr == r);
+ }
+}
+
+
+/* test -- Run the test case in the specified mode. */
+
enum {
MODE_DEFAULT, /* Use default scanner (tagged with 0). */
MODE_CONS, /* Scan words tagged "cons". */
@@ -150,7 +172,6 @@ enum {
MODE_LIMIT
};
-ATTRIBUTE_NOINLINE
static void test(int mode, void *marker)
{
mps_arena_t arena;
@@ -159,9 +180,6 @@ static void test(int mode, void *marker)
mps_fmt_t fmt;
mps_pool_t pool;
mps_ap_t ap;
- mps_word_t p;
- size_t i;
- size_t finalized = 0;
size_t expected = 0;
die(mps_arena_create(&arena, mps_arena_class_vm(), mps_args_none), "arena");
@@ -169,6 +187,9 @@ static void test(int mode, void *marker)
die(mps_thread_reg(&thread, arena), "thread");
switch (mode) {
+ default:
+ Insist(0);
+ /* fall through */
case MODE_DEFAULT:
/* Default stack scanner only recognizes words tagged with 0. */
die(mps_root_create_reg(&root, arena, mps_rank_ambig(), 0, thread,
@@ -187,9 +208,6 @@ static void test(int mode, void *marker)
TAG_MASK, tag_invalid, marker), "root");
expected = OBJCOUNT;
break;
- default:
- Insist(0);
- break;
}
MPS_ARGS_BEGIN(args) {
@@ -210,27 +228,7 @@ static void test(int mode, void *marker)
die(mps_ap_create_k(&ap, pool, mps_args_none), "ap");
- p = alloc_list(arena, ap, OBJCOUNT);
- printf("tag_cons=%lu &p=%p expected=%lu\n",
- (unsigned long)tag_cons, (void*)&p, (unsigned long)expected);
-
- mps_arena_collect(arena);
- while (mps_message_poll(arena)) {
- mps_message_t message;
- mps_addr_t objaddr;
- cdie(mps_message_get(&message, arena, mps_message_type_finalization()),
- "message_get");
- mps_message_finalization_ref(&objaddr, arena, message);
- Insist(TAG(objaddr) == tag_cons);
- mps_message_discard(arena, message);
- ++ finalized;
- }
-
- Insist(finalized == expected);
- for (i = 0; i < OBJCOUNT - expected; ++i) {
- Insist(TAG(p) == tag_cons);
- p = UNTAGGED(p, cons)->cdr;
- }
+ alloc_recursively(arena, ap, expected, OBJCOUNT);
mps_arena_park(arena);
mps_ap_destroy(ap);
From 0bebdf5ad1d7b5ac6bdfbbf8b9f459062266d7d4 Mon Sep 17 00:00:00 2001
From: Gareth Rees
Date: Mon, 14 Sep 2015 21:17:19 +0100
Subject: [PATCH 097/337] Need to pass sizeof(mps_word_t) - 1 for the mask
argument to get the old behaviour.
Copied from Perforce
Change: 188317
ServerID: perforce.ravenbrook.com
---
mps/code/airtest.c | 2 +-
mps/code/amcssth.c | 6 ++++--
mps/code/awlut.c | 3 ++-
mps/code/awluthe.c | 3 ++-
mps/code/awlutth.c | 3 ++-
mps/code/gcbench.c | 6 +++---
mps/code/mpsicv.c | 2 +-
mps/code/zcoll.c | 4 ++--
mps/code/zmess.c | 2 +-
mps/example/scheme/scheme-advanced.c | 2 +-
mps/example/scheme/scheme.c | 2 +-
mps/manual/source/guide/lang.rst | 2 +-
mps/manual/source/topic/deprecated.rst | 9 ++++++---
13 files changed, 27 insertions(+), 19 deletions(-)
diff --git a/mps/code/airtest.c b/mps/code/airtest.c
index 53537ea4c35..302f91bb716 100644
--- a/mps/code/airtest.c
+++ b/mps/code/airtest.c
@@ -128,7 +128,7 @@ static void test_main(void *marker, int interior, int stack)
if (stack) {
res = mps_root_create_stack(®_root, scheme_arena, mps_rank_ambig(),
- 0, thread, 0, 0, marker);
+ 0, thread, sizeof(mps_word_t) - 1, 0, marker);
if (res != MPS_RES_OK)
error("Couldn't create root");
}
diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c
index 51f1a12b9cb..bd06dc9b2c6 100644
--- a/mps/code/amcssth.c
+++ b/mps/code/amcssth.c
@@ -140,7 +140,8 @@ static void *kid_thread(void *arg)
die(mps_thread_reg(&thread, (mps_arena_t)arena), "thread_reg");
die(mps_root_create_stack(®_root, arena, mps_rank_ambig(),
- 0, thread, 0, 0, marker), "root_create");
+ 0, thread, sizeof(mps_word_t) - 1, 0, marker),
+ "root_create");
die(mps_ap_create(&ap, cl->pool, mps_rank_exact()), "BufferCreate(fooey)");
while(mps_collections(arena) < collectionsCOUNT) {
@@ -317,7 +318,8 @@ static void test_arena(int mode)
"root_create_table(ambig)");
die(mps_thread_reg(&thread, arena), "thread_reg");
die(mps_root_create_stack(®_root, arena, mps_rank_ambig(),
- 0, thread, 0, 0, marker), "root_create");
+ 0, thread, sizeof(mps_word_t) - 1, 0, marker),
+ "root_create");
die(mps_pool_create(&amc_pool, arena, mps_class_amc(), format, chain),
"pool_create(amc)");
diff --git a/mps/code/awlut.c b/mps/code/awlut.c
index eeaa788ae5f..93575df854a 100644
--- a/mps/code/awlut.c
+++ b/mps/code/awlut.c
@@ -267,7 +267,8 @@ static void *setup(void *v, size_t s)
arena = guff->arena;
thr = guff->thr;
- die(mps_root_create_stack(&stack, arena, mps_rank_ambig(), 0, thr, 0, 0, v),
+ die(mps_root_create_stack(&stack, arena, mps_rank_ambig(),
+ 0, thr, sizeof(mps_word_t) - 1, 0, v),
"Root Create\n");
die(mps_fmt_create_A(&dylanfmt, arena, dylan_fmt_A()),
"Format Create\n");
diff --git a/mps/code/awluthe.c b/mps/code/awluthe.c
index 18b8347e1fd..e8b22f6ebb9 100644
--- a/mps/code/awluthe.c
+++ b/mps/code/awluthe.c
@@ -271,7 +271,8 @@ static void *setup(void *v, size_t s)
arena = guff->arena;
thr = guff->thr;
- die(mps_root_create_stack(&stack, arena, mps_rank_ambig(), 0, thr, 0, 0, v),
+ die(mps_root_create_stack(&stack, arena, mps_rank_ambig(),
+ 0, thr, sizeof(mps_word_t) - 1, 0, v),
"Root Create\n");
die(EnsureHeaderFormat(&dylanfmt, arena), "EnsureHeaderFormat");
die(EnsureHeaderWeakFormat(&dylanweakfmt, arena), "EnsureHeaderWeakFormat");
diff --git a/mps/code/awlutth.c b/mps/code/awlutth.c
index 1d73a98f29f..b9b60aff962 100644
--- a/mps/code/awlutth.c
+++ b/mps/code/awlutth.c
@@ -254,7 +254,8 @@ static void *setup(void *v, size_t s)
arena = guff->arena;
thr = guff->thr;
- die(mps_root_create_stack(&stack, arena, mps_rank_ambig(), 0, thr, 0, 0, v),
+ die(mps_root_create_stack(&stack, arena, mps_rank_ambig(),
+ 0, thr, sizeof(mps_word_t) - 1, 0, v),
"Root Create\n");
die(mps_fmt_create_A(&dylanfmt, arena, dylan_fmt_A()),
"Format Create\n");
diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c
index 2220ea3ffc8..a65a06108e7 100644
--- a/mps/code/gcbench.c
+++ b/mps/code/gcbench.c
@@ -171,9 +171,9 @@ static void *start(void *p) {
gcthread_t thread = p;
void *marker;
RESMUST(mps_thread_reg(&thread->mps_thread, arena));
- RESMUST(mps_root_create_stack(&thread->reg_root, arena,
- mps_rank_ambig(), (mps_rm_t)0,
- thread->mps_thread, 0, 0, &marker));
+ RESMUST(mps_root_create_stack(&thread->reg_root, arena, mps_rank_ambig(),
+ (mps_rm_t)0, thread->mps_thread,
+ sizeof(mps_word_t) - 1, 0, &marker));
RESMUST(mps_ap_create_k(&thread->ap, pool, mps_args_none));
thread->fn(thread);
mps_ap_destroy(thread->ap);
diff --git a/mps/code/mpsicv.c b/mps/code/mpsicv.c
index 2d3caac8dd8..87d1e02419e 100644
--- a/mps/code/mpsicv.c
+++ b/mps/code/mpsicv.c
@@ -600,7 +600,7 @@ int main(int argc, char *argv[])
} else {
die(mps_root_create_stack(®_root, arena,
mps_rank_ambig(), (mps_rm_t)0,
- thread, 0, 0, marker),
+ thread, sizeof(mps_word_t) - 1, 0, marker),
"root_create_stack");
}
diff --git a/mps/code/zcoll.c b/mps/code/zcoll.c
index 307cc215c7a..64fd5406018 100644
--- a/mps/code/zcoll.c
+++ b/mps/code/zcoll.c
@@ -576,7 +576,7 @@ static void StackScan(mps_arena_t arena, int on)
Insist(root_stackreg == NULL);
die(mps_root_create_stack(&root_stackreg, arena,
mps_rank_ambig(), (mps_rm_t)0, stack_thr,
- 0, 0, stack_start),
+ sizeof(mps_word_t) - 1, 0, stack_start),
"root_stackreg");
Insist(root_stackreg != NULL);
} else {
@@ -764,7 +764,7 @@ static void *testscriptB(void *arg, size_t s)
stack_thr = thr;
die(mps_root_create_stack(&root_stackreg, arena,
mps_rank_ambig(), (mps_rm_t)0, stack_thr,
- 0, 0, stack_start),
+ sizeof(mps_word_t) - 1, 0, stack_start),
"root_stackreg");
diff --git a/mps/code/zmess.c b/mps/code/zmess.c
index e6efe7a702d..ff7cb526509 100644
--- a/mps/code/zmess.c
+++ b/mps/code/zmess.c
@@ -332,7 +332,7 @@ static void *testscriptB(void *arg, size_t s)
/* root_stackreg: stack & registers are ambiguous roots = mutator's workspace */
die(mps_root_create_stack(&root_stackreg, arena,
mps_rank_ambig(), (mps_rm_t)0, thr,
- 0, 0, &stack_starts_here),
+ sizeof(mps_word_t) - 1, 0, &stack_starts_here),
"root_stackreg");
/* Make myrootCOUNT registered-for-finalization objects. */
diff --git a/mps/example/scheme/scheme-advanced.c b/mps/example/scheme/scheme-advanced.c
index 2b5bb6c30be..8f1b83a26a7 100644
--- a/mps/example/scheme/scheme-advanced.c
+++ b/mps/example/scheme/scheme-advanced.c
@@ -4593,7 +4593,7 @@ int main(int argc, char *argv[])
objects around in C parameters, return values, and keeping them in
automatic local variables. See topic/root. */
res = mps_root_create_stack(®_root, arena, mps_rank_ambig(),
- 0, thread, 0, 0, marker);
+ 0, thread, sizeof(mps_word_t) - 1, 0, marker);
if (res != MPS_RES_OK) error("Couldn't create root");
/* Make sure we can pick up finalization messages. */
diff --git a/mps/example/scheme/scheme.c b/mps/example/scheme/scheme.c
index f088e655f14..dacdfd93ab5 100644
--- a/mps/example/scheme/scheme.c
+++ b/mps/example/scheme/scheme.c
@@ -4488,7 +4488,7 @@ int main(int argc, char *argv[])
objects around in C parameters, return values, and keeping them in
automatic local variables. See topic/root. */
res = mps_root_create_stack(®_root, arena, mps_rank_ambig(),
- 0, thread, 0, 0, marker);
+ 0, thread, sizeof(mps_word_t) - 1, 0, marker);
if (res != MPS_RES_OK) error("Couldn't create root");
/* Make sure we can pick up finalization messages. */
diff --git a/mps/manual/source/guide/lang.rst b/mps/manual/source/guide/lang.rst
index 9a864e47414..0205ceccd4d 100644
--- a/mps/manual/source/guide/lang.rst
+++ b/mps/manual/source/guide/lang.rst
@@ -977,7 +977,7 @@ as a root by calling :c:func:`mps_root_create_stack`::
void *marker = ▮
mps_root_t stack_root;
res = mps_root_create_stack(®_root, arena, mps_rank_ambig(),
- 0, thread, 0, 0, marker);
+ 0, thread, sizeof(mps_word_t) - 1, 0, marker);
if (res != MPS_RES_OK) error("Couldn't create root");
In order to scan the control stack, the MPS needs to know where the
diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst
index 77594d4c020..e2407c7b7d1 100644
--- a/mps/manual/source/topic/deprecated.rst
+++ b/mps/manual/source/topic/deprecated.rst
@@ -122,7 +122,9 @@ Deprecated in version 1.115
.. deprecated::
- Use :c:func:`mps_root_create_stack` instead.
+ Use :c:func:`mps_root_create_stack` instead, passing
+ ``sizeof(mps_word_t) - 1`` for the ``mask`` argument, and
+ ``0`` for the ``pattern`` argument.
Register a :term:`root` that consists of the :term:`references`
fixed in a :term:`thread's ` registers and stack by a
@@ -210,8 +212,9 @@ Deprecated in version 1.115
.. deprecated::
- Use :c:func:`mps_root_create_stack` instead, passing ``0`` for
- the ``mask`` and ``pattern`` parameters.
+ Use :c:func:`mps_root_create_stack` instead, passing
+ ``sizeof(mps_word_t) - 1`` for the ``mask`` argument, and
+ ``0`` for the ``pattern`` argument.
A root scanning function for :term:`ambiguous ` scanning of :term:`threads`, suitable for
From b5fe5356ec2bac4f190cbf8d58541eca970233e9 Mon Sep 17 00:00:00 2001
From: Nick Barnes
Date: Tue, 13 Oct 2015 15:19:12 +0100
Subject: [PATCH 098/337] Improve documentation of mps_fix_call(): the called
function must use mps_scan_begin and mps_scan_end itself.
Copied from Perforce
Change: 188410
ServerID: perforce.ravenbrook.com
---
mps/manual/source/topic/scanning.rst | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
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::
From 65bd8e550f6ce3bca6a008bc00d74cc6d8433206 Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Mon, 21 Dec 2015 11:06:06 +0000
Subject: [PATCH 099/337] Making lack of section numbers consistent.
Improving attributions.
Copied from Perforce
Change: 188846
ServerID: perforce.ravenbrook.com
---
mps/design/guide.hex.trans.txt | 40 +++++++++++++++++++++++++++++-----
1 file changed, 34 insertions(+), 6 deletions(-)
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.
From 2aacdd3867004fecf1f445d765f8b7c02d8bbc04 Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Thu, 14 Jan 2016 17:34:49 +0000
Subject: [PATCH 100/337] Using os-provided getopt_long where available, since
it doesn't compile cleanly on os x.
The getopt_long code promises that the argv array is const, but permutes it. (This problem is mentioned in the man page.) We have trouble getting this past our strict compiler options, especially under Xcode.
Copied from Perforce
Change: 188909
ServerID: perforce.ravenbrook.com
---
mps/code/djbench.c | 7 ++++++-
mps/code/gcbench.c | 7 ++++++-
mps/code/mps.xcodeproj/project.pbxproj | 8 --------
3 files changed, 12 insertions(+), 10 deletions(-)
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 2ae97104930..6d7f3339667 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/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;
From eac348d664282b12d2e38c94254adf8fa2738f11 Mon Sep 17 00:00:00 2001
From: Richard Brooksby
Date: Tue, 19 Jan 2016 16:22:39 +0000
Subject: [PATCH 101/337] Catch-up merge from masters.
Copied from Perforce
Change: 188921
ServerID: perforce.ravenbrook.com
---
mps/Makefile.in | 2 +-
mps/code/.p4ignore | 2 +
mps/code/amcss.c | 24 +-
mps/code/amcssth.c | 208 ++++---
mps/code/ananmv.nmk | 3 +-
mps/code/arena.c | 206 ++++---
mps/code/arenacl.c | 68 ++-
mps/code/arenavm.c | 48 +-
mps/code/buffer.c | 8 +-
mps/code/cbs.c | 6 +-
mps/code/comm.gmk | 7 +-
mps/code/{commpost.nmk => comm.nmk} | 337 ++++++++++-
mps/code/commpre.nmk | 369 ------------
mps/code/djbench.c | 7 +-
mps/code/freelist.c | 22 +-
mps/code/gcbench.c | 7 +-
mps/code/global.c | 3 +-
mps/code/land.c | 16 +-
mps/code/ld.c | 17 +-
mps/code/mpm.c | 14 +-
mps/code/mpm.h | 8 +-
mps/code/mpmst.h | 4 +-
mps/code/mpmtypes.h | 1 -
mps/code/mps.c | 1 -
mps/code/mps.xcodeproj/project.pbxproj | 28 +-
mps/code/mpsi.c | 11 +-
mps/code/mv.nmk | 2 +-
mps/code/pc.nmk | 2 +-
mps/code/pool.c | 6 +-
mps/code/poolabs.c | 10 +-
mps/code/poolawl.c | 5 +-
mps/code/poolmv.c | 13 +-
mps/code/protan.c | 7 +-
mps/code/protix.c | 5 +-
mps/code/protw3.c | 5 +-
mps/code/reserv.c | 1 +
mps/code/root.c | 19 +-
mps/code/seg.c | 14 +-
mps/code/shield.c | 7 +-
mps/code/splay.c | 11 +-
mps/code/trace.c | 5 +-
mps/code/traceanc.c | 5 +-
mps/code/tract.c | 11 +-
mps/code/tract.h | 6 +-
mps/code/tree.c | 11 +-
mps/code/w3i3mv.nmk | 6 +-
mps/code/w3i3pc.nmk | 6 +-
mps/code/w3i6mv.nmk | 7 +-
mps/code/w3i6pc.nmk | 8 +-
mps/design/an.txt | 216 +++++++
mps/design/bootstrap.txt | 127 ++++
mps/design/cbs.txt | 4 +-
mps/design/exec-env.txt | 189 ++++++
mps/design/guide.hex.trans.txt | 40 +-
mps/design/guide.review.txt | 96 +++
mps/design/index.txt | 12 +-
mps/design/io.txt | 8 +-
mps/design/land.txt | 14 +-
mps/design/lib.txt | 10 +-
mps/design/lock.txt | 8 +-
mps/design/prmc.txt | 2 +-
mps/design/prot.txt | 17 +-
mps/design/protan.txt | 135 -----
mps/design/sp.txt | 9 +-
mps/design/splay-rotate-left.svg | 4 +-
mps/design/splay-rotate-right.svg | 4 +-
mps/design/ss.txt | 2 +-
mps/design/testthr.txt | 2 +-
mps/design/type.txt | 4 +-
mps/design/vm.txt | 4 +-
mps/design/writef.txt | 46 +-
mps/manual/build.txt | 3 +-
mps/manual/source/_templates/links.html | 4 +-
mps/manual/source/design/index.rst | 5 +
mps/manual/source/design/old.rst | 2 -
mps/manual/source/glossary/b.rst | 17 +-
mps/manual/source/glossary/index.rst | 1 +
mps/manual/source/glossary/m.rst | 6 +-
mps/manual/source/glossary/r.rst | 2 +-
mps/manual/source/guide/index.rst | 2 +-
mps/manual/source/guide/lang.rst | 35 +-
mps/manual/source/guide/malloc.rst | 70 +++
mps/manual/source/pool/amc.rst | 20 +-
mps/manual/source/pool/amcz.rst | 13 +-
mps/manual/source/pool/ams.rst | 35 +-
mps/manual/source/pool/awl.rst | 21 +-
mps/manual/source/pool/lo.rst | 9 -
mps/manual/source/pool/mfs.rst | 13 +-
mps/manual/source/pool/mv.rst | 64 +-
mps/manual/source/pool/mvff.rst | 100 +---
mps/manual/source/pool/mvt.rst | 52 +-
mps/manual/source/pool/snc.rst | 30 +-
mps/manual/source/release.rst | 148 ++++-
mps/manual/source/topic/allocation.rst | 28 +-
mps/manual/source/topic/arena.rst | 187 +-----
mps/manual/source/topic/deprecated.rst | 745 ++++++++++++++++++++++++
mps/manual/source/topic/error.rst | 111 ++--
mps/manual/source/topic/format.rst | 154 +----
mps/manual/source/topic/index.rst | 2 +
mps/manual/source/topic/interface.rst | 7 +-
mps/manual/source/topic/keyword.rst | 82 ++-
mps/manual/source/topic/plinth.rst | 10 +
mps/manual/source/topic/pool.rst | 40 +-
mps/manual/source/topic/porting.rst | 137 +++--
mps/manual/source/topic/scanning.rst | 44 +-
mps/manual/source/topic/telemetry.rst | 35 --
mps/manual/source/topic/thread.rst | 44 --
mps/test/README | 19 +-
mps/test/argerr/111.c | 4 +
mps/test/argerr/143.c | 4 +
mps/test/argerr/146.c | 17 +-
mps/test/argerr/147.c | 8 +-
mps/test/argerr/148.c | 8 +-
mps/test/argerr/149.c | 6 +-
mps/test/argerr/150.c | 6 +-
mps/test/argerr/151.c | 6 +-
mps/test/argerr/35.c | 2 +-
mps/test/argerr/36.c | 11 +-
mps/test/conerr/22.c | 2 +-
mps/test/conerr/26.c | 2 +-
mps/test/conerr/3.c | 6 +-
mps/test/function/103.c | 4 +-
mps/test/function/120.c | 12 +-
mps/test/function/121.c | 50 +-
mps/test/function/137.c | 8 +-
mps/test/function/139.c | 8 +-
mps/test/function/144.c | 8 +-
mps/test/function/150.c | 7 +-
mps/test/function/158.c | 8 +-
mps/test/function/159.c | 8 +-
mps/test/function/160.c | 7 +-
mps/test/function/161.c | 7 +-
mps/test/function/162.c | 7 +-
mps/test/function/163.c | 8 +-
mps/test/function/18.c | 8 +-
mps/test/function/19.c | 6 +-
mps/test/function/20.c | 3 +-
mps/test/function/21.c | 3 +-
mps/test/function/22.c | 3 +-
mps/test/function/224.c | 2 +-
mps/test/function/226.c | 6 +-
mps/test/function/227.c | 19 +-
mps/test/function/229.c | 74 +++
mps/test/function/23.c | 10 +-
mps/test/function/96.c | 8 +-
mps/test/test/script/clib | 6 +-
mps/test/test/script/headread | 2 +-
mps/test/test/script/options | 2 +-
mps/test/test/script/runtest | 2 +-
mps/test/testsets/argerr | 22 +-
mps/test/testsets/conerr | 18 +-
mps/test/testsets/passing | 2 +
mps/tool/testrun.bat | 10 +-
mps/tool/testrun.sh | 80 ++-
154 files changed, 3259 insertions(+), 2100 deletions(-)
rename mps/code/{commpost.nmk => comm.nmk} (64%)
delete mode 100644 mps/code/commpre.nmk
create mode 100644 mps/design/an.txt
create mode 100644 mps/design/bootstrap.txt
create mode 100644 mps/design/exec-env.txt
create mode 100644 mps/design/guide.review.txt
delete mode 100644 mps/design/protan.txt
create mode 100644 mps/manual/source/guide/malloc.rst
create mode 100644 mps/manual/source/topic/deprecated.rst
create mode 100644 mps/test/function/229.c
diff --git a/mps/Makefile.in b/mps/Makefile.in
index 1495a0fc313..fe33a4d49f6 100644
--- a/mps/Makefile.in
+++ b/mps/Makefile.in
@@ -73,7 +73,7 @@ install: @INSTALL_TARGET@
test-make-build:
$(MAKE) $(TARGET_OPTS) testci
$(MAKE) -C code -f anan$(MPS_BUILD_NAME).gmk VARIETY=cool clean testansi
- $(MAKE) -C code -f anan$(MPS_BUILD_NAME).gmk VARIETY=cool CFLAGS="-DCONFIG_POLL_NONE" clean testpoll
+ $(MAKE) -C code -f anan$(MPS_BUILD_NAME).gmk VARIETY=cool CFLAGS="-DCONFIG_POLL_NONE" clean testpollnone
test-xcode-build:
$(XCODEBUILD) -config Debug -target testci
diff --git a/mps/code/.p4ignore b/mps/code/.p4ignore
index 6cb34b80f0c..2864ba7793f 100644
--- a/mps/code/.p4ignore
+++ b/mps/code/.p4ignore
@@ -10,7 +10,9 @@ lii3gc
lii6gc
lii6ll
w3i3mv
+w3i3pc
w3i6mv
+w3i6pc
xci3gc
xci6ll
# Visual Studio junk
diff --git a/mps/code/amcss.c b/mps/code/amcss.c
index bc0d8861149..3b15f7fb967 100644
--- a/mps/code/amcss.c
+++ b/mps/code/amcss.c
@@ -45,14 +45,14 @@ static mps_ap_t ap;
static mps_addr_t exactRoots[exactRootsCOUNT];
static mps_addr_t ambigRoots[ambigRootsCOUNT];
static size_t scale; /* Overall scale factor. */
+static unsigned long nCollsStart;
+static unsigned long nCollsDone;
/* report -- report statistics from any messages */
static void report(mps_arena_t arena)
{
- static int nCollsStart = 0;
- static int nCollsDone = 0;
mps_message_type_t type;
while(mps_message_queue_type(&type, arena)) {
@@ -62,7 +62,7 @@ static void report(mps_arena_t arena)
if (type == mps_message_type_gc_start()) {
nCollsStart += 1;
- printf("\n{\n Collection %d started. Because:\n", nCollsStart);
+ printf("\n{\n Collection %lu started. Because:\n", nCollsStart);
printf(" %s\n", mps_message_gc_start_why(arena, message));
printf(" clock: %"PRIuLONGEST"\n", (ulongest_t)mps_message_clock(arena, message));
@@ -74,7 +74,7 @@ static void report(mps_arena_t arena)
condemned = mps_message_gc_condemned_size(arena, message);
not_condemned = mps_message_gc_not_condemned_size(arena, message);
- printf("\n Collection %d finished:\n", nCollsDone);
+ printf("\n Collection %lu finished:\n", nCollsDone);
printf(" live %"PRIuLONGEST"\n", (ulongest_t)live);
printf(" condemned %"PRIuLONGEST"\n", (ulongest_t)condemned);
printf(" not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned);
@@ -94,10 +94,12 @@ static void report(mps_arena_t arena)
static mps_addr_t make(size_t rootsCount)
{
+ static unsigned long calls = 0;
size_t length = rnd() % (scale * avLEN);
size_t size = (length+2) * sizeof(mps_word_t);
mps_addr_t p;
mps_res_t res;
+ ++ calls;
do {
MPS_RESERVE_BLOCK(res, p, ap, size);
@@ -167,6 +169,8 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class,
/* create an ap, and leave it busy */
die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy");
+ nCollsStart = 0;
+ nCollsDone = 0;
collections = 0;
rampSwitch = rampSIZE;
die(mps_ap_alloc_pattern_begin(ap, ramp), "pattern begin (ap)");
@@ -174,20 +178,18 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class,
ramping = 1;
objs = 0;
while (collections < collectionsCOUNT) {
- mps_word_t c;
size_t r;
- c = mps_collections(arena);
- if (collections != c) {
+ report(arena);
+ if (collections != nCollsStart) {
if (!described) {
die(ArenaDescribe(arena, mps_lib_get_stdout(), 0), "ArenaDescribe");
described = TRUE;
}
- collections = c;
- report(arena);
+ collections = nCollsStart;
- printf("%lu objects (mps_collections says: %"PRIuLONGEST")\n", objs,
- (ulongest_t)c);
+ printf("%lu objects (nCollsStart=%"PRIuLONGEST")\n", objs,
+ (ulongest_t)collections);
/* test mps_arena_has_addr */
{
diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c
index 59b48ff27c4..c6e2d214b5d 100644
--- a/mps/code/amcssth.c
+++ b/mps/code/amcssth.c
@@ -59,33 +59,9 @@ static mps_gen_param_s testChain[genCOUNT] = {
static mps_addr_t exactRoots[exactRootsCOUNT];
static mps_addr_t ambigRoots[ambigRootsCOUNT];
-/* report - report statistics from any terminated GCs */
-
-static void report(mps_arena_t arena)
-{
- mps_message_t message;
- static int nCollections = 0;
-
- while (mps_message_get(&message, arena, mps_message_type_gc())) {
- size_t live, condemned, not_condemned;
-
- live = mps_message_gc_live_size(arena, message);
- condemned = mps_message_gc_condemned_size(arena, message);
- not_condemned = mps_message_gc_not_condemned_size(arena, message);
-
- printf("\nCollection %d finished:\n", ++nCollections);
- printf("live %"PRIuLONGEST"\n", (ulongest_t)live);
- printf("condemned %"PRIuLONGEST"\n", (ulongest_t)condemned);
- printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned);
-
- mps_message_discard(arena, message);
- }
-}
-
+static mps_word_t collections;
static mps_arena_t arena;
-static mps_fmt_t format;
-static mps_chain_t chain;
static mps_root_t exactRoot, ambigRoot;
static unsigned long objs = 0;
@@ -123,32 +99,6 @@ static void test_stepper(mps_addr_t object, mps_fmt_t fmt, mps_pool_t pool,
}
-/* init -- initialize roots and chain */
-
-static void init(void)
-{
- size_t i;
-
- die(dylan_fmt(&format, arena), "fmt_create");
- die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
-
- for(i = 0; i < exactRootsCOUNT; ++i)
- exactRoots[i] = objNULL;
- for(i = 0; i < ambigRootsCOUNT; ++i)
- ambigRoots[i] = rnd_addr();
-
- die(mps_root_create_table_masked(&exactRoot, arena,
- mps_rank_exact(), (mps_rm_t)0,
- &exactRoots[0], exactRootsCOUNT,
- (mps_word_t)1),
- "root_create_table(exact)");
- die(mps_root_create_table(&ambigRoot, arena,
- mps_rank_ambig(), (mps_rm_t)0,
- &ambigRoots[0], ambigRootsCOUNT),
- "root_create_table(ambig)");
-}
-
-
/* churn -- create an object and install into roots */
static void churn(mps_ap_t ap, size_t roots_count)
@@ -207,10 +157,11 @@ static void *kid_thread(void *arg)
/* test -- the body of the test */
-static void test_pool(mps_pool_t pool, size_t roots_count, int mode)
+static void test_pool(const char *name, mps_pool_t pool, size_t roots_count,
+ int mode)
{
size_t i;
- mps_word_t collections, rampSwitch;
+ mps_word_t rampSwitch;
mps_alloc_pattern_t ramp = mps_alloc_pattern_ramp();
int ramping;
mps_ap_t ap, busy_ap;
@@ -219,8 +170,12 @@ static void test_pool(mps_pool_t pool, size_t roots_count, int mode)
closure_s cl;
int walked = FALSE, ramped = FALSE;
+ printf("\n------ mode: %s pool: %s-------\n",
+ mode == ModeWALK ? "WALK" : "COMMIT", name);
+
cl.pool = pool;
cl.roots_count = roots_count;
+ collections = 0;
for (i = 0; i < NELEMS(kids); ++i)
testthr_create(&kids[i], kid_thread, &cl);
@@ -231,72 +186,85 @@ static void test_pool(mps_pool_t pool, size_t roots_count, int mode)
/* create an ap, and leave it busy */
die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy");
- collections = 0;
rampSwitch = rampSIZE;
die(mps_ap_alloc_pattern_begin(ap, ramp), "pattern begin (ap)");
die(mps_ap_alloc_pattern_begin(busy_ap, ramp), "pattern begin (busy_ap)");
ramping = 1;
while (collections < collectionsCOUNT) {
- mps_word_t c;
- size_t r;
+ mps_message_type_t type;
- c = mps_collections(arena);
+ if (mps_message_queue_type(&type, arena)) {
+ mps_message_t msg;
+ mps_bool_t b = mps_message_get(&msg, arena, type);
+ Insist(b); /* we just checked there was one */
- if (collections != c) {
- collections = c;
- printf("\nCollection %lu started, %lu objects, committed=%lu.\n",
- (unsigned long)c, objs, (unsigned long)mps_arena_committed(arena));
- report(arena);
+ if (type == mps_message_type_gc()) {
+ size_t live = mps_message_gc_live_size(arena, msg);
+ size_t condemned = mps_message_gc_condemned_size(arena, msg);
+ size_t not_condemned = mps_message_gc_not_condemned_size(arena, msg);
- for (i = 0; i < exactRootsCOUNT; ++i)
- cdie(exactRoots[i] == objNULL || dylan_check(exactRoots[i]),
- "all roots check");
+ printf("\nCollection %lu finished:\n", collections++);
+ printf("live %"PRIuLONGEST"\n", (ulongest_t)live);
+ printf("condemned %"PRIuLONGEST"\n", (ulongest_t)condemned);
+ printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned);
- if (mode == ModeWALK && collections >= collectionsCOUNT / 2 && !walked) {
- unsigned long object_count = 0;
- mps_arena_park(arena);
- mps_arena_formatted_objects_walk(arena, test_stepper, &object_count, 0);
- mps_arena_release(arena);
- printf("stepped on %lu objects.\n", object_count);
- walked = TRUE;
- }
- if (collections >= rampSwitch && !ramped) {
- int begin_ramp = !ramping
- || /* Every other time, switch back immediately. */ (collections & 1);
+ } else if (type == mps_message_type_gc_start()) {
+ printf("\nCollection %lu started, %lu objects, committed=%lu.\n",
+ (unsigned long)collections, objs,
+ (unsigned long)mps_arena_committed(arena));
- rampSwitch += rampSIZE;
- if (ramping) {
- die(mps_ap_alloc_pattern_end(ap, ramp), "pattern end (ap)");
- die(mps_ap_alloc_pattern_end(busy_ap, ramp), "pattern end (busy_ap)");
- ramping = 0;
- /* kill half of the roots */
- for(i = 0; i < exactRootsCOUNT; i += 2) {
- if (exactRoots[i] != objNULL) {
- cdie(dylan_check(exactRoots[i]), "ramp kill check");
- exactRoots[i] = objNULL;
+ for (i = 0; i < exactRootsCOUNT; ++i)
+ cdie(exactRoots[i] == objNULL || dylan_check(exactRoots[i]),
+ "all roots check");
+
+ if (mode == ModeWALK && collections >= collectionsCOUNT / 2 && !walked)
+ {
+ unsigned long count = 0;
+ mps_arena_park(arena);
+ mps_arena_formatted_objects_walk(arena, test_stepper, &count, 0);
+ mps_arena_release(arena);
+ printf("stepped on %lu objects.\n", count);
+ walked = TRUE;
+ }
+ if (collections >= rampSwitch && !ramped) {
+ /* Every other time, switch back immediately. */
+ int begin_ramp = !ramping || (collections & 1);
+
+ rampSwitch += rampSIZE;
+ if (ramping) {
+ die(mps_ap_alloc_pattern_end(ap, ramp), "pattern end (ap)");
+ die(mps_ap_alloc_pattern_end(busy_ap, ramp),
+ "pattern end (busy_ap)");
+ ramping = 0;
+ /* kill half of the roots */
+ for(i = 0; i < exactRootsCOUNT; i += 2) {
+ if (exactRoots[i] != objNULL) {
+ cdie(dylan_check(exactRoots[i]), "ramp kill check");
+ exactRoots[i] = objNULL;
+ }
}
}
+ if (begin_ramp) {
+ die(mps_ap_alloc_pattern_begin(ap, ramp),
+ "pattern rebegin (ap)");
+ die(mps_ap_alloc_pattern_begin(busy_ap, ramp),
+ "pattern rebegin (busy_ap)");
+ ramping = 1;
+ }
}
- if (begin_ramp) {
- die(mps_ap_alloc_pattern_begin(ap, ramp),
- "pattern rebegin (ap)");
- die(mps_ap_alloc_pattern_begin(busy_ap, ramp),
- "pattern rebegin (busy_ap)");
- ramping = 1;
- }
+ ramped = TRUE;
}
- ramped = TRUE;
+
+ mps_message_discard(arena, msg);
}
churn(ap, roots_count);
-
- r = (size_t)rnd();
-
- if (r % initTestFREQ == 0)
- *(int*)busy_init = -1; /* check that the buffer is still there */
-
+ {
+ size_t r = (size_t)rnd();
+ if (r % initTestFREQ == 0)
+ *(int*)busy_init = -1; /* check that the buffer is still there */
+ }
if (objs % 1024 == 0) {
- report(arena);
putchar('.');
fflush(stdout);
}
@@ -312,6 +280,9 @@ static void test_pool(mps_pool_t pool, size_t roots_count, int mode)
static void test_arena(int mode)
{
+ size_t i;
+ mps_fmt_t format;
+ mps_chain_t chain;
mps_thr_t thread;
mps_root_t reg_root;
mps_pool_t amc_pool, amcz_pool;
@@ -325,7 +296,25 @@ static void test_arena(int mode)
if (mode == ModeCOMMIT)
die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit");
mps_message_type_enable(arena, mps_message_type_gc());
- init();
+ mps_message_type_enable(arena, mps_message_type_gc_start());
+
+ die(dylan_fmt(&format, arena), "fmt_create");
+ die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
+
+ for(i = 0; i < exactRootsCOUNT; ++i)
+ exactRoots[i] = objNULL;
+ for(i = 0; i < ambigRootsCOUNT; ++i)
+ ambigRoots[i] = rnd_addr();
+
+ die(mps_root_create_table_masked(&exactRoot, arena,
+ mps_rank_exact(), (mps_rm_t)0,
+ &exactRoots[0], exactRootsCOUNT,
+ (mps_word_t)1),
+ "root_create_table(exact)");
+ die(mps_root_create_table(&ambigRoot, arena,
+ mps_rank_ambig(), (mps_rm_t)0,
+ &ambigRoots[0], ambigRootsCOUNT),
+ "root_create_table(ambig)");
die(mps_thread_reg(&thread, arena), "thread_reg");
die(mps_root_create_reg(®_root, arena, mps_rank_ambig(), 0, thread,
mps_stack_scan_ambig, marker, 0), "root_create");
@@ -335,8 +324,8 @@ static void test_arena(int mode)
die(mps_pool_create(&amcz_pool, arena, mps_class_amcz(), format, chain),
"pool_create(amcz)");
- test_pool(amc_pool, exactRootsCOUNT, mode);
- test_pool(amcz_pool, 0, mode);
+ test_pool("AMC", amc_pool, exactRootsCOUNT, mode);
+ test_pool("AMCZ", amcz_pool, 0, mode);
mps_arena_park(arena);
mps_pool_destroy(amc_pool);
@@ -347,7 +336,6 @@ static void test_arena(int mode)
mps_root_destroy(ambigRoot);
mps_chain_destroy(chain);
mps_fmt_destroy(format);
- report(arena);
mps_arena_destroy(arena);
}
@@ -367,18 +355,18 @@ int main(int argc, char *argv[])
* 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
@@ -389,7 +377,7 @@ int main(int argc, char *argv[])
* 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
diff --git a/mps/code/ananmv.nmk b/mps/code/ananmv.nmk
index 41d80a0671a..a8017020b5a 100644
--- a/mps/code/ananmv.nmk
+++ b/mps/code/ananmv.nmk
@@ -16,9 +16,8 @@ MPMPF = \
[than] \
[vman]
-!INCLUDE commpre.nmk
!INCLUDE mv.nmk
-!INCLUDE commpost.nmk
+!INCLUDE comm.nmk
# C. COPYRIGHT AND LICENSE
diff --git a/mps/code/arena.c b/mps/code/arena.c
index 6c6b5220229..a54cae0cb60 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 */
@@ -85,7 +86,6 @@ DEFINE_CLASS(AbstractArenaClass, class)
class->varargs = ArgTrivVarargs;
class->init = NULL;
class->finish = NULL;
- class->reserved = NULL;
class->purgeSpare = ArenaNoPurgeSpare;
class->extend = ArenaNoExtend;
class->grow = ArenaNoGrow;
@@ -113,7 +113,6 @@ Bool ArenaClassCheck(ArenaClass class)
CHECKL(FUNCHECK(class->varargs));
CHECKL(FUNCHECK(class->init));
CHECKL(FUNCHECK(class->finish));
- CHECKL(FUNCHECK(class->reserved));
CHECKL(FUNCHECK(class->purgeSpare));
CHECKL(FUNCHECK(class->extend));
CHECKL(FUNCHECK(class->grow));
@@ -142,9 +141,12 @@ Bool ArenaCheck(Arena arena)
CHECKD(Reservoir, &arena->reservoirStruct);
}
- /* Can't check that limit>=size because we may call ArenaCheck */
- /* while the size is being adjusted. */
-
+ /* .reserved.check: Would like to check that arena->committed <=
+ * arena->reserved, but that isn't always true in the VM arena.
+ * Memory is committed early on when VMChunkCreate calls vmArenaMap
+ * (to provide a place for the chunk struct) but is not recorded as
+ * reserved until ChunkInit calls ArenaChunkInsert.
+ */
CHECKL(arena->committed <= arena->commitLimit);
CHECKL(arena->spareCommitted <= arena->committed);
@@ -206,6 +208,7 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args)
arena->class = class;
+ arena->reserved = (Size)0;
arena->committed = (Size)0;
/* commitLimit may be overridden by init (but probably not */
/* as there's not much point) */
@@ -236,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));
@@ -251,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)
@@ -272,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));
@@ -299,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;
@@ -324,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)
@@ -349,7 +370,8 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
failGlobalsCompleteCreate:
ControlFinish(arena);
failControlInit:
-failPrimaryLand:
+ arenaFreeLandFinish(arena);
+failFreeLandInit:
failStripeSize:
(*class->finish)(arena);
failInit:
@@ -390,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);
@@ -399,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);
@@ -427,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,
@@ -444,6 +473,7 @@ Res ControlInit(Arena arena)
void ControlFinish(Arena arena)
{
AVERT(Arena, arena);
+ AVER(arena->poolReady);
arena->poolReady = FALSE;
PoolFinish(MVPool(&arena->controlPoolStruct));
}
@@ -454,7 +484,6 @@ void ControlFinish(Arena arena)
Res ArenaDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
{
Res res;
- Size reserved;
if (!TESTT(Arena, arena))
return ResFAIL;
@@ -476,20 +505,9 @@ Res ArenaDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
return res;
}
- /* Note: this Describe clause calls a function */
- reserved = ArenaReserved(arena);
res = WriteF(stream, depth + 2,
- "reserved $W <-- "
- "total size of address-space reserved\n",
- (WriteFW)reserved,
- NULL);
- if (res != ResOK)
- return res;
-
- res = WriteF(stream, depth + 2,
- "committed $W <-- "
- "total bytes currently stored (in RAM or swap)\n",
- (WriteFW)arena->committed,
+ "reserved $W\n", (WriteFW)arena->reserved,
+ "committed $W\n", (WriteFW)arena->committed,
"commitLimit $W\n", (WriteFW)arena->commitLimit,
"spareCommitted $W\n", (WriteFW)arena->spareCommitted,
"spareCommitLimit $W\n", (WriteFW)arena->spareCommitLimit,
@@ -669,7 +687,10 @@ Res ControlDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
}
-/* ArenaChunkInsert -- insert chunk into arena's chunk tree and ring */
+/* ArenaChunkInsert -- insert chunk into arena's chunk tree and ring,
+ * update the total reserved address space, and set the primary chunk
+ * if not already set.
+ */
void ArenaChunkInsert(Arena arena, Chunk chunk) {
Bool inserted;
@@ -687,6 +708,8 @@ void ArenaChunkInsert(Arena arena, Chunk chunk) {
arena->chunkTree = updatedTree;
RingAppend(&arena->chunkRing, &chunk->arenaRing);
+ arena->reserved += ChunkReserved(chunk);
+
/* As part of the bootstrap, the first created chunk becomes the primary
chunk. This step allows ArenaFreeLandInsert to allocate pages. */
if (arena->primary == NULL)
@@ -694,6 +717,31 @@ void ArenaChunkInsert(Arena arena, Chunk chunk) {
}
+/* ArenaChunkRemoved -- chunk was removed from the arena and is being
+ * finished, so update the total reserved address space, and unset the
+ * primary chunk if necessary.
+ */
+
+void ArenaChunkRemoved(Arena arena, Chunk chunk)
+{
+ Size size;
+
+ AVERT(Arena, arena);
+ AVERT(Chunk, chunk);
+
+ size = ChunkReserved(chunk);
+ AVER(arena->reserved >= size);
+ arena->reserved -= size;
+
+ if (chunk == arena->primary) {
+ /* The primary chunk must be the last chunk to be removed. */
+ AVER(RingIsSingle(&arena->chunkRing));
+ AVER(arena->reserved == 0);
+ arena->primary = NULL;
+ }
+}
+
+
/* arenaAllocPage -- allocate one page from the arena
*
* This is a primitive allocator used to allocate pages for the arena
@@ -781,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;
}
@@ -801,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;
@@ -835,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;
@@ -852,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;
@@ -881,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
@@ -896,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;
@@ -911,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.
@@ -1003,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. */
}
@@ -1215,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);
@@ -1231,7 +1287,7 @@ void ArenaFree(Addr base, Size size, Pool pool)
Size ArenaReserved(Arena arena)
{
AVERT(Arena, arena);
- return (*arena->class->reserved)(arena);
+ return arena->reserved;
}
Size ArenaCommitted(Arena arena)
diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c
index 857c4608e11..cd5c24fe46a 100644
--- a/mps/code/arenacl.c
+++ b/mps/code/arenacl.c
@@ -81,8 +81,15 @@ static Bool ClientChunkCheck(ClientChunk clChunk)
ATTRIBUTE_UNUSED
static Bool ClientArenaCheck(ClientArena clientArena)
{
+ Arena arena;
+
CHECKS(ClientArena, clientArena);
- CHECKD(Arena, ClientArena2Arena(clientArena));
+ arena = ClientArena2Arena(clientArena);
+ CHECKD(Arena, arena);
+ /* See */
+ CHECKL(arena->committed <= arena->reserved);
+ CHECKL(arena->spareCommitted == 0);
+
return TRUE;
}
@@ -125,12 +132,13 @@ static Res clientChunkCreate(Chunk *chunkReturn, ClientArena clientArena,
chunk = ClientChunk2Chunk(clChunk);
res = ChunkInit(chunk, arena, alignedBase,
- AddrAlignDown(limit, ArenaGrainSize(arena)), boot);
+ AddrAlignDown(limit, ArenaGrainSize(arena)),
+ AddrOffset(base, limit), boot);
if (res != ResOK)
goto failChunkInit;
- ClientArena2Arena(clientArena)->committed +=
- AddrOffset(base, PageIndexBase(chunk, chunk->allocBase));
+ arena->committed += ChunkPagesToSize(chunk, chunk->allocBase);
+
BootBlockFinish(boot);
clChunk->sig = ClientChunkSig;
@@ -176,8 +184,10 @@ static Res ClientChunkInit(Chunk chunk, BootBlock boot)
static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS)
{
+ Arena arena;
Chunk chunk;
ClientChunk clChunk;
+ Size size;
AVERT(Tree, tree);
AVER(closureP == UNUSED_POINTER);
@@ -187,8 +197,15 @@ static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS)
chunk = ChunkOfTree(tree);
AVERT(Chunk, chunk);
+ arena = ChunkArena(chunk);
+ AVERT(Arena, arena);
clChunk = Chunk2ClientChunk(chunk);
AVERT(ClientChunk, clChunk);
+ AVER(chunk->pages == clChunk->freePages);
+
+ size = ChunkPagesToSize(chunk, chunk->allocBase);
+ AVER(arena->committed >= size);
+ arena->committed -= size;
clChunk->sig = SigInvalid;
ChunkFinish(chunk);
@@ -257,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;
@@ -324,6 +341,10 @@ static void ClientArenaFinish(Arena arena)
clientArena->sig = SigInvalid;
+ /* Destroying the chunks should leave nothing behind. */
+ AVER(arena->reserved == 0);
+ AVER(arena->committed == 0);
+
ArenaFinish(arena); /* */
}
@@ -348,27 +369,6 @@ static Res ClientArenaExtend(Arena arena, Addr base, Size size)
}
-/* ClientArenaReserved -- return the amount of reserved address space */
-
-static Size ClientArenaReserved(Arena arena)
-{
- Size size;
- Ring node, nextNode;
-
- AVERT(Arena, arena);
-
- size = 0;
- /* .req.extend.slow */
- RING_FOR(node, &arena->chunkRing, nextNode) {
- Chunk chunk = RING_ELT(Chunk, arenaRing, node);
- AVERT(Chunk, chunk);
- size += ChunkSize(chunk);
- }
-
- return size;
-}
-
-
/* ClientArenaPagesMarkAllocated -- Mark the pages allocated */
static Res ClientArenaPagesMarkAllocated(Arena arena, Chunk chunk,
@@ -376,9 +376,12 @@ static Res ClientArenaPagesMarkAllocated(Arena arena, Chunk chunk,
Pool pool)
{
Index i;
+ ClientChunk clChunk;
AVERT(Arena, arena);
AVERT(Chunk, chunk);
+ clChunk = Chunk2ClientChunk(chunk);
+ AVERT(ClientChunk, clChunk);
AVER(chunk->allocBase <= baseIndex);
AVER(pages > 0);
AVER(baseIndex + pages <= chunk->pages);
@@ -387,15 +390,17 @@ static Res ClientArenaPagesMarkAllocated(Arena arena, Chunk chunk,
for (i = 0; i < pages; ++i)
PageAlloc(chunk, baseIndex + i, pool);
- Chunk2ClientChunk(chunk)->freePages -= pages;
+ arena->committed += ChunkPagesToSize(chunk, pages);
+ AVER(clChunk->freePages >= pages);
+ clChunk->freePages -= pages;
return ResOK;
}
-/* ClientFree - free a region in the arena */
+/* ClientArenaFree - free a region in the arena */
-static void ClientFree(Addr base, Size size, Pool pool)
+static void ClientArenaFree(Addr base, Size size, Pool pool)
{
Arena arena;
Chunk chunk = NULL; /* suppress "may be used uninitialized" */
@@ -436,6 +441,8 @@ static void ClientFree(Addr base, Size size, Pool pool)
AVER(BTIsSetRange(chunk->allocTable, baseIndex, limitIndex));
BTResRange(chunk->allocTable, baseIndex, limitIndex);
+ AVER(arena->committed >= size);
+ arena->committed -= size;
clChunk->freePages += pages;
}
@@ -451,10 +458,9 @@ DEFINE_ARENA_CLASS(ClientArenaClass, this)
this->varargs = ClientArenaVarargs;
this->init = ClientArenaInit;
this->finish = ClientArenaFinish;
- this->reserved = ClientArenaReserved;
this->extend = ClientArenaExtend;
this->pagesMarkAllocated = ClientArenaPagesMarkAllocated;
- this->free = ClientFree;
+ this->free = ClientArenaFree;
this->chunkInit = ClientChunkInit;
this->chunkFinish = ClientChunkFinish;
AVERT(ArenaClass, this);
diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c
index 54b7ef7ba25..ba34a7c70ef 100644
--- a/mps/code/arenavm.c
+++ b/mps/code/arenavm.c
@@ -323,7 +323,8 @@ static Res VMChunkCreate(Chunk *chunkReturn, VMArena vmArena, Size size)
/* Copy VM descriptor into its place in the chunk. */
VMCopy(VMChunkVM(vmChunk), vm);
- res = ChunkInit(VMChunk2Chunk(vmChunk), arena, base, limit, boot);
+ res = ChunkInit(VMChunk2Chunk(vmChunk), arena, base, limit,
+ VMReserved(VMChunkVM(vmChunk)), boot);
if (res != ResOK)
goto failChunkInit;
@@ -560,6 +561,7 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
res = ArenaInit(arena, class, grainSize, args);
if (res != ResOK)
goto failArenaInit;
+ arena->reserved = VMReserved(vm);
arena->committed = VMMapped(vm);
/* Copy VM descriptor into its place in the arena. */
@@ -640,6 +642,7 @@ static void VMArenaFinish(Arena arena)
RingFinish(&vmArena->spareRing);
/* Destroying the chunks should leave only the arena's own VM. */
+ AVER(arena->reserved == VMReserved(VMArenaVM(vmArena)));
AVER(arena->committed == VMMapped(VMArenaVM(vmArena)));
vmArena->sig = SigInvalid;
@@ -654,25 +657,6 @@ static void VMArenaFinish(Arena arena)
}
-/* VMArenaReserved -- return the amount of reserved address space
- *
- * Add up the reserved space from all the chunks.
- */
-
-static Size VMArenaReserved(Arena arena)
-{
- Size reserved;
- Ring node, next;
-
- reserved = 0;
- RING_FOR(node, &arena->chunkRing, next) {
- VMChunk vmChunk = Chunk2VMChunk(RING_ELT(Chunk, arenaRing, node));
- reserved += VMReserved(VMChunkVM(vmChunk));
- }
- return reserved;
-}
-
-
/* vmArenaChunkSize -- choose chunk size for arena extension
*
* .vmchunk.overhead: This code still lacks a proper estimate of
@@ -723,7 +707,7 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
chunkSize = vmArenaChunkSize(vmArena, size);
EVENT3(vmArenaExtendStart, size, chunkSize,
- VMArenaReserved(VMArena2Arena(vmArena)));
+ ArenaReserved(VMArena2Arena(vmArena)));
/* .chunk-create.fail: If we fail, try again with a smaller size */
{
@@ -737,17 +721,17 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
if (chunkSize < chunkMin)
chunkSize = chunkMin;
+ res = ResRESOURCE;
for(;; chunkSize = chunkHalf) {
chunkHalf = chunkSize / 2;
sliceSize = chunkHalf / fidelity;
AVER(sliceSize > 0);
/* remove slices, down to chunkHalf but no further */
- res = ResRESOURCE;
for(; chunkSize > chunkHalf; chunkSize -= sliceSize) {
if(chunkSize < chunkMin) {
EVENT2(vmArenaExtendFail, chunkMin,
- VMArenaReserved(VMArena2Arena(vmArena)));
+ ArenaReserved(VMArena2Arena(vmArena)));
return res;
}
res = VMChunkCreate(&newChunk, vmArena, chunkSize);
@@ -758,7 +742,7 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
}
vmArenaGrow_Done:
- EVENT2(vmArenaExtendDone, chunkSize, VMArenaReserved(VMArena2Arena(vmArena)));
+ EVENT2(vmArenaExtendDone, chunkSize, ArenaReserved(VMArena2Arena(vmArena)));
vmArena->extended(VMArena2Arena(vmArena),
newChunk->base,
AddrOffset(newChunk->base, newChunk->limit));
@@ -806,16 +790,23 @@ static Res pageDescMap(VMChunk vmChunk, Index basePI, Index limitPI)
Size before = VMMapped(VMChunkVM(vmChunk));
Arena arena = VMArena2Arena(VMChunkVMArena(vmChunk));
Res res = SparseArrayMap(&vmChunk->pages, basePI, limitPI);
- arena->committed += VMMapped(VMChunkVM(vmChunk)) - before;
+ Size after = VMMapped(VMChunkVM(vmChunk));
+ AVER(before <= after);
+ arena->committed += after - before;
return res;
}
static void pageDescUnmap(VMChunk vmChunk, Index basePI, Index limitPI)
{
+ Size size, after;
Size before = VMMapped(VMChunkVM(vmChunk));
Arena arena = VMArena2Arena(VMChunkVMArena(vmChunk));
SparseArrayUnmap(&vmChunk->pages, basePI, limitPI);
- arena->committed += VMMapped(VMChunkVM(vmChunk)) - before;
+ after = VMMapped(VMChunkVM(vmChunk));
+ AVER(after <= before);
+ size = before - after;
+ AVER(arena->committed >= size);
+ arena->committed -= size;
}
@@ -1144,7 +1135,7 @@ static void VMCompact(Arena arena, Trace trace)
AVERT(VMArena, vmArena);
AVERT(Trace, trace);
- vmem1 = VMArenaReserved(arena);
+ vmem1 = ArenaReserved(arena);
/* Destroy chunks that are completely free, but not the primary
* chunk. See
@@ -1154,7 +1145,7 @@ static void VMCompact(Arena arena, Trace trace)
{
Size vmem0 = trace->preTraceArenaReserved;
- Size vmem2 = VMArenaReserved(arena);
+ Size vmem2 = ArenaReserved(arena);
/* VMCompact event: emit for all client-requested collections, */
/* plus any others where chunks were gained or lost during the */
@@ -1204,7 +1195,6 @@ DEFINE_ARENA_CLASS(VMArenaClass, this)
this->varargs = VMArenaVarargs;
this->init = VMArenaInit;
this->finish = VMArenaFinish;
- this->reserved = VMArenaReserved;
this->purgeSpare = VMPurgeSpare;
this->grow = VMArenaGrow;
this->free = VMFree;
diff --git a/mps/code/buffer.c b/mps/code/buffer.c
index 4c30ed3d8a7..edef611c217 100644
--- a/mps/code/buffer.c
+++ b/mps/code/buffer.c
@@ -19,10 +19,8 @@
*
* TRANSGRESSIONS
*
- * .trans.mod: There are several instances where pool structures are
- * directly accessed by this module because does not provide
- * an adequate (or adequately documented) interface. They bear this
- * tag.
+ * .trans.mod: pool->bufferSerial is directly accessed by this module
+ * because does not provide an interface.
*/
#include "mpm.h"
@@ -221,7 +219,7 @@ static Res BufferInit(Buffer buffer, BufferClass class,
}
buffer->fillSize = 0.0;
buffer->emptySize = 0.0;
- buffer->alignment = pool->alignment; /* .trans.mod */
+ buffer->alignment = PoolAlignment(pool);
buffer->base = (Addr)0;
buffer->initAtFlip = (Addr)0;
/* In the next three assignments we really mean zero, not NULL, because
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/comm.gmk b/mps/code/comm.gmk
index 2eb68381a3f..c82caa4576e 100644
--- a/mps/code/comm.gmk
+++ b/mps/code/comm.gmk
@@ -36,7 +36,6 @@
# NOISY if defined and non-empty, causes commands to be emitted
# MPMPF platform-dependent C sources for the "mpm" part
# MPMS assembler sources for the "mpm" part (.s files)
-# MPMPS pre-processor assembler sources for the "mpm" part (.S files)
#
# %%PART: When adding a new part, add a new parameter above for the
# files included in the part.
@@ -309,12 +308,12 @@ all: $(ALL_TARGETS)
# testci = continuous integration tests, must be known good
# testall = all test cases, for ensuring quality of a release
# testansi = tests that run on the generic ("ANSI") platform
-# testpoll = tests that run on the generic platform with CONFIG_POLL_NONE
+# testpollnone = tests that run on the generic platform with CONFIG_POLL_NONE
-TEST_SUITES=testrun testci testall testansi testpoll
+TEST_SUITES=testrun testci testall testansi testpollnone
$(addprefix $(PFM)/$(VARIETY)/,$(TEST_SUITES)): $(TEST_TARGETS)
- ../tool/testrun.sh "$(PFM)/$(VARIETY)" "$(notdir $@)"
+ ../tool/testrun.sh -s "$(notdir $@)" "$(PFM)/$(VARIETY)"
# These convenience targets allow one to type "make foo" to build target
diff --git a/mps/code/commpost.nmk b/mps/code/comm.nmk
similarity index 64%
rename from mps/code/commpost.nmk
rename to mps/code/comm.nmk
index 1d2783a7bbb..a59132ff354 100644
--- a/mps/code/commpost.nmk
+++ b/mps/code/comm.nmk
@@ -1,11 +1,330 @@
-# commpost.nmk: SECOND COMMON FRAGMENT FOR PLATFORMS USING NMAKE -*- makefile -*-
+# -*- makefile -*-
+#
+# comm.nmk: COMMON NMAKE FRAGMENT
#
# $Id$
# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
#
# DESCRIPTION
#
-# Second common makefile fragment for w3*mv.nmk. See commpre.nmk
+# This makefile fragment is included in more specific makefiles for
+# platforms which use nmake.
+#
+# %%PART: When adding a new part, add a new parameter for the files included
+# in the part
+# Parameters:
+# PFM platform code, e.g. "w3i3mv"
+# PFMDEFS /D options to define platforms preprocessor symbols
+# to the compiler. Avoid using this if possible, as it
+# prevents the MPS being built with a simple command like
+# "cl mps.c".
+# MPMCOMMON list of sources which make up the "mpm" part for all
+# platforms. Each source is stripped of its .c extension
+# and surrounded with [brackets].
+# MPMPF as above for the current platform.
+# PLINTH as above for the "plinth" part
+# AMC as above for the "amc" part
+# AMS as above for the "ams" part
+# LO as above for the "lo" part
+# POOLN as above for the "pooln" part
+# SNC as above for the "snc" part
+# POOLS as above for all pools included in the target
+# MPM as above for the MPMCOMMON + MPMPF + PLINTH + POOLS
+# DW as above for the "dw" part
+# FMTTEST as above for the "fmttest" part
+# FMTSCHEME as above for the "fmtscheme" part
+# TESTLIB as above for the "testlib" part
+# TESTTHR as above for the "testthr" part
+# NOISY if defined, causes command to be emitted
+#
+#
+# EDITING
+#
+# To add new targets. varieties, and parts:
+# Search for the string "%%TARGET", "%%VARIETY", or "%%PART" in this makefile
+# and follow the instructions.
+#
+
+
+# TARGETS
+#
+#
+# %%TARGET: When adding a new target, add it to one of the variables
+# in this section. Library components go in LIB_TARGETS.
+
+LIB_TARGETS=mps.lib
+
+# Test cases go in TEST_TARGETS.
+
+TEST_TARGETS=\
+ abqtest.exe \
+ airtest.exe \
+ amcss.exe \
+ amcsshe.exe \
+ amcssth.exe \
+ amsss.exe \
+ amssshe.exe \
+ apss.exe \
+ arenacv.exe \
+ awlut.exe \
+ awluthe.exe \
+ awlutth.exe \
+ btcv.exe \
+ bttest.exe \
+ djbench.exe \
+ exposet0.exe \
+ expt825.exe \
+ finalcv.exe \
+ finaltest.exe \
+ fotest.exe \
+ gcbench.exe \
+ landtest.exe \
+ locbwcss.exe \
+ lockcov.exe \
+ lockut.exe \
+ locusss.exe \
+ locv.exe \
+ messtest.exe \
+ mpmss.exe \
+ mpsicv.exe \
+ mv2test.exe \
+ nailboardtest.exe \
+ poolncv.exe \
+ qs.exe \
+ sacss.exe \
+ segsmss.exe \
+ steptest.exe \
+ teletest.exe \
+ walkt0.exe \
+ zcoll.exe \
+ zmess.exe
+
+# Stand-alone programs go in EXTRA_TARGETS if they should always be
+# built, or in OPTIONAL_TARGETS if they should only be built if
+
+EXTRA_TARGETS=mpseventcnv.exe mpseventtxt.exe
+OPTIONAL_TARGETS=mpseventsql.exe
+
+# This target records programs that we were once able to build but
+# can't at the moment:
+#
+# replay -- depends on the EPVM pool.
+
+UNBUILDABLE_TARGETS=replay.exe
+
+ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS)
+
+
+# PARAMETERS
+#
+#
+# %%PART: When adding a new part, add the sources for the new part here.
+
+MPMCOMMON=\
+ [abq] \
+ [arena] \
+ [arenacl] \
+ [arenavm] \
+ [arg] \
+ [boot] \
+ [bt] \
+ [buffer] \
+ [cbs] \
+ [dbgpool] \
+ [dbgpooli] \
+ [event] \
+ [failover] \
+ [format] \
+ [freelist] \
+ [global] \
+ [land] \
+ [ld] \
+ [locus] \
+ [message] \
+ [meter] \
+ [mpm] \
+ [mpsi] \
+ [nailboard] \
+ [pool] \
+ [poolabs] \
+ [poolmfs] \
+ [poolmrg] \
+ [poolmv2] \
+ [poolmv] \
+ [protocol] \
+ [range] \
+ [ref] \
+ [reserv] \
+ [ring] \
+ [root] \
+ [sa] \
+ [sac] \
+ [seg] \
+ [shield] \
+ [splay] \
+ [ss] \
+ [table] \
+ [trace] \
+ [traceanc] \
+ [tract] \
+ [tree] \
+ [version] \
+ [vm] \
+ [walk]
+PLINTH = [mpsliban] [mpsioan]
+AMC = [poolamc]
+AMS = [poolams] [poolamsi]
+AWL = [poolawl]
+LO = [poollo]
+MVFF = [poolmvff]
+POOLN = [pooln]
+SNC = [poolsnc]
+FMTDY = [fmtdy] [fmtno]
+FMTTEST = [fmthe] [fmtdy] [fmtno] [fmtdytst]
+FMTSCHEME = [fmtscheme]
+TESTLIB = [testlib] [getoptl]
+TESTTHR = [testthrw3]
+POOLS = $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(SNC)
+MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH)
+
+
+# CHECK PARAMETERS
+#
+#
+# %%PART: When adding a new part, add checks for the parameter with the
+# sources for the new part.
+
+!IFNDEF PFM
+!ERROR comm.nmk: PFM not defined
+!ENDIF
+!IFNDEF MPM
+!ERROR comm.nmk: MPM not defined
+!ENDIF
+!IFNDEF MPMCOMMON
+!ERROR comm.nmk: MPMCOMMON not defined
+!ENDIF
+!IFNDEF MPMPF
+!ERROR comm.nmk: MPMPF not defined
+!ENDIF
+!IFNDEF PLINTH
+!ERROR comm.nmk: PLINTH not defined
+!ENDIF
+!IFNDEF LO
+!ERROR comm.nmk: LO not defined
+!ENDIF
+!IFNDEF AMC
+!ERROR comm.nmk: AMC not defined
+!ENDIF
+!IFNDEF AMS
+!ERROR comm.nmk: AMS not defined
+!ENDIF
+!IFNDEF POOLN
+!ERROR comm.nmk: POOLN not defined
+!ENDIF
+!IFNDEF SNC
+!ERROR comm.nmk: SNC not defined
+!ENDIF
+!IFNDEF FMTDY
+!ERROR comm.nmk: FMTDY not defined
+!ENDIF
+!IFNDEF FMTTEST
+!ERROR comm.nmk: FMTTEST not defined
+!ENDIF
+!IFNDEF FMTSCHEME
+!ERROR comm.nmk: FMTSCHEME not defined
+!ENDIF
+!IFNDEF TESTLIB
+!ERROR comm.nmk: TESTLIB not defined
+!ENDIF
+!IFNDEF TESTTHR
+!ERROR comm.nmk: TESTTHR not defined
+!ENDIF
+
+
+# DECLARATIONS
+
+
+!IFDEF NOISY
+ECHO = rem
+!ELSE
+.SILENT:
+ECHO = echo
+!ENDIF
+
+
+# C FLAGS
+
+CFLAGSTARGETPRE =
+CFLAGSTARGETPOST =
+CRTFLAGSHOT =
+CRTFLAGSCOOL =
+LINKFLAGSHOT =
+LINKFLAGSCOOL =
+
+CFLAGSSQLPRE = /nologo $(PFMDEFS)
+CFLAGSCOMMONPRE = /nologo $(PFMDEFS) $(CFLAGSTARGETPRE)
+CFLAGSSQLPOST =
+CFLAGSCOMMONPOST = $(CFLAGSTARGETPOST)
+
+# Flags for use in the variety combinations
+CFLAGSHOT = /O2
+# (above /O2 (maximise speed) used to be set to /Ox
+# (maximise optimisations) in for tool versions before VS 9)
+# We used to have /GZ here (stack probe).
+# Note that GZ is specific to version 12 of the cl tool. drj 2003-11-04
+# It is ignored on earlier versions of the cl tool.
+# /GZ here generates a dependency on the C library and when we are
+# building a DLL, mpsdy.dll, the linker step will fail (error LNK2001:
+# unresolved external symbol __chkesp). See
+# http://support.microsoft.com/kb/q191669/
+CFLAGSCOOL =
+CFLAGSINTERNAL = /Zi
+CFLAGSEXTERNAL =
+
+# The combinations of variety
+# %%VARIETY: When adding a new variety, define a macro containing the set
+# of flags for the new variety.
+CFRASH = /DCONFIG_VAR_RASH $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSEXTERNAL)
+CFHOT = /DCONFIG_VAR_HOT $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL)
+CFCOOL = /DCONFIG_VAR_COOL $(CRTFLAGSCOOL) $(CFLAGSCOOL) $(CFLAGSINTERNAL)
+
+# Microsoft documentation is not very clear on the point of using both
+# optimization and debug information
+
+# LINKER FLAGS
+# %%VARIETY: When adding a new variety, define a macro containing the flags
+# for the new variety
+LINKER = link
+LINKFLAGSCOMMON = /nologo /LARGEADDRESSAWARE
+LINKFLAGSINTERNAL = /DEBUG
+# ( Internal flags used to be set to /DEBUG:full )
+LINKFLAGSEXTERNAL = /RELEASE
+
+LFRASH = $(LINKFLAGSHOT) $(LINKFLAGSEXTERNAL)
+LFHOT = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL)
+LFCOOL = $(LINKFLAGSCOOL) $(LINKFLAGSINTERNAL)
+
+#LFCV = /PROFILE /DEBUG:full /DEBUGTYPE:cv
+
+# Library manager
+# %%VARIETY: When adding a new variety, define a macro containing the flags
+# for the new variety
+LIBMAN = lib # can't call this LIB - it screws the environment
+LIBFLAGSCOMMON =
+
+LIBFLAGSRASH =
+LIBFLAGSHOT =
+LIBFLAGSCOOL =
+
+# Browser database manager [not used at present]
+#BSC = bscmake
+#BSCFLAGS = /nologo /n
+
+
+# == Common definitions ==
+# %%PART: When adding a new part, add it here, unless it's platform-specific
+# [It is not possible use a macro, like $(PFM), in a substitution,
+# hence all parts end up being platform-specific.]
# == Pseudo-targets ==
@@ -56,10 +375,10 @@ variety: $(PFM)\$(VARIETY)\$(TARGET)
!ENDIF
!ENDIF
-# testrun testci testall testansi testpoll
+# testrun testci testall testansi testpollnone
# Runs automated test cases.
-testrun testci testall testansi testpoll: $(TEST_TARGETS)
+testrun testci testall testansi testpollnone: $(TEST_TARGETS)
!IFDEF VARIETY
..\tool\testrun.bat $(PFM) $(VARIETY) $@
!ELSE
@@ -382,18 +701,18 @@ $(PFM)\$(VARIETY)\sqlite3.obj:
# 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
@@ -404,7 +723,7 @@ $(PFM)\$(VARIETY)\sqlite3.obj:
# 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
diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk
deleted file mode 100644
index b622ff25741..00000000000
--- a/mps/code/commpre.nmk
+++ /dev/null
@@ -1,369 +0,0 @@
-# commpre.nmk: FIRST COMMON FRAGMENT FOR PLATFORMS USING NMAKE -*- makefile -*-1
-#
-# $Id$
-# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
-#
-# DESCRIPTION
-#
-# .description: This makefile fragment is included in more specific
-# makefiles for platforms which use the "mv" builder. This is
-# the first of two common makefile fragements (the other is commpost.nmk).
-# Alas, due to shortcomings in nmake, it is not possible to use only one
-# common fragment.
-#
-# %%PART: When adding a new part, add a new parameter for the files included
-# in the part
-# Parameters:
-# PFM platform code, e.g. "w3i3mv"
-# PFMDEFS /D options to define platforms preprocessor symbols
-# to the compiler. Eg "/DOS_NT /DARCH_386 /DBUILD_MVC"
-# MPMCOMMON list of sources which make up the "mpm" part for all
-# platforms. Each source is stripped of its .c extension
-# and surrounded with [brackets].
-# MPM as above, plus sources for the "mpm" part for the current
-# platform.
-# PLINTH as above for the "plinth" part
-# AMC as above for the "amc" part
-# AMS as above for the "ams" part
-# LO as above for the "lo" part
-# POOLN as above for the "pooln" part
-# SNC as above for the "snc" part
-# DW as above for the "dw" part
-# FMTTEST as above for the "fmttest" part
-# FMTSCHEME as above for the "fmtscheme" part
-# TESTLIB as above for the "testlib" part
-# TESTTHR as above for the "testthr" part
-# NOISY if defined, causes command to be emitted
-#
-#
-# EDITING
-#
-# To add new targets. varieties, and parts:
-# Search for the string "%%TARGET", "%%VARIETY", or "%%PART" in this makefile
-# and follow the instructions.
-#
-
-
-# TARGETS
-#
-#
-# %%TARGET: When adding a new target, add it to one of the variables
-# in this section. Library components go in LIB_TARGETS.
-
-LIB_TARGETS=mps.lib
-
-# Test cases go in TEST_TARGETS.
-
-TEST_TARGETS=\
- abqtest.exe \
- airtest.exe \
- amcss.exe \
- amcsshe.exe \
- amcssth.exe \
- amsss.exe \
- amssshe.exe \
- apss.exe \
- arenacv.exe \
- awlut.exe \
- awluthe.exe \
- awlutth.exe \
- btcv.exe \
- bttest.exe \
- djbench.exe \
- exposet0.exe \
- expt825.exe \
- finalcv.exe \
- finaltest.exe \
- fotest.exe \
- gcbench.exe \
- landtest.exe \
- locbwcss.exe \
- lockcov.exe \
- lockut.exe \
- locusss.exe \
- locv.exe \
- messtest.exe \
- mpmss.exe \
- mpsicv.exe \
- mv2test.exe \
- nailboardtest.exe \
- poolncv.exe \
- qs.exe \
- sacss.exe \
- segsmss.exe \
- steptest.exe \
- teletest.exe \
- walkt0.exe \
- zcoll.exe \
- zmess.exe
-
-# Stand-alone programs go in EXTRA_TARGETS if they should always be
-# built, or in OPTIONAL_TARGETS if they should only be built if
-
-EXTRA_TARGETS=mpseventcnv.exe mpseventtxt.exe
-OPTIONAL_TARGETS=mpseventsql.exe
-
-# This target records programs that we were once able to build but
-# can't at the moment:
-#
-# replay -- depends on the EPVM pool.
-
-UNBUILDABLE_TARGETS=replay.exe
-
-ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS)
-
-
-# PARAMETERS
-#
-#
-# %%PART: When adding a new part, add the sources for the new part here.
-
-MPMCOMMON=\
- [abq] \
- [arena] \
- [arenacl] \
- [arenavm] \
- [arg] \
- [boot] \
- [bt] \
- [buffer] \
- [cbs] \
- [dbgpool] \
- [dbgpooli] \
- [event] \
- [failover] \
- [format] \
- [freelist] \
- [global] \
- [land] \
- [ld] \
- [locus] \
- [message] \
- [meter] \
- [mpm] \
- [mpsi] \
- [nailboard] \
- [pool] \
- [poolabs] \
- [poolmfs] \
- [poolmrg] \
- [poolmv2] \
- [poolmv] \
- [protocol] \
- [range] \
- [ref] \
- [reserv] \
- [ring] \
- [root] \
- [sa] \
- [sac] \
- [seg] \
- [shield] \
- [splay] \
- [ss] \
- [table] \
- [trace] \
- [traceanc] \
- [tract] \
- [tree] \
- [version] \
- [vm] \
- [walk]
-PLINTH = [mpsliban] [mpsioan]
-AMC = [poolamc]
-AMS = [poolams] [poolamsi]
-AWL = [poolawl]
-LO = [poollo]
-MVFF = [poolmvff]
-POOLN = [pooln]
-SNC = [poolsnc]
-FMTDY = [fmtdy] [fmtno]
-FMTTEST = [fmthe] [fmtdy] [fmtno] [fmtdytst]
-FMTSCHEME = [fmtscheme]
-TESTLIB = [testlib] [getoptl]
-TESTTHR = [testthrw3]
-POOLS = $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(SNC)
-MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH)
-
-
-# CHECK PARAMETERS
-#
-#
-# %%PART: When adding a new part, add checks for the parameter with the
-# sources for the new part.
-
-!IFNDEF PFM
-!ERROR commpre.nmk: PFM not defined
-!ENDIF
-!IFNDEF PFMDEFS
-!ERROR commpre.nmk: PFMDEFS not defined
-!ENDIF
-!IFNDEF MPM
-!ERROR commpre.nmk: MPM not defined
-!ENDIF
-!IFNDEF MPMCOMMON
-!ERROR commpre.nmk: MPMCOMMON not defined
-!ENDIF
-!IFNDEF MPMPF
-!ERROR commpre.nmk: MPMPF not defined
-!ENDIF
-!IFNDEF PLINTH
-!ERROR commpre.nmk: PLINTH not defined
-!ENDIF
-!IFNDEF LO
-!ERROR commpre.nmk: LO not defined
-!ENDIF
-!IFNDEF AMC
-!ERROR commpre.nmk: AMC not defined
-!ENDIF
-!IFNDEF AMS
-!ERROR commpre.nmk: AMS not defined
-!ENDIF
-!IFNDEF POOLN
-!ERROR commpre.nmk: POOLN not defined
-!ENDIF
-!IFNDEF SNC
-!ERROR commpre.nmk: SNC not defined
-!ENDIF
-!IFNDEF FMTDY
-!ERROR commpre.nmk: FMTDY not defined
-!ENDIF
-!IFNDEF FMTTEST
-!ERROR commpre.nmk: FMTTEST not defined
-!ENDIF
-!IFNDEF FMTSCHEME
-!ERROR commpre.nmk: FMTSCHEME not defined
-!ENDIF
-!IFNDEF TESTLIB
-!ERROR commpre.nmk: TESTLIB not defined
-!ENDIF
-!IFNDEF TESTTHR
-!ERROR commpre.nmk: TESTTHR not defined
-!ENDIF
-
-
-# DECLARATIONS
-
-
-!IFDEF NOISY
-ECHO = rem
-!ELSE
-.SILENT:
-ECHO = echo
-!ENDIF
-
-
-# C FLAGS
-
-CFLAGSTARGETPRE =
-CFLAGSTARGETPOST =
-CRTFLAGSHOT =
-CRTFLAGSCOOL =
-LINKFLAGSHOT =
-LINKFLAGSCOOL =
-
-CFLAGSSQLPRE = /nologo $(PFMDEFS)
-CFLAGSCOMMONPRE = /nologo $(PFMDEFS) $(CFLAGSTARGETPRE)
-CFLAGSSQLPOST =
-CFLAGSCOMMONPOST = $(CFLAGSTARGETPOST)
-
-# Flags for use in the variety combinations
-CFLAGSHOT = /O2
-# (above /O2 (maximise speed) used to be set to /Ox
-# (maximise optimisations) in for tool versions before VS 9)
-# We used to have /GZ here (stack probe).
-# Note that GZ is specific to version 12 of the cl tool. drj 2003-11-04
-# It is ignored on earlier versions of the cl tool.
-# /GZ here generates a dependency on the C library and when we are
-# building a DLL, mpsdy.dll, the linker step will fail (error LNK2001:
-# unresolved external symbol __chkesp). See
-# http://support.microsoft.com/kb/q191669/
-CFLAGSCOOL =
-CFLAGSINTERNAL = /Zi
-CFLAGSEXTERNAL =
-
-# The combinations of variety
-# %%VARIETY: When adding a new variety, define a macro containing the set
-# of flags for the new variety.
-CFRASH = /DCONFIG_VAR_RASH $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSEXTERNAL)
-CFHOT = /DCONFIG_VAR_HOT $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL)
-CFCOOL = /DCONFIG_VAR_COOL $(CRTFLAGSCOOL) $(CFLAGSCOOL) $(CFLAGSINTERNAL)
-
-# Microsoft documentation is not very clear on the point of using both
-# optimization and debug information
-
-# LINKER FLAGS
-# %%VARIETY: When adding a new variety, define a macro containing the flags
-# for the new variety
-LINKER = link
-LINKFLAGSCOMMON = /nologo /LARGEADDRESSAWARE
-LINKFLAGSINTERNAL = /DEBUG
-# ( Internal flags used to be set to /DEBUG:full )
-LINKFLAGSEXTERNAL = /RELEASE
-
-LFRASH = $(LINKFLAGSHOT) $(LINKFLAGSEXTERNAL)
-LFHOT = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL)
-LFCOOL = $(LINKFLAGSCOOL) $(LINKFLAGSINTERNAL)
-
-#LFCV = /PROFILE /DEBUG:full /DEBUGTYPE:cv
-
-# Library manager
-# %%VARIETY: When adding a new variety, define a macro containing the flags
-# for the new variety
-LIBMAN = lib # can't call this LIB - it screws the environment
-LIBFLAGSCOMMON =
-
-LIBFLAGSRASH =
-LIBFLAGSHOT =
-LIBFLAGSCOOL =
-
-# Browser database manager [not used at present]
-#BSC = bscmake
-#BSCFLAGS = /nologo /n
-
-
-# == Common definitions ==
-# %%PART: When adding a new part, add it here, unless it's platform-specific
-# [It is not possible use a macro, like $(PFM), in a substitution,
-# hence all parts end up being platform-specific.]
-
-
-# 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/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/freelist.c b/mps/code/freelist.c
index a9e482550f3..6eddc3dff83 100644
--- a/mps/code/freelist.c
+++ b/mps/code/freelist.c
@@ -1,7 +1,7 @@
/* freelist.c: FREE LIST ALLOCATOR IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2013-2014 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2013-2015 Ravenbrook Limited. See end of file for license.
*
* .sources: .
*/
@@ -18,11 +18,11 @@ SRCID(freelist, "$Id$");
typedef union FreelistBlockUnion {
- struct {
+ struct FreelistBlockSmall {
FreelistBlock next; /* tagged with low bit 1 */
/* limit is (char *)this + freelistAlignment(fl) */
} small;
- struct {
+ struct FreelistBlockLarge {
FreelistBlock next; /* not tagged (low bit 0) */
Addr limit;
} large;
@@ -101,6 +101,9 @@ static Bool FreelistBlockCheck(FreelistBlock block)
CHECKL(freelistBlockNext(block) == freelistEND
|| block < freelistBlockNext(block));
CHECKL(freelistBlockIsSmall(block) || (Addr)block < block->large.limit);
+ /* Would like to CHECKL(!freelistBlockIsSmall(block) ||
+ * freelistBlockSize(fl, block) == freelistAlignment(fl)) but we
+ * don't have 'fl' here. This is checked in freelistBlockSetLimit. */
return TRUE;
}
@@ -139,6 +142,7 @@ static void freelistBlockSetLimit(Freelist fl, FreelistBlock block, Addr limit)
} else {
AVER(size >= sizeof(block->small));
block->small.next = freelistTagSet(block->small.next);
+ AVER(freelistBlockSize(fl, block) == freelistAlignment(fl));
}
AVER(freelistBlockLimit(fl, block) == limit);
}
@@ -170,6 +174,9 @@ Bool FreelistCheck(Freelist fl)
CHECKS(Freelist, fl);
land = FreelistLand(fl);
CHECKD(Land, land);
+ CHECKL(AlignCheck(FreelistMinimumAlignment));
+ CHECKL(sizeof(struct FreelistBlockSmall) < sizeof(struct FreelistBlockLarge));
+ CHECKL(sizeof(struct FreelistBlockSmall) <= freelistAlignment(fl));
/* See */
CHECKL(AlignIsAligned(freelistAlignment(fl), FreelistMinimumAlignment));
CHECKL((fl->list == freelistEND) == (fl->listSize == 0));
@@ -236,12 +243,14 @@ static Size freelistSize(Land land)
* Otherwise, if next is freelistEND, make prev the last block in the list.
* Otherwise, make next follow prev in the list.
* Update the count of blocks by 'delta'.
-
+ *
* It is tempting to try to simplify this code by putting a
* FreelistBlockUnion into the FreelistStruct and so avoiding the
* special case on prev. But the problem with that idea is that we
* can't guarantee that such a sentinel would respect the isolated
- * range invariant, and so it would still have to be special-cases.
+ * range invariant (it would have to be at a lower address than the
+ * first block in the free list, which the MPS has no mechanism to
+ * enforce), and so it would still have to be special-cased.
*/
static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev,
@@ -781,6 +790,7 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream, Count depth)
res = WriteF(stream, depth,
"Freelist $P {\n", (WriteFP)fl,
" listSize = $U\n", (WriteFU)fl->listSize,
+ " size = $U\n", (WriteFU)fl->size,
NULL);
b = LandIterate(land, freelistDescribeVisitor, stream, depth + 2);
@@ -815,7 +825,7 @@ DEFINE_LAND_CLASS(FreelistLandClass, class)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2013-2014 Ravenbrook Limited .
+ * Copyright (C) 2013-2015 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c
index 2ae97104930..6d7f3339667 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/global.c b/mps/code/global.c
index d60e925fdb3..164798d9695 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -657,7 +657,8 @@ Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context)
res = PoolAccess(SegPool(seg), seg, addr, mode, context);
AVER(res == ResOK); /* Mutator can't continue unless this succeeds */
} else {
- /* Protection was already cleared: nothing to do now. */
+ /* Protection was already cleared, for example by another thread
+ or a fault in a nested exception handler: nothing to do now. */
}
EVENT4(ArenaAccess, arena, count, addr, mode);
ArenaLeave(arena);
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/ld.c b/mps/code/ld.c
index 3c55c27fccd..c9e79f8a762 100644
--- a/mps/code/ld.c
+++ b/mps/code/ld.c
@@ -1,7 +1,7 @@
/* ld.c: LOCATION DEPENDENCY 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.
*
* .def: A location dependency records the fact that the bit-patterns
* of some references will be used directly (most likely for
@@ -92,6 +92,15 @@ void LDReset(mps_ld_t ld, Arena arena)
* occured since the epoch recorded in the dependency. If the location
* were used first only the new location of the reference would end up
* in the set.
+ *
+ * .add.no-arena-check: Add does not check that the address belongs to
+ * the arena because this would require taking the arena lock. We
+ * would rather that this function be lock-free even if some errors
+ * are not detected.
+ *
+ * .add.no-align-check: Add does not check that the address is
+ * aligned, for the same reason as .add.check: it can't find out which
+ * pool the address belongs to without taking the lock.
*/
void LDAdd(mps_ld_t ld, Arena arena, Addr addr)
{
@@ -153,6 +162,10 @@ Bool LDIsStaleAny(mps_ld_t ld, Arena arena)
* .stale.conservative: In fact we just ignore the address and test if
* any dependency is stale. This is conservatively correct (no false
* negatives) but provides a hook for future improvement.
+ *
+ * .stale.no-arena-check: See .add.no-arena-check.
+ *
+ * .stale.no-align-check: See .add.no-align-check.
*/
Bool LDIsStale(mps_ld_t ld, Arena arena, Addr addr)
{
@@ -225,7 +238,7 @@ void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from)
/* 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.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 a3c5a8bbf6c..af2cde97ff1 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 */
@@ -562,13 +563,14 @@ extern Bool (ArenaStep)(Globals globals, double interval, double multiplier);
extern void ArenaClamp(Globals globals);
extern void ArenaRelease(Globals globals);
extern void ArenaPark(Globals globals);
-extern void ArenaExposeRemember(Globals globals, int remember);
+extern void ArenaExposeRemember(Globals globals, Bool remember);
extern void ArenaRestoreProtection(Globals globals);
extern Res ArenaStartCollect(Globals globals, int why);
extern Res ArenaCollect(Globals globals, int why);
extern Bool ArenaHasAddr(Arena arena, Addr addr);
extern Res ArenaAddrObject(Addr *pReturn, Arena arena, Addr addr);
extern void ArenaChunkInsert(Arena arena, Chunk chunk);
+extern void ArenaChunkRemoved(Arena arena, Chunk chunk);
extern void ArenaSetEmergency(Arena arena, Bool emergency);
extern Bool ArenaEmergency(Arena arean);
@@ -1052,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/mpmst.h b/mps/code/mpmst.h
index 01dbf16b732..a798cc71fc4 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -526,7 +526,6 @@ typedef struct mps_arena_class_s {
ArenaVarargsMethod varargs;
ArenaInitMethod init;
ArenaFinishMethod finish;
- ArenaReservedMethod reserved;
ArenaPurgeSpareMethod purgeSpare;
ArenaExtendMethod extend;
ArenaGrowMethod grow;
@@ -714,7 +713,8 @@ typedef struct mps_arena_s {
ReservoirStruct reservoirStruct; /* */
- Size committed; /* amount of committed RAM */
+ Size reserved; /* total reserved address space */
+ Size committed; /* total committed memory */
Size commitLimit; /* client-configurable commit limit */
Size spareCommitted; /* Amount of memory in hysteresis fund */
diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h
index a69b2b79ebe..a6030e4c1e5 100644
--- a/mps/code/mpmtypes.h
+++ b/mps/code/mpmtypes.h
@@ -120,7 +120,6 @@ typedef void (*ArenaVarargsMethod)(ArgStruct args[], va_list varargs);
typedef Res (*ArenaInitMethod)(Arena *arenaReturn,
ArenaClass class, ArgList args);
typedef void (*ArenaFinishMethod)(Arena arena);
-typedef Size (*ArenaReservedMethod)(Arena arena);
typedef Size (*ArenaPurgeSpareMethod)(Arena arena, Size size);
typedef Res (*ArenaExtendMethod)(Arena arena, Addr base, Size size);
typedef Res (*ArenaGrowMethod)(Arena arena, LocusPref pref, Size size);
diff --git a/mps/code/mps.c b/mps/code/mps.c
index d31a1f60a0a..95919d9680c 100644
--- a/mps/code/mps.c
+++ b/mps/code/mps.c
@@ -214,7 +214,6 @@
#include "mpsiw3.c" /* Windows interface layer extras */
/* Windows on 64-bit Intel with Microsoft Visual Studio */
-/* ssw3i6.asm is also required, but can't be included here */
#elif defined(MPS_PF_W3I6MV)
diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj
index c83a1026d6e..30aad557d3b 100644
--- a/mps/code/mps.xcodeproj/project.pbxproj
+++ b/mps/code/mps.xcodeproj/project.pbxproj
@@ -43,16 +43,16 @@
name = testall;
productName = testrun;
};
- 2215A9C1192A47D500E9E2CE /* testpoll */ = {
+ 2215A9C1192A47D500E9E2CE /* testpollnone */ = {
isa = PBXAggregateTarget;
- buildConfigurationList = 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpoll" */;
+ buildConfigurationList = 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpollnone" */;
buildPhases = (
2215A9C4192A47D500E9E2CE /* ShellScript */,
);
dependencies = (
2215A9C2192A47D500E9E2CE /* PBXTargetDependency */,
);
- name = testpoll;
+ name = testpollnone;
productName = testrun;
};
22CDE8EF16E9E97D00366D0A /* testrun */ = {
@@ -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 */,
);
@@ -3403,7 +3397,7 @@
2215A9B9192A47CE00E9E2CE /* testall */,
2215A9B1192A47C500E9E2CE /* testansi */,
2215A9A9192A47BB00E9E2CE /* testci */,
- 2215A9C1192A47D500E9E2CE /* testpoll */,
+ 2215A9C1192A47D500E9E2CE /* testpollnone */,
22CDE8EF16E9E97D00366D0A /* testrun */,
31EEABFA156AAF9D00714D05 /* mps */,
3114A632156E94DB001E0AA3 /* abqtest */,
@@ -3468,7 +3462,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n";
+ shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n";
showEnvVarsInLog = 0;
};
2215A9B4192A47C500E9E2CE /* ShellScript */ = {
@@ -3482,7 +3476,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n";
+ shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n";
showEnvVarsInLog = 0;
};
2215A9BC192A47CE00E9E2CE /* ShellScript */ = {
@@ -3496,7 +3490,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n";
+ shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n";
showEnvVarsInLog = 0;
};
2215A9C4192A47D500E9E2CE /* ShellScript */ = {
@@ -3510,7 +3504,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n";
+ shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n";
showEnvVarsInLog = 0;
};
22CDE8F416E9E9D400366D0A /* ShellScript */ = {
@@ -3524,7 +3518,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n";
+ shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@@ -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;
@@ -5810,7 +5802,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpoll" */ = {
+ 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpollnone" */ = {
isa = XCConfigurationList;
buildConfigurations = (
2215A9C6192A47D500E9E2CE /* Debug */,
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index c00da18c201..283fbc6123e 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -1,14 +1,14 @@
/* mpsi.c: MEMORY POOL SYSTEM C INTERFACE LAYER
*
* $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: This code bridges between the MPS interface to C,
* , 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:
*
@@ -248,7 +248,7 @@ void mps_arena_park(mps_arena_t arena)
void mps_arena_expose(mps_arena_t arena)
{
ArenaEnter(arena);
- ArenaExposeRemember(ArenaGlobals(arena), 0);
+ ArenaExposeRemember(ArenaGlobals(arena), FALSE);
ArenaLeave(arena);
}
@@ -256,7 +256,7 @@ void mps_arena_expose(mps_arena_t arena)
void mps_arena_unsafe_expose_remember_protection(mps_arena_t arena)
{
ArenaEnter(arena);
- ArenaExposeRemember(ArenaGlobals(arena), 1);
+ ArenaExposeRemember(ArenaGlobals(arena), TRUE);
ArenaLeave(arena);
}
@@ -1384,6 +1384,7 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena,
AVER(mps_reg_scan != NULL);
AVER(mps_reg_scan == mps_stack_scan_ambig); /* .reg.scan */
AVER(reg_scan_p != NULL); /* stackBot */
+ AVER(AddrIsAligned(reg_scan_p, sizeof(Word)));
AVER(rank == mps_rank_ambig());
AVER(mps_rm == (mps_rm_t)0);
@@ -2005,7 +2006,7 @@ void _mps_args_set_key(mps_arg_s args[MPS_ARGS_MAX], unsigned i,
/* 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/mv.nmk b/mps/code/mv.nmk
index d0759bad532..6abd37d810e 100644
--- a/mps/code/mv.nmk
+++ b/mps/code/mv.nmk
@@ -7,7 +7,7 @@
#
# This file is included by platform nmake files that use the Microsoft
# Visual C/C+ compiler. It defines the compiler-specific variables
-# that the common nmake file fragment () requires.
+# that the common nmake fragment (comm.nmk) requires.
CC = cl
LIBMAN = lib
diff --git a/mps/code/pc.nmk b/mps/code/pc.nmk
index e52addfba4c..fdcf1235d37 100644
--- a/mps/code/pc.nmk
+++ b/mps/code/pc.nmk
@@ -7,7 +7,7 @@
#
# This file is included by platform nmake files that use the Pelles C
# compiler. It defines the compiler-specific variables that the common
-# nmake file fragment () requires.
+# nmake fragment (comm.nmk) requires.
CC = pocc
LIBMAN = polib
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/poolmv.c b/mps/code/poolmv.c
index 709dfb6bf7b..19b3c2bb443 100644
--- a/mps/code/poolmv.c
+++ b/mps/code/poolmv.c
@@ -1,7 +1,7 @@
/* poolmv.c: MANUAL VARIABLE POOL
*
* $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.
*
* **** RESTRICTION: This pool may not allocate from the arena control
@@ -260,7 +260,7 @@ static Res MVInit(Pool pool, ArgList args)
res = PoolInit(mvBlockPool(mv), arena, PoolClassMFS(), piArgs);
} MPS_ARGS_END(piArgs);
if(res != ResOK)
- return res;
+ goto failBlockPoolInit;
spanExtendBy = sizeof(MVSpanStruct) * (maxSize/extendBy);
@@ -270,7 +270,7 @@ static Res MVInit(Pool pool, ArgList args)
res = PoolInit(mvSpanPool(mv), arena, PoolClassMFS(), piArgs);
} MPS_ARGS_END(piArgs);
if(res != ResOK)
- return res;
+ goto failSpanPoolInit;
mv->extendBy = extendBy;
mv->avgSize = avgSize;
@@ -284,6 +284,11 @@ static Res MVInit(Pool pool, ArgList args)
AVERT(MV, mv);
EVENT5(PoolInitMV, pool, arena, extendBy, avgSize, maxSize);
return ResOK;
+
+failSpanPoolInit:
+ PoolFinish(mvBlockPool(mv));
+failBlockPoolInit:
+ return res;
}
@@ -913,7 +918,7 @@ Bool MVCheck(MV mv)
/* 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/reserv.c b/mps/code/reserv.c
index b0d431c3f9c..91a2fd52559 100644
--- a/mps/code/reserv.c
+++ b/mps/code/reserv.c
@@ -100,6 +100,7 @@ Bool ReservoirCheck(Reservoir reservoir)
}
CHECKL(SizeIsArenaGrains(reservoir->reservoirLimit, arena));
CHECKL(SizeIsArenaGrains(reservoir->reservoirSize, arena));
+ CHECKL(reservoir->reservoirSize <= reservoir->reservoirLimit);
return TRUE;
}
diff --git a/mps/code/root.c b/mps/code/root.c
index bd9afec57d4..7a3e1205be2 100644
--- a/mps/code/root.c
+++ b/mps/code/root.c
@@ -1,7 +1,7 @@
/* root.c: ROOT 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.
*
* .purpose: This is the implementation of the root datatype.
*
@@ -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);
@@ -263,7 +263,9 @@ Res RootCreateTable(Root *rootReturn, Arena arena,
AVERT(Arena, arena);
AVERT(Rank, rank);
AVER(base != 0);
- AVER(base < limit);
+ AVER(AddrIsAligned(base, sizeof(Word)));
+ AVER(base < limit);
+ AVER(AddrIsAligned(limit, sizeof(Word)));
theUnion.table.base = base;
theUnion.table.limit = limit;
@@ -315,6 +317,13 @@ Res RootCreateReg(Root *rootReturn, Arena arena,
return rootCreate(rootReturn, arena, rank, (RootMode)0, RootREG, &theUnion);
}
+/* RootCreateFmt -- create root from block of formatted objects
+ *
+ * .fmt.no-align-check: Note that we don't check the alignment of base
+ * and limit. That's because we're only given the scan function, so we
+ * don't know the format's alignment requirements.
+ */
+
Res RootCreateFmt(Root *rootReturn, Arena arena,
Rank rank, RootMode mode, mps_fmt_scan_t scan,
Addr base, Addr limit)
@@ -549,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 */
@@ -698,7 +707,7 @@ Res RootsDescribe(Globals arenaGlobals, 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/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 88ee8751331..0dfc1945db6 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/splay.c b/mps/code/splay.c
index 658faa7dd25..ed46c7a4ba4 100644
--- a/mps/code/splay.c
+++ b/mps/code/splay.c
@@ -1,7 +1,7 @@
/* splay.c: SPLAY TREE 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.
*
* .purpose: Splay trees are used to manage potentially unbounded
* collections of ordered things. In the MPS these are usually
@@ -9,10 +9,9 @@
*
* .source:
*
- * .note.stack: It's important that the MPS have a bounded stack
- * size, and this is a problem for tree algorithms. Basically,
- * we have to avoid recursion. TODO: Design documentation for this
- * requirement, meanwhile see job003651 and job003640.
+ * .note.stack: It's important that the MPS have a bounded stack size,
+ * and this is a problem for tree algorithms. Basically, we have to
+ * avoid recursion. See design.mps.sp.sol.depth.no-recursion.
*/
@@ -1402,7 +1401,7 @@ Res SplayTreeDescribe(SplayTree splay, 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/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/code/traceanc.c b/mps/code/traceanc.c
index 77fe772d587..ede8d012fe8 100644
--- a/mps/code/traceanc.c
+++ b/mps/code/traceanc.c
@@ -674,7 +674,7 @@ static Res arenaRememberSummaryOne(Globals global, Addr base, RefSet summary)
RememberedSummaryBlock newBlock;
int res;
- res = ControlAlloc(&p, arena, sizeof *newBlock, 0);
+ res = ControlAlloc(&p, arena, sizeof *newBlock, FALSE);
if(res != ResOK) {
return res;
}
@@ -704,12 +704,13 @@ static Res arenaRememberSummaryOne(Globals global, Addr base, RefSet summary)
protection state or not (for later restoration with
ArenaRestoreProtection).
*/
-void ArenaExposeRemember(Globals globals, int remember)
+void ArenaExposeRemember(Globals globals, Bool remember)
{
Seg seg;
Arena arena;
AVERT(Globals, globals);
+ AVERT(Bool, remember);
ArenaPark(globals);
diff --git a/mps/code/tract.c b/mps/code/tract.c
index 5d3bffe9721..9aa815f47ba 100644
--- a/mps/code/tract.c
+++ b/mps/code/tract.c
@@ -167,7 +167,8 @@ Bool ChunkCheck(Chunk chunk)
/* ChunkInit -- initialize generic part of chunk */
-Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, BootBlock boot)
+Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, Size reserved,
+ BootBlock boot)
{
Size size;
Count pages;
@@ -192,6 +193,7 @@ Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, BootBlock boot)
chunk->pageShift = pageShift = SizeLog2(chunk->pageSize);
chunk->base = base;
chunk->limit = limit;
+ chunk->reserved = reserved;
size = ChunkSize(chunk);
chunk->pages = pages = size >> pageShift;
@@ -262,17 +264,16 @@ void ChunkFinish(Chunk chunk)
PageIndexBase(chunk, chunk->allocBase),
chunk->limit);
+ ArenaChunkRemoved(arena, chunk);
+
chunk->sig = SigInvalid;
TreeFinish(&chunk->chunkTree);
RingRemove(&chunk->arenaRing);
- if (chunk->arena->primary == chunk)
- chunk->arena->primary = NULL;
-
/* Finish all other fields before class finish, because they might be */
/* unmapped there. */
- (chunk->arena->class->chunkFinish)(chunk);
+ (*arena->class->chunkFinish)(chunk);
}
diff --git a/mps/code/tract.h b/mps/code/tract.h
index 07906ad5756..ce7c602a176 100644
--- a/mps/code/tract.h
+++ b/mps/code/tract.h
@@ -148,6 +148,9 @@ typedef struct ChunkStruct {
BT allocTable; /* page allocation table */
Page pageTable; /* the page table */
Count pageTablePages; /* number of pages occupied by page table */
+ Size reserved; /* reserved address space for chunk (including overhead
+ such as losses due to alignment): must not change
+ (or arena reserved calculation will break) */
} ChunkStruct;
@@ -159,10 +162,11 @@ typedef struct ChunkStruct {
#define ChunkSizeToPages(chunk, size) ((Count)((size) >> (chunk)->pageShift))
#define ChunkPage(chunk, pi) (&(chunk)->pageTable[pi])
#define ChunkOfTree(tree) PARENT(ChunkStruct, chunkTree, tree)
+#define ChunkReserved(chunk) RVALUE((chunk)->reserved)
extern Bool ChunkCheck(Chunk chunk);
extern Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit,
- BootBlock boot);
+ Size reserved, BootBlock boot);
extern void ChunkFinish(Chunk chunk);
extern Compare ChunkCompare(Tree tree, TreeKey key);
extern TreeKey ChunkKey(Tree tree);
diff --git a/mps/code/tree.c b/mps/code/tree.c
index fb651ed5919..f87e8364ea7 100644
--- a/mps/code/tree.c
+++ b/mps/code/tree.c
@@ -1,7 +1,7 @@
/* tree.c: BINARY TREE 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.
*
* Simple binary trees with utilities, for use as building blocks.
* Keep it simple, like Rings (see ring.h).
@@ -9,10 +9,9 @@
* The performance requirements on tree implementation will depend on
* how each individual function is applied in the MPS.
*
- * .note.stack: It's important that the MPS have a bounded stack
- * size, and this is a problem for tree algorithms. Basically,
- * we have to avoid recursion. TODO: Design documentation for this
- * requirement, meanwhile see job003651 and job003640.
+ * .note.stack: It's important that the MPS have a bounded stack size,
+ * and this is a problem for tree algorithms. Basically, we have to
+ * avoid recursion. See design.mps.sp.sol.depth.no-recursion.
*/
#include "tree.h"
@@ -569,7 +568,7 @@ void TreeTraverseAndDelete(Tree *treeIO, TreeVisitor visitor,
/* 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/w3i3mv.nmk b/mps/code/w3i3mv.nmk
index ff84851b1de..92e609b5f2f 100644
--- a/mps/code/w3i3mv.nmk
+++ b/mps/code/w3i3mv.nmk
@@ -5,9 +5,6 @@
PFM = w3i3mv
-PFMDEFS = /DCONFIG_PF_STRING="w3i3mv" /DCONFIG_PF_W3I3MV /DWIN32 /D_WINDOWS
-
-# MPM platform-specific sources.
MPMPF = \
[lockw3] \
[mpsiw3] \
@@ -20,9 +17,8 @@ MPMPF = \
[thw3i3] \
[vmw3]
-!INCLUDE commpre.nmk
!INCLUDE mv.nmk
-!INCLUDE commpost.nmk
+!INCLUDE comm.nmk
# C. COPYRIGHT AND LICENSE
diff --git a/mps/code/w3i3pc.nmk b/mps/code/w3i3pc.nmk
index da76ee4d338..5ffe8892ebb 100644
--- a/mps/code/w3i3pc.nmk
+++ b/mps/code/w3i3pc.nmk
@@ -5,9 +5,6 @@
PFM = w3i3pc
-PFMDEFS = /DCONFIG_PF_STRING="w3i3pc" /DCONFIG_PF_W3I3PC /DWIN32 /D_WINDOWS
-
-# MPM platform-specific sources.
MPMPF = \
[lockw3] \
[mpsiw3] \
@@ -20,9 +17,8 @@ MPMPF = \
[thw3i3] \
[vmw3]
-!INCLUDE commpre.nmk
!INCLUDE pc.nmk
-!INCLUDE commpost.nmk
+!INCLUDE comm.nmk
# C. COPYRIGHT AND LICENSE
diff --git a/mps/code/w3i6mv.nmk b/mps/code/w3i6mv.nmk
index 26f4329bc0e..eb36bc200d2 100644
--- a/mps/code/w3i6mv.nmk
+++ b/mps/code/w3i6mv.nmk
@@ -5,10 +5,6 @@
PFM = w3i6mv
-PFMDEFS = /DCONFIG_PF_STRING="w3i6mv" /DCONFIG_PF_W3I6MV /DWIN32 /D_WINDOWS
-MASM = ml64
-
-# MPM platform-specific sources.
MPMPF = \
[lockw3] \
[mpsiw3] \
@@ -21,9 +17,8 @@ MPMPF = \
[thw3i6] \
[vmw3]
-!INCLUDE commpre.nmk
!INCLUDE mv.nmk
-!INCLUDE commpost.nmk
+!INCLUDE comm.nmk
# C. COPYRIGHT AND LICENSE
diff --git a/mps/code/w3i6pc.nmk b/mps/code/w3i6pc.nmk
index 9870f697e4b..31b86a82fc0 100644
--- a/mps/code/w3i6pc.nmk
+++ b/mps/code/w3i6pc.nmk
@@ -7,11 +7,8 @@
PFM = w3i6pc
-PFMDEFS = /DCONFIG_PF_STRING="w3i6pc" /DCONFIG_PF_W3I6PC /DWIN32 /D_WINDOWS
+CFLAGSTARGETPRE = /Tamd64-coff
-CFLAGSCOMMONPRE = $(CFLAGSCOMMONPRE) /Tamd64-coff
-
-# MPM platform-specific sources.
MPMPF = \
[lockw3] \
[mpsiw3] \
@@ -24,9 +21,8 @@ MPMPF = \
[thw3i6] \
[vmw3]
-!INCLUDE commpre.nmk
!INCLUDE pc.nmk
-!INCLUDE commpost.nmk
+!INCLUDE comm.nmk
# C. COPYRIGHT AND LICENSE
diff --git a/mps/design/an.txt b/mps/design/an.txt
new file mode 100644
index 00000000000..7d6cc117407
--- /dev/null
+++ b/mps/design/an.txt
@@ -0,0 +1,216 @@
+.. mode: -*- rst -*-
+
+Generic modules
+===============
+
+:Tag: design.mps.an
+:Author: Gareth Rees
+:Date: 2014-11-02
+:Status: complete design
+:Revision: $Id$
+:Copyright: See `Copyright and License`_.
+:Index terms: pair: generic modules; design
+
+
+Introduction
+------------
+
+_`.intro`: This is the design of generic modules in the MPS.
+
+_`.readership`: Any MPS developer; anyone porting the MPS to a new
+platform.
+
+_`.overview`: Generic modules provide implementations of functional
+modules using only the features of the Standard C Library. These
+implementations are partially functional or non-functional, but
+provide a basis for ports of the MPS to new platforms.
+
+_`.name`: The name "ANSI" for the generic modules is historical: the C
+language was originally standardized by the American National
+Standards Institute, and so Standard C used to be known as "ANSI C".
+
+
+Requirements
+------------
+
+_`.req.port`: The MPS must be portable to new platforms. (Otherwise we
+can't meet the needs of customers using new platforms.)
+
+_`.req.port.rapid`: The MPS should be portable to new platforms
+rapidly.
+
+_`.req.port.rapid.expert`: An expert MPS developer (who may be a
+novice on the new platform) should be able to get a minimally useful
+implementation of the MPS running on a new platform within a few
+hours.
+
+_`.req.port.rapid.novice`: A novice MPS developer (who is an expert on
+the new platform) should be able to get the MPS running on a new
+platform within a few days.
+
+
+Design
+------
+
+_`.sol.modules`: Features of the MPS which can benefit from
+platform-specific implementations are divided into *functional
+modules*, with clean interfaces to the MPS and to each other. See
+`.mod`_ for a list of these modules. (This helps meet `.req.port`_ by
+isolating the platform dependencies, and it helps meet
+`.req.port.rapid`_ because a porter can mix and match implementations,
+using existing implementations where possible.)
+
+_`.sol.generic`: Each functional module has a generic implementation
+using only features of the Standard C Library. (This helps meet
+`.req.port.rapid`_ because the MPS can be ported in stages, starting
+with the generic modules and porting the modules needed to meet the
+most urgent requirements. The generic implementations help meet
+`.req.port.rapid.novice`_ by providing clear and illustrative
+examples.)
+
+_`.sol.fallback`: The interfaces to the modules are designed to make
+it possible to implement `.sol.generic`_. When a platform-specific
+feature is needed to meet performance (or other attribute)
+requirements, the interface also makes it possible to meet the
+functional requirements while missing the attribute requirements. See
+`.sol.fallback.example`_ for an example. (This helps meet
+`.req.port.rapid`_ by allowing the generic implementations to meet
+many or most of the functional requirements.)
+
+_`.sol.fallback.example`: The MPS normally uses incremental collection
+to meet requirements on pause times, but this requires barriers. The
+interface to the protection module is designed to make it possible to
+write an implementation without barriers, via the function
+``ProtSync()`` that synchronizes the mutator with the collector.
+
+_`.sol.test`: There are makefiles for the pseudo-platforms ``anangc``,
+``ananll`` and ``ananmv`` that compile and test the generic
+implementations. See design.mps.config.opt_ for the configuration
+options used to implement these platforms. (This supports
+`.req.port.rapid`_ by making sure that the generic implementations are
+working when it is time to use them.)
+
+.. _design.mps.config.opt: config#opt
+
+
+Modules
+-------
+
+_`.mod`: This section lists the functional modules in the MPS.
+
+_`.mod.lock`: Locks. See design.mps.lock_.
+
+_`.mod.prmc`: Protection mutator context. See design.mps.prmc_.
+
+_`.mod.prot`: Memory protection. See design.mps.prot_.
+
+_`.mod.ss`: Stack and register scanning. See design.mps.ss_.
+
+_`.mod.sp`: Stack probe. See design.mps.sp_.
+
+_`.mod.th`: Thread manager. See design.mps.thread-manager_.
+
+_`.mod.vm`: Virtual mapping. See design.mps.vm_.
+
+.. _design.mps.lock: lock
+.. _design.mps.prot: prot
+.. _design.mps.prmc: prmc
+.. _design.mps.sp: sp
+.. _design.mps.ss: ss
+.. _design.mps.thread-manager: thread-manager
+.. _design.mps.vm: vm
+
+
+Limitations of generic implementations
+--------------------------------------
+
+_`.lim`: This section summarizes the limitations of the generic
+implementations of the function modules.
+
+_`.lim.lock`: Requires a single-threaded mutator (see
+design.mps.lock.impl.an_).
+
+_`.lim.prmc`: Does not support single-stepping of accesses (see
+design.mps.prmc.impl.an.fault_) and requires a single-threaded mutator
+(see design.mps.prmc.impl.an.suspend_).
+
+_`.lim.prot`: Does not support incremental collection (see
+design.mps.prot.impl.an.sync_) and is not compatible with
+implementations of the protection mutator context module that support
+single-stepping of accesses (see design.mps.prot.impl.an.sync.issue_).
+
+_`.lim.sp`: Only suitable for use with programs that do not handle
+stack overflow faults, or do not call into the MPS from the handler
+(see design.mps.sp.issue.an_).
+
+_`.lim.ss`: Overscans compared to a platform-specific implementation
+(see design.mps.ss.impl.an_).
+
+_`.lim.th`: Requires a single-threaded mutator (see
+design.mps.thread-manager.impl.an.single_).
+
+_`.lim.vm`: Maps all reserved addresses into main memory (see
+design.mps.vm.impl.an.reserve_), thus using more main memory than a
+platform-specific implementation.
+
+.. _design.mps.lock.impl.an: lock#impl.an
+.. _design.mps.prmc.impl.an.fault: prmc#impl.an.fault
+.. _design.mps.prmc.impl.an.suspend: prmc#impl.an.suspend
+.. _design.mps.prot.impl.an.sync: prot#impl.an.sync
+.. _design.mps.prot.impl.an.sync.issue: prot#impl.an.sync.issue
+.. _design.mps.sp.issue.an: sp#issue.an
+.. _design.mps.ss.impl.an: ss#impl.an
+.. _design.mps.thread-manager.impl.an.single: thread-manager#impl.an.single
+.. _design.mps.vm.impl.an.reserve: vm#impl.an.reserve
+
+
+
+Document History
+----------------
+
+- 2014-11-02 GDR_ Initial draft based on design.mps.protan.
+
+.. _GDR: http://www.ravenbrook.com/consultants/gdr/
+
+
+Copyright and License
+---------------------
+
+Copyright © 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:
+
+#. 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/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/cbs.txt b/mps/design/cbs.txt
index 629ffee08fe..34c2eedd4cd 100644
--- a/mps/design/cbs.txt
+++ b/mps/design/cbs.txt
@@ -76,14 +76,14 @@ class, a subclass of ``LandClass`` suitable for passing to
``LandClass CBSFastLandClassGet(void)``
-_`.function.class`: Returns a subclass of ``CBSLandClass`` that
+_`.function.class.fast`: Returns a subclass of ``CBSLandClass`` that
maintains, for each subtree, the size of the largest block in that
subtree. This enables the ``LandFindFirst()``, ``LandFindLast()``, and
``LandFindLargest()`` generic functions.
``LandClass CBSZonedLandClassGet(void)``
-_`.function.class`: Returns a subclass of ``CBSFastLandClass`` that
+_`.function.class.zoned`: Returns a subclass of ``CBSFastLandClass`` that
maintains, for each subtree, the union of the zone sets of all ranges
in that subtree. This enables the ``LandFindInZones()`` generic
function.
diff --git a/mps/design/exec-env.txt b/mps/design/exec-env.txt
new file mode 100644
index 00000000000..65de1dd228f
--- /dev/null
+++ b/mps/design/exec-env.txt
@@ -0,0 +1,189 @@
+.. mode: -*- rst -*-
+
+Execution environment
+=====================
+
+:Tag: design.mps.exec-env
+:Author: Richard Brooksby
+:Date: 1996-08-30
+:Status: incomplete design
+:Revision: $Id$
+:Copyright: See section `Copyright and License`_.
+:Index terms: pair: execution; environment
+
+
+Introduction
+------------
+
+_`.intro`: This document describes how the MPS is designed to work in
+different execution environments (see standard.ansic section 5.1.2).
+
+
+Discussion
+----------
+
+_`.std`: These are the relevant statements from the International
+Standard ISO/IEC 9899:1990 "Programming languages — C", with tags
+added:
+
+ 4. Compliance
+
+ […]
+
+ _`.std.com.hosted`: A "conforming hosted implementation" shall
+ accept any strictly conforming program. _`.std.com.free`: A
+ "conforming freestanding implementation" shall accept any strictly
+ conforming program in which the use of the features specified in
+ the library clause (clause 7) is confined to the contents of the
+ standard headers ````, ````, ````,
+ and ````. A conforming implementation may have
+ extensions (including additional library functions), provided they
+ do not alter the behaviour of any strictly conforming program.
+
+ […]
+
+ 5.1.2 Execution environments
+
+ _`.std.def`: Two execution environments are defined:
+ "freestanding" and "hosted". […]
+
+ _`.std.init`: All objects in static storage shall be "initialized"
+ (set to their initial values) before program startup. The manner
+ and timing of such initialization are otherwise unspecified. […]
+
+ _`.std.term`: "Program termination" returns control to the execution
+ environment. […]
+
+ 5.1.2.1 Freestanding environment
+
+ _`.std.free.lib`: Any library facilities available to a
+ freestanding environment are implementation-defined.
+
+ _`.std.free.term`: The effect of program termination in a
+ free-standing environment is implementation-defined.
+
+
+Interpretation
+--------------
+
+_`.int.free`: We interpret the "freestanding environment" as being the
+sort of environment you'd expect in an embedded system. The classic
+example is a washing machine. There are no library facilities
+available, only language facilities.
+
+_`.int.free.lib`: We assume that the headers ````,
+````, ```` and ```` are available in the
+freestanding environment, because they define only language features
+and not library calls. We assume that we may not make use of
+definitions in any other headers in freestanding parts of the system.
+
+_`.int.free.term`: We may not terminate the program in a freestanding
+environment, and therefore we may not call :c:func:`abort`. We can't
+call :c:func:`abort` anyway, because it's not defined in the headers
+listed above (`.int.free.lib`_).
+
+_`.int.free.term.own`: We can add an interface for asserting, that is,
+reporting an error and not returning, for use in debugging builds
+only. This is because the environment can implement this in a way that
+does not return to the MPS, but doesn't terminate, either. We need
+this if debugging builds are to run in a (possibly simulated or
+emulated) freestanding environment at all.
+
+
+Requirements
+------------
+
+_`.req`: It should be possible to make use of the MPS in a
+freestanding environment such as an embedded controller.
+
+_`.req.conf`: There can be configurations of the MPS that are not
+freestanding (such as using a VM arena).
+
+
+Architecture
+------------
+
+_`.arch`: Like Gaul, the MPS is divided into three parts: the *core*,
+the *platform*, and the *plinth*.
+
+_`.arch.core`: The *core* consists of the Memory Pool Manager (the
+core data structures and algorithms) and the built-in Pool Classes.
+The core must be freestanding.
+
+_`.arch.platform`: The *platform* provides the core with interfaces to
+features of the operating system and processor (locks, memory
+protection, protection mutator context, stack probing, stack and
+register scanning, thread management, and virtual memory). The
+platform is specialized to a particular environment and so can safely
+use whatever features are available in that environment.
+
+_`.arch.plinth`: The *plinth* provides the core with interfaces to
+features of the user environment (time, assertions, and logging). See
+design.mps.io_ and design.mps.lib_.
+
+.. _design.mps.io: io
+.. _design.mps.lib: lib
+
+_`.arch.distinction`: The distinction between *plinth* and *platform*
+is that end users will need to customize the features provided by the
+plinth for most programs that use the MPS (and so the interface needs
+to be simple, documented and supported), whereas implementing the
+platform interface is a specialized task that will typically be done
+once for each platform and then maintained alongside the core.
+
+
+Document History
+----------------
+
+- 1996-08-30 RB_ Created to clarify concepts needed for
+ design.mps.io_.
+
+- 2015-02-06 GDR_ Converted to reStructuredText; bring the
+ architecture description up to date by describing the platform
+ interface.
+
+.. _RB: http://www.ravenbrook.com/consultants/rb/
+.. _GDR: http://www.ravenbrook.com/consultants/gdr/
+
+
+Copyright and License
+---------------------
+
+Copyright © 1996-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 d2a1e06024f..7e48b625319 100644
--- a/mps/design/index.txt
+++ b/mps/design/index.txt
@@ -41,8 +41,10 @@ Designs
====================== ================================================
abq_ Fixed-length queues
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
@@ -52,6 +54,7 @@ collection_ Collection framework
config_ MPS configuration
critical-path_ The critical path through the MPS
diag_ Diagnostic feedback
+exec-env_ Execution environment
failover_ Fail-over allocator
finalize_ Finalization
fix_ The generic fix function
@@ -59,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
@@ -82,7 +86,6 @@ poolmvt_ Manual Variable Temporal pool class
poolmvff_ Manual Variable First-Fit pool class
prmc_ Protection mutator context
prot_ Memory protection
-protan_ ANSI implementation of protection module
protli_ Linux implementation of protection module
protocol_ Protocol inheritance
protsu_ SunOS 4 implementation of protection module
@@ -117,8 +120,10 @@ writef_ The WriteF function
.. _abq: abq
.. _alloc-frame: alloc-frame
+.. _an: an
.. _arena: arena
.. _arenavm: arenavm
+.. _bootstrap: bootstrap
.. _bt: bt
.. _buffer: buffer
.. _cbs: cbs
@@ -128,6 +133,7 @@ writef_ The WriteF function
.. _config: config
.. _critical-path: critical-path
.. _diag: diag
+.. _exec-env: exec-env
.. _failover: failover
.. _finalize: finalize
.. _fix: fix
@@ -135,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
@@ -158,7 +165,6 @@ writef_ The WriteF function
.. _poolmvff: poolmvff
.. _prmc: prmc
.. _prot: prot
-.. _protan: protan
.. _protli: protli
.. _protocol: protocol
.. _protsu: protsu
@@ -231,7 +237,7 @@ Document History
Copyright and License
---------------------
-Copyright © 2002-2014 Ravenbrook Limited. All rights reserved.
+Copyright © 2002-2015 Ravenbrook Limited. All rights reserved.
. This is an open source license. Contact
Ravenbrook for commercial licensing options.
diff --git a/mps/design/io.txt b/mps/design/io.txt
index 655eea8caf2..27ab9d7802a 100644
--- a/mps/design/io.txt
+++ b/mps/design/io.txt
@@ -95,17 +95,19 @@ which the MPM sends and receives "messages" to and from the hosted I/O
module.
_`.arch.module`: The modules are part of the MPS but not part of the
-freestanding core system (see design.mps.exec-env). The I/O module is
+freestanding core system (see design.mps.exec-env_). The I/O module is
responsible for transmitting those messages to the external tools, and
for receiving messages from external tools and passing them to the
MPM.
+.. _design.mps.exec-env: exec-env
+
_`.arch.module.example`: For example, the "file implementation" might
just send/write telemetry messages into a file so that they can be
received/read later by an off-line measurement tool.
_`.arch.external`: The I/O Interface is part of interface to the
-freestanding core system (see design.mps.exec-env). This is so that
+freestanding core system (see design.mps.exec-env_). This is so that
the MPS can be deployed in a freestanding environment, with a special
I/O module. For example, if the MPS is used in a washing machine the
I/O module could communicate by writing output to the seven-segment
@@ -429,7 +431,7 @@ Document History
Copyright and License
---------------------
-Copyright © 2013-2014 Ravenbrook Limited. All rights reserved.
+Copyright © 2013-2015 Ravenbrook Limited. All rights reserved.
. This is an open source license. Contact
Ravenbrook for commercial licensing options.
diff --git a/mps/design/land.txt b/mps/design/land.txt
index f99ff95baba..df16fc922b9 100644
--- a/mps/design/land.txt
+++ b/mps/design/land.txt
@@ -86,7 +86,7 @@ indicating whether to continue with the iteration.
``typedef Bool (*LandDeleteVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS)``
-_`.type.visitor`: Type ``LandDeleteVisitor`` is a callback function that may
+_`.type.deletevisitor`: Type ``LandDeleteVisitor`` is a callback function that may
be passed to ``LandIterateAndDelete()``. It is called for every isolated
contiguous range in address order. The function must return a ``Bool``
indicating whether to continue with the iteration. It may additionally
@@ -187,6 +187,16 @@ _`.function.iterate.and.delete`: As ``LandIterate()``, but the visitor
function additionally returns a Boolean indicating whether the range
should be deleted from the land.
+_`.function.iterate.and.delete.justify`: The reason for having both
+``LandIterate()`` and ``LandIterateAndDelete()`` is that it may be
+possible to use a more efficient algorithm, or to preserve more
+properties of the data structure, when it is known that the land willl
+not be modified during the iteration. For example, in the CBS
+implementation, ``LandIterate()`` uses ``TreeTraverse()`` which
+preserves the tree structure, whereas ``LandIterateAndDelete()`` uses
+``TreeTraverseAndDelete()`` which flattens the tree structure, losing
+information about recently accessed nodes.
+
``Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)``
_`.function.find.first`: Locate the first block (in address order)
@@ -311,7 +321,7 @@ Document History
Copyright and License
---------------------
-Copyright © 2014 Ravenbrook Limited. All rights reserved.
+Copyright © 2014-2015 Ravenbrook Limited. All rights reserved.
. This is an open source license. Contact
Ravenbrook for commercial licensing options.
diff --git a/mps/design/lib.txt b/mps/design/lib.txt
index 962b6328cb2..1dd7efe6964 100644
--- a/mps/design/lib.txt
+++ b/mps/design/lib.txt
@@ -29,11 +29,13 @@ _`.goal`: The goals of the MPS library interface are:
_`.goal.host`: To control the dependency of the MPS on the hosted ISO
C library so that the core MPS remains freestanding (see
-design.mps.exec-env).
+design.mps.exec-env_).
+
+.. _design.mps.exec-env: exec-env
_`.goal.free`: To allow the core MPS convenient access to ISO C
functionality that is provided on freestanding platforms (see
-design.mps.exec-env.std.com.free).
+design.mps.exec-env_).
Description
@@ -46,7 +48,7 @@ _`.overview.access`: The core MPS needs to access functionality that
could be provided by an ISO C hosted environment.
_`.overview.hosted`: The core MPS must not make direct use of any
-facilities in the hosted environment (design.mps.exec-env). However,
+facilities in the hosted environment (design.mps.exec-env_). However,
it is sensible to make use of them when the MPS is deployed in a
hosted environment.
@@ -93,7 +95,7 @@ Document History
Copyright and License
---------------------
-Copyright © 2013-2014 Ravenbrook Limited. All rights reserved.
+Copyright © 2013-2015 Ravenbrook Limited. All rights reserved.
. This is an open source license. Contact
Ravenbrook for commercial licensing options.
diff --git a/mps/design/lock.txt b/mps/design/lock.txt
index 2c744cedb64..069474ae428 100644
--- a/mps/design/lock.txt
+++ b/mps/design/lock.txt
@@ -166,7 +166,7 @@ implemented using the same mechanism as normal locks. (But an
operating system-specific mechanism is used, if possible, to ensure
that the global locks are initialized just once.)
-_`.impl.ansi`: Single-threaded generic implementation ``lockan.c``:
+_`.impl.an`: Single-threaded generic implementation ``lockan.c``:
- single-threaded;
- no need for locking;
@@ -174,7 +174,7 @@ _`.impl.ansi`: Single-threaded generic implementation ``lockan.c``:
- provides checking in debug version;
- otherwise does nothing except keep count of claims.
-_`.impl.win`: Windows implementation ``lockw3.c``:
+_`.impl.w3`: Windows implementation ``lockw3.c``:
- supports Windows threads;
- uses critical section objects [cso]_;
@@ -182,7 +182,7 @@ _`.impl.win`: Windows implementation ``lockw3.c``:
- recursive and non-recursive calls use the same Windows function;
- also performs checking.
-_`.impl.posix`: POSIX implementation ``lockix.c``:
+_`.impl.ix`: POSIX implementation ``lockix.c``:
- supports [POSIXThreads]_;
- locking structure contains a mutex, initialized to check for
@@ -194,7 +194,7 @@ _`.impl.posix`: POSIX implementation ``lockix.c``:
success or ``EDEADLK`` (indicating a recursive claim);
- also performs checking.
-_`.impl.linux`: Linux implementation ``lockli.c``:
+_`.impl.li`: Linux implementation ``lockli.c``:
- supports [POSIXThreads]_;
- also supports [LinuxThreads]_, a partial implementation of POSIX Threads
diff --git a/mps/design/prmc.txt b/mps/design/prmc.txt
index 8d13d831420..0822e709527 100644
--- a/mps/design/prmc.txt
+++ b/mps/design/prmc.txt
@@ -7,7 +7,7 @@ Protection mutator context
:Author: Gareth Rees
:Date: 2014-10-23
:Status: complete design
-:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/tests.txt#2 $
+:Revision: $Id$
:Copyright: See `Copyright and License`_.
:Index terms: pair: protection mutator context; design
diff --git a/mps/design/prot.txt b/mps/design/prot.txt
index 89635435ede..fb06b78b328 100644
--- a/mps/design/prot.txt
+++ b/mps/design/prot.txt
@@ -116,9 +116,22 @@ _`.if.sync.noop`: ``ProtSync()`` is permitted to be a no-op if
Implementations
---------------
-_`.impl.an`: Generic implementation. See design.mps.protan_.
+_`.impl.an`: Generic implementation in ``protan.c``.
-.. _design.mps.protan: protan
+_`.impl.an.set`: ``ProtSet()`` does nothing.
+
+_`.impl.an.sync`: ``ProtSync()`` has no way of changing the protection
+of a segment, so it simulates faults on all segments that are supposed
+to be protected, by calling ``TraceSegAccess()``, until it determines
+that no segments require protection any more. This forces the trace to
+proceed until it is completed, preventing incremental collection.
+
+_`.impl.an.sync.issue`: This relies on the pool actually removing the
+protection, otherwise there is an infinite loop here. This is
+therefore not compatible with implementations of the protection
+mutator context module that support single-stepping of accesses (see design.mps.prmc.req.fault.step_).
+
+.. _design.mps.prmc.req.fault.step: prmc#req.fault.step
_`.impl.ix`: POSIX implementation.
diff --git a/mps/design/protan.txt b/mps/design/protan.txt
deleted file mode 100644
index 4ab046d7e47..00000000000
--- a/mps/design/protan.txt
+++ /dev/null
@@ -1,135 +0,0 @@
-.. mode: -*- rst -*-
-
-ANSI implementation of protection module
-========================================
-
-:Tag: design.mps.protan
-:Author: David Jones
-:Date: 1997-03-19
-:Status: incomplete document
-:Revision: $Id$
-:Copyright: See `Copyright and License`_.
-:Index terms:
- pair: ANSI; protection interface design
- pair: ANSI protection interface; design
-
-
-Introduction
-------------
-
-_`.readership`: Any MPS developer.
-
-_`.intro`: This is the design for the ANSI implementation of the
-protection module.
-
-
-Requirements
-------------
-
-_`.req.test`: This module is required for testing. Particularly on
-platforms where no real implementation of the protection module
-exists.
-
-_`.req.rapid-port`: This module is required for rapid porting. It
-should enable a developer to port a minimally useful configuration of
-the MPS to new platforms very quickly.
-
-
-Overview
---------
-
-_`.overview`: Most of the functions in the module do nothing. The
-exception is ``ProtSync()`` which traverses over all segments in the
-arena and simulates an access to each segment that has any protection
-on it. This means that this module depends on certain fields in the
-segment structure.
-
-_`.overview.noos`: No operating system specific (or even ANSI hosted
-specific) code is in this module. It can therefore be used on any
-platform, particularly where no real implementation of the module
-exists. It satisfies `.req.test`_ and `.req.rapid-port`_ in this way.
-
-
-Functions
----------
-
-_`.fun.protsetup`: ``ProtSetup()`` does nothing as there is nothing to
-do (under UNIX we might expect the protection module to install one or
-more signal handlers at this pointer, but that is not appropriate for
-the ANSI implementation). Of course, we can't have an empty function
-body, so there is a ``NOOP;`` here.
-
-_`.fun.sync`: ``ProtSync()`` is called to ensure that the actual
-protection of each segment (as determined by the OS) is in accordance
-with the segments's pm field. In the ANSI implementation we have no
-way of changing the protection of a segment, so instead we generate
-faults on all protected segments in the assumption that that will
-remove the protection on segments.
-
-_`.fun.sync.how`: Continually loops over all the segments until it
-finds that all segments have no protection.
-
-_`.fun.sync.seg`: If it finds a segment that is protected then
-``PoolAccess()`` is called on that segment's pool and with that
-segment. The call to ``PoolAccess()`` is wrapped with a
-``ShieldEnter()`` and ``ShieldLeave()`` thereby giving the pool the
-illusion that the fault was generated outside the MM. This depends on
-being able to determine the protection of a segment (using the ``pm``
-field), on being able to call ``ShieldEnter()`` and ``ShieldLeave()``,
-and on being able to call ``PoolAccess()``.
-
-
-Document History
-----------------
-
-- 1997-03-19 David Jones. Incomplete document.
-
-- 2002-06-07 RB_ Converted from MMInfo database design document.
-
-- 2013-05-23 GDR_ Converted to reStructuredText.
-
-.. _RB: http://www.ravenbrook.com/consultants/rb/
-.. _GDR: http://www.ravenbrook.com/consultants/gdr/
-
-
-Copyright and License
----------------------
-
-Copyright © 2013-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:
-
-#. 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/sp.txt b/mps/design/sp.txt
index 235e00f82ac..47dab436b4e 100644
--- a/mps/design/sp.txt
+++ b/mps/design/sp.txt
@@ -7,7 +7,7 @@ Stack probe
:Author: Gareth Rees
:Date: 2014-10-23
: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 probe; design
@@ -143,7 +143,7 @@ that it is only suitable for use with programs that do not handle
stack overflow faults, or do not call into the MPS from the handler.
This is because our customers have only required `.req.overflow`_ on
Windows so far. If this becomes a requirement on other platforms, the
-following Standard C implementation is likely to work::
+following Standard C implementation might work::
void StackProbe(Size depth) {
volatile Word w;
@@ -151,8 +151,9 @@ following Standard C implementation is likely to work::
w = *p;
}
-(The use of ``volatile`` is to prevent compilers from warning about
-the variable ``w`` being written but never read.)
+The use of ``volatile`` here is to prevent compilers from warning
+about the variable ``w`` being written but never read, or worse,
+optimizing away the whole statement under the "as if" rule.
Implementations
diff --git a/mps/design/splay-rotate-left.svg b/mps/design/splay-rotate-left.svg
index f5e50922aa8..00ae646a735 100644
--- a/mps/design/splay-rotate-left.svg
+++ b/mps/design/splay-rotate-left.svg
@@ -388,7 +388,7 @@
id="tspan4371"
x="388"
y="96.362183"
- style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">x
+ style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">y
y
+ sodipodi:role="line">x
diff --git a/mps/design/splay-rotate-right.svg b/mps/design/splay-rotate-right.svg
index 39fea1b2a20..d2a02bc48bb 100644
--- a/mps/design/splay-rotate-right.svg
+++ b/mps/design/splay-rotate-right.svg
@@ -374,7 +374,7 @@
id="tspan4371"
x="388"
y="96.362183"
- style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">x
+ style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">y
y
+ sodipodi:role="line">x
diff --git a/mps/design/ss.txt b/mps/design/ss.txt
index 01dd2caf268..60b5c2817fa 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
diff --git a/mps/design/testthr.txt b/mps/design/testthr.txt
index e00ccd8b317..a1bf99bb247 100644
--- a/mps/design/testthr.txt
+++ b/mps/design/testthr.txt
@@ -7,7 +7,7 @@ Multi-threaded testing
:Author: Gareth Rees
:Date: 2014-10-21
:Status: complete design
-:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/nailboard.txt#3 $
+:Revision: $Id$
:Copyright: See section `Copyright and License`_.
:Index terms: pair: threads; testing
diff --git a/mps/design/type.txt b/mps/design/type.txt
index 708693ad1db..25943f41a4b 100644
--- a/mps/design/type.txt
+++ b/mps/design/type.txt
@@ -180,8 +180,8 @@ Mode Description
======================== ==============================================
``BufferModeATTACHED`` Buffer is attached to a region of memory.
``BufferModeFLIPPED`` Buffer has been flipped.
-``BufferModeLOGGED`` Buffer emits the events ``BufferReserve`` and
- ``BufferCommit``.
+``BufferModeLOGGED`` Buffer remains permanently trapped, so that
+ all reserve and commit events can be logged.
``BufferModeTRANSITION`` Buffer is in the process of being detached.
======================== ==============================================
diff --git a/mps/design/vm.txt b/mps/design/vm.txt
index 85c5506043f..fb1be6eb5da 100644
--- a/mps/design/vm.txt
+++ b/mps/design/vm.txt
@@ -133,8 +133,8 @@ the function ``VMCopy()``. This allows the initialization of a
temporary VM descriptor on the stack. Second, call ``VMInit()`` to
reserve address space and initialize the temporary VM descriptor.
Third, call ``VMMap()`` on the new VM to map enough memory to store a
-``VMChunkStruct``. Fourth, call ``VMCopy()`` to copy the temporary VM
-descriptor into its place in the ``VMChunkStruct``.
+``VMChunk``. Fourth, call ``VMCopy()`` to copy the temporary VM
+descriptor into its place in the ``VMChunk``.
_`.sol.params`: To meet `.req.params`_, the interface provides the
function ``VMParamFromArgs()``, which decodes relevant keyword
diff --git a/mps/design/writef.txt b/mps/design/writef.txt
index bb8547d6616..2a0277990e0 100644
--- a/mps/design/writef.txt
+++ b/mps/design/writef.txt
@@ -6,7 +6,7 @@ The WriteF function
:Tag: design.mps.writef
:Author: Richard Brooksby
:Date: 1996-10-18
-:Status: incomplete design
+:Status: complete design
:Revision: $Id$
:Copyright: See `Copyright and License`_.
:Index terms: pair: WriteF function; design
@@ -16,11 +16,13 @@ Introduction
------------
_`.intro`: This document describes the ``WriteF()`` function, which
-allows formatted output in a manner similar to ANSI C ``printf``, but
-allows the MPM to operate in a freestanding environment (see
-design.mps.exec-env).
+allows formatted output in a manner similar to ``printf()`` from the
+Standard C library, but allows the Memory Pool Manager (MPM) to
+operate in a freestanding environment (see design.mps.exec-env_).
-_`.background`: The documents design.mps.exec-env and design.mps.lib_
+.. _design.mps.exec-env: exec-env
+
+_`.background`: The documents design.mps.exec-env_ and design.mps.lib_
describe the design of the library interface and the reason that it
exists.
@@ -31,10 +33,10 @@ Design
------
_`.no-printf`: There is no dependency on ``printf()``. The MPM only
-depends on ``fputc()`` and ``fputs()``, via the Library Interface
-(design.mps.lib_). This makes it much easier to deploy the MPS in a
-freestanding environment. This is achieved by implementing our own
-internal output routines in mpm.c.
+depends on ``mps_io_fputc()`` and ``mps_io_fputs()``, via the library
+interface (design.mps.lib_), part of the *plinth*. This makes it much
+easier to deploy the MPS in a freestanding environment. This is
+achieved by implementing our own output routines.
_`.writef`: Our output requirements are few, so the code is short. The
only output function which should be used in the rest of the MPM is
@@ -42,9 +44,9 @@ only output function which should be used in the rest of the MPM is
``Res WriteF(mps_lib_FILE *stream, Count depth, ...)``
-If ``depth`` is greater than zero, then the first format character,
-and each format character after a newline, is preceded by ``depth``
-spaces.
+If ``depth`` is greater than zero, then the first output character,
+and each output character after a newline in a format string, is
+preceded by ``depth`` spaces.
``WriteF()`` expects a format string followed by zero or more items to
insert into the output, followed by another format string, more items,
@@ -54,7 +56,8 @@ and so on, and finally a ``NULL`` format string. For example::
"Hello: $A\n", (WriteFA)address,
"Spong: $U ($S)\n", (WriteFU)number, (WriteFS)string,
NULL);
- if (res != ResOK) return res;
+ if (res != ResOK)
+ return res;
This makes ``Describe()`` methods much easier to write. For example, ``BufferDescribe()`` contains the following code::
@@ -83,14 +86,15 @@ This makes ``Describe()`` methods much easier to write. For example, ``BufferDes
" alignment $W\n", (WriteFW)buffer->alignment,
" rampCount $U\n", (WriteFU)buffer->rampCount,
NULL);
- if (res != ResOK) return res;
+ if (res != ResOK)
+ return res;
-_`.types`: For each format ``$X`` that ``WriteF()`` supports, there is a
-type defined in impl.h.mpmtypes ``WriteFX()`` which is the promoted
-version of that type. These are provided both to ensure promotion and
-to avoid any confusion about what type should be used in a cast. It is
-easy to check the casts against the formats to ensure that they
-correspond.
+_`.types`: For each format ``$X`` that ``WriteF()`` supports, there is
+a type ``WriteFX`` defined in mpmtypes.h, which is the promoted
+version of that type. These types are provided both to ensure
+promotion and to avoid any confusion about what type should be used in
+a cast. It is easy to check the casts against the formats to ensure
+that they correspond.
_`.types.cast`: Every argument to ``WriteF()`` must be cast, because
in variable-length argument lists the "default argument promotion"
@@ -154,7 +158,7 @@ Document History
Copyright and License
---------------------
-Copyright © 2013-2014 Ravenbrook Limited. All rights reserved.
+Copyright © 2013-2015 Ravenbrook Limited. All rights reserved.
. This is an open source license. Contact
Ravenbrook for commercial licensing options.
diff --git a/mps/manual/build.txt b/mps/manual/build.txt
index 5403d7ffc44..7b8e17c51b9 100644
--- a/mps/manual/build.txt
+++ b/mps/manual/build.txt
@@ -96,8 +96,7 @@ Building the MPS for development
If you're making modifications to the MPS itself, want to build MPS
libraries for linking, or want to build MPS tests and tools, you should
-use the MPS build. This uses makefiles or Xcode projects. [Coming
-soon, Microsoft Visual Studio solutions.]
+use the MPS build. This uses makefiles or Xcode projects.
Prerequisites
diff --git a/mps/manual/source/_templates/links.html b/mps/manual/source/_templates/links.html
index b62c13d7813..b7263205f3e 100644
--- a/mps/manual/source/_templates/links.html
+++ b/mps/manual/source/_templates/links.html
@@ -1,13 +1,11 @@
Downloads
-MPS Kit release {{ release }}
All MPS Kit releases
Issues
-Known issues
-Issues fixed in release {{ release }}
+All open issues
diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst
index 2dd8d9d4207..b8da67a4333 100644
--- a/mps/manual/source/design/index.rst
+++ b/mps/manual/source/design/index.rst
@@ -7,14 +7,18 @@ Design
:numbered:
abq
+ an
+ bootstrap
cbs
config
critical-path
+ exec-env
failover
freelist
guide.hex.trans
guide.impl.c.format
guide.impl.c.naming
+ guide.review
interface-c
keyword-arguments
land
@@ -32,3 +36,4 @@ Design
thread-manager
type
vm
+ writef
diff --git a/mps/manual/source/design/old.rst b/mps/manual/source/design/old.rst
index ee43ba7ae7c..8a8e71be1a6 100644
--- a/mps/manual/source/design/old.rst
+++ b/mps/manual/source/design/old.rst
@@ -41,7 +41,6 @@ Old design
poolmv
poolmvt
poolmvff
- protan
protli
protsu
protocol
@@ -61,4 +60,3 @@ Old design
version
vmo1
vmso
- writef
diff --git a/mps/manual/source/glossary/b.rst b/mps/manual/source/glossary/b.rst
index 8356404267c..12d4838e466 100644
--- a/mps/manual/source/glossary/b.rst
+++ b/mps/manual/source/glossary/b.rst
@@ -182,9 +182,22 @@ Memory Management Glossary: B
.. relevance::
Bitmaps are sometimes used to represent the marks in a
- :term:`mark-sweep` collector, or the used memory in a
- :term:`bitmapped fits` :term:`allocator`.
+ :term:`mark-sweep` collector (see :term:`bitmap marking`),
+ or the used memory in a :term:`bitmapped fits`
+ :term:`allocator`.
+ bitmap marking
+
+ In :term:`mark-sweep` collectors, bitmap marking is a
+ technique for :term:`marking` objects that stores the mark
+ bits for the objects in a contiguous range of memory in a
+ separate :term:`bitmap`. This improves the collector's
+ :term:`locality of reference` and cache performance, because
+ it avoids setting the :term:`dirty bit` on the :term:`pages`
+ containing the marked objects.
+
+ .. bibref:: :ref:`Zorn (1989) `.
+
bitmapped fit
A class of :term:`allocation mechanisms` that use a
diff --git a/mps/manual/source/glossary/index.rst b/mps/manual/source/glossary/index.rst
index a0484b3c5ee..6c15cbd4e84 100644
--- a/mps/manual/source/glossary/index.rst
+++ b/mps/manual/source/glossary/index.rst
@@ -84,6 +84,7 @@ All
:term:`bit table `
:term:`bit vector `
:term:`bitmap`
+:term:`bitmap marking`
:term:`bitmapped fit`
:term:`bitmask`
:term:`bitset `
diff --git a/mps/manual/source/glossary/m.rst b/mps/manual/source/glossary/m.rst
index db4d8b88a59..92abdcf2740 100644
--- a/mps/manual/source/glossary/m.rst
+++ b/mps/manual/source/glossary/m.rst
@@ -207,7 +207,11 @@ Memory Management Glossary: M
though any conservative representation of a predicate on the
:term:`memory location` of the object can be used. In
particular, storing the mark bit within the object can lead to
- poor :term:`locality of reference`.
+ poor :term:`locality of reference` and to poor cache
+ performance, because the marking phases ends up setting the
+ :term:`dirty bit` on all :term:`pages` in the :term:`working
+ set`. An alternative is to store the mark bits separately:
+ see :term:`bitmap marking`.
.. seealso:: :term:`sweep `, :term:`compact `.
diff --git a/mps/manual/source/glossary/r.rst b/mps/manual/source/glossary/r.rst
index 9f4449a930e..cbab9a255fe 100644
--- a/mps/manual/source/glossary/r.rst
+++ b/mps/manual/source/glossary/r.rst
@@ -39,7 +39,7 @@ Memory Management Glossary: R
.. mps:specific::
A value of :c:type:`mps_rank_t` indicating whether a
- :term:`root` is :term:`ambiguous `
+ :term:`reference` is :term:`ambiguous `
(:c:func:`mps_rank_ambig`), :term:`exact `
(:c:func:`mps_rank_exact`) or :term:`weak `
(:c:func:`mps_rank_weak`).
diff --git a/mps/manual/source/guide/index.rst b/mps/manual/source/guide/index.rst
index a7218dd2ba5..fd98e0481e5 100644
--- a/mps/manual/source/guide/index.rst
+++ b/mps/manual/source/guide/index.rst
@@ -13,4 +13,4 @@ Guide
debug
perf
advanced
-
+ malloc
diff --git a/mps/manual/source/guide/lang.rst b/mps/manual/source/guide/lang.rst
index 68473613ba2..88c7ec93eb5 100644
--- a/mps/manual/source/guide/lang.rst
+++ b/mps/manual/source/guide/lang.rst
@@ -266,6 +266,25 @@ code for creating the object format for the toy Scheme interpreter::
} MPS_ARGS_END(args);
if (res != MPS_RES_OK) error("Couldn't create obj format");
+The keyword arguments specify the :term:`alignment` and the
+:term:`format methods` required by the AMC pool class. These are
+described in the following sections.
+
+.. topics::
+
+ :ref:`topic-format`.
+
+
+.. index::
+ single: alignment
+ single: alignment; object
+ single: Scheme; object alignment
+
+.. _guide-lang-alignment:
+
+Alignment
+^^^^^^^^^
+
The argument for the keyword :c:macro:`MPS_KEY_FMT_ALIGN` is the
:term:`alignment` of objects belonging to this format. Determining the
alignment is hard to do portably, because it depends on the target
@@ -294,13 +313,19 @@ memory. Here are some things you might try:
#define ALIGNMENT sizeof(mps_word_t)
-The other keyword arguments specify the :term:`format methods`
-required by the AMC pool class, which are described in the following
-sections.
+#. The MPS interface provides the type :c:type:`MPS_PF_ALIGN`, which
+ is the :term:`natural alignment` of the platform: the largest
+ alignment that might be required. So as a last resort, you can
+ use::
-.. topics::
+ #define ALIGNMENT MPS_PF_ALIGN
- :ref:`topic-format`.
+ But this may be larger than necessary and so waste space. For
+ example, on Windows on x86-64, :c:type:`MPS_PF_ALIGN` is 16 bytes,
+ but this is only necessary for SSE_ types; ordinary types on this
+ platform require no more than 8-byte alignment.
+
+ .. _SSE: http://msdn.microsoft.com/en-us/library/t467de55.aspx
.. index::
diff --git a/mps/manual/source/guide/malloc.rst b/mps/manual/source/guide/malloc.rst
new file mode 100644
index 00000000000..843fc2371ed
--- /dev/null
+++ b/mps/manual/source/guide/malloc.rst
@@ -0,0 +1,70 @@
+.. index::
+ single: malloc; implementing
+ single: free; implementing
+
+.. _guide-malloc:
+
+Implementing malloc and free
+============================
+
+The MPS function :c:func:`mps_free` is unlike the Standard C Library
+function :c:func:`free` in that it takes a ``size`` argument. That's
+because it's nearly always the case that either the size of a block is
+known statically based on its type (for example, a structure), or else
+the size of the block is easily computed from information that needs
+to be stored anyway (for example, a vector), and so memory can be
+saved by not storing the size separately. It's also better for virtual
+memory performance, as a block does not have to be touched in order
+to free it.
+
+But sometimes you need to interact with :term:`foreign code` which
+requires :c:func:`malloc` and :c:func:`free` (or a pair of functions
+with the same interface). In this situation you can implement this
+interface using a global pool variable, and putting the size of each
+block into its header, like this::
+
+ #include "mps.h"
+
+ static mps_pool_t malloc_pool;
+
+ typedef union {
+ size_t size;
+ char alignment[MPS_PF_ALIGN]; /* see note below */
+ } header_u;
+
+ void *malloc(size_t size) {
+ mps_res_t res;
+ mps_addr_t p;
+ header_u *header;
+ size += sizeof *header;
+ res = mps_alloc(&p, malloc_pool, size);
+ if (res != MPS_RES_OK)
+ return NULL;
+ header = p;
+ header->size = size;
+ return header + 1;
+ }
+
+ void free(void *p) {
+ if (p) {
+ header_u *header = ((header_u *)p) - 1;
+ mps_free(malloc_pool, header, header->size);
+ }
+ }
+
+The ``alignment`` member of ``union header_u`` ensures that
+allocations are aligned to the platform's :term:`natural alignment`
+(see :ref:`guide-lang-alignment`).
+
+The pool needs to belong to a :term:`manually managed ` pool class, for example :ref:`pool-mvff` (or its
+:ref:`debugging counterpart `)::
+
+ #include "mpscmvff.h"
+
+ void malloc_pool_init(mps_arena_t arena) {
+ mps_res_t res;
+ res = mps_pool_create_k(&malloc_pool, arena, mps_class_mvff(), mps_args_none);
+ if (res != RES_OK)
+ abort();
+ }
diff --git a/mps/manual/source/pool/amc.rst b/mps/manual/source/pool/amc.rst
index 0562b9bce5a..a21594202c6 100644
--- a/mps/manual/source/pool/amc.rst
+++ b/mps/manual/source/pool/amc.rst
@@ -115,7 +115,7 @@ AMC interface
method`, a :term:`forward method`, an :term:`is-forwarded
method` and a :term:`padding method`.
- It accepts four optional keyword arguments:
+ It accepts three optional keyword arguments:
* :c:macro:`MPS_KEY_CHAIN` (type :c:type:`mps_chain_t`) specifies
the :term:`generation chain` for the pool. If not specified, the
@@ -128,8 +128,10 @@ AMC interface
pointers` keep objects alive.
* :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`,
- default 4096) is the default :term:`size` of block that the pool
- will request from the :term:`arena`.
+ default 4096) is the minimum :term:`size` of the memory segments
+ that the pool requests from the :term:`arena`. Larger segments
+ reduce the per-segment overhead, but increase
+ :term:`fragmentation` and :term:`retention`.
For example::
@@ -138,20 +140,12 @@ AMC interface
res = mps_pool_create_k(&pool, arena, mps_class_amc(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the format and
- chain like this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_amc(),
- mps_fmt_t fmt,
- mps_chain_t chain)
-
.. index::
pair: AMC; introspection
+.. _pool-amc-introspection:
+
AMC introspection
-----------------
diff --git a/mps/manual/source/pool/amcz.rst b/mps/manual/source/pool/amcz.rst
index 9993647d0db..4f65d205d1b 100644
--- a/mps/manual/source/pool/amcz.rst
+++ b/mps/manual/source/pool/amcz.rst
@@ -87,12 +87,11 @@ AMCZ interface
res = mps_pool_create_k(&pool, arena, mps_class_amcz(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
+
+.. index::
+ pair: AMCZ; introspection
- When using :c:func:`mps_pool_create`, pass the format and
- chain like this::
+AMCZ introspection
+------------------
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_amcz(),
- mps_fmt_t fmt,
- mps_chain_t chain)
+See :ref:`pool-amc-introspection`.
diff --git a/mps/manual/source/pool/ams.rst b/mps/manual/source/pool/ams.rst
index 98da5eda587..4d66fdc0fc3 100644
--- a/mps/manual/source/pool/ams.rst
+++ b/mps/manual/source/pool/ams.rst
@@ -41,7 +41,8 @@ AMS properties
* Supports allocation via :term:`allocation points`. If an allocation
point is created in an AMS pool, the call to
- :c:func:`mps_ap_create_k` takes no keyword arguments.
+ :c:func:`mps_ap_create_k` takes one optional keyword argument,
+ :c:macro:`MPS_KEY_RANK`.
* Supports :term:`allocation frames` but does not use them to improve
the efficiency of stack-like allocation.
@@ -137,19 +138,8 @@ AMS interface
res = mps_pool_create_k(&pool, arena, mps_class_ams(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the format,
- chain, and ambiguous flag like this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_ams(),
- mps_fmt_t fmt,
- mps_chain_t chain,
- mps_bool_t support_ambiguous)
-
When creating an :term:`allocation point` on an AMS pool,
- :c:func:`mps_ap_create_k` accepts 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`, default
:c:func:`mps_rank_exact`) specifies the :term:`rank` of references
@@ -166,13 +156,6 @@ AMS interface
res = mps_ap_create_k(&ap, ams_pool, args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_ap_create`, pass the rank like this::
-
- mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool,
- mps_rank_t rank)
-
.. c:function:: mps_pool_class_t mps_class_ams_debug(void)
@@ -186,15 +169,3 @@ AMS interface
:c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` are as described above,
and :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging
options. See :c:type:`mps_pool_debug_option_s`.
-
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the arguments like
- this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_ams_debug(),
- mps_pool_debug_option_s debug_option,
- mps_fmt_t fmt,
- mps_chain_t chain,
- mps_bool_t support_ambiguous)
diff --git a/mps/manual/source/pool/awl.rst b/mps/manual/source/pool/awl.rst
index e4437ebe5ee..63eca08635e 100644
--- a/mps/manual/source/pool/awl.rst
+++ b/mps/manual/source/pool/awl.rst
@@ -59,7 +59,7 @@ AWL properties
* Supports allocation via :term:`allocation points`. If an allocation
point is created in an AWL pool, the call to
- :c:func:`mps_ap_create_k` accepts one keyword argument,
+ :c:func:`mps_ap_create_k` accepts one optional keyword argument,
:c:macro:`MPS_KEY_RANK`.
* Supports :term:`allocation frames` but does not use them to improve
@@ -350,18 +350,8 @@ AWL interface
res = mps_pool_create_k(&pool, arena, mps_class_awl(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the format and
- find-dependent function like this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_awl(),
- mps_fmt_t fmt,
- mps_awl_find_dependent_t find_dependent)
-
When creating an :term:`allocation point` on an AWL pool,
- :c:func:`mps_ap_create_k` accepts 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`, default
:c:func:`mps_rank_exact`) specifies the :term:`rank` of
@@ -378,13 +368,6 @@ AWL interface
res = mps_ap_create_k(&ap, awl_pool, args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_ap_create`, pass the rank like this::
-
- mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool,
- mps_rank_t rank)
-
.. c:type:: mps_addr_t (*mps_awl_find_dependent_t)(mps_addr_t addr)
diff --git a/mps/manual/source/pool/lo.rst b/mps/manual/source/pool/lo.rst
index edd784c1fe5..197e8b57138 100644
--- a/mps/manual/source/pool/lo.rst
+++ b/mps/manual/source/pool/lo.rst
@@ -136,12 +136,3 @@ LO interface
MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt);
res = mps_pool_create_k(&pool, arena, mps_class_lo(), args);
} MPS_ARGS_END(args);
-
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the format like
- this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_lo(),
- mps_fmt_t fmt)
diff --git a/mps/manual/source/pool/mfs.rst b/mps/manual/source/pool/mfs.rst
index c4501d05c54..c1e13a5479d 100644
--- a/mps/manual/source/pool/mfs.rst
+++ b/mps/manual/source/pool/mfs.rst
@@ -87,7 +87,8 @@ MFS interface
:term:`size` of blocks that will be allocated from this pool, in
:term:`bytes (1)`. It must be at least one :term:`word`.
- In addition, :c:func:`mps_pool_create_k` may take:
+ In addition, :c:func:`mps_pool_create_k` accepts one optional
+ keyword argument:
* :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`,
default 65536) is the :term:`size` of block that the pool will
@@ -103,13 +104,3 @@ MFS interface
MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, 1024 * 1024);
res = mps_pool_create_k(&pool, arena, mps_class_mfs(), args);
} MPS_ARGS_END(args);
-
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the block size and
- unit size like this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_mfs(),
- size_t extend_size,
- size_t unit_size)
diff --git a/mps/manual/source/pool/mv.rst b/mps/manual/source/pool/mv.rst
index 8561e96d7d1..27e691ed3af 100644
--- a/mps/manual/source/pool/mv.rst
+++ b/mps/manual/source/pool/mv.rst
@@ -7,10 +7,6 @@
MV (Manual Variable)
====================
-.. deprecated:: starting with version 1.111.
-
- :ref:`pool-mvff` or :ref:`pool-mvt` should be used instead.
-
**MV** is a general-purpose :term:`manually managed ` :term:`pool class` that manages :term:`blocks` of
variable size.
@@ -70,8 +66,8 @@ MV interface
Return the :term:`pool class` for an MV (Manual Variable)
:term:`pool`.
- When creating an MV pool, :c:func:`mps_pool_create_k` may take
- the following :term:`keyword arguments`:
+ When creating an MV pool, :c:func:`mps_pool_create_k` takes four
+ optional :term:`keyword arguments`:
* :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is
:c:macro:`MPS_PF_ALIGN`) is the
@@ -105,17 +101,6 @@ MV interface
res = mps_pool_create_k(&pool, arena, mps_class_mfs(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the block size,
- mean size, and maximum size like this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_mv(),
- size_t extend_size,
- size_t average_size,
- mps_size_t maximum_size)
-
.. c:function:: mps_pool_class_t mps_class_mv_debug(void)
@@ -123,49 +108,8 @@ MV interface
class.
When creating a debugging MV pool, :c:func:`mps_pool_create_k`
- takes the following keyword arguments: :c:macro:`MPS_KEY_ALIGN`,
+ takes five optional keyword arguments: :c:macro:`MPS_KEY_ALIGN`,
:c:macro:`MPS_KEY_EXTEND_SIZE`, :c:macro:`MPS_KEY_MEAN_SIZE`,
:c:macro:`MPS_KEY_MAX_SIZE` are as described above, and
:c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging
- options. See :c:type:`mps_debug_option_s`.
-
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the arguments like
- this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_mv_debug(),
- mps_pool_debug_option_s debug_option,
- mps_size_t extend_size,
- mps_size_t average_size,
- mps_size_t maximum_size)
-
-
-.. index::
- pair: MV; introspection
-
-MV introspection
-----------------
-
-::
-
- #include "mpscmv.h"
-
-.. c:function:: size_t mps_mv_free_size(mps_pool_t pool)
-
- Return the total amount of free space in an MV pool.
-
- ``pool`` is the MV pool.
-
- Returns the total free space in the pool, in :term:`bytes (1)`.
-
-
-.. c:function:: size_t mps_mv_size(mps_pool_t pool)
-
- Return the total size of an MV pool.
-
- ``pool`` is the MV pool.
-
- Returns the total size of the pool, in :term:`bytes (1)`. This
- is the sum of allocated space and free space.
+ options. See :c:type:`mps_pool_debug_option_s`.
diff --git a/mps/manual/source/pool/mvff.rst b/mps/manual/source/pool/mvff.rst
index 51252208719..04a7d48603d 100644
--- a/mps/manual/source/pool/mvff.rst
+++ b/mps/manual/source/pool/mvff.rst
@@ -102,8 +102,8 @@ MVFF interface
Return the :term:`pool class` for an MVFF (Manual Variable First
Fit) :term:`pool`.
- When creating an MVFF pool, :c:func:`mps_pool_create_k` may take
- the following :term:`keyword arguments`:
+ When creating an MVFF pool, :c:func:`mps_pool_create_k` accepts
+ seven optional :term:`keyword arguments`:
* :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default
65536) is the :term:`size` of block that the pool will request
@@ -132,15 +132,15 @@ MVFF interface
default false) determines whether new blocks are acquired at high
addresses (if true), or at low addresses (if false).
- * :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` [#not-ap]_ (type :c:type:`mps_bool_t`,
- default false) determines whether to search for the highest
- addressed free area (if true) or lowest (if false) when allocating
- using :c:func:`mps_alloc`.
+ * :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` [#not-ap]_ (type
+ :c:type:`mps_bool_t`, default false) determines whether to
+ search for the highest addressed free area (if true) or lowest
+ (if false) when allocating using :c:func:`mps_alloc`.
- * :c:macro:`MPS_KEY_MVFF_FIRST_FIT` [#not-ap]_ (type :c:type:`mps_bool_t`, default
- true) determines whether to allocate from the highest address in a
- found free area (if true) or lowest (if false) when allocating
- using :c:func:`mps_alloc`.
+ * :c:macro:`MPS_KEY_MVFF_FIRST_FIT` [#not-ap]_ (type
+ :c:type:`mps_bool_t`, default true) determines whether to
+ allocate from the highest address in a found free area (if true)
+ or lowest (if false) when allocating using :c:func:`mps_alloc`.
.. [#not-ap]
@@ -150,12 +150,12 @@ MVFF interface
They use a worst-fit policy in order to maximise the number of
in-line allocations.
- The defaults yield a a simple first-fit allocator. Specify
+ The defaults yield a a simple first-fit allocator. Specify
:c:macro:`MPS_KEY_MVFF_ARENA_HIGH` and
:c:macro:`MPS_KEY_MVFF_SLOT_HIGH` true, and
:c:macro:`MPS_KEY_MVFF_FIRST_FIT` false to get a first-fit
- allocator that works from the top of memory downwards.
- Other combinations may be useful in special circumstances.
+ allocator that works from the top of memory downwards. Other
+ combinations may be useful in special circumstances.
For example::
@@ -169,20 +169,6 @@ MVFF interface
res = mps_pool_create_k(&pool, arena, mps_class_mvff(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the arguments like
- this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_mvff(),
- size_t extend_size,
- size_t average_size,
- mps_align_t alignment,
- mps_bool_t slot_high,
- mps_bool_t arena_high,
- mps_bool_t first_fit)
-
.. c:function:: mps_pool_class_t mps_class_mvff_debug(void)
@@ -190,55 +176,11 @@ MVFF interface
class.
When creating a debugging MVFF pool, :c:func:`mps_pool_create_k`
- takes seven :term:`keyword arguments`.
-
- * :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE`,
- :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_MVFF_ARENA_HIGH`,
- :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, and
- :c:macro:`MPS_KEY_MVFF_FIRST_FIT` are as described above, and
- :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging
- options. See :c:type:`mps_pool_debug_option_s`.
-
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the arguments like
- this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_mvff_debug(),
- mps_pool_debug_option_s debug_option,
- size_t extend_size,
- size_t average_size,
- mps_align_t alignment,
- mps_bool_t slot_high,
- mps_bool_t arena_high,
- mps_bool_t first_fit)
-
-
-.. index::
- pair: MVFF; introspection
-
-MVFF introspection
-------------------
-
-::
-
- #include "mpscmvff.h"
-
-.. c:function:: size_t mps_mvff_free_size(mps_pool_t pool)
-
- Return the total amount of free space in an MVFF pool.
-
- ``pool`` is the MVFF pool.
-
- Returns the total free space in the pool, in :term:`bytes (1)`.
-
-
-.. c:function:: size_t mps_mvff_size(mps_pool_t pool)
-
- Return the total size of an MVFF pool.
-
- ``pool`` is the MVFF pool.
-
- Returns the total size of the pool, in :term:`bytes (1)`. This
- is the sum of allocated space and free space.
+ accepts eight optional :term:`keyword arguments`:
+ :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE`,
+ :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_SPARE`,
+ :c:macro:`MPS_KEY_MVFF_ARENA_HIGH`,
+ :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, and
+ :c:macro:`MPS_KEY_MVFF_FIRST_FIT` are as described above, and
+ :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging
+ options. See :c:type:`mps_pool_debug_option_s`.
diff --git a/mps/manual/source/pool/mvt.rst b/mps/manual/source/pool/mvt.rst
index 18e738413b9..da2ce024baa 100644
--- a/mps/manual/source/pool/mvt.rst
+++ b/mps/manual/source/pool/mvt.rst
@@ -111,8 +111,8 @@ MVT interface
Return the :term:`pool class` for an MVT (Manual Variable
Temporal) :term:`pool`.
- When creating an MVT pool, :c:func:`mps_pool_create_k` may take
- six :term:`keyword arguments`:
+ When creating an MVT pool, :c:func:`mps_pool_create_k` accepts six
+ optional :term:`keyword arguments`:
* :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is
:c:macro:`MPS_PF_ALIGN`) is the
@@ -196,51 +196,3 @@ MVT interface
MPS_ARGS_ADD(args, MPS_KEY_MVT_FRAG_LIMIT, 0.5);
res = mps_pool_create_k(&pool, arena, mps_class_mvt(), args);
} MPS_ARGS_END(args);
-
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the arguments like
- this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_mvt(),
- size_t minimum_size,
- size_t mean_size,
- size_t maximum_size,
- mps_word_t reserve_depth,
- mps_word_t fragmentation_limit)
-
- .. note::
-
- The fragmentation_limit is a percentage from 0 to 100
- inclusive when passed to :c:func:`mps_pool_create`, not a
- double from 0.0 to 1.0 as in :c:func:`mps_pool_create_k`.
-
-
-.. index::
- pair: MVT; introspection
-
-MVT introspection
------------------
-
-::
-
- #include "mpscmvt.h"
-
-.. c:function:: size_t mps_mvt_free_size(mps_pool_t pool)
-
- Return the total amount of free space in an MVT pool.
-
- ``pool`` is the MVT pool.
-
- Returns the total free space in the pool, in :term:`bytes (1)`.
-
-
-.. c:function:: size_t mps_mvt_size(mps_pool_t pool)
-
- Return the total size of an MVT pool.
-
- ``pool`` is the MVT pool.
-
- Returns the total size of the pool, in :term:`bytes (1)`. This
- is the sum of allocated space and free space.
diff --git a/mps/manual/source/pool/snc.rst b/mps/manual/source/pool/snc.rst
index 2e82d055e7c..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`.
@@ -83,8 +83,8 @@ SNC properties
.. index::
single: SNC; interface
-SNC introspection
------------------
+SNC interface
+-------------
::
@@ -111,21 +111,12 @@ SNC introspection
res = mps_pool_create_k(&pool, arena, mps_class_snc(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_pool_create`, pass the format like
- this::
-
- mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
- mps_pool_class_t mps_class_snc(),
- mps_fmt_t fmt)
-
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::
@@ -133,10 +124,3 @@ SNC introspection
MPS_ARGS_ADD(args, MPS_KEY_RANK, mps_rank_exact());
res = mps_ap_create_k(&ap, awl_pool, args);
} MPS_ARGS_END(args);
-
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_ap_create`, pass the rank like this::
-
- mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool,
- mps_rank_t rank)
diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst
index fc9cc438c55..cb820397281 100644
--- a/mps/manual/source/release.rst
+++ b/mps/manual/source/release.rst
@@ -9,6 +9,15 @@ Release notes
Release 1.115.0
---------------
+New features
+............
+
+#. When creating an :ref:`pool-amc` pool, :c:func:`mps_pool_create_k`
+ accepts the new keyword argument :c:macro:`MPS_KEY_EXTEND_BY`,
+ specifying the minimum size of the memory segments that the pool
+ requests from the :term:`arena`.
+
+
Interface changes
.................
@@ -16,6 +25,46 @@ Interface changes
name :c:type:`mps_class_t` is still available via a ``typedef``,
but is deprecated.
+#. The functions :c:func:`mps_mv_free_size`, :c:func:`mps_mv_size`,
+ :c:func:`mps_mvff_free_size`, :c:func:`mps_mvff_size`,
+ :c:func:`mps_mvt_free_size` and :c:func:`mps_mvt_size` are now
+ deprecated in favour of the generic functions
+ :c:func:`mps_pool_free_size` and :c:func:`mps_pool_total_size`.
+
+
+Other changes
+.............
+
+#. :c:func:`mps_arena_committed` now returns a meaningful value (the
+ amount of memory marked as in use in the page tables) for
+ :term:`client arenas`. See job001887_.
+
+ .. _job001887: https://www.ravenbrook.com/project/mps/issue/job001887/
+
+#. :ref:`pool-amc` pools now assert that exact references into the
+ pool are aligned to the pool's alignment. See job002175_.
+
+ .. _job002175: https://www.ravenbrook.com/project/mps/issue/job002175/
+
+#. Internal calculation of the address space available to the MPS no
+ longer takes time proportional to the number of times the arena has
+ been extended, speeding up allocation when memory is tight. See
+ job003814_.
+
+ .. _job003814: https://www.ravenbrook.com/project/mps/issue/job003814/
+
+#. Setting :c:macro:`MPS_KEY_SPARE` for a :ref:`pool-mvff` pool now
+ works. See job003870_.
+
+ .. _job003870: https://www.ravenbrook.com/project/mps/issue/job003870/
+
+#. When the arena is out of memory and cannot be extended without
+ hitting the :term:`commit limit`, the MPS now returns
+ :c:macro:`MPS_RES_COMMIT_LIMIT` rather than substituting
+ :c:macro:`MPS_RES_RESOURCE`. See job003899_.
+
+ .. _job003899: https://www.ravenbrook.com/project/mps/issue/job003899/
+
.. _release-notes-1.114:
@@ -57,8 +106,8 @@ New features
generation sizes. (This is not necessary, but may improve
performance.)
-#. New pool introspection functions :c:func:`mps_pool_total_size` and
- :c:func:`mps_pool_free_size`.
+#. New pool introspection functions :c:func:`mps_pool_free_size` and
+ :c:func:`mps_pool_total_size`.
Interface changes
@@ -147,8 +196,8 @@ Other changes
#. Allocation into :ref:`pool-awl` pools again reliably provokes
garbage collections of the generation that the pool belongs to. (In
- release 1.113.0, the generation would only be collected if a pool
- of some other class allocated into it.) See job003772_.
+ version 1.113, the generation would only be collected if a pool of
+ some other class allocated into it.) See job003772_.
.. _job003772: https://www.ravenbrook.com/project/mps/issue/job003772/
@@ -160,13 +209,21 @@ Other changes
.. _job003773: https://www.ravenbrook.com/project/mps/issue/job003773/
#. The :ref:`pool-mvt` and :ref:`pool-mvff` pool classes are now
- around 25% faster (in our benchmarks) than they were in release
- 1.113.0.
+ around 25% faster (in our benchmarks) than they were in version
+ 1.113.
-#. The default assertion handler in the ANSI plinth now flushes the
- telemetry stream before aborting. See
+#. The default assertion handler in the default :term:`plinth` now
+ flushes the telemetry stream before aborting. See
:c:func:`mps_lib_assert_fail`.
+#. Garbage collection performance is substantially improved in the
+ 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_.
+
+ .. _job003554: https://www.ravenbrook.com/project/mps/issue/job003554/
+
.. _release-notes-1.113:
@@ -278,8 +335,8 @@ Interface changes
along indefinitely. See :ref:`topic-error-assertion-handling`.
#. The behaviour when an assertion is triggered is now configurable in
- the standard ANSI :term:`plinth` by installing an assertion
- handler. See :c:func:`mps_lib_assert_fail_install`.
+ the default :term:`plinth` by installing an assertion handler. See
+ :c:func:`mps_lib_assert_fail_install`.
#. Functions that take a variable number of arguments
(:c:func:`mps_arena_create`, :c:func:`mps_pool_create`,
@@ -437,3 +494,74 @@ Other changes
later. See job003473_.
.. _job003473: https://www.ravenbrook.com/project/mps/issue/job003473/
+
+
+.. _release-notes-1.110:
+
+Release 1.110.0
+---------------
+
+New features
+............
+
+#. New supported platforms:
+
+ * ``fri6gc`` (FreeBSD, x86-64, GCC)
+ * ``lii6gc`` (Linux, x86-64, GCC)
+ * ``w3i6mv`` (Windows, x86-64, Microsoft Visual C)
+ * ``xci3ll`` (OS X, IA-32, Clang/LLVM)
+ * ``xci6gc`` (OS X, x86-64, GCC)
+ * ``xci6ll`` (OS X, x86-64, Clang/LLVM)
+
+#. Support removed for platforms:
+
+ * ``iam4cc`` (Irix 6, MIPS R4000, MIPSpro C)
+ * ``lii3eg`` (Linux, IA-32, EGCS)
+ * ``lippgc`` (Linux, PowerPC, GCC)
+ * ``o1alcc`` (OSF/1, Alpha, Digital C)
+ * ``o1algc`` (OSF/1, Alpha, GCC)
+ * ``s7ppmw`` (System 7, PowerPC, MetroWerks C)
+ * ``sos8gc`` (Solaris, SPARC 8, GCC)
+ * ``sos9sc`` (Solaris, SPARC 9, SunPro C)
+ * ``sus8gc`` (SunOS, SPARC 8, GCC)
+ * ``xcppgc`` (OS X, PowerPC, GCC)
+
+#. On Unix platforms, the MPS can now be built and installed by
+ running ``./configure && make install``. See :ref:`guide-build`.
+
+#. The MPS can be compiled in a single step via the new source file
+ ``mps.c``. This also allows you to compile the MPS in the same
+ compilation unit as your object format, allowing the compiler to
+ perform global optimizations between the two. See
+ :ref:`guide-build`.
+
+#. The set of build varieties has been reduced to three: the
+ :term:`cool` variety for development and debugging, the :term:`hot`
+ variety for production, and the :term:`rash` variety for people who
+ like to live dangerously. See :ref:`topic-error-variety`.
+
+#. The environment variable :envvar:`MPS_TELEMETRY_CONTROL` can now be
+ set to a space-separated list of event kinds. See
+ :ref:`topic-telemetry`.
+
+#. Telemetry output is now emitted to the file named by the
+ environment variable :envvar:`MPS_TELEMETRY_FILENAME`, if it is
+ set. See :ref:`topic-telemetry`.
+
+
+Interface changes
+.................
+
+#. Deprecated constants ``MPS_MESSAGE_TYPE_FINALIZATION``,
+ ``MPS_MESSAGE_TYPE_GC`` and ``MPS_MESSAGE_TYPE_GC_START`` have been
+ removed. Use :c:func:`mps_message_type_finalization`,
+ :c:func:`mps_message_type_gc` and
+ :c:func:`mps_message_type_gc_start` instead.
+
+#. Deprecated constants ``MPS_RANK_AMBIG``, ``MPS_RANK_EXACT`` and
+ ``MPS_RANK_WEAK`` have been removed. Use :c:func:`mps_rank_ambig`,
+ :c:func:`mps_rank_exact` and :c:func:`mps_rank_weak` instead.
+
+#. Deprecated functions with names starting ``mps_space_`` have been
+ removed. Use the functions with names starting ``mps_arena_``
+ instead.
diff --git a/mps/manual/source/topic/allocation.rst b/mps/manual/source/topic/allocation.rst
index 57e9c0d6548..4075cfe006a 100644
--- a/mps/manual/source/topic/allocation.rst
+++ b/mps/manual/source/topic/allocation.rst
@@ -120,31 +120,6 @@ many small objects. They must be used according to the
point or points.
-.. c:function:: mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, ...)
-
- .. deprecated:: starting with version 1.112.
-
- Use :c:func:`mps_ap_create_k` instead: the :term:`keyword
- arguments` interface is more reliable and produces better
- error messages.
-
- An alternative to :c:func:`mps_ap_create_k` that takes its extra
- arguments using the standard :term:`C` variable argument list
- mechanism.
-
-
-.. c:function:: mps_res_t mps_ap_create_v(mps_ap_t *ap_o, mps_pool_t pool, va_list args)
-
- .. deprecated:: starting with version 1.112.
-
- Use :c:func:`mps_ap_create_k` instead: the :term:`keyword
- arguments` interface is more reliable and produces better
- error messages.
-
- An alternative to :c:func:`mps_ap_create_k` that takes its extra
- arguments using the standard :term:`C` ``va_list`` mechanism.
-
-
.. c:function:: void mps_ap_destroy(mps_ap_t ap)
Destroy an :term:`allocation point`.
@@ -240,7 +215,8 @@ is thus::
size_t aligned_size = ALIGN(size); /* see note 1 */
do {
mps_res_t res = mps_reserve(&p, ap, aligned_size);
- if (res != MPS_RES_OK) /* handle the error */;
+ if (res != MPS_RES_OK)
+ /* handle the error */;
/* p is now an ambiguous reference to the reserved block */
obj = p;
/* initialize obj */
diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst
index 04c537a79de..d33242e279d 100644
--- a/mps/manual/source/topic/arena.rst
+++ b/mps/manual/source/topic/arena.rst
@@ -92,32 +92,6 @@ the way that they acquire the memory to be managed.
:c:func:`mps_arena_destroy`.
-.. c:function:: mps_res_t mps_arena_create(mps_arena_t *arena_o, mps_arena_class_t arena_class, ...)
-
- .. deprecated:: starting with version 1.112.
-
- Use :c:func:`mps_arena_create_k` instead: the :term:`keyword
- arguments` interface is more reliable and produces better
- error messages.
-
- An alternative to :c:func:`mps_arena_create_k` that takes its
- extra arguments using the standard :term:`C` variable argument
- list mechanism.
-
-
-.. c:function:: mps_res_t mps_arena_create_v(mps_arena_t *arena_o, mps_arena_class_t arena_class, va_list args)
-
- .. deprecated:: starting with version 1.112.
-
- Use :c:func:`mps_arena_create_k` instead: the :term:`keyword
- arguments` interface is more reliable and produces better
- error messages.
-
- An alternative to :c:func:`mps_arena_create_k` that takes its
- extra arguments using the standard :term:`C` ``va_list``
- mechanism.
-
-
.. c:function:: void mps_arena_destroy(mps_arena_t arena)
Destroy an :term:`arena`.
@@ -192,15 +166,6 @@ Client arenas
Client arenas have no mechanism for returning unused memory.
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_arena_create`, pass the size and base
- address like this::
-
- mps_res_t mps_arena_create(mps_arena_t *arena_o,
- mps_arena_class_t mps_arena_class_cl,
- size_t size, mps_addr_t base)
-
.. c:function:: mps_res_t mps_arena_extend(mps_arena_t arena, mps_addr_t base, size_t size)
@@ -311,15 +276,6 @@ Virtual memory arenas
res = mps_arena_create_k(&arena, mps_arena_class_vm(), args);
} MPS_ARGS_END(args);
- .. deprecated:: starting with version 1.112.
-
- When using :c:func:`mps_arena_create`, pass the size like
- this::
-
- mps_res_t mps_arena_create(mps_arena_t *arena_o,
- mps_arena_class_t arena_class_vm(),
- size_t size)
-
.. index::
single: arena; properties
@@ -391,9 +347,18 @@ Arena properties
``arena`` is the arena.
- Returns the total amount of memory that has been committed to RAM
+ Returns the total amount of memory that has been committed for use
by the MPS, in :term:`bytes (1)`.
+ For a :term:`virtual memory arena`, this is the amount of memory
+ mapped to RAM by the operating system's virtual memory interface.
+
+ For a :term:`client arena`, this is the amount of memory marked as
+ in use in the arena's page tables. This is not particularly
+ meaningful by itself, but it corresponds to the amount of mapped
+ memory that the MPS would use if switched to a virtual memory
+ arena.
+
The committed memory is generally larger than the sum of the sizes
of the allocated :term:`blocks`. The reasons for this are:
@@ -420,10 +385,10 @@ Arena properties
state>`). If it is called when the arena is in the unclamped state
then the value may change after this function returns. A possible
use might be to call it just after :c:func:`mps_arena_collect` to
- (over-)estimate the size of the heap.
+ estimate the size of the heap.
If you want to know how much memory the MPS is using then you're
- probably interested in the value :c:func:`mps_arena_committed()` −
+ probably interested in the value :c:func:`mps_arena_committed` −
:c:func:`mps_arena_spare_committed`.
The amount of committed memory can be limited with the function
@@ -447,12 +412,12 @@ Arena properties
.. note::
- For a client arena, the reserved address may be lower than the
- sum of the :c:macro:`MPS_KEY_ARENA_SIZE` keyword argument
- passed to :c:func:`mps_arena_create_k` and the ``size``
- arguments passed to :c:func:`mps_arena_extend`, because the
- arena may be unable to use the whole of each chunk for reasons
- of alignment.
+ For a :term:`client arena`, the reserved address space may be
+ lower than the sum of the :c:macro:`MPS_KEY_ARENA_SIZE`
+ keyword argument passed to :c:func:`mps_arena_create_k` and
+ the ``size`` arguments passed to :c:func:`mps_arena_extend`,
+ because the arena may be unable to use the whole of each chunk
+ for reasons of alignment.
.. c:function:: size_t mps_arena_spare_commit_limit(mps_arena_t arena)
@@ -517,6 +482,11 @@ Arena properties
functions for limiting the amount of :term:`committed `
memory.
+ .. note::
+
+ :term:`Client arenas` do not use spare committed memory, and
+ so this function always returns 0.
+
.. index::
single: arena; states
@@ -839,114 +809,3 @@ Arena introspection
return storage to the operating system). For reliable results
call this function and interpret the result while the arena is
in the :term:`parked state`.
-
-
-.. index::
- pair: arena; protection
-
-Protection interface
---------------------
-
-.. c:function:: void mps_arena_expose(mps_arena_t arena)
-
- .. deprecated:: starting with version 1.111.
-
- Ensure that the MPS is not protecting any :term:`page` in the
- :term:`arena` with a :term:`read barrier` or :term:`write
- barrier`.
-
- ``mps_arena`` is the arena to expose.
-
- This is expected to only be useful for debugging. The arena is
- left in the :term:`clamped state`.
-
- Since barriers are used during a collection, calling this function
- has the same effect as calling :c:func:`mps_arena_park`: all
- collections are run to completion, and the arena is clamped so
- that no new collections begin. The MPS also uses barriers to
- maintain :term:`remembered sets`, so calling this
- function will effectively destroy the remembered sets and any
- optimization gains from them.
-
- Calling this function is time-consuming: any active collections
- will be run to completion; and the next collection will have to
- recompute all the remembered sets by scanning the entire arena.
-
- The recomputation of the remembered sets can be avoided by calling
- :c:func:`mps_arena_unsafe_expose_remember_protection` instead of
- :c:func:`mps_arena_expose`, and by calling
- :c:func:`mps_arena_unsafe_restore_protection` before calling
- :c:func:`mps_arena_release`. Those functions have unsafe aspects
- and place restrictions on what the :term:`client program` can do
- (basically no exposed data can be changed).
-
-
-.. c:function:: void mps_arena_unsafe_expose_remember_protection(mps_arena_t arena)
-
- .. deprecated:: starting with version 1.111.
-
- Ensure that the MPS is not protecting any :term:`page` in the
- :term:`arena` with a :term:`read barrier` or :term:`write
- barrier`. In addition, request the MPS to remember some parts of its
- internal state so that they can be restored later.
-
- ``mps_arena`` is the arena to expose.
-
- This function is the same as :c:func:`mps_arena_expose`, but
- additionally causes the MPS to remember its protection state. The
- remembered protection state can optionally be restored later by
- calling the :c:func:`mps_arena_unsafe_restore_protection` function.
- This is an optimization that avoids the MPS having to recompute
- all the remembered sets by scanning the entire arena.
-
- However, restoring the remembered protections is only safe if the
- contents of the exposed pages have not been changed; therefore
- this function should only be used if you do not intend to change
- the pages, and the remembered protection must only be restored if
- the pages have not been changed.
-
- The MPS will only remember the protection state if resources
- (memory) are available. If memory is low then only some or
- possibly none of the protection state will be remembered, with a
- corresponding necessity to recompute it later. The MPS provides no
- mechanism for the :term:`client program` to determine whether the
- MPS has in fact remembered the protection state.
-
- The remembered protection state, if any, is discarded after
- calling :c:func:`mps_arena_unsafe_restore_protection`, or as soon
- as the arena leaves the :term:`clamped state` by calling
- :c:func:`mps_arena_release`.
-
-
-.. c:function:: void mps_arena_unsafe_restore_protection(mps_arena_t arena)
-
- .. deprecated:: starting with version 1.111.
-
- Restore the remembered protection state for an :term:`arena`.
-
- ``mps_arena`` is the arena to restore the protection state for.
-
- This function restores the protection state that the MPS has
- remembered when the :term:`client program` called
- :c:func:`mps_arena_unsafe_expose_remember_protection`. The purpose
- of remembering and restoring the protection state is to avoid the
- need for the MPS to recompute all the :term:`remembered sets` by scanning the entire arena, that occurs when
- :c:func:`mps_arena_expose` is used, and which causes the next
- :term:`garbage collection` to be slow.
-
- The client program must not change the exposed data between the
- call to :c:func:`mps_arena_unsafe_expose_remember_protection` and
- :c:func:`mps_arena_unsafe_restore_protection`. If the client
- program has changed the exposed data then
- :c:func:`mps_arena_unsafe_restore_protection` must not be called:
- in this case simply call :c:func:`mps_arena_release`.
-
- Calling this function does not release the arena from the clamped
- state: :c:func:`mps_arena_release` must be called to continue
- normal collections.
-
- Calling this function causes the MPS to forget the remember
- protection state; as a consequence the same remembered state
- cannot be restored more than once.
-
-
diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst
new file mode 100644
index 00000000000..dfd4d8d74cb
--- /dev/null
+++ b/mps/manual/source/topic/deprecated.rst
@@ -0,0 +1,745 @@
+.. index::
+ single: deprecated interfaces
+
+.. _topic-deprecated:
+
+Deprecated interfaces
+=====================
+
+This chapter documents the public symbols in the MPS interface that
+are now deprecated. These symbols may be removed in any future release
+(see :ref:`topic-interface-support` for details). If you are using one
+of these symbols, then you should update your code to use the
+supported interface.
+
+.. note::
+
+ If you are relying on a deprecated interface, and there is no
+ supported alternative, please :ref:`contact us `. It
+ makes a difference if we know that someone is using a feature.
+
+
+.. index::
+ single: deprecated interfaces; in version 1.115
+
+Deprecated in version 1.115
+...........................
+
+.. c:type:: typedef mps_pool_class_t mps_class_t
+
+ .. deprecated::
+
+ The former name for :c:type:`mps_pool_class_t`, chosen when
+ pools were the only objects in the MPS that belonged to
+ classes.
+
+
+.. c:function:: size_t mps_mv_free_size(mps_pool_t pool)
+
+ .. deprecated::
+
+ Use the generic function :c:func:`mps_pool_free_size` instead.
+
+ Return the total amount of free space in an MV pool.
+
+ ``pool`` is the MV pool.
+
+ Returns the total free space in the pool, in :term:`bytes (1)`.
+
+
+.. c:function:: size_t mps_mv_size(mps_pool_t pool)
+
+ .. deprecated::
+
+ Use the generic function :c:func:`mps_pool_total_size`
+ instead.
+
+ Return the total size of an MV pool.
+
+ ``pool`` is the MV pool.
+
+ Returns the total size of the pool, in :term:`bytes (1)`. This
+ is the sum of allocated space and free space.
+
+
+.. c:function:: size_t mps_mvff_free_size(mps_pool_t pool)
+
+ .. deprecated::
+
+ Use the generic function :c:func:`mps_pool_free_size` instead.
+
+ Return the total amount of free space in an MVFF pool.
+
+ ``pool`` is the MVFF pool.
+
+ Returns the total free space in the pool, in :term:`bytes (1)`.
+
+
+.. c:function:: size_t mps_mvff_size(mps_pool_t pool)
+
+ .. deprecated::
+
+ Use the generic function :c:func:`mps_pool_total_size`
+ instead.
+
+ Return the total size of an MVFF pool.
+
+ ``pool`` is the MVFF pool.
+
+ Returns the total size of the pool, in :term:`bytes (1)`. This
+ is the sum of allocated space and free space.
+
+
+.. c:function:: size_t mps_mvt_free_size(mps_pool_t pool)
+
+ .. deprecated::
+
+ Use the generic function :c:func:`mps_pool_free_size` instead.
+
+ Return the total amount of free space in an MVT pool.
+
+ ``pool`` is the MVT pool.
+
+ Returns the total free space in the pool, in :term:`bytes (1)`.
+
+
+.. c:function:: size_t mps_mvt_size(mps_pool_t pool)
+
+ .. deprecated::
+
+ Use the generic function :c:func:`mps_pool_total_size`
+ instead.
+
+ Return the total size of an MVT pool.
+
+ ``pool`` is the MVT pool.
+
+ Returns the total size of the pool, in :term:`bytes (1)`. This
+ is the sum of allocated space and free space.
+
+
+.. index::
+ single: deprecated interfaces; in version 1.113
+
+Deprecated in version 1.113
+...........................
+
+.. c:function:: MPS_ARGS_DONE(args)
+
+ .. deprecated::
+
+ Formerly this was used to finalize a list of :term:`keyword
+ arguments` before passing it to a function. It is no longer
+ needed.
+
+
+.. index::
+ single: deprecated interfaces; in version 1.112
+
+Deprecated in version 1.112
+...........................
+
+.. c:function:: mps_res_t mps_arena_create(mps_arena_t *arena_o, mps_arena_class_t arena_class, ...)
+
+ .. deprecated::
+
+ Use :c:func:`mps_arena_create_k` instead.
+
+ An alternative to :c:func:`mps_arena_create_k` that takes its
+ extra arguments using the standard :term:`C` variable argument
+ list mechanism.
+
+ When creating an arena of class :c:func:`mps_arena_class_cl`, pass
+ the values for the keyword arguments :c:macro:`MPS_KEY_ARENA_SIZE`
+ and :c:macro:`MPS_KEY_ARENA_CL_BASE` like this::
+
+ mps_res_t mps_arena_create(mps_arena_t *arena_o,
+ mps_arena_class_t mps_arena_class_cl(),
+ size_t arena_size,
+ mps_addr_t cl_base)
+
+ When creating an arena of class :c:func:`mps_arena_class_vm`, pass
+ the value for the keyword argument :c:macro:`MPS_KEY_ARENA_SIZE`
+ like this::
+
+ mps_res_t mps_arena_create(mps_arena_t *arena_o,
+ mps_arena_class_t mps_arena_class_vm(),
+ size_t arena_size)
+
+
+.. c:function:: mps_res_t mps_arena_create_v(mps_arena_t *arena_o, mps_arena_class_t arena_class, va_list args)
+
+ .. deprecated::
+
+ Use :c:func:`mps_arena_create_k` instead.
+
+ An alternative to :c:func:`mps_arena_create_k` that takes its
+ extra arguments using the standard :term:`C` ``va_list``
+ mechanism. See :c:func:`mps_arena_create` for details of which
+ arguments to pass for the different arena classes.
+
+
+.. c:function:: mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, ...)
+
+ .. deprecated::
+
+ Use :c:func:`mps_pool_create_k` instead.
+
+ An alternative to :c:func:`mps_pool_create_k` that takes its
+ extra arguments using the standard :term:`C` variable argument
+ list mechanism.
+
+ When creating a pool of class :c:func:`mps_class_amc` or
+ :c:func:`mps_class_amcz`, pass the values for the keyword
+ arguments :c:macro:`MPS_KEY_FORMAT` and :c:macro:`MPS_KEY_CHAIN`
+ like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_amc(),
+ mps_fmt_t format,
+ mps_chain_t chain)
+
+ When creating a pool of class :c:func:`mps_class_ams`, pass the
+ values for the keyword arguments :c:macro:`MPS_KEY_FORMAT`,
+ :c:macro:`MPS_KEY_CHAIN` and ambiguous flag
+ :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_ams(),
+ mps_fmt_t format,
+ mps_chain_t chain,
+ mps_bool_t ams_support_ambiguous)
+
+ When creating a pool of class :c:func:`mps_class_ams_debug`, pass
+ the values for the keyword arguments
+ :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`, :c:macro:`MPS_KEY_FORMAT`,
+ :c:macro:`MPS_KEY_CHAIN` and
+ :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_ams_debug(),
+ mps_pool_debug_option_s *pool_debug_options,
+ mps_fmt_t format,
+ mps_chain_t chain,
+ mps_bool_t ams_support_ambiguous)
+
+ When creating a pool of class :c:func:`mps_class_awl`, pass the
+ values for the keyword arguments :c:macro:`MPS_KEY_FORMAT` and
+ :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_awl(),
+ mps_fmt_t format,
+ mps_awl_find_dependent_t awl_find_dependent)
+
+ When creating a pool of class :c:func:`mps_class_lo`, pass the
+ value for the keyword argument :c:macro:`MPS_KEY_FORMAT` like
+ this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_lo(),
+ mps_fmt_t format)
+
+ When creating a pool of class :c:func:`mps_class_mfs`, pass the
+ values for the keyword arguments :c:macro:`MPS_KEY_EXTEND_BY` and
+ :c:macro:`MPS_KEY_MFS_UNIT_SIZE` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_mfs(),
+ size_t extend_by,
+ size_t unit_size)
+
+ When creating a pool of class :c:func:`mps_class_mv`, pass the
+ values for the keyword arguments :c:macro:`MPS_KEY_EXTEND_BY`,
+ :c:macro:`MPS_KEY_MEAN_SIZE`, and :c:macro:`MPS_KEY_MAX_SIZE` like
+ this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_mv(),
+ size_t extend_by,
+ size_t mean_size,
+ size_t max_size)
+
+ When creating a pool of class :c:func:`mps_class_mv_debug`, pass
+ the values for the keyword arguments
+ :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`,
+ :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE` and
+ :c:macro:`MPS_KEY_MAX_SIZE` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_mv_debug(),
+ mps_pool_debug_option_s *pool_debug_options,
+ size_t extend_by,
+ size_t mean_size,
+ size_t max_size)
+
+ When creating a pool of class :c:func:`mps_class_mvff`, pass the
+ values for the keyword arguments :c:macro:`MPS_KEY_EXTEND_BY`,
+ :c:macro:`MPS_KEY_MEAN_SIZE`, :c:macro:`MPS_KEY_ALIGN`,
+ :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`,
+ :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` and
+ :c:macro:`MPS_KEY_MVFF_FIRST_FIT` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_mvff(),
+ size_t extend_by,
+ size_t mean_size,
+ mps_align_t align,
+ mps_bool_t mvff_slot_high,
+ mps_bool_t mvff_arena_high,
+ mps_bool_t mvff_first_fit)
+
+ When creating a pool of class :c:func:`mps_class_mvff_debug`, pass
+ the values for the keyword arguments
+ :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`,
+ :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE`,
+ :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`,
+ :c:macro:`MPS_KEY_MVFF_ARENA_HIGH`, and
+ :c:macro:`MPS_KEY_MVFF_FIRST_FIT` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_mvff_debug(),
+ mps_pool_debug_option_s *pool_debug_options,
+ size_t extend_by,
+ size_t mean_size,
+ mps_align_t align,
+ mps_bool_t mvff_slot_high,
+ mps_bool_t mvff_arena_high,
+ mps_bool_t mvff_first_fit)
+
+ When creating a pool of class :c:func:`mps_class_mvt`, pass the
+ values for the keyword arguments :c:macro:`MPS_KEY_MIN_SIZE`,
+ :c:macro:`MPS_KEY_MEAN_SIZE`, :c:macro:`MPS_KEY_MAX_SIZE`,
+ :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` and
+ :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` like this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_mvt(),
+ size_t min_size,
+ size_t mean_size,
+ size_t max_size,
+ mps_word_t mvt_reserve_depth,
+ mps_word_t mvt_frag_limit)
+
+ .. note::
+
+ The ``mvt_frag_limit`` is a percentage from 0 to 100
+ inclusive when passed to :c:func:`mps_pool_create`, not a
+ double from 0.0 to 1.0 as in :c:func:`mps_pool_create_k`.
+
+ When creating a pool of class :c:func:`mps_class_snc`, pass the
+ value for the keyword argument :c:macro:`MPS_KEY_FORMAT` like
+ this::
+
+ mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
+ mps_pool_class_t mps_class_snc(),
+ mps_fmt_t format)
+
+
+.. c:function:: mps_res_t mps_pool_create_v(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, va_list args)
+
+ .. deprecated::
+
+ Use :c:func:`mps_pool_create_k` instead.
+
+ An alternative to :c:func:`mps_pool_create_k` that takes its extra
+ arguments using the standard :term:`C` ``va_list`` mechanism. See
+ :c:func:`mps_pool_create` for details of which arguments to pass
+ for the different pool classes.
+
+
+.. c:function:: mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, ...)
+
+ .. deprecated::
+
+ Use :c:func:`mps_ap_create_k` instead.
+
+ An alternative to :c:func:`mps_ap_create_k` that takes its extra
+ arguments using the standard :term:`C` variable argument list
+ mechanism.
+
+ When creating an allocation point on a pool of class
+ :c:func:`mps_class_ams`, :c:func:`mps_class_ams_debug`,
+ :c:func:`mps_class_awl` or :c:func:`mps_class_snc`, pass the
+ keyword argument :c:macro:`MPS_KEY_RANK` like this::
+
+ mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool,
+ mps_rank_t rank)
+
+
+.. c:function:: mps_res_t mps_ap_create_v(mps_ap_t *ap_o, mps_pool_t pool, va_list args)
+
+ .. deprecated::
+
+ Use :c:func:`mps_ap_create_k` instead.
+
+ An alternative to :c:func:`mps_ap_create_k` that takes its extra
+ arguments using the standard :term:`C` ``va_list`` mechanism. See
+ :c:func:`mps_ap_create` for details of which arguments to pass
+ for the different pool classes.
+
+
+.. c:type:: mps_fmt_A_s
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ The type of the structure used to create an :term:`object format`
+ of variant A. ::
+
+ typedef struct mps_fmt_A_s {
+ mps_align_t align;
+ mps_fmt_scan_t scan;
+ mps_fmt_skip_t skip;
+ mps_fmt_copy_t copy;
+ mps_fmt_fwd_t fwd;
+ mps_fmt_isfwd_t isfwd;
+ mps_fmt_pad_t pad;
+ } mps_fmt_A_s;
+
+ The fields of this structure correspond to the keyword arguments
+ to :c:func:`mps_fmt_create_k`, except for ``copy``, which is not
+ used. In older versions of the MPS this was a *copy method*
+ that copied objects belonging to this format.
+
+
+.. c:function:: mps_res_t mps_fmt_create_A(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_A_s *fmt_A)
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ Create an :term:`object format` based on a description of an
+ object format of variant A.
+
+
+.. c:type:: mps_fmt_B_s
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ The type of the structure used to create an :term:`object format`
+ of variant B. ::
+
+ typedef struct mps_fmt_B_s {
+ mps_align_t align;
+ mps_fmt_scan_t scan;
+ mps_fmt_skip_t skip;
+ mps_fmt_copy_t copy;
+ mps_fmt_fwd_t fwd;
+ mps_fmt_isfwd_t isfwd;
+ mps_fmt_pad_t pad;
+ mps_fmt_class_t mps_class;
+ } mps_fmt_B_s;
+
+ Variant B is the same as variant A except for the addition of the
+ ``mps_class`` method. See :c:type:`mps_fmt_A_s`.
+
+
+.. c:function:: mps_res_t mps_fmt_create_B(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_B_s *fmt_B)
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ Create an :term:`object format` based on a description of an
+ object format of variant B.
+
+
+.. c:type:: mps_fmt_auto_header_s
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ The type of the structure used to create an :term:`object format`
+ of variant auto-header. ::
+
+ typedef struct mps_fmt_auto_header_s {
+ mps_align_t align;
+ mps_fmt_scan_t scan;
+ mps_fmt_skip_t skip;
+ mps_fmt_fwd_t fwd;
+ mps_fmt_isfwd_t isfwd;
+ mps_fmt_pad_t pad;
+ size_t mps_headerSize;
+ } mps_fmt_auto_header_s;
+
+ Variant auto-header is the same as variant A except for the
+ removal of the unused ``copy`` method, and the addition of the
+ ``mps_headerSize`` field. See :c:type:`mps_fmt_A_s`.
+
+
+.. c:function:: mps_res_t mps_fmt_create_auto_header(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_auto_header_s *fmt_ah)
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ Create an :term:`object format` based on a description of an
+ object format of variant auto-header.
+
+
+.. c:type:: mps_fmt_fixed_s
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ The type of the structure used to create an :term:`object format`
+ of variant fixed. ::
+
+ typedef struct mps_fmt_fixed_s {
+ mps_align_t align;
+ mps_fmt_scan_t scan;
+ mps_fmt_fwd_t fwd;
+ mps_fmt_isfwd_t isfwd;
+ mps_fmt_pad_t pad;
+ } mps_fmt_fixed_s;
+
+ Variant fixed is the same as variant A except for the removal of
+ the unused ``copy`` method, and the lack of a ``skip`` method
+ (this is not needed because the objects are fixed in size). See
+ :c:type:`mps_fmt_A_s`.
+
+
+.. c:function:: mps_res_t mps_fmt_create_fixed(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_fixed_s *fmt_fixed)
+
+ .. deprecated::
+
+ Use :c:func:`mps_fmt_create_k` instead.
+
+ Create an :term:`object format` based on a description of an
+ object format of variant fixed.
+
+
+.. index::
+ single: deprecated interfaces; in version 1.111
+
+Deprecated in version 1.111
+...........................
+
+.. c:function:: mps_res_t mps_fix(mps_ss_t ss, mps_addr_t *ref_io)
+
+ .. deprecated::
+
+ Use :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2` instead.
+
+ :term:`Fix` a :term:`reference`.
+
+ This is a function equivalent to::
+
+ MPS_SCAN_BEGIN(ss);
+ res = MPS_FIX12(ss, ref_io);
+ MPS_SCAN_END(ss);
+ return res;
+
+ Because :term:`scanning ` is an operation on the
+ :term:`critical path`, we recommend that you use
+ :c:func:`MPS_FIX12` (or :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2`)
+ to ensure that the "stage 1 fix" is inlined.
+
+ .. note::
+
+ If you call this between :c:func:`MPS_SCAN_BEGIN` and
+ :c:func:`MPS_SCAN_END`, you must use :c:func:`MPS_FIX_CALL` to
+ ensure that the scan state is passed correctly.
+
+
+.. c:function:: mps_word_t mps_telemetry_control(mps_word_t reset_mask, mps_word_t flip_mask)
+
+ .. deprecated::
+
+ Use :c:func:`mps_telemetry_get`,
+ :c:func:`mps_telemetry_reset`, and :c:func:`mps_telemetry_set`
+ instead.
+
+ Update and return the :term:`telemetry filter`.
+
+ ``reset_mask`` is a :term:`bitmask` indicating the bits in the
+ telemetry filter that should be reset.
+
+ ``flip_mask`` is a bitmask indicating the bits in the telemetry
+ filter whose value should be flipped after the resetting.
+
+ Returns the previous value of the telemetry filter, prior to the
+ reset and the flip.
+
+ The parameters ``reset_mask`` and ``flip_mask`` allow the
+ specification of any binary operation on the filter control. For
+ typical operations, the parameters should be set as follows:
+
+ ============ ============== =============
+ Operation ``reset_mask`` ``flip_mask``
+ ============ ============== =============
+ ``set(M)`` ``M`` ``M``
+ ------------ -------------- -------------
+ ``reset(M)`` ``M`` ``0``
+ ------------ -------------- -------------
+ ``flip(M)`` ``0`` ``M``
+ ------------ -------------- -------------
+ ``read()`` ``0`` ``0``
+ ============ ============== =============
+
+
+.. c:function:: void mps_tramp(void **r_o, mps_tramp_t f, void *p, size_t s)
+
+ .. deprecated::
+
+ The MPS trampoline is no longer required on any operating
+ system supported by the MPS.
+
+ Call a function via the MPS trampoline.
+
+ ``r_o`` points to a location that will store the result of calling
+ ``f``.
+
+ ``f`` is the function to call.
+
+ ``p`` and ``s`` are arguments that will be passed to ``f`` each
+ time it is called. This is intended to make it easy to pass, for
+ example, an array and its size as parameters.
+
+ The MPS relies on :term:`barriers (1)` to protect memory
+ that is in an inconsistent state. On some operating systems,
+ barrier hits generate exceptions that have to be caught by a
+ handler that is on the stack. On these operating systems, any code
+ that uses memory managed by the MPS must be called from inside
+ such an exception handler, that is, inside a call to
+ :c:func:`mps_tramp`.
+
+ If you have multiple threads that run code that uses memory
+ managed by the MPS, each thread must execute such code inside a
+ call to :c:func:`mps_tramp`.
+
+
+.. index::
+ single: trampoline
+
+.. c:type:: void *(*mps_tramp_t)(void *p, size_t s)
+
+ .. deprecated::
+
+ The MPS trampoline is no longer required on any operating
+ system supported by the MPS.
+
+ The type of a function called by :c:func:`mps_tramp`.
+
+ ``p`` and ``s`` are the corresponding arguments that were passed
+ to :c:func:`mps_tramp`.
+
+
+.. c:function:: void mps_arena_expose(mps_arena_t arena)
+
+ .. deprecated::
+
+ If you need access to protected memory for debugging,
+ :ref:`contact us `.
+
+ Ensure that the MPS is not protecting any :term:`page` in the
+ :term:`arena` with a :term:`read barrier` or :term:`write
+ barrier`.
+
+ ``arena`` is the arena to expose.
+
+ This is expected to only be useful for debugging. The arena is
+ left in the :term:`clamped state`.
+
+ Since barriers are used during a collection, calling this function
+ has the same effect as calling :c:func:`mps_arena_park`: all
+ collections are run to completion, and the arena is clamped so
+ that no new collections begin. The MPS also uses barriers to
+ maintain :term:`remembered sets`, so calling this
+ function will effectively destroy the remembered sets and any
+ optimization gains from them.
+
+ Calling this function is time-consuming: any active collections
+ will be run to completion; and the next collection will have to
+ recompute all the remembered sets by scanning the entire arena.
+
+ The recomputation of the remembered sets can be avoided by calling
+ :c:func:`mps_arena_unsafe_expose_remember_protection` instead of
+ :c:func:`mps_arena_expose`, and by calling
+ :c:func:`mps_arena_unsafe_restore_protection` before calling
+ :c:func:`mps_arena_release`. Those functions have unsafe aspects
+ and place restrictions on what the :term:`client program` can do
+ (basically no exposed data can be changed).
+
+
+.. c:function:: void mps_arena_unsafe_expose_remember_protection(mps_arena_t arena)
+
+ .. deprecated::
+
+ If you need access to protected memory for debugging,
+ :ref:`contact us `.
+
+ Ensure that the MPS is not protecting any :term:`page` in the
+ :term:`arena` with a :term:`read barrier` or :term:`write
+ barrier`. In addition, request the MPS to remember some parts of its
+ internal state so that they can be restored later.
+
+ ``arena`` is the arena to expose.
+
+ This function is the same as :c:func:`mps_arena_expose`, but
+ additionally causes the MPS to remember its protection state. The
+ remembered protection state can optionally be restored later by
+ calling the :c:func:`mps_arena_unsafe_restore_protection` function.
+ This is an optimization that avoids the MPS having to recompute
+ all the remembered sets by scanning the entire arena.
+
+ However, restoring the remembered protections is only safe if the
+ contents of the exposed pages have not been changed; therefore
+ this function should only be used if you do not intend to change
+ the pages, and the remembered protection must only be restored if
+ the pages have not been changed.
+
+ The MPS will only remember the protection state if resources
+ (memory) are available. If memory is low then only some or
+ possibly none of the protection state will be remembered, with a
+ corresponding necessity to recompute it later. The MPS provides no
+ mechanism for the :term:`client program` to determine whether the
+ MPS has in fact remembered the protection state.
+
+ The remembered protection state, if any, is discarded after
+ calling :c:func:`mps_arena_unsafe_restore_protection`, or as soon
+ as the arena leaves the :term:`clamped state` by calling
+ :c:func:`mps_arena_release`.
+
+
+.. c:function:: void mps_arena_unsafe_restore_protection(mps_arena_t arena)
+
+ .. deprecated::
+
+ If you need access to protected memory for debugging,
+ :ref:`contact us `.
+
+ Restore the remembered protection state for an :term:`arena`.
+
+ ``arena`` is the arena to restore the protection state for.
+
+ This function restores the protection state that the MPS has
+ remembered when the :term:`client program` called
+ :c:func:`mps_arena_unsafe_expose_remember_protection`. The purpose
+ of remembering and restoring the protection state is to avoid the
+ need for the MPS to recompute all the :term:`remembered sets` by
+ scanning the entire arena, that occurs when
+ :c:func:`mps_arena_expose` is used, and which causes the next
+ :term:`garbage collection` to be slow.
+
+ The client program must not change the exposed data between the
+ call to :c:func:`mps_arena_unsafe_expose_remember_protection` and
+ :c:func:`mps_arena_unsafe_restore_protection`. If the client
+ program has changed the exposed data then
+ :c:func:`mps_arena_unsafe_restore_protection` must not be called:
+ in this case simply call :c:func:`mps_arena_release`.
+
+ Calling this function does not release the arena from the clamped
+ state: :c:func:`mps_arena_release` must be called to continue
+ normal collections.
+
+ Calling this function causes the MPS to forget the remembered
+ protection state; as a consequence the same remembered state
+ cannot be restored more than once.
+
diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst
index 82efa2e5e3c..1120b868897 100644
--- a/mps/manual/source/topic/error.rst
+++ b/mps/manual/source/topic/error.rst
@@ -76,31 +76,28 @@ Result codes
A :term:`result code` indicating that an operation could not be
completed as requested without exceeding the :term:`commit limit`.
- You need to deallocate something to make more space, or increase
+ You need to deallocate something or allow the :term:`garbage
+ collector` to reclaim something to make more space, or increase
the commit limit by calling :c:func:`mps_arena_commit_limit_set`.
.. c:macro:: MPS_RES_FAIL
A :term:`result code` indicating that something went wrong that
- does not fall under the description of any other result code. The
- exact meaning depends on the function that returned this result
- code.
+ does not fall under the description of any other result code.
.. c:macro:: MPS_RES_IO
A :term:`result code` indicating that an input/output error
- occurred. The exact meaning depends on the function that returned
- this result code.
+ occurred in the :term:`telemetry` system.
.. c:macro:: MPS_RES_LIMIT
A :term:`result code` indicating that an operation could not be
completed as requested because of an internal limitation of the
- MPS. The exact meaning depends on the function that returned this
- result code.
+ MPS.
.. c:macro:: MPS_RES_MEMORY
@@ -109,7 +106,7 @@ Result codes
completed because there wasn't enough memory available.
You need to deallocate something or allow the :term:`garbage
- collector` to reclaim something to free enough memory, or expand
+ collector` to reclaim something to free enough memory, or extend
the :term:`arena` (if you're using an arena for which that does
not happen automatically).
@@ -140,27 +137,23 @@ Result codes
A :term:`result code` indicating that an operation could not be
completed as requested because an invalid parameter was passed to
- the operation. The exact meaning depends on the function that
- returned this result code.
+ the operation.
.. c:macro:: MPS_RES_RESOURCE
A :term:`result code` indicating that an operation could not be
completed as requested because the MPS could not obtain a needed
- resource. The resource in question depends on the operation.
+ resource. It can be returned when the MPS runs out of
+ :term:`address space`. If this happens, you need to reclaim memory
+ within your process (as for the result code
+ :c:macro:`MPS_RES_MEMORY`).
Two special cases have their own result codes: when the MPS runs
out of committed memory, it returns :c:macro:`MPS_RES_MEMORY`, and
when it cannot proceed without exceeding the :term:`commit limit`,
it returns :c:macro:`MPS_RES_COMMIT_LIMIT`.
- This result code can be returned when the MPS runs out of
- :term:`virtual memory`. If this happens, you need to reclaim
- memory within your process (as for the result code
- :c:macro:`MPS_RES_MEMORY`), or terminate other processes running
- on the same machine.
-
.. c:macro:: MPS_RES_UNIMPL
@@ -272,13 +265,49 @@ 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``
The client program has made a re-entrant call into the MPS. Look
- at the backtrace to see what it was. Common culprits are
- :term:`format methods` and :term:`stepper functions`.
+ at the backtrace to see what it was. Common culprits are signal
+ handlers, assertion handlers, :term:`format methods`, and
+ :term:`stepper functions`.
``locus.c: chain->activeTraces == TraceSetEMPTY``
@@ -305,13 +334,19 @@ this documentation.
condition?
-``ring.c: ring->next == ring``
+``poolsnc.c: foundSeg``
- The client program destroyed an object without having destroyed
- all the objects 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``
@@ -320,7 +355,7 @@ this documentation.
for finalization, and then continued to run the garbage collector.
See :ref:`topic-finalization-cautions` under
:ref:`topic-finalization`, which says, "You must destroy these
- pools by following the “safe tear-down” procedure described under
+ pools by following the ‘safe tear-down’ procedure described under
:c:func:`mps_pool_destroy`."
@@ -330,22 +365,24 @@ this documentation.
reference to an object that moved. See
:ref:`topic-scanning-protocol`, which says, "If :c:func:`MPS_FIX2`
returns :c:macro:`MPS_RES_OK`, it may have updated the reference.
- If necessary, make sure that the updated reference is stored back
- to the region being scanned."
+ Make sure that the updated reference is stored back to the region
+ being scanned."
.. index::
single: error handling; varieties
single: variety
+.. _topic-error-variety:
+
Varieties
---------
-The MPS has three behaviours with respect to internal checking and
-:ref:`telemetry `, which need to be selected at
-compile time, by defining one of the following preprocessor
-constants. If none is specified then :c:macro:`CONFIG_VAR_HOT` is the
-default.
+The MPS has three *varieties* which have different levels of internal
+checking and :ref:`telemetry `. The variety can be
+selected at compile time, by defining one of the following
+preprocessor constants. If none is specified then
+:c:macro:`CONFIG_VAR_HOT` is the default.
.. index::
@@ -354,7 +391,7 @@ default.
.. c:macro:: CONFIG_VAR_COOL
- The cool variety is intended for development and testing.
+ The *cool variety* is intended for development and testing.
All functions check the consistency of their data structures and may
assert, including functions on the :term:`critical path`.
@@ -372,7 +409,7 @@ default.
.. c:macro:: CONFIG_VAR_HOT
- The hot variety is intended for production and deployment.
+ The *hot variety* is intended for production and deployment.
Some functions check the consistency of their data structures and
may assert, namely those not on the :term:`critical path`. However,
@@ -389,7 +426,7 @@ default.
.. c:macro:: CONFIG_VAR_RASH
- The rash variety is intended for mature integrations, or for
+ The *rash variety* is intended for mature integrations, or for
developers who like living dangerously.
No functions check the consistency of their data structures and
diff --git a/mps/manual/source/topic/format.rst b/mps/manual/source/topic/format.rst
index 9ed826b2ac2..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
@@ -221,9 +235,9 @@ Cautions
#. Format methods must use no more than 64 words of stack space.
This restriction is necessary to avoid stack overflow in the MPS;
- see :mps:ref:`design.mps.sp` for details. If your application has
- format methods that need more stack space than this, :ref:`contact
- us `.
+ see :ref:`design-sp` for details. If your application has format
+ methods that need more stack space than this, :ref:`contact us
+ `.
#. Format methods must not:
@@ -535,137 +549,3 @@ Object format introspection
c. memory not managed by the MPS;
It must not access other memory managed by the MPS.
-
-
-Obsolete interface
-------------------
-
-.. deprecated:: starting with version 1.112.
-
- Use :c:func:`mps_ap_create_k` instead: the :term:`keyword
- arguments` interface is more flexible and easier to understand.
-
-Formerly the only way to create object formats was to describe the
-format in the form of a *format variant structure*.
-
-There are four format variants.
-
-* Variant A (:c:type:`mps_fmt_A_s`): for objects without
- :term:`in-band headers`.
-
-* Variant B (:c:type:`mps_fmt_B_s`): as variant A, but with the
- addition of a class method.
-
-* Variant auto-header (:c:type:`mps_fmt_auto_header_s`): for objects
- with :term:`in-band headers`.
-
-* Variant fixed (:c:type:`mps_fmt_fixed_s`): for fixed-size objects.
-
-The client program creates an object format by construct a format
-variant structure and then calling the appropriate ``mps_fmt_create_``
-function for the variant. The variant structure can then be disposed
-of.
-
-
-.. c:type:: mps_fmt_A_s
-
- The type of the structure used to create an :term:`object format`
- of variant A. ::
-
- typedef struct mps_fmt_A_s {
- mps_align_t align;
- mps_fmt_scan_t scan;
- mps_fmt_skip_t skip;
- mps_fmt_copy_t copy;
- mps_fmt_fwd_t fwd;
- mps_fmt_isfwd_t isfwd;
- mps_fmt_pad_t pad;
- } mps_fmt_A_s;
-
- The fields of this structure correspond to the keyword arguments
- to :c:func:`mps_fmt_create_k`, except for ``copy``, which is not
- used. In older versions of the MPS this was a *copy method*
- that copied objects belonging to this format.
-
-
-.. c:function:: mps_res_t mps_fmt_create_A(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_A_s *fmt_A)
-
- Create an :term:`object format` based on a description of an
- object format of variant A.
-
-
-.. c:type:: mps_fmt_B_s
-
- The type of the structure used to create an :term:`object format`
- of variant B. ::
-
- typedef struct mps_fmt_B_s {
- mps_align_t align;
- mps_fmt_scan_t scan;
- mps_fmt_skip_t skip;
- mps_fmt_copy_t copy;
- mps_fmt_fwd_t fwd;
- mps_fmt_isfwd_t isfwd;
- mps_fmt_pad_t pad;
- mps_fmt_class_t mps_class;
- } mps_fmt_B_s;
-
- Variant B is the same as variant A except for the addition of the
- ``mps_class`` method. See :c:type:`mps_fmt_A_s`.
-
-
-.. c:function:: mps_res_t mps_fmt_create_B(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_B_s *fmt_B)
-
- Create an :term:`object format` based on a description of an
- object format of variant B.
-
-
-.. c:type:: mps_fmt_auto_header_s
-
- The type of the structure used to create an :term:`object format`
- of variant auto-header. ::
-
- typedef struct mps_fmt_auto_header_s {
- mps_align_t align;
- mps_fmt_scan_t scan;
- mps_fmt_skip_t skip;
- mps_fmt_fwd_t fwd;
- mps_fmt_isfwd_t isfwd;
- mps_fmt_pad_t pad;
- size_t mps_headerSize;
- } mps_fmt_auto_header_s;
-
- Variant auto-header is the same as variant A except for the
- removal of the unused ``copy`` method, and the addition of the
- ``mps_headerSize`` field. See :c:type:`mps_fmt_A_s`.
-
-
-.. c:function:: mps_res_t mps_fmt_create_auto_header(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_auto_header_s *fmt_ah)
-
- Create an :term:`object format` based on a description of an
- object format of variant auto-header.
-
-
-.. c:type:: mps_fmt_fixed_s
-
- The type of the structure used to create an :term:`object format`
- of variant fixed. ::
-
- typedef struct mps_fmt_fixed_s {
- mps_align_t align;
- mps_fmt_scan_t scan;
- mps_fmt_fwd_t fwd;
- mps_fmt_isfwd_t isfwd;
- mps_fmt_pad_t pad;
- } mps_fmt_fixed_s;
-
- Variant fixed is the same as variant A except for the removal of
- the unused ``copy`` method, and the lack of a ``skip`` method
- (this is not needed because the objects are fixed in size). See
- :c:type:`mps_fmt_A_s`.
-
-
-.. c:function:: mps_res_t mps_fmt_create_fixed(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_fixed_s *fmt_fixed)
-
- Create an :term:`object format` based on a description of an
- object format of variant fixed.
diff --git a/mps/manual/source/topic/index.rst b/mps/manual/source/topic/index.rst
index 32f4a6bb494..3f2cb2863bf 100644
--- a/mps/manual/source/topic/index.rst
+++ b/mps/manual/source/topic/index.rst
@@ -29,3 +29,5 @@ Reference
plinth
platform
porting
+ deprecated
+
diff --git a/mps/manual/source/topic/interface.rst b/mps/manual/source/topic/interface.rst
index 54637557f60..e7715181836 100644
--- a/mps/manual/source/topic/interface.rst
+++ b/mps/manual/source/topic/interface.rst
@@ -35,6 +35,10 @@ Support policy
a version in which the symbol (or reliance on some of its
behaviour) is deprecated.
+ Symbols may be deprecated in their old place in the reference
+ manual, or they may be moved to the :ref:`topic-deprecated`
+ chapter.
+
.. note::
If you are relying on a feature and you see that it's
@@ -204,7 +208,8 @@ Instead, we recommend this approach::
mps_addr_t p;
struct foo *fp;
res = mps_alloc(&p, pool, sizeof(struct foo));
- if(res) /* handle error case */;
+ if (res != MPS_RES_OK)
+ /* handle error case */;
fp = p;
This has defined behaviour because conversion from ``void *`` to any
diff --git a/mps/manual/source/topic/keyword.rst b/mps/manual/source/topic/keyword.rst
index 25e18f2de4d..ac80333ba36 100644
--- a/mps/manual/source/topic/keyword.rst
+++ b/mps/manual/source/topic/keyword.rst
@@ -82,43 +82,43 @@ now :c:macro:`MPS_KEY_ARGS_END`.
The type of :term:`keyword argument` keys. Must take one of the
following values:
- ======================================== ====================================================== ==========================================================
- Keyword Type & field in ``arg.val`` See
- ======================================== ====================================================== ==========================================================
- :c:macro:`MPS_KEY_ARGS_END` *none* *see above*
- :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt`
- :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams`
- :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl`
- :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
- :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
- :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl`
- :c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo`
- :c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_FWD` :c:type:`mps_fmt_fwd_t` ``fmt_fwd`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_HEADER_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_ISFWD` :c:type:`mps_fmt_isfwd_t` ``fmt_isfwd`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_PAD` :c:type:`mps_fmt_pad_t` ``fmt_pad`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_SCAN` :c:type:`mps_fmt_scan_t` ``fmt_scan`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FMT_SKIP` :c:type:`mps_fmt_skip_t` ``fmt_skip`` :c:func:`mps_fmt_create_k`
- :c:macro:`MPS_KEY_FORMAT` :c:type:`mps_fmt_t` ``format`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` , :c:func:`mps_class_snc`
- :c:macro:`MPS_KEY_GEN` :c:type:`unsigned` ``u`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo`
- :c:macro:`MPS_KEY_INTERIOR` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`
- :c:macro:`MPS_KEY_MAX_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`
- :c:macro:`MPS_KEY_MEAN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvt`, :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_MFS_UNIT_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mfs`
- :c:macro:`MPS_KEY_MIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mvt`
- :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_MVFF_FIRST_FIT` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt`
- :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt`
- :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` ``mps_pool_debug_options_s *`` ``pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug`
- :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc`
- :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff`
- :c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm`
- ======================================== ====================================================== ==========================================================
+ ======================================== ========================================================= ==========================================================
+ Keyword Type & field in ``arg.val`` See
+ ======================================== ========================================================= ==========================================================
+ :c:macro:`MPS_KEY_ARGS_END` *none* *see above*
+ :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt`
+ :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams`
+ :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl`
+ :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
+ :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
+ :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl`
+ :c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo`
+ :c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_FWD` :c:type:`mps_fmt_fwd_t` ``fmt_fwd`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_HEADER_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_ISFWD` :c:type:`mps_fmt_isfwd_t` ``fmt_isfwd`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_PAD` :c:type:`mps_fmt_pad_t` ``fmt_pad`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_SCAN` :c:type:`mps_fmt_scan_t` ``fmt_scan`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FMT_SKIP` :c:type:`mps_fmt_skip_t` ``fmt_skip`` :c:func:`mps_fmt_create_k`
+ :c:macro:`MPS_KEY_FORMAT` :c:type:`mps_fmt_t` ``format`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` , :c:func:`mps_class_snc`
+ :c:macro:`MPS_KEY_GEN` :c:type:`unsigned` ``u`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo`
+ :c:macro:`MPS_KEY_INTERIOR` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`
+ :c:macro:`MPS_KEY_MAX_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`
+ :c:macro:`MPS_KEY_MEAN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvt`, :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_MFS_UNIT_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mfs`
+ :c:macro:`MPS_KEY_MIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mvt`
+ :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_MVFF_FIRST_FIT` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt`
+ :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt`
+ :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` :c:type:`mps_pool_debug_option_s` ``*pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug`
+ :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc`
+ :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff`
+ :c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm`
+ ======================================== ========================================================= ==========================================================
.. c:function:: MPS_ARGS_BEGIN(args)
@@ -192,11 +192,3 @@ now :c:macro:`MPS_KEY_ARGS_END`.
``args`` is the name of array that contains the keyword arguments.
It must match the argument to the preceding call to
:c:func:`MPS_ARGS_BEGIN`.
-
-
-.. c:function:: MPS_ARGS_DONE(args)
-
- .. deprecated:: starting with version 1.113.
-
- Formerly this was used to finalize a list of keyword arguments
- before passing it to a function. It is no longer needed.
diff --git a/mps/manual/source/topic/plinth.rst b/mps/manual/source/topic/plinth.rst
index 8f26f267d70..f771f6c1c31 100644
--- a/mps/manual/source/topic/plinth.rst
+++ b/mps/manual/source/topic/plinth.rst
@@ -262,6 +262,11 @@ Library module
:c:func:`mps_lib_assert_fail_install`. For a discussion of the
default behaviour, see :ref:`topic-error-assertion-handling`.
+ .. warning::
+
+ This function must not call any function in MPS, and it must
+ not access memory managed by the MPS.
+
.. c:function:: extern mps_lib_assert_fail_t mps_lib_assert_fail_install(mps_lib_assert_fail_t handler)
This function customises the behaviour of the default assertion handler
@@ -277,6 +282,11 @@ Library module
Returns the previously installed handler.
+ .. warning::
+
+ The installed assertion handler must not call any function in
+ MPS, and it must not access memory managed by the MPS.
+
.. c:type:: typedef void (*mps_lib_assert_fail_t)(const char *, unsigned, const char *)
The type of assertion handlers passed to and returned by
diff --git a/mps/manual/source/topic/pool.rst b/mps/manual/source/topic/pool.rst
index 68ec8185f03..d1ffe56d45b 100644
--- a/mps/manual/source/topic/pool.rst
+++ b/mps/manual/source/topic/pool.rst
@@ -40,31 +40,6 @@ making it available for allocation.
:c:func:`mps_pool_destroy`.
-.. c:function:: mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, ...)
-
- .. deprecated:: starting with version 1.112.
-
- Use :c:func:`mps_pool_create_k` instead: the :term:`keyword
- arguments` interface is more reliable and produces better
- error messages.
-
- An alternative to :c:func:`mps_pool_create_k` that takes its
- extra arguments using the standard :term:`C` variable argument
- list mechanism.
-
-
-.. c:function:: mps_res_t mps_pool_create_v(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, va_list args)
-
- .. deprecated:: starting with version 1.112.
-
- Use :c:func:`mps_pool_create_k` instead: the :term:`keyword
- arguments` interface is more reliable and produces better
- error messages.
-
- An alternative to :c:func:`mps_pool_create_k` that takes its extra
- arguments using the standard :term:`C` ``va_list`` mechanism.
-
-
.. c:function:: void mps_pool_destroy(mps_pool_t pool)
Destroy a :term:`pool`.
@@ -83,12 +58,12 @@ making it available for allocation.
.. warning::
- It is not safe to destroy an :term:`automatically managed
- ` pool if it contains any objects
+ It is not safe to carry on running the :term:`garbage
+ collector` after destroying an :term:`automatically managed
+ ` pool that contains any objects
that are :term:`reachable` from your roots, or any objects
that have been registered for :term:`finalization` but not yet
- finalized, and then to carry on running the :term:`garbage
- collector`.
+ finalized.
Our recommended approach is to destroy automatically managed
pools just before destroying the arena, and then only while
@@ -123,13 +98,6 @@ See the :ref:`pool` for a list of pool classes.
The type of :term:`pool classes`.
-.. c:type:: typedef mps_pool_class_t mps_class_t
-
- .. deprecated:: starting with version 1.115.
-
- The former name for ``mps_pool_class_t``, chosen when pools
- were the only objects in the MPS that belonged to classes.
-
.. index::
pair: pool; introspection
diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst
index b58663a48b7..600dd7138de 100644
--- a/mps/manual/source/topic/porting.rst
+++ b/mps/manual/source/topic/porting.rst
@@ -38,29 +38,10 @@ usable.
See :ref:`design-lock` for the design, and ``lock.h`` for the
interface. There are implementations for Linux in ``lockli.c``,
- POSIX in ``lockix.c``, and Windows in ``lockw3.c``. There is a
- generic implementation in ``lockan.c``, which cannot actually take
- any locks and so only works for a single thread.
+ POSIX in ``lockix.c``, and Windows in ``lockw3.c``.
-#. The **thread manager** module suspends and resumes :term:`threads`,
- so that the MPS can gain exclusive access to :term:`memory (2)`,
- and so that it can scan the :term:`registers` and :term:`control
- stack` of suspended threads.
-
- See :ref:`design-thread-manager` for the design, and ``th.h`` for
- the interface. There are implementations for POSIX in ``thix.c``
- plus ``pthrdext.c``, OS X using Mach in ``thxc.c``, Windows in
- ``thw3.c``. There is a generic implementation in ``than.c``, which
- necessarily only supports a single thread.
-
-#. The **virtual mapping** module reserves :term:`address space` from
- the operating system (and returns it), and :term:`maps `
- address space to :term:`main memory` (and unmaps it).
-
- See :ref:`design-vm` for the design, and ``vm.h`` for the
- interface. There are implementations for POSIX in ``vmix.c``, and
- Windows in ``vmw3.c``. There is a generic implementation in
- ``vman.c``, which fakes virtual memory by calling :c:func:`malloc`.
+ There is a generic implementation in ``lockan.c``, which cannot
+ actually take any locks and so only works for a single thread.
#. The **memory protection** module applies :term:`protection` to
areas of :term:`memory (2)`, ensuring that attempts to read or
@@ -70,10 +51,13 @@ usable.
See :ref:`design-prot` for the design, and ``prot.h`` for the
interface. There are implementations for POSIX in ``protix.c`` plus
``protsgix.c``, Linux in ``protli.c``, Windows in ``protw3.c``, and
- OS X using Mach in ``protxc.c``. There is a generic implementation
- in ``protan.c``, which can't provide memory protection, so it
- forces memory to be scanned until that there is no further need to
- protect it.
+ OS X using Mach in ``protxc.c``.
+
+ There is a generic implementation in ``protan.c``, which can't
+ provide memory protection, so it forces memory to be scanned until
+ that there is no further need to protect it. This means it can't
+ support incremental collection, and has no control over pause
+ times.
#. The **protection mutator context** module figures out what the
:term:`mutator` was doing when it caused a :term:`protection
@@ -83,8 +67,10 @@ usable.
See :ref:`design-prmc` for the design, and ``prot.h`` for the
interface. There are implementations on Unix, Windows, and OS X for
- IA-32 and x86-64. There is a generic implementation in
- ``prmcan.c``, which can't provide these features.
+ IA-32 and x86-64.
+
+ There is a generic implementation in ``prmcan.c``, which can't
+ provide these features, and so only supports a single thread.
#. The **stack probe** module checks that there is enough space on the
:term:`control stack` for the MPS to complete any operation that it
@@ -93,8 +79,12 @@ usable.
See :ref:`design-sp` for the design, and ``sp.h`` for the
interface. There are implementations on Windows on IA-32 in
- ``spi3w3.c`` and x86-64 in ``spi6w3.c``. There is a generic
- implementation in ``span.c``, which can't provide this feature.
+ ``spi3w3.c`` and x86-64 in ``spi6w3.c``.
+
+ There is a generic implementation in ``span.c``, which can't
+ provide this feature, and so is only suitable for use with a client
+ program that does not handle stack overflow faults, or does not
+ call into the MPS from the handler.
#. The **stack and register scanning** module :term:`scans` the
:term:`registers` and :term:`control stack` of a thread.
@@ -103,8 +93,34 @@ usable.
interface. There are implementations for POSIX on IA-32 in
``ssixi3.c`` and x86-64 in ``ssixi6.c``, and for Windows with
Microsoft Visual C/C++ on IA-32 in ``ssw3i3mv.c`` and x86-64 in
- ``ssw3i6mv.c``. There is a generic implementation in ``ssan.c``,
- which calls :c:func:`setjmp` to spill the registers.
+ ``ssw3i6mv.c``.
+
+ There is a generic implementation in ``ssan.c``, which calls
+ :c:func:`setjmp` to spill the registers and scans the whole jump
+ buffer, thus overscanning compared to a platform-specific
+ implementation.
+
+#. The **thread manager** module suspends and resumes :term:`threads`,
+ so that the MPS can gain exclusive access to :term:`memory (2)`,
+ and so that it can scan the :term:`registers` and :term:`control
+ stack` of suspended threads.
+
+ See :ref:`design-thread-manager` for the design, and ``th.h`` for
+ the interface. There are implementations for POSIX in ``thix.c``
+ plus ``pthrdext.c``, OS X using Mach in ``thxc.c``, Windows in
+ ``thw3.c``.
+
+ There is a generic implementation in ``than.c``, which necessarily
+ only supports a single thread.
+
+#. The **virtual mapping** module reserves :term:`address space` from
+ the operating system (and returns it), and :term:`maps `
+ address space to :term:`main memory` (and unmaps it).
+
+ See :ref:`design-vm` for the design, and ``vm.h`` for the
+ interface. There are implementations for POSIX in ``vmix.c``, and
+ Windows in ``vmw3.c``. There is a generic implementation in
+ ``vman.c``, which fakes virtual memory by calling :c:func:`malloc`.
Platform detection
@@ -185,15 +201,17 @@ Makefile
--------
Add a makefile even if you expect to use an integrated development
-environment like Visual Studio or Xcode. Makefiles make it easier to
-carry out continuous integration and delivery.
+environment (IDE) like Visual Studio or Xcode. Makefiles make it
+easier to carry out continuous integration and delivery, and are less
+likely to stop working because of incompatibilities between IDE
+versions.
-The makefile must be named ``osarct.gmk``, and must define ``PFM`` to
-be the platform code, ``MPMPF`` to be the list of platform modules
-(the same files included by ``mps.c``), and ``LIBS`` to be the linker
-options for any libraries required by the test cases. Then it must
-include the compiler-specific makefile and ``comm.gmk``. For example,
-``lii6ll.gmk`` looks like this::
+On Unix platforms, the makefile must be named ``osarct.gmk``, and must
+define ``PFM`` to be the platform code, ``MPMPF`` to be the list of
+platform modules (the same files included by ``mps.c``), and ``LIBS``
+to be the linker options for any libraries required by the test cases.
+Then it must include the compiler-specific makefile and ``comm.gmk``.
+For example, ``lii6ll.gmk`` looks like this::
PFM = lii6ll
@@ -222,6 +240,29 @@ improve performance by compiling the MPS and their object format in
the same compilation unit. These steps would be more complicated if
the MPS required particular compilation options.
+On Windows, the makefile must be named ``osarct.nmk``, and must define
+``PFM`` to be the platform code, and ``MPMPF`` to be the list of
+platform modules (the same files included by ``mps.c``) in square
+brackets. Then it must include the compiler-specific makefile and
+``comm.nmk``. For example, ``w3i6mv.nmk`` looks like this::
+
+ PFM = w3i6mv
+
+ MPMPF = \
+ [lockw3] \
+ [mpsiw3] \
+ [prmci6w3] \
+ [proti6] \
+ [protw3] \
+ [spw3i6] \
+ [ssw3i6mv] \
+ [thw3] \
+ [thw3i6] \
+ [vmw3]
+
+ !INCLUDE mv.nmk
+ !INCLUDE comm.nmk
+
Porting strategy
----------------
@@ -230,15 +271,17 @@ Start the port by selecting existing implementations of the functional
modules, using the generic implementations where nothing else will do.
Then check that the "smoke tests" pass, by running::
- make -f osarct.gmk testrun
+ make -f osarct.gmk testrun # Unix
+ nmake /f osarct.nmk testrun # Windows
-Most or all of the test cases should pass at this point (if you're
+Most or all of the test cases should pass at this point. If you're
using the generic threading implementation, then the multi-threaded
-test cases ``amcssth`` and ``awlutth`` are expected to fail; and if
-you're using the generic lock implementation, then the lock
-utilization test case ``lockut`` is expected to fail). However,
-performance will be very poor if you're using the generic memory
-protection implementation.
+test cases are expected to fail. If you're using the generic lock
+implementation, then the lock utilization test case ``lockut`` is
+expected to fail. If you're using the generic memory protection
+implementation, all the tests that rely on incremental collection are
+expected to fail. See ``tool/testcases.txt`` for a database of test
+cases and the configurations in which they are expected to pass.
Now that there is a working system to build on, porting the necessary
modules to the new platform can be done incrementally. It's a good
diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst
index ed9adbb045a..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::
@@ -496,30 +501,3 @@ Fixing interface
In the case where the scan method does not need to do anything
between :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2`, you can use
the convenience macro :c:func:`MPS_FIX12`.
-
-
-.. c:function:: mps_res_t mps_fix(mps_ss_t ss, mps_addr_t *ref_io)
-
- .. deprecated:: starting with version 1.111.
-
- Use :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2` instead.
-
- :term:`Fix` a :term:`reference`.
-
- This is a function equivalent to::
-
- MPS_SCAN_BEGIN(ss);
- res = MPS_FIX12(ss, ref_io);
- MPS_SCAN_END(ss);
- return res;
-
- Because :term:`scanning ` is an operation on the
- :term:`critical path`, we recommend that you use
- :c:func:`MPS_FIX12` (or :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2`)
- to ensure that the "stage 1 fix" is inlined.
-
- .. note::
-
- If you call this between :c:func:`MPS_SCAN_BEGIN` and
- :c:func:`MPS_SCAN_END`, you must use :c:func:`MPS_FIX_CALL` to
- ensure that the scan state is passed correctly.
diff --git a/mps/manual/source/topic/telemetry.rst b/mps/manual/source/topic/telemetry.rst
index 4dc6d8d89a7..e25e71e4c59 100644
--- a/mps/manual/source/topic/telemetry.rst
+++ b/mps/manual/source/topic/telemetry.rst
@@ -388,41 +388,6 @@ further analysis by running :program:`mpseventsql`.
Telemetry interface
-------------------
-.. c:function:: mps_word_t mps_telemetry_control(mps_word_t reset_mask, mps_word_t flip_mask)
-
- .. deprecated:: starting with version 1.111.
-
- Use :c:func:`mps_telemetry_get`, :c:func:`mps_telemetry_reset`,
- and :c:func:`mps_telemetry_set` instead.
-
- Update and return the :term:`telemetry filter`.
-
- ``reset_mask`` is a :term:`bitmask` indicating the bits in the
- telemetry filter that should be reset.
-
- ``flip_mask`` is a bitmask indicating the bits in the telemetry
- filter whose value should be flipped after the resetting.
-
- Returns the previous value of the telemetry filter, prior to the
- reset and the flip.
-
- The parameters ``reset_mask`` and ``flip_mask`` allow the
- specification of any binary operation on the filter control. For
- typical operations, the parameters should be set as follows:
-
- ============ ============== =============
- Operation ``reset_mask`` ``flip_mask``
- ============ ============== =============
- ``set(M)`` ``M`` ``M``
- ------------ -------------- -------------
- ``reset(M)`` ``M`` ``0``
- ------------ -------------- -------------
- ``flip(M)`` ``0`` ``M``
- ------------ -------------- -------------
- ``read()`` ``0`` ``0``
- ============ ============== =============
-
-
.. c:function:: void mps_telemetry_flush(void)
Flush the internal event buffers into the :term:`telemetry stream`.
diff --git a/mps/manual/source/topic/thread.rst b/mps/manual/source/topic/thread.rst
index 0a4156613ac..9417c473b04 100644
--- a/mps/manual/source/topic/thread.rst
+++ b/mps/manual/source/topic/thread.rst
@@ -168,47 +168,3 @@ Thread interface
It is recommended that threads be deregistered only when they
are just about to exit.
-
-
-.. c:function:: void mps_tramp(void **r_o, mps_tramp_t f, void *p, size_t s)
-
- .. deprecated:: starting with version 1.111.
-
- Call a function via the MPS trampoline.
-
- ``r_o`` points to a location that will store the result of calling
- ``f``.
-
- ``f`` is the function to call.
-
- ``p`` and ``s`` are arguments that will be passed to ``f`` each
- time it is called. This is intended to make it easy to pass, for
- example, an array and its size as parameters.
-
- The MPS relies on :term:`barriers (1)` to protect memory
- that is in an inconsistent state. On some operating systems,
- barrier hits generate exceptions that have to be caught by a
- handler that is on the stack. On these operating systems, any code
- that uses memory managed by the MPS must be called from inside
- such an exception handler, that is, inside a call to
- :c:func:`mps_tramp`.
-
- If you have multiple threads that run code that uses memory
- managed by the MPS, each thread must execute such code inside a
- call to :c:func:`mps_tramp`.
-
- Starting with version 1.111, this is not required on any operating
- system supported by the MPS.
-
-
-.. index::
- single: trampoline
-
-.. c:type:: void *(*mps_tramp_t)(void *p, size_t s)
-
- .. deprecated:: starting with version 1.111.
-
- The type of a function called by :c:func:`mps_tramp`.
-
- ``p`` and ``s`` are the corresponding arguments that were passed
- to :c:func:`mps_tramp`.
diff --git a/mps/test/README b/mps/test/README
index 08f3f398c36..90edaf8857f 100644
--- a/mps/test/README
+++ b/mps/test/README
@@ -11,18 +11,19 @@ Testing on unix
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
- $ alias qa="perl test/qa -i $CODE -l $CODE/$PLATFORM/cool/mps.o"
- $ qa clib
- $ qa run function/5.c
- $ qa runset testsets/passing
+ PLATFORM=lii6ll # substitute your platform
+ CODE=../code # code directory of the branch you are testing
+ 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
+ qa runset testsets/passing
Each test case is compiled in its turn to the file
``test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test``
so you can debug it with::
- $ lldb test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test
+ lldb test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test
-(Or ``gdb`` instead of ``lldb``.)
+Or ``gdb`` instead of ``lldb``. MMQA sets its own assertion handler,
+so you'll probably want to set a breakpoint on mmqa_assert_handler.
diff --git a/mps/test/argerr/111.c b/mps/test/argerr/111.c
index cba3b7feda8..6f60b0a3269 100644
--- a/mps/test/argerr/111.c
+++ b/mps/test/argerr/111.c
@@ -4,6 +4,10 @@ TEST_HEADER
summary = UNALIGNED base for mps_root_create_table
language = c
link = testlib.o
+OUTPUT_SPEC
+ assert = true
+ assertfile P= root.c
+ assertcond = AddrIsAligned(base, sizeof(Word))
END_HEADER
*/
diff --git a/mps/test/argerr/143.c b/mps/test/argerr/143.c
index 045b8d89893..9099a6c3c13 100644
--- a/mps/test/argerr/143.c
+++ b/mps/test/argerr/143.c
@@ -4,6 +4,10 @@ TEST_HEADER
summary = UNALIGNED stackpointer for mps_root_create_reg
language = c
link = testlib.o
+OUTPUT_SPEC
+ assert = true
+ assertfile P= mpsi.c
+ assertcond = AddrIsAligned(reg_scan_p, sizeof(Word))
END_HEADER
*/
diff --git a/mps/test/argerr/146.c b/mps/test/argerr/146.c
index a2fd7d76910..c6d465671eb 100644
--- a/mps/test/argerr/146.c
+++ b/mps/test/argerr/146.c
@@ -4,6 +4,8 @@ TEST_HEADER
summary = null scan state to fix (function)
language = c
link = testlib.o
+OUTPUT_SPEC
+ abort = true
END_HEADER
*/
@@ -449,7 +451,7 @@ static void test(void)
mps_ap_t ap;
int j;
- mycell *a;
+ mycell *a, *b;
cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena");
@@ -481,9 +483,20 @@ static void test(void)
for (j=1; j<1000; j++)
{
- allocone(ap, 1000);
+ b = allocone(ap, 1000);
+ setref(b, 0, a);
+ a = b;
}
+ mps_arena_collect(arena);
+
+ mps_ap_destroy(ap);
+ mps_pool_destroy(pool);
+ mps_chain_destroy(chain);
+ mps_fmt_destroy(format);
+ mps_root_destroy(root);
+ mps_thread_dereg(thread);
+ mps_arena_destroy(arena);
}
int main(void)
diff --git a/mps/test/argerr/147.c b/mps/test/argerr/147.c
index ecb781e5e39..0b11507cc81 100644
--- a/mps/test/argerr/147.c
+++ b/mps/test/argerr/147.c
@@ -4,6 +4,8 @@ TEST_HEADER
summary = unaligned scan state to fix (function)
language = c
link = testlib.o
+OUTPUT_SPEC
+ abort = true
END_HEADER
*/
@@ -449,7 +451,7 @@ static void test(void)
mps_ap_t ap;
int j;
- mycell *a;
+ mycell *a, *b;
cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena");
@@ -481,7 +483,9 @@ static void test(void)
for (j=1; j<1000; j++)
{
- allocone(ap, 1000);
+ b = allocone(ap, 1000);
+ setref(b, 0, a);
+ a = b;
}
}
diff --git a/mps/test/argerr/148.c b/mps/test/argerr/148.c
index b1ec5cbdd0f..814429c1cdb 100644
--- a/mps/test/argerr/148.c
+++ b/mps/test/argerr/148.c
@@ -4,6 +4,8 @@ TEST_HEADER
summary = null addr to fix (function)
language = c
link = testlib.o
+OUTPUT_SPEC
+ abort = true
END_HEADER
*/
@@ -449,7 +451,7 @@ static void test(void)
mps_ap_t ap;
int j;
- mycell *a;
+ mycell *a, *b;
cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena");
@@ -481,7 +483,9 @@ static void test(void)
for (j=1; j<1000; j++)
{
- allocone(ap, 1000);
+ b = allocone(ap, 1000);
+ setref(b, 0, a);
+ a = b;
}
}
diff --git a/mps/test/argerr/149.c b/mps/test/argerr/149.c
index 422043e8cef..c86d9ce3983 100644
--- a/mps/test/argerr/149.c
+++ b/mps/test/argerr/149.c
@@ -450,7 +450,7 @@ static void test(void)
mps_ap_t ap;
int j;
- mycell *a;
+ mycell *a, *b;
cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena");
@@ -482,7 +482,9 @@ static void test(void)
for (j=1; j<1000; j++)
{
- allocone(ap, 1000);
+ b = allocone(ap, 1000);
+ setref(b, 0, a);
+ a = b;
}
}
diff --git a/mps/test/argerr/150.c b/mps/test/argerr/150.c
index 4be2075aa0e..88d751f5d4a 100644
--- a/mps/test/argerr/150.c
+++ b/mps/test/argerr/150.c
@@ -449,7 +449,7 @@ static void test(void)
mps_ap_t ap;
int j;
- mycell *a;
+ mycell *a, *b;
cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena");
@@ -481,7 +481,9 @@ static void test(void)
for (j=1; j<1000; j++)
{
- allocone(ap, 1000);
+ b = allocone(ap, 1000);
+ setref(b, 0, a);
+ a = b;
}
}
diff --git a/mps/test/argerr/151.c b/mps/test/argerr/151.c
index 6541675947b..19ed2169a93 100644
--- a/mps/test/argerr/151.c
+++ b/mps/test/argerr/151.c
@@ -450,7 +450,7 @@ static void test(void)
mps_ap_t ap;
int j;
- mycell *a;
+ mycell *a, *b;
cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena");
@@ -482,7 +482,9 @@ static void test(void)
for (j=1; j<1000; j++)
{
- allocone(ap, 1000);
+ b = allocone(ap, 1000);
+ setref(b, 0, a);
+ a = b;
}
}
diff --git a/mps/test/argerr/35.c b/mps/test/argerr/35.c
index 4508eac3bff..218721759bf 100644
--- a/mps/test/argerr/35.c
+++ b/mps/test/argerr/35.c
@@ -6,7 +6,7 @@ TEST_HEADER
link = testlib.o
OUTPUT_SPEC
assert = true
- assertfile P= poolmv.c
+ assertfile P= pool.c
assertcond = AddrIsAligned(old, pool->alignment)
END_HEADER
*/
diff --git a/mps/test/argerr/36.c b/mps/test/argerr/36.c
index 8704bc1dc2b..ac35d796cac 100644
--- a/mps/test/argerr/36.c
+++ b/mps/test/argerr/36.c
@@ -4,6 +4,10 @@ TEST_HEADER
summary = wrong size_t to free (MV)
language = c
link = testlib.o
+OUTPUT_SPEC
+ assert = true
+ assertfile P= dbgpool.c
+ assertcond = tag->size == size
END_HEADER
*/
@@ -25,11 +29,8 @@ static void test(void)
cdie(mps_thread_reg(&thread, arena), "register thread");
- cdie(
- mps_pool_create(
- &pool, arena, mps_class_mv(),
- (size_t) 4096, (size_t) 32, (size_t) 64*1024),
- "create pool");
+ cdie(mps_pool_create_k(&pool, arena, mps_class_mv_debug(), mps_args_none),
+ "create pool");
die(mps_alloc(&a, pool, 8),
"alloc a");
diff --git a/mps/test/conerr/22.c b/mps/test/conerr/22.c
index aa371bd68b6..fb020003628 100644
--- a/mps/test/conerr/22.c
+++ b/mps/test/conerr/22.c
@@ -22,7 +22,7 @@ static void test(void)
size_t avgSize;
size_t maxSize;
- mps_addr_t obj = (mps_addr_t)1;
+ mps_addr_t obj = (mps_addr_t)MPS_PF_ALIGN;
extendBy = (size_t) 4096;
avgSize = (size_t) 32;
diff --git a/mps/test/conerr/26.c b/mps/test/conerr/26.c
index 7114c056fc8..8fcabc44357 100644
--- a/mps/test/conerr/26.c
+++ b/mps/test/conerr/26.c
@@ -26,7 +26,7 @@ static void test(void)
cdie(mps_pool_create_k(&pool0, arena, mps_class_mv(), mps_args_none),
"create pool 0");
- cdie(mps_pool_create(&pool1, arena, mps_class_mv(), mps_args_none),
+ cdie(mps_pool_create_k(&pool1, arena, mps_class_mv(), mps_args_none),
"create pool 1");
cdie(mps_alloc(&obj, pool0, 152), "allocate in 0");
diff --git a/mps/test/conerr/3.c b/mps/test/conerr/3.c
index 85f340a5f5b..dae5b202009 100644
--- a/mps/test/conerr/3.c
+++ b/mps/test/conerr/3.c
@@ -1,7 +1,7 @@
/*
TEST_HEADER
id = $Id$
- summary = destroy an arena which isn't an arena, with a pointer in
+ summary = destroy an arena which isn't an arena
language = c
link = testlib.o
OUTPUT_SPEC
@@ -11,13 +11,15 @@ OUTPUT_SPEC
END_HEADER
*/
+#include "mpmst.h"
#include "testlib.h"
static void test(void)
{
+ char buf[sizeof(ArenaStruct)];
mps_arena_t arena;
- arena = (mps_arena_t)&arena;
+ arena = (void *)buf;
mps_arena_destroy(arena);
comment("Destroy arena.");
}
diff --git a/mps/test/function/103.c b/mps/test/function/103.c
index fc4a7fa160a..07a77bf2470 100644
--- a/mps/test/function/103.c
+++ b/mps/test/function/103.c
@@ -32,7 +32,9 @@ static void fillup(void)
mps_addr_t a;
char *b;
- mps_pool_create(&poolmv, arena, mps_class_mv(), 64, 64, 64);
+ die(mps_pool_create(&poolmv, arena, mps_class_mv(),
+ (size_t)64, (size_t)64, (size_t)64),
+ "mps_pool_create");
size=1024ul*1024ul;
while (size) {
while (mps_alloc(&a, poolmv, size)==MPS_RES_OK) {
diff --git a/mps/test/function/120.c b/mps/test/function/120.c
index 915965094c0..4bd55205998 100644
--- a/mps/test/function/120.c
+++ b/mps/test/function/120.c
@@ -27,7 +27,7 @@ void *stackpointer;
mps_arena_t arena;
mps_thr_t thread;
mps_pool_t pool;
-mps_pool_t pools[100];
+mps_pool_t pools[1000];
static void test(void) {
int i;
@@ -100,13 +100,17 @@ static void test(void) {
i = 0;
- while ((i < 100) && (res == MPS_RES_OK)) {
+ while (i < sizeof pools / sizeof pools[0]) {
res = mps_pool_create(&pools[i], arena, mps_class_mv(), (size_t) 64, (size_t) 64, (size_t) 64);
- i++;
+ if (res == MPS_RES_OK) {
+ i++;
+ } else {
+ break;
+ }
}
report_res("poolcr", res);
- for (i -= 2; i >= 0; i--) {
+ for (i--; i >= 0; i--) {
mps_pool_destroy(pools[i]);
}
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;
diff --git a/mps/test/function/137.c b/mps/test/function/137.c
index 178d2f5e628..715dae9b4c8 100644
--- a/mps/test/function/137.c
+++ b/mps/test/function/137.c
@@ -53,10 +53,10 @@ static void test(void) {
mps_arena_commit_limit_set(arena, COMLIMIT1);
- die(
- mps_pool_create(&pool, arena, mps_class_mvff(),
- EXTENDBY, 8, 8, 0, 0, 1),
- "create MVFF pool");
+ die(mps_pool_create(&pool, arena, mps_class_mvff(),
+ (size_t)EXTENDBY, (size_t)8, (mps_align_t)8,
+ (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1),
+ "create MVFF pool");
for (i = 0; i < NSMALL; i++) {
die(mps_alloc(&smallObjects[i], pool, SMALLSIZE), "small alloc failed");
diff --git a/mps/test/function/139.c b/mps/test/function/139.c
index 14537004366..3ba3c2a3395 100644
--- a/mps/test/function/139.c
+++ b/mps/test/function/139.c
@@ -43,10 +43,10 @@ static void test(void) {
mps_arena_commit_limit_set(arena, COMLIMIT1);
- die(
- mps_pool_create(&pool, arena, mps_class_mvff(),
- EXTENDBY, 8, 8, 0, 0, 1),
- "create MVFF pool");
+ die(mps_pool_create(&pool, arena, mps_class_mvff(),
+ (size_t)EXTENDBY, (size_t)8, (mps_align_t)8,
+ (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1),
+ "create MVFF pool");
for (i = 0; i < NSMALL; i++) {
die(mps_alloc(&smallObjects[i], pool, SMALLSIZE), "small alloc failed");
diff --git a/mps/test/function/144.c b/mps/test/function/144.c
index efbcf4d9d29..4343be93fea 100644
--- a/mps/test/function/144.c
+++ b/mps/test/function/144.c
@@ -29,10 +29,10 @@ static void test(void) {
(size_t) (1024*1024*50)), "create arena");
cdie(mps_thread_reg(&thread, arena), "register thread");
- die(
- mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts,
- 8192, 8, 8, 0, 0, 1),
- "create MVFF pool");
+ die(mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts,
+ (size_t)8192, (size_t)8, (mps_align_t)8,
+ (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1),
+ "create MVFF pool");
die(mps_alloc(&a, pool, 64), "alloc a");
die(mps_alloc(&b, pool, 64), "alloc b");
diff --git a/mps/test/function/150.c b/mps/test/function/150.c
index 78eec6b2647..c8496f3d662 100644
--- a/mps/test/function/150.c
+++ b/mps/test/function/150.c
@@ -195,13 +195,12 @@ static void test(void)
/* register loads of objects for finalization (1000*4) */
a = allocone(apamc, 2, 1);
- b = a;
for (j=0; j<1000; j++) {
- a = allocone(apamc, 2, mps_rank_exact());
+ b = allocone(apamc, 2, mps_rank_exact());
c = allocone(apawl, 2, mps_rank_weak());
d = allocone(aplo, 2, mps_rank_exact()); /* rank irrelevant here! */
- mps_finalize(arena, (mps_addr_t*)&a);
+ mps_finalize(arena, (mps_addr_t*)&b);
mps_finalize(arena, (mps_addr_t*)&c);
mps_finalize(arena, (mps_addr_t*)&d);
mps_finalize(arena, (mps_addr_t*)&d);
@@ -209,7 +208,7 @@ static void test(void)
setref(a, 0, b);
setref(a, 1, c);
setref(c, 1, d);
- b = a;
+ a = b;
}
/* throw them all away and collect everything */
diff --git a/mps/test/function/158.c b/mps/test/function/158.c
index b257d879f30..7f54823d1db 100644
--- a/mps/test/function/158.c
+++ b/mps/test/function/158.c
@@ -29,10 +29,10 @@ static void test(void) {
(size_t) (1024*1024*50)), "create arena");
cdie(mps_thread_reg(&thread, arena), "register thread");
- die(
- mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts,
- 8192, 8, 8, 1, 0, 0),
- "create MVFF pool");
+ die(mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts,
+ (size_t)8192, (size_t)8, (mps_align_t)8,
+ (mps_bool_t)1, (mps_bool_t)0, (mps_bool_t)0),
+ "create MVFF pool");
die(mps_alloc(&a, pool, 64), "alloc a");
diff --git a/mps/test/function/159.c b/mps/test/function/159.c
index d3fb350003f..987824dd737 100644
--- a/mps/test/function/159.c
+++ b/mps/test/function/159.c
@@ -29,10 +29,10 @@ static void test(void) {
(size_t) (1024*1024*50)), "create arena");
cdie(mps_thread_reg(&thread, arena), "register thread");
- die(
- mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts,
- 8192, 8, 8, 0, 1, 0),
- "create MVFF pool");
+ die(mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts,
+ (size_t)8192, (size_t)8, (mps_align_t)8,
+ (mps_bool_t)0, (mps_bool_t)1, (mps_bool_t)0),
+ "create MVFF pool");
die(mps_alloc(&a, pool, 63), "alloc a");
diff --git a/mps/test/function/160.c b/mps/test/function/160.c
index 4c58a5058aa..af5b017e2a7 100644
--- a/mps/test/function/160.c
+++ b/mps/test/function/160.c
@@ -29,10 +29,9 @@ static void test(void) {
(size_t) (1024*1024*50)), "create arena");
cdie(mps_thread_reg(&thread, arena), "register thread");
- die(
- mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts,
- 8192, 8, 65536),
- "create MVFF pool");
+ die(mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts,
+ (size_t)8192, (size_t)8, (size_t)65536),
+ "create MV pool");
die(mps_alloc(&a, pool, 64), "alloc a");
diff --git a/mps/test/function/161.c b/mps/test/function/161.c
index 93ede5ed738..23a0fb8be14 100644
--- a/mps/test/function/161.c
+++ b/mps/test/function/161.c
@@ -32,10 +32,9 @@ static void test(void)
(size_t) (1024*1024*50)), "create arena");
cdie(mps_thread_reg(&thread, arena), "register thread");
- die(
- mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts,
- 8192, 8, 65536),
- "create MVFF pool");
+ die(mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts,
+ (size_t)8192, (size_t)8, (size_t)65536),
+ "create MVFF pool");
die(mps_alloc(&a, pool, 64), "alloc a");
diff --git a/mps/test/function/162.c b/mps/test/function/162.c
index 05245b7191c..8967b95b269 100644
--- a/mps/test/function/162.c
+++ b/mps/test/function/162.c
@@ -29,10 +29,9 @@ static void test(void) {
(size_t) (1024*1024*50)), "create arena");
cdie(mps_thread_reg(&thread, arena), "register thread");
- die(
- mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts,
- 8192, 8, 65536),
- "create MVFF pool");
+ die(mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts,
+ (size_t)8192, (size_t)8, (size_t)65536),
+ "create MVFF pool");
die(mps_alloc(&a, pool, 63), "alloc a");
diff --git a/mps/test/function/163.c b/mps/test/function/163.c
index 90e04b83b23..9b735a076fa 100644
--- a/mps/test/function/163.c
+++ b/mps/test/function/163.c
@@ -53,10 +53,10 @@ static void test(void) {
mps_arena_commit_limit_set(arena, COMLIMIT1);
- die(
- mps_pool_create(&pool, arena, mps_class_mvff(),
- EXTENDBY, 8, MPS_PF_ALIGN, 0, 0, 1),
- "create MVFF pool");
+ die(mps_pool_create(&pool, arena, mps_class_mvff(),
+ (size_t)EXTENDBY, (size_t)8, (mps_align_t)MPS_PF_ALIGN,
+ (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1),
+ "create MVFF pool");
for (i = 0; i < NSMALL; i++) {
die(mps_alloc(&smallObjects[i], pool, SMALLSIZE), "small alloc failed");
diff --git a/mps/test/function/18.c b/mps/test/function/18.c
index 60a17e52d57..45f1a0fe8cc 100644
--- a/mps/test/function/18.c
+++ b/mps/test/function/18.c
@@ -5,7 +5,7 @@ TEST_HEADER
language = c
link = testlib.o newfmt.o
OUTPUT_SPEC
- errtext = create pool: COMMIT_LIMIT
+ errtext = create AMC pool: COMMIT_LIMIT
END_HEADER
*/
@@ -48,8 +48,8 @@ static void test(void)
die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
die(mps_pool_create(&pool, arena, mps_class_mv(),
- 1024*32, 1024*16, 1024*256),
- "pool");
+ (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)),
+ "create MV pool");
do {
res = mps_alloc(&q, pool, 64*1024);
@@ -60,7 +60,7 @@ static void test(void)
while (1) {
p++;
die(mmqa_pool_create_chain(&pool, arena, mps_class_amc(), format, chain),
- "create pool");
+ "create AMC pool");
report("pool", "%i", p);
}
diff --git a/mps/test/function/19.c b/mps/test/function/19.c
index bdbe02f88f8..15fdecd9018 100644
--- a/mps/test/function/19.c
+++ b/mps/test/function/19.c
@@ -49,14 +49,14 @@ static void test(void)
die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
die(mps_pool_create(&pool, arena, mps_class_mv(),
- 1024*32, 1024*16, 1024*256),
- "pool");
+ (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)),
+ "create MV pool");
while (mps_alloc(&q, pool, 64*1024)==MPS_RES_OK);
p = 0;
cdie(mmqa_pool_create_chain(&pool, arena, mps_class_amc(), format, chain),
- "create pool");
+ "create AMC pool");
while (1) {
p++;
diff --git a/mps/test/function/20.c b/mps/test/function/20.c
index b66f96d4e67..3cec79e7df3 100644
--- a/mps/test/function/20.c
+++ b/mps/test/function/20.c
@@ -33,7 +33,8 @@ static void test(void) {
mps_stack_scan_ambig, stackpointer, 0), "create root");
die(mps_pool_create(&pool, arena, mps_class_mv(),
- 1024*32, 1024*16, 1024*256), "pool");
+ (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)),
+ "create MV pool");
while (mps_alloc(&q, pool, 64*1024)==MPS_RES_OK);
p=0;
diff --git a/mps/test/function/21.c b/mps/test/function/21.c
index d7e12e266ff..7b493f6602f 100644
--- a/mps/test/function/21.c
+++ b/mps/test/function/21.c
@@ -19,7 +19,8 @@ static void test(void) {
die(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create");
die(mps_pool_create(&pool, arena, mps_class_mv(),
- 1024*32, 1024*16, 1024*256), "pool");
+ (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)),
+ "create MV pool");
for (p=0; p<2000; p++) {
die(mps_alloc(&q, pool, 1024*1024), "alloc");
diff --git a/mps/test/function/22.c b/mps/test/function/22.c
index cbdaa909898..8927643e49f 100644
--- a/mps/test/function/22.c
+++ b/mps/test/function/22.c
@@ -19,7 +19,8 @@ static void test(void) {
die(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create");
die(mps_pool_create(&pool, arena, mps_class_mv(),
- 1024*32, 1024*16, 1024*256), "pool");
+ (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)),
+ "create MV pool");
die(mps_alloc(&q, pool, 1024*1024), "alloc");
diff --git a/mps/test/function/224.c b/mps/test/function/224.c
index 0cec33e1cd8..ec828bd9026 100644
--- a/mps/test/function/224.c
+++ b/mps/test/function/224.c
@@ -32,7 +32,7 @@ static void test(void)
die(mps_arena_commit_limit_set(arena, VMSIZE), "commit limit");
die(mps_pool_create(&pool, arena, mps_class_mv(),
- EXTENDBY, AVGSIZE, EXTENDBY),
+ (size_t)EXTENDBY, (size_t)AVGSIZE, (size_t)EXTENDBY),
"pool create");
for (p=0; psize = size;
+ return header + 1;
+}
+
+static void xfree(void *p)
+{
+ if (p) {
+ header_u *header = ((header_u *)p) - 1;
+ mps_free(malloc_pool, header, header->size);
+ }
+}
+
+static void test(void)
+{
+ mps_arena_t arena;
+ size_t i, j;
+ void *p[POINTERS] = {0};
+
+ cdie(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none),
+ "create arena");
+ cdie(mps_pool_create_k(&malloc_pool, arena, mps_class_mvff(), mps_args_none),
+ "create pool");
+
+ for (i = 0; i < ITERATIONS; ++i) {
+ j = ranint(POINTERS);
+ xfree(p[j]);
+ p[j] = xmalloc(ranint(POINTERS));
+ }
+ for (j = 0; j < POINTERS; ++j) {
+ xfree(p[j]);
+ }
+ asserts(mps_pool_free_size(malloc_pool) == mps_pool_total_size(malloc_pool),
+ "free size != total_size");
+
+ mps_pool_destroy(malloc_pool);
+ mps_arena_destroy(arena);
+}
+
+int main(void)
+{
+ easy_tramp(test);
+ pass();
+ return 0;
+}
diff --git a/mps/test/function/23.c b/mps/test/function/23.c
index afcf764a059..2046aa56b92 100644
--- a/mps/test/function/23.c
+++ b/mps/test/function/23.c
@@ -19,7 +19,9 @@ END_HEADER
#include "mpsavm.h"
#include "newfmt.h"
-
+#define EXTEND_BY ((size_t)(1024*128))
+#define MEAN_SIZE ((size_t)(1024*64))
+#define MAX_SIZE ((size_t)(1024*1024))
#define genCOUNT (3)
static mps_gen_param_s testChain[genCOUNT] = {
@@ -66,7 +68,7 @@ static void test(void)
comment("Sizes in megabytes:");
die(mps_pool_create(&poolMV, arena, mps_class_mv(),
- 1024*128, 1024*64, 1024*1024),
+ EXTEND_BY, MEAN_SIZE, MAX_SIZE),
"create MV pool");
i = 0;
while ((r=mps_alloc(&p, poolMV, 1024*1024)) == 0) i++;
@@ -76,7 +78,7 @@ static void test(void)
mps_pool_destroy(poolMV);
die(mps_pool_create(&poolMV, arena, mps_class_mv(),
- 1024*128, 1024*64, 1024*1024),
+ EXTEND_BY, MEAN_SIZE, MAX_SIZE),
"create MV pool");
i = 0;
while ((r=mps_alloc(&p, poolMV, 1024*1024)) == 0) i++;
@@ -88,7 +90,7 @@ static void test(void)
a = allocdumb(ap, 1024*1024*30); /* allocate 30 M object */
die(mps_pool_create(&poolMV, arena, mps_class_mv(),
- 1024*128, 1024*64, 1024*1024),
+ EXTEND_BY, MEAN_SIZE, MAX_SIZE),
"create MV pool");
i=0;
while ((r=mps_alloc(&p, poolMV, 1024*1024)) == 0) i++;
diff --git a/mps/test/function/96.c b/mps/test/function/96.c
index 210fbf46542..6504674cf41 100644
--- a/mps/test/function/96.c
+++ b/mps/test/function/96.c
@@ -32,7 +32,9 @@ static void fillup(void)
mps_addr_t a;
char *b;
- mps_pool_create(&poolmv, arena, mps_class_mv(), 64, 64, 64);
+ die(mps_pool_create(&poolmv, arena, mps_class_mv(),
+ (size_t)64, (size_t)64, (size_t)64),
+ "create MV pool");
size=1024ul*1024ul;
while (size) {
while (mps_alloc(&a, poolmv, size)==MPS_RES_OK) {
@@ -116,7 +118,9 @@ static void test(void)
for (j=0; j<1000*1024; j++) {
res=allocrdumb(&a, ap, 1024, mps_rank_exact());
if (res == MPS_RES_OK) {
- comment("%i ok", j);
+ if (j % 100000 == 0) {
+ comment("%i ok", j);
+ }
} else {
break;
}
diff --git a/mps/test/test/script/clib b/mps/test/test/script/clib
index be1a45c4fb3..6552a20b3b7 100644
--- a/mps/test/test/script/clib
+++ b/mps/test/test/script/clib
@@ -22,7 +22,7 @@ sub clib {
while (defined($tlfile = )) {
unless ($tlfile =~ /^%/) {
- chop($tlfile);
+ chomp($tlfile);
$tlfile = $testlib_dir."/".$tlfile;
$tlobj = $tlfile;
$tlobj =~ s/\.c/$obj_suffix/;
@@ -326,7 +326,7 @@ sub readSymbols {
}
while () {
- chop;
+ chomp;
if (/#define MMQA_SYMBOL_(.*)$/) {
$mps_symbols{$1} = 1;
} elsif (/#define MMQA_DEFINED_(.*)$/) {
@@ -340,7 +340,7 @@ sub readSymbols {
}
while () {
- chop;
+ chomp;
unless (/^%/) {
$mps_assumed{$_} = 1;
}
diff --git a/mps/test/test/script/headread b/mps/test/test/script/headread
index 8f5c35ca7b6..794027763b2 100644
--- a/mps/test/test/script/headread
+++ b/mps/test/test/script/headread
@@ -48,7 +48,7 @@ sub readheader {
$line = $_;
while (! /END_HEADER/) {
defined($_=) || die "Couldn't find end of test header in $infile.\n";
- chop;
+ chomp;
if ($line =~ /\\$/) {
chop($line);
$line = $line.$_;
diff --git a/mps/test/test/script/options b/mps/test/test/script/options
index 023b1f5c7ae..5ef905a09fb 100644
--- a/mps/test/test/script/options
+++ b/mps/test/test/script/options
@@ -26,7 +26,7 @@ sub platform_detect {
local $os = `uname`;
local $osrel = `uname -r`;
local $processor = `uname -p`;
- chop($os); chop($osrel); chop($processor);
+ chomp($os); chomp($osrel); chomp($processor);
$platform_class = $os."_".$osrel."_".$processor;
$platform_class =~ s/ /_/g;
$platform_phylum = "unix";
diff --git a/mps/test/test/script/runtest b/mps/test/test/script/runtest
index b540843eab4..64269c4382d 100644
--- a/mps/test/test/script/runtest
+++ b/mps/test/test/script/runtest
@@ -241,7 +241,7 @@ sub run_testset {
} else {
while () {
unless (/(^%)|(^\s*$)/) {
- chop;
+ chomp;
&run_from_testset($_);
}
}
diff --git a/mps/test/testsets/argerr b/mps/test/testsets/argerr
index cfea284dfd7..990040192b4 100644
--- a/mps/test/testsets/argerr
+++ b/mps/test/testsets/argerr
@@ -80,14 +80,14 @@ argerr/78.c
argerr/79.c
argerr/80.c
argerr/81.c
-argerr/82.c
-argerr/83.c
+% argerr/82.c -- see
+% argerr/83.c -- see
argerr/84.c
argerr/85.c
argerr/86.c
argerr/87.c
-argerr/88.c
-argerr/89.c
+% argerr/88.c -- see
+% argerr/89.c -- see
argerr/90.c
argerr/91.c
argerr/92.c
@@ -111,7 +111,7 @@ argerr/109.c
argerr/110.c
argerr/111.c
argerr/112.c
-argerr/113.c
+% argerr/113.c -- last argument to mps_root_create_table is count, not size
argerr/114.c
argerr/115.c
argerr/116.c
@@ -124,9 +124,9 @@ argerr/122.c
argerr/123.c
argerr/124.c
argerr/125.c
-argerr/126.c
+% argerr/126.c -- see
argerr/127.c
-argerr/128.c
+% argerr/128.c -- see
argerr/129.c
argerr/130.c
argerr/131.c
@@ -147,9 +147,9 @@ argerr/145.c
argerr/146.c
argerr/147.c
argerr/148.c
-argerr/149.c
-argerr/150.c
-argerr/151.c
-argerr/152.c
+% argerr/149.c -- you're allowed to fix non-references
+% argerr/150.c -- you're allowed to fix non-references
+% argerr/151.c -- you're allowed to fix unaligned references
+% argerr/152.c -- no way to check this
argerr/153.c
argerr/154.c
diff --git a/mps/test/testsets/conerr b/mps/test/testsets/conerr
index 3f108a9cb0f..12966b681a0 100644
--- a/mps/test/testsets/conerr
+++ b/mps/test/testsets/conerr
@@ -10,7 +10,7 @@ conerr/8.c
conerr/9.c
conerr/10.c
conerr/11.c
-conerr/12.c
+% conerr/12.c -- job003889
conerr/13.c
conerr/14.c
conerr/15.c
@@ -31,17 +31,17 @@ conerr/29.c
conerr/30.c
conerr/31.c
conerr/32.c
-conerr/33.c
+% conerr/33.c -- job003791
conerr/34.c
conerr/35.c
conerr/36.c
-conerr/37.c
+% conerr/37.c -- reserve/commit macros don't check arguments
conerr/37f.c
-conerr/38.c
+% conerr/38.c -- reserve/commit macros don't check arguments
conerr/38f.c
-conerr/39.c
+% conerr/39.c -- reserve/commit macros don't check arguments
conerr/39f.c
-conerr/40.c
+% conerr/40.c -- reserve/commit macros don't check arguments
conerr/40f.c
conerr/41.c
conerr/42.c
@@ -52,7 +52,7 @@ conerr/45.c
conerr/46.c
conerr/47.c
conerr/48.c
-conerr/49.c
+% conerr/49.c -- see design.mps.thread-manager.req.register.multi
conerr/50.c
conerr/51.c
conerr/52.c
@@ -60,6 +60,6 @@ conerr/53.c
conerr/54.c
conerr/55.c
conerr/56.c
-conerr/57.c
-conerr/58.c
+% conerr/57.c -- see