From e05a3f745513b6b5b85d50c798e67dde294c5074 Mon Sep 17 00:00:00 2001 From: David Lovemore Date: Mon, 18 Aug 2014 10:42:47 +0100 Subject: [PATCH 001/337] Branching master to branch/2014-08-18/non-incremental. Copied from Perforce Change: 186962 ServerID: perforce.ravenbrook.com From 858954c95e802e8b790039f083d3eb8110ca34ea Mon Sep 17 00:00:00 2001 From: David Lovemore Date: Mon, 18 Aug 2014 12:06:03 +0100 Subject: [PATCH 002/337] Collections now non-incremental. simple change to tracepoll to make collections do work until they are finished. Copied from Perforce Change: 186964 ServerID: perforce.ravenbrook.com --- mps/code/trace.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mps/code/trace.c b/mps/code/trace.c index 163d8b63a39..71d062a3e45 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1817,6 +1817,7 @@ Size TracePoll(Globals globals) Res res; Arena arena; Size scannedSize; + Bool incremental = FALSE; AVERT(Globals, globals); arena = GlobalsArena(globals); @@ -1888,7 +1889,9 @@ Size TracePoll(Globals globals) trace = ArenaTrace(arena, (TraceId)0); AVER(arena->busyTraces == TraceSetSingle(trace)); oldScanned = traceWorkClock(trace); - TraceQuantum(trace); + do { + TraceQuantum(trace); + } while(!incremental && trace->state != TraceFINISHED); scannedSize = traceWorkClock(trace) - oldScanned; if(trace->state == TraceFINISHED) { TraceDestroy(trace); From 8c9353fe341b62437b43a61b46315b373ed73535 Mon Sep 17 00:00:00 2001 From: David Lovemore Date: Wed, 20 Aug 2014 13:03:20 +0100 Subject: [PATCH 003/337] Add mps_key_arena_incremental option. Avoid read and write barrier in non-incremental mode. Add --non-incremental option to gcbench Copied from Perforce Change: 186969 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 6 ++++++ mps/code/config.h | 2 ++ mps/code/gcbench.c | 10 +++++++++- mps/code/mpmst.h | 1 + mps/code/mps.h | 3 +++ mps/code/seg.c | 17 +++++++++-------- mps/code/trace.c | 22 +++++++++++++--------- 7 files changed, 43 insertions(+), 18 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index afff836f647..dab6f300349 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -193,6 +193,7 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) { Res res; Bool zoned = ARENA_DEFAULT_ZONED; + Bool incremental = ARENA_DEFAULT_INCREMENTAL; mps_arg_s arg; AVER(arena != NULL); @@ -202,6 +203,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_INCREMENTAL)) + incremental = arg.val.b; + arena->class = class; arena->committed = (Size)0; @@ -219,6 +223,7 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) arena->hasFreeLand = FALSE; arena->freeZones = ZoneSetUNIV; arena->zoned = zoned; + arena->incremental = incremental; arena->primary = NULL; RingInit(&arena->chunkRing); @@ -296,6 +301,7 @@ ARG_DEFINE_KEY(vmw3_top_down, Bool); ARG_DEFINE_KEY(arena_size, Size); ARG_DEFINE_KEY(arena_grain_size, Size); ARG_DEFINE_KEY(arena_zoned, Bool); +ARG_DEFINE_KEY(arena_incremental, Bool); Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args) { diff --git a/mps/code/config.h b/mps/code/config.h index c0441d1050c..ac5d7a849ec 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -408,6 +408,8 @@ #define ARENA_DEFAULT_ZONED TRUE +#define ARENA_DEFAULT_INCREMENTAL TRUE + #define ArenaDefaultZONESET (ZoneSetUNIV << (MPS_WORD_WIDTH / 2)) /* 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 diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c index 0dc3ef3ded8..3bc1a7ef8eb 100644 --- a/mps/code/gcbench.c +++ b/mps/code/gcbench.c @@ -50,6 +50,7 @@ static size_t arena_size = 256ul * 1024 * 1024; /* arena size */ static size_t arena_grain_size = 1; /* arena grain size */ static unsigned pinleaf = FALSE; /* are leaf objects pinned at start */ static mps_bool_t zoned = TRUE; /* arena allocates using zones */ +static mps_bool_t incremental = TRUE; /* arena allocates using zones */ typedef struct gcthread_s *gcthread_t; @@ -231,6 +232,7 @@ static void arena_setup(gcthread_fn_t fn, MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, arena_size); MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, arena_grain_size); MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, zoned); + MPS_ARGS_ADD(args, MPS_KEY_ARENA_INCREMENTAL, incremental); RESMUST(mps_arena_create_k(&arena, mps_arena_class_vm(), args)); } MPS_ARGS_END(args); RESMUST(dylan_fmt(&format, arena)); @@ -274,6 +276,7 @@ static struct option longopts[] = { {"pin-leaf", no_argument, NULL, 'l'}, {"seed", required_argument, NULL, 'x'}, {"arena-unzoned", no_argument, NULL, 'z'}, + {"non-incremental", no_argument, NULL, 'I'}, {NULL, 0, NULL, 0 } }; @@ -303,7 +306,7 @@ int main(int argc, char *argv[]) { } putchar('\n'); - while ((ch = getopt_long(argc, argv, "ht:i:p:g:m:a:w:d:r:u:lx:z", longopts, NULL)) != -1) + while ((ch = getopt_long(argc, argv, "ht:i:p:g:m:a:w:d:r:u:lx:zI", longopts, NULL)) != -1) switch (ch) { case 't': nthreads = (unsigned)strtoul(optarg, NULL, 10); @@ -392,6 +395,9 @@ int main(int argc, char *argv[]) { case 'z': zoned = FALSE; break; + case 'I': + incremental = FALSE; + break; default: /* This is printed in parts to keep within the 509 character limit for string literals in portable standard C. */ @@ -437,6 +443,8 @@ int main(int argc, char *argv[]) { fprintf(stderr, " -z, --arena-unzoned\n" " Disable zoned allocation in the arena\n" + " -I, --non-incremental\n" + " Disable incremental collection\n" "Tests:\n" " amc pool class AMC\n" " ams pool class AMS\n"); diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 50945d573d4..219858f0f54 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -741,6 +741,7 @@ typedef struct mps_arena_s { CBSStruct freeLandStruct; ZoneSet freeZones; /* zones not yet allocated */ Bool zoned; /* use zoned allocation? */ + Bool incremental; /* perform gc incrementally */ /* locus fields () */ 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 +% conerr/58.c -- see conerr/59.c diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index bf298aae0b2..fde2ca5de8d 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -167,3 +167,5 @@ function/223.c function/224.c % 225 -- no such test function/226.c +function/227.c +function/229.c \ No newline at end of file diff --git a/mps/tool/testrun.bat b/mps/tool/testrun.bat index 2aaf8aa4956..5e9c0606ab7 100755 --- a/mps/tool/testrun.bat +++ b/mps/tool/testrun.bat @@ -35,11 +35,11 @@ mkdir %LOGDIR% @rem Determine which tests to run. set EXCLUDE= -if "%TESTSUITE%"=="testrun" set EXCLUDE=LNX -if "%TESTSUITE%"=="testci" set EXCLUDE=BNX -if "%TESTSUITE%"=="testall" set EXCLUDE=NX -if "%TESTSUITE%"=="testansi" set EXCLUDE=LNTX -if "%TESTSUITE%"=="testpoll" set EXCLUDE=LNPTX +if "%TESTSUITE%"=="testrun" set EXCLUDE=LNX +if "%TESTSUITE%"=="testci" set EXCLUDE=BNX +if "%TESTSUITE%"=="testall" set EXCLUDE=NX +if "%TESTSUITE%"=="testansi" set EXCLUDE=LNTX +if "%TESTSUITE%"=="testpollnone" set EXCLUDE=LNPTX @rem Ensure that test cases don't pop up dialog box on abort() set MPS_TESTLIB_NOABORT=true diff --git a/mps/tool/testrun.sh b/mps/tool/testrun.sh index cdb41ac458b..6ea7dfcb4dc 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -12,9 +12,9 @@ # # Usage:: # -# testrun.sh DIR ( SUITE | CASE1 CASE2 [...] ) +# testrun.sh [-s SUITE] [-r RUNNER] DIR [CASE1 CASE2 ...] # -# You can use this feature to run the same test many times, to get +# You can use this program to run the same test many times, to get # lots of random coverage. For example:: # # yes amcss | head -100 | xargs tool/testrun.sh code/xc/Debug @@ -22,38 +22,58 @@ # This runs the AMC stress test 100 times from the code/xc/Debug # directory, reporting all failures. +echo "MPS test suite" + +TEST_RUNNER= +TEST_CASES= + +# Parse command-line arguments. +while [ $# -gt 0 ]; do + case "$1" in + -s) + TEST_SUITE=$2 + case "$TEST_SUITE" in + testrun) EXCLUDE="LNW" ;; + testci) EXCLUDE="BNW" ;; + testall) EXCLUDE="NW" ;; + testansi) EXCLUDE="LNTW" ;; + testpollnone) EXCLUDE="LNPTW" ;; + *) + echo "Test suite $TEST_SUITE not recognized." + exit 1 ;; + esac + echo "Test suite: $TEST_SUITE" + TEST_CASE_DB=$(dirname -- "$0")/testcases.txt + TEST_CASES=$(<"$TEST_CASE_DB" grep -e '^[a-z]' | + grep -v -e "=[$EXCLUDE]" | + cut -d' ' -f1) + shift 2 + ;; + -r) + TEST_RUNNER=$2 + shift 2 + ;; + -*) + echo "Unrecognized option $1" + exit 1 + ;; + *) + break + ;; + esac +done + # Make a temporary output directory for the test logs. LOGDIR=$(mktemp -d /tmp/mps.log.XXXXXX) -echo "MPS test suite" echo "Logging test output to $LOGDIR" - -# First argument is the directory containing the test cases. + +# Next argument is the directory containing the test cases. TEST_DIR=$1 shift echo "Test directory: $TEST_DIR" # Determine which tests to run. -TEST_CASE_DB=$(dirname -- "$0")/testcases.txt -if [ $# -eq 1 ]; then - TEST_SUITE=$1 - echo "Test suite: $TEST_SUITE" - case $TEST_SUITE in - testrun) EXCLUDE="LNW" ;; - testci) EXCLUDE="BNW" ;; - testall) EXCLUDE="NW" ;; - testansi) EXCLUDE="LNTW" ;; - testpoll) EXCLUDE="LNPTW" ;; - *) - echo "Test suite $TEST_SUITE not recognized." - exit 1 ;; - esac - TEST_CASES=$(<"$TEST_CASE_DB" grep -e '^[a-z]' | - grep -v -e "=[$EXCLUDE]" | - cut -d' ' -f1) -else - echo "$# test cases from the command line" - TEST_CASES=$* -fi +TEST_CASES="$TEST_CASES $*" SEPARATOR=---------------------------------------- TEST_COUNT=0 @@ -67,16 +87,16 @@ for TESTCASE in $TEST_CASES; do export MPS_TELEMETRY_FILENAME echo "Running $TEST" - TEST_COUNT=$(expr $TEST_COUNT + 1) - if "$TEST_DIR/$TESTCASE" > "$LOGTEST" 2>&1; then - PASS_COUNT=$(expr $PASS_COUNT + 1) + TEST_COUNT=$((TEST_COUNT + 1)) + if $TEST_RUNNER "$TEST_DIR/$TESTCASE" > "$LOGTEST" 2>&1; then + PASS_COUNT=$((PASS_COUNT + 1)) else echo "$TEST failed: log follows" echo ${SEPARATOR}${SEPARATOR} cat -- "$LOGTEST" echo echo ${SEPARATOR}${SEPARATOR} - FAIL_COUNT=$(expr $FAIL_COUNT + 1) + FAIL_COUNT=$((FAIL_COUNT + 1)) fi if [ -f "$MPS_TELEMETRY_FILENAME" ]; then From 0141cc951ae7b0f5666467ec31a66fc2e06c1489 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 19 Jan 2016 16:23:39 +0000 Subject: [PATCH 102/337] Resolving review issues in . Improving documentation. Fixing minor type misuse. Copied from Perforce Change: 188922 ServerID: perforce.ravenbrook.com --- mps/code/thix.c | 7 +++++-- mps/code/thxc.c | 9 ++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/mps/code/thix.c b/mps/code/thix.c index be1b1f770ae..c1a31c6e902 100644 --- a/mps/code/thix.c +++ b/mps/code/thix.c @@ -137,10 +137,11 @@ void ThreadDeregister(Thread thread, Arena arena) * each one except the current thread. * * Threads that are found to be dead (that is, if func returns FALSE) - * are moved to deadRing. + * are moved to deadRing, in order to implement + * design.thread-manager.sol.thread.term.attempt. */ -static void mapThreadRing(Ring threadRing, Ring deadRing, Res (*func)(Thread)) +static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread)) { Ring node, next; pthread_t self; @@ -178,6 +179,7 @@ static Bool threadSuspend(Thread thread) res = PThreadextSuspend(&thread->thrextStruct, &thread->mfc); AVER(res == ResOK); AVER(thread->mfc != NULL); + /* design.thread-manager.sol.thread.term.attempt */ return res == ResOK; } @@ -201,6 +203,7 @@ static Bool threadResume(Thread thread) res = PThreadextResume(&thread->thrextStruct); AVER(res == ResOK); thread->mfc = NULL; + /* design.thread-manager.sol.thread.term.attempt */ return res == ResOK; } diff --git a/mps/code/thxc.c b/mps/code/thxc.c index b4d7c4188f0..6ecc1ea726e 100644 --- a/mps/code/thxc.c +++ b/mps/code/thxc.c @@ -115,7 +115,8 @@ void ThreadDeregister(Thread thread, Arena arena) * 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. + * are marked as dead and moved to deadRing, in order to implement + * design.thread-manager.sol.thread.term.attempt. */ static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread)) @@ -151,6 +152,9 @@ static Bool threadSuspend(Thread thread) /* No rendezvous is necessary: thread_suspend "prevents the thread * from executing any more user-level instructions" */ AVER(kern_return == KERN_SUCCESS); + /* Experimentally, values other then KERN_SUCCESS indicate the thread has + terminated . */ + /* design.thread-manager.sol.thread.term.attempt */ return kern_return == KERN_SUCCESS; } @@ -160,6 +164,9 @@ static Bool threadResume(Thread thread) kern_return = thread_resume(thread->port); /* Mach has no equivalent of EAGAIN. */ AVER(kern_return == KERN_SUCCESS); + /* Experimentally, values other then KERN_SUCCESS indicate the thread has + terminated . */ + /* design.thread-manager.sol.thread.term.attempt */ return kern_return == KERN_SUCCESS; } From 7203f2f03aa76008f87c9bed596dcbe48ea2d533 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 20 Jan 2016 11:44:28 +0000 Subject: [PATCH 103/337] Adding reference to job for improving definalization. see . Copied from Perforce Change: 188929 ServerID: perforce.ravenbrook.com --- mps/code/poolmrg.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mps/code/poolmrg.c b/mps/code/poolmrg.c index f329b87f110..2cb5e7a2f21 100644 --- a/mps/code/poolmrg.c +++ b/mps/code/poolmrg.c @@ -745,7 +745,12 @@ Res MRGRegister(Pool pool, Ref ref) } -/* MRGDeregister -- deregister (once) an object for finalization */ +/* MRGDeregister -- deregister (once) an object for finalization + * + * TODO: Definalization loops over all finalizable objects in the heap, + * and so using it could accidentally be disastrous for performance. + * See job003953 and back out changelist 187123 if this is fixed. + */ Res MRGDeregister(Pool pool, Ref obj) { From 8179e2699b5ad404b41dd497a0e62679e55ca894 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 28 Jan 2016 15:52:48 +0000 Subject: [PATCH 104/337] Mps git repository renamed from mps-temporary to mps. Copied from Perforce Change: 189034 ServerID: perforce.ravenbrook.com --- mps/procedure/release-build.rst | 7 ++++--- mps/procedure/version-create.rst | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mps/procedure/release-build.rst b/mps/procedure/release-build.rst index c35f3a25610..cf07cee0620 100644 --- a/mps/procedure/release-build.rst +++ b/mps/procedure/release-build.rst @@ -33,7 +33,7 @@ All relative paths are relative to .. _version-create: version-create -#. Make sure that you have rights to push to the ``mps-temporary`` +#. Make sure that you have rights to push to the ``mps`` repository on GitHub. If not, follow the `Becoming a Ravenbrook team member procedure `_ first. @@ -218,10 +218,10 @@ On a Unix (including OS X) machine: Memory Pool System Kit release $RELEASE. See . END - git push --tags git@github.com:Ravenbrook/mps-temporary.git + git push --tags git@github.com:Ravenbrook/mps.git #. Go to the `list of releases on Github - `__ and + `__ and select "Draft a new release". Select the tag you just pushed, and set the title and description to match the other releases. @@ -259,6 +259,7 @@ B. Document History 2012‑09‑24 RB_ Make sure ZIP files contain files with Windows line endings. Use a fresh Perforce client to avoid any possibility of a clash with working files. Different archive name for custom variants. 2013-03-20 GDR_ Ensure that manual HTML is up to date before making a release. 2014-01-13 GDR_ Make procedure less error-prone by giving exact sequence of commands (where possible) based on experience of release 1.112.0. +2016-01-28 RB_ Git repository renamed from mps-temporary to mps. ========== ===== ========================================================== .. _RB: mailto:rb@ravenbrook.com diff --git a/mps/procedure/version-create.rst b/mps/procedure/version-create.rst index d52c208ce7d..3f743639fdf 100644 --- a/mps/procedure/version-create.rst +++ b/mps/procedure/version-create.rst @@ -154,7 +154,7 @@ the parent branch. A typical invocation looks like this:: PUSHES=$(p4 have //info.ravenbrook.com/infosys/robots/git-fusion/etc/pushes | cut -d' ' -f3) p4 edit $PUSHES - printf "mps-version-$VERSION\tgit@github.com:Ravenbrook/mps-temporary.git\tversion/$VERSION" >> $PUSHES + printf "mps-version-$VERSION\tgit@github.com:Ravenbrook/mps.git\tversion/$VERSION" >> $PUSHES p4 submit -d "Arranging for MPS version $VERSION to be pushed to GitHub by Git Fusion" $PUSHES @@ -178,6 +178,7 @@ B. Document History 2014-01-13 GDR_ Make procedure less error-prone by giving exact sequence of commands (where possible) based on experience of version 1.112. 2014-01-14 GDR_ Step for adding to Git Fusion. 2014-03-19 GDR_ Describe automated procedure. +2016-01-28 RB_ Git repository renamed from mps-temporary to mps. ========== ===== ======================================================== .. _GDR: mailto:gdr@ravenbrook.com From dc77e889d1386c932bf91e99d7629e1e3d2f6664 Mon Sep 17 00:00:00 2001 From: Sam Skulls Date: Wed, 14 May 2014 00:54:47 -0600 Subject: [PATCH 105/337] Fix typo --- mps/example/scheme/scheme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/example/scheme/scheme.c b/mps/example/scheme/scheme.c index 1e7b7084759..fb43e62e344 100644 --- a/mps/example/scheme/scheme.c +++ b/mps/example/scheme/scheme.c @@ -416,7 +416,7 @@ static void error(const char *format, ...) * that type. * * These functions illustrate the two-phase MPS Allocation Point - * Protocol with `reserve` and `commmit`. This protocol allows very fast + * Protocol with `reserve` and `commit`. This protocol allows very fast * in-line allocation without locking, but there is a very tiny chance that * the object must be re-initialized. In nearly all cases, however, it's * just a pointer bump. See topic/allocation. From 273839a83428758909a154a98beb4e8c2a31b0fd Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 28 Jan 2016 16:03:16 +0000 Subject: [PATCH 106/337] Fixing typo thanks to --- mps/example/scheme/scheme-advanced.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/example/scheme/scheme-advanced.c b/mps/example/scheme/scheme-advanced.c index 5089366f0af..830b5b9da33 100644 --- a/mps/example/scheme/scheme-advanced.c +++ b/mps/example/scheme/scheme-advanced.c @@ -424,7 +424,7 @@ static void error(const char *format, ...) * that type. * * These functions illustrate the two-phase MPS Allocation Point - * Protocol with `reserve` and `commmit`. This protocol allows very fast + * Protocol with `reserve` and `commit`. This protocol allows very fast * in-line allocation without locking, but there is a very tiny chance that * the object must be re-initialized. In nearly all cases, however, it's * just a pointer bump. See topic/allocation. From 673d651aba7e46d88bd1d3c6bc40c7a0399dfb4c Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 30 Jan 2016 19:55:37 +0000 Subject: [PATCH 107/337] Fixing uninitialised variable warning from gcc 5.2.1. Copied from Perforce Change: 189069 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 2 +- mps/code/arenavm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 6314cae5b60..cf65402b4e6 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -998,7 +998,7 @@ static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high, { Arena arena; RangeStruct range, oldRange; - Chunk chunk; + Chunk chunk = NULL; /* suppress uninit warning */ Bool found, b; Index baseIndex; Count pages; diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index ba34a7c70ef..f5666a1e7e6 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -992,7 +992,7 @@ static Size arenaUnmapSpare(Arena arena, Size size, Chunk filter) while (RingNext(node) != &vmArena->spareRing && purged < size) { Ring next = RingNext(node); Page page = PageOfSpareRing(next); - Chunk chunk; + Chunk chunk = NULL; /* suppress uninit warning */ Bool b; /* Use the fact that the page table resides in the chunk to find the chunk that owns the page. */ From 1cd22e39b273906aa507235dda8680c97b7c5d2e Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 30 Jan 2016 20:16:30 +0000 Subject: [PATCH 108/337] Removing arena configure method from arena classes. Copied from Perforce Change: 189080 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 2 +- mps/code/arenacl.c | 11 ----------- mps/code/arenavm.c | 11 ----------- mps/code/mpmst.h | 1 - mps/code/mpmtypes.h | 1 - 5 files changed, 1 insertion(+), 25 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index a317f16343e..ed959d04ff7 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -408,7 +408,7 @@ Res ArenaConfigure(Arena arena, ArgList args) return res; } - return (*arena->class->configure)(arena, args); + return ResOK; } diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c index b5837d0b3d9..cd5c24fe46a 100644 --- a/mps/code/arenacl.c +++ b/mps/code/arenacl.c @@ -324,16 +324,6 @@ 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) @@ -467,7 +457,6 @@ DEFINE_ARENA_CLASS(ClientArenaClass, this) this->offset = offsetof(ClientArenaStruct, arenaStruct); this->varargs = ClientArenaVarargs; this->init = ClientArenaInit; - this->configure = ClientArenaConfigure; this->finish = ClientArenaFinish; this->extend = ClientArenaExtend; this->pagesMarkAllocated = ClientArenaPagesMarkAllocated; diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 8dff04b463c..ba34a7c70ef 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -619,16 +619,6 @@ 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) @@ -1204,7 +1194,6 @@ DEFINE_ARENA_CLASS(VMArenaClass, this) this->offset = offsetof(VMArenaStruct, arenaStruct); this->varargs = VMArenaVarargs; this->init = VMArenaInit; - this->configure = VMArenaConfigure; this->finish = VMArenaFinish; this->purgeSpare = VMPurgeSpare; this->grow = VMArenaGrow; diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index ac5c12c1498..d212e0e3307 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -525,7 +525,6 @@ typedef struct mps_arena_class_s { size_t offset; /* offset of generic struct in outer struct */ ArenaVarargsMethod varargs; ArenaInitMethod init; - ArenaConfigureMethod configure; ArenaFinishMethod finish; ArenaPurgeSpareMethod purgeSpare; ArenaExtendMethod extend; diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 3a494760cb6..a6030e4c1e5 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -119,7 +119,6 @@ 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 (*ArenaPurgeSpareMethod)(Arena arena, Size size); typedef Res (*ArenaExtendMethod)(Arena arena, Addr base, Size size); From d4e54ba17ecf481d8b5307acef68ad655b16d977 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 3 Feb 2016 15:33:03 +0000 Subject: [PATCH 109/337] Backing out the introduction of mps_arena_configure. see . Copied from Perforce Change: 189081 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 27 ---------- mps/code/mpm.h | 1 - mps/code/mps.h | 1 - mps/code/mpsi.c | 14 ------ mps/code/mpsicv.c | 7 +-- mps/manual/source/glossary/c.rst | 3 +- mps/manual/source/glossary/s.rst | 3 +- mps/manual/source/release.rst | 8 --- mps/manual/source/topic/arena.rst | 69 +++++++++++++++----------- mps/manual/source/topic/deprecated.rst | 35 ------------- mps/test/function/165.c | 15 ++---- mps/test/function/231.c | 5 +- 12 files changed, 48 insertions(+), 140 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index ed959d04ff7..94dd0044733 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -385,33 +385,6 @@ 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_COMMIT_LIMIT)) { - Size limit = arg.val.size; - res = ArenaSetCommitLimit(arena, limit); - if (res != ResOK) - return res; - } - if (ArgPick(&arg, args, MPS_KEY_SPARE_COMMIT_LIMIT)) { - Size limit = arg.val.size; - res = ArenaSetSpareCommitLimit(arena, limit); - if (res != ResOK) - return res; - } - - return ResOK; -} - - /* ArenaFinish -- finish the generic part of the arena * * .finish.caller: Unlike PoolFinish, this is called by the class finish diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 05286a200d2..022064f3a2f 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -498,7 +498,6 @@ 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/mps.h b/mps/code/mps.h index 10207eb6e94..d9e750417e0 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -439,7 +439,6 @@ 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 112ab313c00..9d9d4986000 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -350,20 +350,6 @@ 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 c1ea620c810..29a81b174c8 100644 --- a/mps/code/mpsicv.c +++ b/mps/code/mpsicv.c @@ -320,7 +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_arena_commit_limit_set * mps_class_mv * mps_pool_create * mps_pool_destroy @@ -347,10 +347,7 @@ 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"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, limit); - die(mps_arena_configure(arena, args), "commit_limit_set after"); - } MPS_ARGS_END(args); + die(mps_arena_commit_limit_set(arena, limit), "commit_limit_set after"); 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 23b2d960048..ffdf1899243 100644 --- a/mps/manual/source/glossary/c.rst +++ b/mps/manual/source/glossary/c.rst @@ -354,8 +354,7 @@ 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 - passing the :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` - :term:`keyword argument` to :c:func:`mps_arena_configure`. + calling :c:func:`mps_arena_commit_limit_set`. committed (1) diff --git a/mps/manual/source/glossary/s.rst b/mps/manual/source/glossary/s.rst index b18c186fd23..dc9355f2a0f 100644 --- a/mps/manual/source/glossary/s.rst +++ b/mps/manual/source/glossary/s.rst @@ -467,8 +467,7 @@ 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 - passing the :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` - :term:`keyword argument` to :c:func:`mps_arena_configure`. + calling :c:func:`mps_arena_spare_commit_limit_set`. spare committed memory diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 5a862a6bc47..ad285d7adc6 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -23,10 +23,6 @@ New features :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 - :term:`keyword argument` interface for changing the properties of - an arena. - Interface changes ................. @@ -41,10 +37,6 @@ 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`. - Other changes ............. diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index 7c9f580adde..f98de4ba56d 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -92,19 +92,6 @@ 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`. @@ -186,10 +173,6 @@ 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_COMMIT_LIMIT` as described above. - .. c:function:: mps_res_t mps_arena_extend(mps_arena_t arena, mps_addr_t base, size_t size) @@ -312,11 +295,6 @@ 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_COMMIT_LIMIT` and - :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` as described above. - .. index:: single: arena; properties @@ -349,9 +327,10 @@ Arena properties 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 + The commit limit can be set by passing the :c:macro:`MPS_KEY_COMMIT_LIMIT` :term:`keyword argument` to - :c:func:`mps_arena_create_k` or :c:func:`mps_arena_configure`. The + :c:func:`mps_arena_create_k`. It can be changed by calling + :c:func:`mps_arena_commit_limit_set`. 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 @@ -376,6 +355,20 @@ Arena properties there is more committed memory than 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. + + See :c:func:`mps_arena_spare_commit_limit` for details. + + .. c:function:: size_t mps_arena_committed(mps_arena_t arena) Return the total :term:`committed ` memory for an @@ -469,10 +462,11 @@ Arena properties use, neither by the :term:`client program`, or by the MPS itself) the MPS is allowed to have. - The spare commit limit can be changed by passing the + The spare commit limit can be set by passing the :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 + argument` to :c:func:`mps_arena_create_k`. It can be changed + by calling :c:func:`mps_arena_spare_commit_limit_set`. + 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 @@ -500,8 +494,8 @@ Arena properties The amount of "spare committed" memory can be limited passing the :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 + argument` to :c:func:`mps_arena_create_k` or by calling + :c:func:`mps_arena_spare_commit_limit_set`. 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. @@ -512,6 +506,23 @@ Arena properties so this function always returns 0. +.. 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`. + + .. index:: single: arena; states diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst index 5a3f9900bf1..dfd4d8d74cb 100644 --- a/mps/manual/source/topic/deprecated.rst +++ b/mps/manual/source/topic/deprecated.rst @@ -25,41 +25,6 @@ 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_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/test/function/165.c b/mps/test/function/165.c index da0734ba279..5bd3bda7a44 100644 --- a/mps/test/function/165.c +++ b/mps/test/function/165.c @@ -59,10 +59,7 @@ static void test(void) /* Set the spare commit limit to 0MB */ - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_SPARE_COMMIT_LIMIT, 0); - cdie(mps_arena_configure(arena, args), "mps_arena_configure"); - } MPS_ARGS_END(args); + mps_arena_spare_commit_limit_set(arena, (size_t) 0); die(mps_alloc(&objs[0], pool, BIGSIZE), "alloc"); com0 = mps_arena_committed(arena); mps_free(pool, objs[0], BIGSIZE); @@ -74,10 +71,7 @@ static void test(void) /* Try again but with arena hysteresis */ /* nb. size_t unsigned, therefore (size_t)-1 is the maximum limit */ - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_SPARE_COMMIT_LIMIT, -1); - cdie(mps_arena_configure(arena, args), "mps_arena_configure"); - } MPS_ARGS_END(args); + mps_arena_spare_commit_limit_set(arena, (size_t)-1); die(mps_alloc(&objs[0], pool, BIGSIZE), "alloc"); com0 = mps_arena_committed(arena); mps_free(pool, objs[0], BIGSIZE); @@ -87,10 +81,7 @@ static void test(void) report("reduce2", "%ld", com0-com1); /* Reducing the spare committed limit should return most of the spare */ - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_SPARE_COMMIT_LIMIT, 1024*1024); - cdie(mps_arena_configure(arena, args), "mps_arena_configure"); - } MPS_ARGS_END(args); + mps_arena_spare_commit_limit_set(arena, (size_t)(1024*1024)); com2 = mps_arena_committed(arena); report("reduce3", "%ld", com0-com2); diff --git a/mps/test/function/231.c b/mps/test/function/231.c index ac13e02d4a1..c8c29fa44e2 100644 --- a/mps/test/function/231.c +++ b/mps/test/function/231.c @@ -27,10 +27,7 @@ static void test(void) 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_COMMIT_LIMIT, 16 * 1024); - report_res("configure", mps_arena_configure(arena, args)); - } MPS_ARGS_END(args); + report_res("configure", mps_arena_commit_limit_set(arena, 16 * 1024)); mps_arena_destroy(arena); } From 38f73575ae2a1c8b0cc6dd7e02c85be92f60148e Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 3 Feb 2016 16:50:42 +0000 Subject: [PATCH 110/337] Removing result code from arenasetsparecommitlimit since it can never fail. See . Copied from Perforce Change: 189084 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 3 +-- mps/code/mpm.h | 2 +- mps/code/mpsi.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 94dd0044733..722e450c4d5 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -1314,7 +1314,7 @@ Size ArenaSpareCommitLimit(Arena arena) return arena->spareCommitLimit; } -Res ArenaSetSpareCommitLimit(Arena arena, Size limit) +void ArenaSetSpareCommitLimit(Arena arena, Size limit) { AVERT(Arena, arena); /* Can't check limit, as all possible values are allowed. */ @@ -1326,7 +1326,6 @@ Res ArenaSetSpareCommitLimit(Arena arena, Size limit) } EVENT2(SpareCommitLimitSet, arena, limit); - 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 022064f3a2f..b8cb8c250ee 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 Res ArenaSetSpareCommitLimit(Arena arena, Size limit); +extern void 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 9d9d4986000..283fbc6123e 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); - (void)ArenaSetSpareCommitLimit(arena, limit); + ArenaSetSpareCommitLimit(arena, limit); ArenaLeave(arena); return; From 989d78b1f42f834aee8e54d8049034c42cd17c7b Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 4 Feb 2016 23:16:17 +0000 Subject: [PATCH 111/337] Adding description code for rootreg_masked to rootdescribe. Copied from Perforce Change: 189105 ServerID: perforce.ravenbrook.com --- mps/code/root.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/mps/code/root.c b/mps/code/root.c index 25780a562f9..6439f3c15ab 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -672,7 +672,7 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) return res; switch(root->var) { - case RootTABLE: + case RootTABLE: res = WriteF(stream, depth + 2, "table base $A limit $A\n", (WriteFA)root->the.table.base, @@ -682,7 +682,7 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) return res; break; - case RootTABLE_MASKED: + case RootTABLE_MASKED: res = WriteF(stream, depth + 2, "table base $A limit $A mask $B\n", (WriteFA)root->the.tableMasked.base, @@ -693,7 +693,7 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) return res; break; - case RootFUN: + case RootFUN: res = WriteF(stream, depth + 2, "scan function $F\n", (WriteFF)root->the.fun.scan, "environment p $P s $W\n", @@ -712,7 +712,18 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) return res; break; - case RootFMT: + case RootREG_MASKED: + res = WriteF(stream, depth + 2, + "thread $P\n", (WriteFP)root->the.regMasked.thread, + "mask $B\n", (WriteFB)root->the.regMasked.mask, + "pattern $B\n", (WriteFB)root->the.regMasked.pattern, + "stackBot $P\n", (WriteFP)root->the.regMasked.stackBot, + NULL); + if (res != ResOK) + return res; + break; + + case RootFMT: res = WriteF(stream, depth + 2, "scan function $F\n", (WriteFF)root->the.fmt.scan, "format base $A limit $A\n", @@ -722,7 +733,7 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) return res; break; - default: + default: NOTREACHED; } From ecff19832ba3da633004316fa71ddaba20c6ffde Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 5 Feb 2016 12:10:03 +0000 Subject: [PATCH 112/337] Using "cold end" rather than "bottom" of the stack, to avoid ambiguity. Copied from Perforce Change: 189106 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/root.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index e120aa7e925..71258c3f64f 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -148,12 +148,13 @@ 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`. -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. +The MPS's stack scanner needs to know how to find the :term:`cold end` +of the part of the stack to scan. The :term:`cold end` 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 From 8ace24237d6866c44a5036a9ffe460affcfc7057 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 10 Feb 2016 15:14:21 +0000 Subject: [PATCH 113/337] Ensuring landfinish doesn't try treecheck on unmapped memory. see . Copied from Perforce Change: 189121 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mps/code/arena.c b/mps/code/arena.c index cf65402b4e6..738761aaa33 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -417,6 +417,11 @@ static void arenaFreeLandFinish(Arena arena) AVERT(Arena, arena); AVER(arena->hasFreeLand); + /* We're about to free the memory occupied by the free land, which + contains a CBS. We want to make sure that LandFinish doesn't try + to check the CBS, so nuke it here. TODO: LandReset? */ + arena->freeLandStruct.splayTreeStruct.root = TreeEMPTY; + /* The CBS block pool can't free its own memory via ArenaFree because * that would use the free land. */ MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor, From f6d3a4f6af23d2058b990b651ae7d870861897ae Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 10 Feb 2016 15:42:40 +0000 Subject: [PATCH 114/337] Adding xcode target for tagtest. Copied from Perforce Change: 189128 ServerID: perforce.ravenbrook.com --- mps/code/mps.xcodeproj/project.pbxproj | 95 ++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index 21abc599f2c..3278a570222 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -216,6 +216,9 @@ 3104B04F156D3B09000A585A /* fmtdy.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAC6156BE48D00753214 /* fmtdy.c */; }; 3104B050156D3B09000A585A /* fmtdytst.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAC7156BE48D00753214 /* fmtdytst.c */; }; 3104B051156D3B09000A585A /* fmtno.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CACC156BE4C200753214 /* fmtno.c */; }; + 31108A3E1C6B90E900E728EA /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; + 31108A411C6B90E900E728EA /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; + 31108A481C6B911B00E728EA /* tagtest.c in Sources */ = {isa = PBXBuildFile; fileRef = 31108A391C6B90D600E728EA /* tagtest.c */; }; 3114A59B156E914B001E0AA3 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; 3114A59C156E914F001E0AA3 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; 3114A5A2156E9168001E0AA3 /* locv.c in Sources */ = {isa = PBXBuildFile; fileRef = 3114A5A1156E9168001E0AA3 /* locv.c */; }; @@ -672,6 +675,13 @@ remoteGlobalIDString = 3104B03C156D3AD7000A585A; remoteInfo = segsmss; }; + 31108A3C1C6B90E900E728EA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 31EEABFA156AAF9D00714D05; + remoteInfo = mps; + }; 3114A59D156E9156001E0AA3 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; @@ -1154,6 +1164,15 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + 31108A421C6B90E900E728EA /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; 3114A58E156E913C001E0AA3 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -1473,6 +1492,8 @@ 3107DC4E173B03D100F705C8 /* arg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = arg.h; sourceTree = ""; }; 310F5D7118B6675F007EFCBC /* tree.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tree.c; sourceTree = ""; }; 310F5D7218B6675F007EFCBC /* tree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = tree.h; sourceTree = ""; }; + 31108A391C6B90D600E728EA /* tagtest.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tagtest.c; sourceTree = ""; }; + 31108A471C6B90E900E728EA /* tagtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tagtest; sourceTree = BUILT_PRODUCTS_DIR; }; 3112ED3A18ABC57F00CC531A /* sa.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sa.h; sourceTree = ""; }; 3112ED3B18ABC75200CC531A /* sa.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sa.c; sourceTree = ""; }; 3114A590156E913C001E0AA3 /* locv */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locv; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1870,6 +1891,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 31108A401C6B90E900E728EA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 31108A411C6B90E900E728EA /* libmps.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 3114A58D156E913C001E0AA3 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -2252,6 +2281,7 @@ 3104AFD6156D3602000A585A /* sacss.c */, 31D60006156D3C5F00337B26 /* segsmss.c */, 31D60098156D403C00337B26 /* steptest.c */, + 31108A391C6B90D600E728EA /* tagtest.c */, 3114A628156E949A001E0AA3 /* teletest.c */, 31EEAC9E156AB73400714D05 /* testlib.c */, 2291A5F0175CB7A4001D4920 /* testlib.h */, @@ -2351,6 +2381,7 @@ 22FACEED18880983000FDBC1 /* airtest */, 22C2ACAF18BE400A006B3677 /* nailboardtest */, 22F846BD18F437B900982BA7 /* lockut */, + 31108A471C6B90E900E728EA /* tagtest */, ); name = Products; sourceTree = ""; @@ -2879,6 +2910,24 @@ productReference = 3104B03D156D3AD7000A585A /* segsmss */; productType = "com.apple.product-type.tool"; }; + 31108A3A1C6B90E900E728EA /* tagtest */ = { + isa = PBXNativeTarget; + buildConfigurationList = 31108A431C6B90E900E728EA /* Build configuration list for PBXNativeTarget "tagtest" */; + buildPhases = ( + 31108A3D1C6B90E900E728EA /* Sources */, + 31108A401C6B90E900E728EA /* Frameworks */, + 31108A421C6B90E900E728EA /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 31108A3B1C6B90E900E728EA /* PBXTargetDependency */, + ); + name = tagtest; + productName = teletest; + productReference = 31108A471C6B90E900E728EA /* tagtest */; + productType = "com.apple.product-type.tool"; + }; 3114A58F156E913C001E0AA3 /* locv */ = { isa = PBXNativeTarget; buildConfigurationList = 3114A599156E913C001E0AA3 /* Build configuration list for PBXNativeTarget "locv" */; @@ -3452,6 +3501,7 @@ 2D604B9B16514B1A003AAF46 /* mpseventtxt */, 31FCAE0917692403008C034C /* scheme */, 22B2BC2C18B6434F00C33E63 /* scheme-advanced */, + 31108A3A1C6B90E900E728EA /* tagtest */, ); }; /* End PBXProject section */ @@ -3731,6 +3781,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 31108A3D1C6B90E900E728EA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 31108A3E1C6B90E900E728EA /* testlib.c in Sources */, + 31108A481C6B911B00E728EA /* tagtest.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 3114A58C156E913C001E0AA3 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -4266,6 +4325,11 @@ target = 3104B03C156D3AD7000A585A /* segsmss */; targetProxy = 3104B049156D3AE4000A585A /* PBXContainerItemProxy */; }; + 31108A3B1C6B90E900E728EA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 31EEABFA156AAF9D00714D05 /* mps */; + targetProxy = 31108A3C1C6B90E900E728EA /* PBXContainerItemProxy */; + }; 3114A59E156E9156001E0AA3 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 31EEABFA156AAF9D00714D05 /* mps */; @@ -4911,6 +4975,27 @@ }; name = Release; }; + 31108A441C6B90E900E728EA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 31108A451C6B90E900E728EA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 31108A461C6B90E900E728EA /* RASH */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = RASH; + }; 3114A597156E913C001E0AA3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -6030,6 +6115,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 31108A431C6B90E900E728EA /* Build configuration list for PBXNativeTarget "tagtest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 31108A441C6B90E900E728EA /* Debug */, + 31108A451C6B90E900E728EA /* Release */, + 31108A461C6B90E900E728EA /* RASH */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 3114A599156E913C001E0AA3 /* Build configuration list for PBXNativeTarget "locv" */ = { isa = XCConfigurationList; buildConfigurations = ( From 9820e020c2ed81d389279cb5aea87367ac661edd Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 10 Feb 2016 20:42:21 +0000 Subject: [PATCH 115/337] Improving test output. Copied from Perforce Change: 189129 ServerID: perforce.ravenbrook.com --- mps/code/tagtest.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c index 76299f6cbce..ada8eb0fcce 100644 --- a/mps/code/tagtest.c +++ b/mps/code/tagtest.c @@ -128,8 +128,8 @@ static void collect(mps_arena_t arena, size_t expected) mps_message_discard(arena, message); ++ finalized; } - printf("tag_cons=%lu finalized=%lu expected=%lu\n", - (unsigned long)tag_cons, (unsigned long)finalized, (unsigned long)expected); + printf("finalized=%lu expected=%lu\n", + (unsigned long)finalized, (unsigned long)expected); Insist(finalized == expected); } @@ -165,13 +165,25 @@ static void alloc_recursively(mps_arena_t arena, mps_ap_t ap, /* test -- Run the test case in the specified mode. */ +#define MODES(R, X) \ + R(X, DEFAULT, "Use default scanner (tagged with 0).") \ + R(X, CONS, "Scan words tagged \"cons\".") \ + R(X, INVALID, "Scan words tagged \"invalid\".") + +#define MODES_ENUM(X, id, comment) MODE_ ## id, + enum { - MODE_DEFAULT, /* Use default scanner (tagged with 0). */ - MODE_CONS, /* Scan words tagged "cons". */ - MODE_INVALID, /* Scan words tagged "invalid". */ + MODES(MODES_ENUM, X) MODE_LIMIT }; +#define MODES_NAME(X, id, comment) #id, + +const char *mode_name[] = { + MODES(MODES_NAME, X) +}; + + static void test(int mode, void *marker) { mps_arena_t arena; @@ -182,6 +194,8 @@ static void test(int mode, void *marker) mps_ap_t ap; size_t expected = 0; + printf("test(%s)\n", mode_name[mode]); + 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"); @@ -267,6 +281,10 @@ int main(int argc, char *argv[]) tag_imm = tags[2]; tag_invalid = tags[3]; + printf("tags: cons = %u, fwd = %u, imm = %u, invalid = %u\n", + (unsigned)tag_cons, (unsigned)tag_fwd, + (unsigned)tag_imm, (unsigned)tag_invalid); + for (mode = 0; mode < MODE_LIMIT; ++mode) { test(mode, marker); } From 9c0c18472809dc9d7eb295995a488a6ad665a3a7 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 11 Feb 2016 20:28:39 +0000 Subject: [PATCH 116/337] Adding mps_root_create_table_tagged as an interface to more generally tagged roots. Deprecating the less general mps_root_create_table_masked. Copied from Perforce Change: 189131 ServerID: perforce.ravenbrook.com --- mps/code/mpm.h | 4 ++-- mps/code/mps.h | 4 ++++ mps/code/mpsi.c | 19 +++++++++++++++---- mps/code/root.c | 6 +++--- mps/manual/source/release.rst | 6 ++++++ mps/manual/source/topic/deprecated.rst | 15 +++++++++++++++ mps/manual/source/topic/root.rst | 15 ++++++++++----- 7 files changed, 55 insertions(+), 14 deletions(-) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 6b3ebc5e88f..ddb32ea189a 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -950,10 +950,10 @@ extern void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from); extern Res RootCreateTable(Root *rootReturn, Arena arena, Rank rank, RootMode mode, Word *base, Word *limit); -extern Res RootCreateTableMasked(Root *rootReturn, Arena arena, +extern Res RootCreateTableTagged(Root *rootReturn, Arena arena, Rank rank, RootMode mode, Word *base, Word *limit, - Word mask); + Word mask, Word pattern); extern Res RootCreateReg(Root *rootReturn, Arena arena, Rank rank, Thread thread, mps_reg_scan_t scan, diff --git a/mps/code/mps.h b/mps/code/mps.h index 45f9543e8da..453adeaef80 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -661,6 +661,10 @@ extern mps_res_t mps_root_create(mps_root_t *, mps_arena_t, mps_rank_t, extern mps_res_t mps_root_create_table(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_addr_t *, size_t); +extern mps_res_t mps_root_create_table_tagged(mps_root_t *, mps_arena_t, + mps_rank_t, mps_rm_t, + mps_addr_t *, size_t, + mps_word_t, mps_word_t); extern mps_res_t mps_root_create_table_masked(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_addr_t *, size_t, diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 3b403fa3450..c678c4e2441 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1314,11 +1314,11 @@ mps_res_t mps_root_create_table(mps_root_t *mps_root_o, mps_arena_t arena, return MPS_RES_OK; } -mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, +mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, mps_arena_t arena, mps_rank_t mps_rank, mps_rm_t mps_rm, mps_addr_t *base, size_t size, - mps_word_t mask) + mps_word_t mask, mps_word_t pattern) { Rank rank = (Rank)mps_rank; Root root; @@ -1331,12 +1331,13 @@ mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, AVER(base != NULL); AVER(size > 0); /* Can't check anything about mask */ + AVER((pattern & mask) == pattern); /* See .root.table-size. */ - res = RootCreateTableMasked(&root, arena, rank, mode, + res = RootCreateTableTagged(&root, arena, rank, mode, (Word *)base, (Word *)base + size, - mask); + mask, pattern); ArenaLeave(arena); @@ -1346,6 +1347,16 @@ mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, return MPS_RES_OK; } +mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, + mps_arena_t arena, + mps_rank_t mps_rank, mps_rm_t mps_rm, + mps_addr_t *base, size_t size, + mps_word_t mask) +{ + return mps_root_create_table_tagged(mps_root_o, arena, mps_rank, mps_rm, + base, size, mask, 0); +} + mps_res_t mps_root_create_fmt(mps_root_t *mps_root_o, mps_arena_t arena, mps_rank_t mps_rank, mps_rm_t mps_rm, mps_fmt_scan_t scan, diff --git a/mps/code/root.c b/mps/code/root.c index 407b84dc246..e278eb05d90 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -290,9 +290,9 @@ Res RootCreateTable(Root *rootReturn, Arena arena, return res; } -Res RootCreateTableMasked(Root *rootReturn, Arena arena, +Res RootCreateTableTagged(Root *rootReturn, Arena arena, Rank rank, RootMode mode, Word *base, Word *limit, - Word mask) + Word mask, Word pattern) { union RootUnion theUnion; @@ -306,7 +306,7 @@ Res RootCreateTableMasked(Root *rootReturn, Arena arena, theUnion.tableMasked.base = base; theUnion.tableMasked.limit = limit; theUnion.tableMasked.mask = mask; - theUnion.tableMasked.pattern = 0; + theUnion.tableMasked.pattern = pattern; return rootCreateProtectable(rootReturn, arena, rank, mode, RootTABLE_MASKED, (Addr)base, (Addr)limit, &theUnion); diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 0b8233f5cba..46e57a14178 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -22,6 +22,9 @@ New features :term:`registers` of a :term:`thread` when scanning them. This supports :term:`tagged references` in these locations. +#. New function :c:func:`mps_root_create_table_tagged` for roots + containing :term:`tagged references`. + Interface changes ................. @@ -39,6 +42,9 @@ Interface changes #. The function :c:func:`mps_root_create_reg` is deprecated in favour of :c:func:`mps_root_create_stack`. +#. The function :c:func:`mps_root_create_table_masked` is deprecated in + favour of :c:func:`mps_root_create_table_tagged`. + Other changes ............. diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst index e2407c7b7d1..a956ddb4990 100644 --- a/mps/manual/source/topic/deprecated.rst +++ b/mps/manual/source/topic/deprecated.rst @@ -166,6 +166,21 @@ Deprecated in version 1.115 argument is ignored. +.. c:function:: mps_res_t mps_root_create_table_masked(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_addr_t *base, size_t count, mps_word_t mask) + + .. deprecated:: + + Use :c:func:`mps_root_create_table_masked` instead, passing + zero for the ``pattern`` argument. + + Register a :term:`root` that consists of a vector of :term:`tagged + references` whose pattern is zero. + + This function is equivalent to calling + :c:func:`mps_root_create_table_tagged` with a ``pattern`` argument + of zero. + + .. c:type:: mps_res_t (*mps_reg_scan_t)(mps_ss_t ss, mps_thr_t thr, void *p, size_t s) .. deprecated:: diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index 71258c3f64f..c54aefb6959 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -97,7 +97,7 @@ scan it for references: #. :c:func:`mps_root_create_table` if the root consists of a table of references; -#. :c:func:`mps_root_create_table_masked` if the root consists of a +#. :c:func:`mps_root_create_table_tagged` if the root consists of a table of :term:`tagged references`; #. :c:func:`mps_root_create_stack` if the root consists of the @@ -490,7 +490,7 @@ Root interface mps_addr_t base = my_table; mps_root_create_table(..., base, ...) -.. c:function:: mps_res_t mps_root_create_table_masked(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_addr_t *base, size_t count, mps_word_t mask) +.. c:function:: mps_res_t mps_root_create_table_tagged(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_addr_t *base, size_t count, mps_word_t mask, mps_word_t pattern) Register a :term:`root` that consists of a vector of :term:`tagged references`. @@ -509,8 +509,11 @@ Root interface ``count`` is the number of tagged references in the vector. ``mask`` is a :term:`bitmask` whose set bits specify the location of - the :term:`tag`. References are assumed to have a tag of zero: any - value in the vector with a non-zero tag is ignored. + the :term:`tag`. + + ``pattern`` is a the value of the tag that indicates that the value + in the vector is a reference. Any value in the vector with a tag + that does not match the pattern is ignored. Returns :c:macro:`MPS_RES_OK` if the root was registered successfully, :c:macro:`MPS_RES_MEMORY` if the new root @@ -523,6 +526,7 @@ Root interface For example:: #define TAG_MASK 0x3 /* bottom two bits */ + #define TAG_PATTERN 0x1 /* bottom bit set for references */ /* Global symbol table. */ size_t symtab_size; @@ -538,7 +542,8 @@ Root interface mps_rank_exact(), (mps_rm_t)0, base, symtab_size * 2, - (mps_word_t)TAG_MASK); + (mps_word_t)TAG_MASK, + (mps_word_t)TAG_PATTERN); if (res != MPS_RES_OK) errror("can't create symtab root"); .. warning:: From 48c5cac4be78c602f81c01268e86e69151f0969a Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 11 Feb 2016 20:34:16 +0000 Subject: [PATCH 117/337] Adding tagtest to the list of xcode targets so that it is build for testing. Copied from Perforce Change: 189132 ServerID: perforce.ravenbrook.com --- mps/code/mps.xcodeproj/project.pbxproj | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index 5e8c90c57fa..0e7b669f9b8 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -113,6 +113,7 @@ 22B2BC3B18B643B000C33E63 /* PBXTargetDependency */, 3104B04A156D3AE4000A585A /* PBXTargetDependency */, 31D6009D156D404B00337B26 /* PBXTargetDependency */, + 314CB6EB1C6D272A0073CA42 /* PBXTargetDependency */, 3114A62E156E94AA001E0AA3 /* PBXTargetDependency */, 3114A6B9156E9763001E0AA3 /* PBXTargetDependency */, 31D60063156D3F5C00337B26 /* PBXTargetDependency */, @@ -876,6 +877,13 @@ remoteGlobalIDString = 3114A6C5156E9815001E0AA3; remoteInfo = mpseventcnv; }; + 314CB6EA1C6D272A0073CA42 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 31108A3A1C6B90E900E728EA; + remoteInfo = tagtest; + }; 31A47BA9156C210D0039B1C2 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; @@ -4462,6 +4470,11 @@ target = 3114A6C5156E9815001E0AA3 /* mpseventcnv */; targetProxy = 3114A6D4156E9839001E0AA3 /* PBXContainerItemProxy */; }; + 314CB6EB1C6D272A0073CA42 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 31108A3A1C6B90E900E728EA /* tagtest */; + targetProxy = 314CB6EA1C6D272A0073CA42 /* PBXContainerItemProxy */; + }; 31A47BAA156C210D0039B1C2 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 31EEABFA156AAF9D00714D05 /* mps */; From c8fed5bb8d50f626bd1efa3876baa9c39d7ed9be Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 11 Feb 2016 20:39:57 +0000 Subject: [PATCH 118/337] Renaming tracescanareamasked to tracescanareatagged Copied from Perforce Change: 189133 ServerID: perforce.ravenbrook.com --- mps/code/mpm.h | 2 +- mps/code/prmci3fr.c | 2 +- mps/code/prmci3li.c | 2 +- mps/code/prmci3xc.c | 2 +- mps/code/prmci6fr.c | 2 +- mps/code/prmci6li.c | 2 +- mps/code/prmci6xc.c | 2 +- mps/code/root.c | 2 +- mps/code/ss.c | 6 +++--- mps/code/thix.c | 2 +- mps/code/thw3i3.c | 4 ++-- mps/code/thw3i6.c | 4 ++-- mps/code/thxc.c | 2 +- mps/code/trace.c | 4 ++-- 14 files changed, 19 insertions(+), 19 deletions(-) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index ddb32ea189a..565641f8cdf 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -474,7 +474,7 @@ extern double TraceWorkFactor; END extern Res TraceScanArea(ScanState ss, Word *base, Word *limit); -extern Res TraceScanAreaMasked(ScanState ss, Word *base, Word *limit, +extern Res TraceScanAreaTagged(ScanState ss, Word *base, Word *limit, Word mask, Word value); extern void TraceScanSingleRef(TraceSet ts, Rank rank, Arena arena, Seg seg, Ref *refIO); diff --git a/mps/code/prmci3fr.c b/mps/code/prmci3fr.c index 2625559564c..10a84bd3621 100644 --- a/mps/code/prmci3fr.c +++ b/mps/code/prmci3fr.c @@ -46,7 +46,7 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, /* 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 = TraceScanAreaMasked( + res = TraceScanAreaTagged( ss, (Word *)mfc->ucontext, (Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))), diff --git a/mps/code/prmci3li.c b/mps/code/prmci3li.c index 7f6400943f1..bac5362cfbe 100644 --- a/mps/code/prmci3li.c +++ b/mps/code/prmci3li.c @@ -111,7 +111,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 = TraceScanAreaMasked(ss, + res = TraceScanAreaTagged(ss, (Word *)mc, (Word *)((char *)mc + sizeof(*mc)), mask, pattern); diff --git a/mps/code/prmci3xc.c b/mps/code/prmci3xc.c index 036550ae3e0..ec9bd88e937 100644 --- a/mps/code/prmci3xc.c +++ b/mps/code/prmci3xc.c @@ -106,7 +106,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->threadState; - res = TraceScanAreaMasked(ss, + res = TraceScanAreaTagged(ss, (Word *)mc, (Word *)((char *)mc + sizeof(*mc)), mask, pattern); diff --git a/mps/code/prmci6fr.c b/mps/code/prmci6fr.c index debc9c760bf..8a36d3156dd 100644 --- a/mps/code/prmci6fr.c +++ b/mps/code/prmci6fr.c @@ -40,7 +40,7 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, /* 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 = TraceScanAreaMasked( + res = TraceScanAreaTagged( ss, (Word *)mfc->ucontext, (Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))), diff --git a/mps/code/prmci6li.c b/mps/code/prmci6li.c index 304cfdc38d3..6a9379209f9 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 = TraceScanAreaMasked(ss, + res = TraceScanAreaTagged(ss, (Word *)mc, (Word *)((char *)mc + sizeof(*mc)), mask, pattern); diff --git a/mps/code/prmci6xc.c b/mps/code/prmci6xc.c index 61e57728473..9a67028a6bd 100644 --- a/mps/code/prmci6xc.c +++ b/mps/code/prmci6xc.c @@ -109,7 +109,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->threadState; - res = TraceScanAreaMasked(ss, + res = TraceScanAreaTagged(ss, (Word *)mc, (Word *)((char *)mc + sizeof(*mc)), mask, pattern); diff --git a/mps/code/root.c b/mps/code/root.c index e278eb05d90..8a0f73e1561 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -516,7 +516,7 @@ Res RootScan(ScanState ss, Root root) break; case RootTABLE_MASKED: - res = TraceScanAreaMasked(ss, + res = TraceScanAreaTagged(ss, root->the.tableMasked.base, root->the.tableMasked.limit, root->the.tableMasked.mask, diff --git a/mps/code/ss.c b/mps/code/ss.c index 7078c59d204..f5400f92e90 100644 --- a/mps/code/ss.c +++ b/mps/code/ss.c @@ -47,16 +47,16 @@ Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop, if (arena->stackAtArenaEnter != NULL) { AVER(stackTop < arena->stackAtArenaEnter); AVER(arena->stackAtArenaEnter < stackBot); - res = TraceScanAreaMasked(ss, stackTop, stackTop + nSavedRegs, + res = TraceScanAreaTagged(ss, stackTop, stackTop + nSavedRegs, mask, pattern); if (res != ResOK) return res; - res = TraceScanAreaMasked(ss, arena->stackAtArenaEnter, stackBot, + res = TraceScanAreaTagged(ss, arena->stackAtArenaEnter, stackBot, mask, pattern); if (res != ResOK) return res; } else { - res = TraceScanAreaMasked(ss, stackTop, stackBot, mask, pattern); + res = TraceScanAreaTagged(ss, stackTop, stackBot, mask, pattern); if (res != ResOK) return res; } diff --git a/mps/code/thix.c b/mps/code/thix.c index c8f3d6ca52a..cb7877223fa 100644 --- a/mps/code/thix.c +++ b/mps/code/thix.c @@ -271,7 +271,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, /* scan stack inclusive of current sp and exclusive of * stackBot (.stack.full-descend) */ - res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern); + res = TraceScanAreaTagged(ss, stackBase, stackLimit, mask, pattern); if(res != ResOK) return res; diff --git a/mps/code/thw3i3.c b/mps/code/thw3i3.c index 997ff2986f2..d1b632daced 100644 --- a/mps/code/thw3i3.c +++ b/mps/code/thw3i3.c @@ -105,7 +105,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, /* scan stack inclusive of current sp and exclusive of * stackBot (.stack.full-descend) */ - res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern); + res = TraceScanAreaTagged(ss, stackBase, stackLimit, mask, pattern); if(res != ResOK) return res; @@ -114,7 +114,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, * unnecessarily scans the rest of the context. The optimisation * to scan only relevant parts would be machine dependent. */ - res = TraceScanAreaMasked(ss, (Word *)&context, + res = TraceScanAreaTagged(ss, (Word *)&context, (Word *)((char *)&context + sizeof(CONTEXT)), mask, pattern); if(res != ResOK) diff --git a/mps/code/thw3i6.c b/mps/code/thw3i6.c index cc11805eb41..3f5622a0ca0 100644 --- a/mps/code/thw3i6.c +++ b/mps/code/thw3i6.c @@ -105,7 +105,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, /* scan stack inclusive of current sp and exclusive of * stackBot (.stack.full-descend) */ - res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern); + res = TraceScanAreaTagged(ss, stackBase, stackLimit, mask, pattern); if(res != ResOK) return res; @@ -114,7 +114,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, * unnecessarily scans the rest of the context. The optimisation * to scan only relevant parts would be machine dependent. */ - res = TraceScanAreaMasked(ss, (Word *)&context, + res = TraceScanAreaTagged(ss, (Word *)&context, (Word *)((char *)&context + sizeof(CONTEXT)), mask, pattern); if(res != ResOK) diff --git a/mps/code/thxc.c b/mps/code/thxc.c index 05d49e0f913..3deac41ff3a 100644 --- a/mps/code/thxc.c +++ b/mps/code/thxc.c @@ -259,7 +259,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, /* scan stack inclusive of current sp and exclusive of * stackBot (.stack.full-descend) */ - res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern); + res = TraceScanAreaTagged(ss, stackBase, stackLimit, mask, pattern); if(res != ResOK) return res; diff --git a/mps/code/trace.c b/mps/code/trace.c index 8dcc6a2643b..a396508d086 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1457,7 +1457,7 @@ Res TraceScanArea(ScanState ss, Word *base, Word *limit) } -/* TraceScanAreaMasked -- scan contiguous area of filtered references +/* TraceScanAreaTagged -- scan contiguous area of tagged references * * This is as TraceScanArea except words are only fixed if they have * the given value when masked with a mask. @@ -1467,7 +1467,7 @@ Res TraceScanArea(ScanState ss, Word *base, Word *limit) */ ATTRIBUTE_NO_SANITIZE_ADDRESS -Res TraceScanAreaMasked(ScanState ss, Word *base, Word *limit, Word mask, +Res TraceScanAreaTagged(ScanState ss, Word *base, Word *limit, Word mask, Word pattern) { Res res; From 65c32e5965e73c477f5c6d72b385afe78817e2a6 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 11 Feb 2016 21:32:41 +0000 Subject: [PATCH 119/337] Fixing misuse of format header offset to decode tagging. see point 5. Copied from Perforce Change: 189134 ServerID: perforce.ravenbrook.com --- mps/code/tagtest.c | 45 +++++++++++++++++++-------------------------- mps/code/trace.c | 31 ++++++++++++++----------------- 2 files changed, 33 insertions(+), 43 deletions(-) diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c index ada8eb0fcce..24b548752a4 100644 --- a/mps/code/tagtest.c +++ b/mps/code/tagtest.c @@ -54,19 +54,14 @@ static mps_word_t make_cons(mps_ap_t ap, mps_word_t car, mps_word_t cdr) static void fwd(mps_addr_t old, mps_addr_t new) { - cons_t cons; - Insist(TAG(old) == tag_cons); - cons = UNTAGGED(old, cons); + cons_t cons = old; 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); + cons_t cons = addr; if (TAG(cons->car) != tag_fwd) return NULL; return (mps_addr_t)cons->cdr; @@ -82,27 +77,24 @@ static void pad(mps_addr_t addr, size_t size) } } -static mps_res_t scan(mps_ss_t ss, mps_addr_t client_base, - mps_addr_t client_limit) +static mps_res_t scan(mps_ss_t ss, mps_addr_t base, + mps_addr_t 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) { - if (MPS_FIX1(ss, *base)) { - mps_addr_t addr = *base; - mps_word_t tag = TAG(addr); - if (tag == tag_cons) { - mps_res_t res = MPS_FIX2(ss, &addr); + mps_word_t *p = base; + while (p < (mps_word_t *)limit) { + mps_word_t word = *p; + mps_word_t tag = TAG(word); + if (tag == tag_cons) { + mps_addr_t ref = UNTAGGED(word, cons); + if (MPS_FIX1(ss, ref)) { + mps_res_t res = MPS_FIX2(ss, &ref); if (res != MPS_RES_OK) return res; - *base = addr; + *p = TAGGED(ref, cons); } } - ++base; + ++p; } } MPS_SCAN_END(ss); return MPS_RES_OK; @@ -124,7 +116,7 @@ static void collect(mps_arena_t arena, size_t expected) cdie(mps_message_get(&message, arena, mps_message_type_finalization()), "message_get"); mps_message_finalization_ref(&objaddr, arena, message); - Insist(TAG(objaddr) == tag_cons); + Insist(TAG(objaddr) == 0); mps_message_discard(arena, message); ++ finalized; } @@ -148,8 +140,11 @@ static void alloc_recursively(mps_arena_t arena, mps_ap_t ap, Insist(TAG(p) == tag_cons); r = TAGGED(p, imm); UNTAGGED(p, cons)->cdr = r; - addr = (mps_addr_t)p; + addr = (mps_addr_t)UNTAGGED(p, cons); die(mps_finalize(arena, &addr), "finalize"); + /* Avoid leaving a zero-tagged reference on the stack, as it will + prevent finalization when scanned with the default mode. */ + addr = NULL; if (count > 1) { alloc_recursively(arena, ap, expected, count - 1); } else { @@ -225,8 +220,6 @@ static void test(int mode, void *marker) } 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); diff --git a/mps/code/trace.c b/mps/code/trace.c index a396508d086..4a58b81d4a7 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1470,9 +1470,6 @@ ATTRIBUTE_NO_SANITIZE_ADDRESS Res TraceScanAreaTagged(ScanState ss, Word *base, Word *limit, Word mask, Word pattern) { - Res res; - Word word, *p; - AVERT(ScanState, ss); AVER(base != NULL); AVER(limit != NULL); @@ -1481,20 +1478,20 @@ Res TraceScanAreaTagged(ScanState ss, Word *base, Word *limit, Word mask, EVENT3(TraceScanAreaTagged, ss, base, limit); TRACE_SCAN_BEGIN(ss) { - p = base; - loop: - if (p >= limit) - goto out; - word = *p++; - if ((word & mask) != pattern) - goto loop; - if (!TRACE_FIX1(ss, (Ref)word)) - goto loop; - res = TRACE_FIX2(ss, (Ref *)(p-1)); - if(res == ResOK) - goto loop; - return res; - out: + Word *p = base; + while (p < limit) { + Word word = *p; + if ((word & mask) == pattern) { + Ref ref = (Ref)(word ^ pattern); + if (TRACE_FIX1(ss, ref)) { + Res res = TRACE_FIX2(ss, &ref); + if(res != ResOK) + return res; + *p = (Word)ref | pattern; + } + } + ++p; + } AVER(p == limit); } TRACE_SCAN_END(ss); From ff6d89c6f9378bcc4fb83f961d793034985afad2 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 11 Feb 2016 23:51:21 +0000 Subject: [PATCH 120/337] Fixing undeclared extern warning that caused travis build failure . Adding missing warning flags in Xcode to bring into line with strictness of makefiles and catch the above sooner. Copied from Perforce Change: 189143 ServerID: perforce.ravenbrook.com --- mps/code/mps.xcodeproj/project.pbxproj | 48 ++------------------------ mps/code/tagtest.c | 2 +- 2 files changed, 4 insertions(+), 46 deletions(-) diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index 0e7b669f9b8..99f323927be 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -5289,21 +5289,7 @@ SDKROOT = macosx; SYMROOT = xc; WARNING_CFLAGS = ( - "-pedantic", - "-Waggregate-return", - "-Wall", - "-Wcast-qual", - "-Wextra", - "-Winline", - "-Wmissing-prototypes", - "-Wnested-externs", - "-Wno-extended-offsetof", - "-Wpointer-arith", - "-Wshadow", - "-Wstrict-aliasing=2", - "-Wstrict-prototypes", - "-Wunreachable-code", - "-Wwrite-strings", + "-pedantic\n-Waggregate-return\n-Wall\n-Wcast-qual\n-Wconversion\n-Wduplicate-enum\n-Wextra\n-Winline\n-Wmissing-prototypes\n-Wmissing-variable-declarations\n-Wnested-externs\n-Wno-extended-offsetof\n-Wpointer-arith\n-Wshadow\n-Wstrict-aliasing=2\n-Wstrict-prototypes\n-Wunreachable-code\n-Wwrite-strings\n", ); }; name = RASH; @@ -5726,21 +5712,7 @@ SDKROOT = macosx; SYMROOT = xc; WARNING_CFLAGS = ( - "-pedantic", - "-Waggregate-return", - "-Wall", - "-Wcast-qual", - "-Wextra", - "-Winline", - "-Wmissing-prototypes", - "-Wnested-externs", - "-Wno-extended-offsetof", - "-Wpointer-arith", - "-Wshadow", - "-Wstrict-aliasing=2", - "-Wstrict-prototypes", - "-Wunreachable-code", - "-Wwrite-strings", + "-pedantic\n-Waggregate-return\n-Wall\n-Wcast-qual\n-Wconversion\n-Wduplicate-enum\n-Wextra\n-Winline\n-Wmissing-prototypes\n-Wmissing-variable-declarations\n-Wnested-externs\n-Wno-extended-offsetof\n-Wpointer-arith\n-Wshadow\n-Wstrict-aliasing=2\n-Wstrict-prototypes\n-Wunreachable-code\n-Wwrite-strings\n", ); }; name = Debug; @@ -5781,21 +5753,7 @@ SDKROOT = macosx; SYMROOT = xc; WARNING_CFLAGS = ( - "-pedantic", - "-Waggregate-return", - "-Wall", - "-Wcast-qual", - "-Wextra", - "-Winline", - "-Wmissing-prototypes", - "-Wnested-externs", - "-Wno-extended-offsetof", - "-Wpointer-arith", - "-Wshadow", - "-Wstrict-aliasing=2", - "-Wstrict-prototypes", - "-Wunreachable-code", - "-Wwrite-strings", + "-pedantic\n-Waggregate-return\n-Wall\n-Wcast-qual\n-Wconversion\n-Wduplicate-enum\n-Wextra\n-Winline\n-Wmissing-prototypes\n-Wmissing-variable-declarations\n-Wnested-externs\n-Wno-extended-offsetof\n-Wpointer-arith\n-Wshadow\n-Wstrict-aliasing=2\n-Wstrict-prototypes\n-Wunreachable-code\n-Wwrite-strings\n", ); }; name = Release; diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c index 24b548752a4..3ce19c8f738 100644 --- a/mps/code/tagtest.c +++ b/mps/code/tagtest.c @@ -174,7 +174,7 @@ enum { #define MODES_NAME(X, id, comment) #id, -const char *mode_name[] = { +static const char *mode_name[] = { MODES(MODES_NAME, X) }; From e6a8d56abc8f66b1408cc5dfae50a8bcb8f227ad Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 12 Feb 2016 14:05:44 +0000 Subject: [PATCH 121/337] Adding os x builds to travis ci. see . Copied from Perforce Change: 189154 ServerID: perforce.ravenbrook.com --- mps/.travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mps/.travis.yml b/mps/.travis.yml index bc1dfd5bfb1..1939ac1c95f 100644 --- a/mps/.travis.yml +++ b/mps/.travis.yml @@ -2,6 +2,9 @@ # $Id$ # See . language: c +os: + - linux + - osx compiler: - clang - gcc From 87a4d3bf7cc2717cffc20be7f73aec746f19aa4f Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 12 Feb 2016 14:35:05 +0000 Subject: [PATCH 122/337] Excluding os x builds with gcc from the travis build matrix, since we don't support that combination. Copied from Perforce Change: 189159 ServerID: perforce.ravenbrook.com --- mps/.travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mps/.travis.yml b/mps/.travis.yml index 1939ac1c95f..d78b45e190a 100644 --- a/mps/.travis.yml +++ b/mps/.travis.yml @@ -8,6 +8,10 @@ os: compiler: - clang - gcc +matrix: + exclude: + - os: osx + compiler: gcc notifications: email: - mps-travis@ravenbrook.com From 29a24f2c6836af6a8060d4df47170da74d7fb10b Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 13 Feb 2016 22:01:47 +0000 Subject: [PATCH 123/337] Adapting tool/branch to git fusion 2 installation. Copied from Perforce Change: 189166 ServerID: perforce.ravenbrook.com --- mps/tool/branch | 65 +++++++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/mps/tool/branch b/mps/tool/branch index e565678b4e6..5bb9b21c3ec 100755 --- a/mps/tool/branch +++ b/mps/tool/branch @@ -24,6 +24,7 @@ import re import subprocess import sys import p4 +import uuid if sys.version_info < (3,): from codecs import open @@ -32,7 +33,7 @@ class Error(Exception): pass DEPOT = '//info.ravenbrook.com' PROJECT_RE = r'[a-z][a-z0-9.-]*' -PROJECT_FILESPEC_RE = r'{}/project/({})/'.format(re.escape(DEPOT), PROJECT_RE) +PROJECT_FILESPEC_RE = r'{}/project/({})/?'.format(re.escape(DEPOT), PROJECT_RE) CUSTOMER_RE = r'[a-z][a-z0-9.-]*' PARENT_RE = r'master|custom/({})/main'.format(CUSTOMER_RE) PARENT_FILESPEC_RE = r'{}({})(?:/|$)'.format(PROJECT_FILESPEC_RE, PARENT_RE) @@ -69,6 +70,22 @@ VERSION_BRANCH_ENTRY = ''' ''' +# Git Fusion repos in which to register new branches. +GF_REPOS = ['mps', 'mps-public'] + +# Regular expression matching the view of the master codeline in Git Fusion +# configuration files. +GF_VIEW_RE = r'git-branch-name\s*=\s*master\s*view\s*=\s*(.*?)\n\n' + +# Template for the new entry in the Git Fusion configuration file +GF_ENTRY = ''' + +[{uuid}] +git-branch-name = {child} +view = {gf_view} +''' + + def main(argv): parser = argparse.ArgumentParser() parser.add_argument('-P', '--project', @@ -233,6 +250,10 @@ def main(argv): else: print(fmt("--yes omitted: skipping submit of {filespec}")) + def p4read(filespec): + return ''.join([d['data'] for d in p4.run('print', filespec) + if d['code'] == 'text']) + if not args.version: # Task branch register('{depot}/project/{project}/branch/index.html', @@ -252,32 +273,22 @@ def main(argv): if args.github and not args.git_name: print(fmt("Don't know how to push {child} to GitHub: skipping.")) elif args.github: - # Create git-fusion client spec - have_git_branch = False - args.git_client = fmt('git-fusion-{git_name}') - if any(p4.run('clients', '-E', args.git_client)): - print(fmt("client {git_client} already exists: skipping.")) - have_git_branch = True - elif args.yes: - client_spec = dict( - Client=args.git_client, - Description=fmt("Git-fusion client for syncing {project} " - "version {version}"), - Root=fmt('/home/git-fusion/.git-fusion/views/{git_name}/p4'), - View0=fmt('{depot}/project/{project}/{child}/... ' - '//{git_client}/...')) - print(fmt("Creating client spec {git_client}")) - p4.run('client', '-i').send(client_spec).done() - have_git_branch = True - else: - print(fmt("--yes omitted: skipping {git_client}")) - # Update table of pushes - register('{depot}/infosys/robots/git-fusion/etc/pushes', - r"\n*\Z", - '\n{git_name}\t' - 'git@github.com:Ravenbrook/mps-temporary.git\t' - '{git_branch}\n') + # Invent a UUID to use as the section title for the branch in + # the Git Fusion configuration files. + args.uuid = uuid.uuid5(uuid.NAMESPACE_URL, args.child.encode('utf7')) + print(fmt("uuid={uuid}")) + + for repo in GF_REPOS: + config = '//.git-fusion/repos/{}/p4gf_config'.format(repo) + text = p4read(config) + if re.search(str(args.uuid), text): + print('Already registered in Git Fusion repo "{}": skipping.'.format(repo)) + else: + view = re.search(GF_VIEW_RE, text, re.MULTILINE | re.DOTALL).group(1) + args.gf_view = view.replace('/master/', fmt('/{child}/')) + print('Registering in Git Fusion repo "{}".'.format(repo)) + register(config, r"\n*\Z", GF_ENTRY) if __name__ == '__main__': @@ -299,6 +310,8 @@ if __name__ == '__main__': # # 2014-03-18 GDR Created based on [BRANCH-MERGE] and [VERSION-CREATE]. # +# 2016-02-13 RB Adapting to Git Fusion 2. +# # # C. COPYRIGHT AND LICENCE # From b6be181e15f9bad9553a3c73756d3e583446cf7f Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 14 Feb 2016 00:57:28 +0000 Subject: [PATCH 124/337] Lifting area scanners into client-side code. These versions also produce tighter loops under Clang. Copied from Perforce Change: 189188 ServerID: perforce.ravenbrook.com --- mps/code/trace.c | 92 ++++++++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 39 deletions(-) diff --git a/mps/code/trace.c b/mps/code/trace.c index 4a58b81d4a7..a2f0b5667cf 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1426,37 +1426,41 @@ 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. */ +static mps_res_t mps_scan_area(mps_ss_t, mps_word_t *, mps_word_t *); + +static mps_res_t mps_scan_area(mps_ss_t ss, mps_word_t *base, mps_word_t *limit) +{ + MPS_SCAN_BEGIN(ss) { + mps_word_t *p = base; + while (p < limit) { + mps_word_t word = *p; + mps_addr_t ref = (mps_addr_t)word; + if (MPS_FIX1(ss, ref)) { + mps_res_t res = MPS_FIX2(ss, &ref); + if (res != MPS_RES_OK) + return res; + *p = (mps_word_t)ref; + } + ++p; + } + } MPS_SCAN_END(ss); + + return MPS_RES_OK; +} + Res TraceScanArea(ScanState ss, Word *base, Word *limit) { - Res res; - Word word, *p; - AVER(base != NULL); AVER(limit != NULL); AVER(base < limit); EVENT3(TraceScanArea, ss, base, limit); - TRACE_SCAN_BEGIN(ss) { - p = base; - loop: - if (p >= limit) - goto out; - word = *p++; - if(!TRACE_FIX1(ss, (Ref)word)) - goto loop; - res = TRACE_FIX2(ss, (Ref *)(p-1)); - if(res == ResOK) - goto loop; - return res; - out: - AVER(p == limit); - } TRACE_SCAN_END(ss); - - return ResOK; + return mps_scan_area(&ss->ss_s, base, limit); } + /* TraceScanAreaTagged -- scan contiguous area of tagged references * * This is as TraceScanArea except words are only fixed if they have @@ -1466,7 +1470,35 @@ Res TraceScanArea(ScanState ss, Word *base, Word *limit) * sanitizer will think we have run off the end of an array. */ +static mps_res_t mps_scan_area_tagged(mps_ss_t, + mps_word_t *, mps_word_t *, + mps_word_t, mps_word_t); + ATTRIBUTE_NO_SANITIZE_ADDRESS +static mps_res_t mps_scan_area_tagged(mps_ss_t ss, + mps_word_t *base, mps_word_t *limit, + mps_word_t mask, mps_word_t pattern) +{ + MPS_SCAN_BEGIN(ss) { + mps_word_t *p = base; + while (p < limit) { + mps_word_t word = *p; + if ((word & mask) == pattern) { + mps_addr_t ref = (mps_addr_t)(word ^ pattern); + if (MPS_FIX1(ss, ref)) { + mps_res_t res = MPS_FIX2(ss, &ref); + if (res != MPS_RES_OK) + return res; + *p = (mps_word_t)ref | pattern; + } + } + ++p; + } + } MPS_SCAN_END(ss); + + return MPS_RES_OK; +} + Res TraceScanAreaTagged(ScanState ss, Word *base, Word *limit, Word mask, Word pattern) { @@ -1477,25 +1509,7 @@ Res TraceScanAreaTagged(ScanState ss, Word *base, Word *limit, Word mask, EVENT3(TraceScanAreaTagged, ss, base, limit); - TRACE_SCAN_BEGIN(ss) { - Word *p = base; - while (p < limit) { - Word word = *p; - if ((word & mask) == pattern) { - Ref ref = (Ref)(word ^ pattern); - if (TRACE_FIX1(ss, ref)) { - Res res = TRACE_FIX2(ss, &ref); - if(res != ResOK) - return res; - *p = (Word)ref | pattern; - } - } - ++p; - } - AVER(p == limit); - } TRACE_SCAN_END(ss); - - return ResOK; + return mps_scan_area_tagged(&ss->ss_s, base, limit, mask, pattern); } From 8f5be2fdfe1facef16f842dd6e28e662eb5fed08 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 14 Feb 2016 08:46:54 +0000 Subject: [PATCH 125/337] Branching master to branch/2016-02-14/clang-cl. Copied from Perforce Change: 189172 ServerID: perforce.ravenbrook.com From d27af53b4d1ea4e8ed2d6ee131295156421ba96f Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 14 Feb 2016 10:51:53 +0000 Subject: [PATCH 126/337] Adding nmake files and w3i6ll platform code for clang-cl Copied from Perforce Change: 189182 ServerID: perforce.ravenbrook.com --- mps/code/ll.nmk | 78 +++++++++++++++++++++++++++++++++++++++++++++ mps/code/mpstd.h | 26 +++++++++++++-- mps/code/w3i6ll.nmk | 62 +++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 mps/code/ll.nmk create mode 100644 mps/code/w3i6ll.nmk diff --git a/mps/code/ll.nmk b/mps/code/ll.nmk new file mode 100644 index 00000000000..a888dab0fdb --- /dev/null +++ b/mps/code/ll.nmk @@ -0,0 +1,78 @@ +# -*- makefile -*- +# +# mv.nmk: NMAKE FRAGMENT FOR MICROSOFT VISUAL C/C++ +# +# $Id$ +# Copyright (c) 2014 Ravenbrook Limited. See end of file for license. +# +# 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 fragment (comm.nmk) requires. + +CC = clang-cl +LIBMAN = lib +LINKER = link + +# /D_CRT_SECURE_NO_WARNINGS suppresses "This function or variable may +# be unsafe" warnings for standard C library functions fopen, getenv, +# snprintf, sscanf, strcpy, and so on. +# +# /Gs appears to be necessary to suppress stack checks. Stack checks +# (if not suppressed) generate a dependency on the C library, __chkesp, +# which causes the linker step to fail when building the DLL, mpsdy.dll. +CFLAGSCOMMONPRE = $(CFLAGSCOMMONPRE) /D_CRT_SECURE_NO_WARNINGS /W4 /WX /Gs /Fd$(PFM)\$(VARIETY) +LIBFLAGSCOMMON = $(LIBFLAGSCOMMON) /nologo + +# /MD means compile for multi-threaded environment with separate C library DLL. +# /MT means compile for multi-threaded environment. +# /ML means compile for single-threaded environment. +# A 'd' at the end means compile for debugging. +CRTFLAGSHOT = $(CRTFLAGSHOT) /MT +CRTFLAGSCOOL = $(CRTFLAGSCOOL) /MTd + +CFLAGSCOOL = $(CFLAGSCOOL) /Od + +LINKFLAGSCOMMON = $(LINKFLAGSCOMMON) /PDB:$*.pdb +LINKFLAGSHOT = $(LINKFLAGSHOT) libcmt.lib +LINKFLAGSCOOL = $(LINKFLAGSCOOL) libcmtd.lib + + +# C. COPYRIGHT AND LICENSE +# +# Copyright (C) 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/mpstd.h b/mps/code/mpstd.h index 1306281224b..534893fd97b 100644 --- a/mps/code/mpstd.h +++ b/mps/code/mpstd.h @@ -36,7 +36,7 @@ * isn't compatible enough for MPS purposes. */ -#if defined(_MSC_VER) && defined(_WIN32) && defined(_M_IX86) && !defined(__POCC__) +#if defined(_MSC_VER) && defined(_WIN32) && defined(_M_IX86) && !defined(__POCC__) && !defined(__clang__) #if defined(CONFIG_PF_STRING) && ! defined(CONFIG_PF_W3I3MV) #error "specified CONFIG_PF_... inconsistent with detected w3i3mv" #endif @@ -61,7 +61,7 @@ * */ -#elif defined(_MSC_VER) && defined(_WIN32) && defined(_WIN64) && defined(_M_X64) && !defined(__POCC__) +#elif defined(_MSC_VER) && defined(_WIN32) && defined(_WIN64) && defined(_M_X64) && !defined(__POCC__) && !defined(__clang__) #if defined(CONFIG_PF_STRING) && ! defined(CONFIG_PF_W3I6MV) #error "specified CONFIG_PF_... inconsistent with detected w3i6mv" #endif @@ -77,6 +77,28 @@ #define MPS_PF_ALIGN 16 +/* clang-cl + * + * Compatible with Visual Studio C, so we just detect the difference with + * defined(__clang__). + */ + +#elif defined(__clang__) && defined(_WIN32) && defined(_WIN64) && defined(_M_X64) +#if defined(CONFIG_PF_STRING) && ! defined(CONFIG_PF_W3I6LL) +#error "specified CONFIG_PF_... inconsistent with detected w3i6ll" +#endif +#define MPS_PF_W3I6LL +#define MPS_PF_STRING "w3i6ll" +#define MPS_OS_W3 +#define MPS_ARCH_I6 +#define MPS_BUILD_LL +#define MPS_T_WORD unsigned __int64 +#define MPS_T_ULONGEST unsigned __int64 +#define MPS_WORD_WIDTH 64 +#define MPS_WORD_SHIFT 6 +#define MPS_PF_ALIGN 16 + + /* PellesC version 7.00.25 with /Ze option (Microsoft compatibility mode) * Help node "Predefined preprocessor symbols (POCC)" */ diff --git a/mps/code/w3i6ll.nmk b/mps/code/w3i6ll.nmk new file mode 100644 index 00000000000..2192058130a --- /dev/null +++ b/mps/code/w3i6ll.nmk @@ -0,0 +1,62 @@ +# w3i6ll.nmk: WINDOWS (x86-64) NMAKE FILE -*- makefile -*- +# +# $Id$ +# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + +PFM = w3i6ll + +MPMPF = \ + [lockw3] \ + [mpsiw3] \ + [prmci6w3] \ + [proti6] \ + [protw3] \ + [spw3i6] \ + [ssw3i6mv] \ + [thw3] \ + [thw3i6] \ + [vmw3] + +!INCLUDE ll.nmk +!INCLUDE comm.nmk + + +# C. COPYRIGHT AND LICENSE +# +# Copyright (C) 2001-2014 Ravenbrook Limited . +# All rights reserved. This is an open source license. Contact +# Ravenbrook for commercial licensing options. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Redistributions in any form must be accompanied by information on how +# to obtain complete source code for this software and any accompanying +# software that uses this software. The source code must either be +# included in the distribution or be available for no more than the cost +# of distribution plus a nominal fee, and must be freely redistributable +# under reasonable conditions. For an executable file, complete source +# code means the source code for all modules it contains. It does not +# include source code for modules or files that typically accompany the +# major components of the operating system on which the executable file +# runs. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From a3fdda4678e5016a824204c75ee33ddc1117a596 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 15 Feb 2016 15:30:08 +0000 Subject: [PATCH 127/337] Lifting and generalising area scanners to allow flexible tagging schemes. Copied from Perforce Change: 189189 ServerID: perforce.ravenbrook.com --- mps/code/comm.gmk | 1 + mps/code/mps.c | 1 + mps/code/mps.h | 21 +++++ mps/code/mpsi.c | 7 +- mps/code/prmci3fr.c | 7 +- mps/code/prmci3li.c | 11 +-- mps/code/prmci3xc.c | 11 +-- mps/code/prmci6fr.c | 7 +- mps/code/prmci6li.c | 11 +-- mps/code/prmci6xc.c | 11 +-- mps/code/prot.h | 3 +- mps/code/root.c | 43 +++++----- mps/code/scan.c | 190 ++++++++++++++++++++++++++++++++++++++++++++ mps/code/ss.c | 14 ++-- mps/code/ss.h | 7 +- mps/code/ssixi6.c | 6 +- mps/code/tagtest.c | 13 +-- mps/code/th.h | 3 +- mps/code/thix.c | 9 ++- mps/code/thw3i3.c | 13 +-- mps/code/thw3i6.c | 14 ++-- mps/code/thxc.c | 7 +- mps/code/trace.c | 64 +++------------ 23 files changed, 335 insertions(+), 139 deletions(-) create mode 100644 mps/code/scan.c diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index f00e636ea08..98758056ce0 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -200,6 +200,7 @@ MPMCOMMON = \ root.c \ sa.c \ sac.c \ + scan.c \ seg.c \ shield.c \ splay.c \ diff --git a/mps/code/mps.c b/mps/code/mps.c index 95919d9680c..2f9dcc106d8 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -45,6 +45,7 @@ #include "poolabs.c" #include "trace.c" #include "traceanc.c" +#include "scan.c" #include "root.c" #include "seg.c" #include "format.c" diff --git a/mps/code/mps.h b/mps/code/mps.h index 453adeaef80..6614db23f09 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -102,7 +102,15 @@ _mps_ENUM_DEF(_mps_RES_ENUM, MPS_RES_) /* see design.mps.root-interface */ /* see design.mps.format-interface */ +typedef struct mps_scan_tag_s *mps_scan_tag_t; +typedef struct mps_scan_tag_s { + mps_word_t mask; + mps_word_t pattern; +} mps_scan_tag_s; + typedef mps_res_t (*mps_root_scan_t)(mps_ss_t, void *, size_t); +typedef mps_res_t (*mps_area_scan_t)(mps_ss_t, mps_word_t *, mps_word_t *, + void *, size_t); typedef mps_res_t (*mps_fmt_scan_t)(mps_ss_t, mps_addr_t, mps_addr_t); typedef mps_res_t (*mps_reg_scan_t)(mps_ss_t, mps_thr_t, void *, size_t); @@ -793,6 +801,19 @@ extern void mps_pool_check_free_space(mps_pool_t); /* Scanner Support */ +extern mps_res_t mps_scan_area(mps_ss_t, + mps_word_t *, mps_word_t *, + void *, size_t); +extern mps_res_t mps_scan_area_masked(mps_ss_t, + mps_word_t *, mps_word_t *, + void *, size_t); +extern mps_res_t mps_scan_area_tagged(mps_ss_t, + mps_word_t *, mps_word_t *, + void *, size_t); +extern mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t, + mps_word_t *, mps_word_t *, + void *, size_t); + extern mps_res_t mps_fix(mps_ss_t, mps_addr_t *); #define MPS_SCAN_BEGIN(ss) \ diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index c678c4e2441..22adaa345c8 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1451,8 +1451,13 @@ mps_res_t mps_stack_scan_ambig(mps_ss_t mps_ss, mps_thr_t thread, void *p, size_t s) { ScanState ss = PARENT(ScanStateStruct, ss_s, mps_ss); + mps_scan_tag_s tag; + UNUSED(s); - return ThreadScan(ss, thread, (Word *)p, sizeof(mps_word_t) - 1, 0); + + tag.mask = sizeof(mps_word_t) - 1; + tag.pattern = 0; + return ThreadScan(ss, thread, (Word *)p, mps_scan_area_tagged, &tag, sizeof(tag)); } diff --git a/mps/code/prmci3fr.c b/mps/code/prmci3fr.c index 10a84bd3621..60392a11417 100644 --- a/mps/code/prmci3fr.c +++ b/mps/code/prmci3fr.c @@ -39,18 +39,19 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, - Word mask, Word pattern) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { 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 = scan_area( ss, (Word *)mfc->ucontext, (Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))), - mask, pattern + closure, closure_size ); return res; diff --git a/mps/code/prmci3li.c b/mps/code/prmci3li.c index bac5362cfbe..4b404317010 100644 --- a/mps/code/prmci3li.c +++ b/mps/code/prmci3li.c @@ -102,7 +102,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, - Word mask, Word pattern) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { mcontext_t *mc; Res res; @@ -111,10 +112,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, - (Word *)mc, - (Word *)((char *)mc + sizeof(*mc)), - mask, pattern); + res = scan_area(ss, + (Word *)mc, + (Word *)((char *)mc + sizeof(*mc)), + closure, closure_size); return res; } diff --git a/mps/code/prmci3xc.c b/mps/code/prmci3xc.c index ec9bd88e937..91507de6f8a 100644 --- a/mps/code/prmci3xc.c +++ b/mps/code/prmci3xc.c @@ -97,7 +97,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, - Word mask, Word pattern) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { x86_thread_state32_t *mc; Res res; @@ -106,10 +107,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, - (Word *)mc, - (Word *)((char *)mc + sizeof(*mc)), - mask, pattern); + res = scan_area(ss, + (Word *)mc, + (Word *)((char *)mc + sizeof(*mc)), + closure, closure_size); return res; } diff --git a/mps/code/prmci6fr.c b/mps/code/prmci6fr.c index 8a36d3156dd..55212077a78 100644 --- a/mps/code/prmci6fr.c +++ b/mps/code/prmci6fr.c @@ -33,18 +33,19 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, - Word mask, Word pattern) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { 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 = scan_area( ss, (Word *)mfc->ucontext, (Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))), - mask, pattern + closure, closure_size ); return res; diff --git a/mps/code/prmci6li.c b/mps/code/prmci6li.c index 6a9379209f9..a88b78211bf 100644 --- a/mps/code/prmci6li.c +++ b/mps/code/prmci6li.c @@ -106,7 +106,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, - Word mask, Word pattern) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { mcontext_t *mc; Res res; @@ -115,10 +116,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, - (Word *)mc, - (Word *)((char *)mc + sizeof(*mc)), - mask, pattern); + res = scan_area(&ss->ss_s, + (Word *)mc, + (Word *)((char *)mc + sizeof(*mc)), + closure, closure_size); return res; } diff --git a/mps/code/prmci6xc.c b/mps/code/prmci6xc.c index 9a67028a6bd..309d4066b64 100644 --- a/mps/code/prmci6xc.c +++ b/mps/code/prmci6xc.c @@ -100,7 +100,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, - Word mask, Word pattern) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { x86_thread_state64_t *mc; Res res; @@ -109,10 +110,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, - (Word *)mc, - (Word *)((char *)mc + sizeof(*mc)), - mask, pattern); + res = scan_area(ss, + (Word *)mc, + (Word *)((char *)mc + sizeof(*mc)), + closure, closure_size); return res; } diff --git a/mps/code/prot.h b/mps/code/prot.h index 733c26c707b..0a5583d7349 100644 --- a/mps/code/prot.h +++ b/mps/code/prot.h @@ -31,7 +31,8 @@ extern Bool ProtCanStepInstruction(MutatorFaultContext context); extern Res ProtStepInstruction(MutatorFaultContext context); extern Addr MutatorFaultContextSP(MutatorFaultContext mfc); extern Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, - Word mask, Word pattern); + mps_area_scan_t scan, + void *closure, size_t closure_size); #endif /* prot_h */ diff --git a/mps/code/root.c b/mps/code/root.c index 8a0f73e1561..8b92a186726 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -44,8 +44,7 @@ typedef struct RootStruct { struct { Word *base; /* beginning of table */ Word *limit; /* one off end of table */ - Word mask; /* tag mask for scanning */ - Word pattern; /* tag pattern for scanning */ + mps_scan_tag_s tag; /* tag for scanning */ } tableMasked; struct { mps_reg_scan_t scan; /* function for scanning registers */ @@ -55,8 +54,7 @@ typedef struct RootStruct { } reg; struct { Thread thread; /* passed to scan */ - Word mask; /* tag mask for scanning */ - Word pattern; /* tag pattern for scanning */ + mps_scan_tag_s tag; /* tag for scanning */ Word *stackBot; /* bottom of stack */ } regMasked; struct { @@ -120,7 +118,7 @@ Bool RootCheck(Root root) case RootTABLE_MASKED: CHECKL(root->the.tableMasked.base != 0); CHECKL(root->the.tableMasked.base < root->the.tableMasked.limit); - CHECKL((~root->the.tableMasked.mask & root->the.tableMasked.pattern) == 0); + CHECKL((~root->the.tableMasked.tag.mask & root->the.tableMasked.tag.pattern) == 0); break; case RootFUN: @@ -135,7 +133,7 @@ Bool RootCheck(Root root) case RootREG_MASKED: CHECKD_NOSIG(Thread, root->the.regMasked.thread); /* */ - CHECKL((~root->the.regMasked.mask & root->the.regMasked.pattern) == 0); + CHECKL((~root->the.regMasked.tag.mask & root->the.regMasked.tag.pattern) == 0); /* Can't check anything about stackBot. */ break; @@ -305,8 +303,8 @@ Res RootCreateTableTagged(Root *rootReturn, Arena arena, theUnion.tableMasked.base = base; theUnion.tableMasked.limit = limit; - theUnion.tableMasked.mask = mask; - theUnion.tableMasked.pattern = pattern; + theUnion.tableMasked.tag.mask = mask; + theUnion.tableMasked.tag.pattern = pattern; return rootCreateProtectable(rootReturn, arena, rank, mode, RootTABLE_MASKED, (Addr)base, (Addr)limit, &theUnion); @@ -347,8 +345,8 @@ Res RootCreateRegMasked(Root *rootReturn, Arena arena, AVER((~mask & pattern) == 0); theUnion.regMasked.thread = thread; - theUnion.regMasked.mask = mask; - theUnion.regMasked.pattern = pattern; + theUnion.regMasked.tag.mask = mask; + theUnion.regMasked.tag.pattern = pattern; theUnion.regMasked.stackBot = stackBot; return rootCreate(rootReturn, arena, rank, (RootMode)0, RootREG_MASKED, @@ -516,11 +514,12 @@ Res RootScan(ScanState ss, Root root) break; case RootTABLE_MASKED: - res = TraceScanAreaTagged(ss, - root->the.tableMasked.base, - root->the.tableMasked.limit, - root->the.tableMasked.mask, - root->the.tableMasked.pattern); + /* FIXME: wrap in checking method */ + res = mps_scan_area_tagged(&ss->ss_s, + root->the.tableMasked.base, + root->the.tableMasked.limit, + &root->the.tableMasked.tag, + sizeof(root->the.tableMasked.tag)); ss->scannedSize += AddrOffset(root->the.table.base, root->the.table.limit); if (res != ResOK) goto failScan; @@ -542,8 +541,9 @@ Res RootScan(ScanState ss, Root root) case RootREG_MASKED: res = ThreadScan(ss, root->the.regMasked.thread, root->the.regMasked.stackBot, - root->the.regMasked.mask, - root->the.regMasked.pattern); + mps_scan_area_tagged, + &root->the.regMasked.tag, + sizeof(root->the.regMasked.tag)); if (res != ResOK) goto failScan; break; @@ -684,10 +684,11 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) case RootTABLE_MASKED: res = WriteF(stream, depth + 2, - "table base $A limit $A mask $B\n", + "table base $A limit $A mask $B pattern $B\n", (WriteFA)root->the.tableMasked.base, (WriteFA)root->the.tableMasked.limit, - (WriteFB)root->the.tableMasked.mask, + (WriteFB)root->the.tableMasked.tag.mask, + (WriteFB)root->the.tableMasked.tag.pattern, NULL); if (res != ResOK) return res; @@ -715,8 +716,8 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) case RootREG_MASKED: res = WriteF(stream, depth + 2, "thread $P\n", (WriteFP)root->the.regMasked.thread, - "mask $B\n", (WriteFB)root->the.regMasked.mask, - "pattern $B\n", (WriteFB)root->the.regMasked.pattern, + "mask $B\n", (WriteFB)root->the.regMasked.tag.mask, + "pattern $B\n", (WriteFB)root->the.regMasked.tag.pattern, "stackBot $P\n", (WriteFP)root->the.regMasked.stackBot, NULL); if (res != ResOK) diff --git a/mps/code/scan.c b/mps/code/scan.c new file mode 100644 index 00000000000..4ac8fb715ad --- /dev/null +++ b/mps/code/scan.c @@ -0,0 +1,190 @@ +/* scan.c: SCANNING FUNCTIONS + * + * $Id$ + * Copyright (c) 2001-2016 Ravenbrook Limited. + * See end of file for license. + * + * TODO: Design document. + */ + +#include "mps.h" + + +/* mps_scan_area -- scan contiguous area of references + * + * This is a convenience function for scanning the contiguous area + * [base, limit). I.e., it calls Fix on all words from base up to + * limit, inclusive of base and exclusive of limit. + * + * This scanner is appropriate for use when all words in the area are + * simple untagged references. + */ + +mps_res_t mps_scan_area(mps_ss_t ss, + mps_word_t *base, mps_word_t *limit, + void *closure, size_t closure_size) +{ + (void)closure; /* unused */ + (void)closure_size; /* unused */ + + MPS_SCAN_BEGIN(ss) { + mps_word_t *_p = base; + while (_p < limit) { + mps_word_t word = *_p; + mps_addr_t ref = (mps_addr_t)word; + if (MPS_FIX1(ss, ref)) { + mps_res_t res = MPS_FIX2(ss, &ref); + if (res != MPS_RES_OK) + return res; + *_p = (mps_word_t)ref; + } + ++_p; + } + } MPS_SCAN_END(ss); + + return MPS_RES_OK; +} + + +#define MPS_SCAN_AREA_TAGGED(test) \ + MPS_SCAN_BEGIN(ss) { \ + mps_word_t *p = base; \ + while (p < limit) { \ + mps_word_t word = *p; \ + mps_word_t tag_bits = word & mask; \ + if (test) { \ + mps_addr_t ref = (mps_addr_t)(word ^ tag_bits); \ + if (MPS_FIX1(ss, ref)) { \ + mps_res_t res = MPS_FIX2(ss, &ref); \ + if (res != MPS_RES_OK) \ + return res; \ + *p = (mps_word_t)ref | tag_bits; \ + } \ + } \ + ++p; \ + } \ + } MPS_SCAN_END(ss); + + + +/* mps_scan_area_masked -- scan area masking off tag bits + * + * Like mps_scan_area, but removes tag bits before fixing references, + * and restores them afterwards. + * + * For example, if mask is 7, then this scanner will clear the bottom + * three bits of each word before fixing. + * + * This scanner is useful when all words in the area must be treated + * as references no matter what tag they have. + */ + +mps_res_t mps_scan_area_masked(mps_ss_t ss, + mps_word_t *base, mps_word_t *limit, + void *closure, size_t closure_size) +{ + mps_scan_tag_t tag = closure; + mps_word_t mask = tag->mask; + (void)closure_size; /* unused */ + + MPS_SCAN_AREA_TAGGED(1); + + return MPS_RES_OK; +} + + +/* mps_scan_area_tagged -- scan area selecting by tag + * + * Like mps_scan_area_masked, except only references whose masked bits + * match a particular tag pattern are fixed. + * + * For example, if mask is 7 and pattern is 5, then this scanner will + * only fix words whose low order bits are 0b101. + */ + +mps_res_t mps_scan_area_tagged(mps_ss_t ss, + mps_word_t *base, mps_word_t *limit, + void *closure, size_t closure_size) +{ + mps_scan_tag_t tag = closure; + mps_word_t mask = tag->mask; + mps_word_t pattern = tag->pattern; + (void)closure_size; /* unused */ + + MPS_SCAN_AREA_TAGGED(tag_bits == pattern); + + return MPS_RES_OK; +} + + +/* mps_scan_area_tagged_or_zero -- scan area selecting by tag or zero + * + * Like mps_scan_area_tagged, except references whose masked bits are + * zero are fixed in addition to those that match the pattern. + * + * For example, if mask is 7 and pattern is 3, then this scanner will + * fix words whose low order bits are 0b011 and words whose low order + * bits are 0b000, but not any others. + * + * This scanner is most useful for ambiguously scanning the stack and + * registers when using an optimising C compiler and non-zero tags on + * references, since the compiler is likely to leave untagged + * addresses of objects around which must not be ignored. + */ + +mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t ss, + mps_word_t *base, mps_word_t *limit, + void *closure, size_t closure_size) +{ + mps_scan_tag_t tag = closure; + mps_word_t mask = tag->mask; + mps_word_t pattern = tag->pattern; + (void)closure_size; /* unused */ + + MPS_SCAN_AREA_TAGGED(tag_bits == 0 || tag_bits == pattern); + + return MPS_RES_OK; +} + + +/* C. COPYRIGHT AND LICENSE + * + * Copyright (C) 2001-2016 Ravenbrook Limited + * . + * All rights reserved. This is an open source license. Contact + * Ravenbrook for commercial licensing options. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Redistributions in any form must be accompanied by information on how + * to obtain complete source code for this software and any accompanying + * software that uses this software. The source code must either be + * included in the distribution or be available for no more than the cost + * of distribution plus a nominal fee, and must be freely redistributable + * under reasonable conditions. For an executable file, complete source + * code means the source code for all modules it contains. It does not + * include source code for modules or files that typically accompany the + * major components of the operating system on which the executable file + * runs. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/mps/code/ss.c b/mps/code/ss.c index f5400f92e90..93ff85be103 100644 --- a/mps/code/ss.c +++ b/mps/code/ss.c @@ -25,7 +25,9 @@ SRCID(ss, "$Id$"); */ Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop, - Count nSavedRegs, Word mask, Word pattern) + Count nSavedRegs, + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { Arena arena; Res res; @@ -47,16 +49,16 @@ Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop, if (arena->stackAtArenaEnter != NULL) { AVER(stackTop < arena->stackAtArenaEnter); AVER(arena->stackAtArenaEnter < stackBot); - res = TraceScanAreaTagged(ss, stackTop, stackTop + nSavedRegs, - mask, pattern); + res = scan_area(&ss->ss_s, stackTop, stackTop + nSavedRegs, + closure, closure_size); if (res != ResOK) return res; - res = TraceScanAreaTagged(ss, arena->stackAtArenaEnter, stackBot, - mask, pattern); + res = scan_area(&ss->ss_s, arena->stackAtArenaEnter, stackBot, + closure, closure_size); if (res != ResOK) return res; } else { - res = TraceScanAreaTagged(ss, stackTop, stackBot, mask, pattern); + res = scan_area(&ss->ss_s, stackTop, stackBot, closure, closure_size); if (res != ResOK) return res; } diff --git a/mps/code/ss.h b/mps/code/ss.h index c4045bbfe47..bac9c3d1110 100644 --- a/mps/code/ss.h +++ b/mps/code/ss.h @@ -32,9 +32,12 @@ * stack itself. */ -extern Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern); +extern Res StackScan(ScanState ss, Word *stackBot, + mps_area_scan_t scan_area, + void *closure, size_t closure_size); extern Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop, - Count nSavedRegs, Word mask, Word pattern); + Count nSavedRegs, mps_area_scan_t scan_area, + void *closure, size_t closure_s); #endif /* ss_h */ diff --git a/mps/code/ssixi6.c b/mps/code/ssixi6.c index 9fd9e8a1811..1142606980d 100644 --- a/mps/code/ssixi6.c +++ b/mps/code/ssixi6.c @@ -47,7 +47,9 @@ SRCID(ssixi6, "$Id$"); #define ASMV(x) __asm__ volatile (x) -Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern) +Res StackScan(ScanState ss, Word *stackBot, + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { Word calleeSaveRegs[6]; @@ -63,7 +65,7 @@ Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern) ASMV("mov %%r15, %0" : "=m" (calleeSaveRegs[5])); return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs), - mask, pattern); + scan_area, closure, closure_size); } diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c index 3ce19c8f738..76d8b5ec792 100644 --- a/mps/code/tagtest.c +++ b/mps/code/tagtest.c @@ -106,7 +106,7 @@ static mps_addr_t skip(mps_addr_t addr) } -static void collect(mps_arena_t arena, size_t expected) +static void collect(mps_arena_t arena, size_t expected, int strict) { size_t finalized = 0; mps_arena_collect(arena); @@ -122,7 +122,7 @@ static void collect(mps_arena_t arena, size_t expected) } printf("finalized=%lu expected=%lu\n", (unsigned long)finalized, (unsigned long)expected); - Insist(finalized == expected); + Insist(finalized == expected || !strict); } @@ -131,7 +131,8 @@ static void collect(mps_arena_t arena, size_t expected) */ static void alloc_recursively(mps_arena_t arena, mps_ap_t ap, - size_t expected, size_t count) + size_t expected, size_t count, + int strict) { mps_word_t p, r; mps_word_t q = TAGGED(count << tag_bits, imm); @@ -146,9 +147,9 @@ static void alloc_recursively(mps_arena_t arena, mps_ap_t ap, prevent finalization when scanned with the default mode. */ addr = NULL; if (count > 1) { - alloc_recursively(arena, ap, expected, count - 1); + alloc_recursively(arena, ap, expected, count - 1, strict); } else { - collect(arena, expected); + collect(arena, expected, strict); } if (expected == 0) { Insist(TAG(p) == tag_cons); @@ -235,7 +236,7 @@ static void test(int mode, void *marker) die(mps_ap_create_k(&ap, pool, mps_args_none), "ap"); - alloc_recursively(arena, ap, expected, OBJCOUNT); + alloc_recursively(arena, ap, expected, OBJCOUNT, mode != MODE_DEFAULT); mps_arena_park(arena); mps_ap_destroy(ap); diff --git a/mps/code/th.h b/mps/code/th.h index ed35733002c..03e57bf3bac 100644 --- a/mps/code/th.h +++ b/mps/code/th.h @@ -69,7 +69,8 @@ extern Thread ThreadRingThread(Ring threadRing); extern Arena ThreadArena(Thread thread); extern Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, - Word mask, Word pattern); + mps_area_scan_t scan_area, + void *closure, size_t closure_size); #endif /* th_h */ diff --git a/mps/code/thix.c b/mps/code/thix.c index cb7877223fa..eac01911f6e 100644 --- a/mps/code/thix.c +++ b/mps/code/thix.c @@ -240,7 +240,8 @@ Arena ThreadArena(Thread thread) /* ThreadScan -- scan the state of a thread (stack and regs) */ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, - Word mask, Word pattern) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { pthread_t self; Res res; @@ -250,7 +251,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, if(pthread_equal(self, thread->id)) { /* scan this thread's stack */ AVER(thread->alive); - res = StackScan(ss, stackBot, mask, pattern); + res = StackScan(ss, stackBot, scan_area, closure, closure_size); if(res != ResOK) return res; } else if (thread->alive) { @@ -271,12 +272,12 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, /* scan stack inclusive of current sp and exclusive of * stackBot (.stack.full-descend) */ - res = TraceScanAreaTagged(ss, stackBase, stackLimit, mask, pattern); + res = scan_area(&ss->ss_s, stackBase, stackLimit, closure, closure_size); if(res != ResOK) return res; /* scan the registers in the mutator fault context */ - res = MutatorFaultContextScan(ss, mfc, mask, pattern); + res = MutatorFaultContextScan(ss, mfc, scan_area, closure, closure_size); if(res != ResOK) return res; } diff --git a/mps/code/thw3i3.c b/mps/code/thw3i3.c index d1b632daced..1ce978fc274 100644 --- a/mps/code/thw3i3.c +++ b/mps/code/thw3i3.c @@ -68,7 +68,8 @@ SRCID(thw3i3, "$Id$"); Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, - Word mask, Word pattern) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { DWORD id; Res res; @@ -105,7 +106,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, /* scan stack inclusive of current sp and exclusive of * stackBot (.stack.full-descend) */ - res = TraceScanAreaTagged(ss, stackBase, stackLimit, mask, pattern); + res = scan_area(ss, stackBase, stackLimit, closure, closure_size); if(res != ResOK) return res; @@ -114,14 +115,14 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, * unnecessarily scans the rest of the context. The optimisation * to scan only relevant parts would be machine dependent. */ - res = TraceScanAreaTagged(ss, (Word *)&context, - (Word *)((char *)&context + sizeof(CONTEXT)), - mask, pattern); + res = scan_area(ss, (Word *)&context, + (Word *)((char *)&context + sizeof(CONTEXT)), + closure, closure_size); if(res != ResOK) return res; } else { /* scan this thread's stack */ - res = StackScan(ss, stackBot, mask, pattern); + res = StackScan(ss, stackBot, scan_area, closure, closure_size); if(res != ResOK) return res; } diff --git a/mps/code/thw3i6.c b/mps/code/thw3i6.c index 3f5622a0ca0..6377d85ac15 100644 --- a/mps/code/thw3i6.c +++ b/mps/code/thw3i6.c @@ -68,7 +68,8 @@ SRCID(thw3i6, "$Id$"); Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, - Word mask, Word pattern) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { DWORD id; Res res; @@ -105,7 +106,8 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, /* scan stack inclusive of current sp and exclusive of * stackBot (.stack.full-descend) */ - res = TraceScanAreaTagged(ss, stackBase, stackLimit, mask, pattern); + res = scan_area(ss, stackBase, stackLimit, + void *closure, size_t closure_size); if(res != ResOK) return res; @@ -114,14 +116,14 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, * unnecessarily scans the rest of the context. The optimisation * to scan only relevant parts would be machine dependent. */ - res = TraceScanAreaTagged(ss, (Word *)&context, - (Word *)((char *)&context + sizeof(CONTEXT)), - mask, pattern); + res = scan_area(ss, (Word *)&context, + (Word *)((char *)&context + sizeof(CONTEXT)), + closure, closure_size); if(res != ResOK) return res; } else { /* scan this thread's stack */ - res = StackScan(ss, stackBot, mask, pattern); + res = StackScan(ss, stackBot, scan_area, closure, closure_size); if(res != ResOK) return res; } diff --git a/mps/code/thxc.c b/mps/code/thxc.c index 3deac41ff3a..2fcd8ab71b6 100644 --- a/mps/code/thxc.c +++ b/mps/code/thxc.c @@ -211,7 +211,8 @@ Arena ThreadArena(Thread thread) #include "prmcxc.h" Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, - Word mask, Word pattern) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { mach_port_t self; Res res; @@ -259,12 +260,12 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, /* scan stack inclusive of current sp and exclusive of * stackBot (.stack.full-descend) */ - res = TraceScanAreaTagged(ss, stackBase, stackLimit, mask, pattern); + res = scan_area(ss, stackBase, stackLimit, closure, closure_sized); if(res != ResOK) return res; /* scan the registers in the mutator fault context */ - res = MutatorFaultContextScan(ss, &mfcStruct, mask, pattern); + res = MutatorFaultContextScan(ss, &mfcStruct, scan_area, closure, closure_size); if(res != ResOK) return res; } diff --git a/mps/code/trace.c b/mps/code/trace.c index a2f0b5667cf..324c2167eeb 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1426,27 +1426,6 @@ 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. */ -static mps_res_t mps_scan_area(mps_ss_t, mps_word_t *, mps_word_t *); - -static mps_res_t mps_scan_area(mps_ss_t ss, mps_word_t *base, mps_word_t *limit) -{ - MPS_SCAN_BEGIN(ss) { - mps_word_t *p = base; - while (p < limit) { - mps_word_t word = *p; - mps_addr_t ref = (mps_addr_t)word; - if (MPS_FIX1(ss, ref)) { - mps_res_t res = MPS_FIX2(ss, &ref); - if (res != MPS_RES_OK) - return res; - *p = (mps_word_t)ref; - } - ++p; - } - } MPS_SCAN_END(ss); - - return MPS_RES_OK; -} Res TraceScanArea(ScanState ss, Word *base, Word *limit) { @@ -1456,11 +1435,11 @@ Res TraceScanArea(ScanState ss, Word *base, Word *limit) EVENT3(TraceScanArea, ss, base, limit); - return mps_scan_area(&ss->ss_s, base, limit); + return mps_scan_area(&ss->ss_s, base, limit, NULL, 0); } - +#if 0 /* TraceScanAreaTagged -- scan contiguous area of tagged references * * This is as TraceScanArea except words are only fixed if they have @@ -1470,38 +1449,11 @@ Res TraceScanArea(ScanState ss, Word *base, Word *limit) * sanitizer will think we have run off the end of an array. */ -static mps_res_t mps_scan_area_tagged(mps_ss_t, - mps_word_t *, mps_word_t *, - mps_word_t, mps_word_t); - -ATTRIBUTE_NO_SANITIZE_ADDRESS -static mps_res_t mps_scan_area_tagged(mps_ss_t ss, - mps_word_t *base, mps_word_t *limit, - mps_word_t mask, mps_word_t pattern) -{ - MPS_SCAN_BEGIN(ss) { - mps_word_t *p = base; - while (p < limit) { - mps_word_t word = *p; - if ((word & mask) == pattern) { - mps_addr_t ref = (mps_addr_t)(word ^ pattern); - if (MPS_FIX1(ss, ref)) { - mps_res_t res = MPS_FIX2(ss, &ref); - if (res != MPS_RES_OK) - return res; - *p = (mps_word_t)ref | pattern; - } - } - ++p; - } - } MPS_SCAN_END(ss); - - return MPS_RES_OK; -} - -Res TraceScanAreaTagged(ScanState ss, Word *base, Word *limit, Word mask, +Res TraceScanAreaTagged(ScanState ss, Word *base, Word *limit,Word mask, Word pattern) { + mps_scan_tag_s tag; + AVERT(ScanState, ss); AVER(base != NULL); AVER(limit != NULL); @@ -1509,8 +1461,12 @@ Res TraceScanAreaTagged(ScanState ss, Word *base, Word *limit, Word mask, EVENT3(TraceScanAreaTagged, ss, base, limit); - return mps_scan_area_tagged(&ss->ss_s, base, limit, mask, pattern); + tag.mask = mask; + tag.pattern = pattern; + + return mps_scan_area_tagged(&ss->ss_s, base, limit, &tag, 0); } +#endif /* traceCondemnAll -- condemn everything and notify all the chains */ From 16bde84a682e0a91073448c665a45bd8cd545d06 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 15 Feb 2016 15:44:57 +0000 Subject: [PATCH 128/337] Generalising tracescanarea to be a checking wrapper for all area scanners. Copied from Perforce Change: 189190 ServerID: perforce.ravenbrook.com --- mps/code/mpm.h | 6 +++--- mps/code/prmci3fr.c | 4 ++-- mps/code/prmci3li.c | 8 ++++---- mps/code/prmci3xc.c | 8 ++++---- mps/code/prmci6fr.c | 4 ++-- mps/code/prmci6li.c | 8 ++++---- mps/code/prmci6xc.c | 8 ++++---- mps/code/root.c | 3 ++- mps/code/ss.c | 11 ++++++----- mps/code/thix.c | 3 ++- mps/code/thw3i3.c | 9 +++++---- mps/code/thw3i6.c | 10 +++++----- mps/code/thxc.c | 3 ++- mps/code/trace.c | 37 +++++-------------------------------- 14 files changed, 50 insertions(+), 72 deletions(-) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 565641f8cdf..d4795b32c91 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -473,9 +473,9 @@ extern double TraceWorkFactor; } \ END -extern Res TraceScanArea(ScanState ss, Word *base, Word *limit); -extern Res TraceScanAreaTagged(ScanState ss, Word *base, Word *limit, - Word mask, Word value); +extern Res TraceScanArea(ScanState ss, Word *base, Word *limit, + mps_area_scan_t scan_area, + void *closure, size_t closure_size); extern void TraceScanSingleRef(TraceSet ts, Rank rank, Arena arena, Seg seg, Ref *refIO); diff --git a/mps/code/prmci3fr.c b/mps/code/prmci3fr.c index 60392a11417..ffbe4dc3e7d 100644 --- a/mps/code/prmci3fr.c +++ b/mps/code/prmci3fr.c @@ -47,11 +47,11 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, /* 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 = scan_area( + res = TraceScanArea( ss, (Word *)mfc->ucontext, (Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))), - closure, closure_size + scan_area, closure, closure_size ); return res; diff --git a/mps/code/prmci3li.c b/mps/code/prmci3li.c index 4b404317010..635676832d8 100644 --- a/mps/code/prmci3li.c +++ b/mps/code/prmci3li.c @@ -112,10 +112,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 = scan_area(ss, - (Word *)mc, - (Word *)((char *)mc + sizeof(*mc)), - closure, closure_size); + res = TraceScanArea(ss, + (Word *)mc, + (Word *)((char *)mc + sizeof(*mc)), + scan_area, closure, closure_size); return res; } diff --git a/mps/code/prmci3xc.c b/mps/code/prmci3xc.c index 91507de6f8a..b133656f3b1 100644 --- a/mps/code/prmci3xc.c +++ b/mps/code/prmci3xc.c @@ -107,10 +107,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 = scan_area(ss, - (Word *)mc, - (Word *)((char *)mc + sizeof(*mc)), - closure, closure_size); + res = TraceScanArea(ss, + (Word *)mc, + (Word *)((char *)mc + sizeof(*mc)), + scan_area, closure, closure_size); return res; } diff --git a/mps/code/prmci6fr.c b/mps/code/prmci6fr.c index 55212077a78..8dd2a680f6e 100644 --- a/mps/code/prmci6fr.c +++ b/mps/code/prmci6fr.c @@ -41,11 +41,11 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, /* 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 = scan_area( + res = TraceScanArea( ss, (Word *)mfc->ucontext, (Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))), - closure, closure_size + scan_area, closure, closure_size ); return res; diff --git a/mps/code/prmci6li.c b/mps/code/prmci6li.c index a88b78211bf..ef4f0c000cc 100644 --- a/mps/code/prmci6li.c +++ b/mps/code/prmci6li.c @@ -116,10 +116,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 = scan_area(&ss->ss_s, - (Word *)mc, - (Word *)((char *)mc + sizeof(*mc)), - closure, closure_size); + res = TraceScanArea(ss, + (Word *)mc, + (Word *)((char *)mc + sizeof(*mc)), + scan_area, closure, closure_size); return res; } diff --git a/mps/code/prmci6xc.c b/mps/code/prmci6xc.c index 309d4066b64..bbea768ceee 100644 --- a/mps/code/prmci6xc.c +++ b/mps/code/prmci6xc.c @@ -110,10 +110,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 = scan_area(ss, - (Word *)mc, - (Word *)((char *)mc + sizeof(*mc)), - closure, closure_size); + res = TraceScanArea(ss, + (Word *)mc, + (Word *)((char *)mc + sizeof(*mc)), + scan_area, closure, closure_size); return res; } diff --git a/mps/code/root.c b/mps/code/root.c index 8b92a186726..43c325fd237 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -507,7 +507,8 @@ Res RootScan(ScanState ss, Root root) switch(root->var) { case RootTABLE: - res = TraceScanArea(ss, root->the.table.base, root->the.table.limit); + res = TraceScanArea(ss, root->the.table.base, root->the.table.limit, + mps_scan_area, NULL, 0); ss->scannedSize += AddrOffset(root->the.table.base, root->the.table.limit); if (res != ResOK) goto failScan; diff --git a/mps/code/ss.c b/mps/code/ss.c index 93ff85be103..40f367400ed 100644 --- a/mps/code/ss.c +++ b/mps/code/ss.c @@ -49,16 +49,17 @@ Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop, if (arena->stackAtArenaEnter != NULL) { AVER(stackTop < arena->stackAtArenaEnter); AVER(arena->stackAtArenaEnter < stackBot); - res = scan_area(&ss->ss_s, stackTop, stackTop + nSavedRegs, - closure, closure_size); + res = TraceScanArea(ss, stackTop, stackTop + nSavedRegs, + scan_area, closure, closure_size); if (res != ResOK) return res; - res = scan_area(&ss->ss_s, arena->stackAtArenaEnter, stackBot, - closure, closure_size); + res = TraceScanArea(ss, arena->stackAtArenaEnter, stackBot, + scan_area, closure, closure_size); if (res != ResOK) return res; } else { - res = scan_area(&ss->ss_s, stackTop, stackBot, closure, closure_size); + res = TraceScanArea(ss, stackTop, stackBot, + scan_area, closure, closure_size); if (res != ResOK) return res; } diff --git a/mps/code/thix.c b/mps/code/thix.c index eac01911f6e..8d3bfe28a5f 100644 --- a/mps/code/thix.c +++ b/mps/code/thix.c @@ -272,7 +272,8 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, /* scan stack inclusive of current sp and exclusive of * stackBot (.stack.full-descend) */ - res = scan_area(&ss->ss_s, stackBase, stackLimit, closure, closure_size); + res = TraceScanArea(ss, stackBase, stackLimit, + scan_area, closure, closure_size); if(res != ResOK) return res; diff --git a/mps/code/thw3i3.c b/mps/code/thw3i3.c index 1ce978fc274..cbe971f3e2a 100644 --- a/mps/code/thw3i3.c +++ b/mps/code/thw3i3.c @@ -106,7 +106,8 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, /* scan stack inclusive of current sp and exclusive of * stackBot (.stack.full-descend) */ - res = scan_area(ss, stackBase, stackLimit, closure, closure_size); + res = TraceScanArea(ss, stackBase, stackLimit, + scan_area, closure, closure_size); if(res != ResOK) return res; @@ -115,9 +116,9 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, * unnecessarily scans the rest of the context. The optimisation * to scan only relevant parts would be machine dependent. */ - res = scan_area(ss, (Word *)&context, - (Word *)((char *)&context + sizeof(CONTEXT)), - closure, closure_size); + res = TraceScanArea(ss, (Word *)&context, + (Word *)((char *)&context + sizeof(CONTEXT)), + scan_area, closure, closure_size); if(res != ResOK) return res; diff --git a/mps/code/thw3i6.c b/mps/code/thw3i6.c index 6377d85ac15..d1f94f37f0e 100644 --- a/mps/code/thw3i6.c +++ b/mps/code/thw3i6.c @@ -106,8 +106,8 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, /* scan stack inclusive of current sp and exclusive of * stackBot (.stack.full-descend) */ - res = scan_area(ss, stackBase, stackLimit, - void *closure, size_t closure_size); + res = TraceScanArea(ss, stackBase, stackLimit, + scan_area, closure, closure_size); if(res != ResOK) return res; @@ -116,9 +116,9 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, * unnecessarily scans the rest of the context. The optimisation * to scan only relevant parts would be machine dependent. */ - res = scan_area(ss, (Word *)&context, - (Word *)((char *)&context + sizeof(CONTEXT)), - closure, closure_size); + res = TraceScanArea(ss, (Word *)&context, + (Word *)((char *)&context + sizeof(CONTEXT)), + scan_area, closure, closure_size); if(res != ResOK) return res; diff --git a/mps/code/thxc.c b/mps/code/thxc.c index 2fcd8ab71b6..e2206ceb0c7 100644 --- a/mps/code/thxc.c +++ b/mps/code/thxc.c @@ -260,7 +260,8 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, /* scan stack inclusive of current sp and exclusive of * stackBot (.stack.full-descend) */ - res = scan_area(ss, stackBase, stackLimit, closure, closure_sized); + res = TraceScanArea(ss, stackBase, stackLimit, + scan_area, closure, closure_size); if(res != ResOK) return res; diff --git a/mps/code/trace.c b/mps/code/trace.c index 324c2167eeb..8867f958a1e 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1427,48 +1427,21 @@ void TraceScanSingleRef(TraceSet ts, Rank rank, Arena arena, * limit, inclusive of base and exclusive of limit. */ -Res TraceScanArea(ScanState ss, Word *base, Word *limit) +Res TraceScanArea(ScanState ss, Word *base, Word *limit, + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { + AVERT(ScanState, ss); AVER(base != NULL); AVER(limit != NULL); AVER(base < limit); EVENT3(TraceScanArea, ss, base, limit); - return mps_scan_area(&ss->ss_s, base, limit, NULL, 0); + return scan_area(&ss->ss_s, base, limit, closure, closure_size); } -#if 0 -/* TraceScanAreaTagged -- scan contiguous area of tagged references - * - * 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. - */ - -Res TraceScanAreaTagged(ScanState ss, Word *base, Word *limit,Word mask, - Word pattern) -{ - mps_scan_tag_s tag; - - AVERT(ScanState, ss); - AVER(base != NULL); - AVER(limit != NULL); - AVER(base < limit); - - EVENT3(TraceScanAreaTagged, ss, base, limit); - - tag.mask = mask; - tag.pattern = pattern; - - return mps_scan_area_tagged(&ss->ss_s, base, limit, &tag, 0); -} -#endif - - /* traceCondemnAll -- condemn everything and notify all the chains */ static Res traceCondemnAll(Trace trace) From 6b7c5f3d74c293922103111712588cb88fdf5005 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 15 Feb 2016 16:46:09 +0000 Subject: [PATCH 129/337] Lifting assumptions about area scanners closer to interface. Copied from Perforce Change: 189191 ServerID: perforce.ravenbrook.com --- mps/code/mps.h | 8 +++---- mps/code/mpsi.c | 57 +++++++++++++++++++++++++++++++++--------------- mps/code/root.c | 33 ++++++++++++++++++++-------- mps/code/trace.c | 1 - 4 files changed, 67 insertions(+), 32 deletions(-) diff --git a/mps/code/mps.h b/mps/code/mps.h index 6614db23f09..029bcfddf64 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -669,14 +669,14 @@ extern mps_res_t mps_root_create(mps_root_t *, mps_arena_t, mps_rank_t, extern mps_res_t mps_root_create_table(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_addr_t *, size_t); -extern mps_res_t mps_root_create_table_tagged(mps_root_t *, mps_arena_t, - mps_rank_t, mps_rm_t, - mps_addr_t *, size_t, - mps_word_t, mps_word_t); extern mps_res_t mps_root_create_table_masked(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_addr_t *, size_t, mps_word_t); +extern mps_res_t mps_root_create_area(mps_root_t *, mps_arena_t, + mps_rank_t, mps_rm_t, + mps_word_t *, mps_word_t *, + mps_area_scan_t, void *, size_t); extern mps_res_t mps_root_create_fmt(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_fmt_scan_t, mps_addr_t, diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 22adaa345c8..5a0b56aec05 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1314,11 +1314,44 @@ mps_res_t mps_root_create_table(mps_root_t *mps_root_o, mps_arena_t arena, return MPS_RES_OK; } -mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, +mps_res_t mps_root_create_area(mps_root_t *mps_root_o, + mps_arena_t arena, + mps_rank_t mps_rank, mps_rm_t mps_rm, + mps_word_t *base, mps_word_t *limit, + mps_area_scan_t scan_area, + void *closure, size_t closure_size) +{ + Rank rank = (Rank)mps_rank; + RootMode mode = (RootMode)mps_rm; + + ArenaEnter(arena); + + AVER(mps_root_o != NULL); + AVER(base != NULL); + AVER(limit != NULL); + AVER(base < limit); + AVER(FUNCHECK(scan_area)); + /* Can't check anything about closure */ + + /* See .root.table-size. */ + + /* FIXME: Implement! */ + UNUSED(rank); + UNUSED(mode); + UNUSED(closure); + UNUSED(closure_size); + NOTREACHED; + + ArenaLeave(arena); + + return ResUNIMPL; +} + +mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, mps_arena_t arena, mps_rank_t mps_rank, mps_rm_t mps_rm, mps_addr_t *base, size_t size, - mps_word_t mask, mps_word_t pattern) + mps_word_t mask) { Rank rank = (Rank)mps_rank; Root root; @@ -1330,14 +1363,12 @@ mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, AVER(mps_root_o != NULL); AVER(base != NULL); AVER(size > 0); - /* Can't check anything about mask */ - AVER((pattern & mask) == pattern); - - /* See .root.table-size. */ + /* Can't check anything about mask. */ + /* .root.table-size */ res = RootCreateTableTagged(&root, arena, rank, mode, - (Word *)base, (Word *)base + size, - mask, pattern); + (Word *)base, (Word *)base + size, + mask, 0); ArenaLeave(arena); @@ -1347,16 +1378,6 @@ mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, return MPS_RES_OK; } -mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, - mps_arena_t arena, - mps_rank_t mps_rank, mps_rm_t mps_rm, - mps_addr_t *base, size_t size, - mps_word_t mask) -{ - return mps_root_create_table_tagged(mps_root_o, arena, mps_rank, mps_rm, - base, size, mask, 0); -} - mps_res_t mps_root_create_fmt(mps_root_t *mps_root_o, mps_arena_t arena, mps_rank_t mps_rank, mps_rm_t mps_rm, mps_fmt_scan_t scan, diff --git a/mps/code/root.c b/mps/code/root.c index 43c325fd237..47e742489d2 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -40,10 +40,14 @@ typedef struct RootStruct { struct { Word *base; /* beginning of table */ Word *limit; /* one off end of table */ + mps_area_scan_t scan_area;/* area scanning function */ + void *closure; /* closure for scanning function */ + size_t closure_size; /* closure for scanning function */ } table; struct { Word *base; /* beginning of table */ Word *limit; /* one off end of table */ + mps_area_scan_t scan_area;/* area scanning function */ mps_scan_tag_s tag; /* tag for scanning */ } tableMasked; struct { @@ -54,6 +58,7 @@ typedef struct RootStruct { } reg; struct { Thread thread; /* passed to scan */ + mps_area_scan_t scan_area;/* area scanner for stack and registers */ mps_scan_tag_s tag; /* tag for scanning */ Word *stackBot; /* bottom of stack */ } regMasked; @@ -282,6 +287,9 @@ Res RootCreateTable(Root *rootReturn, Arena arena, theUnion.table.base = base; theUnion.table.limit = limit; + theUnion.table.scan_area = mps_scan_area; + theUnion.table.closure = NULL; + theUnion.table.closure_size = 0; res = rootCreateProtectable(rootReturn, arena, rank, mode, RootTABLE, (Addr)base, (Addr)limit, &theUnion); @@ -300,9 +308,11 @@ Res RootCreateTableTagged(Root *rootReturn, Arena arena, AVER(base != 0); AVER(base < limit); /* Can't check anything about mask. */ + AVER((mask & pattern) == pattern); theUnion.tableMasked.base = base; theUnion.tableMasked.limit = limit; + theUnion.tableMasked.scan_area = mps_scan_area_tagged; theUnion.tableMasked.tag.mask = mask; theUnion.tableMasked.tag.pattern = pattern; @@ -345,6 +355,7 @@ Res RootCreateRegMasked(Root *rootReturn, Arena arena, AVER((~mask & pattern) == 0); theUnion.regMasked.thread = thread; + theUnion.regMasked.scan_area = mps_scan_area_tagged; theUnion.regMasked.tag.mask = mask; theUnion.regMasked.tag.pattern = pattern; theUnion.regMasked.stackBot = stackBot; @@ -507,20 +518,24 @@ Res RootScan(ScanState ss, Root root) switch(root->var) { case RootTABLE: - res = TraceScanArea(ss, root->the.table.base, root->the.table.limit, - mps_scan_area, NULL, 0); + res = TraceScanArea(ss, + root->the.table.base, + root->the.table.limit, + root->the.table.scan_area, + root->the.table.closure, + root->the.table.closure_size); ss->scannedSize += AddrOffset(root->the.table.base, root->the.table.limit); if (res != ResOK) goto failScan; break; case RootTABLE_MASKED: - /* FIXME: wrap in checking method */ - res = mps_scan_area_tagged(&ss->ss_s, - root->the.tableMasked.base, - root->the.tableMasked.limit, - &root->the.tableMasked.tag, - sizeof(root->the.tableMasked.tag)); + res = TraceScanArea(ss, + root->the.tableMasked.base, + root->the.tableMasked.limit, + root->the.tableMasked.scan_area, + &root->the.tableMasked.tag, + sizeof(root->the.tableMasked.tag)); ss->scannedSize += AddrOffset(root->the.table.base, root->the.table.limit); if (res != ResOK) goto failScan; @@ -542,7 +557,7 @@ Res RootScan(ScanState ss, Root root) case RootREG_MASKED: res = ThreadScan(ss, root->the.regMasked.thread, root->the.regMasked.stackBot, - mps_scan_area_tagged, + root->the.regMasked.scan_area, &root->the.regMasked.tag, sizeof(root->the.regMasked.tag)); if (res != ResOK) diff --git a/mps/code/trace.c b/mps/code/trace.c index 8867f958a1e..bee5e64b2ac 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1426,7 +1426,6 @@ 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, Word *base, Word *limit, mps_area_scan_t scan_area, void *closure, size_t closure_size) From 3b33c0808bf97c77576fbd1b6c9473e409c1adf0 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 15 Feb 2016 16:56:42 +0000 Subject: [PATCH 130/337] Generalising roottable_masked to rootarea_tagged and lifting scanner assumption. Copied from Perforce Change: 189192 ServerID: perforce.ravenbrook.com --- mps/code/mpm.h | 9 ++++---- mps/code/mpmtypes.h | 2 +- mps/code/mpsi.c | 6 +++--- mps/code/root.c | 52 ++++++++++++++++++++++----------------------- 4 files changed, 35 insertions(+), 34 deletions(-) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index d4795b32c91..a362d068bb6 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -950,10 +950,11 @@ extern void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from); extern Res RootCreateTable(Root *rootReturn, Arena arena, Rank rank, RootMode mode, Word *base, Word *limit); -extern Res RootCreateTableTagged(Root *rootReturn, Arena arena, - Rank rank, RootMode mode, - Word *base, Word *limit, - Word mask, Word pattern); +extern Res RootCreateAreaTagged(Root *rootReturn, Arena arena, + Rank rank, RootMode mode, + Word *base, Word *limit, + mps_area_scan_t scan_area, + Word mask, Word pattern); extern Res RootCreateReg(Root *rootReturn, Arena arena, Rank rank, Thread thread, mps_reg_scan_t scan, diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index c241a04c64a..25e03145d44 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -360,7 +360,7 @@ enum { enum { RootFUN, RootTABLE, - RootTABLE_MASKED, + RootAREA_TAGGED, RootREG, RootREG_MASKED, RootFMT, diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 5a0b56aec05..865f0986ebc 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1366,9 +1366,9 @@ mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, /* Can't check anything about mask. */ /* .root.table-size */ - res = RootCreateTableTagged(&root, arena, rank, mode, - (Word *)base, (Word *)base + size, - mask, 0); + res = RootCreateAreaTagged(&root, arena, rank, mode, + (Word *)base, (Word *)base + size, + mps_scan_area_masked, mask, 0); ArenaLeave(arena); diff --git a/mps/code/root.c b/mps/code/root.c index 47e742489d2..79e4c2d2bd7 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -49,7 +49,7 @@ typedef struct RootStruct { Word *limit; /* one off end of table */ mps_area_scan_t scan_area;/* area scanning function */ mps_scan_tag_s tag; /* tag for scanning */ - } tableMasked; + } areaTagged; struct { mps_reg_scan_t scan; /* function for scanning registers */ Thread thread; /* passed to scan */ @@ -76,7 +76,7 @@ typedef struct RootStruct { Bool RootVarCheck(RootVar rootVar) { - CHECKL(rootVar == RootTABLE || rootVar == RootTABLE_MASKED + CHECKL(rootVar == RootTABLE || rootVar == RootAREA_TAGGED || rootVar == RootFUN || rootVar == RootFMT || rootVar == RootREG || rootVar == RootREG_MASKED); UNUSED(rootVar); @@ -120,10 +120,10 @@ Bool RootCheck(Root root) CHECKL(root->the.table.base < root->the.table.limit); break; - case RootTABLE_MASKED: - CHECKL(root->the.tableMasked.base != 0); - CHECKL(root->the.tableMasked.base < root->the.tableMasked.limit); - CHECKL((~root->the.tableMasked.tag.mask & root->the.tableMasked.tag.pattern) == 0); + case RootAREA_TAGGED: + CHECKL(root->the.areaTagged.base != 0); + CHECKL(root->the.areaTagged.base < root->the.areaTagged.limit); + CHECKL((~root->the.areaTagged.tag.mask & root->the.areaTagged.tag.pattern) == 0); break; case RootFUN: @@ -296,9 +296,9 @@ Res RootCreateTable(Root *rootReturn, Arena arena, return res; } -Res RootCreateTableTagged(Root *rootReturn, Arena arena, - Rank rank, RootMode mode, Word *base, Word *limit, - Word mask, Word pattern) +Res RootCreateAreaTagged(Root *rootReturn, Arena arena, + Rank rank, RootMode mode, Word *base, Word *limit, + mps_area_scan_t scan_area, Word mask, Word pattern) { union RootUnion theUnion; @@ -310,13 +310,13 @@ Res RootCreateTableTagged(Root *rootReturn, Arena arena, /* Can't check anything about mask. */ AVER((mask & pattern) == pattern); - theUnion.tableMasked.base = base; - theUnion.tableMasked.limit = limit; - theUnion.tableMasked.scan_area = mps_scan_area_tagged; - theUnion.tableMasked.tag.mask = mask; - theUnion.tableMasked.tag.pattern = pattern; + theUnion.areaTagged.base = base; + theUnion.areaTagged.limit = limit; + theUnion.areaTagged.scan_area = scan_area; + theUnion.areaTagged.tag.mask = mask; + theUnion.areaTagged.tag.pattern = pattern; - return rootCreateProtectable(rootReturn, arena, rank, mode, RootTABLE_MASKED, + return rootCreateProtectable(rootReturn, arena, rank, mode, RootAREA_TAGGED, (Addr)base, (Addr)limit, &theUnion); } @@ -529,13 +529,13 @@ Res RootScan(ScanState ss, Root root) goto failScan; break; - case RootTABLE_MASKED: + case RootAREA_TAGGED: res = TraceScanArea(ss, - root->the.tableMasked.base, - root->the.tableMasked.limit, - root->the.tableMasked.scan_area, - &root->the.tableMasked.tag, - sizeof(root->the.tableMasked.tag)); + root->the.areaTagged.base, + root->the.areaTagged.limit, + root->the.areaTagged.scan_area, + &root->the.areaTagged.tag, + sizeof(root->the.areaTagged.tag)); ss->scannedSize += AddrOffset(root->the.table.base, root->the.table.limit); if (res != ResOK) goto failScan; @@ -698,13 +698,13 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) return res; break; - case RootTABLE_MASKED: + case RootAREA_TAGGED: res = WriteF(stream, depth + 2, "table base $A limit $A mask $B pattern $B\n", - (WriteFA)root->the.tableMasked.base, - (WriteFA)root->the.tableMasked.limit, - (WriteFB)root->the.tableMasked.tag.mask, - (WriteFB)root->the.tableMasked.tag.pattern, + (WriteFA)root->the.areaTagged.base, + (WriteFA)root->the.areaTagged.limit, + (WriteFB)root->the.areaTagged.tag.mask, + (WriteFB)root->the.areaTagged.tag.pattern, NULL); if (res != ResOK) return res; From b04dbd867755617f03f132ed2f9470c4b343c3bc Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 15 Feb 2016 17:30:45 +0000 Subject: [PATCH 131/337] Generalising roottable to rootarea and using it to implement mps_root_create_table_* and mps_root_create_area. Copied from Perforce Change: 189193 ServerID: perforce.ravenbrook.com --- mps/code/mpm.h | 8 +++-- mps/code/mpmtypes.h | 2 +- mps/code/mps.h | 7 +++++ mps/code/mpsi.c | 47 +++++++++++++++++++--------- mps/code/root.c | 76 +++++++++++++++++++++++++++------------------ 5 files changed, 90 insertions(+), 50 deletions(-) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index a362d068bb6..3fcd56d2c77 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -947,9 +947,11 @@ extern void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from); /* Root Interface -- see */ -extern Res RootCreateTable(Root *rootReturn, Arena arena, - Rank rank, RootMode mode, - Word *base, Word *limit); +extern Res RootCreateArea(Root *rootReturn, Arena arena, + Rank rank, RootMode mode, + Word *base, Word *limit, + mps_area_scan_t scan_area, + void *closure, size_t closure_size); extern Res RootCreateAreaTagged(Root *rootReturn, Arena arena, Rank rank, RootMode mode, Word *base, Word *limit, diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 25e03145d44..1dacecbac0f 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -359,7 +359,7 @@ enum { enum { RootFUN, - RootTABLE, + RootAREA, RootAREA_TAGGED, RootREG, RootREG_MASKED, diff --git a/mps/code/mps.h b/mps/code/mps.h index 029bcfddf64..92a02399f10 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -669,6 +669,13 @@ extern mps_res_t mps_root_create(mps_root_t *, mps_arena_t, mps_rank_t, extern mps_res_t mps_root_create_table(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_addr_t *, size_t); +extern mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, + mps_arena_t arena, + mps_rank_t mps_rank, mps_rm_t mps_rm, + mps_addr_t *base, size_t size, + mps_area_scan_t scan_area, + mps_word_t mask, + mps_word_t pattern); extern mps_res_t mps_root_create_table_masked(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_addr_t *, size_t, diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 865f0986ebc..c55b4763890 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1300,11 +1300,12 @@ mps_res_t mps_root_create_table(mps_root_t *mps_root_o, mps_arena_t arena, AVER(size > 0); /* .root.table-size: size is the length of the array at base, not */ - /* the size in bytes. However, RootCreateTable expects base and */ + /* the size in bytes. However, RootCreateArea expects base and */ /* limit pointers. Be careful. */ - res = RootCreateTable(&root, arena, rank, mode, - (Word *)base, (Word *)base + size); + res = RootCreateArea(&root, arena, rank, mode, + (Word *)base, (Word *)base + size, + mps_scan_area, NULL, 0); ArenaLeave(arena); @@ -1314,6 +1315,7 @@ mps_res_t mps_root_create_table(mps_root_t *mps_root_o, mps_arena_t arena, return MPS_RES_OK; } +/* FIXME: document */ mps_res_t mps_root_create_area(mps_root_t *mps_root_o, mps_arena_t arena, mps_rank_t mps_rank, mps_rm_t mps_rm, @@ -1322,7 +1324,9 @@ mps_res_t mps_root_create_area(mps_root_t *mps_root_o, void *closure, size_t closure_size) { Rank rank = (Rank)mps_rank; + Root root; RootMode mode = (RootMode)mps_rm; + Res res; ArenaEnter(arena); @@ -1333,25 +1337,25 @@ mps_res_t mps_root_create_area(mps_root_t *mps_root_o, AVER(FUNCHECK(scan_area)); /* Can't check anything about closure */ - /* See .root.table-size. */ - - /* FIXME: Implement! */ - UNUSED(rank); - UNUSED(mode); - UNUSED(closure); - UNUSED(closure_size); - NOTREACHED; + res = RootCreateArea(&root, arena, rank, mode, + base, limit, + scan_area, closure, closure_size); ArenaLeave(arena); - return ResUNIMPL; + if (res != ResOK) + return (mps_res_t)res; + *mps_root_o = (mps_root_t)root; + return MPS_RES_OK; } -mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, +mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, mps_arena_t arena, mps_rank_t mps_rank, mps_rm_t mps_rm, mps_addr_t *base, size_t size, - mps_word_t mask) + mps_area_scan_t scan_area, + mps_word_t mask, + mps_word_t pattern) { Rank rank = (Rank)mps_rank; Root root; @@ -1363,12 +1367,14 @@ mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, AVER(mps_root_o != NULL); AVER(base != NULL); AVER(size > 0); + AVER(FUNCHECK(scan_area)); /* Can't check anything about mask. */ + AVER((pattern & mask) == pattern); /* .root.table-size */ res = RootCreateAreaTagged(&root, arena, rank, mode, (Word *)base, (Word *)base + size, - mps_scan_area_masked, mask, 0); + scan_area, mask, pattern); ArenaLeave(arena); @@ -1378,6 +1384,17 @@ mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, return MPS_RES_OK; } +mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, + mps_arena_t arena, + mps_rank_t mps_rank, mps_rm_t mps_rm, + mps_addr_t *base, size_t size, + mps_word_t mask) +{ + return mps_root_create_table_tagged(mps_root_o, arena, mps_rank, mps_rm, + base, size, mps_scan_area_masked, + mask, 0); +} + mps_res_t mps_root_create_fmt(mps_root_t *mps_root_o, mps_arena_t arena, mps_rank_t mps_rank, mps_rm_t mps_rm, mps_fmt_scan_t scan, diff --git a/mps/code/root.c b/mps/code/root.c index 79e4c2d2bd7..91708c8f1b2 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -38,15 +38,15 @@ typedef struct RootStruct { size_t s; /* environment for scan */ } fun; struct { - Word *base; /* beginning of table */ - Word *limit; /* one off end of table */ + Word *base; /* beginning of area */ + Word *limit; /* one off end of area */ mps_area_scan_t scan_area;/* area scanning function */ void *closure; /* closure for scanning function */ size_t closure_size; /* closure for scanning function */ - } table; + } area; struct { - Word *base; /* beginning of table */ - Word *limit; /* one off end of table */ + Word *base; /* beginning of area */ + Word *limit; /* one off end of area */ mps_area_scan_t scan_area;/* area scanning function */ mps_scan_tag_s tag; /* tag for scanning */ } areaTagged; @@ -76,7 +76,7 @@ typedef struct RootStruct { Bool RootVarCheck(RootVar rootVar) { - CHECKL(rootVar == RootTABLE || rootVar == RootAREA_TAGGED + CHECKL(rootVar == RootAREA || rootVar == RootAREA_TAGGED || rootVar == RootFUN || rootVar == RootFMT || rootVar == RootREG || rootVar == RootREG_MASKED); UNUSED(rootVar); @@ -115,14 +115,17 @@ Bool RootCheck(Root root) /* Don't need to check var here, because of the switch below */ switch(root->var) { - case RootTABLE: - CHECKL(root->the.table.base != 0); - CHECKL(root->the.table.base < root->the.table.limit); + case RootAREA: + CHECKL(root->the.area.base != 0); + CHECKL(root->the.area.base < root->the.area.limit); + CHECKL(FUNCHECK(root->the.area.scan_area)); + /* Can't check anything about closure */ break; case RootAREA_TAGGED: CHECKL(root->the.areaTagged.base != 0); CHECKL(root->the.areaTagged.base < root->the.areaTagged.limit); + CHECKL(FUNCHECK(root->the.areaTagged.scan_area)); CHECKL((~root->the.areaTagged.tag.mask & root->the.areaTagged.tag.pattern) == 0); break; @@ -138,6 +141,7 @@ Bool RootCheck(Root root) case RootREG_MASKED: CHECKD_NOSIG(Thread, root->the.regMasked.thread); /* */ + CHECKL(FUNCHECK(root->the.regMasked.scan_area)); CHECKL((~root->the.regMasked.tag.mask & root->the.regMasked.tag.pattern) == 0); /* Can't check anything about stackBot. */ break; @@ -167,7 +171,7 @@ Bool RootCheck(Root root) } -/* rootCreate, RootCreateTable, RootCreateReg, RootCreateFmt, RootCreateFun +/* rootCreate, RootCreateArea, RootCreateReg, RootCreateFmt, RootCreateFun * * RootCreate* set up the appropriate union member, and call the generic * create function to do the actual creation @@ -271,8 +275,11 @@ static Res rootCreateProtectable(Root *rootReturn, Arena arena, return ResOK; } -Res RootCreateTable(Root *rootReturn, Arena arena, - Rank rank, RootMode mode, Word *base, Word *limit) +Res RootCreateArea(Root *rootReturn, Arena arena, + Rank rank, RootMode mode, + Word *base, Word *limit, + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { Res res; union RootUnion theUnion; @@ -284,15 +291,17 @@ Res RootCreateTable(Root *rootReturn, Arena arena, AVER(AddrIsAligned(base, sizeof(Word))); AVER(base < limit); AVER(AddrIsAligned(limit, sizeof(Word))); + AVER(FUNCHECK(scan_area)); + /* Can't check anything about closure */ - theUnion.table.base = base; - theUnion.table.limit = limit; - theUnion.table.scan_area = mps_scan_area; - theUnion.table.closure = NULL; - theUnion.table.closure_size = 0; + theUnion.area.base = base; + theUnion.area.limit = limit; + theUnion.area.scan_area = scan_area; + theUnion.area.closure = closure; + theUnion.area.closure_size = closure_size; res = rootCreateProtectable(rootReturn, arena, rank, mode, - RootTABLE, (Addr)base, (Addr)limit, &theUnion); + RootAREA, (Addr)base, (Addr)limit, &theUnion); return res; } @@ -517,14 +526,14 @@ Res RootScan(ScanState ss, Root root) } switch(root->var) { - case RootTABLE: + case RootAREA: res = TraceScanArea(ss, - root->the.table.base, - root->the.table.limit, - root->the.table.scan_area, - root->the.table.closure, - root->the.table.closure_size); - ss->scannedSize += AddrOffset(root->the.table.base, root->the.table.limit); + root->the.area.base, + root->the.area.limit, + root->the.area.scan_area, + root->the.area.closure, + root->the.area.closure_size); + ss->scannedSize += AddrOffset(root->the.area.base, root->the.area.limit); if (res != ResOK) goto failScan; break; @@ -536,7 +545,7 @@ Res RootScan(ScanState ss, Root root) root->the.areaTagged.scan_area, &root->the.areaTagged.tag, sizeof(root->the.areaTagged.tag)); - ss->scannedSize += AddrOffset(root->the.table.base, root->the.table.limit); + ss->scannedSize += AddrOffset(root->the.areaTagged.base, root->the.areaTagged.limit); if (res != ResOK) goto failScan; break; @@ -688,11 +697,14 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) return res; switch(root->var) { - case RootTABLE: + case RootAREA: res = WriteF(stream, depth + 2, - "table base $A limit $A\n", - (WriteFA)root->the.table.base, - (WriteFA)root->the.table.limit, + "area base $A limit $A scan_area $P closure $P closure_size $U\n", + (WriteFA)root->the.area.base, + (WriteFA)root->the.area.limit, + (WriteFP)root->the.area.scan_area, + (WriteFP)root->the.area.closure, + (WriteFP)root->the.area.closure_size, NULL); if (res != ResOK) return res; @@ -700,9 +712,10 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) case RootAREA_TAGGED: res = WriteF(stream, depth + 2, - "table base $A limit $A mask $B pattern $B\n", + "area base $A limit $A scan_area $P mask $B pattern $B\n", (WriteFA)root->the.areaTagged.base, (WriteFA)root->the.areaTagged.limit, + (WriteFP)root->the.areaTagged.scan_area, (WriteFB)root->the.areaTagged.tag.mask, (WriteFB)root->the.areaTagged.tag.pattern, NULL); @@ -732,6 +745,7 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) case RootREG_MASKED: res = WriteF(stream, depth + 2, "thread $P\n", (WriteFP)root->the.regMasked.thread, + "scan_area $P\n", (WriteFP)root->the.regMasked.scan_area, "mask $B\n", (WriteFB)root->the.regMasked.tag.mask, "pattern $B\n", (WriteFB)root->the.regMasked.tag.pattern, "stackBot $P\n", (WriteFP)root->the.regMasked.stackBot, From 9d0ae49fc933ee4b2af9fc2991eb1433f32f7f35 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 15 Feb 2016 17:32:12 +0000 Subject: [PATCH 132/337] Fixing case label indents. Copied from Perforce Change: 189194 ServerID: perforce.ravenbrook.com --- mps/code/root.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mps/code/root.c b/mps/code/root.c index 91708c8f1b2..4433df89033 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -526,7 +526,7 @@ Res RootScan(ScanState ss, Root root) } switch(root->var) { - case RootAREA: + case RootAREA: res = TraceScanArea(ss, root->the.area.base, root->the.area.limit, @@ -538,7 +538,7 @@ Res RootScan(ScanState ss, Root root) goto failScan; break; - case RootAREA_TAGGED: + case RootAREA_TAGGED: res = TraceScanArea(ss, root->the.areaTagged.base, root->the.areaTagged.limit, @@ -550,20 +550,20 @@ Res RootScan(ScanState ss, Root root) goto failScan; break; - case RootFUN: + case RootFUN: res = (*root->the.fun.scan)(&ss->ss_s, root->the.fun.p, root->the.fun.s); if (res != ResOK) goto failScan; break; - case RootREG: + case RootREG: res = (*root->the.reg.scan)(&ss->ss_s, root->the.reg.thread, root->the.reg.p, root->the.reg.s); if (res != ResOK) goto failScan; break; - case RootREG_MASKED: + case RootREG_MASKED: res = ThreadScan(ss, root->the.regMasked.thread, root->the.regMasked.stackBot, root->the.regMasked.scan_area, @@ -573,14 +573,14 @@ Res RootScan(ScanState ss, Root root) goto failScan; break; - case RootFMT: + 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); if (res != ResOK) goto failScan; break; - default: + default: NOTREACHED; res = ResUNIMPL; goto failScan; From 2ad27f73b190d5fbde1f8fbd13fdb8679ecec754 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 15 Feb 2016 17:46:45 +0000 Subject: [PATCH 133/337] Lifting stack and register area scanner into mps interface to allow generalisation of stack format. Copied from Perforce Change: 189195 ServerID: perforce.ravenbrook.com --- mps/code/airtest.c | 3 ++- mps/code/amcssth.c | 6 ++++-- mps/code/awlut.c | 3 ++- mps/code/awluthe.c | 3 ++- mps/code/awlutth.c | 3 ++- mps/code/gcbench.c | 3 ++- mps/code/mpm.h | 1 + mps/code/mps.h | 1 + mps/code/mpsi.c | 14 +++++++++----- mps/code/mpsicv.c | 3 ++- mps/code/root.c | 6 ++++-- mps/code/tagtest.c | 6 ++++-- mps/code/zcoll.c | 6 ++++-- mps/code/zmess.c | 1 + 14 files changed, 40 insertions(+), 19 deletions(-) diff --git a/mps/code/airtest.c b/mps/code/airtest.c index 302f91bb716..eea742def46 100644 --- a/mps/code/airtest.c +++ b/mps/code/airtest.c @@ -128,7 +128,8 @@ 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, sizeof(mps_word_t) - 1, 0, marker); + 0, thread, mps_scan_area_tagged, + 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 bd06dc9b2c6..80320261aec 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, sizeof(mps_word_t) - 1, 0, marker), + 0, thread, mps_scan_area_tagged, + sizeof(mps_word_t) - 1, 0, marker), "root_create"); die(mps_ap_create(&ap, cl->pool, mps_rank_exact()), "BufferCreate(fooey)"); @@ -318,7 +319,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, sizeof(mps_word_t) - 1, 0, marker), + 0, thread, mps_scan_area_tagged, + sizeof(mps_word_t) - 1, 0, marker), "root_create"); die(mps_pool_create(&amc_pool, arena, mps_class_amc(), format, chain), diff --git a/mps/code/awlut.c b/mps/code/awlut.c index 93575df854a..1b2a430af47 100644 --- a/mps/code/awlut.c +++ b/mps/code/awlut.c @@ -268,7 +268,8 @@ static void *setup(void *v, size_t s) thr = guff->thr; die(mps_root_create_stack(&stack, arena, mps_rank_ambig(), - 0, thr, sizeof(mps_word_t) - 1, 0, v), + 0, thr, mps_scan_area_tagged, + 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 e8b22f6ebb9..b5b4f4db07f 100644 --- a/mps/code/awluthe.c +++ b/mps/code/awluthe.c @@ -272,7 +272,8 @@ static void *setup(void *v, size_t s) thr = guff->thr; die(mps_root_create_stack(&stack, arena, mps_rank_ambig(), - 0, thr, sizeof(mps_word_t) - 1, 0, v), + 0, thr, mps_scan_area_tagged, + 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 b9b60aff962..fad46a29844 100644 --- a/mps/code/awlutth.c +++ b/mps/code/awlutth.c @@ -255,7 +255,8 @@ static void *setup(void *v, size_t s) thr = guff->thr; die(mps_root_create_stack(&stack, arena, mps_rank_ambig(), - 0, thr, sizeof(mps_word_t) - 1, 0, v), + 0, thr, mps_scan_area_tagged, + 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 2a61a8662c5..0451cd9fbc0 100644 --- a/mps/code/gcbench.c +++ b/mps/code/gcbench.c @@ -178,7 +178,8 @@ static void *start(void *p) { 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, - sizeof(mps_word_t) - 1, 0, &marker)); + mps_scan_area_tagged, + 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/mpm.h b/mps/code/mpm.h index 3fcd56d2c77..fb5f772ae99 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -963,6 +963,7 @@ extern Res RootCreateReg(Root *rootReturn, Arena arena, void *p, size_t s); extern Res RootCreateRegMasked(Root *rootReturn, Arena arena, Rank rank, Thread thread, + mps_area_scan_t scan_area, Word mask, Word pattern, Word *stackBot); extern Res RootCreateFmt(Root *rootReturn, Arena arena, diff --git a/mps/code/mps.h b/mps/code/mps.h index 92a02399f10..c1fd1e5f0eb 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -693,6 +693,7 @@ extern mps_res_t mps_root_create_reg(mps_root_t *, mps_arena_t, mps_reg_scan_t, void *, size_t); extern mps_res_t mps_root_create_stack(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_thr_t, + mps_area_scan_t, mps_word_t, mps_word_t, void *); extern void mps_root_destroy(mps_root_t); diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index c55b4763890..42db2008cfc 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1450,10 +1450,13 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena, } +/* FIXME: re-document */ 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) + mps_thr_t thread, + mps_area_scan_t scan_area, + mps_word_t mask, mps_word_t pattern, + void *stack) { Rank rank = (Rank)mps_rank; Root root; @@ -1462,15 +1465,16 @@ mps_res_t mps_root_create_stack(mps_root_t *mps_root_o, mps_arena_t arena, ArenaEnter(arena); AVER(mps_root_o != NULL); - AVER(reg_scan_p != NULL); /* stackBot */ - AVER(AddrIsAligned(reg_scan_p, sizeof(Word))); + AVER(stack != NULL); /* stackBot */ + AVER(AddrIsAligned(stack, 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, (Word *)reg_scan_p); + scan_area, mask, pattern, + (Word *)stack); ArenaLeave(arena); diff --git a/mps/code/mpsicv.c b/mps/code/mpsicv.c index aa563683f4f..10b98060ce5 100644 --- a/mps/code/mpsicv.c +++ b/mps/code/mpsicv.c @@ -604,7 +604,8 @@ int main(int argc, char *argv[]) } else { die(mps_root_create_stack(®_root, arena, mps_rank_ambig(), (mps_rm_t)0, - thread, sizeof(mps_word_t) - 1, 0, marker), + thread, mps_scan_area_tagged, + sizeof(mps_word_t) - 1, 0, marker), "root_create_stack"); } diff --git a/mps/code/root.c b/mps/code/root.c index 4433df89033..f1fb45f82d5 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -352,7 +352,9 @@ Res RootCreateReg(Root *rootReturn, Arena arena, Res RootCreateRegMasked(Root *rootReturn, Arena arena, Rank rank, Thread thread, - Word mask, Word pattern, Word *stackBot) + mps_area_scan_t scan_area, + Word mask, Word pattern, + Word *stackBot) { union RootUnion theUnion; @@ -364,7 +366,7 @@ Res RootCreateRegMasked(Root *rootReturn, Arena arena, AVER((~mask & pattern) == 0); theUnion.regMasked.thread = thread; - theUnion.regMasked.scan_area = mps_scan_area_tagged; + theUnion.regMasked.scan_area = scan_area; theUnion.regMasked.tag.mask = mask; theUnion.regMasked.tag.pattern = pattern; theUnion.regMasked.stackBot = stackBot; diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c index 76d8b5ec792..7f27d45fc09 100644 --- a/mps/code/tagtest.c +++ b/mps/code/tagtest.c @@ -209,13 +209,15 @@ static void test(int mode, void *marker) case MODE_CONS: /* Scan words tagged "cons" -- everything will live. */ die(mps_root_create_stack(&root, arena, mps_rank_ambig(), 0, thread, - TAG_MASK, tag_cons, marker), "root"); + mps_scan_area_tagged, TAG_MASK, tag_cons, + marker), "root"); expected = 0; break; case MODE_INVALID: /* Scan words tagged "invalid" -- everything will die. */ die(mps_root_create_stack(&root, arena, mps_rank_ambig(), 0, thread, - TAG_MASK, tag_invalid, marker), "root"); + mps_scan_area_tagged, TAG_MASK, tag_invalid, + marker), "root"); expected = OBJCOUNT; break; } diff --git a/mps/code/zcoll.c b/mps/code/zcoll.c index 64fd5406018..16b403be2f4 100644 --- a/mps/code/zcoll.c +++ b/mps/code/zcoll.c @@ -576,7 +576,8 @@ 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, - sizeof(mps_word_t) - 1, 0, stack_start), + mps_scan_area_tagged, + sizeof(mps_word_t) - 1, 0, stack_start), "root_stackreg"); Insist(root_stackreg != NULL); } else { @@ -764,7 +765,8 @@ 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, - sizeof(mps_word_t) - 1, 0, stack_start), + mps_scan_area_tagged, + sizeof(mps_word_t) - 1, 0, stack_start), "root_stackreg"); diff --git a/mps/code/zmess.c b/mps/code/zmess.c index ff7cb526509..60a9c4a1e99 100644 --- a/mps/code/zmess.c +++ b/mps/code/zmess.c @@ -332,6 +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, + mps_scan_area_tagged, sizeof(mps_word_t) - 1, 0, &stack_starts_here), "root_stackreg"); From 53ce574bfe0d84fba9e52738b755285412ecb1cc Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 15 Feb 2016 17:57:06 +0000 Subject: [PATCH 134/337] Renaming rootreg_masked to rootthread_tagged with corresponding changes to other identifiers. Copied from Perforce Change: 189196 ServerID: perforce.ravenbrook.com --- mps/code/mpm.h | 10 ++++---- mps/code/mpmtypes.h | 2 +- mps/code/mpsi.c | 6 ++--- mps/code/root.c | 58 ++++++++++++++++++++++----------------------- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index fb5f772ae99..cc947117da0 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -961,11 +961,11 @@ 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, - mps_area_scan_t scan_area, - Word mask, Word pattern, - Word *stackBot); +extern Res RootCreateThreadTagged(Root *rootReturn, Arena arena, + Rank rank, Thread thread, + mps_area_scan_t scan_area, + Word mask, Word pattern, + Word *stackBot); extern Res RootCreateFmt(Root *rootReturn, Arena arena, Rank rank, RootMode mode, mps_fmt_scan_t scan, diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 1dacecbac0f..dc48e6dc275 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -362,7 +362,7 @@ enum { RootAREA, RootAREA_TAGGED, RootREG, - RootREG_MASKED, + RootTHREAD_TAGGED, RootFMT, RootLIMIT }; diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 42db2008cfc..6f7f89109d0 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1472,9 +1472,9 @@ mps_res_t mps_root_create_stack(mps_root_t *mps_root_o, mps_arena_t arena, AVER((~mask & pattern) == 0); /* See .root-mode. */ - res = RootCreateRegMasked(&root, arena, rank, thread, - scan_area, mask, pattern, - (Word *)stack); + res = RootCreateThreadTagged(&root, arena, rank, thread, + scan_area, mask, pattern, + (Word *)stack); ArenaLeave(arena); diff --git a/mps/code/root.c b/mps/code/root.c index f1fb45f82d5..07792bc92b5 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -61,7 +61,7 @@ typedef struct RootStruct { mps_area_scan_t scan_area;/* area scanner for stack and registers */ mps_scan_tag_s tag; /* tag for scanning */ Word *stackBot; /* bottom of stack */ - } regMasked; + } threadTagged; struct { mps_fmt_scan_t scan; /* format-like scanner */ Addr base, limit; /* passed to scan */ @@ -78,7 +78,7 @@ Bool RootVarCheck(RootVar rootVar) { CHECKL(rootVar == RootAREA || rootVar == RootAREA_TAGGED || rootVar == RootFUN || rootVar == RootFMT || rootVar == RootREG - || rootVar == RootREG_MASKED); + || rootVar == RootTHREAD_TAGGED); UNUSED(rootVar); return TRUE; } @@ -139,10 +139,10 @@ Bool RootCheck(Root root) /* Can't check anything about p or s. */ break; - case RootREG_MASKED: - CHECKD_NOSIG(Thread, root->the.regMasked.thread); /* */ - CHECKL(FUNCHECK(root->the.regMasked.scan_area)); - CHECKL((~root->the.regMasked.tag.mask & root->the.regMasked.tag.pattern) == 0); + case RootTHREAD_TAGGED: + CHECKD_NOSIG(Thread, root->the.threadTagged.thread); /* */ + CHECKL(FUNCHECK(root->the.threadTagged.scan_area)); + CHECKL((~root->the.threadTagged.tag.mask & root->the.threadTagged.tag.pattern) == 0); /* Can't check anything about stackBot. */ break; @@ -350,11 +350,11 @@ 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, - mps_area_scan_t scan_area, - Word mask, Word pattern, - Word *stackBot) +Res RootCreateThreadTagged(Root *rootReturn, Arena arena, + Rank rank, Thread thread, + mps_area_scan_t scan_area, + Word mask, Word pattern, + Word *stackBot) { union RootUnion theUnion; @@ -365,13 +365,13 @@ Res RootCreateRegMasked(Root *rootReturn, Arena arena, AVER(ThreadArena(thread) == arena); AVER((~mask & pattern) == 0); - theUnion.regMasked.thread = thread; - theUnion.regMasked.scan_area = scan_area; - theUnion.regMasked.tag.mask = mask; - theUnion.regMasked.tag.pattern = pattern; - theUnion.regMasked.stackBot = stackBot; + theUnion.threadTagged.thread = thread; + theUnion.threadTagged.scan_area = scan_area; + theUnion.threadTagged.tag.mask = mask; + theUnion.threadTagged.tag.pattern = pattern; + theUnion.threadTagged.stackBot = stackBot; - return rootCreate(rootReturn, arena, rank, (RootMode)0, RootREG_MASKED, + return rootCreate(rootReturn, arena, rank, (RootMode)0, RootTHREAD_TAGGED, &theUnion); } @@ -565,12 +565,12 @@ 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.scan_area, - &root->the.regMasked.tag, - sizeof(root->the.regMasked.tag)); + case RootTHREAD_TAGGED: + res = ThreadScan(ss, root->the.threadTagged.thread, + root->the.threadTagged.stackBot, + root->the.threadTagged.scan_area, + &root->the.threadTagged.tag, + sizeof(root->the.threadTagged.tag)); if (res != ResOK) goto failScan; break; @@ -744,13 +744,13 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) return res; break; - case RootREG_MASKED: + case RootTHREAD_TAGGED: res = WriteF(stream, depth + 2, - "thread $P\n", (WriteFP)root->the.regMasked.thread, - "scan_area $P\n", (WriteFP)root->the.regMasked.scan_area, - "mask $B\n", (WriteFB)root->the.regMasked.tag.mask, - "pattern $B\n", (WriteFB)root->the.regMasked.tag.pattern, - "stackBot $P\n", (WriteFP)root->the.regMasked.stackBot, + "thread $P\n", (WriteFP)root->the.threadTagged.thread, + "scan_area $P\n", (WriteFP)root->the.threadTagged.scan_area, + "mask $B\n", (WriteFB)root->the.threadTagged.tag.mask, + "pattern $B\n", (WriteFB)root->the.threadTagged.tag.pattern, + "stackBot $P\n", (WriteFP)root->the.threadTagged.stackBot, NULL); if (res != ResOK) return res; From a759889048bc5a06399ed1425f3d1e767fdc6275 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 15 Feb 2016 18:19:30 +0000 Subject: [PATCH 135/337] Reimplementing mps_root_create_reg in terms of rootcreatethreadtagged and abolishing rootreg. yay! Copied from Perforce Change: 189197 ServerID: perforce.ravenbrook.com --- mps/code/mpm.h | 4 ---- mps/code/mpmtypes.h | 1 - mps/code/mpsi.c | 39 ++++++++++++++++++---------------- mps/code/root.c | 51 +-------------------------------------------- 4 files changed, 22 insertions(+), 73 deletions(-) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index cc947117da0..1f652a566eb 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -957,10 +957,6 @@ extern Res RootCreateAreaTagged(Root *rootReturn, Arena arena, Word *base, Word *limit, mps_area_scan_t scan_area, Word mask, Word pattern); -extern Res RootCreateReg(Root *rootReturn, Arena arena, - Rank rank, Thread thread, - mps_reg_scan_t scan, - void *p, size_t s); extern Res RootCreateThreadTagged(Root *rootReturn, Arena arena, Rank rank, Thread thread, mps_area_scan_t scan_area, diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index dc48e6dc275..5f31501938e 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -361,7 +361,6 @@ enum { RootFUN, RootAREA, RootAREA_TAGGED, - RootREG, RootTHREAD_TAGGED, RootFMT, RootLIMIT diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 6f7f89109d0..4b1fb20b574 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -40,13 +40,9 @@ * present. This is because the MPM doesn't ever try to protect them. * In future, it will. * - * .reg-scan: (rule.universal.complete) At present, we only support - * register scanning using our own ambiguous register and stack scanning - * method, mps_stack_scan_ambig. This may never change, but the way the - * interface is designed allows for the possibility of change. - * * .naming: (rule.impl.guide) The exported identifiers do not follow the - * normal MPS naming conventions. See . */ + * normal MPS naming conventions. See . + */ #include "mpm.h" #include "mps.h" @@ -1421,7 +1417,7 @@ mps_res_t mps_root_create_fmt(mps_root_t *mps_root_o, mps_arena_t arena, mps_res_t mps_root_create_reg(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_reg_scan_t mps_reg_scan, - void *reg_scan_p, size_t mps_size) + void *stack, size_t mps_size) { Rank rank = (Rank)mps_rank; Root root; @@ -1432,14 +1428,18 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena, AVER(mps_root_o != NULL); 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(stack != NULL); /* stackBot */ + AVER(AddrIsAligned(stack, sizeof(Word))); AVER(rank == mps_rank_ambig()); AVER(mps_rm == (mps_rm_t)0); + UNUSED(mps_size); + /* See .root-mode. */ - res = RootCreateReg(&root, arena, rank, thread, - mps_reg_scan, reg_scan_p, mps_size); + res = RootCreateThreadTagged(&root, arena, rank, thread, + mps_scan_area_tagged, + sizeof(mps_word_t) - 1, 0, + (Word *)stack); ArenaLeave(arena); @@ -1487,19 +1487,22 @@ mps_res_t mps_root_create_stack(mps_root_t *mps_root_o, mps_arena_t arena, /* mps_stack_scan_ambig -- scan the thread state ambiguously * - * See .reg-scan. */ + * This is a helper function for the deprecated mps_root_create_reg + * and should no longer be reached since that has been reimplemented + * in terms of the more general RootCreateThreadTagged. + */ mps_res_t mps_stack_scan_ambig(mps_ss_t mps_ss, mps_thr_t thread, void *p, size_t s) { - ScanState ss = PARENT(ScanStateStruct, ss_s, mps_ss); - mps_scan_tag_s tag; - + UNUSED(mps_ss); + UNUSED(thread); + UNUSED(p); UNUSED(s); - tag.mask = sizeof(mps_word_t) - 1; - tag.pattern = 0; - return ThreadScan(ss, thread, (Word *)p, mps_scan_area_tagged, &tag, sizeof(tag)); + NOTREACHED; + + return ResUNIMPL; } diff --git a/mps/code/root.c b/mps/code/root.c index 07792bc92b5..42c7510b5d1 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -50,12 +50,6 @@ typedef struct RootStruct { mps_area_scan_t scan_area;/* area scanning function */ mps_scan_tag_s tag; /* tag for scanning */ } areaTagged; - struct { - mps_reg_scan_t scan; /* function for scanning registers */ - Thread thread; /* passed to scan */ - void *p; /* passed to scan */ - size_t s; /* passed to scan */ - } reg; struct { Thread thread; /* passed to scan */ mps_area_scan_t scan_area;/* area scanner for stack and registers */ @@ -77,7 +71,7 @@ typedef struct RootStruct { Bool RootVarCheck(RootVar rootVar) { CHECKL(rootVar == RootAREA || rootVar == RootAREA_TAGGED - || rootVar == RootFUN || rootVar == RootFMT || rootVar == RootREG + || rootVar == RootFUN || rootVar == RootFMT || rootVar == RootTHREAD_TAGGED); UNUSED(rootVar); return TRUE; @@ -133,12 +127,6 @@ Bool RootCheck(Root root) CHECKL(root->the.fun.scan != NULL); break; - 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 RootTHREAD_TAGGED: CHECKD_NOSIG(Thread, root->the.threadTagged.thread); /* */ CHECKL(FUNCHECK(root->the.threadTagged.scan_area)); @@ -329,27 +317,6 @@ Res RootCreateAreaTagged(Root *rootReturn, Arena arena, (Addr)base, (Addr)limit, &theUnion); } -Res RootCreateReg(Root *rootReturn, Arena arena, - Rank rank, Thread thread, - mps_reg_scan_t scan, void *p, size_t s) -{ - union RootUnion theUnion; - - AVER(rootReturn != NULL); - AVERT(Arena, arena); - AVERT(Rank, rank); - AVERT(Thread, thread); - AVER(ThreadArena(thread) == arena); - AVER(scan != NULL); - - theUnion.reg.scan = scan; - theUnion.reg.thread = thread; - theUnion.reg.p = p; - theUnion.reg.s = s; - - return rootCreate(rootReturn, arena, rank, (RootMode)0, RootREG, &theUnion); -} - Res RootCreateThreadTagged(Root *rootReturn, Arena arena, Rank rank, Thread thread, mps_area_scan_t scan_area, @@ -558,13 +525,6 @@ Res RootScan(ScanState ss, Root root) goto failScan; break; - case RootREG: - res = (*root->the.reg.scan)(&ss->ss_s, root->the.reg.thread, - root->the.reg.p, root->the.reg.s); - if (res != ResOK) - goto failScan; - break; - case RootTHREAD_TAGGED: res = ThreadScan(ss, root->the.threadTagged.thread, root->the.threadTagged.stackBot, @@ -735,15 +695,6 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) return res; break; - case RootREG: - res = WriteF(stream, depth + 2, - "thread $P\n", (WriteFP)root->the.reg.thread, - "environment p $P", (WriteFP)root->the.reg.p, - NULL); - if (res != ResOK) - return res; - break; - case RootTHREAD_TAGGED: res = WriteF(stream, depth + 2, "thread $P\n", (WriteFP)root->the.threadTagged.thread, From 8140fab4dd5d694f774d0824b5724c1501d597ee Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 15 Feb 2016 19:12:59 +0000 Subject: [PATCH 136/337] Creating general mps_root_create_thread and renaming mps_root_create_stack as a specialised version of it, mps_root_create_thread_tagged. Copied from Perforce Change: 189198 ServerID: perforce.ravenbrook.com --- mps/code/airtest.c | 2 +- mps/code/amcssth.c | 4 +- mps/code/awlut.c | 2 +- mps/code/awluthe.c | 2 +- mps/code/awlutth.c | 2 +- mps/code/gcbench.c | 2 +- mps/code/mpm.h | 5 +++ mps/code/mpmtypes.h | 1 + mps/code/mps.h | 15 ++++--- mps/code/mpsi.c | 57 ++++++++++++++++++++++---- mps/code/mpsicv.c | 2 +- mps/code/root.c | 97 +++++++++++++++++++++++++++++++++++---------- mps/code/tagtest.c | 12 +++--- mps/code/zcoll.c | 4 +- mps/code/zmess.c | 2 +- 15 files changed, 160 insertions(+), 49 deletions(-) diff --git a/mps/code/airtest.c b/mps/code/airtest.c index eea742def46..9399f643269 100644 --- a/mps/code/airtest.c +++ b/mps/code/airtest.c @@ -127,7 +127,7 @@ static void test_main(void *marker, int interior, int stack) error("Couldn't register thread"); if (stack) { - res = mps_root_create_stack(®_root, scheme_arena, mps_rank_ambig(), + res = mps_root_create_thread_tagged(®_root, scheme_arena, mps_rank_ambig(), 0, thread, mps_scan_area_tagged, sizeof(mps_word_t) - 1, 0, marker); if (res != MPS_RES_OK) diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c index 80320261aec..cf9c6cbf0a4 100644 --- a/mps/code/amcssth.c +++ b/mps/code/amcssth.c @@ -139,7 +139,7 @@ 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_stack(®_root, arena, mps_rank_ambig(), + die(mps_root_create_thread_tagged(®_root, arena, mps_rank_ambig(), 0, thread, mps_scan_area_tagged, sizeof(mps_word_t) - 1, 0, marker), "root_create"); @@ -318,7 +318,7 @@ 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_stack(®_root, arena, mps_rank_ambig(), + die(mps_root_create_thread_tagged(®_root, arena, mps_rank_ambig(), 0, thread, mps_scan_area_tagged, sizeof(mps_word_t) - 1, 0, marker), "root_create"); diff --git a/mps/code/awlut.c b/mps/code/awlut.c index 1b2a430af47..61b3636d80a 100644 --- a/mps/code/awlut.c +++ b/mps/code/awlut.c @@ -267,7 +267,7 @@ static void *setup(void *v, size_t s) arena = guff->arena; thr = guff->thr; - die(mps_root_create_stack(&stack, arena, mps_rank_ambig(), + die(mps_root_create_thread_tagged(&stack, arena, mps_rank_ambig(), 0, thr, mps_scan_area_tagged, sizeof(mps_word_t) - 1, 0, v), "Root Create\n"); diff --git a/mps/code/awluthe.c b/mps/code/awluthe.c index b5b4f4db07f..331128d54c0 100644 --- a/mps/code/awluthe.c +++ b/mps/code/awluthe.c @@ -271,7 +271,7 @@ static void *setup(void *v, size_t s) arena = guff->arena; thr = guff->thr; - die(mps_root_create_stack(&stack, arena, mps_rank_ambig(), + die(mps_root_create_thread_tagged(&stack, arena, mps_rank_ambig(), 0, thr, mps_scan_area_tagged, sizeof(mps_word_t) - 1, 0, v), "Root Create\n"); diff --git a/mps/code/awlutth.c b/mps/code/awlutth.c index fad46a29844..8944df9b8bc 100644 --- a/mps/code/awlutth.c +++ b/mps/code/awlutth.c @@ -254,7 +254,7 @@ static void *setup(void *v, size_t s) arena = guff->arena; thr = guff->thr; - die(mps_root_create_stack(&stack, arena, mps_rank_ambig(), + die(mps_root_create_thread_tagged(&stack, arena, mps_rank_ambig(), 0, thr, mps_scan_area_tagged, sizeof(mps_word_t) - 1, 0, v), "Root Create\n"); diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c index 0451cd9fbc0..920c55d07da 100644 --- a/mps/code/gcbench.c +++ b/mps/code/gcbench.c @@ -176,7 +176,7 @@ 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(), + RESMUST(mps_root_create_thread_tagged(&thread->reg_root, arena, mps_rank_ambig(), (mps_rm_t)0, thread->mps_thread, mps_scan_area_tagged, sizeof(mps_word_t) - 1, 0, &marker)); diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 1f652a566eb..8c9ab7a40a2 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -957,6 +957,11 @@ extern Res RootCreateAreaTagged(Root *rootReturn, Arena arena, Word *base, Word *limit, mps_area_scan_t scan_area, Word mask, Word pattern); +extern Res RootCreateThread(Root *rootReturn, Arena arena, + Rank rank, Thread thread, + mps_area_scan_t scan_area, + void *closure, size_t closure_size, + Word *stackBot); extern Res RootCreateThreadTagged(Root *rootReturn, Arena arena, Rank rank, Thread thread, mps_area_scan_t scan_area, diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 5f31501938e..2571106984a 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -361,6 +361,7 @@ enum { RootFUN, RootAREA, RootAREA_TAGGED, + RootTHREAD, RootTHREAD_TAGGED, RootFMT, RootLIMIT diff --git a/mps/code/mps.h b/mps/code/mps.h index c1fd1e5f0eb..bc04426524b 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -691,11 +691,16 @@ 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_stack(mps_root_t *, mps_arena_t, - mps_rank_t, mps_rm_t, mps_thr_t, - mps_area_scan_t, - mps_word_t, mps_word_t, - void *); +extern mps_res_t mps_root_create_thread(mps_root_t *, mps_arena_t, + mps_rank_t, mps_rm_t, mps_thr_t, + mps_area_scan_t, + void *, size_t, + void *); +extern mps_res_t mps_root_create_thread_tagged(mps_root_t *, mps_arena_t, + mps_rank_t, mps_rm_t, mps_thr_t, + mps_area_scan_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 4b1fb20b574..db941471cd7 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1450,13 +1450,16 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena, } -/* FIXME: re-document */ -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_area_scan_t scan_area, - mps_word_t mask, mps_word_t pattern, - void *stack) +/* FIXME: document */ +mps_res_t mps_root_create_thread(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_area_scan_t scan_area, + void *closure, + size_t closure_size, + void *stack) { Rank rank = (Rank)mps_rank; Root root; @@ -1469,6 +1472,46 @@ mps_res_t mps_root_create_stack(mps_root_t *mps_root_o, mps_arena_t arena, AVER(AddrIsAligned(stack, sizeof(Word))); AVER(rank == mps_rank_ambig()); AVER(mps_rm == (mps_rm_t)0); + AVER(FUNCHECK(scan_area)); + /* Can't check anything about closure. */ + + /* See .root-mode. */ + res = RootCreateThread(&root, arena, rank, thread, + scan_area, closure, closure_size, + (Word *)stack); + + ArenaLeave(arena); + + if (res != ResOK) + return (mps_res_t)res; + *mps_root_o = (mps_root_t)root; + return MPS_RES_OK; +} + + +/* FIXME: re-document */ +mps_res_t mps_root_create_thread_tagged(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_area_scan_t scan_area, + mps_word_t mask, + mps_word_t pattern, + void *stack) +{ + Rank rank = (Rank)mps_rank; + Root root; + Res res; + + ArenaEnter(arena); + + AVER(mps_root_o != NULL); + AVER(stack != NULL); /* stackBot */ + AVER(AddrIsAligned(stack, sizeof(Word))); + AVER(rank == mps_rank_ambig()); + AVER(mps_rm == (mps_rm_t)0); + AVER(FUNCHECK(scan_area)); AVER((~mask & pattern) == 0); /* See .root-mode. */ diff --git a/mps/code/mpsicv.c b/mps/code/mpsicv.c index 10b98060ce5..55e499f55da 100644 --- a/mps/code/mpsicv.c +++ b/mps/code/mpsicv.c @@ -602,7 +602,7 @@ int main(int argc, char *argv[]) marker, (size_t)0), "root_create_reg"); } else { - die(mps_root_create_stack(®_root, arena, + die(mps_root_create_thread_tagged(®_root, arena, mps_rank_ambig(), (mps_rm_t)0, thread, mps_scan_area_tagged, sizeof(mps_word_t) - 1, 0, marker), diff --git a/mps/code/root.c b/mps/code/root.c index 42c7510b5d1..bfcfb09d74c 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -53,9 +53,15 @@ typedef struct RootStruct { struct { Thread thread; /* passed to scan */ mps_area_scan_t scan_area;/* area scanner for stack and registers */ - mps_scan_tag_s tag; /* tag for scanning */ + union { + struct { + void *p; + size_t s; + } closure; + mps_scan_tag_s tag; /* tag for scanning */ + } the; Word *stackBot; /* bottom of stack */ - } threadTagged; + } thread; struct { mps_fmt_scan_t scan; /* format-like scanner */ Addr base, limit; /* passed to scan */ @@ -72,6 +78,7 @@ Bool RootVarCheck(RootVar rootVar) { CHECKL(rootVar == RootAREA || rootVar == RootAREA_TAGGED || rootVar == RootFUN || rootVar == RootFMT + || rootVar == RootTHREAD || rootVar == RootTHREAD_TAGGED); UNUSED(rootVar); return TRUE; @@ -128,9 +135,9 @@ Bool RootCheck(Root root) break; case RootTHREAD_TAGGED: - CHECKD_NOSIG(Thread, root->the.threadTagged.thread); /* */ - CHECKL(FUNCHECK(root->the.threadTagged.scan_area)); - CHECKL((~root->the.threadTagged.tag.mask & root->the.threadTagged.tag.pattern) == 0); + CHECKD_NOSIG(Thread, root->the.thread.thread); /* */ + CHECKL(FUNCHECK(root->the.thread.scan_area)); + CHECKL((~root->the.thread.the.tag.mask & root->the.thread.the.tag.pattern) == 0); /* Can't check anything about stackBot. */ break; @@ -317,6 +324,32 @@ Res RootCreateAreaTagged(Root *rootReturn, Arena arena, (Addr)base, (Addr)limit, &theUnion); } +Res RootCreateThread(Root *rootReturn, Arena arena, + Rank rank, Thread thread, + mps_area_scan_t scan_area, + void *closure, size_t closure_size, + Word *stackBot) +{ + union RootUnion theUnion; + + AVER(rootReturn != NULL); + AVERT(Arena, arena); + AVERT(Rank, rank); + AVERT(Thread, thread); + AVER(ThreadArena(thread) == arena); + AVER(FUNCHECK(scan_area)); + /* Can't check anything about closure. */ + + theUnion.thread.thread = thread; + theUnion.thread.scan_area = scan_area; + theUnion.thread.the.closure.p = closure; + theUnion.thread.the.closure.s = closure_size; + theUnion.thread.stackBot = stackBot; + + return rootCreate(rootReturn, arena, rank, (RootMode)0, RootTHREAD, + &theUnion); +} + Res RootCreateThreadTagged(Root *rootReturn, Arena arena, Rank rank, Thread thread, mps_area_scan_t scan_area, @@ -330,13 +363,14 @@ Res RootCreateThreadTagged(Root *rootReturn, Arena arena, AVERT(Rank, rank); AVERT(Thread, thread); AVER(ThreadArena(thread) == arena); + AVER(FUNCHECK(scan_area)); AVER((~mask & pattern) == 0); - theUnion.threadTagged.thread = thread; - theUnion.threadTagged.scan_area = scan_area; - theUnion.threadTagged.tag.mask = mask; - theUnion.threadTagged.tag.pattern = pattern; - theUnion.threadTagged.stackBot = stackBot; + theUnion.thread.thread = thread; + theUnion.thread.scan_area = scan_area; + theUnion.thread.the.tag.mask = mask; + theUnion.thread.the.tag.pattern = pattern; + theUnion.thread.stackBot = stackBot; return rootCreate(rootReturn, arena, rank, (RootMode)0, RootTHREAD_TAGGED, &theUnion); @@ -525,12 +559,22 @@ Res RootScan(ScanState ss, Root root) goto failScan; break; + case RootTHREAD: + res = ThreadScan(ss, root->the.thread.thread, + root->the.thread.stackBot, + root->the.thread.scan_area, + root->the.thread.the.closure.p, + root->the.thread.the.closure.s); + if (res != ResOK) + goto failScan; + break; + case RootTHREAD_TAGGED: - res = ThreadScan(ss, root->the.threadTagged.thread, - root->the.threadTagged.stackBot, - root->the.threadTagged.scan_area, - &root->the.threadTagged.tag, - sizeof(root->the.threadTagged.tag)); + res = ThreadScan(ss, root->the.thread.thread, + root->the.thread.stackBot, + root->the.thread.scan_area, + &root->the.thread.the.tag, + sizeof(root->the.thread.the.tag)); if (res != ResOK) goto failScan; break; @@ -695,13 +739,26 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) return res; break; + case RootTHREAD: + res = WriteF(stream, depth + 2, + "thread $P\n", (WriteFP)root->the.thread.thread, + "scan_area $P\n", (WriteFP)root->the.thread.scan_area, + "closure $P size $U\n", + (WriteFP)root->the.thread.the.closure.p, + (WriteFU)root->the.thread.the.closure.s, + "stackBot $P\n", (WriteFP)root->the.thread.stackBot, + NULL); + if (res != ResOK) + return res; + break; + case RootTHREAD_TAGGED: res = WriteF(stream, depth + 2, - "thread $P\n", (WriteFP)root->the.threadTagged.thread, - "scan_area $P\n", (WriteFP)root->the.threadTagged.scan_area, - "mask $B\n", (WriteFB)root->the.threadTagged.tag.mask, - "pattern $B\n", (WriteFB)root->the.threadTagged.tag.pattern, - "stackBot $P\n", (WriteFP)root->the.threadTagged.stackBot, + "thread $P\n", (WriteFP)root->the.thread.thread, + "scan_area $P\n", (WriteFP)root->the.thread.scan_area, + "mask $B\n", (WriteFB)root->the.thread.the.tag.mask, + "pattern $B\n", (WriteFB)root->the.thread.the.tag.pattern, + "stackBot $P\n", (WriteFP)root->the.thread.stackBot, NULL); if (res != ResOK) return res; diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c index 7f27d45fc09..fa751b82537 100644 --- a/mps/code/tagtest.c +++ b/mps/code/tagtest.c @@ -208,16 +208,16 @@ static void test(int mode, void *marker) break; case MODE_CONS: /* Scan words tagged "cons" -- everything will live. */ - die(mps_root_create_stack(&root, arena, mps_rank_ambig(), 0, thread, - mps_scan_area_tagged, TAG_MASK, tag_cons, - marker), "root"); + die(mps_root_create_thread_tagged(&root, arena, mps_rank_ambig(), 0, thread, + mps_scan_area_tagged, TAG_MASK, tag_cons, + marker), "root"); expected = 0; break; case MODE_INVALID: /* Scan words tagged "invalid" -- everything will die. */ - die(mps_root_create_stack(&root, arena, mps_rank_ambig(), 0, thread, - mps_scan_area_tagged, TAG_MASK, tag_invalid, - marker), "root"); + die(mps_root_create_thread_tagged(&root, arena, mps_rank_ambig(), 0, thread, + mps_scan_area_tagged, TAG_MASK, tag_invalid, + marker), "root"); expected = OBJCOUNT; break; } diff --git a/mps/code/zcoll.c b/mps/code/zcoll.c index 16b403be2f4..96dfdbf7f46 100644 --- a/mps/code/zcoll.c +++ b/mps/code/zcoll.c @@ -574,7 +574,7 @@ static void StackScan(mps_arena_t arena, int on) { if(on) { Insist(root_stackreg == NULL); - die(mps_root_create_stack(&root_stackreg, arena, + die(mps_root_create_thread_tagged(&root_stackreg, arena, mps_rank_ambig(), (mps_rm_t)0, stack_thr, mps_scan_area_tagged, sizeof(mps_word_t) - 1, 0, stack_start), @@ -763,7 +763,7 @@ 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_stack(&root_stackreg, arena, + die(mps_root_create_thread_tagged(&root_stackreg, arena, mps_rank_ambig(), (mps_rm_t)0, stack_thr, mps_scan_area_tagged, sizeof(mps_word_t) - 1, 0, stack_start), diff --git a/mps/code/zmess.c b/mps/code/zmess.c index 60a9c4a1e99..b1294dd4324 100644 --- a/mps/code/zmess.c +++ b/mps/code/zmess.c @@ -330,7 +330,7 @@ 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_stack(&root_stackreg, arena, + die(mps_root_create_thread_tagged(&root_stackreg, arena, mps_rank_ambig(), (mps_rm_t)0, thr, mps_scan_area_tagged, sizeof(mps_word_t) - 1, 0, &stack_starts_here), From 6da9d98d98f88d9d03311e4b086f118abb5d5a56 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 15 Feb 2016 19:42:44 +0000 Subject: [PATCH 137/337] Using an array rather than a stack for tagtest to get reliable results. Copied from Perforce Change: 189204 ServerID: perforce.ravenbrook.com --- mps/code/tagtest.c | 85 ++++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 55 deletions(-) diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c index fa751b82537..d1f78cc957f 100644 --- a/mps/code/tagtest.c +++ b/mps/code/tagtest.c @@ -4,8 +4,7 @@ * 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. + * tagged pointers via the object format and tagged area scanning. */ #include /* printf */ @@ -16,7 +15,7 @@ #include "mpscamc.h" #include "testlib.h" -#define OBJCOUNT (1000) /* Number of conses to allocate */ +#define OBJCOUNT 1000 /* Number of conses to allocate */ typedef struct cons_s { mps_word_t car, cdr; @@ -30,6 +29,7 @@ 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 */ +static mps_addr_t refs[OBJCOUNT]; /* Tagged references to objects */ #define TAG_COUNT ((mps_word_t)1 << tag_bits) /* Number of distinct tags */ #define TAG_MASK (TAG_COUNT - 1) /* Tag mask */ @@ -106,7 +106,7 @@ static mps_addr_t skip(mps_addr_t addr) } -static void collect(mps_arena_t arena, size_t expected, int strict) +static void collect(mps_arena_t arena, size_t expected) { size_t finalized = 0; mps_arena_collect(arena); @@ -122,47 +122,13 @@ static void collect(mps_arena_t arena, size_t expected, int strict) } printf("finalized=%lu expected=%lu\n", (unsigned long)finalized, (unsigned long)expected); - Insist(finalized == expected || !strict); -} - - -/* 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, - int strict) -{ - 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)UNTAGGED(p, cons); - die(mps_finalize(arena, &addr), "finalize"); - /* Avoid leaving a zero-tagged reference on the stack, as it will - prevent finalization when scanned with the default mode. */ - addr = NULL; - if (count > 1) { - alloc_recursively(arena, ap, expected, count - 1, strict); - } else { - collect(arena, expected, strict); - } - if (expected == 0) { - Insist(TAG(p) == tag_cons); - Insist(UNTAGGED(p, cons)->car == q); - Insist(UNTAGGED(p, cons)->cdr == r); - } + Insist(finalized == expected); } /* test -- Run the test case in the specified mode. */ #define MODES(R, X) \ - R(X, DEFAULT, "Use default scanner (tagged with 0).") \ R(X, CONS, "Scan words tagged \"cons\".") \ R(X, INVALID, "Scan words tagged \"invalid\".") @@ -180,7 +146,7 @@ static const char *mode_name[] = { }; -static void test(int mode, void *marker) +static void test(int mode) { mps_arena_t arena; mps_thr_t thread; @@ -189,6 +155,7 @@ static void test(int mode, void *marker) mps_pool_t pool; mps_ap_t ap; size_t expected = 0; + size_t i; printf("test(%s)\n", mode_name[mode]); @@ -200,24 +167,20 @@ static void test(int mode, void *marker) 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, - mps_stack_scan_ambig, marker, 0), "root"); - expected = (tag_cons != 0) * OBJCOUNT; - break; case MODE_CONS: /* Scan words tagged "cons" -- everything will live. */ - die(mps_root_create_thread_tagged(&root, arena, mps_rank_ambig(), 0, thread, - mps_scan_area_tagged, TAG_MASK, tag_cons, - marker), "root"); + die(mps_root_create_table_tagged(&root, arena, mps_rank_ambig(), 0, + refs, OBJCOUNT, + mps_scan_area_tagged, TAG_MASK, tag_cons), + "root"); expected = 0; break; case MODE_INVALID: /* Scan words tagged "invalid" -- everything will die. */ - die(mps_root_create_thread_tagged(&root, arena, mps_rank_ambig(), 0, thread, - mps_scan_area_tagged, TAG_MASK, tag_invalid, - marker), "root"); + die(mps_root_create_table_tagged(&root, arena, mps_rank_ambig(), 0, + refs, OBJCOUNT, + mps_scan_area_tagged, TAG_MASK, tag_invalid), + "root"); expected = OBJCOUNT; break; } @@ -238,7 +201,20 @@ static void test(int mode, void *marker) die(mps_ap_create_k(&ap, pool, mps_args_none), "ap"); - alloc_recursively(arena, ap, expected, OBJCOUNT, mode != MODE_DEFAULT); + for (i = 0; i < OBJCOUNT; ++i) { + mps_word_t p, r; + mps_word_t q = TAGGED(i << 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; + refs[i] = (mps_addr_t)p; + addr = (mps_addr_t)UNTAGGED(p, cons); + die(mps_finalize(arena, &addr), "finalize"); + } + + collect(arena, expected); mps_arena_park(arena); mps_ap_destroy(ap); @@ -251,7 +227,6 @@ static void test(int mode, void *marker) int main(int argc, char *argv[]) { - void *marker = ▮ mps_word_t tags[sizeof(mps_word_t)]; size_t i; int mode; @@ -282,7 +257,7 @@ int main(int argc, char *argv[]) (unsigned)tag_imm, (unsigned)tag_invalid); for (mode = 0; mode < MODE_LIMIT; ++mode) { - test(mode, marker); + test(mode); } printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); From 525e7dc95b14b2d9d7e5b063aba053be3b58990d Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 15 Feb 2016 23:30:12 +0000 Subject: [PATCH 138/337] Making mps_root_create_thread a convenience function for the common case. Copied from Perforce Change: 189205 ServerID: perforce.ravenbrook.com --- mps/code/airtest.c | 4 +--- mps/code/amcssth.c | 8 ++------ mps/code/awlut.c | 4 +--- mps/code/awluthe.c | 4 +--- mps/code/awlutth.c | 4 +--- mps/code/gcbench.c | 6 ++---- mps/code/mps.h | 10 ++++++---- mps/code/mpsi.c | 28 +++++++++++++++++++++++----- mps/code/mpsicv.c | 7 ++----- mps/code/zcoll.c | 12 ++++-------- mps/code/zmess.c | 6 ++---- 11 files changed, 45 insertions(+), 48 deletions(-) diff --git a/mps/code/airtest.c b/mps/code/airtest.c index 9399f643269..ad0ec456b99 100644 --- a/mps/code/airtest.c +++ b/mps/code/airtest.c @@ -127,9 +127,7 @@ static void test_main(void *marker, int interior, int stack) error("Couldn't register thread"); if (stack) { - res = mps_root_create_thread_tagged(®_root, scheme_arena, mps_rank_ambig(), - 0, thread, mps_scan_area_tagged, - sizeof(mps_word_t) - 1, 0, marker); + res = mps_root_create_thread(®_root, scheme_arena, thread, marker); if (res != MPS_RES_OK) error("Couldn't create root"); } diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c index cf9c6cbf0a4..f8738e9f590 100644 --- a/mps/code/amcssth.c +++ b/mps/code/amcssth.c @@ -139,9 +139,7 @@ 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_thread_tagged(®_root, arena, mps_rank_ambig(), - 0, thread, mps_scan_area_tagged, - sizeof(mps_word_t) - 1, 0, marker), + die(mps_root_create_thread(®_root, arena, thread, marker), "root_create"); die(mps_ap_create(&ap, cl->pool, mps_rank_exact()), "BufferCreate(fooey)"); @@ -318,9 +316,7 @@ 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_thread_tagged(®_root, arena, mps_rank_ambig(), - 0, thread, mps_scan_area_tagged, - sizeof(mps_word_t) - 1, 0, marker), + die(mps_root_create_thread(®_root, arena, thread, marker), "root_create"); die(mps_pool_create(&amc_pool, arena, mps_class_amc(), format, chain), diff --git a/mps/code/awlut.c b/mps/code/awlut.c index 61b3636d80a..e31e157c14c 100644 --- a/mps/code/awlut.c +++ b/mps/code/awlut.c @@ -267,9 +267,7 @@ static void *setup(void *v, size_t s) arena = guff->arena; thr = guff->thr; - die(mps_root_create_thread_tagged(&stack, arena, mps_rank_ambig(), - 0, thr, mps_scan_area_tagged, - sizeof(mps_word_t) - 1, 0, v), + die(mps_root_create_thread(&stack, arena, thr, 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 331128d54c0..a6653a3e23b 100644 --- a/mps/code/awluthe.c +++ b/mps/code/awluthe.c @@ -271,9 +271,7 @@ static void *setup(void *v, size_t s) arena = guff->arena; thr = guff->thr; - die(mps_root_create_thread_tagged(&stack, arena, mps_rank_ambig(), - 0, thr, mps_scan_area_tagged, - sizeof(mps_word_t) - 1, 0, v), + die(mps_root_create_thread(&stack, arena, thr, 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 8944df9b8bc..97d2c3f6a0f 100644 --- a/mps/code/awlutth.c +++ b/mps/code/awlutth.c @@ -254,9 +254,7 @@ static void *setup(void *v, size_t s) arena = guff->arena; thr = guff->thr; - die(mps_root_create_thread_tagged(&stack, arena, mps_rank_ambig(), - 0, thr, mps_scan_area_tagged, - sizeof(mps_word_t) - 1, 0, v), + die(mps_root_create_thread(&stack, arena, thr, 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 920c55d07da..1af36446ec6 100644 --- a/mps/code/gcbench.c +++ b/mps/code/gcbench.c @@ -176,10 +176,8 @@ static void *start(void *p) { gcthread_t thread = p; void *marker; RESMUST(mps_thread_reg(&thread->mps_thread, arena)); - RESMUST(mps_root_create_thread_tagged(&thread->reg_root, arena, mps_rank_ambig(), - (mps_rm_t)0, thread->mps_thread, - mps_scan_area_tagged, - sizeof(mps_word_t) - 1, 0, &marker)); + RESMUST(mps_root_create_thread(&thread->reg_root, arena, + thread->mps_thread, &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 bc04426524b..f976feec196 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -692,10 +692,12 @@ 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_thread(mps_root_t *, mps_arena_t, - mps_rank_t, mps_rm_t, mps_thr_t, - mps_area_scan_t, - void *, size_t, - void *); + mps_thr_t, void *); +extern mps_res_t mps_root_create_thread_scanned(mps_root_t *, mps_arena_t, + mps_rank_t, mps_rm_t, mps_thr_t, + mps_area_scan_t, + void *, size_t, + void *); extern mps_res_t mps_root_create_thread_tagged(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_thr_t, mps_area_scan_t, diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index db941471cd7..c191cabf664 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1453,13 +1453,31 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena, /* FIXME: document */ mps_res_t mps_root_create_thread(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_area_scan_t scan_area, - void *closure, - size_t closure_size, void *stack) +{ + return mps_root_create_thread_tagged(mps_root_o, + arena, + mps_rank_ambig(), + (mps_rm_t)0, + thread, + mps_scan_area_tagged, + sizeof(mps_word_t) - 1, + 0, + stack); +} + + +/* FIXME: document */ +mps_res_t mps_root_create_thread_scanned(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_area_scan_t scan_area, + void *closure, + size_t closure_size, + void *stack) { Rank rank = (Rank)mps_rank; Root root; diff --git a/mps/code/mpsicv.c b/mps/code/mpsicv.c index 55e499f55da..d0669947b2c 100644 --- a/mps/code/mpsicv.c +++ b/mps/code/mpsicv.c @@ -602,11 +602,8 @@ int main(int argc, char *argv[]) marker, (size_t)0), "root_create_reg"); } else { - die(mps_root_create_thread_tagged(®_root, arena, - mps_rank_ambig(), (mps_rm_t)0, - thread, mps_scan_area_tagged, - sizeof(mps_word_t) - 1, 0, marker), - "root_create_stack"); + die(mps_root_create_thread(®_root, arena, thread, marker), + "root_create_thread"); } mps_tramp(&r, test, arena, 0); diff --git a/mps/code/zcoll.c b/mps/code/zcoll.c index 96dfdbf7f46..6c921090317 100644 --- a/mps/code/zcoll.c +++ b/mps/code/zcoll.c @@ -574,10 +574,8 @@ static void StackScan(mps_arena_t arena, int on) { if(on) { Insist(root_stackreg == NULL); - die(mps_root_create_thread_tagged(&root_stackreg, arena, - mps_rank_ambig(), (mps_rm_t)0, stack_thr, - mps_scan_area_tagged, - sizeof(mps_word_t) - 1, 0, stack_start), + die(mps_root_create_thread(&root_stackreg, arena, + stack_thr, stack_start), "root_stackreg"); Insist(root_stackreg != NULL); } else { @@ -763,10 +761,8 @@ 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_thread_tagged(&root_stackreg, arena, - mps_rank_ambig(), (mps_rm_t)0, stack_thr, - mps_scan_area_tagged, - sizeof(mps_word_t) - 1, 0, stack_start), + die(mps_root_create_thread(&root_stackreg, arena, + stack_thr, stack_start), "root_stackreg"); diff --git a/mps/code/zmess.c b/mps/code/zmess.c index b1294dd4324..505de361200 100644 --- a/mps/code/zmess.c +++ b/mps/code/zmess.c @@ -330,10 +330,8 @@ 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_thread_tagged(&root_stackreg, arena, - mps_rank_ambig(), (mps_rm_t)0, thr, - mps_scan_area_tagged, - sizeof(mps_word_t) - 1, 0, &stack_starts_here), + die(mps_root_create_thread(&root_stackreg, arena, + thr, &stack_starts_here), "root_stackreg"); /* Make myrootCOUNT registered-for-finalization objects. */ From 4f9d662103bda4e3638784264977fa7ff2ef7d91 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 15 Feb 2016 23:39:24 +0000 Subject: [PATCH 139/337] Bringing scheme example up to date with interface changes. Copied from Perforce Change: 189206 ServerID: perforce.ravenbrook.com --- mps/example/scheme/scheme-advanced.c | 3 +-- mps/example/scheme/scheme.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/mps/example/scheme/scheme-advanced.c b/mps/example/scheme/scheme-advanced.c index d2275da895f..aaf16824498 100644 --- a/mps/example/scheme/scheme-advanced.c +++ b/mps/example/scheme/scheme-advanced.c @@ -4582,8 +4582,7 @@ 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_stack(®_root, arena, mps_rank_ambig(), - 0, thread, sizeof(mps_word_t) - 1, 0, marker); + res = mps_root_create_thread(®_root, arena, thread, 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 ea5583c5f19..69d34612660 100644 --- a/mps/example/scheme/scheme.c +++ b/mps/example/scheme/scheme.c @@ -4477,8 +4477,7 @@ 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_stack(®_root, arena, mps_rank_ambig(), - 0, thread, sizeof(mps_word_t) - 1, 0, marker); + res = mps_root_create_thread(®_root, arena, thread, marker); if (res != MPS_RES_OK) error("Couldn't create root"); /* Make sure we can pick up finalization messages. */ From 553093f3ed640a1a5caf94362a43851938337305 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 16 Feb 2016 00:34:10 +0000 Subject: [PATCH 140/337] Documenting thread root registration functions. Copied from Perforce Change: 189207 ServerID: perforce.ravenbrook.com --- mps/code/mpsi.c | 5 +- mps/code/root.c | 8 +- mps/code/scan.c | 1 + mps/manual/source/guide/lang.rst | 5 +- mps/manual/source/guide/vector.rst | 2 +- mps/manual/source/release.rst | 19 ++-- mps/manual/source/topic/allocation.rst | 2 +- mps/manual/source/topic/deprecated.rst | 13 +-- mps/manual/source/topic/root.rst | 132 +++++++++++++++++++++---- 9 files changed, 140 insertions(+), 47 deletions(-) diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index c191cabf664..3204a802dd5 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1387,7 +1387,7 @@ mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, mps_word_t mask) { return mps_root_create_table_tagged(mps_root_o, arena, mps_rank, mps_rm, - base, size, mps_scan_area_masked, + base, size, mps_scan_area_tagged, mask, 0); } @@ -1450,7 +1450,6 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena, } -/* FIXME: document */ mps_res_t mps_root_create_thread(mps_root_t *mps_root_o, mps_arena_t arena, mps_thr_t thread, @@ -1468,7 +1467,6 @@ mps_res_t mps_root_create_thread(mps_root_t *mps_root_o, } -/* FIXME: document */ mps_res_t mps_root_create_thread_scanned(mps_root_t *mps_root_o, mps_arena_t arena, mps_rank_t mps_rank, @@ -1507,7 +1505,6 @@ mps_res_t mps_root_create_thread_scanned(mps_root_t *mps_root_o, } -/* FIXME: re-document */ mps_res_t mps_root_create_thread_tagged(mps_root_t *mps_root_o, mps_arena_t arena, mps_rank_t mps_rank, diff --git a/mps/code/root.c b/mps/code/root.c index bfcfb09d74c..2338ca8120e 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -705,10 +705,9 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) switch(root->var) { case RootAREA: res = WriteF(stream, depth + 2, - "area base $A limit $A scan_area $P closure $P closure_size $U\n", + "area base $A limit $A scan_area closure $P closure_size $U\n", (WriteFA)root->the.area.base, (WriteFA)root->the.area.limit, - (WriteFP)root->the.area.scan_area, (WriteFP)root->the.area.closure, (WriteFP)root->the.area.closure_size, NULL); @@ -718,10 +717,9 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) case RootAREA_TAGGED: res = WriteF(stream, depth + 2, - "area base $A limit $A scan_area $P mask $B pattern $B\n", + "area base $A limit $A scan_area mask $B pattern $B\n", (WriteFA)root->the.areaTagged.base, (WriteFA)root->the.areaTagged.limit, - (WriteFP)root->the.areaTagged.scan_area, (WriteFB)root->the.areaTagged.tag.mask, (WriteFB)root->the.areaTagged.tag.pattern, NULL); @@ -742,7 +740,6 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) case RootTHREAD: res = WriteF(stream, depth + 2, "thread $P\n", (WriteFP)root->the.thread.thread, - "scan_area $P\n", (WriteFP)root->the.thread.scan_area, "closure $P size $U\n", (WriteFP)root->the.thread.the.closure.p, (WriteFU)root->the.thread.the.closure.s, @@ -755,7 +752,6 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) case RootTHREAD_TAGGED: res = WriteF(stream, depth + 2, "thread $P\n", (WriteFP)root->the.thread.thread, - "scan_area $P\n", (WriteFP)root->the.thread.scan_area, "mask $B\n", (WriteFB)root->the.thread.the.tag.mask, "pattern $B\n", (WriteFB)root->the.thread.the.tag.pattern, "stackBot $P\n", (WriteFP)root->the.thread.stackBot, diff --git a/mps/code/scan.c b/mps/code/scan.c index 4ac8fb715ad..df2b4a74e2f 100644 --- a/mps/code/scan.c +++ b/mps/code/scan.c @@ -5,6 +5,7 @@ * See end of file for license. * * TODO: Design document. + * FIXME: Manual entries for mps_scan_area etc. */ #include "mps.h" diff --git a/mps/manual/source/guide/lang.rst b/mps/manual/source/guide/lang.rst index 0205ceccd4d..6ae1ce60aaf 100644 --- a/mps/manual/source/guide/lang.rst +++ b/mps/manual/source/guide/lang.rst @@ -972,12 +972,11 @@ You register a thread with an :term:`arena` by calling if (res != MPS_RES_OK) error("Couldn't register thread"); You register the thread's :term:`registers` and :term:`control stack` -as a root by calling :c:func:`mps_root_create_stack`:: +as a root by calling :c:func:`mps_root_create_thread`:: void *marker = ▮ mps_root_t stack_root; - res = mps_root_create_stack(®_root, arena, mps_rank_ambig(), - 0, thread, sizeof(mps_word_t) - 1, 0, marker); + res = mps_root_create_thread(®_root, arena, thread, 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/guide/vector.rst b/mps/manual/source/guide/vector.rst index b6336e23569..bd09e0ade09 100644 --- a/mps/manual/source/guide/vector.rst +++ b/mps/manual/source/guide/vector.rst @@ -64,7 +64,7 @@ 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_stack` + registered as a root by calling :c:func:`mps_root_create_thread` then any local variable will do. 2. References in the new array must not be scanned until they have been diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 46e57a14178..f6229dbf6a7 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -17,14 +17,21 @@ 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_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. +#. New area scanning functions :c:func:`mps_scan_area`, + :c:func:`mps_scan_area_masked`, :c:func:`mps_scan_area_tagged`, + :c:func:`mps_scan_area_tagged_or_zero` for use when scanning, + especially when scanning threads and :term:`tagged references`. -#. New function :c:func:`mps_root_create_table_tagged` for roots +#. New thread root functions :c:func:`mps_root_create_thread` and + :c:func:`mps_root_create_thread_tagged` allow flexible scanning of + thread stacks and registers in any format, with convenient + implementations provided for :term:`tagged references`. + +#. New function :c:func:`mps_root_create_table_tagged` for tables of roots containing :term:`tagged references`. +#. New area root function :c:func:`mps_root_create_area` for areas of memory + that can be scanned by area scanning functions. Interface changes ................. @@ -40,7 +47,7 @@ Interface changes :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`. + of :c:func:`mps_root_create_thread_tagged`. #. The function :c:func:`mps_root_create_table_masked` is deprecated in favour of :c:func:`mps_root_create_table_tagged`. diff --git a/mps/manual/source/topic/allocation.rst b/mps/manual/source/topic/allocation.rst index e473cded0f7..7559381202b 100644 --- a/mps/manual/source/topic/allocation.rst +++ b/mps/manual/source/topic/allocation.rst @@ -152,7 +152,7 @@ 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 calling - :c:func:`mps_root_create_stack`. This is the simplest way to write + :c:func:`mps_root_create_thread`. 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). diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst index a956ddb4990..0589003950e 100644 --- a/mps/manual/source/topic/deprecated.rst +++ b/mps/manual/source/topic/deprecated.rst @@ -122,9 +122,7 @@ Deprecated in version 1.115 .. deprecated:: - Use :c:func:`mps_root_create_stack` instead, passing - ``sizeof(mps_word_t) - 1`` for the ``mask`` argument, and - ``0`` for the ``pattern`` argument. + Use :c:func:`mps_root_create_thread` instead. Register a :term:`root` that consists of the :term:`references` fixed in a :term:`thread's ` registers and stack by a @@ -176,9 +174,12 @@ Deprecated in version 1.115 Register a :term:`root` that consists of a vector of :term:`tagged references` whose pattern is zero. - This function is equivalent to calling - :c:func:`mps_root_create_table_tagged` with a ``pattern`` argument - of zero. + This function is equivalent to:: + + mps_root_create_table_tagged(root_o, arena, rank, rm, + base, size, + mps_scan_area_tagged, + mask, 0) .. c:type:: mps_res_t (*mps_reg_scan_t)(mps_ss_t ss, mps_thr_t thr, void *p, size_t s) diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index c54aefb6959..e68f435ee41 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -100,7 +100,7 @@ scan it for references: #. :c:func:`mps_root_create_table_tagged` if the root consists of a table of :term:`tagged references`; -#. :c:func:`mps_root_create_stack` if the root consists of the +#. :c:func:`mps_root_create_thread` if the root consists of the :term:`registers` and :term:`control stack` of a thread. See :ref:`topic-root-thread` below. @@ -146,7 +146,7 @@ Thread roots 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`. +root by calling :c:func:`mps_root_create_thread`. The MPS's stack scanner needs to know how to find the :term:`cold end` of the part of the stack to scan. The :term:`cold end` of the relevant @@ -170,8 +170,7 @@ registers a thread root and then calls the program:: res = mps_thread_reg(&thread, arena); if (res != MPS_RES_OK) error("Couldn't register thread"); - res = mps_root_create_stack(&stack_root, arena, mps_rank_ambig(), - 0, thread, 0, 0, marker); + res = mps_root_create_thread(&stack_root, arena, thread, marker); if (res != MPS_RES_OK) error("Couldn't create root"); exit_code = start(argc, argv); @@ -331,6 +330,10 @@ Root interface The registered root description persists until it is destroyed by calling :c:func:`mps_root_destroy`. + This is the most general kind of root, but gives the MPS the least + information to use for optimisation. Use a more specialized kind + of root whenever possible. + .. c:type:: mps_res_t (*mps_root_scan_t)(mps_ss_t ss, void *p, size_t s) @@ -384,7 +387,25 @@ Root interface calling :c:func:`mps_root_destroy`. -.. 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) +.. c:function:: mps_res_t mps_root_create_thread(mps_root_t *root_o, mps_arena_t arena, mps_thr_t thr, void *stack) + + Register a :term:`root` that consists of the :term:`references` in + a :term:`thread's ` registers and stack that are word aligned. + This is the most common kind of thread root. + + This function is equivalent to calling:: + + mps_root_create_thread_tagged(root_o, + arena, + mps_rank_ambig(), + (mps_rm_t)0, + thr, + mps_scan_area_tagged, + sizeof(mps_word_t) - 1, + 0, + stack); + +.. c:function:: mps_res_t mps_root_create_thread_tagged(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thr, mps_area_scan_t scan_area, 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 @@ -401,12 +422,19 @@ Root interface ``thr`` is the thread. - ``mask`` is an arbitrary mask that is applied to each word in the - thread's registers and stack. + ``scan_area`` is an tagged area scanning function that will be + used to scan the threads registers and stack, for example + :c:func:`mps_scan_area_tagged` or + :c:func:`mps_scan_area_tagged_or_zero`. - ``pattern`` is an arbitrary pattern; any word that is unequal to - this (after masking with ``mask``) is not considered to be a - reference. + ``mask`` is a :term:`bitmask` that is passed to ``scan_area`` to + be applied to the thread's registers and stack to locate the + :term:`tag`. + + ``pattern`` is passed to ``scan_area`` to determine whether to + consider a word as a reference. For example, + :c:func:`mps_scan_area_tagged` will not consider any word that is + unequal to this (after masking with ``mask``) to be a reference. ``stack`` is a pointer into the thread's stack. On platforms where the stack grows downwards (currently, all supported platforms), @@ -429,9 +457,27 @@ Root interface 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. + You can avoid this risk in several ways: + + #. Choosing to tag pointers with zero, setting ``scan_area`` + as :c:func:`mps_scan_area_tagged` and setting ``pattern`` + to zero. + + #. Set ``scan_area`` to :c:func:`mps_scan_area_tagged_or_zero` + so that untagged pointers are scanned. Thist may lead to + some additional scanning and retention. + + #. Use :c:func:`mps_root_create_thread_scanned` and set + ``scan_area`` to :c:func:`mps_scan_area`: in this case all + words in registers and on the stack are scanned, leading to + possible additional scanning and retention. + + #. Write your own compiler with complete control over register + contents and stack format, use + :c:func:`mps_root_create_thread_scanned` and set + ``scan_area`` to your own custom scanner, derived from the + source code of :c:func:`mps_scan_area`, that knows the + format. .. note:: @@ -441,6 +487,46 @@ Root interface expertise with the platform's virtual memory interface. +.. c:function:: mps_res_t mps_root_create_thread_scanned(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thread, mps_area_scan_t scan_area, void *closure, size_t closure_size, void *stack) + + Register a :term:`root` that consists of the :term:`references` in + a :term:`thread's ` registers and stack, scanned by an + arbitrary area 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. + + ``scan_area`` is an area scanning function that will be used to + scan the threads registers and stack, for example + :c:func:`mps_scan_area`, or a similar user-defined function. + + ``closure`` is an arbitrary pointer that is passed to ``scan_area`` + and intended to point to any parameters it needs. + + ``closure_size`` is an arbitrary size that is passed to + ``scan_area`` but is conventionally the size of the parameter + object pointer to by ``closure``. + + ``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`. + .. 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 @@ -490,7 +576,7 @@ Root interface mps_addr_t base = my_table; mps_root_create_table(..., base, ...) -.. c:function:: mps_res_t mps_root_create_table_tagged(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_addr_t *base, size_t count, mps_word_t mask, mps_word_t pattern) +.. c:function:: mps_res_t mps_root_create_table_tagged(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_addr_t *base, size_t count, mps_area_scan_t scan_area, mps_word_t mask, mps_word_t pattern) Register a :term:`root` that consists of a vector of :term:`tagged references`. @@ -508,12 +594,17 @@ Root interface ``count`` is the number of tagged references in the vector. - ``mask`` is a :term:`bitmask` whose set bits specify the location of - the :term:`tag`. + ``scan_area`` is an tagged area scanning function that will be + used to scan the table, for example :c:func:`mps_scan_area_tagged` + or :c:func:`mps_scan_area_tagged_or_zero`. - ``pattern`` is a the value of the tag that indicates that the value - in the vector is a reference. Any value in the vector with a tag - that does not match the pattern is ignored. + ``mask`` is a :term:`bitmask` that is passed to ``scan_area`` to + be applied to the words in the vector to locate the :term:`tag`. + + ``pattern`` is passed to ``scan_area`` to determine whether to + consider a word as a reference. For example, + :c:func:`mps_scan_area_tagged` will not consider any word that is + unequal to this (after masking with ``mask``) to be a reference. Returns :c:macro:`MPS_RES_OK` if the root was registered successfully, :c:macro:`MPS_RES_MEMORY` if the new root @@ -538,10 +629,11 @@ Root interface mps_res_t res; mps_root_t root; mps_addr_t base = symtab; - res = mps_root_create_table_masked(&root, arena, + res = mps_root_create_table_tagged(&root, arena, mps_rank_exact(), (mps_rm_t)0, base, symtab_size * 2, + mps_scan_area_tagged, (mps_word_t)TAG_MASK, (mps_word_t)TAG_PATTERN); if (res != MPS_RES_OK) errror("can't create symtab root"); From 7e04c0f137f6b7a55d8b84f11d5be38058d3bfb8 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 16 Feb 2016 00:55:23 +0000 Subject: [PATCH 141/337] Fixing build for os x. Copied from Perforce Change: 189210 ServerID: perforce.ravenbrook.com --- mps/code/ssixi3.c | 6 ++++-- mps/code/thxc.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mps/code/ssixi3.c b/mps/code/ssixi3.c index db67d0e61e4..34d457944d0 100644 --- a/mps/code/ssixi3.c +++ b/mps/code/ssixi3.c @@ -49,7 +49,9 @@ SRCID(ssixi3, "$Id$"); #define ASMV(x) __asm__ volatile (x) -Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern) +Res StackScan(ScanState ss, Word *stackBot, + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { Word calleeSaveRegs[4]; @@ -63,7 +65,7 @@ Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern) ASMV("mov %%ebp, %0" : "=m" (calleeSaveRegs[3])); return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs), - mask, pattern); + scan_area, closure, closure_size); } diff --git a/mps/code/thxc.c b/mps/code/thxc.c index e2206ceb0c7..26a3db2c845 100644 --- a/mps/code/thxc.c +++ b/mps/code/thxc.c @@ -223,7 +223,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, if (thread->port == self) { /* scan this thread's stack */ AVER(thread->alive); - res = StackScan(ss, stackBot, mask, pattern); + res = StackScan(ss, stackBot, scan_area, closure, closure_size); if(res != ResOK) return res; } else if (thread->alive) { From c08c579ef1c36cd72745c6b11d50340af6bae54c Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 16 Feb 2016 01:01:32 +0000 Subject: [PATCH 142/337] Adding scan.c to xcode project. Copied from Perforce Change: 189220 ServerID: perforce.ravenbrook.com --- mps/code/mps.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index 99f323927be..0a268989292 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -1657,6 +1657,7 @@ 3124CAE4156BE6D500753214 /* fmthe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fmthe.c; sourceTree = ""; }; 3124CAEB156BE7F300753214 /* amcss */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = amcss; sourceTree = BUILT_PRODUCTS_DIR; }; 3124CAF5156BE81100753214 /* amcss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = amcss.c; sourceTree = ""; }; + 314562191C72ABFA00D7A514 /* scan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scan.c; sourceTree = ""; }; 315B7AFC17834FDB00B097C4 /* proti3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = proti3.c; sourceTree = ""; }; 315B7AFD17834FDB00B097C4 /* proti6.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = proti6.c; sourceTree = ""; }; 317B3C2A1731830100F9A469 /* arg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arg.c; sourceTree = ""; }; @@ -2476,6 +2477,7 @@ 31EEAC31156AB2F200714D05 /* sac.c */, 311F2F7417398B7100C15B6A /* sac.h */, 311F2F7517398B8E00C15B6A /* sc.h */, + 314562191C72ABFA00D7A514 /* scan.c */, 31EEAC1D156AB2B200714D05 /* seg.c */, 31EEAC32156AB2F200714D05 /* shield.c */, 31EEAC43156AB32500714D05 /* splay.c */, From 9da5d74f1ca513e46ac178f7c37bbeade180eecb Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 16 Feb 2016 11:40:17 +0000 Subject: [PATCH 143/337] Fixing build for windows. Copied from Perforce Change: 189215 ServerID: perforce.ravenbrook.com --- mps/code/comm.nmk | 1 + mps/code/ssw3i3mv.c | 6 ++++-- mps/code/ssw3i6mv.c | 6 ++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/mps/code/comm.nmk b/mps/code/comm.nmk index 523a6831ec5..661e1c6c0c9 100644 --- a/mps/code/comm.nmk +++ b/mps/code/comm.nmk @@ -160,6 +160,7 @@ MPMCOMMON=\ [root] \ [sa] \ [sac] \ + [scan] \ [seg] \ [shield] \ [splay] \ diff --git a/mps/code/ssw3i3mv.c b/mps/code/ssw3i3mv.c index 85d3d750322..c5a1aa15620 100644 --- a/mps/code/ssw3i3mv.c +++ b/mps/code/ssw3i3mv.c @@ -22,7 +22,9 @@ SRCID(ssw3i3mv, "$Id$"); -Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern) +Res StackScan(ScanState ss, Word *stackBot, + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { jmp_buf jb; @@ -43,7 +45,7 @@ Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern) AVER(offsetof(_JUMP_BUFFER, Esi) == offsetof(_JUMP_BUFFER, Ebx) + 8); return StackScanInner(ss, stackBot, (Word *)&((_JUMP_BUFFER *)jb)->Ebx, 3, - mask, pattern); + scan_area, closure, closure_size); } /* C. COPYRIGHT AND LICENSE diff --git a/mps/code/ssw3i6mv.c b/mps/code/ssw3i6mv.c index 62c7b023cb1..a146e28d22f 100644 --- a/mps/code/ssw3i6mv.c +++ b/mps/code/ssw3i6mv.c @@ -30,7 +30,9 @@ SRCID(ssw3i6mv, "$Id$"); -Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern) +Res StackScan(ScanState ss, Word *stackBot, + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { jmp_buf jb; @@ -62,7 +64,7 @@ Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern) AVER(offsetof(_JUMP_BUFFER, R15) == offsetof(_JUMP_BUFFER, Rbx) + 64); return StackScanInner(ss, stackBot, (Word *)&((_JUMP_BUFFER *)jb)->Rbx, 9, - mask, pattern); + scan_area, closure, closure_size); } /* C. COPYRIGHT AND LICENSE From e5cc472798e41112ae801adbfc0b208cc5f5864c Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 16 Feb 2016 11:53:15 +0000 Subject: [PATCH 144/337] Probably fixing build for pelles c (untested). Copied from Perforce Change: 189216 ServerID: perforce.ravenbrook.com --- mps/code/ssw3i3pc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mps/code/ssw3i3pc.c b/mps/code/ssw3i3pc.c index 88d4d2a70cf..bb84b199618 100644 --- a/mps/code/ssw3i3pc.c +++ b/mps/code/ssw3i3pc.c @@ -46,7 +46,9 @@ typedef struct __JUMP_BUFFER { } _JUMP_BUFFER; -Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern) +Res StackScan(ScanState ss, Word *stackBot, + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { jmp_buf jb; @@ -66,7 +68,7 @@ Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern) AVER(offsetof(_JUMP_BUFFER, Esi) == offsetof(_JUMP_BUFFER, Ebx) + 8); return StackScanInner(ss, stackBot, (Word *)&((_JUMP_BUFFER *)jb)->Ebx, 3, - mask, pattern); + scan_area, closure, closure_size); } From 3ec32b9a96b5fda768d1317e2bbeb1b0d5ce028a Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 16 Feb 2016 11:54:39 +0000 Subject: [PATCH 145/337] Fixing build for ansi. Copied from Perforce Change: 189221 ServerID: perforce.ravenbrook.com --- mps/code/ssan.c | 6 ++++-- mps/code/than.c | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/mps/code/ssan.c b/mps/code/ssan.c index 922f15f397c..8414b3a1157 100644 --- a/mps/code/ssan.c +++ b/mps/code/ssan.c @@ -21,7 +21,9 @@ SRCID(ssan, "$Id$"); -Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern) +Res StackScan(ScanState ss, Word *stackBot, + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { jmp_buf jb; Word *stackTop = (Word *)&jb; @@ -36,7 +38,7 @@ Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern) (void)setjmp(jb); return StackScanInner(ss, stackBot, stackTop, sizeof jb / sizeof(Word), - mask, pattern); + scan_area, closure, closure_size); } diff --git a/mps/code/than.c b/mps/code/than.c index fb3219c270d..44c3b48bd60 100644 --- a/mps/code/than.c +++ b/mps/code/than.c @@ -118,10 +118,11 @@ Arena ThreadArena(Thread thread) Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, - Word mask, Word pattern) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { UNUSED(thread); - return StackScan(ss, stackBot, mask, pattern); + return StackScan(ss, stackBot, scan_area, closure, closure_size); } From 0327e5ff27ac905b2b2e40a7575b799f60549a90 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 16 Feb 2016 13:55:32 +0000 Subject: [PATCH 146/337] Documenting area scanners. Copied from Perforce Change: 189233 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/scanning.rst | 131 +++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst index 6b4c4a1d396..5ca607e6e34 100644 --- a/mps/manual/source/topic/scanning.rst +++ b/mps/manual/source/topic/scanning.rst @@ -501,3 +501,134 @@ 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`. + + +.. index:: + single: scanning; area scanners + +Area scanners +------------- + +An area scanner :term:`scans` an area of memory for +:term:`refrerences `. Various functions in the MPS interface, +:such as :c:func:`mps_root_create_thread_tagged`, accept area scanners as +arguments so that the :term:`client program` can specify how to scan +special areas such as the :term:`control stack`. + +The MPS provides some area scanners for common situations (such as an +area which is a vector of words with references identified by +:term:`tag bits `) but the :term:`client program` can provide +its own. + +If you want to develop your own area scanner you can start by adapting +the scanners, found in ``scan.c`` in the MPS source code. + +.. c:type:: mps_area_scan_t + + The type of area scanning functions, which are all of the form:: + + mps_res_t scan(mps_ss_t ss, + mps_word_t *base, mps_word_t *limit, + void *closure, size_t closure_size); + + ``ss`` is the :term:`scan state`. + + ``base`` points to the first word to be scanned. + + ``limit`` points to the location just beyond the end of the area to be scanned. + + ``closure`` is a pointer to an arbitrary :term:`closure` object that + contains parameters for the scan. The object passed depends on the + context. For example, if the scanner was originally registered with + :c:func:`mps_root_create_thread_tagged` then it is the value of + the ``closure`` argument originally passed to that function. + + ``closure_size`` is an arbitrary size, conventionally used for the + size of the :term:`closure` pointed to by ``closure``. For example, + if the scanner was originally registered with + :c:func:`mps_root_create_thread_tagged` then it is the value of + the ``closure_size`` argument originally passed to that function. + +.. c:function:: mps_res_t mps_scan_area(mps_ss_t ss, mps_word_t *base, mps_word_t *limit, void *closure, size_t closure_size) + + Scan an area of memory :term:`fixing ` every word. ``closure`` and ``closure_size`` are ignored. + + This scanner is appropriate for use when all words in the area are simple untagged references. + +.. c:type:: mps_scan_tag_t + + The type of a scan closure that is passed to the tagged area + scanners in order to specify the format of the :term:`tagged + references` in the area. + + It is a pointer to a :c:type:`mps_scan_tag_s` structure. + +.. c:type:: mps_scan_tag_s + + The type of the structure used to represent :term:`tag bits ` in :term:`tagged references` :: + + typedef struct mps_scan_tag_s { + mps_word_t mask; + mps_word_t pattern; + } mps_scan_tag_s; + + ``mask`` is bit mask that is applied to words in the area to find + the tag. For example, a mask of 0b111 (decimal 7) specifies that + the tag is stored in the least-significant three bits of the word. + + ``pattern`` is a bit pattern that is compared to the bits extracted + by the ``mask`` to determine if the word is a reference. The exact + interpretation depends on which area scanner it is passed to. See + the documentation for the individual area scanners. + +.. c:function:: mps_res_t mps_scan_area_masked(mps_ss_t ss, mps_word_t *base, mps_word_t *limit, void *closure, size_t closure_size) + + Scan an area of memory :term:`fixing ` every word, but but remove tag bits before fixing references, and restore them afterwards. ``closure`` should point to an :c:type:`mps_scan_tag_s`. + + For example, if ``mask`` is 0b111 (decimal 7), then this scanner + will clear the bottom three bits of each word before fixing. A word + such as 0xC1374823 would be detagged to 0xC1374820 before fixing. + If it were fixed to 0xC812BC88 then it would be tagged back to + 0xC812BC8B before being stored. + + This scanner is useful when all words in the area must be treated as + references no matter what tag they have. This can be especially + useful if you are debugging your tagging scheme. + +.. c:function:: mps_res_t mps_scan_area_tagged(mps_ss_t ss, mps_word_t *base, mps_word_t *limit, void *closure, size_t closure_size) + + Scan an area of memory :term:`fixing ` only words whose masked + bits match a particular tag pattern. ``closure`` should point to a + :c:type:`mps_scan_tag_s`. + + For example, if ``mask`` is 7 and ``pattern`` is 5, then this + scanner will only fix words whose low order bits are 0b101. + + Tags are masked off and restored as in :c:func:`mps_scan_area_masked`. + + This scanner is useful when you have a single tag pattern that + distinguishes references, especially when that pattern is zero. + + .. 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. See + :c:func:`mps_root_create_thread_tagged`. + +.. c:function:: mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t ss, mps_word_t *base, mps_word_t *limit, void *closure, size_t closure_size) + + Scan an area of memory :term:`fixing ` only words whose masked + bits are zero or match a particular tag pattern. ``closure`` should + point to a + :c:type:`mps_scan_tag_s`. + + For example, if ``mask`` is 7 and ``pattern`` is 3, then this + scanner will fix words whose low order bits are 0b011 and words + whose low order bits are 0b000, but not any others. + + This scanner is most useful for ambiguously scanning the stack and + registers when using an optimising C compiler and non-zero tags on + references, since the compiler is likely to leave untagged addresses + of objects around which must not be ignored. From e014bf6aeb5c7413ed646691c604a2871b62d8b9 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 16 Feb 2016 14:41:40 +0000 Subject: [PATCH 147/337] Cross-referencing area scanners documentation from root topic that mentions them. Copied from Perforce Change: 189238 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/root.rst | 13 ++++++++----- mps/manual/source/topic/scanning.rst | 2 ++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index e68f435ee41..dd22f7b7c0b 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -422,10 +422,11 @@ Root interface ``thr`` is the thread. - ``scan_area`` is an tagged area scanning function that will be - used to scan the threads registers and stack, for example + ``scan_area`` is an tagged area scanning function that will be used + to scan the threads registers and stack, for example :c:func:`mps_scan_area_tagged` or - :c:func:`mps_scan_area_tagged_or_zero`. + :c:func:`mps_scan_area_tagged_or_zero`. See + :ref:`topic-area-scanners`. ``mask`` is a :term:`bitmask` that is passed to ``scan_area`` to be applied to the thread's registers and stack to locate the @@ -506,7 +507,8 @@ Root interface ``scan_area`` is an area scanning function that will be used to scan the threads registers and stack, for example - :c:func:`mps_scan_area`, or a similar user-defined function. + :c:func:`mps_scan_area`, or a similar user-defined function. See + :ref:`topic-area-scanners`. ``closure`` is an arbitrary pointer that is passed to ``scan_area`` and intended to point to any parameters it needs. @@ -596,7 +598,8 @@ Root interface ``scan_area`` is an tagged area scanning function that will be used to scan the table, for example :c:func:`mps_scan_area_tagged` - or :c:func:`mps_scan_area_tagged_or_zero`. + or :c:func:`mps_scan_area_tagged_or_zero`. See + :ref:`topic-area-scanners`. ``mask`` is a :term:`bitmask` that is passed to ``scan_area`` to be applied to the words in the vector to locate the :term:`tag`. diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst index 5ca607e6e34..46159238860 100644 --- a/mps/manual/source/topic/scanning.rst +++ b/mps/manual/source/topic/scanning.rst @@ -506,6 +506,8 @@ Fixing interface .. index:: single: scanning; area scanners +.. _topic-area-scanners: + Area scanners ------------- From 855719a568498fbb8d2b5186a7a520e4fe724ecb Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 16 Feb 2016 16:03:28 +0000 Subject: [PATCH 148/337] Documenting mps_root_create_area and mps_root_create_area_tagged. Copied from Perforce Change: 189243 ServerID: perforce.ravenbrook.com --- mps/code/mpsi.c | 12 ++-- mps/manual/source/topic/root.rst | 95 ++++++++++++++++++++++++++++++-- 2 files changed, 97 insertions(+), 10 deletions(-) diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 3204a802dd5..da2572cc98e 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1295,12 +1295,13 @@ mps_res_t mps_root_create_table(mps_root_t *mps_root_o, mps_arena_t arena, AVER(base != NULL); AVER(size > 0); - /* .root.table-size: size is the length of the array at base, not */ - /* the size in bytes. However, RootCreateArea expects base and */ - /* limit pointers. Be careful. */ + /* .root.table-size: size is the length of the array at base, not + the size in bytes. However, RootCreateArea expects base and limit + pointers. Be careful. Avoid type punning by casting through + void *. */ res = RootCreateArea(&root, arena, rank, mode, - (Word *)base, (Word *)base + size, + (void *)base, (void *)(base + size), mps_scan_area, NULL, 0); ArenaLeave(arena); @@ -1311,7 +1312,6 @@ mps_res_t mps_root_create_table(mps_root_t *mps_root_o, mps_arena_t arena, return MPS_RES_OK; } -/* FIXME: document */ mps_res_t mps_root_create_area(mps_root_t *mps_root_o, mps_arena_t arena, mps_rank_t mps_rank, mps_rm_t mps_rm, @@ -1369,7 +1369,7 @@ mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, /* .root.table-size */ res = RootCreateAreaTagged(&root, arena, rank, mode, - (Word *)base, (Word *)base + size, + (void *)base, (void *)(base + size), scan_area, mask, pattern); ArenaLeave(arena); diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index dd22f7b7c0b..0955118e757 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -394,7 +394,7 @@ Root interface This is the most common kind of thread root. This function is equivalent to calling:: - + mps_root_create_thread_tagged(root_o, arena, mps_rank_ambig(), @@ -481,15 +481,14 @@ Root interface format. .. 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_thread_scanned(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thread, mps_area_scan_t scan_area, void *closure, size_t closure_size, void *stack) - + Register a :term:`root` that consists of the :term:`references` in a :term:`thread's ` registers and stack, scanned by an arbitrary area scanning function. @@ -529,6 +528,82 @@ 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_area(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_word_t *base, mps_word_t *limit, mps_area_scan_t scan_area, void *closure, size_t closure_size) + + Register a :term:`root` that consists of an area of memory scanned + by an area 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`. + + ``base`` points to the first word to be scanned. + + ``limit`` points to the location just beyond the end of the area to be scanned. + + ``scan_area`` is an area scanning function, for example + :c:func:`mps_scan_area`, or a similar user-defined function. See + :ref:`topic-area-scanners`. + + ``closure`` is an arbitrary pointer that is passed to ``scan_area`` + and intended to point to any parameters it needs. + + ``closure_size`` is an arbitrary size that is passed to + ``scan_area`` but is conventionally the size of the parameter + object pointer to by ``closure``. + + 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`. + +.. c:function:: mps_res_t mps_root_create_area_tagged(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_word_t *base, mps_word_t *limit, mps_area_scan_t scan_area, mps_word_t mask, mps_word_t pattern) + + Register a :term:`root` that consists of an area of memory scanned by + a tagged area 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`. + + ``base`` points to a vector of tagged references. + + ``count`` is the number of tagged references in the vector. + + ``scan_area`` is an tagged area scanning function that will be + used to scan the table, for example :c:func:`mps_scan_area_tagged` + or :c:func:`mps_scan_area_tagged_or_zero`. See + :ref:`topic-area-scanners`. + + ``mask`` is a :term:`bitmask` that is passed to ``scan_area`` to + be applied to the words in the vector to locate the :term:`tag`. + + ``pattern`` is passed to ``scan_area`` to determine whether to + consider a word as a reference. For example, + :c:func:`mps_scan_area_tagged` will not consider any word that is + unequal to this (after masking with ``mask``) to be a reference. + + 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`. + .. 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 @@ -547,6 +622,12 @@ Root interface ``count`` is the number of references in the vector. + This function is equivalent to:: + + mps_root_create_area(root_o, arena, rank, mode, + (void *)base, (void *)(base + count), + mps_scan_area, NULL, 0) + 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` @@ -617,6 +698,12 @@ Root interface The registered root description persists until it is destroyed by calling :c:func:`mps_root_destroy`. + This function is equivalent to:: + + mps_root_create_area_tagged(root_o, arena, rank, mode, + (void *)base, (void *)(base + size), + scan_area, mask, pattern) + For example:: #define TAG_MASK 0x3 /* bottom two bits */ From 5ab2ac2aab255a030f8edbc587708309c8e74afc Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 16 Feb 2016 16:27:20 +0000 Subject: [PATCH 149/337] Minor tidying up of the manual. Copied from Perforce Change: 189246 ServerID: perforce.ravenbrook.com --- mps/manual/source/release.rst | 8 +++++--- mps/manual/source/topic/root.rst | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index e3b793a24f4..f95aaba331e 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -28,15 +28,17 @@ New features :c:func:`mps_scan_area_tagged_or_zero` for use when scanning, especially when scanning threads and :term:`tagged references`. -#. New thread root functions :c:func:`mps_root_create_thread` and - :c:func:`mps_root_create_thread_tagged` allow flexible scanning of +#. New thread root functions :c:func:`mps_root_create_thread`, + :c:func:`mps_root_create_thread_tagged`, and + :c:func:`mps_root_create_thread_scanned` allow flexible scanning of thread stacks and registers in any format, with convenient implementations provided for :term:`tagged references`. #. New function :c:func:`mps_root_create_table_tagged` for tables of roots containing :term:`tagged references`. -#. New area root function :c:func:`mps_root_create_area` for areas of memory +#. New area root functions :c:func:`mps_root_create_area` and + :c:func:`mps_root_create_area_tagged` for areas of memory that can be scanned by area scanning functions. Interface changes diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index 0955118e757..9a5aa69ed94 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 six ways to register a root, depending on how you need to +There are five 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 @@ -94,12 +94,12 @@ scan it for references: by the format's :term:`scan method` (of type :c:type:`mps_fmt_scan_t`); +#. :c:func:`mps_root_create_area` if the root consists of an area + of memory; + #. :c:func:`mps_root_create_table` if the root consists of a table of references; -#. :c:func:`mps_root_create_table_tagged` if the root consists of a - table of :term:`tagged references`; - #. :c:func:`mps_root_create_thread` if the root consists of the :term:`registers` and :term:`control stack` of a thread. See :ref:`topic-root-thread` below. From fd45719968cd2b867a328cad9b234624493735dc Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 16 Feb 2016 16:27:57 +0000 Subject: [PATCH 150/337] Reducing the number of root union variants using a nested union. detabifying. Copied from Perforce Change: 189247 ServerID: perforce.ravenbrook.com --- mps/code/root.c | 79 +++++++++++++++++++++++-------------------------- mps/code/scan.c | 26 ++++++++-------- 2 files changed, 50 insertions(+), 55 deletions(-) diff --git a/mps/code/root.c b/mps/code/root.c index 2338ca8120e..c08fb79274f 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -17,6 +17,14 @@ SRCID(root, "$Id$"); #define RootSig ((Sig)0x51960029) /* SIGnature ROOT */ +typedef union AreaScanUnion { + struct { + void *p; + size_t s; + } closure; + mps_scan_tag_s tag; /* tag for scanning */ +} AreaScanUnion; + typedef struct RootStruct { Sig sig; Serial serial; /* from arena->rootSerial */ @@ -41,25 +49,12 @@ typedef struct RootStruct { Word *base; /* beginning of area */ Word *limit; /* one off end of area */ mps_area_scan_t scan_area;/* area scanning function */ - void *closure; /* closure for scanning function */ - size_t closure_size; /* closure for scanning function */ + AreaScanUnion the; } area; - struct { - Word *base; /* beginning of area */ - Word *limit; /* one off end of area */ - mps_area_scan_t scan_area;/* area scanning function */ - mps_scan_tag_s tag; /* tag for scanning */ - } areaTagged; struct { Thread thread; /* passed to scan */ mps_area_scan_t scan_area;/* area scanner for stack and registers */ - union { - struct { - void *p; - size_t s; - } closure; - mps_scan_tag_s tag; /* tag for scanning */ - } the; + AreaScanUnion the; Word *stackBot; /* bottom of stack */ } thread; struct { @@ -78,7 +73,7 @@ Bool RootVarCheck(RootVar rootVar) { CHECKL(rootVar == RootAREA || rootVar == RootAREA_TAGGED || rootVar == RootFUN || rootVar == RootFMT - || rootVar == RootTHREAD + || rootVar == RootTHREAD || rootVar == RootTHREAD_TAGGED); UNUSED(rootVar); return TRUE; @@ -124,10 +119,10 @@ Bool RootCheck(Root root) break; case RootAREA_TAGGED: - CHECKL(root->the.areaTagged.base != 0); - CHECKL(root->the.areaTagged.base < root->the.areaTagged.limit); - CHECKL(FUNCHECK(root->the.areaTagged.scan_area)); - CHECKL((~root->the.areaTagged.tag.mask & root->the.areaTagged.tag.pattern) == 0); + CHECKL(root->the.area.base != 0); + CHECKL(root->the.area.base < root->the.area.limit); + CHECKL(FUNCHECK(root->the.area.scan_area)); + CHECKL((~root->the.area.the.tag.mask & root->the.area.the.tag.pattern) == 0); break; case RootFUN: @@ -166,7 +161,7 @@ Bool RootCheck(Root root) } -/* rootCreate, RootCreateArea, RootCreateReg, RootCreateFmt, RootCreateFun +/* rootCreate, RootCreateArea, RootCreateThread, RootCreateFmt, RootCreateFun * * RootCreate* set up the appropriate union member, and call the generic * create function to do the actual creation @@ -292,8 +287,8 @@ Res RootCreateArea(Root *rootReturn, Arena arena, theUnion.area.base = base; theUnion.area.limit = limit; theUnion.area.scan_area = scan_area; - theUnion.area.closure = closure; - theUnion.area.closure_size = closure_size; + theUnion.area.the.closure.p = closure; + theUnion.area.the.closure.s = closure_size; res = rootCreateProtectable(rootReturn, arena, rank, mode, RootAREA, (Addr)base, (Addr)limit, &theUnion); @@ -314,11 +309,11 @@ Res RootCreateAreaTagged(Root *rootReturn, Arena arena, /* Can't check anything about mask. */ AVER((mask & pattern) == pattern); - theUnion.areaTagged.base = base; - theUnion.areaTagged.limit = limit; - theUnion.areaTagged.scan_area = scan_area; - theUnion.areaTagged.tag.mask = mask; - theUnion.areaTagged.tag.pattern = pattern; + theUnion.area.base = base; + theUnion.area.limit = limit; + theUnion.area.scan_area = scan_area; + theUnion.area.the.tag.mask = mask; + theUnion.area.the.tag.pattern = pattern; return rootCreateProtectable(rootReturn, arena, rank, mode, RootAREA_TAGGED, (Addr)base, (Addr)limit, &theUnion); @@ -534,8 +529,8 @@ Res RootScan(ScanState ss, Root root) root->the.area.base, root->the.area.limit, root->the.area.scan_area, - root->the.area.closure, - root->the.area.closure_size); + root->the.area.the.closure.p, + root->the.area.the.closure.s); ss->scannedSize += AddrOffset(root->the.area.base, root->the.area.limit); if (res != ResOK) goto failScan; @@ -543,12 +538,12 @@ Res RootScan(ScanState ss, Root root) case RootAREA_TAGGED: res = TraceScanArea(ss, - root->the.areaTagged.base, - root->the.areaTagged.limit, - root->the.areaTagged.scan_area, - &root->the.areaTagged.tag, - sizeof(root->the.areaTagged.tag)); - ss->scannedSize += AddrOffset(root->the.areaTagged.base, root->the.areaTagged.limit); + root->the.area.base, + root->the.area.limit, + root->the.area.scan_area, + &root->the.area.the.tag, + sizeof(root->the.area.the.tag)); + ss->scannedSize += AddrOffset(root->the.area.base, root->the.area.limit); if (res != ResOK) goto failScan; break; @@ -708,8 +703,8 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) "area base $A limit $A scan_area closure $P closure_size $U\n", (WriteFA)root->the.area.base, (WriteFA)root->the.area.limit, - (WriteFP)root->the.area.closure, - (WriteFP)root->the.area.closure_size, + (WriteFP)root->the.area.the.closure.p, + (WriteFP)root->the.area.the.closure.s, NULL); if (res != ResOK) return res; @@ -718,10 +713,10 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) case RootAREA_TAGGED: res = WriteF(stream, depth + 2, "area base $A limit $A scan_area mask $B pattern $B\n", - (WriteFA)root->the.areaTagged.base, - (WriteFA)root->the.areaTagged.limit, - (WriteFB)root->the.areaTagged.tag.mask, - (WriteFB)root->the.areaTagged.tag.pattern, + (WriteFA)root->the.area.base, + (WriteFA)root->the.area.limit, + (WriteFB)root->the.area.the.tag.mask, + (WriteFB)root->the.area.the.tag.pattern, NULL); if (res != ResOK) return res; diff --git a/mps/code/scan.c b/mps/code/scan.c index df2b4a74e2f..ce735710069 100644 --- a/mps/code/scan.c +++ b/mps/code/scan.c @@ -22,8 +22,8 @@ */ mps_res_t mps_scan_area(mps_ss_t ss, - mps_word_t *base, mps_word_t *limit, - void *closure, size_t closure_size) + mps_word_t *base, mps_word_t *limit, + void *closure, size_t closure_size) { (void)closure; /* unused */ (void)closure_size; /* unused */ @@ -34,10 +34,10 @@ mps_res_t mps_scan_area(mps_ss_t ss, mps_word_t word = *_p; mps_addr_t ref = (mps_addr_t)word; if (MPS_FIX1(ss, ref)) { - mps_res_t res = MPS_FIX2(ss, &ref); - if (res != MPS_RES_OK) - return res; - *_p = (mps_word_t)ref; + mps_res_t res = MPS_FIX2(ss, &ref); + if (res != MPS_RES_OK) + return res; + *_p = (mps_word_t)ref; } ++_p; } @@ -57,7 +57,7 @@ mps_res_t mps_scan_area(mps_ss_t ss, mps_addr_t ref = (mps_addr_t)(word ^ tag_bits); \ if (MPS_FIX1(ss, ref)) { \ mps_res_t res = MPS_FIX2(ss, &ref); \ - if (res != MPS_RES_OK) \ + if (res != MPS_RES_OK) \ return res; \ *p = (mps_word_t)ref | tag_bits; \ } \ @@ -81,8 +81,8 @@ mps_res_t mps_scan_area(mps_ss_t ss, */ mps_res_t mps_scan_area_masked(mps_ss_t ss, - mps_word_t *base, mps_word_t *limit, - void *closure, size_t closure_size) + mps_word_t *base, mps_word_t *limit, + void *closure, size_t closure_size) { mps_scan_tag_t tag = closure; mps_word_t mask = tag->mask; @@ -104,8 +104,8 @@ mps_res_t mps_scan_area_masked(mps_ss_t ss, */ mps_res_t mps_scan_area_tagged(mps_ss_t ss, - mps_word_t *base, mps_word_t *limit, - void *closure, size_t closure_size) + mps_word_t *base, mps_word_t *limit, + void *closure, size_t closure_size) { mps_scan_tag_t tag = closure; mps_word_t mask = tag->mask; @@ -134,8 +134,8 @@ mps_res_t mps_scan_area_tagged(mps_ss_t ss, */ mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t ss, - mps_word_t *base, mps_word_t *limit, - void *closure, size_t closure_size) + mps_word_t *base, mps_word_t *limit, + void *closure, size_t closure_size) { mps_scan_tag_t tag = closure; mps_word_t mask = tag->mask; From 0f8bee3762d6ebd896b68d1e6ac43506d98dff20 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 18 Feb 2016 19:58:13 +0000 Subject: [PATCH 151/337] Detabifying code and restructuredtext files. Copied from Perforce Change: 189309 ServerID: perforce.ravenbrook.com --- mps/code/arenavm.c | 4 +- mps/code/fmtscheme.h | 72 +-- mps/code/gcbench.c | 2 +- mps/code/getopt.h | 44 +- mps/code/getoptl.c | 794 ++++++++++++------------- mps/code/mpm.h | 36 +- mps/code/mps.h | 54 +- mps/code/mpsi.c | 98 +-- mps/code/prmci3fr.c | 4 +- mps/code/prmci3li.c | 10 +- mps/code/prmci3xc.c | 10 +- mps/code/prmci6fr.c | 4 +- mps/code/prmci6li.c | 10 +- mps/code/prmci6xc.c | 10 +- mps/code/prot.h | 4 +- mps/code/root.c | 78 +-- mps/code/ss.c | 10 +- mps/code/ss.h | 6 +- mps/code/ssan.c | 6 +- mps/code/ssixi3.c | 6 +- mps/code/ssixi6.c | 6 +- mps/code/ssw3i3mv.c | 6 +- mps/code/ssw3i3pc.c | 6 +- mps/code/ssw3i6mv.c | 6 +- mps/code/tagtest.c | 12 +- mps/code/th.h | 4 +- mps/code/than.c | 4 +- mps/code/thix.c | 6 +- mps/code/thw3i3.c | 10 +- mps/code/thw3i6.c | 8 +- mps/code/thxc.c | 6 +- mps/code/trace.c | 4 +- mps/code/zcoll.c | 4 +- mps/code/zmess.c | 2 +- mps/example/scheme/scheme-advanced.c | 118 ++-- mps/example/scheme/scheme-boehm.c | 134 ++--- mps/example/scheme/scheme-malloc.c | 134 ++--- mps/example/scheme/scheme.c | 134 ++--- mps/manual/source/glossary/r.rst | 8 +- mps/manual/source/glossary/v.rst | 2 +- mps/manual/source/guide/debug.rst | 20 +- mps/manual/source/mmref/lang.rst | 12 +- mps/manual/source/topic/deprecated.rst | 4 +- mps/manual/source/topic/root.rst | 48 +- mps/manual/source/topic/scanning.rst | 2 +- mps/procedure/branch-merge.rst | 2 +- mps/procedure/release-build.rst | 4 +- mps/procedure/version-create.rst | 4 +- 48 files changed, 986 insertions(+), 986 deletions(-) diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index f5666a1e7e6..9a0f43202f7 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -744,8 +744,8 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size) vmArenaGrow_Done: EVENT2(vmArenaExtendDone, chunkSize, ArenaReserved(VMArena2Arena(vmArena))); vmArena->extended(VMArena2Arena(vmArena), - newChunk->base, - AddrOffset(newChunk->base, newChunk->limit)); + newChunk->base, + AddrOffset(newChunk->base, newChunk->limit)); return res; } diff --git a/mps/code/fmtscheme.h b/mps/code/fmtscheme.h index 95a62a53cef..1149d9496a1 100644 --- a/mps/code/fmtscheme.h +++ b/mps/code/fmtscheme.h @@ -40,55 +40,55 @@ typedef struct type_s { } type_s; typedef struct pair_s { - type_t type; /* TYPE_PAIR */ - obj_t car, cdr; /* first and second projections */ + type_t type; /* TYPE_PAIR */ + obj_t car, cdr; /* first and second projections */ } pair_s; typedef struct symbol_s { - type_t type; /* TYPE_SYMBOL */ - size_t length; /* length of symbol string (excl. NUL) */ - char string[1]; /* symbol string, NUL terminated */ + type_t type; /* TYPE_SYMBOL */ + size_t length; /* length of symbol string (excl. NUL) */ + char string[1]; /* symbol string, NUL terminated */ } symbol_s; typedef struct integer_s { - type_t type; /* TYPE_INTEGER */ - long integer; /* the integer */ + type_t type; /* TYPE_INTEGER */ + long integer; /* the integer */ } integer_s; typedef struct special_s { - type_t type; /* TYPE_SPECIAL */ - char *name; /* printed representation, NUL terminated */ + type_t type; /* TYPE_SPECIAL */ + char *name; /* printed representation, NUL terminated */ } special_s; typedef struct operator_s { - type_t type; /* TYPE_OPERATOR */ - char *name; /* printed name, NUL terminated */ - entry_t entry; /* entry point -- see eval() */ - obj_t arguments, body; /* function arguments and code */ - obj_t env, op_env; /* closure environments */ + type_t type; /* TYPE_OPERATOR */ + char *name; /* printed name, NUL terminated */ + entry_t entry; /* entry point -- see eval() */ + obj_t arguments, body; /* function arguments and code */ + obj_t env, op_env; /* closure environments */ } operator_s; typedef struct string_s { - type_t type; /* TYPE_STRING */ - size_t length; /* number of chars in string */ - char string[1]; /* string, NUL terminated */ + type_t type; /* TYPE_STRING */ + size_t length; /* number of chars in string */ + char string[1]; /* string, NUL terminated */ } string_s; typedef struct port_s { - type_t type; /* TYPE_PORT */ - obj_t name; /* name of stream */ + type_t type; /* TYPE_PORT */ + obj_t name; /* name of stream */ FILE *stream; } port_s; typedef struct character_s { - type_t type; /* TYPE_CHARACTER */ - char c; /* the character */ + type_t type; /* TYPE_CHARACTER */ + char c; /* the character */ } character_s; typedef struct vector_s { - type_t type; /* TYPE_VECTOR */ - size_t length; /* number of elements */ - obj_t vector[1]; /* vector elements */ + type_t type; /* TYPE_VECTOR */ + size_t length; /* number of elements */ + obj_t vector[1]; /* vector elements */ } vector_s; typedef struct table_s { @@ -134,7 +134,7 @@ typedef struct pad_s { typedef union obj_u { - type_s type; /* one of TYPE_* */ + type_s type; /* one of TYPE_* */ pair_s pair; symbol_s symbol; integer_s integer; @@ -154,17 +154,17 @@ typedef union obj_u { /* structure macros */ -#define TYPE(obj) ((obj)->type.type) -#define CAR(obj) ((obj)->pair.car) -#define CDR(obj) ((obj)->pair.cdr) -#define CAAR(obj) CAR(CAR(obj)) -#define CADR(obj) CAR(CDR(obj)) -#define CDAR(obj) CDR(CAR(obj)) -#define CDDR(obj) CDR(CDR(obj)) -#define CADDR(obj) CAR(CDDR(obj)) -#define CDDDR(obj) CDR(CDDR(obj)) -#define CDDAR(obj) CDR(CDAR(obj)) -#define CADAR(obj) CAR(CDAR(obj)) +#define TYPE(obj) ((obj)->type.type) +#define CAR(obj) ((obj)->pair.car) +#define CDR(obj) ((obj)->pair.cdr) +#define CAAR(obj) CAR(CAR(obj)) +#define CADR(obj) CAR(CDR(obj)) +#define CDAR(obj) CDR(CAR(obj)) +#define CDDR(obj) CDR(CDR(obj)) +#define CADDR(obj) CAR(CDDR(obj)) +#define CDDDR(obj) CDR(CDDR(obj)) +#define CDDAR(obj) CDR(CDAR(obj)) +#define CADAR(obj) CAR(CDAR(obj)) extern obj_t scheme_make_bool(int condition); diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c index 1af36446ec6..8624637da4a 100644 --- a/mps/code/gcbench.c +++ b/mps/code/gcbench.c @@ -177,7 +177,7 @@ static void *start(void *p) { void *marker; RESMUST(mps_thread_reg(&thread->mps_thread, arena)); RESMUST(mps_root_create_thread(&thread->reg_root, arena, - thread->mps_thread, &marker)); + thread->mps_thread, &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/getopt.h b/mps/code/getopt.h index fb9c789d235..ca1ae21db87 100644 --- a/mps/code/getopt.h +++ b/mps/code/getopt.h @@ -6,8 +6,8 @@ * in the Memory Pool System test programs. */ -/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ -/* $FreeBSD: src/include/getopt.h,v 1.6.30.1.8.1 2012/03/03 06:15:13 kensmith Exp $ */ +/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ +/* $FreeBSD: src/include/getopt.h,v 1.6.30.1.8.1 2012/03/03 06:15:13 kensmith Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. @@ -57,33 +57,33 @@ #define optional_argument 2 struct option { - /* name of long option */ - const char *name; - /* - * one of no_argument, required_argument, and optional_argument: - * whether option takes an argument - */ - int has_arg; - /* if not NULL, set *flag to val when option found */ - int *flag; - /* if flag not NULL, value to set *flag to; else return value */ - int val; + /* name of long option */ + const char *name; + /* + * one of no_argument, required_argument, and optional_argument: + * whether option takes an argument + */ + int has_arg; + /* if not NULL, set *flag to val when option found */ + int *flag; + /* if flag not NULL, value to set *flag to; else return value */ + int val; }; -int getopt_long(int, char * const *, const char *, - const struct option *, int *); -int getopt_long_only(int, char * const *, const char *, - const struct option *, int *); +int getopt_long(int, char * const *, const char *, + const struct option *, int *); +int getopt_long_only(int, char * const *, const char *, + const struct option *, int *); #ifndef _GETOPT_DECLARED -#define _GETOPT_DECLARED -int getopt(int, char * const [], const char *); +#define _GETOPT_DECLARED +int getopt(int, char * const [], const char *); -extern char *optarg; /* getopt(3) external variables */ +extern char *optarg; /* getopt(3) external variables */ extern int optind, opterr, optopt; #endif #ifndef _OPTRESET_DECLARED -#define _OPTRESET_DECLARED -extern int optreset; /* getopt(3) external variable */ +#define _OPTRESET_DECLARED +extern int optreset; /* getopt(3) external variable */ #endif #endif /* !_GETOPT_H_ */ diff --git a/mps/code/getoptl.c b/mps/code/getoptl.c index cd09bb98990..3564362ed6d 100644 --- a/mps/code/getoptl.c +++ b/mps/code/getoptl.c @@ -6,8 +6,8 @@ * in the Memory Pool System test programs. */ -/* $OpenBSD: getopt_long.c,v 1.21 2006/09/22 17:22:05 millert Exp $ */ -/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ +/* $OpenBSD: getopt_long.c,v 1.21 2006/09/22 17:22:05 millert Exp $ */ +/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ /* * Copyright (c) 2002 Todd C. Miller @@ -73,38 +73,38 @@ #include #include -#define GNU_COMPATIBLE /* Be more compatible, configure's use us! */ +#define GNU_COMPATIBLE /* Be more compatible, configure's use us! */ -int opterr = 1; /* if error message should be printed */ -int optind = 1; /* index into parent argv vector */ -int optopt = '?'; /* character checked for validity */ -int optreset; /* reset getopt */ -char *optarg; /* argument associated with option */ +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ -#define PRINT_ERROR ((opterr) && (*options != ':')) +#define PRINT_ERROR ((opterr) && (*options != ':')) -#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ -#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ -#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ /* return values */ -#define BADCH (int)'?' -#define BADARG ((*options == ':') ? (int)':' : (int)'?') -#define INORDER (int)1 +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 -#define EMSG "" +#define EMSG "" #ifdef GNU_COMPATIBLE -#define NO_PREFIX (-1) -#define D_PREFIX 0 -#define DD_PREFIX 1 -#define W_PREFIX 2 +#define NO_PREFIX (-1) +#define D_PREFIX 0 +#define DD_PREFIX 1 +#define W_PREFIX 2 #endif static int getopt_internal(int, char * const *, const char *, - const struct option *, int *, int); + const struct option *, int *, int); static int parse_long_options(char * const *, const char *, - const struct option *, int *, int, int); + const struct option *, int *, int, int); static int gcd(int, int); static void permute_args(int, int, int, char * const *); @@ -136,7 +136,7 @@ static const char illoptstring[] = "unknown option -- %s"; static void warnx(const char *fmt, ...) { - va_list varargs; + va_list varargs; va_start(varargs, fmt); vfprintf(stderr, fmt, varargs); fputc('\n', stderr); @@ -149,16 +149,16 @@ warnx(const char *fmt, ...) static int gcd(int a, int b) { - int c; + int c; - c = a % b; - while (c != 0) { - a = b; - b = c; - c = a % b; - } + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } - return (b); + return (b); } /* @@ -168,427 +168,427 @@ gcd(int a, int b) */ static void permute_args(int panonopt_start, int panonopt_end, int opt_end, - char * const *nargv) + char * const *nargv) { - int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; - char *swap; + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; - /* - * compute lengths of blocks and number and size of cycles - */ - nnonopts = panonopt_end - panonopt_start; - nopts = opt_end - panonopt_end; - ncycle = gcd(nnonopts, nopts); - cyclelen = (opt_end - panonopt_start) / ncycle; + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; - for (i = 0; i < ncycle; i++) { - cstart = panonopt_end+i; - pos = cstart; - for (j = 0; j < cyclelen; j++) { - if (pos >= panonopt_end) - pos -= nnonopts; - else - pos += nopts; - swap = nargv[pos]; - /* LINTED const cast */ - ((char **) nargv)[pos] = nargv[cstart]; - /* LINTED const cast */ - ((char **)nargv)[cstart] = swap; - } - } + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } } /* * parse_long_options -- - * Parse long options in argc/argv argument vector. + * Parse long options in argc/argv argument vector. * Returns -1 if short_too is set and the option does not match long_options. */ static int parse_long_options(char * const *nargv, const char *options, - const struct option *long_options, int *idx, int short_too, int flags) + const struct option *long_options, int *idx, int short_too, int flags) { - char *current_argv, *has_equal; + char *current_argv, *has_equal; #ifdef GNU_COMPATIBLE - const char *current_dash; + const char *current_dash; #endif - size_t current_argv_len; - int i, match, exact_match, second_partial_match; + size_t current_argv_len; + int i, match, exact_match, second_partial_match; - current_argv = place; + current_argv = place; #ifdef GNU_COMPATIBLE - switch (dash_prefix) { - case D_PREFIX: - current_dash = "-"; - break; - case DD_PREFIX: - current_dash = "--"; - break; - case W_PREFIX: - current_dash = "-W "; - break; - default: - current_dash = ""; - break; - } + switch (dash_prefix) { + case D_PREFIX: + current_dash = "-"; + break; + case DD_PREFIX: + current_dash = "--"; + break; + case W_PREFIX: + current_dash = "-W "; + break; + default: + current_dash = ""; + break; + } #endif - match = -1; - exact_match = 0; - second_partial_match = 0; + match = -1; + exact_match = 0; + second_partial_match = 0; - optind++; + optind++; - if ((has_equal = strchr(current_argv, '=')) != NULL) { - /* argument found (--option=arg) */ + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ assert(has_equal > current_argv); - current_argv_len = (size_t)(has_equal - current_argv); - has_equal++; - } else - current_argv_len = strlen(current_argv); + current_argv_len = (size_t)(has_equal - current_argv); + has_equal++; + } else + current_argv_len = strlen(current_argv); - for (i = 0; long_options[i].name; i++) { - /* find matching long option */ - if (strncmp(current_argv, long_options[i].name, - current_argv_len)) - continue; + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; - if (strlen(long_options[i].name) == current_argv_len) { - /* exact match */ - match = i; - exact_match = 1; - break; - } - /* - * If this is a known short option, don't allow - * a partial match of a single character. - */ - if (short_too && current_argv_len == 1) - continue; + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + exact_match = 1; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; - if (match == -1) /* first partial match */ - match = i; - else if ((flags & FLAG_LONGONLY) || - long_options[i].has_arg != - long_options[match].has_arg || - long_options[i].flag != long_options[match].flag || - long_options[i].val != long_options[match].val) - second_partial_match = 1; - } - if (!exact_match && second_partial_match) { - /* ambiguous abbreviation */ - if (PRINT_ERROR) - fprintf(stderr, + if (match == -1) /* first partial match */ + match = i; + else if ((flags & FLAG_LONGONLY) || + long_options[i].has_arg != + long_options[match].has_arg || + long_options[i].flag != long_options[match].flag || + long_options[i].val != long_options[match].val) + second_partial_match = 1; + } + if (!exact_match && second_partial_match) { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + fprintf(stderr, ambig, #ifdef GNU_COMPATIBLE - current_dash, + current_dash, #endif - (int)current_argv_len, - current_argv); - optopt = 0; - return (BADCH); - } - if (match != -1) { /* option found */ - if (long_options[match].has_arg == no_argument - && has_equal) { - if (PRINT_ERROR) - warnx(noarg, + (int)current_argv_len, + current_argv); + optopt = 0; + return (BADCH); + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + warnx(noarg, #ifdef GNU_COMPATIBLE - current_dash, + current_dash, #endif - (int)current_argv_len, - current_argv); - /* - * XXX: GNU sets optopt to val regardless of flag - */ - if (long_options[match].flag == NULL) - optopt = long_options[match].val; - else - optopt = 0; + (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; #ifdef GNU_COMPATIBLE - return (BADCH); + return (BADCH); #else - return (BADARG); + return (BADARG); #endif - } - if (long_options[match].has_arg == required_argument || - long_options[match].has_arg == optional_argument) { - if (has_equal) - optarg = has_equal; - else if (long_options[match].has_arg == - required_argument) { - /* - * optional argument doesn't use next nargv - */ - optarg = nargv[optind++]; - } - } - if ((long_options[match].has_arg == required_argument) - && (optarg == NULL)) { - /* - * Missing argument; leading ':' indicates no error - * should be generated. - */ - if (PRINT_ERROR) - warnx(recargstring, + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + warnx(recargstring, #ifdef GNU_COMPATIBLE - current_dash, + current_dash, #endif - current_argv); - /* - * XXX: GNU sets optopt to val regardless of flag - */ - if (long_options[match].flag == NULL) - optopt = long_options[match].val; - else - optopt = 0; - --optind; - return (BADARG); - } - } else { /* unknown option */ - if (short_too) { - --optind; - return (-1); - } - if (PRINT_ERROR) - warnx(illoptstring, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return (BADARG); + } + } else { /* unknown option */ + if (short_too) { + --optind; + return (-1); + } + if (PRINT_ERROR) + warnx(illoptstring, #ifdef GNU_COMPATIBLE - current_dash, + current_dash, #endif - current_argv); - optopt = 0; - return (BADCH); - } - if (idx) - *idx = match; - if (long_options[match].flag) { - *long_options[match].flag = long_options[match].val; - return (0); - } else - return (long_options[match].val); + current_argv); + optopt = 0; + return (BADCH); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else + return (long_options[match].val); } /* * getopt_internal -- - * Parse argc/argv argument vector. Called by user level routines. + * Parse argc/argv argument vector. Called by user level routines. */ static int getopt_internal(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx, int flags) + const struct option *long_options, int *idx, int flags) { - char *oli; /* option letter list index */ - int optchar, short_too; - int posixly_correct; /* no static, can be changed on the fly */ + char *oli; /* option letter list index */ + int optchar, short_too; + int posixly_correct; /* no static, can be changed on the fly */ - if (options == NULL) - return (-1); + if (options == NULL) + return (-1); - /* - * Disable GNU extensions if POSIXLY_CORRECT is set or options - * string begins with a '+'. - */ - posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + */ + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); #ifdef GNU_COMPATIBLE - if (*options == '-') - flags |= FLAG_ALLARGS; - else if (posixly_correct || *options == '+') - flags &= ~FLAG_PERMUTE; + if (*options == '-') + flags |= FLAG_ALLARGS; + else if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; #else - if (posixly_correct || *options == '+') - flags &= ~FLAG_PERMUTE; - else if (*options == '-') - flags |= FLAG_ALLARGS; + if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + else if (*options == '-') + flags |= FLAG_ALLARGS; #endif - if (*options == '+' || *options == '-') - options++; + if (*options == '+' || *options == '-') + options++; - /* - * XXX Some GNU programs (like cvs) set optind to 0 instead of - * XXX using optreset. Work around this braindamage. - */ - if (optind == 0) - optind = optreset = 1; + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (optind == 0) + optind = optreset = 1; - optarg = NULL; - if (optreset) - nonopt_start = nonopt_end = -1; + optarg = NULL; + if (optreset) + nonopt_start = nonopt_end = -1; start: - if (optreset || !*place) { /* update scanning pointer */ - optreset = 0; - if (optind >= nargc) { /* end of argument vector */ - place = emsg; - if (nonopt_end != -1) { - /* do permutation, if we have to */ - permute_args(nonopt_start, nonopt_end, - optind, nargv); - optind -= nonopt_end - nonopt_start; - } - else if (nonopt_start != -1) { - /* - * If we skipped non-options, set optind - * to the first of them. - */ - optind = nonopt_start; - } - nonopt_start = nonopt_end = -1; - return (-1); - } - if (*(place = nargv[optind]) != '-' || + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = emsg; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + if (*(place = nargv[optind]) != '-' || #ifdef GNU_COMPATIBLE - place[1] == '\0') { + place[1] == '\0') { #else - (place[1] == '\0' && strchr(options, '-') == NULL)) { + (place[1] == '\0' && strchr(options, '-') == NULL)) { #endif - place = emsg; /* found non-option */ - if (flags & FLAG_ALLARGS) { - /* - * GNU extension: - * return non-option as argument to option 1 - */ - optarg = nargv[optind++]; - return (INORDER); - } - if (!(flags & FLAG_PERMUTE)) { - /* - * If no permutation wanted, stop parsing - * at first non-option. - */ - return (-1); - } - /* do permutation */ - if (nonopt_start == -1) - nonopt_start = optind; - else if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, - optind, nargv); - nonopt_start = optind - - (nonopt_end - nonopt_start); - nonopt_end = -1; - } - optind++; - /* process next argument */ - goto start; - } - if (nonopt_start != -1 && nonopt_end == -1) - nonopt_end = optind; + place = emsg; /* found non-option */ + if (flags & FLAG_ALLARGS) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return (INORDER); + } + if (!(flags & FLAG_PERMUTE)) { + /* + * If no permutation wanted, stop parsing + * at first non-option. + */ + return (-1); + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; - /* - * If we have "-" do nothing, if "--" we are done. - */ - if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { - optind++; - place = emsg; - /* - * We found an option (--), so if we skipped - * non-options, we have to permute. - */ - if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, - optind, nargv); - optind -= nonopt_end - nonopt_start; - } - nonopt_start = nonopt_end = -1; - return (-1); - } - } + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = emsg; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + } - /* - * Check long options if: - * 1) we were passed some - * 2) the arg is not just "-" - * 3) either the arg starts with -- we are getopt_long_only() - */ - if (long_options != NULL && place != nargv[optind] && - (*place == '-' || (flags & FLAG_LONGONLY))) { - short_too = 0; + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; #ifdef GNU_COMPATIBLE - dash_prefix = D_PREFIX; + dash_prefix = D_PREFIX; #endif - if (*place == '-') { - place++; /* --foo long option */ + if (*place == '-') { + place++; /* --foo long option */ #ifdef GNU_COMPATIBLE - dash_prefix = DD_PREFIX; + dash_prefix = DD_PREFIX; #endif - } else if (*place != ':' && strchr(options, *place) != NULL) - short_too = 1; /* could be short option too */ + } else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ - optchar = parse_long_options(nargv, options, long_options, - idx, short_too, flags); - if (optchar != -1) { - place = emsg; - return (optchar); - } - } + optchar = parse_long_options(nargv, options, long_options, + idx, short_too, flags); + if (optchar != -1) { + place = emsg; + return (optchar); + } + } - if ((optchar = (int)*place++) == (int)':' || - (optchar == (int)'-' && *place != '\0') || - (oli = strchr(options, optchar)) == NULL) { - /* - * If the user specified "-" and '-' isn't listed in - * options, return -1 (non-option) as per POSIX. - * Otherwise, it is an unknown option character (or ':'). - */ - if (optchar == (int)'-' && *place == '\0') - return (-1); - if (!*place) - ++optind; + if ((optchar = (int)*place++) == (int)':' || + (optchar == (int)'-' && *place != '\0') || + (oli = strchr(options, optchar)) == NULL) { + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int)'-' && *place == '\0') + return (-1); + if (!*place) + ++optind; #ifdef GNU_COMPATIBLE - if (PRINT_ERROR) - warnx(posixly_correct ? illoptchar : gnuoptchar, - optchar); + if (PRINT_ERROR) + warnx(posixly_correct ? illoptchar : gnuoptchar, + optchar); #else - if (PRINT_ERROR) - warnx(illoptchar, optchar); + if (PRINT_ERROR) + warnx(illoptchar, optchar); #endif - optopt = optchar; - return (BADCH); - } - if (long_options != NULL && optchar == 'W' && oli[1] == ';') { - /* -W long-option */ - if (*place) /* no space */ - /* NOTHING */; - else if (++optind >= nargc) { /* no arg */ - place = emsg; - if (PRINT_ERROR) - warnx(recargchar, optchar); - optopt = optchar; - return (BADARG); - } else /* white space */ - place = nargv[optind]; + optopt = optchar; + return (BADCH); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ + place = emsg; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else /* white space */ + place = nargv[optind]; #ifdef GNU_COMPATIBLE - dash_prefix = W_PREFIX; + dash_prefix = W_PREFIX; #endif - optchar = parse_long_options(nargv, options, long_options, - idx, 0, flags); - place = emsg; - return (optchar); - } - if (*++oli != ':') { /* doesn't take argument */ - if (!*place) - ++optind; - } else { /* takes (optional) argument */ - optarg = NULL; - if (*place) /* no white space */ - optarg = place; - else if (oli[1] != ':') { /* arg not optional */ - if (++optind >= nargc) { /* no arg */ - place = emsg; - if (PRINT_ERROR) - warnx(recargchar, optchar); - optopt = optchar; - return (BADARG); - } else - optarg = nargv[optind]; - } - place = emsg; - ++optind; - } - /* dump back option letter */ - return (optchar); + optchar = parse_long_options(nargv, options, long_options, + idx, 0, flags); + place = emsg; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = emsg; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else + optarg = nargv[optind]; + } + place = emsg; + ++optind; + } + /* dump back option letter */ + return (optchar); } #ifdef REPLACE_GETOPT /* * getopt -- - * Parse argc/argv argument vector. + * Parse argc/argv argument vector. * * [eventually this will replace the BSD getopt] */ @@ -596,40 +596,40 @@ int getopt(int nargc, char * const *nargv, const char *options) { - /* - * We don't pass FLAG_PERMUTE to getopt_internal() since - * the BSD getopt(3) (unlike GNU) has never done this. - * - * Furthermore, since many privileged programs call getopt() - * before dropping privileges it makes sense to keep things - * as simple (and bug-free) as possible. - */ - return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); + /* + * We don't pass FLAG_PERMUTE to getopt_internal() since + * the BSD getopt(3) (unlike GNU) has never done this. + * + * Furthermore, since many privileged programs call getopt() + * before dropping privileges it makes sense to keep things + * as simple (and bug-free) as possible. + */ + return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); } #endif /* REPLACE_GETOPT */ /* * getopt_long -- - * Parse argc/argv argument vector. + * Parse argc/argv argument vector. */ int getopt_long(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx) + const struct option *long_options, int *idx) { - return (getopt_internal(nargc, nargv, options, long_options, idx, - FLAG_PERMUTE)); + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE)); } /* * getopt_long_only -- - * Parse argc/argv argument vector. + * Parse argc/argv argument vector. */ int getopt_long_only(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx) + const struct option *long_options, int *idx) { - return (getopt_internal(nargc, nargv, options, long_options, idx, - FLAG_PERMUTE|FLAG_LONGONLY)); + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE|FLAG_LONGONLY)); } diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 8c9ab7a40a2..2a2f850963b 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -474,8 +474,8 @@ extern double TraceWorkFactor; END extern Res TraceScanArea(ScanState ss, Word *base, Word *limit, - mps_area_scan_t scan_area, - void *closure, size_t closure_size); + mps_area_scan_t scan_area, + void *closure, size_t closure_size); extern void TraceScanSingleRef(TraceSet ts, Rank rank, Arena arena, Seg seg, Ref *refIO); @@ -948,25 +948,25 @@ extern void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from); /* Root Interface -- see */ extern Res RootCreateArea(Root *rootReturn, Arena arena, - Rank rank, RootMode mode, - Word *base, Word *limit, - mps_area_scan_t scan_area, - void *closure, size_t closure_size); + Rank rank, RootMode mode, + Word *base, Word *limit, + mps_area_scan_t scan_area, + void *closure, size_t closure_size); extern Res RootCreateAreaTagged(Root *rootReturn, Arena arena, - Rank rank, RootMode mode, - Word *base, Word *limit, - mps_area_scan_t scan_area, - Word mask, Word pattern); + Rank rank, RootMode mode, + Word *base, Word *limit, + mps_area_scan_t scan_area, + Word mask, Word pattern); extern Res RootCreateThread(Root *rootReturn, Arena arena, - Rank rank, Thread thread, - mps_area_scan_t scan_area, - void *closure, size_t closure_size, - Word *stackBot); + Rank rank, Thread thread, + mps_area_scan_t scan_area, + void *closure, size_t closure_size, + Word *stackBot); extern Res RootCreateThreadTagged(Root *rootReturn, Arena arena, - Rank rank, Thread thread, - mps_area_scan_t scan_area, - Word mask, Word pattern, - Word *stackBot); + Rank rank, Thread thread, + mps_area_scan_t scan_area, + Word mask, Word pattern, + Word *stackBot); extern Res RootCreateFmt(Root *rootReturn, Arena arena, Rank rank, RootMode mode, mps_fmt_scan_t scan, diff --git a/mps/code/mps.h b/mps/code/mps.h index 0c78d05bb6d..10ca5f01078 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -110,7 +110,7 @@ typedef struct mps_scan_tag_s { typedef mps_res_t (*mps_root_scan_t)(mps_ss_t, void *, size_t); typedef mps_res_t (*mps_area_scan_t)(mps_ss_t, mps_word_t *, mps_word_t *, - void *, size_t); + void *, size_t); typedef mps_res_t (*mps_fmt_scan_t)(mps_ss_t, mps_addr_t, mps_addr_t); typedef mps_res_t (*mps_reg_scan_t)(mps_ss_t, mps_thr_t, void *, size_t); @@ -676,20 +676,20 @@ extern mps_res_t mps_root_create_table(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_addr_t *, size_t); extern mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, - mps_arena_t arena, - mps_rank_t mps_rank, mps_rm_t mps_rm, - mps_addr_t *base, size_t size, - mps_area_scan_t scan_area, - mps_word_t mask, - mps_word_t pattern); + mps_arena_t arena, + mps_rank_t mps_rank, mps_rm_t mps_rm, + mps_addr_t *base, size_t size, + mps_area_scan_t scan_area, + mps_word_t mask, + mps_word_t pattern); extern mps_res_t mps_root_create_table_masked(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_addr_t *, size_t, mps_word_t); extern mps_res_t mps_root_create_area(mps_root_t *, mps_arena_t, - mps_rank_t, mps_rm_t, - mps_word_t *, mps_word_t *, - mps_area_scan_t, void *, size_t); + mps_rank_t, mps_rm_t, + mps_word_t *, mps_word_t *, + mps_area_scan_t, void *, size_t); extern mps_res_t mps_root_create_fmt(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_fmt_scan_t, mps_addr_t, @@ -698,17 +698,17 @@ 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_thread(mps_root_t *, mps_arena_t, - mps_thr_t, void *); + mps_thr_t, void *); extern mps_res_t mps_root_create_thread_scanned(mps_root_t *, mps_arena_t, - mps_rank_t, mps_rm_t, mps_thr_t, - mps_area_scan_t, - void *, size_t, - void *); + mps_rank_t, mps_rm_t, mps_thr_t, + mps_area_scan_t, + void *, size_t, + void *); extern mps_res_t mps_root_create_thread_tagged(mps_root_t *, mps_arena_t, - mps_rank_t, mps_rm_t, mps_thr_t, - mps_area_scan_t, - mps_word_t, mps_word_t, - void *); + mps_rank_t, mps_rm_t, mps_thr_t, + mps_area_scan_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, @@ -823,17 +823,17 @@ extern void mps_pool_check_free_space(mps_pool_t); /* Scanner Support */ extern mps_res_t mps_scan_area(mps_ss_t, - mps_word_t *, mps_word_t *, - void *, size_t); + mps_word_t *, mps_word_t *, + void *, size_t); extern mps_res_t mps_scan_area_masked(mps_ss_t, - mps_word_t *, mps_word_t *, - void *, size_t); + mps_word_t *, mps_word_t *, + void *, size_t); extern mps_res_t mps_scan_area_tagged(mps_ss_t, - mps_word_t *, mps_word_t *, - void *, size_t); + mps_word_t *, mps_word_t *, + void *, size_t); extern mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t, - mps_word_t *, mps_word_t *, - void *, size_t); + mps_word_t *, mps_word_t *, + void *, size_t); extern mps_res_t mps_fix(mps_ss_t, mps_addr_t *); diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index da2572cc98e..a7fa2857180 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1301,8 +1301,8 @@ mps_res_t mps_root_create_table(mps_root_t *mps_root_o, mps_arena_t arena, void *. */ res = RootCreateArea(&root, arena, rank, mode, - (void *)base, (void *)(base + size), - mps_scan_area, NULL, 0); + (void *)base, (void *)(base + size), + mps_scan_area, NULL, 0); ArenaLeave(arena); @@ -1313,11 +1313,11 @@ mps_res_t mps_root_create_table(mps_root_t *mps_root_o, mps_arena_t arena, } mps_res_t mps_root_create_area(mps_root_t *mps_root_o, - mps_arena_t arena, - mps_rank_t mps_rank, mps_rm_t mps_rm, - mps_word_t *base, mps_word_t *limit, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_arena_t arena, + mps_rank_t mps_rank, mps_rm_t mps_rm, + mps_word_t *base, mps_word_t *limit, + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { Rank rank = (Rank)mps_rank; Root root; @@ -1334,8 +1334,8 @@ mps_res_t mps_root_create_area(mps_root_t *mps_root_o, /* Can't check anything about closure */ res = RootCreateArea(&root, arena, rank, mode, - base, limit, - scan_area, closure, closure_size); + base, limit, + scan_area, closure, closure_size); ArenaLeave(arena); @@ -1349,9 +1349,9 @@ mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, mps_arena_t arena, mps_rank_t mps_rank, mps_rm_t mps_rm, mps_addr_t *base, size_t size, - mps_area_scan_t scan_area, + mps_area_scan_t scan_area, mps_word_t mask, - mps_word_t pattern) + mps_word_t pattern) { Rank rank = (Rank)mps_rank; Root root; @@ -1369,8 +1369,8 @@ mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, /* .root.table-size */ res = RootCreateAreaTagged(&root, arena, rank, mode, - (void *)base, (void *)(base + size), - scan_area, mask, pattern); + (void *)base, (void *)(base + size), + scan_area, mask, pattern); ArenaLeave(arena); @@ -1387,8 +1387,8 @@ mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, mps_word_t mask) { return mps_root_create_table_tagged(mps_root_o, arena, mps_rank, mps_rm, - base, size, mps_scan_area_tagged, - mask, 0); + base, size, mps_scan_area_tagged, + mask, 0); } mps_res_t mps_root_create_fmt(mps_root_t *mps_root_o, mps_arena_t arena, @@ -1437,9 +1437,9 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena, /* See .root-mode. */ res = RootCreateThreadTagged(&root, arena, rank, thread, - mps_scan_area_tagged, - sizeof(mps_word_t) - 1, 0, - (Word *)stack); + mps_scan_area_tagged, + sizeof(mps_word_t) - 1, 0, + (Word *)stack); ArenaLeave(arena); @@ -1451,31 +1451,31 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena, mps_res_t mps_root_create_thread(mps_root_t *mps_root_o, - mps_arena_t arena, - mps_thr_t thread, - void *stack) + mps_arena_t arena, + mps_thr_t thread, + void *stack) { return mps_root_create_thread_tagged(mps_root_o, - arena, - mps_rank_ambig(), - (mps_rm_t)0, - thread, - mps_scan_area_tagged, - sizeof(mps_word_t) - 1, - 0, - stack); + arena, + mps_rank_ambig(), + (mps_rm_t)0, + thread, + mps_scan_area_tagged, + sizeof(mps_word_t) - 1, + 0, + stack); } mps_res_t mps_root_create_thread_scanned(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_area_scan_t scan_area, - void *closure, - size_t closure_size, - void *stack) + mps_arena_t arena, + mps_rank_t mps_rank, + mps_rm_t mps_rm, + mps_thr_t thread, + mps_area_scan_t scan_area, + void *closure, + size_t closure_size, + void *stack) { Rank rank = (Rank)mps_rank; Root root; @@ -1493,8 +1493,8 @@ mps_res_t mps_root_create_thread_scanned(mps_root_t *mps_root_o, /* See .root-mode. */ res = RootCreateThread(&root, arena, rank, thread, - scan_area, closure, closure_size, - (Word *)stack); + scan_area, closure, closure_size, + (Word *)stack); ArenaLeave(arena); @@ -1506,14 +1506,14 @@ mps_res_t mps_root_create_thread_scanned(mps_root_t *mps_root_o, mps_res_t mps_root_create_thread_tagged(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_area_scan_t scan_area, - mps_word_t mask, - mps_word_t pattern, - void *stack) + mps_arena_t arena, + mps_rank_t mps_rank, + mps_rm_t mps_rm, + mps_thr_t thread, + mps_area_scan_t scan_area, + mps_word_t mask, + mps_word_t pattern, + void *stack) { Rank rank = (Rank)mps_rank; Root root; @@ -1531,8 +1531,8 @@ mps_res_t mps_root_create_thread_tagged(mps_root_t *mps_root_o, /* See .root-mode. */ res = RootCreateThreadTagged(&root, arena, rank, thread, - scan_area, mask, pattern, - (Word *)stack); + scan_area, mask, pattern, + (Word *)stack); ArenaLeave(arena); diff --git a/mps/code/prmci3fr.c b/mps/code/prmci3fr.c index ffbe4dc3e7d..d9f989db17c 100644 --- a/mps/code/prmci3fr.c +++ b/mps/code/prmci3fr.c @@ -39,8 +39,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { Res res; diff --git a/mps/code/prmci3li.c b/mps/code/prmci3li.c index 635676832d8..419f83f8b4a 100644 --- a/mps/code/prmci3li.c +++ b/mps/code/prmci3li.c @@ -102,8 +102,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { mcontext_t *mc; Res res; @@ -113,9 +113,9 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, to scan only relevant parts would be machine dependent. */ mc = &mfc->ucontext->uc_mcontext; res = TraceScanArea(ss, - (Word *)mc, - (Word *)((char *)mc + sizeof(*mc)), - scan_area, closure, closure_size); + (Word *)mc, + (Word *)((char *)mc + sizeof(*mc)), + scan_area, closure, closure_size); return res; } diff --git a/mps/code/prmci3xc.c b/mps/code/prmci3xc.c index b133656f3b1..abeef4988c4 100644 --- a/mps/code/prmci3xc.c +++ b/mps/code/prmci3xc.c @@ -97,8 +97,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { x86_thread_state32_t *mc; Res res; @@ -108,9 +108,9 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, to scan only relevant parts would be machine dependent. */ mc = mfc->threadState; res = TraceScanArea(ss, - (Word *)mc, - (Word *)((char *)mc + sizeof(*mc)), - scan_area, closure, closure_size); + (Word *)mc, + (Word *)((char *)mc + sizeof(*mc)), + scan_area, closure, closure_size); return res; } diff --git a/mps/code/prmci6fr.c b/mps/code/prmci6fr.c index 8dd2a680f6e..d8676d2a4c3 100644 --- a/mps/code/prmci6fr.c +++ b/mps/code/prmci6fr.c @@ -33,8 +33,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { Res res; diff --git a/mps/code/prmci6li.c b/mps/code/prmci6li.c index ef4f0c000cc..fe7cb96627a 100644 --- a/mps/code/prmci6li.c +++ b/mps/code/prmci6li.c @@ -106,8 +106,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { mcontext_t *mc; Res res; @@ -117,9 +117,9 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, to scan only relevant parts would be machine dependent. */ mc = &mfc->ucontext->uc_mcontext; res = TraceScanArea(ss, - (Word *)mc, - (Word *)((char *)mc + sizeof(*mc)), - scan_area, closure, closure_size); + (Word *)mc, + (Word *)((char *)mc + sizeof(*mc)), + scan_area, closure, closure_size); return res; } diff --git a/mps/code/prmci6xc.c b/mps/code/prmci6xc.c index bbea768ceee..69591a321ab 100644 --- a/mps/code/prmci6xc.c +++ b/mps/code/prmci6xc.c @@ -100,8 +100,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { x86_thread_state64_t *mc; Res res; @@ -111,9 +111,9 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, to scan only relevant parts would be machine dependent. */ mc = mfc->threadState; res = TraceScanArea(ss, - (Word *)mc, - (Word *)((char *)mc + sizeof(*mc)), - scan_area, closure, closure_size); + (Word *)mc, + (Word *)((char *)mc + sizeof(*mc)), + scan_area, closure, closure_size); return res; } diff --git a/mps/code/prot.h b/mps/code/prot.h index 0a5583d7349..c2ae9d20e69 100644 --- a/mps/code/prot.h +++ b/mps/code/prot.h @@ -31,8 +31,8 @@ extern Bool ProtCanStepInstruction(MutatorFaultContext context); extern Res ProtStepInstruction(MutatorFaultContext context); extern Addr MutatorFaultContextSP(MutatorFaultContext mfc); extern Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, - mps_area_scan_t scan, - void *closure, size_t closure_size); + mps_area_scan_t scan, + void *closure, size_t closure_size); #endif /* prot_h */ diff --git a/mps/code/root.c b/mps/code/root.c index c08fb79274f..0a73c5c190c 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -266,10 +266,10 @@ static Res rootCreateProtectable(Root *rootReturn, Arena arena, } Res RootCreateArea(Root *rootReturn, Arena arena, - Rank rank, RootMode mode, - Word *base, Word *limit, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + Rank rank, RootMode mode, + Word *base, Word *limit, + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { Res res; union RootUnion theUnion; @@ -297,7 +297,7 @@ Res RootCreateArea(Root *rootReturn, Arena arena, Res RootCreateAreaTagged(Root *rootReturn, Arena arena, Rank rank, RootMode mode, Word *base, Word *limit, - mps_area_scan_t scan_area, Word mask, Word pattern) + mps_area_scan_t scan_area, Word mask, Word pattern) { union RootUnion theUnion; @@ -320,10 +320,10 @@ Res RootCreateAreaTagged(Root *rootReturn, Arena arena, } Res RootCreateThread(Root *rootReturn, Arena arena, - Rank rank, Thread thread, - mps_area_scan_t scan_area, - void *closure, size_t closure_size, - Word *stackBot) + Rank rank, Thread thread, + mps_area_scan_t scan_area, + void *closure, size_t closure_size, + Word *stackBot) { union RootUnion theUnion; @@ -346,10 +346,10 @@ Res RootCreateThread(Root *rootReturn, Arena arena, } Res RootCreateThreadTagged(Root *rootReturn, Arena arena, - Rank rank, Thread thread, - mps_area_scan_t scan_area, - Word mask, Word pattern, - Word *stackBot) + Rank rank, Thread thread, + mps_area_scan_t scan_area, + Word mask, Word pattern, + Word *stackBot) { union RootUnion theUnion; @@ -526,11 +526,11 @@ Res RootScan(ScanState ss, Root root) switch(root->var) { case RootAREA: res = TraceScanArea(ss, - root->the.area.base, - root->the.area.limit, - root->the.area.scan_area, - root->the.area.the.closure.p, - root->the.area.the.closure.s); + root->the.area.base, + root->the.area.limit, + root->the.area.scan_area, + root->the.area.the.closure.p, + root->the.area.the.closure.s); ss->scannedSize += AddrOffset(root->the.area.base, root->the.area.limit); if (res != ResOK) goto failScan; @@ -538,11 +538,11 @@ Res RootScan(ScanState ss, Root root) case RootAREA_TAGGED: res = TraceScanArea(ss, - root->the.area.base, - root->the.area.limit, - root->the.area.scan_area, - &root->the.area.the.tag, - sizeof(root->the.area.the.tag)); + root->the.area.base, + root->the.area.limit, + root->the.area.scan_area, + &root->the.area.the.tag, + sizeof(root->the.area.the.tag)); ss->scannedSize += AddrOffset(root->the.area.base, root->the.area.limit); if (res != ResOK) goto failScan; @@ -557,9 +557,9 @@ Res RootScan(ScanState ss, Root root) case RootTHREAD: res = ThreadScan(ss, root->the.thread.thread, root->the.thread.stackBot, - root->the.thread.scan_area, - root->the.thread.the.closure.p, - root->the.thread.the.closure.s); + root->the.thread.scan_area, + root->the.thread.the.closure.p, + root->the.thread.the.closure.s); if (res != ResOK) goto failScan; break; @@ -567,9 +567,9 @@ Res RootScan(ScanState ss, Root root) case RootTHREAD_TAGGED: res = ThreadScan(ss, root->the.thread.thread, root->the.thread.stackBot, - root->the.thread.scan_area, - &root->the.thread.the.tag, - sizeof(root->the.thread.the.tag)); + root->the.thread.scan_area, + &root->the.thread.the.tag, + sizeof(root->the.thread.the.tag)); if (res != ResOK) goto failScan; break; @@ -703,8 +703,8 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) "area base $A limit $A scan_area closure $P closure_size $U\n", (WriteFA)root->the.area.base, (WriteFA)root->the.area.limit, - (WriteFP)root->the.area.the.closure.p, - (WriteFP)root->the.area.the.closure.s, + (WriteFP)root->the.area.the.closure.p, + (WriteFP)root->the.area.the.closure.s, NULL); if (res != ResOK) return res; @@ -716,7 +716,7 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) (WriteFA)root->the.area.base, (WriteFA)root->the.area.limit, (WriteFB)root->the.area.the.tag.mask, - (WriteFB)root->the.area.the.tag.pattern, + (WriteFB)root->the.area.the.tag.pattern, NULL); if (res != ResOK) return res; @@ -735,10 +735,10 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) case RootTHREAD: res = WriteF(stream, depth + 2, "thread $P\n", (WriteFP)root->the.thread.thread, - "closure $P size $U\n", - (WriteFP)root->the.thread.the.closure.p, - (WriteFU)root->the.thread.the.closure.s, - "stackBot $P\n", (WriteFP)root->the.thread.stackBot, + "closure $P size $U\n", + (WriteFP)root->the.thread.the.closure.p, + (WriteFU)root->the.thread.the.closure.s, + "stackBot $P\n", (WriteFP)root->the.thread.stackBot, NULL); if (res != ResOK) return res; @@ -747,9 +747,9 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) case RootTHREAD_TAGGED: res = WriteF(stream, depth + 2, "thread $P\n", (WriteFP)root->the.thread.thread, - "mask $B\n", (WriteFB)root->the.thread.the.tag.mask, - "pattern $B\n", (WriteFB)root->the.thread.the.tag.pattern, - "stackBot $P\n", (WriteFP)root->the.thread.stackBot, + "mask $B\n", (WriteFB)root->the.thread.the.tag.mask, + "pattern $B\n", (WriteFB)root->the.thread.the.tag.pattern, + "stackBot $P\n", (WriteFP)root->the.thread.stackBot, NULL); if (res != ResOK) return res; diff --git a/mps/code/ss.c b/mps/code/ss.c index 40f367400ed..3d0d68ee34b 100644 --- a/mps/code/ss.c +++ b/mps/code/ss.c @@ -26,8 +26,8 @@ SRCID(ss, "$Id$"); Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop, Count nSavedRegs, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { Arena arena; Res res; @@ -50,16 +50,16 @@ Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop, AVER(stackTop < arena->stackAtArenaEnter); AVER(arena->stackAtArenaEnter < stackBot); res = TraceScanArea(ss, stackTop, stackTop + nSavedRegs, - scan_area, closure, closure_size); + scan_area, closure, closure_size); if (res != ResOK) return res; res = TraceScanArea(ss, arena->stackAtArenaEnter, stackBot, - scan_area, closure, closure_size); + scan_area, closure, closure_size); if (res != ResOK) return res; } else { res = TraceScanArea(ss, stackTop, stackBot, - scan_area, closure, closure_size); + scan_area, closure, closure_size); if (res != ResOK) return res; } diff --git a/mps/code/ss.h b/mps/code/ss.h index bac9c3d1110..b186535edf2 100644 --- a/mps/code/ss.h +++ b/mps/code/ss.h @@ -33,11 +33,11 @@ */ extern Res StackScan(ScanState ss, Word *stackBot, - mps_area_scan_t scan_area, - void *closure, size_t closure_size); + mps_area_scan_t scan_area, + void *closure, size_t closure_size); extern Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop, Count nSavedRegs, mps_area_scan_t scan_area, - void *closure, size_t closure_s); + void *closure, size_t closure_s); #endif /* ss_h */ diff --git a/mps/code/ssan.c b/mps/code/ssan.c index 8414b3a1157..3011eba756f 100644 --- a/mps/code/ssan.c +++ b/mps/code/ssan.c @@ -22,8 +22,8 @@ SRCID(ssan, "$Id$"); Res StackScan(ScanState ss, Word *stackBot, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { jmp_buf jb; Word *stackTop = (Word *)&jb; @@ -38,7 +38,7 @@ Res StackScan(ScanState ss, Word *stackBot, (void)setjmp(jb); return StackScanInner(ss, stackBot, stackTop, sizeof jb / sizeof(Word), - scan_area, closure, closure_size); + scan_area, closure, closure_size); } diff --git a/mps/code/ssixi3.c b/mps/code/ssixi3.c index 34d457944d0..d3273d4e674 100644 --- a/mps/code/ssixi3.c +++ b/mps/code/ssixi3.c @@ -50,8 +50,8 @@ SRCID(ssixi3, "$Id$"); Res StackScan(ScanState ss, Word *stackBot, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { Word calleeSaveRegs[4]; @@ -65,7 +65,7 @@ Res StackScan(ScanState ss, Word *stackBot, ASMV("mov %%ebp, %0" : "=m" (calleeSaveRegs[3])); return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs), - scan_area, closure, closure_size); + scan_area, closure, closure_size); } diff --git a/mps/code/ssixi6.c b/mps/code/ssixi6.c index 1142606980d..ee07136dfad 100644 --- a/mps/code/ssixi6.c +++ b/mps/code/ssixi6.c @@ -48,8 +48,8 @@ SRCID(ssixi6, "$Id$"); Res StackScan(ScanState ss, Word *stackBot, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { Word calleeSaveRegs[6]; @@ -65,7 +65,7 @@ Res StackScan(ScanState ss, Word *stackBot, ASMV("mov %%r15, %0" : "=m" (calleeSaveRegs[5])); return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs), - scan_area, closure, closure_size); + scan_area, closure, closure_size); } diff --git a/mps/code/ssw3i3mv.c b/mps/code/ssw3i3mv.c index c5a1aa15620..cbc63da3e0e 100644 --- a/mps/code/ssw3i3mv.c +++ b/mps/code/ssw3i3mv.c @@ -23,8 +23,8 @@ SRCID(ssw3i3mv, "$Id$"); Res StackScan(ScanState ss, Word *stackBot, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { jmp_buf jb; @@ -45,7 +45,7 @@ Res StackScan(ScanState ss, Word *stackBot, AVER(offsetof(_JUMP_BUFFER, Esi) == offsetof(_JUMP_BUFFER, Ebx) + 8); return StackScanInner(ss, stackBot, (Word *)&((_JUMP_BUFFER *)jb)->Ebx, 3, - scan_area, closure, closure_size); + scan_area, closure, closure_size); } /* C. COPYRIGHT AND LICENSE diff --git a/mps/code/ssw3i3pc.c b/mps/code/ssw3i3pc.c index bb84b199618..4e75dac247c 100644 --- a/mps/code/ssw3i3pc.c +++ b/mps/code/ssw3i3pc.c @@ -47,8 +47,8 @@ typedef struct __JUMP_BUFFER { Res StackScan(ScanState ss, Word *stackBot, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { jmp_buf jb; @@ -68,7 +68,7 @@ Res StackScan(ScanState ss, Word *stackBot, AVER(offsetof(_JUMP_BUFFER, Esi) == offsetof(_JUMP_BUFFER, Ebx) + 8); return StackScanInner(ss, stackBot, (Word *)&((_JUMP_BUFFER *)jb)->Ebx, 3, - scan_area, closure, closure_size); + scan_area, closure, closure_size); } diff --git a/mps/code/ssw3i6mv.c b/mps/code/ssw3i6mv.c index a146e28d22f..f3b140b8065 100644 --- a/mps/code/ssw3i6mv.c +++ b/mps/code/ssw3i6mv.c @@ -31,8 +31,8 @@ SRCID(ssw3i6mv, "$Id$"); Res StackScan(ScanState ss, Word *stackBot, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { jmp_buf jb; @@ -64,7 +64,7 @@ Res StackScan(ScanState ss, Word *stackBot, AVER(offsetof(_JUMP_BUFFER, R15) == offsetof(_JUMP_BUFFER, Rbx) + 64); return StackScanInner(ss, stackBot, (Word *)&((_JUMP_BUFFER *)jb)->Rbx, 9, - scan_area, closure, closure_size); + scan_area, closure, closure_size); } /* C. COPYRIGHT AND LICENSE diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c index d1f78cc957f..d1f96e00c18 100644 --- a/mps/code/tagtest.c +++ b/mps/code/tagtest.c @@ -170,17 +170,17 @@ static void test(int mode) case MODE_CONS: /* Scan words tagged "cons" -- everything will live. */ die(mps_root_create_table_tagged(&root, arena, mps_rank_ambig(), 0, - refs, OBJCOUNT, - mps_scan_area_tagged, TAG_MASK, tag_cons), - "root"); + refs, OBJCOUNT, + mps_scan_area_tagged, TAG_MASK, tag_cons), + "root"); expected = 0; break; case MODE_INVALID: /* Scan words tagged "invalid" -- everything will die. */ die(mps_root_create_table_tagged(&root, arena, mps_rank_ambig(), 0, - refs, OBJCOUNT, - mps_scan_area_tagged, TAG_MASK, tag_invalid), - "root"); + refs, OBJCOUNT, + mps_scan_area_tagged, TAG_MASK, tag_invalid), + "root"); expected = OBJCOUNT; break; } diff --git a/mps/code/th.h b/mps/code/th.h index 03e57bf3bac..65064ecaafa 100644 --- a/mps/code/th.h +++ b/mps/code/th.h @@ -69,8 +69,8 @@ extern Thread ThreadRingThread(Ring threadRing); extern Arena ThreadArena(Thread thread); extern Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, - mps_area_scan_t scan_area, - void *closure, size_t closure_size); + mps_area_scan_t scan_area, + void *closure, size_t closure_size); #endif /* th_h */ diff --git a/mps/code/than.c b/mps/code/than.c index 44c3b48bd60..63a6b8628a3 100644 --- a/mps/code/than.c +++ b/mps/code/than.c @@ -118,8 +118,8 @@ Arena ThreadArena(Thread thread) Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { UNUSED(thread); return StackScan(ss, stackBot, scan_area, closure, closure_size); diff --git a/mps/code/thix.c b/mps/code/thix.c index 8d3bfe28a5f..28403d9cae5 100644 --- a/mps/code/thix.c +++ b/mps/code/thix.c @@ -240,8 +240,8 @@ Arena ThreadArena(Thread thread) /* ThreadScan -- scan the state of a thread (stack and regs) */ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { pthread_t self; Res res; @@ -273,7 +273,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, * stackBot (.stack.full-descend) */ res = TraceScanArea(ss, stackBase, stackLimit, - scan_area, closure, closure_size); + scan_area, closure, closure_size); if(res != ResOK) return res; diff --git a/mps/code/thw3i3.c b/mps/code/thw3i3.c index cbe971f3e2a..e7faa370b77 100644 --- a/mps/code/thw3i3.c +++ b/mps/code/thw3i3.c @@ -68,8 +68,8 @@ SRCID(thw3i3, "$Id$"); Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { DWORD id; Res res; @@ -107,7 +107,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, * stackBot (.stack.full-descend) */ res = TraceScanArea(ss, stackBase, stackLimit, - scan_area, closure, closure_size); + scan_area, closure, closure_size); if(res != ResOK) return res; @@ -117,8 +117,8 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, * to scan only relevant parts would be machine dependent. */ res = TraceScanArea(ss, (Word *)&context, - (Word *)((char *)&context + sizeof(CONTEXT)), - scan_area, closure, closure_size); + (Word *)((char *)&context + sizeof(CONTEXT)), + scan_area, closure, closure_size); if(res != ResOK) return res; diff --git a/mps/code/thw3i6.c b/mps/code/thw3i6.c index d1f94f37f0e..f84063013e7 100644 --- a/mps/code/thw3i6.c +++ b/mps/code/thw3i6.c @@ -69,7 +69,7 @@ SRCID(thw3i6, "$Id$"); Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure, size_t closure_size) { DWORD id; Res res; @@ -107,7 +107,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, * stackBot (.stack.full-descend) */ res = TraceScanArea(ss, stackBase, stackLimit, - scan_area, closure, closure_size); + scan_area, closure, closure_size); if(res != ResOK) return res; @@ -117,8 +117,8 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, * to scan only relevant parts would be machine dependent. */ res = TraceScanArea(ss, (Word *)&context, - (Word *)((char *)&context + sizeof(CONTEXT)), - scan_area, closure, closure_size); + (Word *)((char *)&context + sizeof(CONTEXT)), + scan_area, closure, closure_size); if(res != ResOK) return res; diff --git a/mps/code/thxc.c b/mps/code/thxc.c index 26a3db2c845..25bb37e706d 100644 --- a/mps/code/thxc.c +++ b/mps/code/thxc.c @@ -211,8 +211,8 @@ Arena ThreadArena(Thread thread) #include "prmcxc.h" Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { mach_port_t self; Res res; @@ -261,7 +261,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, * stackBot (.stack.full-descend) */ res = TraceScanArea(ss, stackBase, stackLimit, - scan_area, closure, closure_size); + scan_area, closure, closure_size); if(res != ResOK) return res; diff --git a/mps/code/trace.c b/mps/code/trace.c index bee5e64b2ac..458106800db 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1427,8 +1427,8 @@ void TraceScanSingleRef(TraceSet ts, Rank rank, Arena arena, * limit, inclusive of base and exclusive of limit. */ Res TraceScanArea(ScanState ss, Word *base, Word *limit, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, + void *closure, size_t closure_size) { AVERT(ScanState, ss); AVER(base != NULL); diff --git a/mps/code/zcoll.c b/mps/code/zcoll.c index 6c921090317..459f87595f5 100644 --- a/mps/code/zcoll.c +++ b/mps/code/zcoll.c @@ -575,7 +575,7 @@ static void StackScan(mps_arena_t arena, int on) if(on) { Insist(root_stackreg == NULL); die(mps_root_create_thread(&root_stackreg, arena, - stack_thr, stack_start), + stack_thr, stack_start), "root_stackreg"); Insist(root_stackreg != NULL); } else { @@ -762,7 +762,7 @@ static void *testscriptB(void *arg, size_t s) stack_start = &stack_starts_here; stack_thr = thr; die(mps_root_create_thread(&root_stackreg, arena, - stack_thr, stack_start), + stack_thr, stack_start), "root_stackreg"); diff --git a/mps/code/zmess.c b/mps/code/zmess.c index 505de361200..afa6c0b128d 100644 --- a/mps/code/zmess.c +++ b/mps/code/zmess.c @@ -331,7 +331,7 @@ static void *testscriptB(void *arg, size_t s) /* root_stackreg: stack & registers are ambiguous roots = mutator's workspace */ die(mps_root_create_thread(&root_stackreg, arena, - thr, &stack_starts_here), + thr, &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 aaf16824498..81587327d9e 100644 --- a/mps/example/scheme/scheme-advanced.c +++ b/mps/example/scheme/scheme-advanced.c @@ -53,17 +53,17 @@ /* LANGUAGE EXTENSION */ -#define unless(c) if(!(c)) -#define LENGTH(array) (sizeof(array) / sizeof(array[0])) +#define unless(c) if(!(c)) +#define LENGTH(array) (sizeof(array) / sizeof(array[0])) #define UNUSED(var) ((void)var) /* CONFIGURATION PARAMETERS */ -#define SYMMAX ((size_t)255) /* max length of a symbol */ -#define MSGMAX ((size_t)255) /* max length of error message */ -#define STRMAX ((size_t)255) /* max length of a string */ +#define SYMMAX ((size_t)255) /* max length of a symbol */ +#define MSGMAX ((size_t)255) /* max length of error message */ +#define STRMAX ((size_t)255) /* max length of a string */ /* DATA TYPES */ @@ -116,54 +116,54 @@ typedef struct type_s { } type_s; typedef struct pair_s { - type_t type; /* TYPE_PAIR */ - obj_t car, cdr; /* first and second projections */ + type_t type; /* TYPE_PAIR */ + obj_t car, cdr; /* first and second projections */ } pair_s; typedef struct symbol_s { - type_t type; /* TYPE_SYMBOL */ + type_t type; /* TYPE_SYMBOL */ obj_t name; /* its name (a string) */ } symbol_s; typedef struct integer_s { - type_t type; /* TYPE_INTEGER */ - long integer; /* the integer */ + type_t type; /* TYPE_INTEGER */ + long integer; /* the integer */ } integer_s; typedef struct special_s { - type_t type; /* TYPE_SPECIAL */ - const char *name; /* printed representation, NUL terminated */ + type_t type; /* TYPE_SPECIAL */ + const char *name; /* printed representation, NUL terminated */ } special_s; typedef struct operator_s { - type_t type; /* TYPE_OPERATOR */ - const char *name; /* printed name, NUL terminated */ - entry_t entry; /* entry point -- see eval() */ - obj_t arguments, body; /* function arguments and code */ - obj_t env, op_env; /* closure environments */ + type_t type; /* TYPE_OPERATOR */ + const char *name; /* printed name, NUL terminated */ + entry_t entry; /* entry point -- see eval() */ + obj_t arguments, body; /* function arguments and code */ + obj_t env, op_env; /* closure environments */ } operator_s; typedef struct string_s { - type_t type; /* TYPE_STRING */ - size_t length; /* number of chars in string */ - char string[1]; /* string, NUL terminated */ + type_t type; /* TYPE_STRING */ + size_t length; /* number of chars in string */ + char string[1]; /* string, NUL terminated */ } string_s; typedef struct port_s { - type_t type; /* TYPE_PORT */ - obj_t name; /* name of stream */ + type_t type; /* TYPE_PORT */ + obj_t name; /* name of stream */ FILE *stream; } port_s; typedef struct character_s { - type_t type; /* TYPE_CHARACTER */ - char c; /* the character */ + type_t type; /* TYPE_CHARACTER */ + char c; /* the character */ } character_s; typedef struct vector_s { - type_t type; /* TYPE_VECTOR */ - size_t length; /* number of elements */ - obj_t vector[1]; /* vector elements */ + type_t type; /* TYPE_VECTOR */ + size_t length; /* number of elements */ + obj_t vector[1]; /* vector elements */ } vector_s; /* %%MPS: Objects in AWL pools must be formatted so that aligned @@ -241,7 +241,7 @@ typedef struct pad_s { typedef union obj_u { - type_s type; /* one of TYPE_* */ + type_s type; /* one of TYPE_* */ pair_s pair; symbol_s symbol; integer_s integer; @@ -260,17 +260,17 @@ typedef union obj_u { /* structure macros */ -#define TYPE(obj) ((obj)->type.type) -#define CAR(obj) ((obj)->pair.car) -#define CDR(obj) ((obj)->pair.cdr) -#define CAAR(obj) CAR(CAR(obj)) -#define CADR(obj) CAR(CDR(obj)) -#define CDAR(obj) CDR(CAR(obj)) -#define CDDR(obj) CDR(CDR(obj)) -#define CADDR(obj) CAR(CDDR(obj)) -#define CDDDR(obj) CDR(CDDR(obj)) -#define CDDAR(obj) CDR(CDAR(obj)) -#define CADAR(obj) CAR(CDAR(obj)) +#define TYPE(obj) ((obj)->type.type) +#define CAR(obj) ((obj)->pair.car) +#define CDR(obj) ((obj)->pair.cdr) +#define CAAR(obj) CAR(CAR(obj)) +#define CADR(obj) CAR(CDR(obj)) +#define CDAR(obj) CDR(CAR(obj)) +#define CDDR(obj) CDR(CDR(obj)) +#define CADDR(obj) CAR(CDDR(obj)) +#define CDDDR(obj) CDR(CDDR(obj)) +#define CDDAR(obj) CDR(CDAR(obj)) +#define CADAR(obj) CAR(CDAR(obj)) /* GLOBAL DATA */ @@ -305,12 +305,12 @@ static mps_root_t symtab_root; * See `globals_scan`. */ -static obj_t obj_empty; /* (), the empty list */ -static obj_t obj_eof; /* end of file */ -static obj_t obj_error; /* error indicator */ -static obj_t obj_true; /* #t, boolean true */ -static obj_t obj_false; /* #f, boolean false */ -static obj_t obj_undefined; /* undefined result indicator */ +static obj_t obj_empty; /* (), the empty list */ +static obj_t obj_eof; /* end of file */ +static obj_t obj_error; /* error indicator */ +static obj_t obj_true; /* #t, boolean true */ +static obj_t obj_false; /* #f, boolean false */ +static obj_t obj_undefined; /* undefined result indicator */ static obj_t obj_tail; /* tail recursion indicator */ static obj_t obj_deleted; /* deleted key in hashtable */ static obj_t obj_unused; /* unused entry in hashtable */ @@ -323,13 +323,13 @@ static obj_t obj_unused; /* unused entry in hashtable */ * Scheme language, and are used by the evaluator to parse code. */ -static obj_t obj_quote; /* "quote" symbol */ -static obj_t obj_quasiquote; /* "quasiquote" symbol */ -static obj_t obj_lambda; /* "lambda" symbol */ -static obj_t obj_begin; /* "begin" symbol */ -static obj_t obj_else; /* "else" symbol */ -static obj_t obj_unquote; /* "unquote" symbol */ -static obj_t obj_unquote_splic; /* "unquote-splicing" symbol */ +static obj_t obj_quote; /* "quote" symbol */ +static obj_t obj_quasiquote; /* "quasiquote" symbol */ +static obj_t obj_lambda; /* "lambda" symbol */ +static obj_t obj_begin; /* "begin" symbol */ +static obj_t obj_else; /* "else" symbol */ +static obj_t obj_unquote; /* "unquote" symbol */ +static obj_t obj_unquote_splic; /* "unquote-splicing" symbol */ /* error handler @@ -1322,13 +1322,13 @@ static obj_t read_special(FILE *stream, int c) switch(tolower(c)) { case 't': return obj_true; case 'f': return obj_false; - case '\\': { /* character (R4RS 6.6) */ + case '\\': { /* character (R4RS 6.6) */ c = getc(stream); if(c == EOF) error("read: end of file reading character literal"); return make_character((char)c); } - case '(': { /* vector (R4RS 6.8) */ + case '(': { /* vector (R4RS 6.8) */ obj_t list = read_list(stream, c); obj_t vector = list_to_vector(list); if(vector == obj_error) @@ -1429,7 +1429,7 @@ static obj_t lookup(obj_t env, obj_t symbol) static void define(obj_t env, obj_t symbol, obj_t value) { obj_t binding; - assert(TYPE(env) == TYPE_PAIR); /* always at least one frame */ + assert(TYPE(env) == TYPE_PAIR); /* always at least one frame */ binding = lookup_in_frame(CAR(env), symbol); if(binding != obj_undefined) CDR(binding) = value; @@ -1848,7 +1848,7 @@ static obj_t entry_let(obj_t env, obj_t op_env, obj_t operator, obj_t operands) unless(TYPE(operands) == TYPE_PAIR && TYPE(CDR(operands)) == TYPE_PAIR) error("%s: illegal syntax", operator->operator.name); - inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ + inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ bindings = CAR(operands); while(TYPE(bindings) == TYPE_PAIR) { obj_t binding = CAR(bindings); @@ -1875,7 +1875,7 @@ static obj_t entry_let_star(obj_t env, obj_t op_env, obj_t operator, obj_t opera unless(TYPE(operands) == TYPE_PAIR && TYPE(CDR(operands)) == TYPE_PAIR) error("%s: illegal syntax", operator->operator.name); - inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ + inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ bindings = CAR(operands); while(TYPE(bindings) == TYPE_PAIR) { obj_t binding = CAR(bindings); @@ -1902,7 +1902,7 @@ static obj_t entry_letrec(obj_t env, obj_t op_env, obj_t operator, obj_t operand unless(TYPE(operands) == TYPE_PAIR && TYPE(CDR(operands)) == TYPE_PAIR) error("%s: illegal syntax", operator->operator.name); - inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ + inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ bindings = CAR(operands); while(TYPE(bindings) == TYPE_PAIR) { obj_t binding = CAR(bindings); @@ -2626,7 +2626,7 @@ static obj_t entry_divide(obj_t env, obj_t op_env, obj_t operator, obj_t operand if(args == obj_empty) { if(result == 0) error("%s: reciprocal of zero", operator->operator.name); - result = 1/result; /* TODO: pretty meaningless for integers */ + result = 1/result; /* TODO: pretty meaningless for integers */ } else { while(TYPE(args) == TYPE_PAIR) { unless(TYPE(CAR(args)) == TYPE_INTEGER) diff --git a/mps/example/scheme/scheme-boehm.c b/mps/example/scheme/scheme-boehm.c index 43e8967fb21..a5d39fa7dd5 100644 --- a/mps/example/scheme/scheme-boehm.c +++ b/mps/example/scheme/scheme-boehm.c @@ -25,16 +25,16 @@ /* LANGUAGE EXTENSION */ -#define unless(c) if(!(c)) -#define LENGTH(array) (sizeof(array) / sizeof(array[0])) +#define unless(c) if(!(c)) +#define LENGTH(array) (sizeof(array) / sizeof(array[0])) /* CONFIGURATION PARAMETERS */ -#define SYMMAX ((size_t)255) /* max length of a symbol */ -#define MSGMAX ((size_t)255) /* max length of error message */ -#define STRMAX ((size_t)255) /* max length of a string */ +#define SYMMAX ((size_t)255) /* max length of a symbol */ +#define MSGMAX ((size_t)255) /* max length of error message */ +#define STRMAX ((size_t)255) /* max length of a string */ /* DATA TYPES */ @@ -84,55 +84,55 @@ typedef struct type_s { } type_s; typedef struct pair_s { - type_t type; /* TYPE_PAIR */ - obj_t car, cdr; /* first and second projections */ + type_t type; /* TYPE_PAIR */ + obj_t car, cdr; /* first and second projections */ } pair_s; typedef struct symbol_s { - type_t type; /* TYPE_SYMBOL */ - size_t length; /* length of symbol string (excl. NUL) */ - char string[1]; /* symbol string, NUL terminated */ + type_t type; /* TYPE_SYMBOL */ + size_t length; /* length of symbol string (excl. NUL) */ + char string[1]; /* symbol string, NUL terminated */ } symbol_s; typedef struct integer_s { - type_t type; /* TYPE_INTEGER */ - long integer; /* the integer */ + type_t type; /* TYPE_INTEGER */ + long integer; /* the integer */ } integer_s; typedef struct special_s { - type_t type; /* TYPE_SPECIAL */ - char *name; /* printed representation, NUL terminated */ + type_t type; /* TYPE_SPECIAL */ + char *name; /* printed representation, NUL terminated */ } special_s; typedef struct operator_s { - type_t type; /* TYPE_OPERATOR */ - char *name; /* printed name, NUL terminated */ - entry_t entry; /* entry point -- see eval() */ - obj_t arguments, body; /* function arguments and code */ - obj_t env, op_env; /* closure environments */ + type_t type; /* TYPE_OPERATOR */ + char *name; /* printed name, NUL terminated */ + entry_t entry; /* entry point -- see eval() */ + obj_t arguments, body; /* function arguments and code */ + obj_t env, op_env; /* closure environments */ } operator_s; typedef struct string_s { - type_t type; /* TYPE_STRING */ - size_t length; /* number of chars in string */ - char string[1]; /* string, NUL terminated */ + type_t type; /* TYPE_STRING */ + size_t length; /* number of chars in string */ + char string[1]; /* string, NUL terminated */ } string_s; typedef struct port_s { - type_t type; /* TYPE_PORT */ - obj_t name; /* name of stream */ + type_t type; /* TYPE_PORT */ + obj_t name; /* name of stream */ FILE *stream; } port_s; typedef struct character_s { - type_t type; /* TYPE_CHARACTER */ - char c; /* the character */ + type_t type; /* TYPE_CHARACTER */ + char c; /* the character */ } character_s; typedef struct vector_s { - type_t type; /* TYPE_VECTOR */ - size_t length; /* number of elements */ - obj_t vector[1]; /* vector elements */ + type_t type; /* TYPE_VECTOR */ + size_t length; /* number of elements */ + obj_t vector[1]; /* vector elements */ } vector_s; typedef unsigned long (*hash_t)(obj_t obj); @@ -156,7 +156,7 @@ typedef struct buckets_s { } buckets_s; typedef union obj_u { - type_s type; /* one of TYPE_* */ + type_s type; /* one of TYPE_* */ pair_s pair; symbol_s symbol; integer_s integer; @@ -173,17 +173,17 @@ typedef union obj_u { /* structure macros */ -#define TYPE(obj) ((obj)->type.type) -#define CAR(obj) ((obj)->pair.car) -#define CDR(obj) ((obj)->pair.cdr) -#define CAAR(obj) CAR(CAR(obj)) -#define CADR(obj) CAR(CDR(obj)) -#define CDAR(obj) CDR(CAR(obj)) -#define CDDR(obj) CDR(CDR(obj)) -#define CADDR(obj) CAR(CDDR(obj)) -#define CDDDR(obj) CDR(CDDR(obj)) -#define CDDAR(obj) CDR(CDAR(obj)) -#define CADAR(obj) CAR(CDAR(obj)) +#define TYPE(obj) ((obj)->type.type) +#define CAR(obj) ((obj)->pair.car) +#define CDR(obj) ((obj)->pair.cdr) +#define CAAR(obj) CAR(CAR(obj)) +#define CADR(obj) CAR(CDR(obj)) +#define CDAR(obj) CDR(CAR(obj)) +#define CDDR(obj) CDR(CDR(obj)) +#define CADDR(obj) CAR(CDDR(obj)) +#define CDDDR(obj) CDR(CDDR(obj)) +#define CDDAR(obj) CDR(CDAR(obj)) +#define CADAR(obj) CAR(CDAR(obj)) /* GLOBAL DATA */ @@ -213,12 +213,12 @@ static size_t symtab_size; * special purposes. */ -static obj_t obj_empty; /* (), the empty list */ -static obj_t obj_eof; /* end of file */ -static obj_t obj_error; /* error indicator */ -static obj_t obj_true; /* #t, boolean true */ -static obj_t obj_false; /* #f, boolean false */ -static obj_t obj_undefined; /* undefined result indicator */ +static obj_t obj_empty; /* (), the empty list */ +static obj_t obj_eof; /* end of file */ +static obj_t obj_error; /* error indicator */ +static obj_t obj_true; /* #t, boolean true */ +static obj_t obj_false; /* #f, boolean false */ +static obj_t obj_undefined; /* undefined result indicator */ static obj_t obj_tail; /* tail recursion indicator */ static obj_t obj_deleted; /* deleted key in hashtable */ @@ -230,13 +230,13 @@ static obj_t obj_deleted; /* deleted key in hashtable */ * Scheme language, and are used by the evaluator to parse code. */ -static obj_t obj_quote; /* "quote" symbol */ -static obj_t obj_quasiquote; /* "quasiquote" symbol */ -static obj_t obj_lambda; /* "lambda" symbol */ -static obj_t obj_begin; /* "begin" symbol */ -static obj_t obj_else; /* "else" symbol */ -static obj_t obj_unquote; /* "unquote" symbol */ -static obj_t obj_unquote_splic; /* "unquote-splicing" symbol */ +static obj_t obj_quote; /* "quote" symbol */ +static obj_t obj_quasiquote; /* "quasiquote" symbol */ +static obj_t obj_lambda; /* "lambda" symbol */ +static obj_t obj_begin; /* "begin" symbol */ +static obj_t obj_else; /* "else" symbol */ +static obj_t obj_unquote; /* "unquote" symbol */ +static obj_t obj_unquote_splic; /* "unquote-splicing" symbol */ /* error handler @@ -545,8 +545,8 @@ static void rehash(void) { for(i = 0; i < old_symtab_size; ++i) if(old_symtab[i] != NULL) { obj_t *where = find(old_symtab[i]->symbol.string); - assert(where != NULL); /* new table shouldn't be full */ - assert(*where == NULL); /* shouldn't be in new table */ + assert(where != NULL); /* new table shouldn't be full */ + assert(*where == NULL); /* shouldn't be in new table */ *where = old_symtab[i]; } } @@ -560,10 +560,10 @@ static obj_t intern(char *string) { if(where == NULL) { rehash(); where = find(string); - assert(where != NULL); /* shouldn't be full after rehash */ + assert(where != NULL); /* shouldn't be full after rehash */ } - if(*where == NULL) /* symbol not found in table */ + if(*where == NULL) /* symbol not found in table */ *where = make_symbol(strlen(string), string); return *where; @@ -673,8 +673,8 @@ static void table_rehash(obj_t tbl) struct bucket_s *old_b = &tbl->table.buckets->buckets.bucket[i]; if (old_b->key != NULL && old_b->key != obj_deleted) { struct bucket_s *b = buckets_find(tbl, new_buckets, old_b->key); - assert(b != NULL); /* new table shouldn't be full */ - assert(b->key == NULL); /* shouldn't be in new table */ + assert(b != NULL); /* new table shouldn't be full */ + assert(b->key == NULL); /* shouldn't be in new table */ *b = *old_b; ++ new_buckets->buckets.used; } @@ -1052,13 +1052,13 @@ static obj_t read_special(FILE *stream, int c) switch(tolower(c)) { case 't': return obj_true; case 'f': return obj_false; - case '\\': { /* character (R4RS 6.6) */ + case '\\': { /* character (R4RS 6.6) */ c = getc(stream); if(c == EOF) error("read: end of file reading character literal"); return make_character(c); } - case '(': { /* vector (R4RS 6.8) */ + case '(': { /* vector (R4RS 6.8) */ obj_t list = read_list(stream, c); obj_t vector = list_to_vector(list); if(vector == obj_error) @@ -1159,7 +1159,7 @@ static obj_t lookup(obj_t env, obj_t symbol) static void define(obj_t env, obj_t symbol, obj_t value) { obj_t binding; - assert(TYPE(env) == TYPE_PAIR); /* always at least one frame */ + assert(TYPE(env) == TYPE_PAIR); /* always at least one frame */ binding = lookup_in_frame(CAR(env), symbol); if(binding != obj_undefined) CDR(binding) = value; @@ -1572,7 +1572,7 @@ static obj_t entry_let(obj_t env, obj_t op_env, obj_t operator, obj_t operands) unless(TYPE(operands) == TYPE_PAIR && TYPE(CDR(operands)) == TYPE_PAIR) error("%s: illegal syntax", operator->operator.name); - inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ + inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ bindings = CAR(operands); while(TYPE(bindings) == TYPE_PAIR) { obj_t binding = CAR(bindings); @@ -1599,7 +1599,7 @@ static obj_t entry_let_star(obj_t env, obj_t op_env, obj_t operator, obj_t opera unless(TYPE(operands) == TYPE_PAIR && TYPE(CDR(operands)) == TYPE_PAIR) error("%s: illegal syntax", operator->operator.name); - inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ + inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ bindings = CAR(operands); while(TYPE(bindings) == TYPE_PAIR) { obj_t binding = CAR(bindings); @@ -1626,7 +1626,7 @@ static obj_t entry_letrec(obj_t env, obj_t op_env, obj_t operator, obj_t operand unless(TYPE(operands) == TYPE_PAIR && TYPE(CDR(operands)) == TYPE_PAIR) error("%s: illegal syntax", operator->operator.name); - inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ + inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ bindings = CAR(operands); while(TYPE(bindings) == TYPE_PAIR) { obj_t binding = CAR(bindings); @@ -2350,7 +2350,7 @@ static obj_t entry_divide(obj_t env, obj_t op_env, obj_t operator, obj_t operand if(args == obj_empty) { if(result == 0) error("%s: reciprocal of zero", operator->operator.name); - result = 1/result; /* TODO: pretty meaningless for integers */ + result = 1/result; /* TODO: pretty meaningless for integers */ } else { while(TYPE(args) == TYPE_PAIR) { unless(TYPE(CAR(args)) == TYPE_INTEGER) diff --git a/mps/example/scheme/scheme-malloc.c b/mps/example/scheme/scheme-malloc.c index af619f9c15c..b09bd253fc1 100644 --- a/mps/example/scheme/scheme-malloc.c +++ b/mps/example/scheme/scheme-malloc.c @@ -23,16 +23,16 @@ /* LANGUAGE EXTENSION */ -#define unless(c) if(!(c)) -#define LENGTH(array) (sizeof(array) / sizeof(array[0])) +#define unless(c) if(!(c)) +#define LENGTH(array) (sizeof(array) / sizeof(array[0])) /* CONFIGURATION PARAMETERS */ -#define SYMMAX ((size_t)255) /* max length of a symbol */ -#define MSGMAX ((size_t)255) /* max length of error message */ -#define STRMAX ((size_t)255) /* max length of a string */ +#define SYMMAX ((size_t)255) /* max length of a symbol */ +#define MSGMAX ((size_t)255) /* max length of error message */ +#define STRMAX ((size_t)255) /* max length of a string */ /* DATA TYPES */ @@ -82,55 +82,55 @@ typedef struct type_s { } type_s; typedef struct pair_s { - type_t type; /* TYPE_PAIR */ - obj_t car, cdr; /* first and second projections */ + type_t type; /* TYPE_PAIR */ + obj_t car, cdr; /* first and second projections */ } pair_s; typedef struct symbol_s { - type_t type; /* TYPE_SYMBOL */ - size_t length; /* length of symbol string (excl. NUL) */ - char string[1]; /* symbol string, NUL terminated */ + type_t type; /* TYPE_SYMBOL */ + size_t length; /* length of symbol string (excl. NUL) */ + char string[1]; /* symbol string, NUL terminated */ } symbol_s; typedef struct integer_s { - type_t type; /* TYPE_INTEGER */ - long integer; /* the integer */ + type_t type; /* TYPE_INTEGER */ + long integer; /* the integer */ } integer_s; typedef struct special_s { - type_t type; /* TYPE_SPECIAL */ - char *name; /* printed representation, NUL terminated */ + type_t type; /* TYPE_SPECIAL */ + char *name; /* printed representation, NUL terminated */ } special_s; typedef struct operator_s { - type_t type; /* TYPE_OPERATOR */ - char *name; /* printed name, NUL terminated */ - entry_t entry; /* entry point -- see eval() */ - obj_t arguments, body; /* function arguments and code */ - obj_t env, op_env; /* closure environments */ + type_t type; /* TYPE_OPERATOR */ + char *name; /* printed name, NUL terminated */ + entry_t entry; /* entry point -- see eval() */ + obj_t arguments, body; /* function arguments and code */ + obj_t env, op_env; /* closure environments */ } operator_s; typedef struct string_s { - type_t type; /* TYPE_STRING */ - size_t length; /* number of chars in string */ - char string[1]; /* string, NUL terminated */ + type_t type; /* TYPE_STRING */ + size_t length; /* number of chars in string */ + char string[1]; /* string, NUL terminated */ } string_s; typedef struct port_s { - type_t type; /* TYPE_PORT */ - obj_t name; /* name of stream */ + type_t type; /* TYPE_PORT */ + obj_t name; /* name of stream */ FILE *stream; } port_s; typedef struct character_s { - type_t type; /* TYPE_CHARACTER */ - char c; /* the character */ + type_t type; /* TYPE_CHARACTER */ + char c; /* the character */ } character_s; typedef struct vector_s { - type_t type; /* TYPE_VECTOR */ - size_t length; /* number of elements */ - obj_t vector[1]; /* vector elements */ + type_t type; /* TYPE_VECTOR */ + size_t length; /* number of elements */ + obj_t vector[1]; /* vector elements */ } vector_s; typedef unsigned long (*hash_t)(obj_t obj); @@ -154,7 +154,7 @@ typedef struct buckets_s { } buckets_s; typedef union obj_u { - type_s type; /* one of TYPE_* */ + type_s type; /* one of TYPE_* */ pair_s pair; symbol_s symbol; integer_s integer; @@ -171,17 +171,17 @@ typedef union obj_u { /* structure macros */ -#define TYPE(obj) ((obj)->type.type) -#define CAR(obj) ((obj)->pair.car) -#define CDR(obj) ((obj)->pair.cdr) -#define CAAR(obj) CAR(CAR(obj)) -#define CADR(obj) CAR(CDR(obj)) -#define CDAR(obj) CDR(CAR(obj)) -#define CDDR(obj) CDR(CDR(obj)) -#define CADDR(obj) CAR(CDDR(obj)) -#define CDDDR(obj) CDR(CDDR(obj)) -#define CDDAR(obj) CDR(CDAR(obj)) -#define CADAR(obj) CAR(CDAR(obj)) +#define TYPE(obj) ((obj)->type.type) +#define CAR(obj) ((obj)->pair.car) +#define CDR(obj) ((obj)->pair.cdr) +#define CAAR(obj) CAR(CAR(obj)) +#define CADR(obj) CAR(CDR(obj)) +#define CDAR(obj) CDR(CAR(obj)) +#define CDDR(obj) CDR(CDR(obj)) +#define CADDR(obj) CAR(CDDR(obj)) +#define CDDDR(obj) CDR(CDDR(obj)) +#define CDDAR(obj) CDR(CDAR(obj)) +#define CADAR(obj) CAR(CDAR(obj)) /* GLOBAL DATA */ @@ -211,12 +211,12 @@ static size_t symtab_size; * special purposes. */ -static obj_t obj_empty; /* (), the empty list */ -static obj_t obj_eof; /* end of file */ -static obj_t obj_error; /* error indicator */ -static obj_t obj_true; /* #t, boolean true */ -static obj_t obj_false; /* #f, boolean false */ -static obj_t obj_undefined; /* undefined result indicator */ +static obj_t obj_empty; /* (), the empty list */ +static obj_t obj_eof; /* end of file */ +static obj_t obj_error; /* error indicator */ +static obj_t obj_true; /* #t, boolean true */ +static obj_t obj_false; /* #f, boolean false */ +static obj_t obj_undefined; /* undefined result indicator */ static obj_t obj_tail; /* tail recursion indicator */ static obj_t obj_deleted; /* deleted key in hashtable */ @@ -228,13 +228,13 @@ static obj_t obj_deleted; /* deleted key in hashtable */ * Scheme language, and are used by the evaluator to parse code. */ -static obj_t obj_quote; /* "quote" symbol */ -static obj_t obj_quasiquote; /* "quasiquote" symbol */ -static obj_t obj_lambda; /* "lambda" symbol */ -static obj_t obj_begin; /* "begin" symbol */ -static obj_t obj_else; /* "else" symbol */ -static obj_t obj_unquote; /* "unquote" symbol */ -static obj_t obj_unquote_splic; /* "unquote-splicing" symbol */ +static obj_t obj_quote; /* "quote" symbol */ +static obj_t obj_quasiquote; /* "quasiquote" symbol */ +static obj_t obj_lambda; /* "lambda" symbol */ +static obj_t obj_begin; /* "begin" symbol */ +static obj_t obj_else; /* "else" symbol */ +static obj_t obj_unquote; /* "unquote" symbol */ +static obj_t obj_unquote_splic; /* "unquote-splicing" symbol */ /* error handler @@ -543,8 +543,8 @@ static void rehash(void) { for(i = 0; i < old_symtab_size; ++i) if(old_symtab[i] != NULL) { obj_t *where = find(old_symtab[i]->symbol.string); - assert(where != NULL); /* new table shouldn't be full */ - assert(*where == NULL); /* shouldn't be in new table */ + assert(where != NULL); /* new table shouldn't be full */ + assert(*where == NULL); /* shouldn't be in new table */ *where = old_symtab[i]; } @@ -560,10 +560,10 @@ static obj_t intern(char *string) { if(where == NULL) { rehash(); where = find(string); - assert(where != NULL); /* shouldn't be full after rehash */ + assert(where != NULL); /* shouldn't be full after rehash */ } - if(*where == NULL) /* symbol not found in table */ + if(*where == NULL) /* symbol not found in table */ *where = make_symbol(strlen(string), string); return *where; @@ -673,8 +673,8 @@ static void table_rehash(obj_t tbl) struct bucket_s *old_b = &tbl->table.buckets->buckets.bucket[i]; if (old_b->key != NULL && old_b->key != obj_deleted) { struct bucket_s *b = buckets_find(tbl, new_buckets, old_b->key); - assert(b != NULL); /* new table shouldn't be full */ - assert(b->key == NULL); /* shouldn't be in new table */ + assert(b != NULL); /* new table shouldn't be full */ + assert(b->key == NULL); /* shouldn't be in new table */ *b = *old_b; ++ new_buckets->buckets.used; } @@ -1052,13 +1052,13 @@ static obj_t read_special(FILE *stream, int c) switch(tolower(c)) { case 't': return obj_true; case 'f': return obj_false; - case '\\': { /* character (R4RS 6.6) */ + case '\\': { /* character (R4RS 6.6) */ c = getc(stream); if(c == EOF) error("read: end of file reading character literal"); return make_character(c); } - case '(': { /* vector (R4RS 6.8) */ + case '(': { /* vector (R4RS 6.8) */ obj_t list = read_list(stream, c); obj_t vector = list_to_vector(list); if(vector == obj_error) @@ -1159,7 +1159,7 @@ static obj_t lookup(obj_t env, obj_t symbol) static void define(obj_t env, obj_t symbol, obj_t value) { obj_t binding; - assert(TYPE(env) == TYPE_PAIR); /* always at least one frame */ + assert(TYPE(env) == TYPE_PAIR); /* always at least one frame */ binding = lookup_in_frame(CAR(env), symbol); if(binding != obj_undefined) CDR(binding) = value; @@ -1572,7 +1572,7 @@ static obj_t entry_let(obj_t env, obj_t op_env, obj_t operator, obj_t operands) unless(TYPE(operands) == TYPE_PAIR && TYPE(CDR(operands)) == TYPE_PAIR) error("%s: illegal syntax", operator->operator.name); - inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ + inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ bindings = CAR(operands); while(TYPE(bindings) == TYPE_PAIR) { obj_t binding = CAR(bindings); @@ -1599,7 +1599,7 @@ static obj_t entry_let_star(obj_t env, obj_t op_env, obj_t operator, obj_t opera unless(TYPE(operands) == TYPE_PAIR && TYPE(CDR(operands)) == TYPE_PAIR) error("%s: illegal syntax", operator->operator.name); - inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ + inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ bindings = CAR(operands); while(TYPE(bindings) == TYPE_PAIR) { obj_t binding = CAR(bindings); @@ -1626,7 +1626,7 @@ static obj_t entry_letrec(obj_t env, obj_t op_env, obj_t operator, obj_t operand unless(TYPE(operands) == TYPE_PAIR && TYPE(CDR(operands)) == TYPE_PAIR) error("%s: illegal syntax", operator->operator.name); - inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ + inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ bindings = CAR(operands); while(TYPE(bindings) == TYPE_PAIR) { obj_t binding = CAR(bindings); @@ -2350,7 +2350,7 @@ static obj_t entry_divide(obj_t env, obj_t op_env, obj_t operator, obj_t operand if(args == obj_empty) { if(result == 0) error("%s: reciprocal of zero", operator->operator.name); - result = 1/result; /* TODO: pretty meaningless for integers */ + result = 1/result; /* TODO: pretty meaningless for integers */ } else { while(TYPE(args) == TYPE_PAIR) { unless(TYPE(CAR(args)) == TYPE_INTEGER) diff --git a/mps/example/scheme/scheme.c b/mps/example/scheme/scheme.c index 69d34612660..5b201a26a54 100644 --- a/mps/example/scheme/scheme.c +++ b/mps/example/scheme/scheme.c @@ -54,17 +54,17 @@ /* LANGUAGE EXTENSION */ -#define unless(c) if(!(c)) -#define LENGTH(array) (sizeof(array) / sizeof(array[0])) +#define unless(c) if(!(c)) +#define LENGTH(array) (sizeof(array) / sizeof(array[0])) #define UNUSED(var) ((void)var) /* CONFIGURATION PARAMETERS */ -#define SYMMAX ((size_t)255) /* max length of a symbol */ -#define MSGMAX ((size_t)255) /* max length of error message */ -#define STRMAX ((size_t)255) /* max length of a string */ +#define SYMMAX ((size_t)255) /* max length of a symbol */ +#define MSGMAX ((size_t)255) /* max length of error message */ +#define STRMAX ((size_t)255) /* max length of a string */ /* DATA TYPES */ @@ -118,55 +118,55 @@ typedef struct type_s { } type_s; typedef struct pair_s { - type_t type; /* TYPE_PAIR */ - obj_t car, cdr; /* first and second projections */ + type_t type; /* TYPE_PAIR */ + obj_t car, cdr; /* first and second projections */ } pair_s; typedef struct symbol_s { - type_t type; /* TYPE_SYMBOL */ - size_t length; /* length of symbol string (excl. NUL) */ - char string[1]; /* symbol string, NUL terminated */ + type_t type; /* TYPE_SYMBOL */ + size_t length; /* length of symbol string (excl. NUL) */ + char string[1]; /* symbol string, NUL terminated */ } symbol_s; typedef struct integer_s { - type_t type; /* TYPE_INTEGER */ - long integer; /* the integer */ + type_t type; /* TYPE_INTEGER */ + long integer; /* the integer */ } integer_s; typedef struct special_s { - type_t type; /* TYPE_SPECIAL */ - const char *name; /* printed representation, NUL terminated */ + type_t type; /* TYPE_SPECIAL */ + const char *name; /* printed representation, NUL terminated */ } special_s; typedef struct operator_s { - type_t type; /* TYPE_OPERATOR */ - const char *name; /* printed name, NUL terminated */ - entry_t entry; /* entry point -- see eval() */ - obj_t arguments, body; /* function arguments and code */ - obj_t env, op_env; /* closure environments */ + type_t type; /* TYPE_OPERATOR */ + const char *name; /* printed name, NUL terminated */ + entry_t entry; /* entry point -- see eval() */ + obj_t arguments, body; /* function arguments and code */ + obj_t env, op_env; /* closure environments */ } operator_s; typedef struct string_s { - type_t type; /* TYPE_STRING */ - size_t length; /* number of chars in string */ - char string[1]; /* string, NUL terminated */ + type_t type; /* TYPE_STRING */ + size_t length; /* number of chars in string */ + char string[1]; /* string, NUL terminated */ } string_s; typedef struct port_s { - type_t type; /* TYPE_PORT */ - obj_t name; /* name of stream */ + type_t type; /* TYPE_PORT */ + obj_t name; /* name of stream */ FILE *stream; } port_s; typedef struct character_s { - type_t type; /* TYPE_CHARACTER */ - char c; /* the character */ + type_t type; /* TYPE_CHARACTER */ + char c; /* the character */ } character_s; typedef struct vector_s { - type_t type; /* TYPE_VECTOR */ - size_t length; /* number of elements */ - obj_t vector[1]; /* vector elements */ + type_t type; /* TYPE_VECTOR */ + size_t length; /* number of elements */ + obj_t vector[1]; /* vector elements */ } vector_s; typedef unsigned long (*hash_t)(obj_t obj, mps_ld_t ld); @@ -238,7 +238,7 @@ typedef struct pad_s { typedef union obj_u { - type_s type; /* one of TYPE_* */ + type_s type; /* one of TYPE_* */ pair_s pair; symbol_s symbol; integer_s integer; @@ -258,17 +258,17 @@ typedef union obj_u { /* structure macros */ -#define TYPE(obj) ((obj)->type.type) -#define CAR(obj) ((obj)->pair.car) -#define CDR(obj) ((obj)->pair.cdr) -#define CAAR(obj) CAR(CAR(obj)) -#define CADR(obj) CAR(CDR(obj)) -#define CDAR(obj) CDR(CAR(obj)) -#define CDDR(obj) CDR(CDR(obj)) -#define CADDR(obj) CAR(CDDR(obj)) -#define CDDDR(obj) CDR(CDDR(obj)) -#define CDDAR(obj) CDR(CDAR(obj)) -#define CADAR(obj) CAR(CDAR(obj)) +#define TYPE(obj) ((obj)->type.type) +#define CAR(obj) ((obj)->pair.car) +#define CDR(obj) ((obj)->pair.cdr) +#define CAAR(obj) CAR(CAR(obj)) +#define CADR(obj) CAR(CDR(obj)) +#define CDAR(obj) CDR(CAR(obj)) +#define CDDR(obj) CDR(CDR(obj)) +#define CADDR(obj) CAR(CDDR(obj)) +#define CDDDR(obj) CDR(CDDR(obj)) +#define CDDAR(obj) CDR(CDAR(obj)) +#define CADAR(obj) CAR(CDAR(obj)) /* GLOBAL DATA */ @@ -308,12 +308,12 @@ static mps_root_t symtab_root; * See `globals_scan`. */ -static obj_t obj_empty; /* (), the empty list */ -static obj_t obj_eof; /* end of file */ -static obj_t obj_error; /* error indicator */ -static obj_t obj_true; /* #t, boolean true */ -static obj_t obj_false; /* #f, boolean false */ -static obj_t obj_undefined; /* undefined result indicator */ +static obj_t obj_empty; /* (), the empty list */ +static obj_t obj_eof; /* end of file */ +static obj_t obj_error; /* error indicator */ +static obj_t obj_true; /* #t, boolean true */ +static obj_t obj_false; /* #f, boolean false */ +static obj_t obj_undefined; /* undefined result indicator */ static obj_t obj_tail; /* tail recursion indicator */ static obj_t obj_deleted; /* deleted key in hashtable */ @@ -325,13 +325,13 @@ static obj_t obj_deleted; /* deleted key in hashtable */ * Scheme language, and are used by the evaluator to parse code. */ -static obj_t obj_quote; /* "quote" symbol */ -static obj_t obj_quasiquote; /* "quasiquote" symbol */ -static obj_t obj_lambda; /* "lambda" symbol */ -static obj_t obj_begin; /* "begin" symbol */ -static obj_t obj_else; /* "else" symbol */ -static obj_t obj_unquote; /* "unquote" symbol */ -static obj_t obj_unquote_splic; /* "unquote-splicing" symbol */ +static obj_t obj_quote; /* "quote" symbol */ +static obj_t obj_quasiquote; /* "quasiquote" symbol */ +static obj_t obj_lambda; /* "lambda" symbol */ +static obj_t obj_begin; /* "begin" symbol */ +static obj_t obj_else; /* "else" symbol */ +static obj_t obj_unquote; /* "unquote" symbol */ +static obj_t obj_unquote_splic; /* "unquote-splicing" symbol */ /* error handler @@ -783,8 +783,8 @@ static void rehash(void) { for(i = 0; i < old_symtab_size; ++i) if(old_symtab[i] != NULL) { obj_t *where = find(old_symtab[i]->symbol.string); - assert(where != NULL); /* new table shouldn't be full */ - assert(*where == NULL); /* shouldn't be in new table */ + assert(where != NULL); /* new table shouldn't be full */ + assert(*where == NULL); /* shouldn't be in new table */ *where = old_symtab[i]; } @@ -801,10 +801,10 @@ static obj_t intern(const char *string) { if(where == NULL) { rehash(); where = find(string); - assert(where != NULL); /* shouldn't be full after rehash */ + assert(where != NULL); /* shouldn't be full after rehash */ } - if(*where == NULL) /* symbol not found in table */ + if(*where == NULL) /* symbol not found in table */ *where = make_symbol(strlen(string), string); return *where; @@ -928,8 +928,8 @@ static struct bucket_s *table_rehash(obj_t tbl, size_t new_length, obj_t key) struct bucket_s *old_b = &tbl->table.buckets->buckets.bucket[i]; if (old_b->key != NULL && old_b->key != obj_deleted) { struct bucket_s *b = buckets_find(tbl, new_buckets, old_b->key, 1); - assert(b != NULL); /* new table shouldn't be full */ - assert(b->key == NULL); /* shouldn't be in new table */ + assert(b != NULL); /* new table shouldn't be full */ + assert(b->key == NULL); /* shouldn't be in new table */ *b = *old_b; if (b->key == key) key_bucket = b; ++ new_buckets->buckets.used; @@ -1352,13 +1352,13 @@ static obj_t read_special(FILE *stream, int c) switch(tolower(c)) { case 't': return obj_true; case 'f': return obj_false; - case '\\': { /* character (R4RS 6.6) */ + case '\\': { /* character (R4RS 6.6) */ c = getc(stream); if(c == EOF) error("read: end of file reading character literal"); return make_character((char)c); } - case '(': { /* vector (R4RS 6.8) */ + case '(': { /* vector (R4RS 6.8) */ obj_t list = read_list(stream, c); obj_t vector = list_to_vector(list); if(vector == obj_error) @@ -1459,7 +1459,7 @@ static obj_t lookup(obj_t env, obj_t symbol) static void define(obj_t env, obj_t symbol, obj_t value) { obj_t binding; - assert(TYPE(env) == TYPE_PAIR); /* always at least one frame */ + assert(TYPE(env) == TYPE_PAIR); /* always at least one frame */ binding = lookup_in_frame(CAR(env), symbol); if(binding != obj_undefined) CDR(binding) = value; @@ -1878,7 +1878,7 @@ static obj_t entry_let(obj_t env, obj_t op_env, obj_t operator, obj_t operands) unless(TYPE(operands) == TYPE_PAIR && TYPE(CDR(operands)) == TYPE_PAIR) error("%s: illegal syntax", operator->operator.name); - inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ + inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ bindings = CAR(operands); while(TYPE(bindings) == TYPE_PAIR) { obj_t binding = CAR(bindings); @@ -1905,7 +1905,7 @@ static obj_t entry_let_star(obj_t env, obj_t op_env, obj_t operator, obj_t opera unless(TYPE(operands) == TYPE_PAIR && TYPE(CDR(operands)) == TYPE_PAIR) error("%s: illegal syntax", operator->operator.name); - inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ + inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ bindings = CAR(operands); while(TYPE(bindings) == TYPE_PAIR) { obj_t binding = CAR(bindings); @@ -1932,7 +1932,7 @@ static obj_t entry_letrec(obj_t env, obj_t op_env, obj_t operator, obj_t operand unless(TYPE(operands) == TYPE_PAIR && TYPE(CDR(operands)) == TYPE_PAIR) error("%s: illegal syntax", operator->operator.name); - inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ + inner_env = make_pair(obj_empty, env); /* TODO: common with interpret */ bindings = CAR(operands); while(TYPE(bindings) == TYPE_PAIR) { obj_t binding = CAR(bindings); @@ -2656,7 +2656,7 @@ static obj_t entry_divide(obj_t env, obj_t op_env, obj_t operator, obj_t operand if(args == obj_empty) { if(result == 0) error("%s: reciprocal of zero", operator->operator.name); - result = 1/result; /* TODO: pretty meaningless for integers */ + result = 1/result; /* TODO: pretty meaningless for integers */ } else { while(TYPE(args) == TYPE_PAIR) { unless(TYPE(CAR(args)) == TYPE_INTEGER) diff --git a/mps/manual/source/glossary/r.rst b/mps/manual/source/glossary/r.rst index cbab9a255fe..1b0f7d51813 100644 --- a/mps/manual/source/glossary/r.rst +++ b/mps/manual/source/glossary/r.rst @@ -339,10 +339,10 @@ Memory Management Glossary: R register - A *register* is a small unit of :term:`memory (2)` that is - attached to a processor and accessible very quickly. Registers - typically form the highest level of a computer's - :term:`storage hierarchy`. + A *register* is a small unit of :term:`memory (2)` that is + attached to a processor and accessible very quickly. Registers + typically form the highest level of a computer's + :term:`storage hierarchy`. .. relevance:: diff --git a/mps/manual/source/glossary/v.rst b/mps/manual/source/glossary/v.rst index dd7b4fcaa27..14e24bb7f1b 100644 --- a/mps/manual/source/glossary/v.rst +++ b/mps/manual/source/glossary/v.rst @@ -54,7 +54,7 @@ Memory Management Glossary: V variety - .. mps:specific:: + .. mps:specific:: A behaviour of the MPS that must be selected at compilation time. There are three varieties: :term:`cool`, diff --git a/mps/manual/source/guide/debug.rst b/mps/manual/source/guide/debug.rst index 060928c2ba6..3c1678e660b 100644 --- a/mps/manual/source/guide/debug.rst +++ b/mps/manual/source/guide/debug.rst @@ -398,16 +398,16 @@ And here's how it shows up in the debugger: #3 0x00000001000014e3 in obj_skip (base=0x1003f9b88) at scheme.c:2940 2940 assert(0); (gdb) list - 2935 break; - 2936 case TYPE_PAD1: - 2937 base = (char *)base + ALIGN_OBJ(sizeof(pad1_s)); - 2938 break; - 2939 default: - 2940 assert(0); - 2941 fprintf(stderr, "Unexpected object on the heap\n"); - 2942 abort(); - 2943 return NULL; - 2944 } + 2935 break; + 2936 case TYPE_PAD1: + 2937 base = (char *)base + ALIGN_OBJ(sizeof(pad1_s)); + 2938 break; + 2939 default: + 2940 assert(0); + 2941 fprintf(stderr, "Unexpected object on the heap\n"); + 2942 abort(); + 2943 return NULL; + 2944 } The object being skipped is corrupt:: diff --git a/mps/manual/source/mmref/lang.rst b/mps/manual/source/mmref/lang.rst index d00ffa49c37..569a5bae4e2 100644 --- a/mps/manual/source/mmref/lang.rst +++ b/mps/manual/source/mmref/lang.rst @@ -147,8 +147,8 @@ Memory management in various languages is reclaimed by the memory manager), and :term:`weak references (1)` (via the ``WeakReference`` class). - The :term:`garbage collector` in the .NET Framework is - configurable to run in soft real time, or in batch mode. + The :term:`garbage collector` in the .NET Framework is + configurable to run in soft real time, or in batch mode. The Mono runtime comes with two collectors: the Boehm–Demers–Weiser :term:`conservative collector @@ -607,10 +607,10 @@ Memory management in various languages Python is a "duck-typed" object-oriented language created in the early 1990s by Guido van Rossum. - There are several implementations running on a variety of - virtual machines: the original "CPython" implementation runs - on its own virtual machine; IronPython runs on the Common - Language Runtime; Jython on the Java Virtual Machine. + There are several implementations running on a variety of + virtual machines: the original "CPython" implementation runs + on its own virtual machine; IronPython runs on the Common + Language Runtime; Jython on the Java Virtual Machine. CPython manages memory using a mixture of :term:`reference counting` and :term:`non-moving ` diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst index 0589003950e..18819c2ce09 100644 --- a/mps/manual/source/topic/deprecated.rst +++ b/mps/manual/source/topic/deprecated.rst @@ -178,8 +178,8 @@ Deprecated in version 1.115 mps_root_create_table_tagged(root_o, arena, rank, rm, base, size, - mps_scan_area_tagged, - mask, 0) + mps_scan_area_tagged, + mask, 0) .. c:type:: mps_res_t (*mps_reg_scan_t)(mps_ss_t ss, mps_thr_t thr, void *p, size_t s) diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index 9a5aa69ed94..4ffdf8727bd 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -396,14 +396,14 @@ Root interface This function is equivalent to calling:: mps_root_create_thread_tagged(root_o, - arena, - mps_rank_ambig(), - (mps_rm_t)0, - thr, - mps_scan_area_tagged, - sizeof(mps_word_t) - 1, - 0, - stack); + arena, + mps_rank_ambig(), + (mps_rm_t)0, + thr, + mps_scan_area_tagged, + sizeof(mps_word_t) - 1, + 0, + stack); .. c:function:: mps_res_t mps_root_create_thread_tagged(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thr, mps_area_scan_t scan_area, mps_word_t mask, mps_word_t pattern, void *stack) @@ -460,25 +460,25 @@ Root interface You can avoid this risk in several ways: - #. Choosing to tag pointers with zero, setting ``scan_area`` - as :c:func:`mps_scan_area_tagged` and setting ``pattern`` - to zero. + #. Choosing to tag pointers with zero, setting ``scan_area`` + as :c:func:`mps_scan_area_tagged` and setting ``pattern`` + to zero. #. Set ``scan_area`` to :c:func:`mps_scan_area_tagged_or_zero` - so that untagged pointers are scanned. Thist may lead to - some additional scanning and retention. + so that untagged pointers are scanned. Thist may lead to + some additional scanning and retention. - #. Use :c:func:`mps_root_create_thread_scanned` and set - ``scan_area`` to :c:func:`mps_scan_area`: in this case all - words in registers and on the stack are scanned, leading to - possible additional scanning and retention. + #. Use :c:func:`mps_root_create_thread_scanned` and set + ``scan_area`` to :c:func:`mps_scan_area`: in this case all + words in registers and on the stack are scanned, leading to + possible additional scanning and retention. - #. Write your own compiler with complete control over register - contents and stack format, use - :c:func:`mps_root_create_thread_scanned` and set - ``scan_area`` to your own custom scanner, derived from the - source code of :c:func:`mps_scan_area`, that knows the - format. + #. Write your own compiler with complete control over register + contents and stack format, use + :c:func:`mps_root_create_thread_scanned` and set + ``scan_area`` to your own custom scanner, derived from the + source code of :c:func:`mps_scan_area`, that knows the + format. .. note:: @@ -723,7 +723,7 @@ Root interface mps_rank_exact(), (mps_rm_t)0, base, symtab_size * 2, - mps_scan_area_tagged, + mps_scan_area_tagged, (mps_word_t)TAG_MASK, (mps_word_t)TAG_PATTERN); if (res != MPS_RES_OK) errror("can't create symtab root"); diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst index 46159238860..a22969cb8f4 100644 --- a/mps/manual/source/topic/scanning.rst +++ b/mps/manual/source/topic/scanning.rst @@ -531,7 +531,7 @@ the scanners, found in ``scan.c`` in the MPS source code. mps_res_t scan(mps_ss_t ss, mps_word_t *base, mps_word_t *limit, - void *closure, size_t closure_size); + void *closure, size_t closure_size); ``ss`` is the :term:`scan state`. diff --git a/mps/procedure/branch-merge.rst b/mps/procedure/branch-merge.rst index a29a6daa197..2645d3385f4 100644 --- a/mps/procedure/branch-merge.rst +++ b/mps/procedure/branch-merge.rst @@ -52,7 +52,7 @@ the parent branch. So a typical invocation looks like this:: The specification should look like this:: - Branch: mps/branch/2013-08-21/lii6ll + Branch: mps/branch/2013-08-21/lii6ll Description: Adding new supported platform lii6ll (job003596). diff --git a/mps/procedure/release-build.rst b/mps/procedure/release-build.rst index cf07cee0620..66a56fba2f8 100644 --- a/mps/procedure/release-build.rst +++ b/mps/procedure/release-build.rst @@ -147,7 +147,7 @@ On a Unix (including OS X) machine: View: //info.ravenbrook.com/project/mps/version/$VERSION/... //$CLIENT/mps-kit-$RELEASE/... //info.ravenbrook.com/project/mps/release/$RELEASE/... //$CLIENT/release/$RELEASE/... - END + END #. Sync this client to *CHANGELEVEL*:: @@ -169,7 +169,7 @@ On a Unix (including OS X) machine: #. Sync the version sources again:: rm -rf /tmp/$CLIENT/version/$VERSION - p4 -c $CLIENT sync -f @$CHANGELEVEL + p4 -c $CLIENT sync -f @$CHANGELEVEL #. Create a zip file containing the MPS sources, and open it for add:: diff --git a/mps/procedure/version-create.rst b/mps/procedure/version-create.rst index 3f743639fdf..e92e93535d3 100644 --- a/mps/procedure/version-create.rst +++ b/mps/procedure/version-create.rst @@ -145,8 +145,8 @@ the parent branch. A typical invocation looks like this:: p4 client -i < Date: Thu, 18 Feb 2016 19:59:44 +0000 Subject: [PATCH 152/337] Removing argument identifiers from prototype of mps_root_create_table_tagged. Copied from Perforce Change: 189310 ServerID: perforce.ravenbrook.com --- mps/code/mps.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mps/code/mps.h b/mps/code/mps.h index 10ca5f01078..2856cc16c7e 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -675,13 +675,13 @@ extern mps_res_t mps_root_create(mps_root_t *, mps_arena_t, mps_rank_t, extern mps_res_t mps_root_create_table(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_addr_t *, size_t); -extern mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, - mps_arena_t arena, - mps_rank_t mps_rank, mps_rm_t mps_rm, - mps_addr_t *base, size_t size, - mps_area_scan_t scan_area, - mps_word_t mask, - mps_word_t pattern); +extern mps_res_t mps_root_create_table_tagged(mps_root_t *, + mps_arena_t, + mps_rank_t, mps_rm_t, + mps_addr_t *, size_t, + mps_area_scan_t, + mps_word_t, + mps_word_t); extern mps_res_t mps_root_create_table_masked(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_addr_t *, size_t, From 8a62ebbd66fe2d56bb3185450592dc8c31c6fa2a Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 18 Feb 2016 20:06:06 +0000 Subject: [PATCH 153/337] Explaining why code in scan.c is written outside the mps interface. Copied from Perforce Change: 189311 ServerID: perforce.ravenbrook.com --- mps/code/scan.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mps/code/scan.c b/mps/code/scan.c index ce735710069..23a43e26c62 100644 --- a/mps/code/scan.c +++ b/mps/code/scan.c @@ -4,8 +4,12 @@ * Copyright (c) 2001-2016 Ravenbrook Limited. * See end of file for license. * + * .outside: The code in this file is written as if *outside* the MPS, + * and so is restricted to facilities in the MPS interface. MPS users + * are invited to read this code and use it as a basis for their own + * scanners. See topic "Area Scanners" in the MPS manual. + * * TODO: Design document. - * FIXME: Manual entries for mps_scan_area etc. */ #include "mps.h" From 44664b7cc7dc53f442170fc338de7476e1ca9d05 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 18 Feb 2016 20:49:21 +0000 Subject: [PATCH 154/337] Removing check that pattern fits within mask, as this restricts the generality of scan_area. Copied from Perforce Change: 189312 ServerID: perforce.ravenbrook.com --- mps/code/mpsi.c | 7 ++++--- mps/code/root.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index a7fa2857180..c7cde2d4f5d 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1364,8 +1364,8 @@ mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, AVER(base != NULL); AVER(size > 0); AVER(FUNCHECK(scan_area)); - /* Can't check anything about mask. */ - AVER((pattern & mask) == pattern); + /* Can't check anything about mask or pattern, as they could mean + anything to scan_area. */ /* .root.table-size */ res = RootCreateAreaTagged(&root, arena, rank, mode, @@ -1527,7 +1527,8 @@ mps_res_t mps_root_create_thread_tagged(mps_root_t *mps_root_o, AVER(rank == mps_rank_ambig()); AVER(mps_rm == (mps_rm_t)0); AVER(FUNCHECK(scan_area)); - AVER((~mask & pattern) == 0); + /* Can't check anything about mask or pattern, as they could mean + anything to scan_area. */ /* See .root-mode. */ res = RootCreateThreadTagged(&root, arena, rank, thread, diff --git a/mps/code/root.c b/mps/code/root.c index 0a73c5c190c..bdf01a90e30 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -306,8 +306,8 @@ Res RootCreateAreaTagged(Root *rootReturn, Arena arena, AVERT(Rank, rank); AVER(base != 0); AVER(base < limit); - /* Can't check anything about mask. */ - AVER((mask & pattern) == pattern); + /* Can't check anything about mask or pattern, as they could mean + anything to scan_area. */ theUnion.area.base = base; theUnion.area.limit = limit; @@ -359,7 +359,8 @@ Res RootCreateThreadTagged(Root *rootReturn, Arena arena, AVERT(Thread, thread); AVER(ThreadArena(thread) == arena); AVER(FUNCHECK(scan_area)); - AVER((~mask & pattern) == 0); + /* Can't check anything about mask or pattern, as they could mean + anything to scan_area. */ theUnion.thread.thread = thread; theUnion.thread.scan_area = scan_area; From 5ba0a765cc6e9aed5eac85e2b08c81e170fde675 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 18 Feb 2016 20:54:35 +0000 Subject: [PATCH 155/337] Renaming variable _p to p, as it was left over from an earlier name clash by mistake. Copied from Perforce Change: 189313 ServerID: perforce.ravenbrook.com --- mps/code/scan.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mps/code/scan.c b/mps/code/scan.c index 23a43e26c62..0dc0747e3c6 100644 --- a/mps/code/scan.c +++ b/mps/code/scan.c @@ -33,17 +33,17 @@ mps_res_t mps_scan_area(mps_ss_t ss, (void)closure_size; /* unused */ MPS_SCAN_BEGIN(ss) { - mps_word_t *_p = base; - while (_p < limit) { - mps_word_t word = *_p; + mps_word_t *p = base; + while (p < limit) { + mps_word_t word = *p; mps_addr_t ref = (mps_addr_t)word; if (MPS_FIX1(ss, ref)) { mps_res_t res = MPS_FIX2(ss, &ref); if (res != MPS_RES_OK) return res; - *_p = (mps_word_t)ref; + *p = (mps_word_t)ref; } - ++_p; + ++p; } } MPS_SCAN_END(ss); From 8366a15a3e03c9fa666b78dd06df359a40535bc3 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 18 Feb 2016 21:00:38 +0000 Subject: [PATCH 156/337] Fixing design documentation of mutatorfaultcontextscan. Copied from Perforce Change: 189314 ServerID: perforce.ravenbrook.com --- mps/design/prmc.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mps/design/prmc.txt b/mps/design/prmc.txt index 0822e709527..43d24a34ec4 100644 --- a/mps/design/prmc.txt +++ b/mps/design/prmc.txt @@ -104,11 +104,11 @@ instruction which was caused the fault to be re-executed. Return This function is only called if ``ProtCanStepInstruction(context)`` returned ``TRUE``. -``Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext context)`` +``Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, mps_area_scan_t scan, void *closure, size_t closure_size)`` _`.if.context.scan`: Scan all roots found in ``context`` using the -given scan state (typically by calling ``TraceScanAreaTagged()``), and -return the result code from the scanner. +given scan state by calling ``scan``, and return the result code from +the scanner. ``Addr MutatorFaultContextSP(MutatorFaultContext context)`` From 724307ce1ec9717df04ac76f2363eebb1334862b Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 18 Feb 2016 21:07:58 +0000 Subject: [PATCH 157/337] Removing check that pattern fits within mask, as this restricts the generality of scan_area. Copied from Perforce Change: 189315 ServerID: perforce.ravenbrook.com --- mps/code/root.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mps/code/root.c b/mps/code/root.c index bdf01a90e30..7e77050e6ed 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -122,7 +122,8 @@ Bool RootCheck(Root root) CHECKL(root->the.area.base != 0); CHECKL(root->the.area.base < root->the.area.limit); CHECKL(FUNCHECK(root->the.area.scan_area)); - CHECKL((~root->the.area.the.tag.mask & root->the.area.the.tag.pattern) == 0); + /* Can't check anything about tag as it could mean anything to + scan_area. */ break; case RootFUN: @@ -132,7 +133,8 @@ Bool RootCheck(Root root) case RootTHREAD_TAGGED: CHECKD_NOSIG(Thread, root->the.thread.thread); /* */ CHECKL(FUNCHECK(root->the.thread.scan_area)); - CHECKL((~root->the.thread.the.tag.mask & root->the.thread.the.tag.pattern) == 0); + /* Can't check anything about tag as it could mean anything to + scan_area. */ /* Can't check anything about stackBot. */ break; From 845e0bedb667d1ebdc25da84ca2ab684d265eb24 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 18 Feb 2016 21:12:00 +0000 Subject: [PATCH 158/337] Lifting closure structure out of areascanunion and using for rootfun as well. clarifying checking of same. Copied from Perforce Change: 189316 ServerID: perforce.ravenbrook.com --- mps/code/root.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/mps/code/root.c b/mps/code/root.c index 7e77050e6ed..1bb4a98d931 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -17,11 +17,13 @@ SRCID(root, "$Id$"); #define RootSig ((Sig)0x51960029) /* SIGnature ROOT */ +typedef struct ClosureStruct { + void *p; + size_t s; +} ClosureStruct; + typedef union AreaScanUnion { - struct { - void *p; - size_t s; - } closure; + ClosureStruct closure; mps_scan_tag_s tag; /* tag for scanning */ } AreaScanUnion; @@ -42,8 +44,7 @@ typedef struct RootStruct { union RootUnion { struct { mps_root_scan_t scan; /* the function which does the scanning */ - void *p; /* environment for scan */ - size_t s; /* environment for scan */ + ClosureStruct closure; /* closure for scan function */ } fun; struct { Word *base; /* beginning of area */ @@ -128,6 +129,8 @@ Bool RootCheck(Root root) case RootFUN: CHECKL(root->the.fun.scan != NULL); + /* Can't check anything about closure as it could mean anything to + scan. */ break; case RootTHREAD_TAGGED: @@ -413,8 +416,8 @@ Res RootCreateFun(Root *rootReturn, Arena arena, Rank rank, AVER(FUNCHECK(scan)); theUnion.fun.scan = scan; - theUnion.fun.p = p; - theUnion.fun.s = s; + theUnion.fun.closure.p = p; + theUnion.fun.closure.s = s; return rootCreate(rootReturn, arena, rank, (RootMode)0, RootFUN, &theUnion); } @@ -552,7 +555,9 @@ Res RootScan(ScanState ss, Root root) break; case RootFUN: - res = (*root->the.fun.scan)(&ss->ss_s, root->the.fun.p, root->the.fun.s); + res = root->the.fun.scan(&ss->ss_s, + root->the.fun.closure.p, + root->the.fun.closure.s); if (res != ResOK) goto failScan; break; @@ -729,7 +734,8 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) res = WriteF(stream, depth + 2, "scan function $F\n", (WriteFF)root->the.fun.scan, "environment p $P s $W\n", - (WriteFP)root->the.fun.p, (WriteFW)root->the.fun.s, + (WriteFP)root->the.fun.closure.p, + (WriteFW)root->the.fun.closure.s, NULL); if (res != ResOK) return res; From 0245c09885be15b46de2ea6763a0862827f35587 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 18 Feb 2016 21:12:28 +0000 Subject: [PATCH 159/337] Fixing indentation of case labels. Copied from Perforce Change: 189317 ServerID: perforce.ravenbrook.com --- mps/code/root.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mps/code/root.c b/mps/code/root.c index 1bb4a98d931..8560aea72a4 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -112,14 +112,14 @@ Bool RootCheck(Root root) /* Don't need to check var here, because of the switch below */ switch(root->var) { - case RootAREA: + case RootAREA: CHECKL(root->the.area.base != 0); CHECKL(root->the.area.base < root->the.area.limit); CHECKL(FUNCHECK(root->the.area.scan_area)); /* Can't check anything about closure */ break; - case RootAREA_TAGGED: + case RootAREA_TAGGED: CHECKL(root->the.area.base != 0); CHECKL(root->the.area.base < root->the.area.limit); CHECKL(FUNCHECK(root->the.area.scan_area)); @@ -127,13 +127,13 @@ Bool RootCheck(Root root) scan_area. */ break; - case RootFUN: + case RootFUN: CHECKL(root->the.fun.scan != NULL); /* Can't check anything about closure as it could mean anything to scan. */ break; - case RootTHREAD_TAGGED: + case RootTHREAD_TAGGED: CHECKD_NOSIG(Thread, root->the.thread.thread); /* */ CHECKL(FUNCHECK(root->the.thread.scan_area)); /* Can't check anything about tag as it could mean anything to @@ -141,13 +141,13 @@ Bool RootCheck(Root root) /* Can't check anything about stackBot. */ break; - case RootFMT: + case RootFMT: CHECKL(root->the.fmt.scan != NULL); CHECKL(root->the.fmt.base != 0); CHECKL(root->the.fmt.base < root->the.fmt.limit); break; - default: + default: NOTREACHED; } CHECKL(RootModeCheck(root->mode)); From ed561e855a2944d6462c3b519dc92c6988e6ce4f Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 18 Feb 2016 21:18:05 +0000 Subject: [PATCH 160/337] Avoid possible type pun hazard of jump buffer by casting to void *. Copied from Perforce Change: 189318 ServerID: perforce.ravenbrook.com --- mps/code/ssan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/ssan.c b/mps/code/ssan.c index 3011eba756f..6d9cc0ff08e 100644 --- a/mps/code/ssan.c +++ b/mps/code/ssan.c @@ -26,7 +26,7 @@ Res StackScan(ScanState ss, Word *stackBot, void *closure, size_t closure_size) { jmp_buf jb; - Word *stackTop = (Word *)&jb; + Word *stackTop = (void *)&jb; /* .assume.stack: This implementation assumes that the stack grows * downwards, so that the address of the jmp_buf is the limit of the From f84e1d8f7e1d504807ab7c94a1bddce99fc92017 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 18 Feb 2016 21:22:05 +0000 Subject: [PATCH 161/337] Fixing leftover sizeof(addr) that should've been changed to sizeof(word). Copied from Perforce Change: 189319 ServerID: perforce.ravenbrook.com --- mps/code/thix.c | 2 +- mps/code/thw3i3.c | 2 +- mps/code/thw3i6.c | 2 +- mps/code/thxc.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mps/code/thix.c b/mps/code/thix.c index 28403d9cae5..6b4118cdaf0 100644 --- a/mps/code/thix.c +++ b/mps/code/thix.c @@ -264,7 +264,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, stackPtr = MutatorFaultContextSP(mfc); /* .stack.align */ - stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr)); + stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Word)); stackLimit = stackBot; if (stackBase >= stackLimit) return ResOK; /* .stack.below-bottom */ diff --git a/mps/code/thw3i3.c b/mps/code/thw3i3.c index e7faa370b77..1624c775102 100644 --- a/mps/code/thw3i3.c +++ b/mps/code/thw3i3.c @@ -98,7 +98,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, stackPtr = (Addr)context.Esp; /* .i3.sp */ /* .stack.align */ - stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr)); + stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Word)); stackLimit = stackBot; if (stackBase >= stackLimit) return ResOK; /* .stack.below-bottom */ diff --git a/mps/code/thw3i6.c b/mps/code/thw3i6.c index f84063013e7..e749b7d7381 100644 --- a/mps/code/thw3i6.c +++ b/mps/code/thw3i6.c @@ -98,7 +98,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, stackPtr = (Addr)context.Rsp; /* .i6.sp */ /* .stack.align */ - stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr)); + stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Word)); stackLimit = stackBot; if (stackBase >= stackLimit) return ResOK; /* .stack.below-bottom */ diff --git a/mps/code/thxc.c b/mps/code/thxc.c index 25bb37e706d..0533aafc422 100644 --- a/mps/code/thxc.c +++ b/mps/code/thxc.c @@ -252,7 +252,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, stackPtr = MutatorFaultContextSP(&mfcStruct); /* .stack.align */ - stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr)); + stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Word)); stackLimit = stackBot; if (stackBase >= stackLimit) return ResOK; /* .stack.below-bottom */ From 266228be7c9700458cbcae815e67205cdb008208 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 18 Feb 2016 23:49:58 +0000 Subject: [PATCH 162/337] Renaming "bottom" and "top" of stack to "cold" and "hot" end, to prevent confusion about descending stacks. Correcting design documentation relating to stacks. Referencing hot and cold end concepts from glossary entry for control stacks. Copied from Perforce Change: 189320 ServerID: perforce.ravenbrook.com --- mps/code/mpm.h | 4 ++-- mps/code/mpsi.c | 24 ++++++++++++------------ mps/code/root.c | 20 ++++++++++---------- mps/code/sc.h | 12 ++++++------ mps/code/ss.c | 16 ++++++++-------- mps/code/ss.h | 16 ++++++++-------- mps/code/ssan.c | 10 +++++----- mps/code/ssixi3.c | 4 ++-- mps/code/ssixi6.c | 4 ++-- mps/code/ssw3i3mv.c | 4 ++-- mps/code/ssw3i3pc.c | 4 ++-- mps/code/ssw3i6mv.c | 4 ++-- mps/code/ssw3i6pc.c | 4 ++-- mps/code/th.h | 2 +- mps/code/than.c | 4 ++-- mps/code/thix.c | 8 ++++---- mps/code/thw3i3.c | 8 ++++---- mps/code/thw3i6.c | 8 ++++---- mps/code/thxc.c | 8 ++++---- mps/design/ss.txt | 19 +++++++++++-------- mps/design/thread-manager.txt | 16 ++++++++-------- mps/manual/source/glossary/c.rst | 2 +- 22 files changed, 102 insertions(+), 99 deletions(-) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 2a2f850963b..3e296dacb2f 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -961,12 +961,12 @@ extern Res RootCreateThread(Root *rootReturn, Arena arena, Rank rank, Thread thread, mps_area_scan_t scan_area, void *closure, size_t closure_size, - Word *stackBot); + Word *stackCold); extern Res RootCreateThreadTagged(Root *rootReturn, Arena arena, Rank rank, Thread thread, mps_area_scan_t scan_area, Word mask, Word pattern, - Word *stackBot); + Word *stackCold); 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 c7cde2d4f5d..f8fdb7e403b 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1417,7 +1417,7 @@ mps_res_t mps_root_create_fmt(mps_root_t *mps_root_o, mps_arena_t arena, mps_res_t mps_root_create_reg(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_reg_scan_t mps_reg_scan, - void *stack, size_t mps_size) + void *cold, size_t mps_size) { Rank rank = (Rank)mps_rank; Root root; @@ -1428,8 +1428,8 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena, AVER(mps_root_o != NULL); AVER(mps_reg_scan != NULL); AVER(mps_reg_scan == mps_stack_scan_ambig); /* .reg.scan */ - AVER(stack != NULL); /* stackBot */ - AVER(AddrIsAligned(stack, sizeof(Word))); + AVER(cold != NULL); + AVER(AddrIsAligned(cold, sizeof(Word))); AVER(rank == mps_rank_ambig()); AVER(mps_rm == (mps_rm_t)0); @@ -1439,7 +1439,7 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena, res = RootCreateThreadTagged(&root, arena, rank, thread, mps_scan_area_tagged, sizeof(mps_word_t) - 1, 0, - (Word *)stack); + (Word *)cold); ArenaLeave(arena); @@ -1475,7 +1475,7 @@ mps_res_t mps_root_create_thread_scanned(mps_root_t *mps_root_o, mps_area_scan_t scan_area, void *closure, size_t closure_size, - void *stack) + void *cold) { Rank rank = (Rank)mps_rank; Root root; @@ -1484,8 +1484,8 @@ mps_res_t mps_root_create_thread_scanned(mps_root_t *mps_root_o, ArenaEnter(arena); AVER(mps_root_o != NULL); - AVER(stack != NULL); /* stackBot */ - AVER(AddrIsAligned(stack, sizeof(Word))); + AVER(cold != NULL); + AVER(AddrIsAligned(cold, sizeof(Word))); AVER(rank == mps_rank_ambig()); AVER(mps_rm == (mps_rm_t)0); AVER(FUNCHECK(scan_area)); @@ -1494,7 +1494,7 @@ mps_res_t mps_root_create_thread_scanned(mps_root_t *mps_root_o, /* See .root-mode. */ res = RootCreateThread(&root, arena, rank, thread, scan_area, closure, closure_size, - (Word *)stack); + (Word *)cold); ArenaLeave(arena); @@ -1513,7 +1513,7 @@ mps_res_t mps_root_create_thread_tagged(mps_root_t *mps_root_o, mps_area_scan_t scan_area, mps_word_t mask, mps_word_t pattern, - void *stack) + void *cold) { Rank rank = (Rank)mps_rank; Root root; @@ -1522,8 +1522,8 @@ mps_res_t mps_root_create_thread_tagged(mps_root_t *mps_root_o, ArenaEnter(arena); AVER(mps_root_o != NULL); - AVER(stack != NULL); /* stackBot */ - AVER(AddrIsAligned(stack, sizeof(Word))); + AVER(cold != NULL); + AVER(AddrIsAligned(cold, sizeof(Word))); AVER(rank == mps_rank_ambig()); AVER(mps_rm == (mps_rm_t)0); AVER(FUNCHECK(scan_area)); @@ -1533,7 +1533,7 @@ mps_res_t mps_root_create_thread_tagged(mps_root_t *mps_root_o, /* See .root-mode. */ res = RootCreateThreadTagged(&root, arena, rank, thread, scan_area, mask, pattern, - (Word *)stack); + (Word *)cold); ArenaLeave(arena); diff --git a/mps/code/root.c b/mps/code/root.c index 8560aea72a4..f1212be9eb4 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -56,7 +56,7 @@ typedef struct RootStruct { Thread thread; /* passed to scan */ mps_area_scan_t scan_area;/* area scanner for stack and registers */ AreaScanUnion the; - Word *stackBot; /* bottom of stack */ + Word *stackCold; /* cold end of stack */ } thread; struct { mps_fmt_scan_t scan; /* format-like scanner */ @@ -138,7 +138,7 @@ Bool RootCheck(Root root) CHECKL(FUNCHECK(root->the.thread.scan_area)); /* Can't check anything about tag as it could mean anything to scan_area. */ - /* Can't check anything about stackBot. */ + /* Can't check anything about stackCold. */ break; case RootFMT: @@ -328,7 +328,7 @@ Res RootCreateThread(Root *rootReturn, Arena arena, Rank rank, Thread thread, mps_area_scan_t scan_area, void *closure, size_t closure_size, - Word *stackBot) + Word *stackCold) { union RootUnion theUnion; @@ -344,7 +344,7 @@ Res RootCreateThread(Root *rootReturn, Arena arena, theUnion.thread.scan_area = scan_area; theUnion.thread.the.closure.p = closure; theUnion.thread.the.closure.s = closure_size; - theUnion.thread.stackBot = stackBot; + theUnion.thread.stackCold = stackCold; return rootCreate(rootReturn, arena, rank, (RootMode)0, RootTHREAD, &theUnion); @@ -354,7 +354,7 @@ Res RootCreateThreadTagged(Root *rootReturn, Arena arena, Rank rank, Thread thread, mps_area_scan_t scan_area, Word mask, Word pattern, - Word *stackBot) + Word *stackCold) { union RootUnion theUnion; @@ -371,7 +371,7 @@ Res RootCreateThreadTagged(Root *rootReturn, Arena arena, theUnion.thread.scan_area = scan_area; theUnion.thread.the.tag.mask = mask; theUnion.thread.the.tag.pattern = pattern; - theUnion.thread.stackBot = stackBot; + theUnion.thread.stackCold = stackCold; return rootCreate(rootReturn, arena, rank, (RootMode)0, RootTHREAD_TAGGED, &theUnion); @@ -564,7 +564,7 @@ Res RootScan(ScanState ss, Root root) case RootTHREAD: res = ThreadScan(ss, root->the.thread.thread, - root->the.thread.stackBot, + root->the.thread.stackCold, root->the.thread.scan_area, root->the.thread.the.closure.p, root->the.thread.the.closure.s); @@ -574,7 +574,7 @@ Res RootScan(ScanState ss, Root root) case RootTHREAD_TAGGED: res = ThreadScan(ss, root->the.thread.thread, - root->the.thread.stackBot, + root->the.thread.stackCold, root->the.thread.scan_area, &root->the.thread.the.tag, sizeof(root->the.thread.the.tag)); @@ -747,7 +747,7 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) "closure $P size $U\n", (WriteFP)root->the.thread.the.closure.p, (WriteFU)root->the.thread.the.closure.s, - "stackBot $P\n", (WriteFP)root->the.thread.stackBot, + "stackCold $P\n", (WriteFP)root->the.thread.stackCold, NULL); if (res != ResOK) return res; @@ -758,7 +758,7 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) "thread $P\n", (WriteFP)root->the.thread.thread, "mask $B\n", (WriteFB)root->the.thread.the.tag.mask, "pattern $B\n", (WriteFB)root->the.thread.the.tag.pattern, - "stackBot $P\n", (WriteFP)root->the.thread.stackBot, + "stackCold $P\n", (WriteFP)root->the.thread.stackCold, NULL); if (res != ResOK) return res; diff --git a/mps/code/sc.h b/mps/code/sc.h index 765c4ccb033..abbae9848c9 100644 --- a/mps/code/sc.h +++ b/mps/code/sc.h @@ -38,7 +38,7 @@ * setjmp magic. */ -/* StackContextStackTop - return the stack top from the stack context. +/* StackContextStackHot - return the stack hot end from the stack context. * * We assume the stack is full. In other words the stack top points at * a word that contains a potential Ref. @@ -68,7 +68,7 @@ typedef struct StackContextStruct { * which we assume to be stored on the stack because it is no longer * needed once we have _longjmp()ed back. So take the minimum of the * SP and the base of the StackContext structure. */ -#define StackContextStackTop(sc) \ +#define StackContextStackHot(sc) \ (StackContextSP(sc) < (Addr*)(sc) ? StackContextSP(sc) : (Addr*)(sc)) @@ -103,7 +103,7 @@ typedef struct StackContextStruct { * which we assume to be stored on the stack because it is no longer * needed once we have _longjmp()ed back. So take the minimum of the * SP and the base of the StackContext structure. */ -#define StackContextStackTop(sc) \ +#define StackContextStackHot(sc) \ (StackContextSP(sc) < (Addr*)(sc) ? StackContextSP(sc) : (Addr*)(sc)) @@ -119,7 +119,7 @@ typedef struct StackContextStruct { #define STACK_CONTEXT_SAVE(sc) ((void)setjmp((sc)->jumpBuffer)) -#define StackContextStackTop(sc) \ +#define StackContextStackHot(sc) \ ((Addr *)((_JUMP_BUFFER *)(sc)->jumpBuffer)->Esp) @@ -135,7 +135,7 @@ typedef struct StackContextStruct { #define STACK_CONTEXT_SAVE(sc) ((void)setjmp((sc)->jumpBuffer)) -#define StackContextStackTop(sc) \ +#define StackContextStackHot(sc) \ ((Addr *)((_JUMP_BUFFER *)(sc)->jumpBuffer)->Rsp) @@ -155,7 +155,7 @@ typedef struct StackContextStruct { #define STACK_CONTEXT_SAVE(sc) ((void)setjmp((sc)->jumpBuffer)) -#define StackContextStackTop(sc) ((Addr *)(sc)->jumpBuffer) +#define StackContextStackHot(sc) ((Addr *)(sc)->jumpBuffer) #endif /* platform defines */ diff --git a/mps/code/ss.c b/mps/code/ss.c index 3d0d68ee34b..c0c109e01d2 100644 --- a/mps/code/ss.c +++ b/mps/code/ss.c @@ -24,7 +24,7 @@ SRCID(ss, "$Id$"); * scanning. */ -Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop, +Res StackScanInner(ScanState ss, Word *stackCold, Word *stackHot, Count nSavedRegs, mps_area_scan_t scan_area, void *closure, size_t closure_size) @@ -33,8 +33,8 @@ Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop, Res res; AVERT(ScanState, ss); - AVER(stackTop < stackBot); - AVER(AddrIsAligned((Addr)stackTop, sizeof(Addr))); /* .assume.align */ + AVER(stackHot < stackCold); + AVER(AddrIsAligned((Addr)stackHot, sizeof(Addr))); /* .assume.align */ AVER(0 < nSavedRegs); AVER(nSavedRegs < 128); /* sanity check */ @@ -47,18 +47,18 @@ Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop, (trans.c). Otherwise, scan the whole stack. */ if (arena->stackAtArenaEnter != NULL) { - AVER(stackTop < arena->stackAtArenaEnter); - AVER(arena->stackAtArenaEnter < stackBot); - res = TraceScanArea(ss, stackTop, stackTop + nSavedRegs, + AVER(stackHot < arena->stackAtArenaEnter); + AVER(arena->stackAtArenaEnter < stackCold); + res = TraceScanArea(ss, stackHot, stackHot + nSavedRegs, scan_area, closure, closure_size); if (res != ResOK) return res; - res = TraceScanArea(ss, arena->stackAtArenaEnter, stackBot, + res = TraceScanArea(ss, arena->stackAtArenaEnter, stackCold, scan_area, closure, closure_size); if (res != ResOK) return res; } else { - res = TraceScanArea(ss, stackTop, stackBot, + res = TraceScanArea(ss, stackHot, stackCold, scan_area, closure, closure_size); if (res != ResOK) return res; diff --git a/mps/code/ss.h b/mps/code/ss.h index b186535edf2..02dc34f9fcf 100644 --- a/mps/code/ss.h +++ b/mps/code/ss.h @@ -14,30 +14,30 @@ /* StackScan -- scan the current thread's stack * - * StackScan scans the stack of the current thread, Between stackBot and the - * current top of stack. It also fixes any roots which may be in callee-save - * registers. + * StackScan scans the stack of the current thread, Between stackCold + * and the current hot end of the stack. It also fixes any roots which + * may be in callee-save registers. * * See the specific implementation for the exact registers which are scanned. * * If a stack pointer has been stashed at arena entry (through the MPS * interface in mpsi*.c) then only the registers and the stack between - * stackAtArenaEnter and stackBot is scanned, to avoid scanning false + * stackAtArenaEnter and stackCold is scanned, to avoid scanning false * ambiguous references on the MPS's own stack. This is particularly * important for transforms (trans.c). * - * The word pointed to by stackBot is fixed if the stack is by convention + * The word pointed to by stackCold is fixed if the stack is by convention * empty, and not fixed if it is full. Where empty means sp points to first * free word beyond the top of stack. Full means sp points to the top of * stack itself. */ -extern Res StackScan(ScanState ss, Word *stackBot, +extern Res StackScan(ScanState ss, Word *stackCold, mps_area_scan_t scan_area, void *closure, size_t closure_size); -extern Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop, +extern Res StackScanInner(ScanState ss, Word *stackCold, Word *stackHot, Count nSavedRegs, mps_area_scan_t scan_area, - void *closure, size_t closure_s); + void *closure, size_t closure_size); #endif /* ss_h */ diff --git a/mps/code/ssan.c b/mps/code/ssan.c index 6d9cc0ff08e..cbb0daa4dd2 100644 --- a/mps/code/ssan.c +++ b/mps/code/ssan.c @@ -21,23 +21,23 @@ SRCID(ssan, "$Id$"); -Res StackScan(ScanState ss, Word *stackBot, +Res StackScan(ScanState ss, Word *stackCold, mps_area_scan_t scan_area, void *closure, size_t closure_size) { jmp_buf jb; - Word *stackTop = (void *)&jb; + Word *stackHot = (void *)&jb; /* .assume.stack: This implementation assumes that the stack grows - * downwards, so that the address of the jmp_buf is the limit of the + * downwards, so that the address of the jmp_buf is the base of the * part of the stack that needs to be scanned. (StackScanInner makes * the same assumption.) */ - AVER(stackTop < stackBot); + AVER(stackHot < stackCold); (void)setjmp(jb); - return StackScanInner(ss, stackBot, stackTop, sizeof jb / sizeof(Word), + return StackScanInner(ss, stackCold, stackHot, sizeof jb / sizeof(Word), scan_area, closure, closure_size); } diff --git a/mps/code/ssixi3.c b/mps/code/ssixi3.c index d3273d4e674..56fb1290a66 100644 --- a/mps/code/ssixi3.c +++ b/mps/code/ssixi3.c @@ -49,7 +49,7 @@ SRCID(ssixi3, "$Id$"); #define ASMV(x) __asm__ volatile (x) -Res StackScan(ScanState ss, Word *stackBot, +Res StackScan(ScanState ss, Word *stackCold, mps_area_scan_t scan_area, void *closure, size_t closure_size) { @@ -64,7 +64,7 @@ Res StackScan(ScanState ss, Word *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, stackCold, calleeSaveRegs, NELEMS(calleeSaveRegs), scan_area, closure, closure_size); } diff --git a/mps/code/ssixi6.c b/mps/code/ssixi6.c index ee07136dfad..71a3dd40cf2 100644 --- a/mps/code/ssixi6.c +++ b/mps/code/ssixi6.c @@ -47,7 +47,7 @@ SRCID(ssixi6, "$Id$"); #define ASMV(x) __asm__ volatile (x) -Res StackScan(ScanState ss, Word *stackBot, +Res StackScan(ScanState ss, Word *stackCold, mps_area_scan_t scan_area, void *closure, size_t closure_size) { @@ -64,7 +64,7 @@ Res StackScan(ScanState ss, Word *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, stackCold, calleeSaveRegs, NELEMS(calleeSaveRegs), scan_area, closure, closure_size); } diff --git a/mps/code/ssw3i3mv.c b/mps/code/ssw3i3mv.c index cbc63da3e0e..da95ebb106d 100644 --- a/mps/code/ssw3i3mv.c +++ b/mps/code/ssw3i3mv.c @@ -22,7 +22,7 @@ SRCID(ssw3i3mv, "$Id$"); -Res StackScan(ScanState ss, Word *stackBot, +Res StackScan(ScanState ss, Word *stackCold, mps_area_scan_t scan_area, void *closure, size_t closure_size) { @@ -44,7 +44,7 @@ Res StackScan(ScanState ss, Word *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, (Word *)&((_JUMP_BUFFER *)jb)->Ebx, 3, + return StackScanInner(ss, stackCold, (Word *)&((_JUMP_BUFFER *)jb)->Ebx, 3, scan_area, closure, closure_size); } diff --git a/mps/code/ssw3i3pc.c b/mps/code/ssw3i3pc.c index 4e75dac247c..913a3d5a035 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, Word *stackBot, +Res StackScan(ScanState ss, Word *stackCold, mps_area_scan_t scan_area, void *closure, size_t closure_size) { @@ -67,7 +67,7 @@ Res StackScan(ScanState ss, Word *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, (Word *)&((_JUMP_BUFFER *)jb)->Ebx, 3, + return StackScanInner(ss, stackCold, (Word *)&((_JUMP_BUFFER *)jb)->Ebx, 3, scan_area, closure, closure_size); } diff --git a/mps/code/ssw3i6mv.c b/mps/code/ssw3i6mv.c index f3b140b8065..9bc3a8e573b 100644 --- a/mps/code/ssw3i6mv.c +++ b/mps/code/ssw3i6mv.c @@ -30,7 +30,7 @@ SRCID(ssw3i6mv, "$Id$"); -Res StackScan(ScanState ss, Word *stackBot, +Res StackScan(ScanState ss, Word *stackCold, mps_area_scan_t scan_area, void *closure, size_t closure_size) { @@ -63,7 +63,7 @@ Res StackScan(ScanState ss, Word *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, (Word *)&((_JUMP_BUFFER *)jb)->Rbx, 9, + return StackScanInner(ss, stackCold, (Word *)&((_JUMP_BUFFER *)jb)->Rbx, 9, scan_area, closure, closure_size); } diff --git a/mps/code/ssw3i6pc.c b/mps/code/ssw3i6pc.c index 7ae89fb85ea..5e8818282ac 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, Word *stackBot, Word mask, Word pattern) +Res StackScan(ScanState ss, Word *stackCold, Word mask, Word pattern) { jmp_buf jb; @@ -99,7 +99,7 @@ Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern) AVER(offsetof(_JUMP_BUFFER, R14) == offsetof(_JUMP_BUFFER, Rbx) + 56); AVER(offsetof(_JUMP_BUFFER, R15) == offsetof(_JUMP_BUFFER, Rbx) + 64); - return StackScanInner(ss, stackBot, (Word *)&((_JUMP_BUFFER *)jb)->Rbx, 9, + return StackScanInner(ss, stackCold, (Word *)&((_JUMP_BUFFER *)jb)->Rbx, 9, mask, pattern); } diff --git a/mps/code/th.h b/mps/code/th.h index 65064ecaafa..39f1d91133b 100644 --- a/mps/code/th.h +++ b/mps/code/th.h @@ -68,7 +68,7 @@ extern Thread ThreadRingThread(Ring threadRing); extern Arena ThreadArena(Thread thread); -extern Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, +extern Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, mps_area_scan_t scan_area, void *closure, size_t closure_size); diff --git a/mps/code/than.c b/mps/code/than.c index 63a6b8628a3..cf41e02f50b 100644 --- a/mps/code/than.c +++ b/mps/code/than.c @@ -117,12 +117,12 @@ Arena ThreadArena(Thread thread) } -Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, +Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, mps_area_scan_t scan_area, void *closure, size_t closure_size) { UNUSED(thread); - return StackScan(ss, stackBot, scan_area, closure, closure_size); + return StackScan(ss, stackCold, scan_area, closure, closure_size); } diff --git a/mps/code/thix.c b/mps/code/thix.c index 6b4118cdaf0..6e51d2a5d5f 100644 --- a/mps/code/thix.c +++ b/mps/code/thix.c @@ -239,7 +239,7 @@ Arena ThreadArena(Thread thread) /* ThreadScan -- scan the state of a thread (stack and regs) */ -Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, +Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, mps_area_scan_t scan_area, void *closure, size_t closure_size) { @@ -251,7 +251,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, if(pthread_equal(self, thread->id)) { /* scan this thread's stack */ AVER(thread->alive); - res = StackScan(ss, stackBot, scan_area, closure, closure_size); + res = StackScan(ss, stackCold, scan_area, closure, closure_size); if(res != ResOK) return res; } else if (thread->alive) { @@ -265,12 +265,12 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, stackPtr = MutatorFaultContextSP(mfc); /* .stack.align */ stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Word)); - stackLimit = stackBot; + stackLimit = stackCold; if (stackBase >= stackLimit) return ResOK; /* .stack.below-bottom */ /* scan stack inclusive of current sp and exclusive of - * stackBot (.stack.full-descend) + * stackCold (.stack.full-descend) */ res = TraceScanArea(ss, stackBase, stackLimit, scan_area, closure, closure_size); diff --git a/mps/code/thw3i3.c b/mps/code/thw3i3.c index 1624c775102..e5fa73a8082 100644 --- a/mps/code/thw3i3.c +++ b/mps/code/thw3i3.c @@ -67,7 +67,7 @@ SRCID(thw3i3, "$Id$"); -Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, +Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, mps_area_scan_t scan_area, void *closure, size_t closure_size) { @@ -99,12 +99,12 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, stackPtr = (Addr)context.Esp; /* .i3.sp */ /* .stack.align */ stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Word)); - stackLimit = stackBot; + stackLimit = stackCold; if (stackBase >= stackLimit) return ResOK; /* .stack.below-bottom */ /* scan stack inclusive of current sp and exclusive of - * stackBot (.stack.full-descend) + * stackCold (.stack.full-descend) */ res = TraceScanArea(ss, stackBase, stackLimit, scan_area, closure, closure_size); @@ -123,7 +123,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, return res; } else { /* scan this thread's stack */ - res = StackScan(ss, stackBot, scan_area, closure, closure_size); + res = StackScan(ss, stackCold, scan_area, closure, closure_size); if(res != ResOK) return res; } diff --git a/mps/code/thw3i6.c b/mps/code/thw3i6.c index e749b7d7381..090c2c43aa9 100644 --- a/mps/code/thw3i6.c +++ b/mps/code/thw3i6.c @@ -67,7 +67,7 @@ SRCID(thw3i6, "$Id$"); -Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, +Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, mps_area_scan_t scan_area, void *closure, size_t closure_size) { @@ -99,12 +99,12 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, stackPtr = (Addr)context.Rsp; /* .i6.sp */ /* .stack.align */ stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Word)); - stackLimit = stackBot; + stackLimit = stackCold; if (stackBase >= stackLimit) return ResOK; /* .stack.below-bottom */ /* scan stack inclusive of current sp and exclusive of - * stackBot (.stack.full-descend) + * stackCold (.stack.full-descend) */ res = TraceScanArea(ss, stackBase, stackLimit, scan_area, closure, closure_size); @@ -123,7 +123,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, return res; } else { /* scan this thread's stack */ - res = StackScan(ss, stackBot, scan_area, closure, closure_size); + res = StackScan(ss, stackCold, scan_area, closure, closure_size); if(res != ResOK) return res; } diff --git a/mps/code/thxc.c b/mps/code/thxc.c index 0533aafc422..e5277072dc5 100644 --- a/mps/code/thxc.c +++ b/mps/code/thxc.c @@ -210,7 +210,7 @@ Arena ThreadArena(Thread thread) #include "prmcxc.h" -Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, +Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, mps_area_scan_t scan_area, void *closure, size_t closure_size) { @@ -223,7 +223,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, if (thread->port == self) { /* scan this thread's stack */ AVER(thread->alive); - res = StackScan(ss, stackBot, scan_area, closure, closure_size); + res = StackScan(ss, stackCold, scan_area, closure, closure_size); if(res != ResOK) return res; } else if (thread->alive) { @@ -253,12 +253,12 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackBot, stackPtr = MutatorFaultContextSP(&mfcStruct); /* .stack.align */ stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Word)); - stackLimit = stackBot; + stackLimit = stackCold; if (stackBase >= stackLimit) return ResOK; /* .stack.below-bottom */ /* scan stack inclusive of current sp and exclusive of - * stackBot (.stack.full-descend) + * stackCold (.stack.full-descend) */ res = TraceScanArea(ss, stackBase, stackLimit, scan_area, closure, closure_size); diff --git a/mps/design/ss.txt b/mps/design/ss.txt index 60b5c2817fa..7489ad3537f 100644 --- a/mps/design/ss.txt +++ b/mps/design/ss.txt @@ -66,21 +66,24 @@ been spilled onto the stack by the time the MPS is entered, so will be scanned by the stack scan. Floating-point registers and debugging registers do not, as far as we are aware, contain pointers. -_`.sol.inner`: Having located the top of the stack (``stackTop``), and -spilled the root registers into the next ``n`` words, implementations -call the generic function ``StackScanInner(ss, stackBot, stackTop, -n)`` to actually do the scanning. +_`.sol.inner`: Having located the hot end of the stack (``stackHot``), +and spilled the root registers into the next ``n`` words, +implementations call the generic higher-order function +``StackScanInner(ss, stackCold, stackHot, n, scan_area, closure, +closure_size)`` to actually do the scanning. Interface --------- -``Res StackScan(ScanState ss, Addr *stackBot)`` +``Res StackScan(ScanState ss, Word *stackCold, + mps_area_scan_t scan_area, + void *closure, size_t closure_size)`` _`.if.scan`: Scan the root registers of the current thread, and the -control stack between ``stackBot`` and the top of the stack, in the -context of the given scan state. Return ``ResOK`` if successful, or -another result code if not. +control stack between ``stackCold`` and the hot end of the stack, in +the context of the given scan state, using ``scan_area``. Return +``ResOK`` if successful, or another result code if not. Issue diff --git a/mps/design/thread-manager.txt b/mps/design/thread-manager.txt index 48cbb912533..686ad8d3381 100644 --- a/mps/design/thread-manager.txt +++ b/mps/design/thread-manager.txt @@ -153,15 +153,15 @@ threads are discovered to have terminated, move them to ``deadRing``. _`.if.ring.thread`: Return the thread that owns the given element of the thread ring. -``Res ThreadScan(ScanState ss, Thread thread, void *stackBot)`` +``Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, mps_area_scan_t scan_area, void *closure, size_t closure_size)`` -_`.if.scan`: Scan the stacks and root registers of ``thread``, -treating each value found as an ambiguous reference. ``stackBot`` -points to the "bottom" of the thread's stack---this is the value that -was supplied by the client program when it called -``mps_root_create_reg()``. In the common case, where the stack grows -downwards, ``stackBot`` is actually the highest stack address. Return -``ResOK`` if successful, another result code otherwise. +_`.if.scan`: Scan the stacks and root registers of ``thread``, using +``ss`` and ``scan_area``. ``stackCold`` points to the cold end of the +thread's stack---this is the value that was supplied by the client +program when it called ``mps_root_create_thread()``. In the common +case, where the stack grows downwards, ``stackCold`` is the highest +stack address. Return ``ResOK`` if successful, another result code +otherwise. Implementations diff --git a/mps/manual/source/glossary/c.rst b/mps/manual/source/glossary/c.rst index afa39c9e437..90201002ee3 100644 --- a/mps/manual/source/glossary/c.rst +++ b/mps/manual/source/glossary/c.rst @@ -589,7 +589,7 @@ Memory Management Glossary: C .. similar:: :term:`stack`. - .. seealso:: :term:`data stack`. + .. seealso:: :term:`cold end`, :term:`data stack`, :term:`hot end`. cool From 890b7ddeb19f261869ac1e1068d1e07cbc046daf Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 18 Feb 2016 23:57:54 +0000 Subject: [PATCH 163/337] Clarifying that the pointer passed to thread root registration is the cold end of the stack. Copied from Perforce Change: 189321 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/root.rst | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index 4ffdf8727bd..e07b5cafab2 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -165,12 +165,12 @@ registers a thread root and then calls the program:: mps_thr_t thread; mps_root_t stack_root; int exit_code; - void *marker = ▮ + void *cold = &cold; res = mps_thread_reg(&thread, arena); if (res != MPS_RES_OK) error("Couldn't register thread"); - res = mps_root_create_thread(&stack_root, arena, thread, marker); + res = mps_root_create_thread(&stack_root, arena, thread, cold); if (res != MPS_RES_OK) error("Couldn't create root"); exit_code = start(argc, argv); @@ -387,7 +387,7 @@ Root interface calling :c:func:`mps_root_destroy`. -.. c:function:: mps_res_t mps_root_create_thread(mps_root_t *root_o, mps_arena_t arena, mps_thr_t thr, void *stack) +.. c:function:: mps_res_t mps_root_create_thread(mps_root_t *root_o, mps_arena_t arena, mps_thr_t thr, void *cold) Register a :term:`root` that consists of the :term:`references` in a :term:`thread's ` registers and stack that are word aligned. @@ -403,9 +403,9 @@ Root interface mps_scan_area_tagged, sizeof(mps_word_t) - 1, 0, - stack); + cold); -.. c:function:: mps_res_t mps_root_create_thread_tagged(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thr, mps_area_scan_t scan_area, mps_word_t mask, mps_word_t pattern, void *stack) +.. c:function:: mps_res_t mps_root_create_thread_tagged(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thr, mps_area_scan_t scan_area, mps_word_t mask, mps_word_t pattern, void *cold) Register a :term:`root` that consists of the :term:`references` in a :term:`thread's ` registers and stack that match a @@ -437,9 +437,10 @@ Root interface :c:func:`mps_scan_area_tagged` will not consider any word that is unequal to this (after masking with ``mask``) 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. + ``cold`` is a pointer to the :term:`cold end` of stack to be + scanned. 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 @@ -487,7 +488,7 @@ Root interface 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_thread_scanned(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thread, mps_area_scan_t scan_area, void *closure, size_t closure_size, void *stack) +.. c:function:: mps_res_t mps_root_create_thread_scanned(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thread, mps_area_scan_t scan_area, void *closure, size_t closure_size, void *cold) Register a :term:`root` that consists of the :term:`references` in a :term:`thread's ` registers and stack, scanned by an @@ -516,9 +517,10 @@ Root interface ``scan_area`` but is conventionally the size of the parameter object pointer to by ``closure``. - ``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. + ``cold`` is a pointer to the :term:`cold end` of stack to be + scanned. 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 From fd957d9eab4b07b57af492dad7ce54ee76e3dd0f Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 19 Feb 2016 00:10:12 +0000 Subject: [PATCH 164/337] Miscellaneous root documentation fixes from review. Copied from Perforce Change: 189322 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/root.rst | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index e07b5cafab2..048b39bf7d7 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -104,6 +104,9 @@ scan it for references: :term:`registers` and :term:`control stack` of a thread. See :ref:`topic-root-thread` below. +Several of these categories of roots have variants for dealing with +:term:`tagged references`. See :ref:`topic-scanning-tag`. + .. index:: pair: root; cautions @@ -461,12 +464,12 @@ Root interface You can avoid this risk in several ways: - #. Choosing to tag pointers with zero, setting ``scan_area`` - as :c:func:`mps_scan_area_tagged` and setting ``pattern`` - to zero. + #. Choose to tag pointers with zero, setting ``scan_area`` to + :c:func:`mps_scan_area_tagged` and setting ``pattern`` to + zero. #. Set ``scan_area`` to :c:func:`mps_scan_area_tagged_or_zero` - so that untagged pointers are scanned. Thist may lead to + so that untagged pointers are scanned. This may lead to some additional scanning and retention. #. Use :c:func:`mps_root_create_thread_scanned` and set @@ -484,9 +487,10 @@ Root interface .. 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. + of the top bits in ``mask`` and ``pattern`` 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_thread_scanned(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thread, mps_area_scan_t scan_area, void *closure, size_t closure_size, void *cold) From 6e062e10bd8947cc5134f08967e2c15f639a2fb9 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 19 Feb 2016 00:15:23 +0000 Subject: [PATCH 165/337] Miscellaneous scanning documentation fixes from review. Copied from Perforce Change: 189323 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/root.rst | 10 +++++----- mps/manual/source/topic/scanning.rst | 8 +++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index 048b39bf7d7..2b24823f051 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -429,7 +429,7 @@ Root interface to scan the threads registers and stack, for example :c:func:`mps_scan_area_tagged` or :c:func:`mps_scan_area_tagged_or_zero`. See - :ref:`topic-area-scanners`. + :ref:`topic-scanning-area`. ``mask`` is a :term:`bitmask` that is passed to ``scan_area`` to be applied to the thread's registers and stack to locate the @@ -512,7 +512,7 @@ Root interface ``scan_area`` is an area scanning function that will be used to scan the threads registers and stack, for example :c:func:`mps_scan_area`, or a similar user-defined function. See - :ref:`topic-area-scanners`. + :ref:`topic-scanning-area`. ``closure`` is an arbitrary pointer that is passed to ``scan_area`` and intended to point to any parameters it needs. @@ -554,7 +554,7 @@ Root interface ``scan_area`` is an area scanning function, for example :c:func:`mps_scan_area`, or a similar user-defined function. See - :ref:`topic-area-scanners`. + :ref:`topic-scanning-area`. ``closure`` is an arbitrary pointer that is passed to ``scan_area`` and intended to point to any parameters it needs. @@ -592,7 +592,7 @@ Root interface ``scan_area`` is an tagged area scanning function that will be used to scan the table, for example :c:func:`mps_scan_area_tagged` or :c:func:`mps_scan_area_tagged_or_zero`. See - :ref:`topic-area-scanners`. + :ref:`topic-scanning-area`. ``mask`` is a :term:`bitmask` that is passed to ``scan_area`` to be applied to the words in the vector to locate the :term:`tag`. @@ -686,7 +686,7 @@ Root interface ``scan_area`` is an tagged area scanning function that will be used to scan the table, for example :c:func:`mps_scan_area_tagged` or :c:func:`mps_scan_area_tagged_or_zero`. See - :ref:`topic-area-scanners`. + :ref:`topic-scanning-area`. ``mask`` is a :term:`bitmask` that is passed to ``scan_area`` to be applied to the words in the vector to locate the :term:`tag`. diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst index a22969cb8f4..dcf270b80df 100644 --- a/mps/manual/source/topic/scanning.rst +++ b/mps/manual/source/topic/scanning.rst @@ -506,13 +506,13 @@ Fixing interface .. index:: single: scanning; area scanners -.. _topic-area-scanners: +.. _topic-scanning-area: Area scanners ------------- An area scanner :term:`scans` an area of memory for -:term:`refrerences `. Various functions in the MPS interface, +:term:`references `. Various functions in the MPS interface, :such as :c:func:`mps_root_create_thread_tagged`, accept area scanners as arguments so that the :term:`client program` can specify how to scan special areas such as the :term:`control stack`. @@ -585,7 +585,9 @@ the scanners, found in ``scan.c`` in the MPS source code. .. c:function:: mps_res_t mps_scan_area_masked(mps_ss_t ss, mps_word_t *base, mps_word_t *limit, void *closure, size_t closure_size) - Scan an area of memory :term:`fixing ` every word, but but remove tag bits before fixing references, and restore them afterwards. ``closure`` should point to an :c:type:`mps_scan_tag_s`. + Scan an area of memory :term:`fixing ` every word, but remove + tag bits before fixing references, and restore them afterwards. + ``closure`` should point to an :c:type:`mps_scan_tag_s`. For example, if ``mask`` is 0b111 (decimal 7), then this scanner will clear the bottom three bits of each word before fixing. A word From b771a2112a2eff439caba71237b0a36ffc456759 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 19 Feb 2016 00:23:54 +0000 Subject: [PATCH 166/337] Implementing mps_root_create_area_tagged as documented. Copied from Perforce Change: 189324 ServerID: perforce.ravenbrook.com --- mps/code/mps.h | 5 +++++ mps/code/mpsi.c | 37 +++++++++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/mps/code/mps.h b/mps/code/mps.h index 2856cc16c7e..a6495f0dd88 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -690,6 +690,11 @@ extern mps_res_t mps_root_create_area(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_word_t *, mps_word_t *, mps_area_scan_t, void *, size_t); +extern mps_res_t mps_root_create_area_tagged(mps_root_t *, mps_arena_t, + mps_rank_t, mps_rm_t, + mps_word_t *, mps_word_t *, + mps_area_scan_t, + mps_word_t, mps_word_t); extern mps_res_t mps_root_create_fmt(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_fmt_scan_t, mps_addr_t, diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index f8fdb7e403b..cb3c7c894a5 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1345,13 +1345,15 @@ mps_res_t mps_root_create_area(mps_root_t *mps_root_o, return MPS_RES_OK; } -mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, - mps_arena_t arena, - mps_rank_t mps_rank, mps_rm_t mps_rm, - mps_addr_t *base, size_t size, - mps_area_scan_t scan_area, - mps_word_t mask, - mps_word_t pattern) +mps_res_t mps_root_create_area_tagged(mps_root_t *mps_root_o, + mps_arena_t arena, + mps_rank_t mps_rank, + mps_rm_t mps_rm, + mps_word_t *base, + mps_word_t *limit, + mps_area_scan_t scan_area, + mps_word_t mask, + mps_word_t pattern) { Rank rank = (Rank)mps_rank; Root root; @@ -1362,14 +1364,14 @@ mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, AVER(mps_root_o != NULL); AVER(base != NULL); - AVER(size > 0); + AVER(limit != NULL); + AVER(base < limit); AVER(FUNCHECK(scan_area)); /* Can't check anything about mask or pattern, as they could mean anything to scan_area. */ - /* .root.table-size */ res = RootCreateAreaTagged(&root, arena, rank, mode, - (void *)base, (void *)(base + size), + base, limit, scan_area, mask, pattern); ArenaLeave(arena); @@ -1379,6 +1381,21 @@ mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, *mps_root_o = (mps_root_t)root; return MPS_RES_OK; } + + +mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, + mps_arena_t arena, + mps_rank_t mps_rank, mps_rm_t mps_rm, + mps_addr_t *base, size_t size, + mps_area_scan_t scan_area, + mps_word_t mask, + mps_word_t pattern) +{ + return mps_root_create_area_tagged(mps_root_o, arena, mps_rank, mps_rm, + (void *)base, (void *)(base + size), + scan_area, mask, pattern); +} + mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, mps_arena_t arena, From 8a4e5ab290ecf3ec5aa23ecda4041d0ccf557541 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 19 Feb 2016 12:07:59 +0000 Subject: [PATCH 167/337] Moving scanning accounting to tracescanarea and creating analogous formatscan. Copied from Perforce Change: 189325 ServerID: perforce.ravenbrook.com --- mps/code/format.c | 30 ++++++++++++++++++++++++++++++ mps/code/mpm.h | 1 + mps/code/poolamc.c | 19 ++++++------------- mps/code/poolams.c | 11 +++++------ mps/code/poolawl.c | 4 +--- mps/code/poolsnc.c | 4 +--- mps/code/root.c | 2 -- mps/code/trace.c | 17 +++++++++++++---- 8 files changed, 57 insertions(+), 31 deletions(-) diff --git a/mps/code/format.c b/mps/code/format.c index 07a8319082a..26b3e4bb751 100644 --- a/mps/code/format.c +++ b/mps/code/format.c @@ -190,6 +190,36 @@ Arena FormatArena(Format format) } +/* FormatScan -- scan formatted objects for references + * + * This is a wrapper for formatted objects scanning functions, which + * should not otherwise be called directly from within the MPS. This + * function checks arguments and takes care of accounting for the + * scanned memory. + * + * c.f. TraceScanArea() + */ + +Res FormatScan(Format format, ScanState ss, Addr base, Addr limit) +{ + /* TODO: How critical are these? */ + AVERT_CRITICAL(Format, format); + AVERT_CRITICAL(ScanState, ss); + AVER_CRITICAL(base != NULL); + AVER_CRITICAL(limit != NULL); + AVER_CRITICAL(base < limit); + + /* TODO: EVENT here? */ + + /* scannedSize is accumulated whether or not format->scan succeeds, + so it's safe to accumulate now so that we can tail-call + format->scan. */ + ss->scannedSize += AddrOffset(base, limit); + + return format->scan(&ss->ss_s, base, limit); +} + + /* FormatDescribe -- describe a format */ Res FormatDescribe(Format format, mps_lib_FILE *stream, Count depth) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 3e296dacb2f..214ad8c4cad 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -845,6 +845,7 @@ extern Res FormatCreate(Format *formatReturn, Arena arena, ArgList args); extern void FormatDestroy(Format format); extern Arena FormatArena(Format format); extern Res FormatDescribe(Format format, mps_lib_FILE *stream, Count depth); +extern Res FormatScan(Format format, ScanState ss, Addr base, Addr limit); /* Reference Interface -- see */ diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index dfe3cfc37d9..28fcbd7e8bd 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -1249,7 +1249,7 @@ static Res AMCWhiten(Pool pool, Trace trace, Seg seg) * addresses in a nailed segment. */ static Res amcScanNailedRange(Bool *totalReturn, Bool *moreReturn, - Size *bytesScanned, ScanState ss, + ScanState ss, AMC amc, Nailboard board, Addr base, Addr limit) { @@ -1265,14 +1265,12 @@ static Res amcScanNailedRange(Bool *totalReturn, Bool *moreReturn, Addr q; q = (*format->skip)(p); if ((*amc->pinned)(amc, board, p, q)) { - Res res; - res = (*format->scan)(&ss->ss_s, p, q); + Res res = FormatScan(format, ss, p, q); if(res != ResOK) { *totalReturn = FALSE; *moreReturn = TRUE; return res; } - *bytesScanned += AddrOffset(p, q); } else { *totalReturn = FALSE; } @@ -1297,7 +1295,6 @@ static Res amcScanNailedOnce(Bool *totalReturn, Bool *moreReturn, ScanState ss, Seg seg, AMC amc) { Addr p, limit; - Size bytesScanned = 0; Nailboard board; Res res; @@ -1314,7 +1311,7 @@ static Res amcScanNailedOnce(Bool *totalReturn, Bool *moreReturn, AVER(p == limit); goto returnGood; } - res = amcScanNailedRange(totalReturn, moreReturn, &bytesScanned, + res = amcScanNailedRange(totalReturn, moreReturn, ss, amc, board, p, limit); if (res != ResOK) return res; @@ -1323,7 +1320,7 @@ static Res amcScanNailedOnce(Bool *totalReturn, Bool *moreReturn, limit = SegLimit(seg); /* @@@@ Shouldn't p be set to BufferLimit here?! */ - res = amcScanNailedRange(totalReturn, moreReturn, &bytesScanned, + res = amcScanNailedRange(totalReturn, moreReturn, ss, amc, board, p, limit); if (res != ResOK) return res; @@ -1331,8 +1328,6 @@ static Res amcScanNailedOnce(Bool *totalReturn, Bool *moreReturn, returnGood: EVENT3(AMCScanEnd, amc, seg, ss); /* TODO: consider using own event */ - AVER(bytesScanned <= SegSize(seg)); - ss->scannedSize += bytesScanned; *moreReturn = NailboardNewNails(board); return ResOK; } @@ -1423,12 +1418,11 @@ static Res AMCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg) *totalReturn = TRUE; return ResOK; } - res = (*format->scan)(&ss->ss_s, base, limit); + res = FormatScan(format, ss, base, limit); if(res != ResOK) { *totalReturn = FALSE; return res; } - ss->scannedSize += AddrOffset(base, limit); base = limit; } @@ -1437,14 +1431,13 @@ static Res AMCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg) AVER(SegBase(seg) <= base); AVER(base <= AddrAdd(SegLimit(seg), format->headerSize)); if(base < limit) { - res = (*format->scan)(&ss->ss_s, base, limit); + res = FormatScan(format, ss, base, limit); if(res != ResOK) { *totalReturn = FALSE; return res; } } - ss->scannedSize += AddrOffset(base, limit); EVENT3(AMCScanEnd, amc, seg, ss); *totalReturn = TRUE; diff --git a/mps/code/poolams.c b/mps/code/poolams.c index 3f7f170ddbc..d3ecfa47028 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -1318,12 +1318,12 @@ static Res amsScanObject(Seg seg, Index i, Addr p, Addr next, void *clos) /* @@@@ This isn't quite right for multiple traces. */ if (closure->scanAllObjects || AMS_IS_GREY(seg, i)) { - res = (*format->scan)(&closure->ss->ss_s, - AddrAdd(p, format->headerSize), - AddrAdd(next, format->headerSize)); + res = FormatScan(format, + closure->ss, + AddrAdd(p, format->headerSize), + AddrAdd(next, format->headerSize)); if (res != ResOK) return res; - closure->ss->scannedSize += AddrOffset(p, next); if (!closure->scanAllObjects) { Index j = AMS_ADDR_INDEX(seg, next); AVER(!AMS_IS_INVALID_COLOUR(seg, i)); @@ -1412,7 +1412,7 @@ Res AMSScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg) next = AddrAdd(p, alignment); } j = AMS_ADDR_INDEX(seg, next); - res = (*format->scan)(&ss->ss_s, clientP, clientNext); + res = FormatScan(format, ss, clientP, clientNext); if (res != ResOK) { /* */ amsseg->marksChanged = TRUE; @@ -1422,7 +1422,6 @@ Res AMSScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg) /* Check that there haven't been any ambiguous fixes during the */ /* scan, because AMSFindGrey won't work otherwise. */ AVER_CRITICAL(!amsseg->ambiguousFixes); - ss->scannedSize += AddrOffset(p, next); AMS_GREY_BLACKEN(seg, i); if (i+1 < j) AMS_RANGE_WHITE_BLACKEN(seg, i+1, j); diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 5bb0e6b9025..738194f26c8 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -901,9 +901,7 @@ static Res awlScanObject(Arena arena, AWL awl, ScanState ss, SegSetSummary(dependentSeg, RefSetUNIV); } - res = (*format->scan)(&ss->ss_s, base, limit); - if (res == ResOK) - ss->scannedSize += AddrOffset(base, limit); + res = FormatScan(format, ss, base, limit); if (dependent) ShieldCover(arena, dependentSeg); diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c index f507d41222b..ef295fc7d9a 100644 --- a/mps/code/poolsnc.c +++ b/mps/code/poolsnc.c @@ -527,7 +527,7 @@ static Res SNCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg) } if (base < limit) { - res = (*format->scan)(&ss->ss_s, base, limit); + res = FormatScan(format, ss, base, limit); if (res != ResOK) { *totalReturn = FALSE; return res; @@ -536,8 +536,6 @@ static Res SNCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg) AVER(base == limit); } - ss->scannedSize += AddrOffset(base, limit); - *totalReturn = TRUE; return ResOK; } diff --git a/mps/code/root.c b/mps/code/root.c index f1212be9eb4..82737e536b0 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -537,7 +537,6 @@ Res RootScan(ScanState ss, Root root) root->the.area.scan_area, root->the.area.the.closure.p, root->the.area.the.closure.s); - ss->scannedSize += AddrOffset(root->the.area.base, root->the.area.limit); if (res != ResOK) goto failScan; break; @@ -549,7 +548,6 @@ Res RootScan(ScanState ss, Root root) root->the.area.scan_area, &root->the.area.the.tag, sizeof(root->the.area.the.tag)); - ss->scannedSize += AddrOffset(root->the.area.base, root->the.area.limit); if (res != ResOK) goto failScan; break; diff --git a/mps/code/trace.c b/mps/code/trace.c index 458106800db..6471488e1e2 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1420,11 +1420,15 @@ void TraceScanSingleRef(TraceSet ts, Rank rank, Arena arena, } -/* TraceScanArea -- scan contiguous area of references +/* TraceScanArea -- scan an area of memory for references * - * This is a convenience function for scanning the contiguous area - * [base, limit). I.e., it calls Fix on all words from base up to - * limit, inclusive of base and exclusive of limit. */ + * This is a wrapper for area scanning functions, which should not + * otherwise be called directly from within the MPS. This function + * checks arguments and takes care of accounting for the scanned + * memory. + * + * c.f. FormatScan() + */ Res TraceScanArea(ScanState ss, Word *base, Word *limit, mps_area_scan_t scan_area, @@ -1437,6 +1441,11 @@ Res TraceScanArea(ScanState ss, Word *base, Word *limit, EVENT3(TraceScanArea, ss, base, limit); + /* scannedSize is accumulated whether or not scan_area succeeds, so + it's safe to accumulate now so that we can tail-call + scan_area. */ + ss->scannedSize += AddrOffset(base, limit); + return scan_area(&ss->ss_s, base, limit, closure, closure_size); } From 6a15535df6e034a37ece41826aa4f12a4adc7033 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 17 Feb 2016 14:28:17 +0000 Subject: [PATCH 168/337] Removing unused function arenascannable. Reinstate when needed. See . Copied from Perforce Change: 189292 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 9 --------- mps/code/mpm.h | 1 - 2 files changed, 10 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 319de523c68..2d460e06c35 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -1327,15 +1327,6 @@ Size ArenaCollectable(Arena 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/mpm.h b/mps/code/mpm.h index a1b68636f6a..8efa22c155d 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -627,7 +627,6 @@ extern Res ArenaNoGrow(Arena arena, LocusPref pref, Size size); extern Size ArenaAvail(Arena arena); extern Size ArenaCollectable(Arena arena); -extern Size ArenaScannable(Arena arena); extern Res ArenaExtend(Arena, Addr base, Size size); From 2de01f7d2dcae876827cbcada505c648efd4af74 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 25 Feb 2016 23:43:50 +0000 Subject: [PATCH 169/337] Improving detail of design.mps.bootstrap.land.sol and cross-referencing from source code. Copied from Perforce Change: 189345 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 4 ++-- mps/code/poolmfs.c | 3 ++- mps/design/bootstrap.txt | 30 ++++++++++++++++++++++-------- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 2d460e06c35..519a85d735b 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -758,7 +758,7 @@ void ArenaChunkRemoved(Arena arena, Chunk chunk) * This is a primitive allocator used to allocate pages for the arena * Land. It is called rarely and can use a simple search. It may not * use the Land or any pool, because it is used as part of the - * bootstrap. + * bootstrap. See design.mps.bootstrap.land.sol.alloc. */ static Res arenaAllocPageInChunk(Addr *baseReturn, Chunk chunk, Pool pool) @@ -866,7 +866,7 @@ static void arenaExcludePage(Arena arena, Range pageRange) * 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). + * arenaExtendCBSBlockPool). See design.mps.bootstrap.land.sol.pool. * * Only fails if it can't get a page for the block pool. */ diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c index ed1c0343aba..90232621c25 100644 --- a/mps/code/poolmfs.c +++ b/mps/code/poolmfs.c @@ -249,7 +249,8 @@ static Res MFSAlloc(Addr *pReturn, Pool pool, Size size, if(f == NULL) { Addr base; - + + /* See design.mps.bootstrap.land.sol.pool. */ if (!mfs->extendSelf) return ResLIMIT; diff --git a/mps/design/bootstrap.txt b/mps/design/bootstrap.txt index 7eb79df1475..8615aee0f99 100644 --- a/mps/design/bootstrap.txt +++ b/mps/design/bootstrap.txt @@ -67,13 +67,23 @@ 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). +into the arena's free land, the free land's block pool must have +memory from the arena 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. +in combination. + +_`.land.sol.alloc`: First, there is a mechanism for allocating a +page of memory directly from a chunk, bypassing the free land. + +_`.land.sol.pool`: Second, the free land's block pool has an option to +prevent it extending itself by allocating memory from the arena. +Instead, it fails allocations with ``ResLIMIT``. The free land's +block pool also has a mechanism, ``MFSExtend`` to extend it with a +block of memory. When the free land fails with ``ResLIMIT`` the arena +uses `.land.sol.alloc`_ to provide it with memory. + Document History @@ -81,15 +91,19 @@ Document History - 2015-09-01 GDR_ Initial draft. +- 2016-02-25 RB_ Improving description of arena free land bootstrap + and cross-referencing from source code. + .. _GDR: http://www.ravenbrook.com/consultants/gdr/ +.. _RB: http://www.ravenbrook.com/consultants/rb/ Copyright and License --------------------- -Copyright © 2015 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact -Ravenbrook for commercial licensing options. +Copyright © 2015-2016 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 From c47a41d1639b9418939e21ef5464acb98b60e121 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 26 Feb 2016 19:09:10 +0000 Subject: [PATCH 170/337] Branching master to branch/2016-02-26/job003898. Copied from Perforce Change: 189352 ServerID: perforce.ravenbrook.com From ef17ba047bcfe96f49967f05d3af0f78bca454a3 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 26 Feb 2016 18:58:34 +0000 Subject: [PATCH 171/337] Purge spare committed memory when growing the arena fails due to the commit limit. Copied from Perforce Change: 189362 ServerID: perforce.ravenbrook.com --- mps/code/policy.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mps/code/policy.c b/mps/code/policy.c index dbcb33e278f..f90c4c485f5 100644 --- a/mps/code/policy.c +++ b/mps/code/policy.c @@ -77,6 +77,14 @@ Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref, /* Plan C: Extend the arena, then try A and B again. */ if (moreZones != ZoneSetEMPTY) { res = arena->class->grow(arena, pref, size); + /* If we can't extent because we hit the commit limit, try purging + some spare committed memory and try again.*/ + /* TODO: This would be a good time to *remap* VM instead of + returning it to the OS. */ + if (res == ResCOMMIT_LIMIT) { + if (arena->class->purgeSpare(arena, size) >= size) + res = arena->class->grow(arena, pref, size); + } if (res != ResOK) return res; if (zones != ZoneSetEMPTY) { From 13eab92d0005b5143e79512060fd3b040a6c65fa Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 26 Feb 2016 19:06:07 +0000 Subject: [PATCH 172/337] Try later allocation plans if growing the arena fails. Copied from Perforce Change: 189363 ServerID: perforce.ravenbrook.com --- mps/code/policy.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/mps/code/policy.c b/mps/code/policy.c index f90c4c485f5..502b1cc3583 100644 --- a/mps/code/policy.c +++ b/mps/code/policy.c @@ -85,19 +85,21 @@ Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref, if (arena->class->purgeSpare(arena, size) >= size) 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) { - res = ArenaFreeLandAlloc(&tract, arena, moreZones, pref->high, - size, pool); - if (res == ResOK) - goto found; + if (res == ResOK) { + if (zones != ZoneSetEMPTY) { + res = ArenaFreeLandAlloc(&tract, arena, zones, pref->high, size, pool); + if (res == ResOK) + goto found; + } + if (moreZones != zones) { + res = ArenaFreeLandAlloc(&tract, arena, moreZones, pref->high, + size, pool); + if (res == ResOK) + goto found; + } } + /* TODO: Log an event here, since something went wrong, before + trying the next plan anyway. */ } /* Plan D: add every zone that isn't blacklisted. This might mix GC'd From a509df4c2b4e6a7ac83817e13a96da07fed45353 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 28 Feb 2016 20:12:12 +0000 Subject: [PATCH 173/337] Fix typo found by gdr. Copied from Perforce Change: 189376 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 502b1cc3583..541a29159f7 100644 --- a/mps/code/policy.c +++ b/mps/code/policy.c @@ -77,7 +77,7 @@ Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref, /* Plan C: Extend the arena, then try A and B again. */ if (moreZones != ZoneSetEMPTY) { res = arena->class->grow(arena, pref, size); - /* If we can't extent because we hit the commit limit, try purging + /* If we can't extend because we hit the commit limit, try purging some spare committed memory and try again.*/ /* TODO: This would be a good time to *remap* VM instead of returning it to the OS. */ From 8baf699abec67bb1373a5d0f311a8bb348a6c953 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 7 Mar 2014 15:50:15 +0000 Subject: [PATCH 174/337] Improving type naming in table code. Copied from Perforce Change: 189403 ServerID: perforce.ravenbrook.com --- mps/code/eventrep.c | 66 ++++++++++++++++++++++----------------------- mps/code/eventtxt.c | 12 ++++----- mps/code/table.c | 18 ++++++------- mps/code/table.h | 35 +++++++++++++----------- 4 files changed, 68 insertions(+), 63 deletions(-) diff --git a/mps/code/eventrep.c b/mps/code/eventrep.c index 9dae5056fc7..e7f303ca47d 100644 --- a/mps/code/eventrep.c +++ b/mps/code/eventrep.c @@ -189,11 +189,11 @@ static void objDefine(objectTable table, if (table != NULL) { Res ires; - ires = TableDefine(table->startTable, (Word)logObj, obj); + ires = TableDefine(table->startTable, (TableKey)logObj, obj); verify(ires == ResOK); if (table->endTable != NULL) { ires = TableDefine(table->endTable, - (Word)PointerAdd(logObj, size), + (TableKey)PointerAdd(logObj, size), PointerAdd(obj, size)); verify(ires == ResOK); } @@ -212,13 +212,13 @@ static void objRemove(void **objReturn, objectTable table, void *end; void *logEnd; - found = TableLookup(&obj, table->startTable, (Word)logObj); + found = TableLookup(&obj, table->startTable, (TableKey)logObj); if (found) { - ires = TableRemove(table->startTable, (Word)logObj); + ires = TableRemove(table->startTable, (TableKey)logObj); verify(ires == ResOK); if (table->endTable != NULL) { ires = TableRemove(table->endTable, - (Word)PointerAdd(logObj, size)); + (TableKey)PointerAdd(logObj, size)); verify(ires == ResOK); } *objReturn = obj; @@ -227,13 +227,13 @@ static void objRemove(void **objReturn, objectTable table, /* Must be a truncation. */ verify(table->endTable != NULL); logEnd = PointerAdd(logObj, size); - found = TableLookup(&end, table->endTable, (Word)logEnd); + found = TableLookup(&end, table->endTable, (TableKey)logEnd); verify(found); obj = PointerSub(end, size); /* Remove the old end and insert the new one. */ - ires = TableRemove(table->endTable, (Word)logEnd); + ires = TableRemove(table->endTable, (TableKey)logEnd); verify(ires == ResOK); - ires = TableDefine(table->endTable, (Word)logObj, obj); + ires = TableDefine(table->endTable, (TableKey)logObj, obj); verify(ires == ResOK); *objReturn = obj; return; @@ -254,7 +254,7 @@ static void poolRecreate(void *logPool, void *logArena, void *entry; Bool found; - found = TableLookup(&entry, arenaTable, (Word)logArena); + found = TableLookup(&entry, arenaTable, (TableKey)logArena); verify(found); va_start(args, bufferClassLevel); eres = mps_pool_create_v(&pool, (mps_arena_t)entry, class, args); @@ -265,7 +265,7 @@ static void poolRecreate(void *logPool, void *logArena, rep->pool = pool; rep->objects = objectTableCreate(support); rep->bufferClassLevel = bufferClassLevel; - ires = TableDefine(poolTable, (Word)logPool, (void *)rep); + ires = TableDefine(poolTable, (TableKey)logPool, (void *)rep); verify(ires == ResOK); } @@ -279,11 +279,11 @@ static void poolRedestroy(void *logPool) Bool found; poolRep rep; - found = TableLookup(&entry, poolTable, (Word)logPool); + found = TableLookup(&entry, poolTable, (TableKey)logPool); verify(found); rep = (poolRep)entry; mps_pool_destroy(rep->pool); - ires = TableRemove(poolTable, (Word)logPool); + ires = TableRemove(poolTable, (TableKey)logPool); verify(ires == ResOK); objectTableDestroy(rep->objects); free(rep); @@ -303,7 +303,7 @@ static void apRecreate(void *logAp, void *logPool, ...) void *entry; Bool found; - found = TableLookup(&entry, poolTable, (Word)logPool); + found = TableLookup(&entry, poolTable, (TableKey)logPool); verify(found); pRep = (poolRep)entry; va_start(args, logPool); @@ -314,7 +314,7 @@ static void apRecreate(void *logAp, void *logPool, ...) verify(aRep != NULL); aRep->ap = ap; aRep->objects = pRep->objects; - ires = TableDefine(apTable, (Word)logAp, (void *)aRep); + ires = TableDefine(apTable, (TableKey)logAp, (void *)aRep); verify(ires == ResOK); } @@ -328,11 +328,11 @@ static void apRedestroy(void *logAp) Bool found; apRep rep; - found = TableLookup(&entry, apTable, (Word)logAp); + found = TableLookup(&entry, apTable, (TableKey)logAp); verify(found); rep = (apRep)entry; mps_ap_destroy(rep->ap); - ires = TableRemove(apTable, (Word)logAp); + ires = TableRemove(apTable, (TableKey)logAp); verify(ires == ResOK); free(rep); } @@ -358,7 +358,7 @@ void EventReplay(Event event, Word etime) eres = mps_arena_create(&arena, mps_arena_class_vm(), event->pww.w1); verifyMPS(eres); - ires = TableDefine(arenaTable, (Word)event->pww.p0, (void *)arena); + ires = TableDefine(arenaTable, (TableKey)event->pww.p0, (void *)arena); verify(ires == ResOK); arenaJustCreated = TRUE; } break; @@ -368,7 +368,7 @@ void EventReplay(Event event, Word etime) eres = mps_arena_create(&arena, mps_arena_class_vmnz(), event->pww.w1); verifyMPS(eres); - ires = TableDefine(arenaTable, (Word)event->pww.p0, (void *)arena); + ires = TableDefine(arenaTable, (TableKey)event->pww.p0, (void *)arena); verify(ires == ResOK); arenaJustCreated = TRUE; } break; @@ -381,15 +381,15 @@ void EventReplay(Event event, Word etime) eres = mps_arena_create(&arena, mps_arena_class_cl(), (Size)event->pwa.w1, base); verifyMPS(eres); - ires = TableDefine(arenaTable, (Word)event->pw.p0, (void *)arena); + ires = TableDefine(arenaTable, (TableKey)event->pw.p0, (void *)arena); verify(ires == ResOK); arenaJustCreated = TRUE; } break; case EventArenaDestroy: { /* arena */ - found = TableLookup(&entry, arenaTable, (Word)event->p.p0); + found = TableLookup(&entry, arenaTable, (TableKey)event->p.p0); verify(found); mps_arena_destroy((mps_arena_t)entry); - ires = TableRemove(arenaTable, (Word)event->pw.p0); + ires = TableRemove(arenaTable, (TableKey)event->pw.p0); verify(ires == ResOK); } break; case EventPoolInitMVFF: { @@ -423,7 +423,7 @@ void EventReplay(Event event, Word etime) ++discardedEvents; } break; case EventPoolFinish: { /* pool */ - found = TableLookup(&entry, poolTable, (Word)event->p.p0); + found = TableLookup(&entry, poolTable, (TableKey)event->p.p0); if (found) { poolRedestroy(event->p.p0); } else { @@ -432,7 +432,7 @@ void EventReplay(Event event, Word etime) } break; case EventBufferInit: { /* buffer, pool, isMutator */ if ((Bool)event->ppu.u2) { - found = TableLookup(&entry, poolTable, (Word)event->ppu.p1); + found = TableLookup(&entry, poolTable, (TableKey)event->ppu.p1); if (found) { poolRep rep = (poolRep)entry; @@ -450,7 +450,7 @@ void EventReplay(Event event, Word etime) } break; case EventBufferInitSeg: { /* buffer, pool, isMutator */ if ((Bool)event->ppu.u2) { - found = TableLookup(&entry, poolTable, (Word)event->ppu.p1); + found = TableLookup(&entry, poolTable, (TableKey)event->ppu.p1); if (found) { poolRep rep = (poolRep)entry; @@ -468,7 +468,7 @@ void EventReplay(Event event, Word etime) } break; case EventBufferInitRank: { /* buffer, pool, isMutator, rank */ if ((Bool)event->ppuu.u2) { - found = TableLookup(&entry, poolTable, (Word)event->ppuu.p1); + found = TableLookup(&entry, poolTable, (TableKey)event->ppuu.p1); if (found) { poolRep rep = (poolRep)entry; @@ -485,7 +485,7 @@ void EventReplay(Event event, Word etime) } } break; case EventBufferFinish: { /* buffer */ - found = TableLookup(&entry, apTable, (Word)event->p.p0); + found = TableLookup(&entry, apTable, (TableKey)event->p.p0); if (found) { apRedestroy(event->p.p0); } else { @@ -493,7 +493,7 @@ void EventReplay(Event event, Word etime) } } break; case EventBufferReserve: { /* buffer, init, size */ - found = TableLookup(&entry, apTable, (Word)event->paw.p0); + found = TableLookup(&entry, apTable, (TableKey)event->paw.p0); if (found) { apRep rep = (apRep)entry; mps_addr_t p; @@ -505,7 +505,7 @@ void EventReplay(Event event, Word etime) } } break; case EventBufferCommit: { /* buffer, p, size, clientClass */ - found = TableLookup(&entry, apTable, (Word)event->pawa.p0); + found = TableLookup(&entry, apTable, (TableKey)event->pawa.p0); if (found) { apRep rep = (apRep)entry; mps_addr_t obj = rep->ap->init; @@ -520,7 +520,7 @@ void EventReplay(Event event, Word etime) } } break; case EventPoolAlloc: { /* pool, obj, size */ - found = TableLookup(&entry, poolTable, (Word)event->paw.p0); + found = TableLookup(&entry, poolTable, (TableKey)event->paw.p0); if (found) { poolRep rep = (poolRep)entry; void *obj; @@ -534,7 +534,7 @@ void EventReplay(Event event, Word etime) } } break; case EventPoolFree: { /* pool, obj, size */ - found = TableLookup(&entry, poolTable, (Word)event->paw.p0); + found = TableLookup(&entry, poolTable, (TableKey)event->paw.p0); if (found) { poolRep rep = (poolRep)entry; void *obj; @@ -547,7 +547,7 @@ void EventReplay(Event event, Word etime) } } break; case EventCommitLimitSet: { /* arena, limit, succeeded */ - found = TableLookup(&entry, arenaTable, (Word)event->pwu.p0); + found = TableLookup(&entry, arenaTable, (TableKey)event->pwu.p0); verify(found); eres = mps_arena_commit_limit_set((mps_arena_t)entry, (size_t)event->pwu.w1); @@ -555,13 +555,13 @@ void EventReplay(Event event, Word etime) ? MPS_RES_OK : MPS_RES_FAIL); } break; case EventSpareCommitLimitSet: { /* arena, limit */ - found = TableLookup(&entry, arenaTable, (Word)event->pw.p0); + found = TableLookup(&entry, arenaTable, (TableKey)event->pw.p0); verify(found); (void)mps_arena_spare_commit_limit_set((mps_arena_t)entry, (size_t)event->pw.w1); } break; case EventReservoirLimitSet: { /* arena, limit */ - found = TableLookup(&entry, arenaTable, (Word)event->pw.p0); + found = TableLookup(&entry, arenaTable, (TableKey)event->pw.p0); verify(found); mps_reservoir_limit_set((mps_arena_t)entry, (size_t)event->pw.w1); } break; diff --git a/mps/code/eventtxt.c b/mps/code/eventtxt.c index 70914740766..f739c55923d 100644 --- a/mps/code/eventtxt.c +++ b/mps/code/eventtxt.c @@ -250,7 +250,7 @@ static void createTables(mps_pool_t pool) res = TableCreate(&internTable, (size_t)1<<4, tableAlloc, tableFree, pool, - (Word)-1, (Word)-2); + (TableKey)-1, (TableKey)-2); if (res != ResOK) everror("Couldn't make intern table."); @@ -280,7 +280,7 @@ static void recordIntern(mps_pool_t pool, char *p) if (res != MPS_RES_OK) everror("Couldn't allocate space for a string."); (void)strcpy(copy, string); - res = TableDefine(internTable, (Word)stringId, (void *)copy); + res = TableDefine(internTable, (TableKey)stringId, (void *)copy); if (res != ResOK) everror("Couldn't create an intern mapping."); } @@ -359,7 +359,7 @@ static void recordLabel(mps_pool_t pool, EventClock clock, char *p) return; } - if (TableLookup(&tmp, labelTable, address)) { + if (TableLookup(&tmp, labelTable, (TableKey)address)) { list = tmp; } else { /* First label for this address */ @@ -368,7 +368,7 @@ static void recordLabel(mps_pool_t pool, EventClock clock, char *p) everror("Can't allocate space for a label list"); list = tmp; list->n = 0; - res = TableDefine(labelTable, (Word)address, list); + res = TableDefine(labelTable, (TableKey)address, list); if (res != ResOK) everror("Couldn't create a label mapping."); } @@ -408,13 +408,13 @@ static void printAddr(EventClock clock, ulongest_t addr, const char *ident) void *tmp; printf("%s:%0*" PRIXLONGEST, ident, hexWordWidth, addr); - if (TableLookup(&tmp, labelTable, addr)) { + if (TableLookup(&tmp, labelTable, (TableKey)addr)) { LabelList list = tmp; size_t pos = labelFind(list, clock); if (pos > 0) { ulongest_t id = list->labels[pos - 1].id; putchar('['); - if (TableLookup(&tmp, internTable, id)) + if (TableLookup(&tmp, internTable, (TableKey)id)) printStr((char *)tmp); else printf("unknown label %" PRIXLONGEST, id); diff --git a/mps/code/table.c b/mps/code/table.c index 34552476298..b8d0576e759 100644 --- a/mps/code/table.c +++ b/mps/code/table.c @@ -53,7 +53,7 @@ SRCID(table, "$Id$"); typedef Word Hash; -static Hash tableHash(Word key) +static Hash tableHash(TableKey key) { Hash hash = (Hash)(key & 0x7FFFFFFF); /* requires m == 2^31-1, a < 2^16 */ @@ -93,7 +93,7 @@ static Bool entryIsActive(Table table, TableEntry entry) * that all the items still fit in after growing the table. */ -static TableEntry tableFind(Table table, Word key, Bool skip_deleted) +static TableEntry tableFind(Table table, TableKey key, Bool skip_deleted) { Hash hash; Index i; @@ -225,8 +225,8 @@ extern Res TableCreate(Table *tableReturn, TableAllocFunction tableAlloc, TableFreeFunction tableFree, void *allocClosure, - Word unusedKey, - Word deletedKey) + TableKey unusedKey, + TableKey deletedKey) { Table table; Res res; @@ -279,7 +279,7 @@ extern void TableDestroy(Table table) /* TableLookup -- look up */ -extern Bool TableLookup(void **valueReturn, Table table, Word key) +extern Bool TableLookup(TableValue *valueReturn, Table table, TableKey key) { TableEntry entry = tableFind(table, key, TRUE /* skip deleted */); @@ -292,7 +292,7 @@ extern Bool TableLookup(void **valueReturn, Table table, Word key) /* TableDefine -- add a new mapping */ -extern Res TableDefine(Table table, Word key, void *value) +extern Res TableDefine(Table table, TableKey key, TableValue value) { TableEntry entry; @@ -326,7 +326,7 @@ extern Res TableDefine(Table table, Word key, void *value) /* TableRedefine -- redefine an existing mapping */ -extern Res TableRedefine(Table table, Word key, void *value) +extern Res TableRedefine(Table table, TableKey key, TableValue value) { TableEntry entry; @@ -344,7 +344,7 @@ extern Res TableRedefine(Table table, Word key, void *value) /* TableRemove -- remove a mapping */ -extern Res TableRemove(Table table, Word key) +extern Res TableRemove(Table table, TableKey key) { TableEntry entry; @@ -363,7 +363,7 @@ extern Res TableRemove(Table table, Word key) /* TableMap -- apply a function to all the mappings */ extern void TableMap(Table table, - void (*fun)(void *closure, Word key, void*value), + void (*fun)(void *closure, TableKey key, TableValue value), void *closure) { Index i; diff --git a/mps/code/table.h b/mps/code/table.h index 797f7644a38..9e7c8d1b9b4 100644 --- a/mps/code/table.h +++ b/mps/code/table.h @@ -1,7 +1,9 @@ /* table.h: Interface for a dictionary - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * $Id$ + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * + * A table is a hashed mapping from keys to values. */ #ifndef table_h @@ -13,15 +15,18 @@ typedef struct TableStruct *Table; -#define TableSig ((Sig)0x5192AB13) /* SIGnature TABLE */ +typedef Word TableKey; +typedef void *TableValue; + +typedef struct TableEntryStruct { + TableKey key; + TableValue value; +} TableEntryStruct, *TableEntry; typedef void *(*TableAllocFunction)(void *closure, size_t size); typedef void (*TableFreeFunction)(void *closure, void *p, size_t size); -typedef struct TableEntryStruct { - Word key; - void *value; -} TableEntryStruct, *TableEntry; +#define TableSig ((Sig)0x5192AB13) /* SIGnature TABLE */ typedef struct TableStruct { Sig sig; /* */ @@ -31,8 +36,8 @@ typedef struct TableStruct { TableAllocFunction alloc; TableFreeFunction free; void *allocClosure; - Word unusedKey; /* key marking unused (undefined) entries */ - Word deletedKey; /* key marking deleted entries */ + TableKey unusedKey; /* key marking unused (undefined) entries */ + TableKey deletedKey; /* key marking deleted entries */ } TableStruct; extern Res TableCreate(Table *tableReturn, @@ -40,17 +45,17 @@ extern Res TableCreate(Table *tableReturn, TableAllocFunction tableAlloc, TableFreeFunction tableFree, void *allocClosure, - Word unusedKey, - Word deletedKey); + TableKey unusedKey, + TableKey deletedKey); extern void TableDestroy(Table table); extern Bool TableCheck(Table table); -extern Res TableDefine(Table table, Word key, void *value); -extern Res TableRedefine(Table table, Word key, void *value); -extern Bool TableLookup(void **valueReturn, Table table, Word key); -extern Res TableRemove(Table table, Word key); +extern Res TableDefine(Table table, TableKey key, TableValue value); +extern Res TableRedefine(Table table, TableKey key, TableValue value); +extern Bool TableLookup(TableValue *valueReturn, Table table, TableKey key); +extern Res TableRemove(Table table, TableKey key); extern Count TableCount(Table table); extern void TableMap(Table table, - void(*fun)(void *closure, Word key, void *value), + void(*fun)(void *closure, TableKey key, TableValue value), void *closure); extern Res TableGrow(Table table, Count extraCapacity); From e292753025c156c1d16cb9392efb27cd785b6cfb Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 29 Feb 2016 16:38:07 +0000 Subject: [PATCH 175/337] Fixing perforce filetype of bootstrap.txt to expand keywords. Copied from Perforce Change: 189439 ServerID: perforce.ravenbrook.com From 0b8f2dea167214dfdfdd15e0db97d979ab3b7b70 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 1 Mar 2016 13:16:46 +0000 Subject: [PATCH 176/337] Fixing references to mps_root_create_stack to mps_root_create_thread. Copied from Perforce Change: 189480 ServerID: perforce.ravenbrook.com --- mps/manual/source/glossary/c.rst | 2 +- mps/manual/source/glossary/t.rst | 2 +- mps/manual/source/topic/deprecated.rst | 4 ++-- mps/manual/source/topic/thread.rst | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mps/manual/source/glossary/c.rst b/mps/manual/source/glossary/c.rst index 90201002ee3..6fe83e370d0 100644 --- a/mps/manual/source/glossary/c.rst +++ b/mps/manual/source/glossary/c.rst @@ -302,7 +302,7 @@ Memory Management Glossary: C 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`. + :c:func:`mps_root_create_thread`. collect diff --git a/mps/manual/source/glossary/t.rst b/mps/manual/source/glossary/t.rst index 222a3cbb512..eabf6e530b0 100644 --- a/mps/manual/source/glossary/t.rst +++ b/mps/manual/source/glossary/t.rst @@ -183,7 +183,7 @@ Memory Management Glossary: T :c:func:`mps_thread_reg`. In order for the MPS to find 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`. + :c:func:`mps_root_create_thread`. See :ref:`topic-thread`. threatened set diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst index 18819c2ce09..964fcc2c2d1 100644 --- a/mps/manual/source/topic/deprecated.rst +++ b/mps/manual/source/topic/deprecated.rst @@ -186,7 +186,7 @@ Deprecated in version 1.115 .. deprecated:: - Use :c:func:`mps_root_create_stack` instead. + Use :c:func:`mps_root_create_thread` instead. The type of a root scanning function for roots created with :c:func:`mps_root_create_reg`. @@ -228,7 +228,7 @@ Deprecated in version 1.115 .. deprecated:: - Use :c:func:`mps_root_create_stack` instead, passing + Use :c:func:`mps_root_create_thread` instead, passing ``sizeof(mps_word_t) - 1`` for the ``mask`` argument, and ``0`` for the ``pattern`` argument. diff --git a/mps/manual/source/topic/thread.rst b/mps/manual/source/topic/thread.rst index 54a929b6f65..0697daac301 100644 --- a/mps/manual/source/topic/thread.rst +++ b/mps/manual/source/topic/thread.rst @@ -48,7 +48,7 @@ For simplicity, we recommend that a thread must be registered with an :term:`arena` if: * its :term:`control stack` and :term:`registers` form a root (this is - enforced by :c:func:`mps_root_create_stack`); or + enforced by :c:func:`mps_root_create_thread`); or * it reads or writes from a location in an :term:`automatically managed ` :term:`pool` in the arena. @@ -119,7 +119,7 @@ Thread interface Even in a single-threaded environment it may be necessary to 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`. + calling :c:func:`mps_root_create_thread`. .. c:function:: mps_res_t mps_thread_reg(mps_thr_t *thr_o, mps_arena_t arena) From 2f025ea5d2183ee91f81117330fe7bdcb4159a6e Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 1 Mar 2016 13:36:30 +0000 Subject: [PATCH 177/337] Deprecating table roots. Copied from Perforce Change: 189483 ServerID: perforce.ravenbrook.com --- mps/code/mps.h | 7 -- mps/code/mpsi.c | 21 +--- mps/code/tagtest.c | 12 +-- mps/manual/source/topic/deprecated.rst | 124 ++++++++++++++++++++++-- mps/manual/source/topic/root.rst | 129 ++----------------------- 5 files changed, 135 insertions(+), 158 deletions(-) diff --git a/mps/code/mps.h b/mps/code/mps.h index a6495f0dd88..51275c711a7 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -675,13 +675,6 @@ extern mps_res_t mps_root_create(mps_root_t *, mps_arena_t, mps_rank_t, extern mps_res_t mps_root_create_table(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_addr_t *, size_t); -extern mps_res_t mps_root_create_table_tagged(mps_root_t *, - mps_arena_t, - mps_rank_t, mps_rm_t, - mps_addr_t *, size_t, - mps_area_scan_t, - mps_word_t, - mps_word_t); extern mps_res_t mps_root_create_table_masked(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_addr_t *, size_t, diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index cb3c7c894a5..a4778a051c3 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1383,29 +1383,16 @@ mps_res_t mps_root_create_area_tagged(mps_root_t *mps_root_o, } -mps_res_t mps_root_create_table_tagged(mps_root_t *mps_root_o, - mps_arena_t arena, - mps_rank_t mps_rank, mps_rm_t mps_rm, - mps_addr_t *base, size_t size, - mps_area_scan_t scan_area, - mps_word_t mask, - mps_word_t pattern) -{ - return mps_root_create_area_tagged(mps_root_o, arena, mps_rank, mps_rm, - (void *)base, (void *)(base + size), - scan_area, mask, pattern); -} - - mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, mps_arena_t arena, mps_rank_t mps_rank, mps_rm_t mps_rm, mps_addr_t *base, size_t size, mps_word_t mask) { - return mps_root_create_table_tagged(mps_root_o, arena, mps_rank, mps_rm, - base, size, mps_scan_area_tagged, - mask, 0); + return mps_root_create_area_tagged(mps_root_o, arena, mps_rank, mps_rm, + (void *)base, (void *)(base + size), + mps_scan_area_tagged, + mask, 0); } mps_res_t mps_root_create_fmt(mps_root_t *mps_root_o, mps_arena_t arena, diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c index d1f96e00c18..8673390538c 100644 --- a/mps/code/tagtest.c +++ b/mps/code/tagtest.c @@ -169,17 +169,17 @@ static void test(int mode) /* fall through */ case MODE_CONS: /* Scan words tagged "cons" -- everything will live. */ - die(mps_root_create_table_tagged(&root, arena, mps_rank_ambig(), 0, - refs, OBJCOUNT, - mps_scan_area_tagged, TAG_MASK, tag_cons), + die(mps_root_create_area_tagged(&root, arena, mps_rank_ambig(), 0, + (void *)refs, (void *)&refs[OBJCOUNT], + mps_scan_area_tagged, TAG_MASK, tag_cons), "root"); expected = 0; break; case MODE_INVALID: /* Scan words tagged "invalid" -- everything will die. */ - die(mps_root_create_table_tagged(&root, arena, mps_rank_ambig(), 0, - refs, OBJCOUNT, - mps_scan_area_tagged, TAG_MASK, tag_invalid), + die(mps_root_create_area_tagged(&root, arena, mps_rank_ambig(), 0, + (void *)refs, (void *)&refs[OBJCOUNT], + mps_scan_area_tagged, TAG_MASK, tag_invalid), "root"); expected = OBJCOUNT; break; diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst index 964fcc2c2d1..592c52ef1f0 100644 --- a/mps/manual/source/topic/deprecated.rst +++ b/mps/manual/source/topic/deprecated.rst @@ -163,24 +163,130 @@ Deprecated in version 1.115 containing references to memory managed by the MPS). The ``s`` argument is ignored. +.. 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) + + .. deprecated:: + + This function is equivalent to:: + + mps_root_create_area(root_o, arena, rank, mode, + (void *)base, (void *)(base + count), + mps_scan_area, NULL, 0) + + Register a :term:`root` that consists of a vector of + :term:`references`. + + ``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`. + + ``base`` points to a vector of references. + + ``count`` is the number of references in the vector. + + 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`. + + .. _topic-root-type-pun: + + .. warning:: + + The ``base`` argument has type ``mps_addr_t *`` (a typedef for + ``void **``) but the table of references most likely has some + other pointer type, ``my_object *`` say. It is tempting to + write:: + + mps_root_create_table(..., (mps_addr_t *)my_table, ...) + + but this is :term:`type punning`, and its behaviour is not + defined in ANSI/ISO Standard C. (GCC and Clang have a warning + flag ``-Wstrict-aliasing`` which detects some errors of this + form.) + + To ensure well-defined behaviour, the pointer must be + converted via ``void *`` (or via :c:type:`mps_addr_t`, which + is a typedef for ``void *``), like this:: + + mps_addr_t base = my_table; + mps_root_create_table(..., base, ...) + +.. c:function:: mps_res_t mps_root_create_table_tagged(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_addr_t *base, size_t count, mps_area_scan_t scan_area, mps_word_t mask, mps_word_t pattern) + + .. deprecated:: + + This function is equivalent to:: + + mps_root_create_area_tagged(root_o, arena, rank, mode, + (void *)base, (void *)(base + size), + scan_area, mask, pattern) + + Register a :term:`root` that consists of a vector of :term:`tagged + references`. + + ``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`. + + ``base`` points to a vector of tagged references. + + ``count`` is the number of tagged references in the vector. + + ``scan_area`` is an tagged area scanning function that will be + used to scan the table, for example :c:func:`mps_scan_area_tagged` + or :c:func:`mps_scan_area_tagged_or_zero`. See + :ref:`topic-scanning-area`. + + ``mask`` is a :term:`bitmask` that is passed to ``scan_area`` to + be applied to the words in the vector to locate the :term:`tag`. + + ``pattern`` is passed to ``scan_area`` to determine whether to + consider a word as a reference. For example, + :c:func:`mps_scan_area_tagged` will not consider any word that is + unequal to this (after masking with ``mask``) to be a reference. + + 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:: + + See the warning for :c:func:`mps_root_create_table` above. .. c:function:: mps_res_t mps_root_create_table_masked(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_addr_t *base, size_t count, mps_word_t mask) .. deprecated:: - Use :c:func:`mps_root_create_table_masked` instead, passing + This function is equivalent to:: + + mps_root_create_area_tagged(root_o, arena, rank, rm, + (void *)base, (void *)(base + size), + mps_scan_area_tagged, + mask, 0) + + Use :c:func:`mps_root_create_area_masked` instead, passing zero for the ``pattern`` argument. Register a :term:`root` that consists of a vector of :term:`tagged references` whose pattern is zero. - - This function is equivalent to:: - - mps_root_create_table_tagged(root_o, arena, rank, rm, - base, size, - mps_scan_area_tagged, - mask, 0) - .. c:type:: mps_res_t (*mps_reg_scan_t)(mps_ss_t ss, mps_thr_t thr, void *p, size_t s) diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index 2b24823f051..8a8ee334a9a 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 four 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 @@ -97,9 +97,6 @@ scan it for references: #. :c:func:`mps_root_create_area` if the root consists of an area of memory; -#. :c:func:`mps_root_create_table` if the root consists of a table of - references; - #. :c:func:`mps_root_create_thread` if the root consists of the :term:`registers` and :term:`control stack` of a thread. See :ref:`topic-root-thread` below. @@ -256,7 +253,7 @@ allowing the MPS to detect whether they have changed. the :term:`root` after it is registered: that is, scanning the root will produce the same set of :term:`references` every time. Furthermore, for roots registered by - :c:func:`mps_root_create_fmt` and :c:func:`mps_root_create_table`, + :c:func:`mps_root_create_fmt` and :c:func:`mps_root_create_area`, the client program will not write to the root at all. .. c:macro:: MPS_RM_PROT @@ -590,7 +587,7 @@ Root interface ``count`` is the number of tagged references in the vector. ``scan_area`` is an tagged area scanning function that will be - used to scan the table, for example :c:func:`mps_scan_area_tagged` + used to scan the area, for example :c:func:`mps_scan_area_tagged` or :c:func:`mps_scan_area_tagged_or_zero`. See :ref:`topic-scanning-area`. @@ -610,106 +607,6 @@ 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_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 - :term:`references`. - - ``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`. - - ``base`` points to a vector of references. - - ``count`` is the number of references in the vector. - - This function is equivalent to:: - - mps_root_create_area(root_o, arena, rank, mode, - (void *)base, (void *)(base + count), - mps_scan_area, NULL, 0) - - 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`. - - .. _topic-root-type-pun: - - .. warning:: - - The ``base`` argument has type ``mps_addr_t *`` (a typedef for - ``void **``) but the table of references most likely has some - other pointer type, ``my_object *`` say. It is tempting to - write:: - - mps_root_create_table(..., (mps_addr_t *)my_table, ...) - - but this is :term:`type punning`, and its behaviour is not - defined in ANSI/ISO Standard C. (GCC and Clang have a warning - flag ``-Wstrict-aliasing`` which detects some errors of this - form.) - - To ensure well-defined behaviour, the pointer must be - converted via ``void *`` (or via :c:type:`mps_addr_t`, which - is a typedef for ``void *``), like this:: - - mps_addr_t base = my_table; - mps_root_create_table(..., base, ...) - -.. c:function:: mps_res_t mps_root_create_table_tagged(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_addr_t *base, size_t count, mps_area_scan_t scan_area, mps_word_t mask, mps_word_t pattern) - - Register a :term:`root` that consists of a vector of :term:`tagged - references`. - - ``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`. - - ``base`` points to a vector of tagged references. - - ``count`` is the number of tagged references in the vector. - - ``scan_area`` is an tagged area scanning function that will be - used to scan the table, for example :c:func:`mps_scan_area_tagged` - or :c:func:`mps_scan_area_tagged_or_zero`. See - :ref:`topic-scanning-area`. - - ``mask`` is a :term:`bitmask` that is passed to ``scan_area`` to - be applied to the words in the vector to locate the :term:`tag`. - - ``pattern`` is passed to ``scan_area`` to determine whether to - consider a word as a reference. For example, - :c:func:`mps_scan_area_tagged` will not consider any word that is - unequal to this (after masking with ``mask``) to be a reference. - - 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`. - - This function is equivalent to:: - - mps_root_create_area_tagged(root_o, arena, rank, mode, - (void *)base, (void *)(base + size), - scan_area, mask, pattern) - For example:: #define TAG_MASK 0x3 /* bottom two bits */ @@ -724,19 +621,13 @@ Root interface mps_res_t res; mps_root_t root; - mps_addr_t base = symtab; - res = mps_root_create_table_tagged(&root, arena, - mps_rank_exact(), - (mps_rm_t)0, - base, symtab_size * 2, - mps_scan_area_tagged, - (mps_word_t)TAG_MASK, - (mps_word_t)TAG_PATTERN); - if (res != MPS_RES_OK) errror("can't create symtab root"); - - .. warning:: - - See the warning for :c:func:`mps_root_create_table` above. + res = mps_root_create_area_tagged(&root, arena, + mps_rank_exact(), + 0, + (void *)symtab, (void *)&symtab[symtab_size], + mps_scan_area_tagged, + TAG_MASK, TAG_PATTERN); + if (res != MPS_RES_OK) error("can't create symtab root"); .. c:function:: void mps_root_destroy(mps_root_t root) From cce61c51de8130a98c67ef0b2fd3c92dd475d266 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 1 Mar 2016 13:57:13 +0000 Subject: [PATCH 178/337] Removing assumption that area scanners take pointers to words. the client is at liberty to encode references in other ways. Copied from Perforce Change: 189484 ServerID: perforce.ravenbrook.com --- mps/code/mps.h | 14 ++++----- mps/code/mpsi.c | 8 +++--- mps/code/scan.c | 12 ++++---- mps/code/tagtest.c | 4 +-- mps/manual/source/topic/deprecated.rst | 10 +++---- mps/manual/source/topic/root.rst | 6 ++-- mps/manual/source/topic/scanning.rst | 39 +++++++++++++++----------- 7 files changed, 49 insertions(+), 44 deletions(-) diff --git a/mps/code/mps.h b/mps/code/mps.h index 51275c711a7..737677da518 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -109,7 +109,7 @@ typedef struct mps_scan_tag_s { } mps_scan_tag_s; typedef mps_res_t (*mps_root_scan_t)(mps_ss_t, void *, size_t); -typedef mps_res_t (*mps_area_scan_t)(mps_ss_t, mps_word_t *, mps_word_t *, +typedef mps_res_t (*mps_area_scan_t)(mps_ss_t, void *, void *, void *, size_t); typedef mps_res_t (*mps_fmt_scan_t)(mps_ss_t, mps_addr_t, mps_addr_t); typedef mps_res_t (*mps_reg_scan_t)(mps_ss_t, mps_thr_t, @@ -681,11 +681,11 @@ extern mps_res_t mps_root_create_table_masked(mps_root_t *, mps_arena_t, mps_word_t); extern mps_res_t mps_root_create_area(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, - mps_word_t *, mps_word_t *, + void *, void *, mps_area_scan_t, void *, size_t); extern mps_res_t mps_root_create_area_tagged(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, - mps_word_t *, mps_word_t *, + void *, void *, mps_area_scan_t, mps_word_t, mps_word_t); extern mps_res_t mps_root_create_fmt(mps_root_t *, mps_arena_t, @@ -821,16 +821,16 @@ extern void mps_pool_check_free_space(mps_pool_t); /* Scanner Support */ extern mps_res_t mps_scan_area(mps_ss_t, - mps_word_t *, mps_word_t *, + void *, void *, void *, size_t); extern mps_res_t mps_scan_area_masked(mps_ss_t, - mps_word_t *, mps_word_t *, + void *, void *, void *, size_t); extern mps_res_t mps_scan_area_tagged(mps_ss_t, - mps_word_t *, mps_word_t *, + void *, void *, void *, size_t); extern mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t, - mps_word_t *, mps_word_t *, + void *, void *, void *, size_t); extern mps_res_t mps_fix(mps_ss_t, mps_addr_t *); diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index a4778a051c3..655a226549c 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1315,7 +1315,7 @@ mps_res_t mps_root_create_table(mps_root_t *mps_root_o, mps_arena_t arena, mps_res_t mps_root_create_area(mps_root_t *mps_root_o, mps_arena_t arena, mps_rank_t mps_rank, mps_rm_t mps_rm, - mps_word_t *base, mps_word_t *limit, + void *base, void *limit, mps_area_scan_t scan_area, void *closure, size_t closure_size) { @@ -1349,8 +1349,8 @@ mps_res_t mps_root_create_area_tagged(mps_root_t *mps_root_o, mps_arena_t arena, mps_rank_t mps_rank, mps_rm_t mps_rm, - mps_word_t *base, - mps_word_t *limit, + void *base, + void *limit, mps_area_scan_t scan_area, mps_word_t mask, mps_word_t pattern) @@ -1390,7 +1390,7 @@ mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, mps_word_t mask) { return mps_root_create_area_tagged(mps_root_o, arena, mps_rank, mps_rm, - (void *)base, (void *)(base + size), + base, base + size, mps_scan_area_tagged, mask, 0); } diff --git a/mps/code/scan.c b/mps/code/scan.c index 0dc0747e3c6..99b4d5d0987 100644 --- a/mps/code/scan.c +++ b/mps/code/scan.c @@ -26,7 +26,7 @@ */ mps_res_t mps_scan_area(mps_ss_t ss, - mps_word_t *base, mps_word_t *limit, + void *base, void *limit, void *closure, size_t closure_size) { (void)closure; /* unused */ @@ -34,7 +34,7 @@ mps_res_t mps_scan_area(mps_ss_t ss, MPS_SCAN_BEGIN(ss) { mps_word_t *p = base; - while (p < limit) { + while (p < (mps_word_t *)limit) { mps_word_t word = *p; mps_addr_t ref = (mps_addr_t)word; if (MPS_FIX1(ss, ref)) { @@ -54,7 +54,7 @@ mps_res_t mps_scan_area(mps_ss_t ss, #define MPS_SCAN_AREA_TAGGED(test) \ MPS_SCAN_BEGIN(ss) { \ mps_word_t *p = base; \ - while (p < limit) { \ + while (p < (mps_word_t *)limit) { \ mps_word_t word = *p; \ mps_word_t tag_bits = word & mask; \ if (test) { \ @@ -85,7 +85,7 @@ mps_res_t mps_scan_area(mps_ss_t ss, */ mps_res_t mps_scan_area_masked(mps_ss_t ss, - mps_word_t *base, mps_word_t *limit, + void *base, void *limit, void *closure, size_t closure_size) { mps_scan_tag_t tag = closure; @@ -108,7 +108,7 @@ mps_res_t mps_scan_area_masked(mps_ss_t ss, */ mps_res_t mps_scan_area_tagged(mps_ss_t ss, - mps_word_t *base, mps_word_t *limit, + void *base, void *limit, void *closure, size_t closure_size) { mps_scan_tag_t tag = closure; @@ -138,7 +138,7 @@ mps_res_t mps_scan_area_tagged(mps_ss_t ss, */ mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t ss, - mps_word_t *base, mps_word_t *limit, + void *base, void *limit, void *closure, size_t closure_size) { mps_scan_tag_t tag = closure; diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c index 8673390538c..a33bf122614 100644 --- a/mps/code/tagtest.c +++ b/mps/code/tagtest.c @@ -170,7 +170,7 @@ static void test(int mode) case MODE_CONS: /* Scan words tagged "cons" -- everything will live. */ die(mps_root_create_area_tagged(&root, arena, mps_rank_ambig(), 0, - (void *)refs, (void *)&refs[OBJCOUNT], + refs, refs + OBJCOUNT, mps_scan_area_tagged, TAG_MASK, tag_cons), "root"); expected = 0; @@ -178,7 +178,7 @@ static void test(int mode) case MODE_INVALID: /* Scan words tagged "invalid" -- everything will die. */ die(mps_root_create_area_tagged(&root, arena, mps_rank_ambig(), 0, - (void *)refs, (void *)&refs[OBJCOUNT], + refs, refs + OBJCOUNT, mps_scan_area_tagged, TAG_MASK, tag_invalid), "root"); expected = OBJCOUNT; diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst index 592c52ef1f0..2bdced17215 100644 --- a/mps/manual/source/topic/deprecated.rst +++ b/mps/manual/source/topic/deprecated.rst @@ -170,7 +170,7 @@ Deprecated in version 1.115 This function is equivalent to:: mps_root_create_area(root_o, arena, rank, mode, - (void *)base, (void *)(base + count), + base, base + count, mps_scan_area, NULL, 0) Register a :term:`root` that consists of a vector of @@ -227,7 +227,7 @@ Deprecated in version 1.115 This function is equivalent to:: mps_root_create_area_tagged(root_o, arena, rank, mode, - (void *)base, (void *)(base + size), + base, base + size, scan_area, mask, pattern) Register a :term:`root` that consists of a vector of :term:`tagged @@ -278,9 +278,9 @@ Deprecated in version 1.115 This function is equivalent to:: mps_root_create_area_tagged(root_o, arena, rank, rm, - (void *)base, (void *)(base + size), - mps_scan_area_tagged, - mask, 0) + base, base + size, + mps_scan_area_tagged, + mask, 0) Use :c:func:`mps_root_create_area_masked` instead, passing zero for the ``pattern`` argument. diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index 8a8ee334a9a..743c865f6a5 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -531,7 +531,7 @@ 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_area(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_word_t *base, mps_word_t *limit, mps_area_scan_t scan_area, void *closure, size_t closure_size) +.. c:function:: mps_res_t mps_root_create_area(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, void *base, void *limit, mps_area_scan_t scan_area, void *closure, size_t closure_size) Register a :term:`root` that consists of an area of memory scanned by an area scanning function. @@ -568,7 +568,7 @@ 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_area_tagged(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_word_t *base, mps_word_t *limit, mps_area_scan_t scan_area, mps_word_t mask, mps_word_t pattern) +.. c:function:: mps_res_t mps_root_create_area_tagged(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, void *base, void *limit, mps_area_scan_t scan_area, mps_word_t mask, mps_word_t pattern) Register a :term:`root` that consists of an area of memory scanned by a tagged area scanning function. @@ -624,7 +624,7 @@ Root interface res = mps_root_create_area_tagged(&root, arena, mps_rank_exact(), 0, - (void *)symtab, (void *)&symtab[symtab_size], + symtab, symtab + symtab_size, mps_scan_area_tagged, TAG_MASK, TAG_PATTERN); if (res != MPS_RES_OK) error("can't create symtab root"); diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst index dcf270b80df..cac8d7457e3 100644 --- a/mps/manual/source/topic/scanning.rst +++ b/mps/manual/source/topic/scanning.rst @@ -513,7 +513,7 @@ Area scanners An area scanner :term:`scans` an area of memory for :term:`references `. Various functions in the MPS interface, -:such as :c:func:`mps_root_create_thread_tagged`, accept area scanners as +such as :c:func:`mps_root_create_thread_tagged`, accept area scanners as arguments so that the :term:`client program` can specify how to scan special areas such as the :term:`control stack`. @@ -530,12 +530,12 @@ the scanners, found in ``scan.c`` in the MPS source code. The type of area scanning functions, which are all of the form:: mps_res_t scan(mps_ss_t ss, - mps_word_t *base, mps_word_t *limit, + void *base, void *limit, void *closure, size_t closure_size); ``ss`` is the :term:`scan state`. - ``base`` points to the first word to be scanned. + ``base`` points to the first location to be scanned. ``limit`` points to the location just beyond the end of the area to be scanned. @@ -551,11 +551,14 @@ the scanners, found in ``scan.c`` in the MPS source code. :c:func:`mps_root_create_thread_tagged` then it is the value of the ``closure_size`` argument originally passed to that function. -.. c:function:: mps_res_t mps_scan_area(mps_ss_t ss, mps_word_t *base, mps_word_t *limit, void *closure, size_t closure_size) +.. c:function:: mps_res_t mps_scan_area(mps_ss_t ss, void *base, void *limit, void *closure, size_t closure_size) - Scan an area of memory :term:`fixing ` every word. ``closure`` and ``closure_size`` are ignored. + Scan an area of memory :term:`fixing ` every word. + ``closure`` and ``closure_size`` are ignored. Expects ``base`` + and ``limit`` to be word-aligned. - This scanner is appropriate for use when all words in the area are simple untagged references. + This scanner is appropriate for use when all words in the area are + simple untagged references. .. c:type:: mps_scan_tag_t @@ -583,11 +586,12 @@ the scanners, found in ``scan.c`` in the MPS source code. interpretation depends on which area scanner it is passed to. See the documentation for the individual area scanners. -.. c:function:: mps_res_t mps_scan_area_masked(mps_ss_t ss, mps_word_t *base, mps_word_t *limit, void *closure, size_t closure_size) +.. c:function:: mps_res_t mps_scan_area_masked(mps_ss_t ss, void *base, void *limit, void *closure, size_t closure_size) Scan an area of memory :term:`fixing ` every word, but remove tag bits before fixing references, and restore them afterwards. - ``closure`` should point to an :c:type:`mps_scan_tag_s`. + ``closure`` should point to an :c:type:`mps_scan_tag_s`. Expects + ``base`` and ``limit`` to be word-aligned. For example, if ``mask`` is 0b111 (decimal 7), then this scanner will clear the bottom three bits of each word before fixing. A word @@ -599,11 +603,12 @@ the scanners, found in ``scan.c`` in the MPS source code. references no matter what tag they have. This can be especially useful if you are debugging your tagging scheme. -.. c:function:: mps_res_t mps_scan_area_tagged(mps_ss_t ss, mps_word_t *base, mps_word_t *limit, void *closure, size_t closure_size) +.. c:function:: mps_res_t mps_scan_area_tagged(mps_ss_t ss, void *base, void *limit, void *closure, size_t closure_size) - Scan an area of memory :term:`fixing ` only words whose masked - bits match a particular tag pattern. ``closure`` should point to a - :c:type:`mps_scan_tag_s`. + Scan an area of memory :term:`fixing ` only words whose + masked bits match a particular tag pattern. ``closure`` should + point to a :c:type:`mps_scan_tag_s`. Expects ``base`` and + ``limit`` to be word-aligned. For example, if ``mask`` is 7 and ``pattern`` is 5, then this scanner will only fix words whose low order bits are 0b101. @@ -621,12 +626,12 @@ the scanners, found in ``scan.c`` in the MPS source code. version of the pointer. See :c:func:`mps_root_create_thread_tagged`. -.. c:function:: mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t ss, mps_word_t *base, mps_word_t *limit, void *closure, size_t closure_size) +.. c:function:: mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t ss, void *base, void *limit, void *closure, size_t closure_size) - Scan an area of memory :term:`fixing ` only words whose masked - bits are zero or match a particular tag pattern. ``closure`` should - point to a - :c:type:`mps_scan_tag_s`. + Scan an area of memory :term:`fixing ` only words whose + masked bits are zero or match a particular tag pattern. + ``closure`` should point to a :c:type:`mps_scan_tag_s`. Expects + ``base`` and ``limit`` to be word-aligned. For example, if ``mask`` is 7 and ``pattern`` is 3, then this scanner will fix words whose low order bits are 0b011 and words From f9743bb9f47228f8b1d4be122383e8dff6a2b4fd Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 1 Mar 2016 15:11:39 +0000 Subject: [PATCH 179/337] Updating scheme example to demonstrate mps_root_create_area rather than deprecated mps_root_create_table. Copied from Perforce Change: 189488 ServerID: perforce.ravenbrook.com --- mps/example/scheme/scheme-advanced.c | 14 +++++++------- mps/example/scheme/scheme.c | 25 ++++++++++++------------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/mps/example/scheme/scheme-advanced.c b/mps/example/scheme/scheme-advanced.c index 81587327d9e..4d75ed854bc 100644 --- a/mps/example/scheme/scheme-advanced.c +++ b/mps/example/scheme/scheme-advanced.c @@ -4311,7 +4311,6 @@ static int start(int argc, char *argv[]) size_t i; volatile obj_t env, op_env, obj; jmp_buf jb; - mps_addr_t ref; mps_res_t res; mps_root_t globals_root; int exit_code = EXIT_SUCCESS; @@ -4325,13 +4324,14 @@ static int start(int argc, char *argv[]) /* We must register the global variable 'symtab' as a root before creating the symbol table, otherwise the symbol table might be - collected in the interval between creation and registration. But - we must also ensure that 'symtab' is valid before registration - (in this case, by setting it to NULL). See topic/root. */ + collected in the interval between creation and + registration. But we must also ensure that 'symtab' is valid + before registration (in this case, by setting it to NULL). See + topic/root. */ symtab = NULL; - ref = &symtab; - res = mps_root_create_table(&symtab_root, arena, mps_rank_exact(), 0, - ref, 1); + res = mps_root_create_area(&symtab_root, arena, mps_rank_exact(), 0, + &symtab, &symtab + 1, + mps_scan_area, NULL, 0); if(res != MPS_RES_OK) error("Couldn't register symtab root"); /* The symbol table is strong-key weak-value. */ diff --git a/mps/example/scheme/scheme.c b/mps/example/scheme/scheme.c index 5b201a26a54..6c909c98f40 100644 --- a/mps/example/scheme/scheme.c +++ b/mps/example/scheme/scheme.c @@ -759,7 +759,6 @@ static void rehash(void) { size_t old_symtab_size = symtab_size; mps_root_t old_symtab_root = symtab_root; unsigned i; - mps_addr_t ref; mps_res_t res; symtab_size *= 2; @@ -770,14 +769,15 @@ static void rehash(void) { for(i = 0; i < symtab_size; ++i) symtab[i] = NULL; - /* Once the symbol table is initialized with scannable references (NULL - in this case) we must register it as a root before we copy objects - across from the old symbol table. The MPS might be moving objects - in memory at any time, and will arrange that both copies are updated - atomically to the mutator (this interpreter). */ - ref = symtab; - res = mps_root_create_table(&symtab_root, arena, mps_rank_exact(), 0, - ref, symtab_size); + /* %%MPS: Once the symbol table is initialized with scannable + references (NULL in this case) we must register it as a root + before we copy objects across from the old symbol table. The MPS + might be moving objects in memory at any time, and will arrange + that both copies are updated atomically to the mutator (this + interpreter). */ + res = mps_root_create_area(&symtab_root, arena, mps_rank_exact(), 0, + symtab, symtab + symtab_size, + mps_scan_area, NULL, 0); if(res != MPS_RES_OK) error("Couldn't register new symtab root"); for(i = 0; i < old_symtab_size; ++i) @@ -4243,7 +4243,6 @@ static int start(int argc, char *argv[]) size_t i; volatile obj_t env, op_env, obj; jmp_buf jb; - mps_addr_t ref; mps_res_t res; mps_root_t globals_root; int exit_code = EXIT_SUCCESS; @@ -4261,9 +4260,9 @@ static int start(int argc, char *argv[]) pointers -- NULL in this case. Random values look like false references into MPS memory and cause undefined behaviour (most likely assertion failures). See topic/root. */ - ref = symtab; - res = mps_root_create_table(&symtab_root, arena, mps_rank_exact(), 0, - ref, symtab_size); + res = mps_root_create_area(&symtab_root, arena, mps_rank_exact(), 0, + symtab, symtab + symtab_size, + mps_scan_area, NULL, 0); if(res != MPS_RES_OK) error("Couldn't register symtab root"); error_handler = &jb; From 07a1290f3ea48632bbc112bcf1e0728920a75813 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 1 Mar 2016 15:59:06 +0000 Subject: [PATCH 180/337] Eliminating closure_size from area scanners and root registration functions, as it isn't all that useful. Copied from Perforce Change: 189491 ServerID: perforce.ravenbrook.com --- mps/code/mpm.h | 6 ++-- mps/code/mps.h | 23 ++++-------- mps/code/mpsi.c | 9 +++-- mps/code/prmci3fr.c | 4 +-- mps/code/prmci3li.c | 4 +-- mps/code/prmci3xc.c | 4 +-- mps/code/prmci6fr.c | 4 +-- mps/code/prmci6li.c | 4 +-- mps/code/prmci6xc.c | 4 +-- mps/code/prot.h | 2 +- mps/code/root.c | 54 +++++++++++----------------- mps/code/scan.c | 12 +++---- mps/code/ss.c | 9 +++-- mps/code/ss.h | 7 ++-- mps/code/ssan.c | 4 +-- mps/code/ssixi3.c | 4 +-- mps/code/ssixi6.c | 4 +-- mps/code/ssw3i3mv.c | 4 +-- mps/code/ssw3i3pc.c | 4 +-- mps/code/ssw3i6mv.c | 6 ++-- mps/code/th.h | 2 +- mps/code/than.c | 4 +-- mps/code/thix.c | 8 ++--- mps/code/thw3i3.c | 9 +++-- mps/code/thw3i6.c | 8 ++--- mps/code/thxc.c | 9 +++-- mps/code/trace.c | 4 +-- mps/manual/source/topic/root.rst | 18 +++------- mps/manual/source/topic/scanning.rst | 20 ++++------- 29 files changed, 105 insertions(+), 149 deletions(-) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index ebe75a09707..17ece35d524 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -475,7 +475,7 @@ extern double TraceWorkFactor; extern Res TraceScanArea(ScanState ss, Word *base, Word *limit, mps_area_scan_t scan_area, - void *closure, size_t closure_size); + void *closure); extern void TraceScanSingleRef(TraceSet ts, Rank rank, Arena arena, Seg seg, Ref *refIO); @@ -966,7 +966,7 @@ extern Res RootCreateArea(Root *rootReturn, Arena arena, Rank rank, RootMode mode, Word *base, Word *limit, mps_area_scan_t scan_area, - void *closure, size_t closure_size); + void *closure); extern Res RootCreateAreaTagged(Root *rootReturn, Arena arena, Rank rank, RootMode mode, Word *base, Word *limit, @@ -975,7 +975,7 @@ extern Res RootCreateAreaTagged(Root *rootReturn, Arena arena, extern Res RootCreateThread(Root *rootReturn, Arena arena, Rank rank, Thread thread, mps_area_scan_t scan_area, - void *closure, size_t closure_size, + void *closure, Word *stackCold); extern Res RootCreateThreadTagged(Root *rootReturn, Arena arena, Rank rank, Thread thread, diff --git a/mps/code/mps.h b/mps/code/mps.h index 737677da518..65ab6d6bbf3 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -109,8 +109,7 @@ typedef struct mps_scan_tag_s { } mps_scan_tag_s; typedef mps_res_t (*mps_root_scan_t)(mps_ss_t, void *, size_t); -typedef mps_res_t (*mps_area_scan_t)(mps_ss_t, void *, void *, - void *, size_t); +typedef mps_res_t (*mps_area_scan_t)(mps_ss_t, void *, void *, void *); typedef mps_res_t (*mps_fmt_scan_t)(mps_ss_t, mps_addr_t, mps_addr_t); typedef mps_res_t (*mps_reg_scan_t)(mps_ss_t, mps_thr_t, void *, size_t); @@ -682,7 +681,7 @@ extern mps_res_t mps_root_create_table_masked(mps_root_t *, mps_arena_t, extern mps_res_t mps_root_create_area(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, void *, void *, - mps_area_scan_t, void *, size_t); + mps_area_scan_t, void *); extern mps_res_t mps_root_create_area_tagged(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, void *, void *, @@ -700,7 +699,7 @@ extern mps_res_t mps_root_create_thread(mps_root_t *, mps_arena_t, extern mps_res_t mps_root_create_thread_scanned(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_thr_t, mps_area_scan_t, - void *, size_t, + void *, void *); extern mps_res_t mps_root_create_thread_tagged(mps_root_t *, mps_arena_t, mps_rank_t, mps_rm_t, mps_thr_t, @@ -820,18 +819,10 @@ extern void mps_pool_check_free_space(mps_pool_t); /* Scanner Support */ -extern mps_res_t mps_scan_area(mps_ss_t, - void *, void *, - void *, size_t); -extern mps_res_t mps_scan_area_masked(mps_ss_t, - void *, void *, - void *, size_t); -extern mps_res_t mps_scan_area_tagged(mps_ss_t, - void *, void *, - void *, size_t); -extern mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t, - void *, void *, - void *, size_t); +extern mps_res_t mps_scan_area(mps_ss_t, void *, void *, void *); +extern mps_res_t mps_scan_area_masked(mps_ss_t, void *, void *, void *); +extern mps_res_t mps_scan_area_tagged(mps_ss_t, void *, void *, void *); +extern mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t, void *, void *, void *); extern mps_res_t mps_fix(mps_ss_t, mps_addr_t *); diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 655a226549c..c9acee2da5e 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1302,7 +1302,7 @@ mps_res_t mps_root_create_table(mps_root_t *mps_root_o, mps_arena_t arena, res = RootCreateArea(&root, arena, rank, mode, (void *)base, (void *)(base + size), - mps_scan_area, NULL, 0); + mps_scan_area, NULL); ArenaLeave(arena); @@ -1317,7 +1317,7 @@ mps_res_t mps_root_create_area(mps_root_t *mps_root_o, mps_rank_t mps_rank, mps_rm_t mps_rm, void *base, void *limit, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { Rank rank = (Rank)mps_rank; Root root; @@ -1335,7 +1335,7 @@ mps_res_t mps_root_create_area(mps_root_t *mps_root_o, res = RootCreateArea(&root, arena, rank, mode, base, limit, - scan_area, closure, closure_size); + scan_area, closure); ArenaLeave(arena); @@ -1478,7 +1478,6 @@ mps_res_t mps_root_create_thread_scanned(mps_root_t *mps_root_o, mps_thr_t thread, mps_area_scan_t scan_area, void *closure, - size_t closure_size, void *cold) { Rank rank = (Rank)mps_rank; @@ -1497,7 +1496,7 @@ mps_res_t mps_root_create_thread_scanned(mps_root_t *mps_root_o, /* See .root-mode. */ res = RootCreateThread(&root, arena, rank, thread, - scan_area, closure, closure_size, + scan_area, closure, (Word *)cold); ArenaLeave(arena); diff --git a/mps/code/prmci3fr.c b/mps/code/prmci3fr.c index d9f989db17c..87ec5f436dc 100644 --- a/mps/code/prmci3fr.c +++ b/mps/code/prmci3fr.c @@ -40,7 +40,7 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { Res res; @@ -51,7 +51,7 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, ss, (Word *)mfc->ucontext, (Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))), - scan_area, closure, closure_size + scan_area, closure ); return res; diff --git a/mps/code/prmci3li.c b/mps/code/prmci3li.c index 419f83f8b4a..da04ac4810b 100644 --- a/mps/code/prmci3li.c +++ b/mps/code/prmci3li.c @@ -103,7 +103,7 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { mcontext_t *mc; Res res; @@ -115,7 +115,7 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, res = TraceScanArea(ss, (Word *)mc, (Word *)((char *)mc + sizeof(*mc)), - scan_area, closure, closure_size); + scan_area, closure); return res; } diff --git a/mps/code/prmci3xc.c b/mps/code/prmci3xc.c index abeef4988c4..8eda902c244 100644 --- a/mps/code/prmci3xc.c +++ b/mps/code/prmci3xc.c @@ -98,7 +98,7 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { x86_thread_state32_t *mc; Res res; @@ -110,7 +110,7 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, res = TraceScanArea(ss, (Word *)mc, (Word *)((char *)mc + sizeof(*mc)), - scan_area, closure, closure_size); + scan_area, closure); return res; } diff --git a/mps/code/prmci6fr.c b/mps/code/prmci6fr.c index d8676d2a4c3..b1c1a67590f 100644 --- a/mps/code/prmci6fr.c +++ b/mps/code/prmci6fr.c @@ -34,7 +34,7 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { Res res; @@ -45,7 +45,7 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, ss, (Word *)mfc->ucontext, (Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))), - scan_area, closure, closure_size + scan_area, closure ); return res; diff --git a/mps/code/prmci6li.c b/mps/code/prmci6li.c index fe7cb96627a..67354c99414 100644 --- a/mps/code/prmci6li.c +++ b/mps/code/prmci6li.c @@ -107,7 +107,7 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { mcontext_t *mc; Res res; @@ -119,7 +119,7 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, res = TraceScanArea(ss, (Word *)mc, (Word *)((char *)mc + sizeof(*mc)), - scan_area, closure, closure_size); + scan_area, closure); return res; } diff --git a/mps/code/prmci6xc.c b/mps/code/prmci6xc.c index 69591a321ab..ae8ef06f739 100644 --- a/mps/code/prmci6xc.c +++ b/mps/code/prmci6xc.c @@ -101,7 +101,7 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc) Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { x86_thread_state64_t *mc; Res res; @@ -113,7 +113,7 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, res = TraceScanArea(ss, (Word *)mc, (Word *)((char *)mc + sizeof(*mc)), - scan_area, closure, closure_size); + scan_area, closure); return res; } diff --git a/mps/code/prot.h b/mps/code/prot.h index c2ae9d20e69..f3104cb27b7 100644 --- a/mps/code/prot.h +++ b/mps/code/prot.h @@ -32,7 +32,7 @@ extern Res ProtStepInstruction(MutatorFaultContext context); extern Addr MutatorFaultContextSP(MutatorFaultContext mfc); extern Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, mps_area_scan_t scan, - void *closure, size_t closure_size); + void *closure); #endif /* prot_h */ diff --git a/mps/code/root.c b/mps/code/root.c index 82737e536b0..ae16e3dcd13 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -17,13 +17,8 @@ SRCID(root, "$Id$"); #define RootSig ((Sig)0x51960029) /* SIGnature ROOT */ -typedef struct ClosureStruct { - void *p; - size_t s; -} ClosureStruct; - typedef union AreaScanUnion { - ClosureStruct closure; + void *closure; mps_scan_tag_s tag; /* tag for scanning */ } AreaScanUnion; @@ -44,7 +39,8 @@ typedef struct RootStruct { union RootUnion { struct { mps_root_scan_t scan; /* the function which does the scanning */ - ClosureStruct closure; /* closure for scan function */ + void *p; /* closure for scan function */ + size_t s; /* closure for scan function */ } fun; struct { Word *base; /* beginning of area */ @@ -274,7 +270,7 @@ Res RootCreateArea(Root *rootReturn, Arena arena, Rank rank, RootMode mode, Word *base, Word *limit, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { Res res; union RootUnion theUnion; @@ -292,8 +288,7 @@ Res RootCreateArea(Root *rootReturn, Arena arena, theUnion.area.base = base; theUnion.area.limit = limit; theUnion.area.scan_area = scan_area; - theUnion.area.the.closure.p = closure; - theUnion.area.the.closure.s = closure_size; + theUnion.area.the.closure = closure; res = rootCreateProtectable(rootReturn, arena, rank, mode, RootAREA, (Addr)base, (Addr)limit, &theUnion); @@ -327,7 +322,7 @@ Res RootCreateAreaTagged(Root *rootReturn, Arena arena, Res RootCreateThread(Root *rootReturn, Arena arena, Rank rank, Thread thread, mps_area_scan_t scan_area, - void *closure, size_t closure_size, + void *closure, Word *stackCold) { union RootUnion theUnion; @@ -342,8 +337,7 @@ Res RootCreateThread(Root *rootReturn, Arena arena, theUnion.thread.thread = thread; theUnion.thread.scan_area = scan_area; - theUnion.thread.the.closure.p = closure; - theUnion.thread.the.closure.s = closure_size; + theUnion.thread.the.closure = closure; theUnion.thread.stackCold = stackCold; return rootCreate(rootReturn, arena, rank, (RootMode)0, RootTHREAD, @@ -416,8 +410,8 @@ Res RootCreateFun(Root *rootReturn, Arena arena, Rank rank, AVER(FUNCHECK(scan)); theUnion.fun.scan = scan; - theUnion.fun.closure.p = p; - theUnion.fun.closure.s = s; + theUnion.fun.p = p; + theUnion.fun.s = s; return rootCreate(rootReturn, arena, rank, (RootMode)0, RootFUN, &theUnion); } @@ -535,8 +529,7 @@ Res RootScan(ScanState ss, Root root) root->the.area.base, root->the.area.limit, root->the.area.scan_area, - root->the.area.the.closure.p, - root->the.area.the.closure.s); + root->the.area.the.closure); if (res != ResOK) goto failScan; break; @@ -546,16 +539,15 @@ Res RootScan(ScanState ss, Root root) root->the.area.base, root->the.area.limit, root->the.area.scan_area, - &root->the.area.the.tag, - sizeof(root->the.area.the.tag)); + &root->the.area.the.tag); if (res != ResOK) goto failScan; break; case RootFUN: res = root->the.fun.scan(&ss->ss_s, - root->the.fun.closure.p, - root->the.fun.closure.s); + root->the.fun.p, + root->the.fun.s); if (res != ResOK) goto failScan; break; @@ -564,8 +556,7 @@ Res RootScan(ScanState ss, Root root) res = ThreadScan(ss, root->the.thread.thread, root->the.thread.stackCold, root->the.thread.scan_area, - root->the.thread.the.closure.p, - root->the.thread.the.closure.s); + root->the.thread.the.closure); if (res != ResOK) goto failScan; break; @@ -574,8 +565,7 @@ Res RootScan(ScanState ss, Root root) res = ThreadScan(ss, root->the.thread.thread, root->the.thread.stackCold, root->the.thread.scan_area, - &root->the.thread.the.tag, - sizeof(root->the.thread.the.tag)); + &root->the.thread.the.tag); if (res != ResOK) goto failScan; break; @@ -706,11 +696,10 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) switch(root->var) { case RootAREA: res = WriteF(stream, depth + 2, - "area base $A limit $A scan_area closure $P closure_size $U\n", + "area base $A limit $A scan_area closure $P\n", (WriteFA)root->the.area.base, (WriteFA)root->the.area.limit, - (WriteFP)root->the.area.the.closure.p, - (WriteFP)root->the.area.the.closure.s, + (WriteFP)root->the.area.the.closure, NULL); if (res != ResOK) return res; @@ -732,8 +721,8 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) res = WriteF(stream, depth + 2, "scan function $F\n", (WriteFF)root->the.fun.scan, "environment p $P s $W\n", - (WriteFP)root->the.fun.closure.p, - (WriteFW)root->the.fun.closure.s, + (WriteFP)root->the.fun.p, + (WriteFW)root->the.fun.s, NULL); if (res != ResOK) return res; @@ -742,9 +731,8 @@ Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth) case RootTHREAD: res = WriteF(stream, depth + 2, "thread $P\n", (WriteFP)root->the.thread.thread, - "closure $P size $U\n", - (WriteFP)root->the.thread.the.closure.p, - (WriteFU)root->the.thread.the.closure.s, + "closure $P\n", + (WriteFP)root->the.thread.the.closure, "stackCold $P\n", (WriteFP)root->the.thread.stackCold, NULL); if (res != ResOK) diff --git a/mps/code/scan.c b/mps/code/scan.c index 99b4d5d0987..3e01c9fed17 100644 --- a/mps/code/scan.c +++ b/mps/code/scan.c @@ -27,10 +27,9 @@ mps_res_t mps_scan_area(mps_ss_t ss, void *base, void *limit, - void *closure, size_t closure_size) + void *closure) { (void)closure; /* unused */ - (void)closure_size; /* unused */ MPS_SCAN_BEGIN(ss) { mps_word_t *p = base; @@ -86,11 +85,10 @@ mps_res_t mps_scan_area(mps_ss_t ss, mps_res_t mps_scan_area_masked(mps_ss_t ss, void *base, void *limit, - void *closure, size_t closure_size) + void *closure) { mps_scan_tag_t tag = closure; mps_word_t mask = tag->mask; - (void)closure_size; /* unused */ MPS_SCAN_AREA_TAGGED(1); @@ -109,12 +107,11 @@ mps_res_t mps_scan_area_masked(mps_ss_t ss, mps_res_t mps_scan_area_tagged(mps_ss_t ss, void *base, void *limit, - void *closure, size_t closure_size) + void *closure) { mps_scan_tag_t tag = closure; mps_word_t mask = tag->mask; mps_word_t pattern = tag->pattern; - (void)closure_size; /* unused */ MPS_SCAN_AREA_TAGGED(tag_bits == pattern); @@ -139,12 +136,11 @@ mps_res_t mps_scan_area_tagged(mps_ss_t ss, mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t ss, void *base, void *limit, - void *closure, size_t closure_size) + void *closure) { mps_scan_tag_t tag = closure; mps_word_t mask = tag->mask; mps_word_t pattern = tag->pattern; - (void)closure_size; /* unused */ MPS_SCAN_AREA_TAGGED(tag_bits == 0 || tag_bits == pattern); diff --git a/mps/code/ss.c b/mps/code/ss.c index c0c109e01d2..fb23794c4a8 100644 --- a/mps/code/ss.c +++ b/mps/code/ss.c @@ -26,8 +26,7 @@ SRCID(ss, "$Id$"); Res StackScanInner(ScanState ss, Word *stackCold, Word *stackHot, Count nSavedRegs, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, void *closure) { Arena arena; Res res; @@ -50,16 +49,16 @@ Res StackScanInner(ScanState ss, Word *stackCold, Word *stackHot, AVER(stackHot < arena->stackAtArenaEnter); AVER(arena->stackAtArenaEnter < stackCold); res = TraceScanArea(ss, stackHot, stackHot + nSavedRegs, - scan_area, closure, closure_size); + scan_area, closure); if (res != ResOK) return res; res = TraceScanArea(ss, arena->stackAtArenaEnter, stackCold, - scan_area, closure, closure_size); + scan_area, closure); if (res != ResOK) return res; } else { res = TraceScanArea(ss, stackHot, stackCold, - scan_area, closure, closure_size); + scan_area, closure); if (res != ResOK) return res; } diff --git a/mps/code/ss.h b/mps/code/ss.h index 02dc34f9fcf..75d939194e2 100644 --- a/mps/code/ss.h +++ b/mps/code/ss.h @@ -33,11 +33,10 @@ */ extern Res StackScan(ScanState ss, Word *stackCold, - mps_area_scan_t scan_area, - void *closure, size_t closure_size); + mps_area_scan_t scan_area, void *closure); extern Res StackScanInner(ScanState ss, Word *stackCold, Word *stackHot, - Count nSavedRegs, mps_area_scan_t scan_area, - void *closure, size_t closure_size); + Count nSavedRegs, + mps_area_scan_t scan_area, void *closure); #endif /* ss_h */ diff --git a/mps/code/ssan.c b/mps/code/ssan.c index cbb0daa4dd2..2a36f493351 100644 --- a/mps/code/ssan.c +++ b/mps/code/ssan.c @@ -23,7 +23,7 @@ SRCID(ssan, "$Id$"); Res StackScan(ScanState ss, Word *stackCold, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { jmp_buf jb; Word *stackHot = (void *)&jb; @@ -38,7 +38,7 @@ Res StackScan(ScanState ss, Word *stackCold, (void)setjmp(jb); return StackScanInner(ss, stackCold, stackHot, sizeof jb / sizeof(Word), - scan_area, closure, closure_size); + scan_area, closure); } diff --git a/mps/code/ssixi3.c b/mps/code/ssixi3.c index 56fb1290a66..a922cabc5a6 100644 --- a/mps/code/ssixi3.c +++ b/mps/code/ssixi3.c @@ -51,7 +51,7 @@ SRCID(ssixi3, "$Id$"); Res StackScan(ScanState ss, Word *stackCold, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { Word calleeSaveRegs[4]; @@ -65,7 +65,7 @@ Res StackScan(ScanState ss, Word *stackCold, ASMV("mov %%ebp, %0" : "=m" (calleeSaveRegs[3])); return StackScanInner(ss, stackCold, calleeSaveRegs, NELEMS(calleeSaveRegs), - scan_area, closure, closure_size); + scan_area, closure); } diff --git a/mps/code/ssixi6.c b/mps/code/ssixi6.c index 71a3dd40cf2..2d70d62697c 100644 --- a/mps/code/ssixi6.c +++ b/mps/code/ssixi6.c @@ -49,7 +49,7 @@ SRCID(ssixi6, "$Id$"); Res StackScan(ScanState ss, Word *stackCold, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { Word calleeSaveRegs[6]; @@ -65,7 +65,7 @@ Res StackScan(ScanState ss, Word *stackCold, ASMV("mov %%r15, %0" : "=m" (calleeSaveRegs[5])); return StackScanInner(ss, stackCold, calleeSaveRegs, NELEMS(calleeSaveRegs), - scan_area, closure, closure_size); + scan_area, closure); } diff --git a/mps/code/ssw3i3mv.c b/mps/code/ssw3i3mv.c index da95ebb106d..2b2d0bd4d08 100644 --- a/mps/code/ssw3i3mv.c +++ b/mps/code/ssw3i3mv.c @@ -24,7 +24,7 @@ SRCID(ssw3i3mv, "$Id$"); Res StackScan(ScanState ss, Word *stackCold, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { jmp_buf jb; @@ -45,7 +45,7 @@ Res StackScan(ScanState ss, Word *stackCold, AVER(offsetof(_JUMP_BUFFER, Esi) == offsetof(_JUMP_BUFFER, Ebx) + 8); return StackScanInner(ss, stackCold, (Word *)&((_JUMP_BUFFER *)jb)->Ebx, 3, - scan_area, closure, closure_size); + scan_area, closure); } /* C. COPYRIGHT AND LICENSE diff --git a/mps/code/ssw3i3pc.c b/mps/code/ssw3i3pc.c index 913a3d5a035..bead20fe898 100644 --- a/mps/code/ssw3i3pc.c +++ b/mps/code/ssw3i3pc.c @@ -48,7 +48,7 @@ typedef struct __JUMP_BUFFER { Res StackScan(ScanState ss, Word *stackCold, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { jmp_buf jb; @@ -68,7 +68,7 @@ Res StackScan(ScanState ss, Word *stackCold, AVER(offsetof(_JUMP_BUFFER, Esi) == offsetof(_JUMP_BUFFER, Ebx) + 8); return StackScanInner(ss, stackCold, (Word *)&((_JUMP_BUFFER *)jb)->Ebx, 3, - scan_area, closure, closure_size); + scan_area, closure); } diff --git a/mps/code/ssw3i6mv.c b/mps/code/ssw3i6mv.c index 9bc3a8e573b..884424d259c 100644 --- a/mps/code/ssw3i6mv.c +++ b/mps/code/ssw3i6mv.c @@ -31,8 +31,8 @@ SRCID(ssw3i6mv, "$Id$"); Res StackScan(ScanState ss, Word *stackCold, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area + void *closure) { jmp_buf jb; @@ -64,7 +64,7 @@ Res StackScan(ScanState ss, Word *stackCold, AVER(offsetof(_JUMP_BUFFER, R15) == offsetof(_JUMP_BUFFER, Rbx) + 64); return StackScanInner(ss, stackCold, (Word *)&((_JUMP_BUFFER *)jb)->Rbx, 9, - scan_area, closure, closure_size); + scan_area, closure); } /* C. COPYRIGHT AND LICENSE diff --git a/mps/code/th.h b/mps/code/th.h index 39f1d91133b..29a4d243d1d 100644 --- a/mps/code/th.h +++ b/mps/code/th.h @@ -70,7 +70,7 @@ extern Arena ThreadArena(Thread thread); extern Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, mps_area_scan_t scan_area, - void *closure, size_t closure_size); + void *closure); #endif /* th_h */ diff --git a/mps/code/than.c b/mps/code/than.c index cf41e02f50b..3e2dbaa81a0 100644 --- a/mps/code/than.c +++ b/mps/code/than.c @@ -119,10 +119,10 @@ Arena ThreadArena(Thread thread) Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { UNUSED(thread); - return StackScan(ss, stackCold, scan_area, closure, closure_size); + return StackScan(ss, stackCold, scan_area, closure); } diff --git a/mps/code/thix.c b/mps/code/thix.c index 6e51d2a5d5f..219ae33bcdd 100644 --- a/mps/code/thix.c +++ b/mps/code/thix.c @@ -241,7 +241,7 @@ Arena ThreadArena(Thread thread) Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { pthread_t self; Res res; @@ -251,7 +251,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, if(pthread_equal(self, thread->id)) { /* scan this thread's stack */ AVER(thread->alive); - res = StackScan(ss, stackCold, scan_area, closure, closure_size); + res = StackScan(ss, stackCold, scan_area, closure); if(res != ResOK) return res; } else if (thread->alive) { @@ -273,12 +273,12 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, * stackCold (.stack.full-descend) */ res = TraceScanArea(ss, stackBase, stackLimit, - scan_area, closure, closure_size); + scan_area, closure); if(res != ResOK) return res; /* scan the registers in the mutator fault context */ - res = MutatorFaultContextScan(ss, mfc, scan_area, closure, closure_size); + res = MutatorFaultContextScan(ss, mfc, scan_area, closure); if(res != ResOK) return res; } diff --git a/mps/code/thw3i3.c b/mps/code/thw3i3.c index e5fa73a8082..03675ed46b2 100644 --- a/mps/code/thw3i3.c +++ b/mps/code/thw3i3.c @@ -68,8 +68,7 @@ SRCID(thw3i3, "$Id$"); Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, void *closure) { DWORD id; Res res; @@ -107,7 +106,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, * stackCold (.stack.full-descend) */ res = TraceScanArea(ss, stackBase, stackLimit, - scan_area, closure, closure_size); + scan_area, closure); if(res != ResOK) return res; @@ -118,12 +117,12 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, */ res = TraceScanArea(ss, (Word *)&context, (Word *)((char *)&context + sizeof(CONTEXT)), - scan_area, closure, closure_size); + scan_area, closure); if(res != ResOK) return res; } else { /* scan this thread's stack */ - res = StackScan(ss, stackCold, scan_area, closure, closure_size); + res = StackScan(ss, stackCold, scan_area, closure); if(res != ResOK) return res; } diff --git a/mps/code/thw3i6.c b/mps/code/thw3i6.c index 090c2c43aa9..67350022ad6 100644 --- a/mps/code/thw3i6.c +++ b/mps/code/thw3i6.c @@ -69,7 +69,7 @@ SRCID(thw3i6, "$Id$"); Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { DWORD id; Res res; @@ -107,7 +107,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, * stackCold (.stack.full-descend) */ res = TraceScanArea(ss, stackBase, stackLimit, - scan_area, closure, closure_size); + scan_area, closure); if(res != ResOK) return res; @@ -118,12 +118,12 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, */ res = TraceScanArea(ss, (Word *)&context, (Word *)((char *)&context + sizeof(CONTEXT)), - scan_area, closure, closure_size); + scan_area, closure); if(res != ResOK) return res; } else { /* scan this thread's stack */ - res = StackScan(ss, stackCold, scan_area, closure, closure_size); + res = StackScan(ss, stackCold, scan_area, closure); if(res != ResOK) return res; } diff --git a/mps/code/thxc.c b/mps/code/thxc.c index e5277072dc5..3bb449d46fe 100644 --- a/mps/code/thxc.c +++ b/mps/code/thxc.c @@ -211,8 +211,7 @@ Arena ThreadArena(Thread thread) #include "prmcxc.h" Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, - mps_area_scan_t scan_area, - void *closure, size_t closure_size) + mps_area_scan_t scan_area, void *closure) { mach_port_t self; Res res; @@ -223,7 +222,7 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, if (thread->port == self) { /* scan this thread's stack */ AVER(thread->alive); - res = StackScan(ss, stackCold, scan_area, closure, closure_size); + res = StackScan(ss, stackCold, scan_area, closure); if(res != ResOK) return res; } else if (thread->alive) { @@ -261,12 +260,12 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, * stackCold (.stack.full-descend) */ res = TraceScanArea(ss, stackBase, stackLimit, - scan_area, closure, closure_size); + scan_area, closure); if(res != ResOK) return res; /* scan the registers in the mutator fault context */ - res = MutatorFaultContextScan(ss, &mfcStruct, scan_area, closure, closure_size); + res = MutatorFaultContextScan(ss, &mfcStruct, scan_area, closure); if(res != ResOK) return res; } diff --git a/mps/code/trace.c b/mps/code/trace.c index 001c5b90526..10592f7df2e 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1432,7 +1432,7 @@ void TraceScanSingleRef(TraceSet ts, Rank rank, Arena arena, Res TraceScanArea(ScanState ss, Word *base, Word *limit, mps_area_scan_t scan_area, - void *closure, size_t closure_size) + void *closure) { AVERT(ScanState, ss); AVER(base != NULL); @@ -1446,7 +1446,7 @@ Res TraceScanArea(ScanState ss, Word *base, Word *limit, scan_area. */ ss->scannedSize += AddrOffset(base, limit); - return scan_area(&ss->ss_s, base, limit, closure, closure_size); + return scan_area(&ss->ss_s, base, limit, closure); } diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index 743c865f6a5..3b49d120a3f 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -489,7 +489,7 @@ Root interface requires expertise with the platform's virtual memory interface. -.. c:function:: mps_res_t mps_root_create_thread_scanned(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thread, mps_area_scan_t scan_area, void *closure, size_t closure_size, void *cold) +.. c:function:: mps_res_t mps_root_create_thread_scanned(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thread, mps_area_scan_t scan_area, void *closure, void *cold) Register a :term:`root` that consists of the :term:`references` in a :term:`thread's ` registers and stack, scanned by an @@ -511,13 +511,9 @@ Root interface :c:func:`mps_scan_area`, or a similar user-defined function. See :ref:`topic-scanning-area`. - ``closure`` is an arbitrary pointer that is passed to ``scan_area`` + ``closure`` is an arbitrary pointer that will be passed to ``scan_area`` and intended to point to any parameters it needs. - ``closure_size`` is an arbitrary size that is passed to - ``scan_area`` but is conventionally the size of the parameter - object pointer to by ``closure``. - ``cold`` is a pointer to the :term:`cold end` of stack to be scanned. On platforms where the stack grows downwards (currently, all supported platforms), locations below this address will be @@ -531,7 +527,7 @@ 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_area(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, void *base, void *limit, mps_area_scan_t scan_area, void *closure, size_t closure_size) +.. c:function:: mps_res_t mps_root_create_area(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, void *base, void *limit, mps_area_scan_t scan_area, void *closure) Register a :term:`root` that consists of an area of memory scanned by an area scanning function. @@ -553,12 +549,8 @@ Root interface :c:func:`mps_scan_area`, or a similar user-defined function. See :ref:`topic-scanning-area`. - ``closure`` is an arbitrary pointer that is passed to ``scan_area`` - and intended to point to any parameters it needs. - - ``closure_size`` is an arbitrary size that is passed to - ``scan_area`` but is conventionally the size of the parameter - object pointer to by ``closure``. + ``closure`` is an arbitrary pointer that will be passed to + ``scan_area`` and intended to point to any parameters it needs. Returns :c:macro:`MPS_RES_OK` if the root was registered successfully, :c:macro:`MPS_RES_MEMORY` if the new root diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst index cac8d7457e3..eab99c79b2f 100644 --- a/mps/manual/source/topic/scanning.rst +++ b/mps/manual/source/topic/scanning.rst @@ -531,7 +531,7 @@ the scanners, found in ``scan.c`` in the MPS source code. mps_res_t scan(mps_ss_t ss, void *base, void *limit, - void *closure, size_t closure_size); + void *closure); ``ss`` is the :term:`scan state`. @@ -545,17 +545,11 @@ the scanners, found in ``scan.c`` in the MPS source code. :c:func:`mps_root_create_thread_tagged` then it is the value of the ``closure`` argument originally passed to that function. - ``closure_size`` is an arbitrary size, conventionally used for the - size of the :term:`closure` pointed to by ``closure``. For example, - if the scanner was originally registered with - :c:func:`mps_root_create_thread_tagged` then it is the value of - the ``closure_size`` argument originally passed to that function. - -.. c:function:: mps_res_t mps_scan_area(mps_ss_t ss, void *base, void *limit, void *closure, size_t closure_size) +.. c:function:: mps_res_t mps_scan_area(mps_ss_t ss, void *base, void *limit, void *closure) Scan an area of memory :term:`fixing ` every word. - ``closure`` and ``closure_size`` are ignored. Expects ``base`` - and ``limit`` to be word-aligned. + ``closure`` is ignored. Expects ``base`` and ``limit`` to be + word-aligned. This scanner is appropriate for use when all words in the area are simple untagged references. @@ -586,7 +580,7 @@ the scanners, found in ``scan.c`` in the MPS source code. interpretation depends on which area scanner it is passed to. See the documentation for the individual area scanners. -.. c:function:: mps_res_t mps_scan_area_masked(mps_ss_t ss, void *base, void *limit, void *closure, size_t closure_size) +.. c:function:: mps_res_t mps_scan_area_masked(mps_ss_t ss, void *base, void *limit, void *closure) Scan an area of memory :term:`fixing ` every word, but remove tag bits before fixing references, and restore them afterwards. @@ -603,7 +597,7 @@ the scanners, found in ``scan.c`` in the MPS source code. references no matter what tag they have. This can be especially useful if you are debugging your tagging scheme. -.. c:function:: mps_res_t mps_scan_area_tagged(mps_ss_t ss, void *base, void *limit, void *closure, size_t closure_size) +.. c:function:: mps_res_t mps_scan_area_tagged(mps_ss_t ss, void *base, void *limit, void *closure) Scan an area of memory :term:`fixing ` only words whose masked bits match a particular tag pattern. ``closure`` should @@ -626,7 +620,7 @@ the scanners, found in ``scan.c`` in the MPS source code. version of the pointer. See :c:func:`mps_root_create_thread_tagged`. -.. c:function:: mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t ss, void *base, void *limit, void *closure, size_t closure_size) +.. c:function:: mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t ss, void *base, void *limit, void *closure) Scan an area of memory :term:`fixing ` only words whose masked bits are zero or match a particular tag pattern. From f4ed2a04a26514d0648b2ad022a92c60664e6e20 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 1 Mar 2016 16:03:55 +0000 Subject: [PATCH 181/337] Removing redundant closure size argument from scheme example. Copied from Perforce Change: 189494 ServerID: perforce.ravenbrook.com --- mps/example/scheme/scheme-advanced.c | 2 +- mps/example/scheme/scheme.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mps/example/scheme/scheme-advanced.c b/mps/example/scheme/scheme-advanced.c index 4d75ed854bc..707390b2962 100644 --- a/mps/example/scheme/scheme-advanced.c +++ b/mps/example/scheme/scheme-advanced.c @@ -4331,7 +4331,7 @@ static int start(int argc, char *argv[]) symtab = NULL; res = mps_root_create_area(&symtab_root, arena, mps_rank_exact(), 0, &symtab, &symtab + 1, - mps_scan_area, NULL, 0); + mps_scan_area, NULL); if(res != MPS_RES_OK) error("Couldn't register symtab root"); /* The symbol table is strong-key weak-value. */ diff --git a/mps/example/scheme/scheme.c b/mps/example/scheme/scheme.c index 6c909c98f40..4a10b5c9b10 100644 --- a/mps/example/scheme/scheme.c +++ b/mps/example/scheme/scheme.c @@ -777,7 +777,7 @@ static void rehash(void) { interpreter). */ res = mps_root_create_area(&symtab_root, arena, mps_rank_exact(), 0, symtab, symtab + symtab_size, - mps_scan_area, NULL, 0); + mps_scan_area, NULL); if(res != MPS_RES_OK) error("Couldn't register new symtab root"); for(i = 0; i < old_symtab_size; ++i) @@ -4262,7 +4262,7 @@ static int start(int argc, char *argv[]) assertion failures). See topic/root. */ res = mps_root_create_area(&symtab_root, arena, mps_rank_exact(), 0, symtab, symtab + symtab_size, - mps_scan_area, NULL, 0); + mps_scan_area, NULL); if(res != MPS_RES_OK) error("Couldn't register symtab root"); error_handler = &jb; From a551694ce1e54ba73237e716343b9ef1c6b915d7 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 1 Mar 2016 17:09:56 +0000 Subject: [PATCH 182/337] Branching master to branch/2016-03-01/closure-size. Copied from Perforce Change: 189498 ServerID: perforce.ravenbrook.com From aa0412e07192eb002c12b2e8ffde645f018229a3 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 1 Mar 2016 17:20:50 +0000 Subject: [PATCH 183/337] Removing the mostly unused size component of the closure convention. Copied from Perforce Change: 189503 ServerID: perforce.ravenbrook.com --- mps/code/abq.c | 4 +- mps/code/abq.h | 4 +- mps/code/abqtest.c | 8 ++-- mps/code/arena.c | 10 ++--- mps/code/arenacl.c | 10 ++--- mps/code/arenavm.c | 21 ++++----- mps/code/cbs.c | 102 +++++++++++++++++++++----------------------- mps/code/failover.c | 6 +-- mps/code/fbmtest.c | 18 ++++---- mps/code/freelist.c | 33 ++++++++------ mps/code/land.c | 40 ++++++++--------- mps/code/landtest.c | 7 ++- mps/code/mpm.h | 4 +- mps/code/mpmtypes.h | 8 ++-- mps/code/poolmfs.c | 14 +++--- mps/code/poolmfs.h | 4 +- mps/code/poolmv2.c | 32 ++++++-------- mps/code/poolmvff.c | 11 ++--- mps/code/splay.c | 79 ++++++++++++++++------------------ mps/code/splay.h | 10 ++--- mps/code/tree.c | 22 +++++----- mps/code/tree.h | 8 ++-- 22 files changed, 210 insertions(+), 245 deletions(-) diff --git a/mps/code/abq.c b/mps/code/abq.c index 0e9b808a277..7a3df81408e 100644 --- a/mps/code/abq.c +++ b/mps/code/abq.c @@ -232,7 +232,7 @@ Count ABQDepth(ABQ abq) /* ABQIterate -- call 'visitor' for each element in an ABQ */ -void ABQIterate(ABQ abq, ABQVisitor visitor, void *closureP, Size closureS) +void ABQIterate(ABQ abq, ABQVisitor visitor, void *closure) { Index copy, index, in; @@ -247,7 +247,7 @@ void ABQIterate(ABQ abq, ABQVisitor visitor, void *closureP, Size closureS) void *element = ABQElement(abq, index); Bool delete = FALSE; Bool cont; - cont = (*visitor)(&delete, element, closureP, closureS); + cont = (*visitor)(&delete, element, closure); AVERT(Bool, cont); AVERT(Bool, delete); if (!delete) { diff --git a/mps/code/abq.h b/mps/code/abq.h index 85cdfcd5756..e781d00e156 100644 --- a/mps/code/abq.h +++ b/mps/code/abq.h @@ -24,7 +24,7 @@ typedef struct ABQStruct *ABQ; typedef Res (*ABQDescribeElement)(void *element, mps_lib_FILE *stream, Count depth); -typedef Bool (*ABQVisitor)(Bool *deleteReturn, void *element, void *closureP, Size closureS); +typedef Bool (*ABQVisitor)(Bool *deleteReturn, void *element, void *closure); extern Res ABQInit(Arena arena, ABQ abq, void *owner, Count elements, Size elementSize); extern Bool ABQCheck(ABQ abq); @@ -36,7 +36,7 @@ extern Res ABQDescribe(ABQ abq, ABQDescribeElement describeElement, mps_lib_FILE extern Bool ABQIsEmpty(ABQ abq); extern Bool ABQIsFull(ABQ abq); extern Count ABQDepth(ABQ abq); -extern void ABQIterate(ABQ abq, ABQVisitor visitor, void *closureP, Size closureS); +extern void ABQIterate(ABQ abq, ABQVisitor visitor, void *closure); /* Types */ diff --git a/mps/code/abqtest.c b/mps/code/abqtest.c index 9aad3351cb6..b9618b2ff60 100644 --- a/mps/code/abqtest.c +++ b/mps/code/abqtest.c @@ -92,12 +92,10 @@ typedef struct TestClosureStruct { } TestClosureStruct; static Bool TestDeleteCallback(Bool *deleteReturn, void *element, - void *closureP, Size closureS) + void *closure) { TestBlock *a = (TestBlock *)element; - TestClosure cl = (TestClosure)closureP; - AVER(closureS == UNUSED_SIZE); - UNUSED(closureS); + TestClosure cl = (TestClosure)closure; if (*a == cl->b) { *deleteReturn = TRUE; cl->res = ResOK; @@ -145,7 +143,7 @@ static void step(void) cdie(b != NULL, "found to delete"); cl.b = b; cl.res = ResFAIL; - ABQIterate(&abq, TestDeleteCallback, &cl, UNUSED_SIZE); + ABQIterate(&abq, TestDeleteCallback, &cl); cdie(cl.res == ResOK, "ABQIterate"); } } diff --git a/mps/code/arena.c b/mps/code/arena.c index 519a85d735b..860715c5059 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -406,13 +406,11 @@ void ArenaFinish(Arena arena) /* ArenaDestroy -- destroy the arena */ static void arenaMFSPageFreeVisitor(Pool pool, Addr base, Size size, - void *closureP, Size closureS) + void *closure) { AVERT(Pool, pool); - AVER(closureP == UNUSED_POINTER); - AVER(closureS == UNUSED_SIZE); - UNUSED(closureP); - UNUSED(closureS); + AVER(closure == UNUSED_POINTER); + UNUSED(closure); UNUSED(size); AVER(size == ArenaGrainSize(PoolArena(pool))); arenaFreePage(PoolArena(pool), base, pool); @@ -431,7 +429,7 @@ static void arenaFreeLandFinish(Arena arena) /* The CBS block pool can't free its own memory via ArenaFree because * that would use the free land. */ MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor, - UNUSED_POINTER, UNUSED_SIZE); + UNUSED_POINTER); arena->hasFreeLand = FALSE; LandFinish(ArenaFreeLand(arena)); diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c index cd5c24fe46a..ff5a0d8e462 100644 --- a/mps/code/arenacl.c +++ b/mps/code/arenacl.c @@ -182,7 +182,7 @@ static Res ClientChunkInit(Chunk chunk, BootBlock boot) /* clientChunkDestroy -- destroy a ClientChunk */ -static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS) +static Bool clientChunkDestroy(Tree tree, void *closure) { Arena arena; Chunk chunk; @@ -190,10 +190,8 @@ static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS) Size size; AVERT(Tree, tree); - AVER(closureP == UNUSED_POINTER); - UNUSED(closureP); - AVER(closureS == UNUSED_SIZE); - UNUSED(closureS); + AVER(closure == UNUSED_POINTER); + UNUSED(closure); chunk = ChunkOfTree(tree); AVERT(Chunk, chunk); @@ -337,7 +335,7 @@ static void ClientArenaFinish(Arena arena) * */ arena->primary = NULL; TreeTraverseAndDelete(&arena->chunkTree, clientChunkDestroy, - UNUSED_POINTER, UNUSED_SIZE); + UNUSED_POINTER); clientArena->sig = SigInvalid; diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index f5666a1e7e6..4b5f9f73cd0 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -409,16 +409,14 @@ static Res VMChunkInit(Chunk chunk, BootBlock boot) /* vmChunkDestroy -- destroy a VMChunk */ -static Bool vmChunkDestroy(Tree tree, void *closureP, Size closureS) +static Bool vmChunkDestroy(Tree tree, void *closure) { Chunk chunk; VMChunk vmChunk; AVERT(Tree, tree); - AVER(closureP == UNUSED_POINTER); - UNUSED(closureP); - AVER(closureS == UNUSED_SIZE); - UNUSED(closureS); + AVER(closure == UNUSED_POINTER); + UNUSED(closure); chunk = ChunkOfTree(tree); AVERT(Chunk, chunk); @@ -636,7 +634,7 @@ static void VMArenaFinish(Arena arena) * */ arena->primary = NULL; TreeTraverseAndDelete(&arena->chunkTree, vmChunkDestroy, - UNUSED_POINTER, UNUSED_SIZE); + UNUSED_POINTER); /* Destroying the chunks should have purged and removed all spare pages. */ RingFinish(&vmArena->spareRing); @@ -1094,16 +1092,14 @@ static void VMFree(Addr base, Size size, Pool pool) /* vmChunkCompact -- delete chunk if empty and not primary */ -static Bool vmChunkCompact(Tree tree, void *closureP, Size closureS) +static Bool vmChunkCompact(Tree tree, void *closure) { Chunk chunk; - Arena arena = closureP; + Arena arena = closure; VMArena vmArena; AVERT(Tree, tree); AVERT(Arena, arena); - AVER(closureS == UNUSED_SIZE); - UNUSED(closureS); vmArena = Arena2VMArena(arena); AVERT(VMArena, vmArena); @@ -1117,7 +1113,7 @@ static Bool vmChunkCompact(Tree tree, void *closureP, Size closureS) /* Callback before destroying the chunk, as the arena is (briefly) invalid afterwards. See job003893. */ (*vmArena->contracted)(arena, base, size); - vmChunkDestroy(tree, UNUSED_POINTER, UNUSED_SIZE); + vmChunkDestroy(tree, UNUSED_POINTER); return TRUE; } else { /* Keep this chunk. */ @@ -1140,8 +1136,7 @@ static void VMCompact(Arena arena, Trace trace) /* Destroy chunks that are completely free, but not the primary * chunk. See * TODO: add hysteresis here. See job003815. */ - TreeTraverseAndDelete(&arena->chunkTree, vmChunkCompact, arena, - UNUSED_SIZE); + TreeTraverseAndDelete(&arena->chunkTree, vmChunkCompact, arena); { Size vmem0 = trace->preTraceArenaReserved; diff --git a/mps/code/cbs.c b/mps/code/cbs.c index 0b30b68acb1..6fb96b6940f 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -117,36 +117,37 @@ static TreeKey cbsKey(Tree tree) /* cbsTestNode, cbsTestTree -- test for nodes larger than the S parameter */ -static Bool cbsTestNode(SplayTree splay, Tree tree, - void *closureP, Size size) +static Bool cbsTestNode(SplayTree splay, Tree tree, void *closure) { CBSBlock block; + Size *sizeP = closure; AVERT(SplayTree, splay); AVERT(Tree, tree); - AVER(closureP == NULL); - AVER(size > 0); + AVER(sizeP != NULL); + AVER(*sizeP > 0); AVER(IsLandSubclass(CBSLand(cbsOfSplay(splay)), CBSFastLandClass)); block = cbsBlockOfTree(tree); - return CBSBlockSize(block) >= size; + return CBSBlockSize(block) >= *sizeP; } static Bool cbsTestTree(SplayTree splay, Tree tree, - void *closureP, Size size) + void *closure) { CBSFastBlock block; + Size *sizeP = closure; AVERT(SplayTree, splay); AVERT(Tree, tree); - AVER(closureP == NULL); - AVER(size > 0); + AVER(sizeP != NULL); + AVER(*sizeP > 0); AVER(IsLandSubclass(CBSLand(cbsOfSplay(splay)), CBSFastLandClass)); block = cbsFastBlockOfTree(tree); - return block->maxSize >= size; + return block->maxSize >= *sizeP; } @@ -726,25 +727,24 @@ static Res cbsZonedSplayNodeDescribe(Tree tree, mps_lib_FILE *stream) typedef struct CBSIterateClosure { Land land; LandVisitor visitor; - void *closureP; + void *visitorClosure; } CBSIterateClosure; -static Bool cbsIterateVisit(Tree tree, void *closureP, Size closureS) +static Bool cbsIterateVisit(Tree tree, void *closure) { - CBSIterateClosure *closure = closureP; - Land land = closure->land; + CBSIterateClosure *my = closure; + Land land = my->land; CBSBlock cbsBlock = cbsBlockOfTree(tree); RangeStruct range; RangeInit(&range, CBSBlockBase(cbsBlock), CBSBlockLimit(cbsBlock)); - return (*closure->visitor)(land, &range, closure->closureP, closureS); + return my->visitor(land, &range, my->visitorClosure); } -static Bool cbsIterate(Land land, LandVisitor visitor, - void *closureP, Size closureS) +static Bool cbsIterate(Land land, LandVisitor visitor, void *visitorClosure) { CBS cbs; SplayTree splay; - CBSIterateClosure closure; + CBSIterateClosure iterateClosure; AVERT(Land, land); cbs = cbsOfLand(land); @@ -756,11 +756,11 @@ static Bool cbsIterate(Land land, LandVisitor visitor, /* searches and meter it. */ METER_ACC(cbs->treeSearch, cbs->treeSize); - closure.land = land; - closure.visitor = visitor; - closure.closureP = closureP; + iterateClosure.land = land; + iterateClosure.visitor = visitor; + iterateClosure.visitorClosure = visitorClosure; return TreeTraverse(SplayTreeRoot(splay), splay->compare, splay->nodeKey, - cbsIterateVisit, &closure, closureS); + cbsIterateVisit, &iterateClosure); } @@ -773,33 +773,33 @@ typedef struct CBSIterateAndDeleteClosure { Land land; LandDeleteVisitor visitor; Bool cont; - void *closureP; + void *visitorClosure; } CBSIterateAndDeleteClosure; -static Bool cbsIterateAndDeleteVisit(Tree tree, void *closureP, Size closureS) +static Bool cbsIterateAndDeleteVisit(Tree tree, void *closure) { - CBSIterateAndDeleteClosure *closure = closureP; - Land land = closure->land; + CBSIterateAndDeleteClosure *my = closure; + Land land = my->land; CBS cbs = cbsOfLand(land); CBSBlock cbsBlock = cbsBlockOfTree(tree); Bool deleteNode = FALSE; RangeStruct range; RangeInit(&range, CBSBlockBase(cbsBlock), CBSBlockLimit(cbsBlock)); - if (closure->cont) - closure->cont = (*closure->visitor)(&deleteNode, land, &range, - closure->closureP, closureS); + if (my->cont) + my->cont = my->visitor(&deleteNode, land, &range, + my->visitorClosure); if (deleteNode) cbsBlockDestroy(cbs, cbsBlock); return deleteNode; } static Bool cbsIterateAndDelete(Land land, LandDeleteVisitor visitor, - void *closureP, Size closureS) + void *visitorClosure) { CBS cbs; SplayTree splay; - CBSIterateAndDeleteClosure closure; + CBSIterateAndDeleteClosure iterateClosure; AVERT(Land, land); cbs = cbsOfLand(land); @@ -811,13 +811,13 @@ static Bool cbsIterateAndDelete(Land land, LandDeleteVisitor visitor, /* searches and meter it. */ METER_ACC(cbs->treeSearch, cbs->treeSize); - closure.land = land; - closure.visitor = visitor; - closure.closureP = closureP; - closure.cont = TRUE; + iterateClosure.land = land; + iterateClosure.visitor = visitor; + iterateClosure.visitorClosure = visitorClosure; + iterateClosure.cont = TRUE; TreeTraverseAndDelete(&splay->root, cbsIterateAndDeleteVisit, - &closure, closureS); - return closure.cont; + &iterateClosure); + return iterateClosure.cont; } @@ -904,7 +904,7 @@ static Bool cbsFindFirst(Range rangeReturn, Range oldRangeReturn, METER_ACC(cbs->treeSearch, cbs->treeSize); found = SplayFindFirst(&tree, cbsSplay(cbs), &cbsTestNode, - &cbsTestTree, NULL, size); + &cbsTestTree, &size); if (found) { CBSBlock block; RangeStruct range; @@ -934,36 +934,32 @@ typedef struct cbsTestNodeInZonesClosureStruct { } cbsTestNodeInZonesClosureStruct, *cbsTestNodeInZonesClosure; static Bool cbsTestNodeInZones(SplayTree splay, Tree tree, - void *closureP, Size closureS) + void *closure) { CBSBlock block = cbsBlockOfTree(tree); - cbsTestNodeInZonesClosure closure = closureP; + cbsTestNodeInZonesClosure my = closure; RangeInZoneSet search; UNUSED(splay); - AVER(closureS == UNUSED_SIZE); - UNUSED(closureS); - search = closure->high ? RangeInZoneSetLast : RangeInZoneSetFirst; + search = my->high ? RangeInZoneSetLast : RangeInZoneSetFirst; - return search(&closure->base, &closure->limit, + return search(&my->base, &my->limit, CBSBlockBase(block), CBSBlockLimit(block), - closure->arena, closure->zoneSet, closure->size); + my->arena, my->zoneSet, my->size); } static Bool cbsTestTreeInZones(SplayTree splay, Tree tree, - void *closureP, Size closureS) + void *closure) { CBSFastBlock fastBlock = cbsFastBlockOfTree(tree); CBSZonedBlock zonedBlock = cbsZonedBlockOfTree(tree); - cbsTestNodeInZonesClosure closure = closureP; + cbsTestNodeInZonesClosure my = closure; UNUSED(splay); - AVER(closureS == UNUSED_SIZE); - UNUSED(closureS); - return fastBlock->maxSize >= closure->size - && ZoneSetInter(zonedBlock->zones, closure->zoneSet) != ZoneSetEMPTY; + return fastBlock->maxSize >= my->size + && ZoneSetInter(zonedBlock->zones, my->zoneSet) != ZoneSetEMPTY; } @@ -989,7 +985,7 @@ static Bool cbsFindLast(Range rangeReturn, Range oldRangeReturn, METER_ACC(cbs->treeSearch, cbs->treeSize); found = SplayFindLast(&tree, cbsSplay(cbs), &cbsTestNode, - &cbsTestTree, NULL, size); + &cbsTestTree, &size); if (found) { CBSBlock block; RangeStruct range; @@ -1033,7 +1029,7 @@ static Bool cbsFindLargest(Range rangeReturn, Range oldRangeReturn, CBSBlock block; METER_ACC(cbs->treeSearch, cbs->treeSize); found = SplayFindFirst(&tree, cbsSplay(cbs), &cbsTestNode, - &cbsTestTree, NULL, maxSize); + &cbsTestTree, &maxSize); AVER(found); /* maxSize is exact, so we will find it. */ block = cbsBlockOfTree(tree); AVER(CBSBlockSize(block) >= maxSize); @@ -1093,7 +1089,7 @@ static Res cbsFindInZones(Bool *foundReturn, Range rangeReturn, closure.high = high; if (!(*splayFind)(&tree, cbsSplay(cbs), cbsTestNodeInZones, cbsTestTreeInZones, - &closure, UNUSED_SIZE)) + &closure)) goto fail; block = cbsBlockOfTree(tree); diff --git a/mps/code/failover.c b/mps/code/failover.c index 750c6b1b17b..eba8737ec33 100644 --- a/mps/code/failover.c +++ b/mps/code/failover.c @@ -177,7 +177,7 @@ static Res failoverDelete(Range rangeReturn, Land land, Range range) } -static Bool failoverIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) +static Bool failoverIterate(Land land, LandVisitor visitor, void *closure) { Failover fo; @@ -186,8 +186,8 @@ static Bool failoverIterate(Land land, LandVisitor visitor, void *closureP, Size AVERT(Failover, fo); AVER(visitor != NULL); - return LandIterate(fo->primary, visitor, closureP, closureS) - && LandIterate(fo->secondary, visitor, closureP, closureS); + return LandIterate(fo->primary, visitor, closure) + && LandIterate(fo->secondary, visitor, closure); } diff --git a/mps/code/fbmtest.c b/mps/code/fbmtest.c index f5aa6831db8..0ef954d071d 100644 --- a/mps/code/fbmtest.c +++ b/mps/code/fbmtest.c @@ -94,13 +94,11 @@ static void describe(FBMState state) { } -static Bool checkCallback(Range range, void *closureP, Size closureS) +static Bool checkCallback(Range range, void *closure) { Addr base, limit; - CheckFBMClosure cl = (CheckFBMClosure)closureP; + CheckFBMClosure cl = (CheckFBMClosure)closure; - AVER(closureS == UNUSED_SIZE); - UNUSED(closureS); Insist(cl != NULL); base = RangeBase(range); @@ -126,18 +124,18 @@ static Bool checkCallback(Range range, void *closureP, Size closureS) static Bool checkCBSCallback(CBS cbs, Range range, - void *closureP, Size closureS) + void *closure) { UNUSED(cbs); - return checkCallback(range, closureP, closureS); + return checkCallback(range, closure); } static Bool checkFLCallback(Bool *deleteReturn, Range range, - void *closureP, Size closureS) + void *closure) { *deleteReturn = FALSE; - return checkCallback(range, closureP, closureS); + return checkCallback(range, closure); } @@ -151,10 +149,10 @@ static void check(FBMState state) switch (state->type) { case FBMTypeCBS: - CBSIterate(state->the.cbs, checkCBSCallback, &closure, UNUSED_SIZE); + CBSIterate(state->the.cbs, checkCBSCallback, &closure); break; case FBMTypeFreelist: - FreelistIterate(state->the.fl, checkFLCallback, &closure, UNUSED_SIZE); + FreelistIterate(state->the.fl, checkFLCallback, &closure); break; default: cdie(0, "invalid state->type"); diff --git a/mps/code/freelist.c b/mps/code/freelist.c index 6eddc3dff83..14e02f58e40 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -444,7 +444,7 @@ static Res freelistDelete(Range rangeReturn, Land land, Range range) static Bool freelistIterate(Land land, LandVisitor visitor, - void *closureP, Size closureS) + void *closure) { Freelist fl; FreelistBlock cur, next; @@ -453,7 +453,7 @@ static Bool freelistIterate(Land land, LandVisitor visitor, fl = freelistOfLand(land); AVERT(Freelist, fl); AVER(FUNCHECK(visitor)); - /* closureP and closureS are arbitrary */ + /* closure arbitrary */ for (cur = fl->list; cur != freelistEND; cur = next) { RangeStruct range; @@ -462,7 +462,7 @@ static Bool freelistIterate(Land land, LandVisitor visitor, * visitor touches the block. */ next = freelistBlockNext(cur); RangeInit(&range, freelistBlockBase(cur), freelistBlockLimit(fl, cur)); - cont = (*visitor)(land, &range, closureP, closureS); + cont = (*visitor)(land, &range, closure); if (!cont) return FALSE; } @@ -471,7 +471,7 @@ static Bool freelistIterate(Land land, LandVisitor visitor, static Bool freelistIterateAndDelete(Land land, LandDeleteVisitor visitor, - void *closureP, Size closureS) + void *closure) { Freelist fl; FreelistBlock prev, cur, next; @@ -480,7 +480,7 @@ static Bool freelistIterateAndDelete(Land land, LandDeleteVisitor visitor, fl = freelistOfLand(land); AVERT(Freelist, fl); AVER(FUNCHECK(visitor)); - /* closureP and closureS are arbitrary */ + /* closure arbitrary */ prev = freelistEND; cur = fl->list; @@ -492,7 +492,7 @@ static Bool freelistIterateAndDelete(Land land, LandDeleteVisitor visitor, next = freelistBlockNext(cur); /* See .next.first. */ size = freelistBlockSize(fl, cur); RangeInit(&range, freelistBlockBase(cur), freelistBlockLimit(fl, cur)); - cont = (*visitor)(&delete, land, &range, closureP, closureS); + cont = (*visitor)(&delete, land, &range, closure); if (delete) { freelistBlockSetPrevNext(fl, prev, next, -1); AVER(fl->size >= size); @@ -746,24 +746,28 @@ static Res freelistFindInZones(Bool *foundReturn, Range rangeReturn, /* freelistDescribeVisitor -- visitor method for freelistDescribe * * Writes a decription of the range into the stream pointed to by - * closureP. + * closure. */ +typedef struct FreelistDescribeClosureStruct { + mps_lib_FILE *stream; + Count depth; +} FreelistDescribeClosureStruct, *FreelistDescribeClosure; + static Bool freelistDescribeVisitor(Land land, Range range, - void *closureP, Size closureS) + void *closure) { Res res; - mps_lib_FILE *stream = closureP; - Count depth = closureS; + FreelistDescribeClosure my = closure; if (!TESTT(Land, land)) return FALSE; if (!RangeCheck(range)) return FALSE; - if (stream == NULL) + if (my->stream == NULL) return FALSE; - res = WriteF(stream, depth, + res = WriteF(my->stream, my->depth, "[$P,", (WriteFP)RangeBase(range), "$P)", (WriteFP)RangeLimit(range), " {$U}\n", (WriteFU)RangeSize(range), @@ -778,6 +782,7 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream, Count depth) Freelist fl; Res res; Bool b; + FreelistDescribeClosureStruct closure; if (!TESTT(Land, land)) return ResFAIL; @@ -793,7 +798,9 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream, Count depth) " size = $U\n", (WriteFU)fl->size, NULL); - b = LandIterate(land, freelistDescribeVisitor, stream, depth + 2); + closure.stream = stream; + closure.depth = depth + 2; + b = LandIterate(land, freelistDescribeVisitor, &closure); if (!b) return ResFAIL; diff --git a/mps/code/land.c b/mps/code/land.c index 18d446288f8..1853b4a6ad5 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -235,14 +235,14 @@ Res LandDelete(Range rangeReturn, Land land, Range range) * See */ -Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) +Bool LandIterate(Land land, LandVisitor visitor, void *closure) { Bool b; AVERT(Land, land); AVER(FUNCHECK(visitor)); landEnter(land); - b = (*land->class->iterate)(land, visitor, closureP, closureS); + b = (*land->class->iterate)(land, visitor, closure); landLeave(land); return b; @@ -255,14 +255,14 @@ Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) * See */ -Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS) +Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closure) { Bool b; AVERT(Land, land); AVER(FUNCHECK(visitor)); landEnter(land); - b = (*land->class->iterateAndDelete)(land, visitor, closureP, closureS); + b = (*land->class->iterateAndDelete)(land, visitor, closure); landLeave(land); return b; @@ -403,11 +403,11 @@ Res LandDescribe(Land land, mps_lib_FILE *stream, Count depth) /* landFlushVisitor -- visitor for LandFlush. * - * closureP argument is the destination Land. Attempt to insert the + * closure argument is the destination Land. Attempt to insert the * range into the destination. */ static Bool landFlushVisitor(Bool *deleteReturn, Land land, Range range, - void *closureP, Size closureS) + void *closure) { Res res; RangeStruct newRange; @@ -416,11 +416,9 @@ static Bool landFlushVisitor(Bool *deleteReturn, Land land, Range range, AVER(deleteReturn != NULL); AVERT(Land, land); AVERT(Range, range); - AVER(closureP != NULL); - AVER(closureS == UNUSED_SIZE); - UNUSED(closureS); + AVER(closure != NULL); - dest = closureP; + dest = closure; res = LandInsert(&newRange, dest, range); if (res == ResOK) { *deleteReturn = TRUE; @@ -442,7 +440,7 @@ Bool LandFlush(Land dest, Land src) AVERT(Land, dest); AVERT(Land, src); - return LandIterateAndDelete(src, landFlushVisitor, dest, UNUSED_SIZE); + return LandIterateAndDelete(src, landFlushVisitor, dest); } @@ -491,17 +489,15 @@ static Size landNoSize(Land land) /* LandSlowSize -- generic size method but slow */ static Bool landSizeVisitor(Land land, Range range, - void *closureP, Size closureS) + void *closure) { Size *size; AVERT(Land, land); AVERT(Range, range); - AVER(closureP != NULL); - AVER(closureS == UNUSED_SIZE); - UNUSED(closureS); + AVER(closure != NULL); - size = closureP; + size = closure; *size += RangeSize(range); return TRUE; @@ -510,7 +506,7 @@ static Bool landSizeVisitor(Land land, Range range, Size LandSlowSize(Land land) { Size size = 0; - Bool b = LandIterate(land, landSizeVisitor, &size, UNUSED_SIZE); + Bool b = LandIterate(land, landSizeVisitor, &size); AVER(b); return size; } @@ -531,21 +527,19 @@ static Res landNoDelete(Range rangeReturn, Land land, Range range) return ResUNIMPL; } -static Bool landNoIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) +static Bool landNoIterate(Land land, LandVisitor visitor, void *closure) { AVERT(Land, land); AVER(visitor != NULL); - UNUSED(closureP); - UNUSED(closureS); + UNUSED(closure); return FALSE; } -static Bool landNoIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS) +static Bool landNoIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closure) { AVERT(Land, land); AVER(visitor != NULL); - UNUSED(closureP); - UNUSED(closureS); + UNUSED(closure); return FALSE; } diff --git a/mps/code/landtest.c b/mps/code/landtest.c index eb4229f65e8..7ec55461d1e 100644 --- a/mps/code/landtest.c +++ b/mps/code/landtest.c @@ -67,13 +67,12 @@ static void describe(TestState state) { } -static Bool checkVisitor(Land land, Range range, void *closureP, Size closureS) +static Bool checkVisitor(Land land, Range range, void *closure) { Addr base, limit; - CheckTestClosure cl = closureP; + CheckTestClosure cl = closure; testlib_unused(land); - Insist(closureS == UNUSED_SIZE); Insist(cl != NULL); base = RangeBase(range); @@ -106,7 +105,7 @@ static void check(TestState state) closure.limit = addrOfIndex(state, state->size); closure.oldLimit = state->block; - b = LandIterate(state->land, checkVisitor, &closure, UNUSED_SIZE); + b = LandIterate(state->land, checkVisitor, &closure); Insist(b); if (closure.oldLimit == state->block) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 8efa22c155d..8a3984a6233 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -1009,8 +1009,8 @@ extern void LandDestroy(Land land); extern void LandFinish(Land land); extern Res LandInsert(Range rangeReturn, Land land, Range range); extern Res LandDelete(Range rangeReturn, Land land, Range range); -extern Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS); -extern Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS); +extern Bool LandIterate(Land land, LandVisitor visitor, void *closure); +extern Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closure); extern Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete); extern Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete); extern Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete); diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index a6030e4c1e5..3545021f50f 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -270,10 +270,10 @@ typedef void (*LandFinishMethod)(Land land); typedef Size (*LandSizeMethod)(Land land); typedef Res (*LandInsertMethod)(Range rangeReturn, Land land, Range range); typedef Res (*LandDeleteMethod)(Range rangeReturn, Land land, Range range); -typedef Bool (*LandVisitor)(Land land, Range range, void *closureP, Size closureS); -typedef Bool (*LandDeleteVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS); -typedef Bool (*LandIterateMethod)(Land land, LandVisitor visitor, void *closureP, Size closureS); -typedef Bool (*LandIterateAndDeleteMethod)(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS); +typedef Bool (*LandVisitor)(Land land, Range range, void *closure); +typedef Bool (*LandDeleteVisitor)(Bool *deleteReturn, Land land, Range range, void *closure); +typedef Bool (*LandIterateMethod)(Land land, LandVisitor visitor, void *closure); +typedef Bool (*LandIterateAndDeleteMethod)(Land land, LandDeleteVisitor visitor, void *closure); typedef Bool (*LandFindMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete); typedef Res (*LandFindInZonesMethod)(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high); typedef Res (*LandDescribeMethod)(Land land, mps_lib_FILE *stream, Count depth); diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c index 90232621c25..4ce6e66ed1c 100644 --- a/mps/code/poolmfs.c +++ b/mps/code/poolmfs.c @@ -126,7 +126,7 @@ static Res MFSInit(Pool pool, ArgList args) void MFSFinishTracts(Pool pool, MFSTractVisitor visitor, - void *closureP, Size closureS) + void *closure) { MFS mfs; @@ -136,19 +136,17 @@ void MFSFinishTracts(Pool pool, MFSTractVisitor visitor, while (mfs->tractList != NULL) { Tract nextTract = (Tract)TractP(mfs->tractList); /* .tract.chain */ - visitor(pool, TractBase(mfs->tractList), mfs->extendBy, closureP, closureS); + visitor(pool, TractBase(mfs->tractList), mfs->extendBy, closure); mfs->tractList = nextTract; } } static void MFSTractFreeVisitor(Pool pool, Addr base, Size size, - void *closureP, Size closureS) + void *closure) { - AVER(closureP == UNUSED_POINTER); - AVER(closureS == UNUSED_SIZE); - UNUSED(closureP); - UNUSED(closureS); + AVER(closure == UNUSED_POINTER); + UNUSED(closure); ArenaFree(base, size, pool); } @@ -161,7 +159,7 @@ static void MFSFinish(Pool pool) mfs = PoolPoolMFS(pool); AVERT(MFS, mfs); - MFSFinishTracts(pool, MFSTractFreeVisitor, UNUSED_POINTER, UNUSED_SIZE); + MFSFinishTracts(pool, MFSTractFreeVisitor, UNUSED_POINTER); mfs->sig = SigInvalid; } diff --git a/mps/code/poolmfs.h b/mps/code/poolmfs.h index ac4122a9f02..70d4124cb42 100644 --- a/mps/code/poolmfs.h +++ b/mps/code/poolmfs.h @@ -46,9 +46,9 @@ extern const struct mps_key_s _mps_key_MFSExtendSelf; extern void MFSExtend(Pool pool, Addr base, Size size); typedef void MFSTractVisitor(Pool pool, Addr base, Size size, - void *closureP, Size closureS); + void *closure); extern void MFSFinishTracts(Pool pool, MFSTractVisitor visitor, - void *closureP, Size closureS); + void *closure); #endif /* poolmfs_h */ diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index 95c3e9ecc9a..1189f7d73e1 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -751,23 +751,21 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn, /* MVTDeleteOverlapping -- ABQIterate callback used by MVTInsert and - * MVTDelete. It receives a Range in its closureP argument, and sets + * MVTDelete. It receives a Range in its closure argument, and sets * *deleteReturn to TRUE for ranges in the ABQ that overlap with it, * and FALSE for ranges that do not. */ static Bool MVTDeleteOverlapping(Bool *deleteReturn, void *element, - void *closureP, Size closureS) + void *closure) { Range oldRange, newRange; AVER(deleteReturn != NULL); AVER(element != NULL); - AVER(closureP != NULL); - AVER(closureS == UNUSED_SIZE); - UNUSED(closureS); + AVER(closure != NULL); oldRange = element; - newRange = closureP; + newRange = closure; *deleteReturn = RangesOverlap(oldRange, newRange); return TRUE; @@ -830,7 +828,7 @@ static Res MVTInsert(MVT mvt, Addr base, Addr limit) * with ranges on the ABQ, so ensure that the corresponding ranges * are coalesced on the ABQ. */ - ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &newRange, UNUSED_SIZE); + ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &newRange); (void)MVTReserve(mvt, &newRange); } @@ -859,7 +857,7 @@ static Res MVTDelete(MVT mvt, Addr base, Addr limit) * might be on the ABQ, so ensure it is removed. */ if (RangeSize(&rangeOld) >= mvt->reuseSize) - ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &rangeOld, UNUSED_SIZE); + ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &rangeOld); /* There might be fragments at the left or the right of the deleted * range, and either might be big enough to go back on the ABQ. @@ -1210,15 +1208,13 @@ static Bool MVTReturnSegs(MVT mvt, Range range, Arena arena) */ static Bool MVTRefillVisitor(Land land, Range range, - void *closureP, Size closureS) + void *closure) { MVT mvt; AVERT(Land, land); - mvt = closureP; + mvt = closure; AVERT(MVT, mvt); - AVER(closureS == UNUSED_SIZE); - UNUSED(closureS); if (RangeSize(range) < mvt->reuseSize) return TRUE; @@ -1241,7 +1237,7 @@ static void MVTRefillABQIfEmpty(MVT mvt, Size size) mvt->abqOverflow = FALSE; METER_ACC(mvt->refills, size); /* The iteration stops if the ABQ overflows, so may finish or not. */ - (void)LandIterate(MVTFreeLand(mvt), MVTRefillVisitor, mvt, UNUSED_SIZE); + (void)LandIterate(MVTFreeLand(mvt), MVTRefillVisitor, mvt); } } @@ -1260,7 +1256,7 @@ typedef struct MVTContigencyClosureStruct } MVTContigencyClosureStruct, *MVTContigencyClosure; static Bool MVTContingencyVisitor(Land land, Range range, - void *closureP, Size closureS) + void *closure) { MVT mvt; Size size; @@ -1269,12 +1265,10 @@ static Bool MVTContingencyVisitor(Land land, Range range, AVERT(Land, land); AVERT(Range, range); - AVER(closureP != NULL); - cl = closureP; + AVER(closure != NULL); + cl = closure; mvt = cl->mvt; AVERT(MVT, mvt); - AVER(closureS == UNUSED_SIZE); - UNUSED(closureS); base = RangeBase(range); limit = RangeLimit(range); @@ -1312,7 +1306,7 @@ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn, cls.steps = 0; cls.hardSteps = 0; - if (LandIterate(MVTFreeLand(mvt), MVTContingencyVisitor, &cls, UNUSED_SIZE)) + if (LandIterate(MVTFreeLand(mvt), MVTContingencyVisitor, &cls)) return FALSE; AVER(RangeSize(&cls.range) >= min); diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 22b6d004f68..1125f018a07 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -585,18 +585,16 @@ static Res MVFFInit(Pool pool, ArgList args) /* MVFFFinish -- finish method for MVFF */ static Bool mvffFinishVisitor(Bool *deleteReturn, Land land, Range range, - void *closureP, Size closureS) + void *closure) { Pool pool; AVER(deleteReturn != NULL); AVERT(Land, land); AVERT(Range, range); - AVER(closureP != NULL); - pool = closureP; + AVER(closure != NULL); + pool = closure; AVERT(Pool, pool); - AVER(closureS == UNUSED_SIZE); - UNUSED(closureS); ArenaFree(RangeBase(range), RangeSize(range), pool); *deleteReturn = TRUE; @@ -613,8 +611,7 @@ static void MVFFFinish(Pool pool) AVERT(MVFF, mvff); mvff->sig = SigInvalid; - b = LandIterateAndDelete(MVFFTotalLand(mvff), mvffFinishVisitor, pool, - UNUSED_SIZE); + b = LandIterateAndDelete(MVFFTotalLand(mvff), mvffFinishVisitor, pool); AVER(b); AVER(LandSize(MVFFTotalLand(mvff)) == 0); diff --git a/mps/code/splay.c b/mps/code/splay.c index ed46c7a4ba4..0030b4aee65 100644 --- a/mps/code/splay.c +++ b/mps/code/splay.c @@ -1088,19 +1088,17 @@ static Res SplayNodeDescribe(Tree node, mps_lib_FILE *stream, typedef struct SplayFindClosureStruct { SplayTestNodeFunction testNode; SplayTestTreeFunction testTree; - void *p; - Size s; + void *testClosure; SplayTree splay; Bool found; } SplayFindClosureStruct, *SplayFindClosure; static Compare SplayFindFirstCompare(Tree node, TreeKey key) { - SplayFindClosure closure; - void *closureP; - Size closureS; + SplayFindClosure my; SplayTestNodeFunction testNode; SplayTestTreeFunction testTree; + void *testClosure; SplayTree splay; AVERT(Tree, node); @@ -1108,18 +1106,17 @@ static Compare SplayFindFirstCompare(Tree node, TreeKey key) /* Lift closure values into variables so that they aren't aliased by calls to the test functions. */ - closure = (SplayFindClosure)key; - closureP = closure->p; - closureS = closure->s; - testNode = closure->testNode; - testTree = closure->testTree; - splay = closure->splay; + my = (SplayFindClosure)key; + testClosure = my->testClosure; + testNode = my->testNode; + testTree = my->testTree; + splay = my->splay; if (TreeHasLeft(node) && - (*testTree)(splay, TreeLeft(node), closureP, closureS)) { + (*testTree)(splay, TreeLeft(node), testClosure)) { return CompareLESS; - } else if ((*testNode)(splay, node, closureP, closureS)) { - closure->found = TRUE; + } else if ((*testNode)(splay, node, testClosure)) { + my->found = TRUE; return CompareEQUAL; } else { /* If there's a right subtree but it doesn't satisfy the tree test @@ -1127,8 +1124,8 @@ static Compare SplayFindFirstCompare(Tree node, TreeKey key) return TRUE, so the caller must check closure->found to find out whether the result node actually satisfies testNode. */ if (TreeHasRight(node) && - !(*testTree)(splay, TreeRight(node), closureP, closureS)) { - closure->found = FALSE; + !(*testTree)(splay, TreeRight(node), testClosure)) { + my->found = FALSE; return CompareEQUAL; } return CompareGREATER; @@ -1137,11 +1134,10 @@ static Compare SplayFindFirstCompare(Tree node, TreeKey key) static Compare SplayFindLastCompare(Tree node, TreeKey key) { - SplayFindClosure closure; - void *closureP; - Size closureS; + SplayFindClosure my; SplayTestNodeFunction testNode; SplayTestTreeFunction testTree; + void *testClosure; SplayTree splay; AVERT(Tree, node); @@ -1149,24 +1145,23 @@ static Compare SplayFindLastCompare(Tree node, TreeKey key) /* Lift closure values into variables so that they aren't aliased by calls to the test functions. */ - closure = (SplayFindClosure)key; - closureP = closure->p; - closureS = closure->s; - testNode = closure->testNode; - testTree = closure->testTree; - splay = closure->splay; + my = (SplayFindClosure)key; + testClosure = my->testClosure; + testNode = my->testNode; + testTree = my->testTree; + splay = my->splay; if (TreeHasRight(node) && - (*testTree)(splay, TreeRight(node), closureP, closureS)) { - return CompareGREATER; - } else if ((*testNode)(splay, node, closureP, closureS)) { - closure->found = TRUE; + (*testTree)(splay, TreeRight(node), testClosure)) { + return CompareGREATER; + } else if ((*testNode)(splay, node, testClosure)) { + my->found = TRUE; return CompareEQUAL; } else { /* See SplayFindFirstCompare. */ if (TreeHasLeft(node) && - !(*testTree)(splay, TreeLeft(node), closureP, closureS)) { - closure->found = FALSE; + !(*testTree)(splay, TreeLeft(node), testClosure)) { + my->found = FALSE; return CompareEQUAL; } return CompareLESS; @@ -1184,8 +1179,8 @@ static Compare SplayFindLastCompare(Tree node, TreeKey key) * ``*nodeReturn`` is set to the node. * * The given callbacks testNode and testTree detect this property in - * a single node or a sub-tree rooted at a node, and both receive the - * arbitrary closures closureP and closureS. + * a single node or a sub-tree rooted at a node, and both receive an + * arbitrary closure. * * TODO: This repeatedly splays failed matches to the root and rotates * them, so it could have quite an unbalancing effect if size is small. @@ -1195,7 +1190,7 @@ static Compare SplayFindLastCompare(Tree node, TreeKey key) Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeFunction testNode, SplayTestTreeFunction testTree, - void *closureP, Size closureS) + void *testClosure) { SplayFindClosureStruct closureStruct; Bool found; @@ -1206,11 +1201,10 @@ Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, AVER(FUNCHECK(testTree)); if (SplayTreeIsEmpty(splay) || - !testTree(splay, SplayTreeRoot(splay), closureP, closureS)) + !testTree(splay, SplayTreeRoot(splay), testClosure)) return FALSE; /* no suitable nodes in tree */ - closureStruct.p = closureP; - closureStruct.s = closureS; + closureStruct.testClosure = testClosure; closureStruct.testNode = testNode; closureStruct.testTree = testTree; closureStruct.splay = splay; @@ -1227,7 +1221,7 @@ Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, oldRoot = SplayTreeRoot(splay); newRoot = TreeRight(oldRoot); - if (newRoot == TreeEMPTY || !(*testTree)(splay, newRoot, closureP, closureS)) + if (newRoot == TreeEMPTY || !(*testTree)(splay, newRoot, testClosure)) return FALSE; /* no suitable nodes in the rest of the tree */ /* Temporarily chop off the left half-tree, inclusive of root, @@ -1259,7 +1253,7 @@ Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, Bool SplayFindLast(Tree *nodeReturn, SplayTree splay, SplayTestNodeFunction testNode, SplayTestTreeFunction testTree, - void *closureP, Size closureS) + void *testClosure) { SplayFindClosureStruct closureStruct; Bool found; @@ -1270,11 +1264,10 @@ Bool SplayFindLast(Tree *nodeReturn, SplayTree splay, AVER(FUNCHECK(testTree)); if (SplayTreeIsEmpty(splay) || - !testTree(splay, SplayTreeRoot(splay), closureP, closureS)) + !testTree(splay, SplayTreeRoot(splay), testClosure)) return FALSE; /* no suitable nodes in tree */ - closureStruct.p = closureP; - closureStruct.s = closureS; + closureStruct.testClosure = testClosure; closureStruct.testNode = testNode; closureStruct.testTree = testTree; closureStruct.splay = splay; @@ -1289,7 +1282,7 @@ Bool SplayFindLast(Tree *nodeReturn, SplayTree splay, oldRoot = SplayTreeRoot(splay); newRoot = TreeLeft(oldRoot); - if (newRoot == TreeEMPTY || !(*testTree)(splay, newRoot, closureP, closureS)) + if (newRoot == TreeEMPTY || !(*testTree)(splay, newRoot, testClosure)) return FALSE; /* no suitable nodes in the rest of the tree */ /* Temporarily chop off the right half-tree, inclusive of root, diff --git a/mps/code/splay.h b/mps/code/splay.h index c1b109e64a7..d9cf821eb90 100644 --- a/mps/code/splay.h +++ b/mps/code/splay.h @@ -16,9 +16,9 @@ typedef struct SplayTreeStruct *SplayTree; typedef Bool (*SplayTestNodeFunction)(SplayTree splay, Tree node, - void *closureP, Size closureS); + void *closure); typedef Bool (*SplayTestTreeFunction)(SplayTree splay, Tree node, - void *closureP, Size closureS); + void *closure); typedef void (*SplayUpdateNodeFunction)(SplayTree splay, Tree node); extern void SplayTrivUpdate(SplayTree splay, Tree node); @@ -58,15 +58,15 @@ extern Tree SplayTreeNext(SplayTree splay, TreeKey oldKey); typedef Bool (*SplayFindFunction)(Tree *nodeReturn, SplayTree splay, SplayTestNodeFunction testNode, SplayTestTreeFunction testTree, - void *closureP, Size closureS); + void *closure); extern Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeFunction testNode, SplayTestTreeFunction testTree, - void *closureP, Size closureS); + void *closure); extern Bool SplayFindLast(Tree *nodeReturn, SplayTree splay, SplayTestNodeFunction testNode, SplayTestTreeFunction testTree, - void *closureP, Size closureS); + void *closure); extern void SplayNodeRefresh(SplayTree splay, Tree node); extern void SplayNodeInit(SplayTree splay, Tree node); diff --git a/mps/code/tree.c b/mps/code/tree.c index f87e8364ea7..3afea83bca3 100644 --- a/mps/code/tree.c +++ b/mps/code/tree.c @@ -230,20 +230,20 @@ Bool TreeInsert(Tree *treeReturn, Tree root, Tree node, */ Bool TreeTraverseMorris(Tree tree, TreeVisitor visit, - void *closureP, Size closureS) + void *closure) { Tree node; Bool visiting = TRUE; AVERT(Tree, tree); AVER(FUNCHECK(visit)); - /* closureP, closureS arbitrary */ + /* closure arbitrary */ node = tree; while (node != TreeEMPTY) { if (node->left == TreeEMPTY) { if (visiting) - visiting = visit(node, closureP, closureS); + visiting = visit(node, closure); node = node->right; } else { Tree pre = node->left; @@ -256,7 +256,7 @@ Bool TreeTraverseMorris(Tree tree, TreeVisitor visit, if (pre->right == node) { pre->right = TreeEMPTY; if (visiting) - visiting = visit(node, closureP, closureS); + visiting = visit(node, closure); else if (node == tree) return FALSE; node = node->right; @@ -323,13 +323,13 @@ static Tree stepUpLeft(Tree node, Tree *parentIO) Bool TreeTraverse(Tree tree, TreeCompareFunction compare, TreeKeyFunction key, - TreeVisitor visit, void *closureP, Size closureS) + TreeVisitor visit, void *closure) { Tree parent, node; AVERT(Tree, tree); AVER(FUNCHECK(visit)); - /* closureP, closureS arbitrary */ + /* closure arbitrary */ parent = TreeEMPTY; node = tree; @@ -343,7 +343,7 @@ Bool TreeTraverse(Tree tree, AVER(compare(parent, key(node)) == CompareLESS); goto down; } - if (!visit(node, closureP, closureS)) + if (!visit(node, closure)) goto abort; if (TreeHasRight(node)) { node = stepDownRight(node, &parent); @@ -359,7 +359,7 @@ Bool TreeTraverse(Tree tree, goto up; } node = stepUpRight(node, &parent); - if (!visit(node, closureP, closureS)) + if (!visit(node, closure)) goto abort; if (!TreeHasRight(node)) goto up; @@ -539,14 +539,14 @@ void TreeBalance(Tree *treeIO) * See . */ void TreeTraverseAndDelete(Tree *treeIO, TreeVisitor visitor, - void *closureP, Size closureS) + void *closure) { Tree *treeref = treeIO; AVER(treeIO != NULL); AVERT(Tree, *treeIO); AVER(FUNCHECK(visitor)); - /* closureP and closureS are arbitrary */ + /* closure arbitrary */ TreeToVine(treeIO); @@ -554,7 +554,7 @@ void TreeTraverseAndDelete(Tree *treeIO, TreeVisitor visitor, Tree tree = *treeref; /* Current node. */ Tree *nextref = &tree->right; /* Location of pointer to next node. */ Tree next = *nextref; /* Next node. */ - if ((*visitor)(tree, closureP, closureS)) { + if ((*visitor)(tree, closure)) { /* Delete current node. */ *treeref = next; } else { diff --git a/mps/code/tree.h b/mps/code/tree.h index 7b463067f0e..a4f883c48cf 100644 --- a/mps/code/tree.h +++ b/mps/code/tree.h @@ -123,13 +123,13 @@ extern Bool TreeFindNext(Tree *treeReturn, Tree root, extern Bool TreeInsert(Tree *treeReturn, Tree root, Tree node, TreeKey key, TreeCompareFunction compare); -typedef Bool TreeVisitor(Tree tree, void *closureP, Size closureS); +typedef Bool TreeVisitor(Tree tree, void *closure); extern Bool TreeTraverse(Tree tree, TreeCompareFunction compare, TreeKeyFunction key, - TreeVisitor visit, void *closureP, Size closureS); + TreeVisitor visit, void *closure); extern Bool TreeTraverseMorris(Tree tree, TreeVisitor visit, - void *closureP, Size closureS); + void *closure); extern void TreeRotateLeft(Tree *nodeIO); extern void TreeRotateRight(Tree *nodeIO); @@ -139,7 +139,7 @@ extern Count TreeToVine(Tree *treeIO); extern void TreeBalance(Tree *treeIO); extern void TreeTraverseAndDelete(Tree *treeIO, TreeVisitor visitor, - void *closureP, Size closureS); + void *closure); #endif /* tree_h */ From 6a1b956a7326980665fff1ad54250690e90a335b Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 2 Mar 2016 08:58:45 +0000 Subject: [PATCH 184/337] Expanding tabs. Copied from Perforce Change: 189516 ServerID: perforce.ravenbrook.com --- mps/code/mpsi.c | 6 +++--- mps/code/tagtest.c | 8 ++++---- mps/manual/source/topic/root.rst | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index c9acee2da5e..a6e24f0c63a 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1390,9 +1390,9 @@ mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o, mps_word_t mask) { return mps_root_create_area_tagged(mps_root_o, arena, mps_rank, mps_rm, - base, base + size, - mps_scan_area_tagged, - mask, 0); + base, base + size, + mps_scan_area_tagged, + mask, 0); } mps_res_t mps_root_create_fmt(mps_root_t *mps_root_o, mps_arena_t arena, diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c index a33bf122614..fda27efd9b7 100644 --- a/mps/code/tagtest.c +++ b/mps/code/tagtest.c @@ -170,16 +170,16 @@ static void test(int mode) case MODE_CONS: /* Scan words tagged "cons" -- everything will live. */ die(mps_root_create_area_tagged(&root, arena, mps_rank_ambig(), 0, - refs, refs + OBJCOUNT, - mps_scan_area_tagged, TAG_MASK, tag_cons), + refs, refs + OBJCOUNT, + mps_scan_area_tagged, TAG_MASK, tag_cons), "root"); expected = 0; break; case MODE_INVALID: /* Scan words tagged "invalid" -- everything will die. */ die(mps_root_create_area_tagged(&root, arena, mps_rank_ambig(), 0, - refs, refs + OBJCOUNT, - mps_scan_area_tagged, TAG_MASK, tag_invalid), + refs, refs + OBJCOUNT, + mps_scan_area_tagged, TAG_MASK, tag_invalid), "root"); expected = OBJCOUNT; break; diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index 3b49d120a3f..9c1f20b2b52 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -615,7 +615,7 @@ Root interface mps_root_t root; res = mps_root_create_area_tagged(&root, arena, mps_rank_exact(), - 0, + 0, symtab, symtab + symtab_size, mps_scan_area_tagged, TAG_MASK, TAG_PATTERN); From 9c6b618149585bba23ddf2174c36b31a4073c337 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 2 Mar 2016 09:42:17 +0000 Subject: [PATCH 185/337] Removing design references to closure_size which was removed in changelist 189491. Copied from Perforce Change: 189522 ServerID: perforce.ravenbrook.com --- mps/design/prmc.txt | 2 +- mps/design/ss.txt | 5 ++--- mps/design/thread-manager.txt | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/mps/design/prmc.txt b/mps/design/prmc.txt index 43d24a34ec4..b7fae2d0559 100644 --- a/mps/design/prmc.txt +++ b/mps/design/prmc.txt @@ -104,7 +104,7 @@ instruction which was caused the fault to be re-executed. Return This function is only called if ``ProtCanStepInstruction(context)`` returned ``TRUE``. -``Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, mps_area_scan_t scan, void *closure, size_t closure_size)`` +``Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, mps_area_scan_t scan, void *closure)`` _`.if.context.scan`: Scan all roots found in ``context`` using the given scan state by calling ``scan``, and return the result code from diff --git a/mps/design/ss.txt b/mps/design/ss.txt index 7489ad3537f..8ecd6a18153 100644 --- a/mps/design/ss.txt +++ b/mps/design/ss.txt @@ -69,8 +69,7 @@ registers do not, as far as we are aware, contain pointers. _`.sol.inner`: Having located the hot end of the stack (``stackHot``), and spilled the root registers into the next ``n`` words, implementations call the generic higher-order function -``StackScanInner(ss, stackCold, stackHot, n, scan_area, closure, -closure_size)`` to actually do the scanning. +``StackScanInner(ss, stackCold, stackHot, n, scan_area, closure)`` to actually do the scanning. Interface @@ -78,7 +77,7 @@ Interface ``Res StackScan(ScanState ss, Word *stackCold, mps_area_scan_t scan_area, - void *closure, size_t closure_size)`` + void *closure)`` _`.if.scan`: Scan the root registers of the current thread, and the control stack between ``stackCold`` and the hot end of the stack, in diff --git a/mps/design/thread-manager.txt b/mps/design/thread-manager.txt index 686ad8d3381..88f2b2478fa 100644 --- a/mps/design/thread-manager.txt +++ b/mps/design/thread-manager.txt @@ -153,7 +153,7 @@ threads are discovered to have terminated, move them to ``deadRing``. _`.if.ring.thread`: Return the thread that owns the given element of the thread ring. -``Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, mps_area_scan_t scan_area, void *closure, size_t closure_size)`` +``Res ThreadScan(ScanState ss, Thread thread, Word *stackCold, mps_area_scan_t scan_area, void *closure)`` _`.if.scan`: Scan the stacks and root registers of ``thread``, using ``ss`` and ``scan_area``. ``stackCold`` points to the cold end of the From 58ef1c2a9cae0f2922ba3e95a6169e7807d9a110 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 2 Mar 2016 09:47:01 +0000 Subject: [PATCH 186/337] Improving very old comments. Copied from Perforce Change: 189523 ServerID: perforce.ravenbrook.com --- mps/code/root.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/code/root.c b/mps/code/root.c index ae16e3dcd13..e4c8b3f81ab 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -43,8 +43,8 @@ typedef struct RootStruct { size_t s; /* closure for scan function */ } fun; struct { - Word *base; /* beginning of area */ - Word *limit; /* one off end of area */ + Word *base; /* base of area to be scanned */ + Word *limit; /* limit of area to be scanned */ mps_area_scan_t scan_area;/* area scanning function */ AreaScanUnion the; } area; From 0bb563ff310c374c7bc53e1971e4a1ea51175df7 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 2 Mar 2016 10:00:15 +0000 Subject: [PATCH 187/337] Improving comment. Copied from Perforce Change: 189526 ServerID: perforce.ravenbrook.com --- mps/code/sc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/sc.h b/mps/code/sc.h index abbae9848c9..da4a9c8eac5 100644 --- a/mps/code/sc.h +++ b/mps/code/sc.h @@ -38,7 +38,7 @@ * setjmp magic. */ -/* StackContextStackHot - return the stack hot end from the stack context. +/* StackContextStackHot - return the hot end of the stack from the stack context * * We assume the stack is full. In other words the stack top points at * a word that contains a potential Ref. From 92b5414b3cfa0613ee11dcd563744cceb3b475a7 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 2 Mar 2016 10:06:04 +0000 Subject: [PATCH 188/337] Miscellaneous minor documentation improvements from review. Copied from Perforce Change: 189529 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/root.rst | 10 +++++----- mps/manual/source/topic/scanning.rst | 11 ++++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index 9c1f20b2b52..c174568b446 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -150,11 +150,11 @@ root by calling :c:func:`mps_root_create_thread`. The MPS's stack scanner needs to know how to find the :term:`cold end` of the part of the stack to scan. The :term:`cold end` 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. +part of the 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 diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst index eab99c79b2f..b842240995f 100644 --- a/mps/manual/source/topic/scanning.rst +++ b/mps/manual/source/topic/scanning.rst @@ -505,6 +505,7 @@ Fixing interface .. index:: single: scanning; area scanners + single: area; scanning .. _topic-scanning-area: @@ -512,8 +513,8 @@ Area scanners ------------- An area scanner :term:`scans` an area of memory for -:term:`references `. Various functions in the MPS interface, -such as :c:func:`mps_root_create_thread_tagged`, accept area scanners as +:term:`references`. Various functions in the MPS interface, such as +:c:func:`mps_root_create_thread_tagged`, accept area scanners as arguments so that the :term:`client program` can specify how to scan special areas such as the :term:`control stack`. @@ -584,7 +585,7 @@ the scanners, found in ``scan.c`` in the MPS source code. Scan an area of memory :term:`fixing ` every word, but remove tag bits before fixing references, and restore them afterwards. - ``closure`` should point to an :c:type:`mps_scan_tag_s`. Expects + ``closure`` must point to an :c:type:`mps_scan_tag_s`. Expects ``base`` and ``limit`` to be word-aligned. For example, if ``mask`` is 0b111 (decimal 7), then this scanner @@ -600,7 +601,7 @@ the scanners, found in ``scan.c`` in the MPS source code. .. c:function:: mps_res_t mps_scan_area_tagged(mps_ss_t ss, void *base, void *limit, void *closure) Scan an area of memory :term:`fixing ` only words whose - masked bits match a particular tag pattern. ``closure`` should + masked bits match a particular tag pattern. ``closure`` must point to a :c:type:`mps_scan_tag_s`. Expects ``base`` and ``limit`` to be word-aligned. @@ -624,7 +625,7 @@ the scanners, found in ``scan.c`` in the MPS source code. Scan an area of memory :term:`fixing ` only words whose masked bits are zero or match a particular tag pattern. - ``closure`` should point to a :c:type:`mps_scan_tag_s`. Expects + ``closure`` must point to a :c:type:`mps_scan_tag_s`. Expects ``base`` and ``limit`` to be word-aligned. For example, if ``mask`` is 7 and ``pattern`` is 3, then this From 50384dd4789edebeb66028cf619b0751980d8f35 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 2 Mar 2016 10:16:44 +0000 Subject: [PATCH 189/337] Fixing terminology from "top" to "hot end" of stack. Copied from Perforce Change: 189530 ServerID: perforce.ravenbrook.com --- mps/code/mpmst.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index d893c25afc4..ec643313307 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -792,7 +792,7 @@ typedef struct mps_arena_s { Bool emergency; /* garbage collect in emergency mode? */ - Word *stackAtArenaEnter; /* NULL or top of client stack, in the thread */ + Word *stackAtArenaEnter; /* NULL or hot end of client stack, in the thread */ /* that then entered the MPS. */ Sig sig; From 42624364bcd985b2c2c9423554151b15939e4f06 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 2 Mar 2016 10:25:37 +0000 Subject: [PATCH 190/337] Reducing redundant code after examining output of clang on mps_scan_area. Copied from Perforce Change: 189531 ServerID: perforce.ravenbrook.com --- mps/code/scan.c | 66 ++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 39 deletions(-) diff --git a/mps/code/scan.c b/mps/code/scan.c index 3e01c9fed17..59bda4ba583 100644 --- a/mps/code/scan.c +++ b/mps/code/scan.c @@ -15,42 +15,7 @@ #include "mps.h" -/* mps_scan_area -- scan contiguous area of references - * - * This is a convenience function for scanning the contiguous area - * [base, limit). I.e., it calls Fix on all words from base up to - * limit, inclusive of base and exclusive of limit. - * - * This scanner is appropriate for use when all words in the area are - * simple untagged references. - */ - -mps_res_t mps_scan_area(mps_ss_t ss, - void *base, void *limit, - void *closure) -{ - (void)closure; /* unused */ - - MPS_SCAN_BEGIN(ss) { - mps_word_t *p = base; - while (p < (mps_word_t *)limit) { - mps_word_t word = *p; - mps_addr_t ref = (mps_addr_t)word; - if (MPS_FIX1(ss, ref)) { - mps_res_t res = MPS_FIX2(ss, &ref); - if (res != MPS_RES_OK) - return res; - *p = (mps_word_t)ref; - } - ++p; - } - } MPS_SCAN_END(ss); - - return MPS_RES_OK; -} - - -#define MPS_SCAN_AREA_TAGGED(test) \ +#define MPS_SCAN_AREA(test) \ MPS_SCAN_BEGIN(ss) { \ mps_word_t *p = base; \ while (p < (mps_word_t *)limit) { \ @@ -70,6 +35,29 @@ mps_res_t mps_scan_area(mps_ss_t ss, } MPS_SCAN_END(ss); +/* mps_scan_area -- scan contiguous area of references + * + * This is a convenience function for scanning the contiguous area + * [base, limit). I.e., it calls Fix on all words from base up to + * limit, inclusive of base and exclusive of limit. + * + * This scanner is appropriate for use when all words in the area are + * simple untagged references. + */ + +mps_res_t mps_scan_area(mps_ss_t ss, + void *base, void *limit, + void *closure) +{ + mps_word_t mask = 0; + + (void)closure; /* unused */ + + MPS_SCAN_AREA(1); + + return MPS_RES_OK; +} + /* mps_scan_area_masked -- scan area masking off tag bits * @@ -90,7 +78,7 @@ mps_res_t mps_scan_area_masked(mps_ss_t ss, mps_scan_tag_t tag = closure; mps_word_t mask = tag->mask; - MPS_SCAN_AREA_TAGGED(1); + MPS_SCAN_AREA(1); return MPS_RES_OK; } @@ -113,7 +101,7 @@ mps_res_t mps_scan_area_tagged(mps_ss_t ss, mps_word_t mask = tag->mask; mps_word_t pattern = tag->pattern; - MPS_SCAN_AREA_TAGGED(tag_bits == pattern); + MPS_SCAN_AREA(tag_bits == pattern); return MPS_RES_OK; } @@ -142,7 +130,7 @@ mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t ss, mps_word_t mask = tag->mask; mps_word_t pattern = tag->pattern; - MPS_SCAN_AREA_TAGGED(tag_bits == 0 || tag_bits == pattern); + MPS_SCAN_AREA(tag_bits == 0 || tag_bits == pattern); return MPS_RES_OK; } From 3c6ee3d589af3d986a4a613dae5e10a69849b90d Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 2 Mar 2016 10:32:46 +0000 Subject: [PATCH 191/337] Fixing location of assumptions about descending stack that had gone astray. Copied from Perforce Change: 189534 ServerID: perforce.ravenbrook.com --- mps/code/ss.c | 13 +++++++++---- mps/code/ssan.c | 7 ------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/mps/code/ss.c b/mps/code/ss.c index fb23794c4a8..506001d04d2 100644 --- a/mps/code/ss.c +++ b/mps/code/ss.c @@ -32,11 +32,16 @@ Res StackScanInner(ScanState ss, Word *stackCold, Word *stackHot, Res res; AVERT(ScanState, ss); - AVER(stackHot < stackCold); - AVER(AddrIsAligned((Addr)stackHot, sizeof(Addr))); /* .assume.align */ AVER(0 < nSavedRegs); AVER(nSavedRegs < 128); /* sanity check */ + /* .assume.stack: This implementation assumes that the stack grows + * downwards, so that the address of the jmp_buf is the base of the + * part of the stack that needs to be scanned. (StackScanInner makes + * the same assumption.) + */ + AVER(stackHot < stackCold); + arena = ss->arena; /* If a stack pointer was stored when we entered the arena (through the @@ -46,8 +51,8 @@ Res StackScanInner(ScanState ss, Word *stackCold, Word *stackHot, (trans.c). Otherwise, scan the whole stack. */ if (arena->stackAtArenaEnter != NULL) { - AVER(stackHot < arena->stackAtArenaEnter); - AVER(arena->stackAtArenaEnter < stackCold); + AVER(stackHot < arena->stackAtArenaEnter); /* .assume.stack */ + AVER(arena->stackAtArenaEnter < stackCold); /* .assume.stack */ res = TraceScanArea(ss, stackHot, stackHot + nSavedRegs, scan_area, closure); if (res != ResOK) diff --git a/mps/code/ssan.c b/mps/code/ssan.c index 2a36f493351..fc3c0ec84df 100644 --- a/mps/code/ssan.c +++ b/mps/code/ssan.c @@ -28,13 +28,6 @@ Res StackScan(ScanState ss, Word *stackCold, jmp_buf jb; Word *stackHot = (void *)&jb; - /* .assume.stack: This implementation assumes that the stack grows - * downwards, so that the address of the jmp_buf is the base of the - * part of the stack that needs to be scanned. (StackScanInner makes - * the same assumption.) - */ - AVER(stackHot < stackCold); - (void)setjmp(jb); return StackScanInner(ss, stackCold, stackHot, sizeof jb / sizeof(Word), From bd59b5e1fb67854b4e324ceef18ba38a5ec12875 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 2 Mar 2016 10:34:21 +0000 Subject: [PATCH 192/337] Fixing argument name to be consistent with text. Copied from Perforce Change: 189535 ServerID: perforce.ravenbrook.com --- mps/design/prmc.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/design/prmc.txt b/mps/design/prmc.txt index b7fae2d0559..c7aaad52d57 100644 --- a/mps/design/prmc.txt +++ b/mps/design/prmc.txt @@ -104,7 +104,7 @@ instruction which was caused the fault to be re-executed. Return This function is only called if ``ProtCanStepInstruction(context)`` returned ``TRUE``. -``Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, mps_area_scan_t scan, void *closure)`` +``Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext context, mps_area_scan_t scan, void *closure)`` _`.if.context.scan`: Scan all roots found in ``context`` using the given scan state by calling ``scan``, and return the result code from From a8de8eec7c2e298f0210643ae526fa9f3617f8c3 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 2 Mar 2016 22:00:11 +0000 Subject: [PATCH 193/337] Adding new platform fri6ll to support freebsd 10 and above, which have clang and not gcc by default. Copied from Perforce Change: 189560 ServerID: perforce.ravenbrook.com --- mps/code/.p4ignore | 1 + mps/code/fri6ll.gmk | 68 +++++++++++++++++++++++++++++++++++++++++++++ mps/code/mps.c | 2 +- mps/code/mpstd.h | 17 ++++++++++++ mps/configure.ac | 9 ++++++ 5 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 mps/code/fri6ll.gmk diff --git a/mps/code/.p4ignore b/mps/code/.p4ignore index 6cb34b80f0c..016e58eef6a 100644 --- a/mps/code/.p4ignore +++ b/mps/code/.p4ignore @@ -6,6 +6,7 @@ ananll ananmv fri3gc fri6gc +fri6ll lii3gc lii6gc lii6ll diff --git a/mps/code/fri6ll.gmk b/mps/code/fri6ll.gmk new file mode 100644 index 00000000000..6595410c9a3 --- /dev/null +++ b/mps/code/fri6ll.gmk @@ -0,0 +1,68 @@ +# -*- makefile -*- +# +# fri6ll.gmk: BUILD FOR FreeBSD/x86-64/GCC PLATFORM +# +# $Id$ +# Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. + +PFM = fri6ll + +MPMPF = lockix.c thix.c pthrdext.c vmix.c \ + protix.c protsgix.c prmcan.c prmci6fr.c ssixi6.c span.c + +LIBS = -lm -pthread + +include ll.gmk + +# FIXME: We pun types through the MPS interface, setting off this warning. +# Can we avoid this? The puns might indeed be dangerous. +#CFLAGSCOMPILER += -Wno-strict-aliasing + +# For SQLite3. +LINKFLAGS += -L/usr/local/lib +CFLAGSCOMPILER += -I/usr/local/include + +CC = cc + +include comm.gmk + + +# C. COPYRIGHT AND LICENSE +# +# Copyright (C) 2001-2016 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/mps.c b/mps/code/mps.c index 4dceeeeec86..e71a0af19e1 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -157,7 +157,7 @@ /* FreeBSD on 64-bit Intel built with GCC */ -#elif defined(MPS_PF_FRI6GC) +#elif defined(MPS_PF_FRI6GC) || defined(MPS_PF_FRI6LL) #include "lockix.c" /* Posix locks */ #include "thix.c" /* Posix threading */ diff --git a/mps/code/mpstd.h b/mps/code/mpstd.h index 1306281224b..a0a913b28c2 100644 --- a/mps/code/mpstd.h +++ b/mps/code/mpstd.h @@ -278,6 +278,23 @@ #define MPS_PF_ALIGN 8 +#elif defined(__FreeBSD__) && defined (__x86_64__) && defined (__GNUC__) \ + && defined(__clang__) +#if defined(CONFIG_PF_STRING) && ! defined(CONFIG_PF_FRI6LL) +#error "specified CONFIG_PF_... inconsistent with detected fri6ll" +#endif +#define MPS_PF_FRI6LL +#define MPS_PF_STRING "fri6ll" +#define MPS_OS_FR +#define MPS_ARCH_I6 +#define MPS_BUILD_LL +#define MPS_T_WORD unsigned long +#define MPS_T_ULONGEST unsigned long /* FIXME: Check this for Clang */ +#define MPS_WORD_WIDTH 64 +#define MPS_WORD_SHIFT 6 +#define MPS_PF_ALIGN 8 + + #else #error "The MPS Kit does not have a configuration for this platform out of the box; see manual/build.txt" #endif diff --git a/mps/configure.ac b/mps/configure.ac index f564f047d5e..f6a276ad0cc 100644 --- a/mps/configure.ac +++ b/mps/configure.ac @@ -98,6 +98,15 @@ case $host/$CLANG in CPP="$CC -I/usr/local/include -E" PFMCFLAGS="$CFLAGS_GC" ;; + amd64-*-freebsd*/yes | x86_64-*-freebsd*/yes) + AC_MSG_RESULT([FreeBSD x86_64]) + MPS_OS_NAME=fr + MPS_ARCH_NAME=i6 + MPS_BUILD_NAME=ll + # Need /usr/local/include in order to find sqlite3.h + CFLAGS="-I/usr/local/include" + CPP="$CC -I/usr/local/include -E" + PFMCFLAGS="$CFLAGS_GC" amd64-*-freebsd*/no | x86_64-*-freebsd*/no) AC_MSG_RESULT([FreeBSD x86_64]) MPS_OS_NAME=fr From 7d93da3182729553937473995882be09c737014e Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 4 Mar 2016 13:20:51 +0000 Subject: [PATCH 194/337] Adding new platform fri3ll to support freebsd 10 and above, which have clang and not gcc by default. Copied from Perforce Change: 189622 ServerID: perforce.ravenbrook.com --- mps/code/.p4ignore | 1 + mps/code/fri3ll.gmk | 71 +++++++++++++++++++++++++++++++++++++++++++++ mps/code/mps.c | 6 ++-- mps/code/mpstd.h | 17 +++++++++++ 4 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 mps/code/fri3ll.gmk diff --git a/mps/code/.p4ignore b/mps/code/.p4ignore index 016e58eef6a..f64f4cd5d6b 100644 --- a/mps/code/.p4ignore +++ b/mps/code/.p4ignore @@ -5,6 +5,7 @@ anangc ananll ananmv fri3gc +fri3ll fri6gc fri6ll lii3gc diff --git a/mps/code/fri3ll.gmk b/mps/code/fri3ll.gmk new file mode 100644 index 00000000000..8801830e757 --- /dev/null +++ b/mps/code/fri3ll.gmk @@ -0,0 +1,71 @@ +# -*- makefile -*- +# +# fri3ll.gmk: BUILD FOR FreeBSD/i386/GCC PLATFORM +# +# $Id$ +# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + +PFM = fri3ll + +MPMPF = \ + lockix.c \ + prmcan.c \ + prmci3fr.c \ + protix.c \ + protsgix.c \ + pthrdext.c \ + span.c \ + ssixi3.c \ + thix.c \ + vmix.c + +LIBS = -lm -pthread + +include ll.gmk + +# For SQLite3. +LINKFLAGS += -L/usr/local/lib +CFLAGSCOMPILER += -I/usr/local/include + +include comm.gmk + + +# 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/mps.c b/mps/code/mps.c index e71a0af19e1..5c82e162594 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -140,9 +140,9 @@ #include "span.c" /* generic stack probe */ #include "ssixi6.c" /* Posix on 64-bit Intel stack scan */ -/* FreeBSD on 32-bit Intel built with GCC */ +/* FreeBSD on 32-bit Intel built with GCC or Clang */ -#elif defined(MPS_PF_FRI3GC) +#elif defined(MPS_PF_FRI3GC) || defined(MPS_PF_FRI3LL) #include "lockix.c" /* Posix locks */ #include "thix.c" /* Posix threading */ @@ -155,7 +155,7 @@ #include "span.c" /* generic stack probe */ #include "ssixi3.c" /* Posix on 32-bit Intel stack scan */ -/* FreeBSD on 64-bit Intel built with GCC */ +/* FreeBSD on 64-bit Intel built with GCC or Clang */ #elif defined(MPS_PF_FRI6GC) || defined(MPS_PF_FRI6LL) diff --git a/mps/code/mpstd.h b/mps/code/mpstd.h index a0a913b28c2..6147e2a40e7 100644 --- a/mps/code/mpstd.h +++ b/mps/code/mpstd.h @@ -261,6 +261,23 @@ #define MPS_PF_ALIGN 4 +#elif defined(__FreeBSD__) && defined (__i386__) && defined (__GNUC__) \ + && defined(__clang__) +#if defined(CONFIG_PF_STRING) && ! defined(CONFIG_PF_FRI3LL) +#error "specified CONFIG_PF_... inconsistent with detected fri3ll" +#endif +#define MPS_PF_FRI3LL +#define MPS_PF_STRING "fri3ll" +#define MPS_OS_FR +#define MPS_ARCH_I3 +#define MPS_BUILD_LL +#define MPS_T_WORD unsigned long +#define MPS_T_ULONGEST unsigned long +#define MPS_WORD_WIDTH 32 +#define MPS_WORD_SHIFT 5 +#define MPS_PF_ALIGN 4 + + #elif defined(__FreeBSD__) && defined (__x86_64__) && defined (__GNUC__) \ && !defined(__clang__) #if defined(CONFIG_PF_STRING) && ! defined(CONFIG_PF_FRI6GC) From 75a200ecde50c98b85d37e6df1921603abf7eba7 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 4 Mar 2016 13:26:43 +0000 Subject: [PATCH 195/337] Adding platforms fri3ll and fri6ll to autoconf and generating configure script. Copied from Perforce Change: 189625 ServerID: perforce.ravenbrook.com --- mps/configure | 40 +++++++++++++++++++++++++++++++--------- mps/configure.ac | 20 ++++++++++++++++++++ 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/mps/configure b/mps/configure index edbc7320304..2aa767cd2d5 100755 --- a/mps/configure +++ b/mps/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for Memory Pool System Kit release/1.114.0. +# Generated by GNU Autoconf 2.69 for Memory Pool System Kit release/1.115.0. # # Report bugs to . # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='Memory Pool System Kit' PACKAGE_TARNAME='mps-kit' -PACKAGE_VERSION='release/1.114.0' -PACKAGE_STRING='Memory Pool System Kit release/1.114.0' +PACKAGE_VERSION='release/1.115.0' +PACKAGE_STRING='Memory Pool System Kit release/1.115.0' PACKAGE_BUGREPORT='mps-questions@ravenbrook.com' PACKAGE_URL='http://www.ravenbrook.com/project/mps/' @@ -1245,7 +1245,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures Memory Pool System Kit release/1.114.0 to adapt to many kinds of systems. +\`configure' configures Memory Pool System Kit release/1.115.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1310,7 +1310,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of Memory Pool System Kit release/1.114.0:";; + short | recursive ) echo "Configuration of Memory Pool System Kit release/1.115.0:";; esac cat <<\_ACEOF @@ -1391,7 +1391,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -Memory Pool System Kit configure release/1.114.0 +Memory Pool System Kit configure release/1.115.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1693,7 +1693,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by Memory Pool System Kit $as_me release/1.114.0, which was +It was created by Memory Pool System Kit $as_me release/1.115.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3524,6 +3524,28 @@ $as_echo "FreeBSD x86_64" >&6; } CPP="$CC -I/usr/local/include -E" PFMCFLAGS="$CFLAGS_GC" ;; + i*86-*-freebsd*/yes) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: FreeBSD x86" >&5 +$as_echo "FreeBSD x86" >&6; } + MPS_OS_NAME=fr + MPS_ARCH_NAME=i3 + MPS_BUILD_NAME=ll + # Need /usr/local/include in order to find sqlite3.h + CFLAGS="-I/usr/local/include" + CPP="$CC -I/usr/local/include -E" + PFMCFLAGS="$CFLAGS_LL" + ;; + amd64-*-freebsd*/no | x86_64-*-freebsd*/no) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: FreeBSD x86_64" >&5 +$as_echo "FreeBSD x86_64" >&6; } + MPS_OS_NAME=fr + MPS_ARCH_NAME=i6 + MPS_BUILD_NAME=ll + # Need /usr/local/include in order to find sqlite3.h + CFLAGS="-I/usr/local/include" + CPP="$CC -I/usr/local/include -E" + PFMCFLAGS="$CFLAGS_LL" + ;; *) as_fn_error $? "MPS does not support this platform out of the box. See manual/build.txt" "$LINENO" 5 esac @@ -4144,7 +4166,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by Memory Pool System Kit $as_me release/1.114.0, which was +This file was extended by Memory Pool System Kit $as_me release/1.115.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4198,7 +4220,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -Memory Pool System Kit config.status release/1.114.0 +Memory Pool System Kit config.status release/1.115.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/mps/configure.ac b/mps/configure.ac index f6a276ad0cc..940ca852cc2 100644 --- a/mps/configure.ac +++ b/mps/configure.ac @@ -117,6 +117,26 @@ case $host/$CLANG in CPP="$CC -I/usr/local/include -E" PFMCFLAGS="$CFLAGS_GC" ;; + i*86-*-freebsd*/yes) + AC_MSG_RESULT([FreeBSD x86]) + MPS_OS_NAME=fr + MPS_ARCH_NAME=i3 + MPS_BUILD_NAME=ll + # Need /usr/local/include in order to find sqlite3.h + CFLAGS="-I/usr/local/include" + CPP="$CC -I/usr/local/include -E" + PFMCFLAGS="$CFLAGS_LL" + ;; + amd64-*-freebsd*/no | x86_64-*-freebsd*/no) + AC_MSG_RESULT([FreeBSD x86_64]) + MPS_OS_NAME=fr + MPS_ARCH_NAME=i6 + MPS_BUILD_NAME=ll + # Need /usr/local/include in order to find sqlite3.h + CFLAGS="-I/usr/local/include" + CPP="$CC -I/usr/local/include -E" + PFMCFLAGS="$CFLAGS_LL" + ;; *) AC_MSG_ERROR([MPS does not support this platform out of the box. See manual/build.txt]) esac From 35d7ce99d639281a3f0306d6557c7293cac5733e Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 5 Mar 2016 14:08:09 +0000 Subject: [PATCH 196/337] Fixing build on w3i6mv. Copied from Perforce Change: 189651 ServerID: perforce.ravenbrook.com --- mps/code/.p4ignore | 2 ++ mps/code/commpre.nmk | 2 ++ mps/code/scan.c | 8 ++++++++ mps/code/ssw3i6mv.c | 3 +-- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/mps/code/.p4ignore b/mps/code/.p4ignore index f64f4cd5d6b..7db90ebb062 100644 --- a/mps/code/.p4ignore +++ b/mps/code/.p4ignore @@ -51,3 +51,5 @@ tags 9 # Mac OS X Finder turds .DS_Store +# Emacs backups +*~ diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index eaaa46c84a0..c6738c64c02 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -146,6 +146,7 @@ MPMCOMMON=\ [mpm] \ [mpsi] \ [nailboard] \ + [policy] \ [pool] \ [poolabs] \ [poolmfs] \ @@ -160,6 +161,7 @@ MPMCOMMON=\ [root] \ [sa] \ [sac] \ + [scan] \ [seg] \ [shield] \ [splay] \ diff --git a/mps/code/scan.c b/mps/code/scan.c index 59bda4ba583..b4c4eceae3f 100644 --- a/mps/code/scan.c +++ b/mps/code/scan.c @@ -13,6 +13,14 @@ */ #include "mps.h" +#include "mpstd.h" /* for MPS_BUILD_MV */ + + +#ifdef MPS_BUILD_MV +/* MSVC warning 4127 = conditional expression is constant */ +/* Objects to: MPS_SCAN_AREA(1). */ +#pragma warning( disable : 4127 ) +#endif #define MPS_SCAN_AREA(test) \ diff --git a/mps/code/ssw3i6mv.c b/mps/code/ssw3i6mv.c index 884424d259c..c95f8c30608 100644 --- a/mps/code/ssw3i6mv.c +++ b/mps/code/ssw3i6mv.c @@ -31,8 +31,7 @@ SRCID(ssw3i6mv, "$Id$"); Res StackScan(ScanState ss, Word *stackCold, - mps_area_scan_t scan_area - void *closure) + mps_area_scan_t scan_area, void *closure) { jmp_buf jb; From 8d3b67be05a0e6f6e441c5bf68a047d21a5043f9 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 5 Mar 2016 14:08:43 +0000 Subject: [PATCH 197/337] Enabling keyword expansion on scan.c. Copied from Perforce Change: 189652 ServerID: perforce.ravenbrook.com From 9a7475e4e8d231231de0274d413dbbc75caeb40f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 6 Mar 2016 14:07:45 +0000 Subject: [PATCH 198/337] Change 189541 renamed the reg_scan_p parameter to mps_root_create_reg; update test cases accordingly. Copied from Perforce Change: 189673 ServerID: perforce.ravenbrook.com --- mps/test/argerr/142.c | 2 +- mps/test/argerr/143.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/test/argerr/142.c b/mps/test/argerr/142.c index 1c077ba710b..05869f11ce8 100644 --- a/mps/test/argerr/142.c +++ b/mps/test/argerr/142.c @@ -7,7 +7,7 @@ TEST_HEADER OUTPUT_SPEC assert = true assertfile P= mpsi.c - assertcond = reg_scan_p != NULL + assertcond = cold != NULL END_HEADER */ diff --git a/mps/test/argerr/143.c b/mps/test/argerr/143.c index 9099a6c3c13..90563119c8c 100644 --- a/mps/test/argerr/143.c +++ b/mps/test/argerr/143.c @@ -7,7 +7,7 @@ TEST_HEADER OUTPUT_SPEC assert = true assertfile P= mpsi.c - assertcond = AddrIsAligned(reg_scan_p, sizeof(Word)) + assertcond = AddrIsAligned(cold, sizeof(Word)) END_HEADER */ From 484941d9a0185ef5fd0b758d5de7588edeed6e1c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 6 Mar 2016 14:15:37 +0000 Subject: [PATCH 199/337] Add make target for running the mmqa test suite. Copied from Perforce Change: 189674 ServerID: perforce.ravenbrook.com --- mps/code/comm.gmk | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index e5629f064d9..ee5d05bc1b8 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -3,7 +3,7 @@ # comm.gmk: COMMON GNUMAKEFILE FRAGMENT # # $Id$ -# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. +# Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. # # DESCRIPTION # @@ -319,10 +319,23 @@ $(addprefix $(PFM)/$(VARIETY)/,$(TEST_SUITES)): $(TEST_TARGETS) ../tool/testrun.sh -s "$(notdir $@)" "$(PFM)/$(VARIETY)" +# == MMQA test suite == +# +# See test/README for documentation on running the MMQA test suite. + +MMQA=perl test/qa -i ../code -l ../code/$(PFM)/$(VARIETY)/mps.o + +$(PFM)/$(VARIETY)/testmmqa: + $(MAKE) -f $(PFM).gmk VARIETY=$(VARIETY) TARGET=mps.o variety + (cd ../test && $(MMQA) runset testsets/argerr) + (cd ../test && $(MMQA) runset testsets/conerr) + (cd ../test && $(MMQA) runset testsets/passing) + + # These convenience targets allow one to type "make foo" to build target # foo in selected varieties (or none, for the latter rule). -$(ALL_TARGETS) $(TEST_SUITES): phony +$(ALL_TARGETS) $(TEST_SUITES) testmmqa: phony ifdef VARIETY $(MAKE) -f $(PFM).gmk TARGET=$@ variety else @@ -667,7 +680,7 @@ find-puns: phony # C. COPYRIGHT AND LICENSE # -# Copyright (c) 2001-2014 Ravenbrook Limited . +# Copyright (c) 2001-2016 Ravenbrook Limited . # All rights reserved. This is an open source license. Contact # Ravenbrook for commercial licensing options. # From ca1cb12c55519f52b7b8bf63d335d1d747ccd413 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 6 Mar 2016 18:36:47 +0000 Subject: [PATCH 200/337] Index to mps source code. Copied from Perforce Change: 189679 ServerID: perforce.ravenbrook.com --- mps/manual/source/code-index.rst | 451 +++++++++++++++++++++++++ mps/manual/source/index.rst | 1 + mps/manual/source/topic/allocation.rst | 2 + mps/manual/source/topic/telemetry.rst | 2 + 4 files changed, 456 insertions(+) create mode 100644 mps/manual/source/code-index.rst diff --git a/mps/manual/source/code-index.rst b/mps/manual/source/code-index.rst new file mode 100644 index 00000000000..8e853eebc5c --- /dev/null +++ b/mps/manual/source/code-index.rst @@ -0,0 +1,451 @@ +.. _code-index: + +Index to source code +==================== + + +External MPS interface +---------------------- + +The external MPS interface consists of header files that the +:term:`client program` is expected to include, plus the single-file +source code (mps.c). See design.mps.interface-c_. + +=========== ================================================================== +File Description +=========== ================================================================== +mps.h Public MPS interface. +mps.c Single-file source code. See :ref:`guide-build`. +mpsacl.h :ref:`topic-arena-client` external interface. +mpsavm.h :ref:`topic-arena-vm` external interface. +mpscamc.h :ref:`pool-amc` pool class external interface. +mpscams.h :ref:`pool-ams` pool class external interface. +mpscawl.h :ref:`pool-awl` pool class external interface. +mpsclo.h :ref:`pool-lo` pool class external interface. +mpscmfs.h :ref:`pool-mfs` pool class external interface. +mpscmv.h :ref:`pool-mv` pool class external interface. +mpscmv2.h Former (deprecated) :ref:`pool-mvt` pool class interface. +mpscmvff.h :ref:`pool-mvff` pool class external interface. +mpscmvt.h :ref:`pool-mvt` pool class external interface. +mpscsnc.h :ref:`pool-snc` pool class external interface. +mpsio.h :ref:`topic-plinth-io` interface. +mpslib.h :ref:`topic-plinth-lib` interface. +=========== ================================================================== + + +Plinth +------ + +The :term:`plinth` provides an interface between the MPS and the +execution environment, to help support :term:`freestanding` +implementations. See :ref:`topic-plinth`. + +=========== ================================================================== +File Description +=========== ================================================================== +mpsioan.c :ref:`topic-plinth-io` for "ANSI" (hosted) environments. +mpsliban.c :ref:`topic-plinth-lib` for "ANSI" (hosted) environments. +=========== ================================================================== + + +Configuration +------------- + +These header files provide platform-specific constants, type +declarations, and macros. See :ref:`topic-porting` and +design.mps.config_. + +=========== ================================================================== +File Description +=========== ================================================================== +clock.h Fast high-resolution clocks. +config.h MPS configuration header. +mpstd.h Target detection header. +=========== ================================================================== + + +Core MPS +-------- + +============ ================================================================= +File Description +============ ================================================================= +abq.c Fixed-length queue implementation. See design.mps.abq_. +abq.h Fixed-length queue interface. See design.mps.abq_. +arena.c Arena implementation. See design.mps.arena_. +arenacl.c :ref:`topic-arena-client` implementation. +arenavm.c :ref:`topic-arena-vm` implementation. +arg.c :ref:`topic-keyword` implementation. +arg.h :ref:`topic-keyword` interface. +boot.c Bootstrap allocator implementation. See design.mps.bootstrap_. +boot.h Bootstrap allocator interface. See design.mps.bootstrap_. +bt.c Bit table implementation. See design.mps.bt_. +bt.h Bit table interface. See design.mps.bt_. +buffer.c Buffer implementation. See design.mps.buffer_. +cbs.c Coalescing block implementation. See design.mps.cbs_. +cbs.h Coalescing block interface. See design.mps.cbs_. +chain.h Locus manager interface. See design.mps.locus_. +check.h Assertion interface. See design.mps.check_. +dbgpool.c :ref:`topic-debugging` implementation. +dbgpool.h :ref:`topic-debugging` interface. +dbgpooli.c :ref:`topic-debugging` external interface. +event.c :ref:`topic-telemetry` implementation. +event.h :ref:`topic-telemetry` interface (internal). +eventcom.h :ref:`topic-telemetry` interface (auxiliary programs). +eventdef.h :ref:`topic-telemetry` event definitions. +failover.c Fail-over allocator implementation. See design.mps.failover_. +failover.h Fail-over allocator interface. See design.mps.failover_. +format.c :ref:`topic-format` implementation. +freelist.c Freelist allocator implementation. See design.mps.freelist_. +freelist.h Freelist allocator interface. See design.mps.freelist_. +global.c Global arena implementation. +land.c Land implementation. See design.mps.land_. +ld.c :ref:`topic-location` implementation. +locus.c Locus manager implementation. See design.mps.locus_. +message.c :ref:`topic-message` implementation. +meter.c Debugging accumulator implementation. +meter.h Debugging accumulator interface. +misc.h Miscellaneous constant and macro definitions. +mpm.c Miscellaneous support functions. See design.mps.writef_. +mpm.h Core MPS interface. ("MPM" = "Memory Pool Manager") +mpmst.h Core data structure declarations. +mpmtypes.h Core type declarations. +mpsi.c External interface implementation. See design.mps.interface-c_. +mpsiw3.c Additional external interface implementation for Windows. +mpswin.h Wrapper for windows.h. +nailboard.c Nailboard implementation. See design.mps.nailboard_. +nailboard.h Nailboard interface. See design.mps.nailboard_. +policy.c Collection policy decisions. See design.mps.strategy_. +pool.c Pool implementation. See design.mps.pool_. +poolabs.c Abstract pool classes. +poolmrg.c Manual Rank Guardian pool implementation. See design.mps.poolmrg_. +poolmrg.h Manual Rank Guardian pool interface. See design.mps.poolmrg_. +protocol.c Inheritance protocol implementation. See design.mps.protocol_. +protocol.h Inheritance protocol interface. See design.mps.protocol_. +range.c Address ranges implementation. See design.mps.range_. +range.h Address ranges interface. See design.mps.range_. +ref.c Ranks and zones implementation. +reserv.c Reservoir pool implementation. See design.mps.reservoir_. +ring.c Ring implementation. See design.mps.ring_. +ring.h Ring interface. See design.mps.ring_. +root.c :ref:`topic-root` implementation. +sa.c Sparse array implementation. +sa.h Sparse array interface. +sac.c :ref:`topic-cache` implementation. +sac.h :ref:`topic-cache` interface. +sc.h Stack context interface. +scan.c :ref:`topic-scanning` functions. +seg.c Segment implementation. See design.mps.seg_. +shield.c Shield implementation. See design.mps.shield_. +splay.c Splay tree implementation. See design.mps.splay_. +splay.h Splay tree interface. See design.mps.splay_. +trace.c Trace implementation. See design.mps.trace_. +traceanc.c More trace implementation. See design.mps.trace_. +tract.c Chunk and tract implementation. See design.mps.arena_. +tract.h Chunk and tract interface. See design.mps.arena_. +tree.c Binary tree implementation. +tree.h Binary tree interface. +version.c MPS version implementation. See design.mps.version_. +walk.c Formatted object walker. +============ ================================================================= + + +Platform interfaces +------------------- + +These modules provide interfaces to features that are not available in +standard C, and so may need to be ported to new platforms. See +:ref:`topic-porting`. + +============ ================================================================= +File Description +============ ================================================================= +lock.h Lock interface. See design.mps.lock_. +lockan.c Lock implementation for standard C. +lockix.c Lock implementation for POSIX. +lockli.c Lock implementation for Linux. +lockw3.c Lock implementation for Windows. +prmcan.c Mutator context implementation for standard C. +prmci3.h Mutator context interface for IA-32. +prmci3fr.c Mutator context implementation for FreeBSD, IA-32. +prmci3li.c Mutator context implementation for Linux, IA-32. +prmci3w3.c Mutator context implementation for Windows, IA-32. +prmci3xc.c Mutator context implementation for OS X, IA-32. +prmci6.h Mutator context interface for x86-64. +prmci6fr.c Mutator context implementation for FreeBSD, x86-64. +prmci6li.c Mutator context implementation for Linux, x86-64. +prmci6w3.c Mutator context implementation for Windows, x86-64. +prmci6xc.c Mutator context implementation for OS X, x86-64. +prmcix.h Mutator context interface for POSIX. +prmcw3.h Mutator context interface for Windows. +prmcxc.h Mutator context interface for OS X. +prot.h Protection interface. See design.mps.prot_. +protan.c Protection implementation for standard C. +proti3.c Protection implementation for IA-32. +proti6.c Protection implementation for x86-64. +protix.c Protection implementation for POSIX. +protli.c Protection implementation for Linux. +protsgix.c Protection implementation for POSIX (signals part). +protw3.c Protection implementation for Windows. +protxc.c Protection implementation for OS X. +protxc.h Protection interface for OS X. +pthrdext.c Protection implementation for POSIX (threads part). +pthrdext.h Protection interface for POSIX (threads part). +sp.h Stack probe interface. See design.mps.sp_. +span.c Stack probe implementation for standard C. +spw3i3.c Stack probe implementation for Windows, IA-32. +spw3i6.c Stack probe implementation for Windows, x86-64. +ss.c Stack scanning implementation (common part). +ss.h Stack scanning interface. See design.mps.ss_. +ssan.c Stack scanning implementation for standard C. +ssixi3.c Stack scanning implementation for POSIX, IA-32. +ssixi6.c Stack scanning implementation for POSIX, x86-64. +ssw3i3mv.c Stack scanning implementation for Windows, IA-32, Visual C. +ssw3i3pc.c Stack scanning implementation for Windows, x86-64, Pelles C. +ssw3i6mv.c Stack scanning implementation for Windows, IA-32, Visual C. +ssw3i6pc.c Stack scanning implementation for Windows, x86-64, Pelles C. +th.h Threads interface. See design.mps.thread-manager_. +than.c Threads implementation for standard C. +thix.c Threads implementation for POSIX. +thw3.c Threads implementation for Windows. +thw3.h Threads interface for Windows. +thw3i3.c Threads implementation for Windows, IA-32. +thw3i6.c Threads implementation for Windows, x86-64. +thxc.c Threads implementation for OS X. +vm.c Virtual memory implementation (common part). +vm.h Virtual memory interface. See design.mps.vm_. +vman.c Virtual memory implementation for standard C. +vmix.c Virtual memory implementation for POSIX. +vmw3.c Virtual memory implementation for Windows. +============ ================================================================= + + +Pool classes +------------ + +These files implement the supported :term:`pool classes`. Some of +these (MFS, MV) are used internally by the MPS; the others are +available for :term:`client programs` only. See :ref:`pool`. + +=========== ================================================================== +File Description +=========== ================================================================== +lo.h :ref:`pool-lo` internal interface. +poolamc.c :ref:`pool-amc` implementation. +poolams.c :ref:`pool-ams` implementation. +poolams.h :ref:`pool-ams` internal interface. +poolamsi.c :ref:`pool-ams` external interface implementation. +poolawl.c :ref:`pool-awl` implementation. +poollo.c :ref:`pool-lo` implementation. +poolmfs.c :ref:`pool-mfs` implementation. +poolmfs.h :ref:`pool-mfs` internal interface. +poolmv.c :ref:`pool-mv` implementation. +poolmv.h :ref:`pool-mv` internal interface. +poolmv2.c :ref:`pool-amc` implementation. +poolmv2.h :ref:`pool-mvt` internal interface. +poolmvff.c :ref:`pool-mvff` implementation. +poolsnc.c :ref:`pool-snc` implementation. +=========== ================================================================== + + +Auxiliary programs +------------------ + +These files implement auxiliary programs. See +:ref:`topic-telemetry-utilities`. + +=========== ================================================================== +File Description +=========== ================================================================== +eventcnv.c :ref:`telemetry-mpseventcnv`. +eventrep.c Event replaying implementation (broken). +eventrep.h Event replaying interface (broken). +eventsql.c :ref:`telemetry-mpseventsql`. +eventtxt.c :ref:`telemetry-mpseventtxt`. +getopt.h Command-line option interface. Adapted from FreeBSD. +getoptl.c Command-line option implementation. Adapted from FreeBSD. +replay.c Event replaying program (broken). +table.c Address-based hash table implementation. +table.h Address-based hash table interface. +=========== ================================================================== + + +Benchmarks +---------- + +=========== ================================================================== +File Description +=========== ================================================================== +djbench.c Benchmark for manually managed pool classes. +gcbench.c Benchmark for automatically managed pool classes. +=========== ================================================================== + + +Test support +------------ + +This is code that's shared between test cases. + +============ ================================================================= +File Description +============ ================================================================= +fmtdy.c Dylan object format implementation. +fmtdy.h Dylan object format interface. +fmtdytst.c Dylan object constructor implementation. +fmtdytst.h Dylan object constructor interface. +fmthe.c Dylan-like object format with headers (implementation). +fmthe.h Dylan-like object format with headers (interface). +fmtno.c Null object format implementation. +fmtno.h Null object format interface. +fmtscheme.c Scheme object format implementation. +fmtscheme.h Scheme object format interface. +pooln.c Null pool implementation. +pooln.h Null pool interface. +testlib.c Test utilities implementation. +testlib.h Test utilities interface. +testthr.h Test threads interface. See design.mps.testthr_. +testthrix.c Test threads implementation for POSIX. +testthrw3.c Test threads implementation for Windows. +============ ================================================================= + + +Interactive test cases +---------------------- + +These test cases provide harness for interacting with parts of the +MPS, for exploring the interface and testing by hand. These predate +the use of continuous integration: we wouldn't write this kind of test +case now. + +=========== ================================================================== +File Description +=========== ================================================================== +bttest.c Interactive bit tables test harness. +teletest.c Interactive telemetry test harness. +=========== ================================================================== + + +Automated test cases +-------------------- + +These are test cases that run automatically and form the main test +suite. See design.mps.tests_. + +================ ============================================================= +File Description +================ ============================================================= +abqtest.c Fixed-length queue test. +airtest.c Ambiguous interior reference test. +amcss.c :ref:`pool-amc` stress test. +amcsshe.c :ref:`pool-amc` stress test (using in-band headers). +amcssth.c :ref:`pool-amc` stress test (using multiple threads). +amsss.c :ref:`pool-ams` stress test. +amssshe.c :ref:`pool-ams` stress test (using in-band headers). +apss.c :ref:`topic-allocation-point` stress test. +arenacv.c Arena coverage test. +awlut.c :ref:`pool-awl` unit test. +awluthe.c :ref:`pool-awl` unit test (using in-band headers). +awlutth.c :ref:`pool-awl` unit test (using multiple threads). +btcv.c Bit table coverage test. +exposet0.c :c:func:`mps_arena_expose` test. +expt825.c Regression test for job000825_. +fbmtest.c Free block manager (CBS and Freelist) test. +finalcv.c :ref:`topic-finalization` coverage test. +finaltest.c :ref:`topic-finalization` test. +fotest.c Failover allocator test. +landtest.c Land test. +locbwcss.c Locus backwards compatibility stress test. +lockcov.c Lock coverage test. +lockut.c Lock unit test. +locusss.c Locus stress test. +locv.c :ref:`pool-lo` coverage test. +messtest.c :ref:`topic-message` test. +mpmss.c Manual allocation stress test. +mpsicv.c External interface coverage test. +mv2test.c :ref:`pool-mvt` test. +nailboardtest.c Nailboard test. +poolncv.c Null pool class test. +qs.c Quicksort test. +sacss.c :ref:`topic-cache` stress test. +segsmss.c Segment splitting and merging stress test. +steptest.c :c:func:`mps_arena_step` test. +tagtest.c Tagged pointer scanning test. +walkt0.c Formatted object walking test. +zcoll.c Garbage collection progress test. +zmess.c Garbage collection and finalization message test. +================ ============================================================= + + +Build infrastructure +-------------------- + +These are makefiles (and makefile fragments) used to build the MPS. +See :ref:`topic-porting`. + +============= ================================================================ +File Description +============= ================================================================ +anangc.gmk GNU makefile for platform ANANGC. +ananll.gmk GNU makefile for platform ANANLL. +ananmv.nmk NMAKE file for platform ANANMV. +comm.gmk Common GNU make fragment. +commpost.nmk Common NMAKE fragment (included before the compiler fragment). +commpre.nmk Common NMAKE fragment (included after the compiler fragment). +fri3gc.gmk GNU makefile for platform FRI3GC. +fri3ll.gmk GNU makefile for platform FRI3LL. +fri6gc.gmk GNU makefile for platform FRI6GC. +fri6ll.gmk GNU makefile for platform FRI6LL. +gc.gmk GNU make fragment for GCC. +gp.gmk GNU make fragment for GCC/GProf (broken). +lii3gc.gmk GNU makefile for platform LII3GC. +lii6gc.gmk GNU makefile for platform LII6GC. +lii6ll.gmk GNU makefile for platform LII6LL. +ll.gmk GNU make fragment for Clang/LLVM. +mv.nmk NMAKE fragment for Microsoft Visual C. +pc.nmk NMAKE fragment for Pelles C. +w3i3mv.nmk NMAKE file for platform W3I3MV. +w3i3pc.nmk NMAKE file for platform W3I3PC. +w3i6mv.nmk NMAKE file for platform W3I6MV. +w3i6pc.nmk NMAKE file for platform W3I6PC. +xci3gc.gmk GNU makefile for platform XCI3GC. +xci6ll.gmk GNU makefile for platform XCI6LL. +============= ================================================================ + + +.. _design.mps.abq: design/abq.html +.. _design.mps.arena: design/arena.html +.. _design.mps.bootstrap: design/bootstrap.html +.. _design.mps.bt: design/bt.html +.. _design.mps.buffer: design/buffer.html +.. _design.mps.cbs: design/cbs.html +.. _design.mps.check: design/check.html +.. _design.mps.config: design/config.html +.. _design.mps.failover: design/failover.html +.. _design.mps.freelist: design/freelist.html +.. _design.mps.interface-c: design/interface-c.html +.. _design.mps.land: design/land.html +.. _design.mps.lock: design/lock.html +.. _design.mps.locus: design/locus.html +.. _design.mps.nailboard: design/nailboard.html +.. _design.mps.pool: design/pool.html +.. _design.mps.poolmrg: design/poolmrg.html +.. _design.mps.prmc: design/prmc.html +.. _design.mps.protocol: design/protocol.html +.. _design.mps.prot: design/prot.html +.. _design.mps.range: design/range.html +.. _design.mps.reservoir: design/reservoir.html +.. _design.mps.ring: design/ring.html +.. _design.mps.seg: design/seg.html +.. _design.mps.shield: design/shield.html +.. _design.mps.sp: design/sp.html +.. _design.mps.splay: design/splay.html +.. _design.mps.ss: design/ss.html +.. _design.mps.strategy: design/strategy.html +.. _design.mps.tests: design/tests.html +.. _design.mps.testthr: design/testthr.html +.. _design.mps.thread-manager: design/thread-manager.html +.. _design.mps.trace: design/trace.html +.. _design.mps.version: design/version.html +.. _design.mps.vm: design/vm.html +.. _design.mps.writef: design/writef.html +.. _job000825: https://www.ravenbrook.com/project/mps/issue/job000825 diff --git a/mps/manual/source/index.rst b/mps/manual/source/index.rst index 57758fea8ef..5d61d583c2d 100644 --- a/mps/manual/source/index.rst +++ b/mps/manual/source/index.rst @@ -19,6 +19,7 @@ Appendices bib glossary/index + code-index copyright contact contributing diff --git a/mps/manual/source/topic/allocation.rst b/mps/manual/source/topic/allocation.rst index 7559381202b..aaf8fc60a78 100644 --- a/mps/manual/source/topic/allocation.rst +++ b/mps/manual/source/topic/allocation.rst @@ -79,6 +79,8 @@ Manual allocation .. index:: single: allocation point +.. _topic-allocation-point: + Allocation points ----------------- diff --git a/mps/manual/source/topic/telemetry.rst b/mps/manual/source/topic/telemetry.rst index e25e71e4c59..acb680828f3 100644 --- a/mps/manual/source/topic/telemetry.rst +++ b/mps/manual/source/topic/telemetry.rst @@ -49,6 +49,8 @@ demonstration of :term:`Lisp` in an appendix to his paper .. index:: single: telemetry; utilities +.. _topic-telemetry-utilities: + Telemetry utilities ------------------- From 734485d234c90091c6805b28798940808589c3f8 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 6 Mar 2016 18:44:37 +0000 Subject: [PATCH 201/337] Delete unused header lo.h. Copied from Perforce Change: 189680 ServerID: perforce.ravenbrook.com --- mps/code/lo.h | 83 -------------------------------- mps/manual/source/code-index.rst | 1 - 2 files changed, 84 deletions(-) delete mode 100644 mps/code/lo.h diff --git a/mps/code/lo.h b/mps/code/lo.h deleted file mode 100644 index 55acbec0a8e..00000000000 --- a/mps/code/lo.h +++ /dev/null @@ -1,83 +0,0 @@ -/* lo.h: LEAF OBJECT POOL CLASS INTERFACE - * - * $Id$ - * - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. - * - * The Leaf Object PoolClass is an automatically managed (ie garbage - * collected) pool for managing "leaf" objects. Leaf objects are - * objects that have no references or no references that need tracing - * (ie the objects they refer too are non-moving and are manually - * managed). - * - * This Class has the following features: - * - * Approximately 6% (asymptotically) space overhead on managed objects. - * - * Automatically reclaims memory used by objects no longer reachable - * from the roots. - * - * Non-moving. References to objects in this pool will never change - * due to "fixing". - * - * Buffers will always "commit". When allocating using a buffer, - * commit will never fail. - * - * The following caveat applies: - * - * Space and time performance will degrade when fragmentation - * increases. - */ - -#ifndef lo_h -#define lo_h - -#include "mpm.h" - -typedef struct LOStruct *LO; - -extern PoolClass PoolClassLO(void); - -#endif /* lo_h */ - - -/* C. COPYRIGHT AND LICENSE - * - * Copyright (C) 2001-2002 Ravenbrook Limited . - * All rights reserved. This is an open source license. Contact - * Ravenbrook for commercial licensing options. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Redistributions in any form must be accompanied by information on how - * to obtain complete source code for this software and any accompanying - * software that uses this software. The source code must either be - * included in the distribution or be available for no more than the cost - * of distribution plus a nominal fee, and must be freely redistributable - * under reasonable conditions. For an executable file, complete source - * code means the source code for all modules it contains. It does not - * include source code for modules or files that typically accompany the - * major components of the operating system on which the executable file - * runs. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/mps/manual/source/code-index.rst b/mps/manual/source/code-index.rst index 8e853eebc5c..0f1ff28cf3e 100644 --- a/mps/manual/source/code-index.rst +++ b/mps/manual/source/code-index.rst @@ -230,7 +230,6 @@ available for :term:`client programs` only. See :ref:`pool`. =========== ================================================================== File Description =========== ================================================================== -lo.h :ref:`pool-lo` internal interface. poolamc.c :ref:`pool-amc` implementation. poolams.c :ref:`pool-ams` implementation. poolams.h :ref:`pool-ams` internal interface. From c56dd90bbb0c9065464c848d1f3c62e3d6b3dc22 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 6 Mar 2016 18:49:47 +0000 Subject: [PATCH 202/337] Merge poolamsi.c into poolams.c for consistency with other pool class implementations. Copied from Perforce Change: 189681 ServerID: perforce.ravenbrook.com --- mps/code/comm.gmk | 2 +- mps/code/commpre.nmk | 6 +-- mps/code/mps.c | 5 +-- mps/code/poolams.c | 20 ++++++++- mps/code/poolamsi.c | 69 -------------------------------- mps/manual/source/code-index.rst | 1 - 6 files changed, 24 insertions(+), 79 deletions(-) delete mode 100644 mps/code/poolamsi.c diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index ee5d05bc1b8..0ac2c94256f 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -148,7 +148,7 @@ ARFLAGS=rc$(ARFLAGSPFM) # platforms. AMC = poolamc.c -AMS = poolams.c poolamsi.c +AMS = poolams.c AWL = poolawl.c LO = poollo.c SNC = poolsnc.c diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index c6738c64c02..e3d2443fe21 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -1,7 +1,7 @@ # commpre.nmk: FIRST COMMON FRAGMENT FOR PLATFORMS USING NMAKE -*- makefile -*-1 # # $Id$ -# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. +# Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. # # DESCRIPTION # @@ -176,7 +176,7 @@ MPMCOMMON=\ [walk] PLINTH = [mpsliban] [mpsioan] AMC = [poolamc] -AMS = [poolams] [poolamsi] +AMS = [poolams] AWL = [poolawl] LO = [poollo] MVFF = [poolmvff] @@ -332,7 +332,7 @@ LIBFLAGSCOOL = # C. COPYRIGHT AND LICENSE # -# Copyright (C) 2001-2014 Ravenbrook Limited . +# Copyright (C) 2001-2016 Ravenbrook Limited . # All rights reserved. This is an open source license. Contact # Ravenbrook for commercial licensing options. # diff --git a/mps/code/mps.c b/mps/code/mps.c index 5c82e162594..48028242a92 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -1,7 +1,7 @@ /* mps.c: MEMORY POOL SYSTEM ALL-IN-ONE TRANSLATION UNIT * * $Id$ - * Copyright (C) 2012-2014 Ravenbrook Limited. See end of file for license. + * Copyright (C) 2012-2016 Ravenbrook Limited. See end of file for license. * * .purpose: This file can be compiled to create the complete MPS library in * a single compilation, allowing the compiler to apply global optimizations @@ -86,7 +86,6 @@ #include "poolamc.c" #include "poolams.c" -#include "poolamsi.c" #include "poolawl.c" #include "poollo.c" #include "poolsnc.c" @@ -270,7 +269,7 @@ /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2012-2014 Ravenbrook Limited . + * Copyright (C) 2012-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolams.c b/mps/code/poolams.c index d3ecfa47028..40ca5f65426 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -1,7 +1,7 @@ /* poolams.c: AUTOMATIC MARK & SWEEP POOL CLASS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (c) 2002 Global Graphics Software. * * @@ -1808,6 +1808,22 @@ DEFINE_POOL_CLASS(AMSDebugPoolClass, this) } +/* mps_class_ams -- return the AMS pool class descriptor */ + +mps_pool_class_t mps_class_ams(void) +{ + return (mps_pool_class_t)AMSPoolClassGet(); +} + + +/* mps_class_ams_debug -- return the AMS (debug) pool class descriptor */ + +mps_pool_class_t mps_class_ams_debug(void) +{ + return (mps_pool_class_t)AMSDebugPoolClassGet(); +} + + /* AMSCheck -- the check method for an AMS */ Bool AMSCheck(AMS ams) @@ -1830,7 +1846,7 @@ Bool AMSCheck(AMS ams) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolamsi.c b/mps/code/poolamsi.c deleted file mode 100644 index 20ed01d6b39..00000000000 --- a/mps/code/poolamsi.c +++ /dev/null @@ -1,69 +0,0 @@ -/* poolamsi.c: AUTOMATIC MARK & SWEEP POOL CLASS C INTERFACE - * - * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. - */ - -#include "mpscams.h" -#include "mps.h" -#include "poolams.h" - -SRCID(poolamsi, "$Id$"); - - -/* mps_class_ams -- return the AMS pool class descriptor */ - -mps_pool_class_t mps_class_ams(void) -{ - return (mps_pool_class_t)AMSPoolClassGet(); -} - - -/* mps_class_ams_debug -- return the AMS (debug) pool class descriptor */ - -mps_pool_class_t mps_class_ams_debug(void) -{ - return (mps_pool_class_t)AMSDebugPoolClassGet(); -} - - -/* 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/manual/source/code-index.rst b/mps/manual/source/code-index.rst index 0f1ff28cf3e..2cfbbfd0f85 100644 --- a/mps/manual/source/code-index.rst +++ b/mps/manual/source/code-index.rst @@ -233,7 +233,6 @@ File Description poolamc.c :ref:`pool-amc` implementation. poolams.c :ref:`pool-ams` implementation. poolams.h :ref:`pool-ams` internal interface. -poolamsi.c :ref:`pool-ams` external interface implementation. poolawl.c :ref:`pool-awl` implementation. poollo.c :ref:`pool-lo` implementation. poolmfs.c :ref:`pool-mfs` implementation. From 973f5369e1af64eb952e59a1bf285102a2fd54a2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 6 Mar 2016 18:56:32 +0000 Subject: [PATCH 203/337] Rename chain.h to locus.h, for consistency with other modules, where the interface has the same name as the implemention. Copied from Perforce Change: 189682 ServerID: perforce.ravenbrook.com --- mps/code/locus.c | 6 +++--- mps/code/{chain.h => locus.h} | 12 ++++++------ mps/code/mpmst.h | 6 +++--- mps/code/mps.h | 6 +++--- mps/code/policy.c | 6 +++--- mps/code/poolamc.c | 6 +++--- mps/code/poolawl.c | 6 +++--- mps/code/segsmss.c | 6 +++--- mps/code/trace.c | 6 +++--- mps/manual/source/code-index.rst | 2 +- 10 files changed, 31 insertions(+), 31 deletions(-) rename mps/code/{chain.h => locus.h} (96%) diff --git a/mps/code/locus.c b/mps/code/locus.c index e17ec3137c1..cc367b15a6c 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -1,7 +1,7 @@ /* locus.c: LOCUS MANAGER * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * DESIGN * @@ -10,7 +10,7 @@ * collection strategy. */ -#include "chain.h" +#include "locus.h" #include "ring.h" #include "mpm.h" #include "mpstd.h" @@ -766,7 +766,7 @@ Bool LocusCheck(Arena arena) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/chain.h b/mps/code/locus.h similarity index 96% rename from mps/code/chain.h rename to mps/code/locus.h index 6dddf0f5e2f..d1d9716303e 100644 --- a/mps/code/chain.h +++ b/mps/code/locus.h @@ -1,11 +1,11 @@ -/* chain.h: GENERATION CHAINS +/* locus.h: GENERATION CHAINS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. */ -#ifndef chain_h -#define chain_h +#ifndef locus_h +#define locus_h #include "mpmtypes.h" #include "ring.h" @@ -108,12 +108,12 @@ extern void PoolGenAccountForSegSplit(PoolGen pgen); extern void PoolGenAccountForSegMerge(PoolGen pgen); extern Res PoolGenDescribe(PoolGen gen, mps_lib_FILE *stream, Count depth); -#endif /* chain_h */ +#endif /* locus_h */ /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 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 ec643313307..8b76dec162a 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -1,7 +1,7 @@ /* mpmst.h: MEMORY POOL MANAGER DATA STRUCTURES * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2001 Global Graphics Software. * * .design: This header file crosses module boundaries. The relevant @@ -26,7 +26,7 @@ #include "protocol.h" #include "ring.h" -#include "chain.h" +#include "locus.h" #include "splay.h" #include "meter.h" @@ -809,7 +809,7 @@ typedef struct AllocPatternStruct { /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mps.h b/mps/code/mps.h index 65ab6d6bbf3..05b2644ec8e 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -1,7 +1,7 @@ /* mps.h: RAVENBROOK MEMORY POOL SYSTEM C INTERFACE * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (c) 2002 Global Graphics Software. * * THIS HEADER IS NOT DOCUMENTATION. @@ -498,7 +498,7 @@ extern size_t mps_pool_free_size(mps_pool_t); /* Chains */ -/* .gen-param: This structure must match . */ +/* .gen-param: This structure must match . */ typedef struct mps_gen_param_s { size_t mps_capacity; double mps_mortality; @@ -867,7 +867,7 @@ extern mps_res_t _mps_fix2(mps_ss_t, mps_addr_t *); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/policy.c b/mps/code/policy.c index 541a29159f7..134b8236013 100644 --- a/mps/code/policy.c +++ b/mps/code/policy.c @@ -1,7 +1,7 @@ /* policy.c: POLICY DECISIONS * * $Id$ - * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 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. @@ -9,7 +9,7 @@ * .sources: . */ -#include "chain.h" +#include "locus.h" #include "mpm.h" SRCID(policy, "$Id$"); @@ -394,7 +394,7 @@ Bool PolicyPollAgain(Arena arena, Clock start, Size tracedSize) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2015 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 173d13f8954..7b625c4dac4 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -1,14 +1,14 @@ /* poolamc.c: AUTOMATIC MOSTLY-COPYING MEMORY POOL CLASS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * .sources: . */ #include "mpscamc.h" -#include "chain.h" +#include "locus.h" #include "bt.h" #include "mpm.h" #include "nailboard.h" @@ -2254,7 +2254,7 @@ static Bool AMCCheck(AMC amc) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 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 738194f26c8..6d7c4d6efb2 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-2015 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * * DESIGN @@ -41,7 +41,7 @@ #include "mpscawl.h" #include "mpm.h" -#include "chain.h" +#include "locus.h" SRCID(poolawl, "$Id$"); @@ -1374,7 +1374,7 @@ static Bool AWLCheck(AWL awl) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2015 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/segsmss.c b/mps/code/segsmss.c index a271a582f7c..73f3f79461b 100644 --- a/mps/code/segsmss.c +++ b/mps/code/segsmss.c @@ -1,7 +1,7 @@ /* segsmss.c: Segment splitting and merging stress test * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (c) 2002 Global Graphics Software. * * .design: Adapted from amsss.c (because AMS already supports @@ -17,7 +17,7 @@ #include "fmtdytst.h" #include "testlib.h" #include "mpslib.h" -#include "chain.h" +#include "locus.h" #include "mpscams.h" #include "mpsavm.h" #include "mpstd.h" @@ -885,7 +885,7 @@ int main(int argc, char *argv[]) /* C. COPYRIGHT AND LICENSE * - * Copyright (c) 2001-2014 Ravenbrook Limited . + * Copyright (c) 2001-2016 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 10592f7df2e..5ce3e3617ad 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1,13 +1,13 @@ /* trace.c: GENERIC TRACER IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2015 Ravenbrook Limited. + * Copyright (c) 2001-2016 Ravenbrook Limited. * See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * .design: . */ -#include "chain.h" +#include "locus.h" #include "mpm.h" #include /* for LONG_MAX */ @@ -1825,7 +1825,7 @@ Res TraceDescribe(Trace trace, mps_lib_FILE *stream, Count depth) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2015 Ravenbrook Limited + * Copyright (C) 2001-2016 Ravenbrook Limited * . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. diff --git a/mps/manual/source/code-index.rst b/mps/manual/source/code-index.rst index 2cfbbfd0f85..c38dff4a9cf 100644 --- a/mps/manual/source/code-index.rst +++ b/mps/manual/source/code-index.rst @@ -84,7 +84,6 @@ bt.h Bit table interface. See design.mps.bt_. buffer.c Buffer implementation. See design.mps.buffer_. cbs.c Coalescing block implementation. See design.mps.cbs_. cbs.h Coalescing block interface. See design.mps.cbs_. -chain.h Locus manager interface. See design.mps.locus_. check.h Assertion interface. See design.mps.check_. dbgpool.c :ref:`topic-debugging` implementation. dbgpool.h :ref:`topic-debugging` interface. @@ -102,6 +101,7 @@ global.c Global arena implementation. land.c Land implementation. See design.mps.land_. ld.c :ref:`topic-location` implementation. locus.c Locus manager implementation. See design.mps.locus_. +locus.h Locus manager interface. See design.mps.locus_. message.c :ref:`topic-message` implementation. meter.c Debugging accumulator implementation. meter.h Debugging accumulator interface. From 85bef47f05a9d19f8c8dfb6179d838b4494e831a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 6 Mar 2016 19:07:36 +0000 Subject: [PATCH 204/337] Add glossary entry for telemetry system. Copied from Perforce Change: 189685 ServerID: perforce.ravenbrook.com --- mps/manual/source/glossary/t.rst | 7 +++++++ mps/manual/source/topic/error.rst | 2 +- mps/manual/source/topic/telemetry.rst | 8 ++++---- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/mps/manual/source/glossary/t.rst b/mps/manual/source/glossary/t.rst index eabf6e530b0..1b4411a8e6c 100644 --- a/mps/manual/source/glossary/t.rst +++ b/mps/manual/source/glossary/t.rst @@ -123,6 +123,13 @@ Memory Management Glossary: T stream can be configured by setting the :term:`telemetry filter`. See :ref:`topic-telemetry`. + telemetry system + + .. mps:specific:: + + The subsystem of the MPS that outputs the :term:`telemetry + stream`. See :ref:`topic-telemetry`. + tenuring .. see:: :term:`promotion`. diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 7ae2900fed4..9afbb22ebe0 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -90,7 +90,7 @@ Result codes .. c:macro:: MPS_RES_IO A :term:`result code` indicating that an input/output error - occurred in the :term:`telemetry` system. + occurred in the :term:`telemetry system`. .. c:macro:: MPS_RES_LIMIT diff --git a/mps/manual/source/topic/telemetry.rst b/mps/manual/source/topic/telemetry.rst index acb680828f3..1cfc5476241 100644 --- a/mps/manual/source/topic/telemetry.rst +++ b/mps/manual/source/topic/telemetry.rst @@ -6,16 +6,16 @@ Telemetry ========= In its :term:`cool` and :term:`hot` :term:`varieties`, the MPS is -capable of outputting a configurable stream of events to assist with -debugging and profiling. +capable of outputting a configurable stream of events (the +:term:`telemetry stream`) to assist with debugging and profiling. The selection of events that appear in the stream is controlled by the environment variable :envvar:`MPS_TELEMETRY_CONTROL` (by default none), and the stream is written to the file named by the environment variable :envvar:`MPS_TELEMETRY_FILENAME` (by default ``mpsio.log``). -The telemetry system writes blocks of binary output, and is fast -enough to be left turned on in production code (the :term:`hot` +The :term:`telemetry system` writes blocks of binary output, and is +fast enough to be left turned on in production code (the :term:`hot` variety avoids emitting events on the :term:`critical path`), which can be useful for diagnosing memory management problems in production environments. From a86715c9f61d9570281ae6e7c2bb42b382260901 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 6 Mar 2016 19:27:48 +0000 Subject: [PATCH 205/337] Avoid warnings from sphinx 1.3.5. Copied from Perforce Change: 189686 ServerID: perforce.ravenbrook.com --- mps/manual/source/extensions/mps/designs.py | 2 ++ mps/manual/source/guide/build.rst | 2 ++ mps/manual/source/topic/porting.rst | 12 +++++++++--- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/mps/manual/source/extensions/mps/designs.py b/mps/manual/source/extensions/mps/designs.py index 42acd049d62..0bf5039f866 100644 --- a/mps/manual/source/extensions/mps/designs.py +++ b/mps/manual/source/extensions/mps/designs.py @@ -121,6 +121,8 @@ def convert_file(name, source, dest): s = design_ref.sub(r'\1.html', s) s = design_frag_ref.sub(r'\1.html#design.mps.\2.\3', s) s = history.sub('', s) + # Don't try to format all the quoted code blocks as C. + s = '.. highlight:: none\n\n' + s try: os.makedirs(os.path.dirname(dest)) except: diff --git a/mps/manual/source/guide/build.rst b/mps/manual/source/guide/build.rst index 2fe95eb888f..9c97e9a3bb3 100644 --- a/mps/manual/source/guide/build.rst +++ b/mps/manual/source/guide/build.rst @@ -1,3 +1,5 @@ +.. highlight:: none + .. index:: single: building single: compiling diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index 26c663f58f9..54d4b019acc 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -211,7 +211,9 @@ 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:: +For example, ``lii6ll.gmk`` looks like this: + +.. code-block:: make PFM = lii6ll @@ -245,7 +247,9 @@ On Windows, the makefile must be named ``osarct.nmk``, and must define platform modules (the same files included by ``mps.c``) in square brackets. Then it must include ``commpre.nmk``, the compiler-specific makefile and ``commpost.nmk``. For example, ``w3i6mv.nmk`` looks like -this:: +this: + +.. code-block:: none PFM = w3i6mv @@ -272,7 +276,9 @@ Porting strategy 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:: +Then check that the "smoke tests" pass, by running: + +.. code-block:: none make -f osarct.gmk testrun # Unix nmake /f osarct.nmk testrun # Windows From 57a29c80972274a7b9a4893e4b23f840d0f95167 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 6 Mar 2016 21:45:59 +0000 Subject: [PATCH 206/337] Design.mps.clock Copied from Perforce Change: 189692 ServerID: perforce.ravenbrook.com --- mps/code/clock.h | 6 +- mps/design/clock.txt | 133 ++++++++++++++++++++ mps/design/index.txt | 4 +- mps/manual/source/design/index.rst | 1 + mps/manual/source/extensions/mps/designs.py | 6 +- mps/manual/source/topic/porting.rst | 12 +- 6 files changed, 155 insertions(+), 7 deletions(-) create mode 100644 mps/design/clock.txt diff --git a/mps/code/clock.h b/mps/code/clock.h index 3bf2a6deed1..ec8ccc2bb80 100644 --- a/mps/code/clock.h +++ b/mps/code/clock.h @@ -1,7 +1,9 @@ /* clock.h -- Fast clocks and timers * - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * $Id$ + * + * .design: . */ #ifndef clock_h @@ -176,7 +178,7 @@ typedef mps_clock_t EventClock; /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/design/clock.txt b/mps/design/clock.txt new file mode 100644 index 00000000000..9cb4c683049 --- /dev/null +++ b/mps/design/clock.txt @@ -0,0 +1,133 @@ +.. mode: -*- rst -*- + +Fast high-resolution clock +========================== + +:Tag: design.mps.clock +:Author: Gareth Rees +:Date: 2016-03-06 +:Status: complete design +:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/abq.txt#5 $ +:Copyright: See section `Copyright and License`_. +:Index terms: pair: clock; design + + +Introduction +------------ + +_`.intro`: This is the design of the clock module, which implements a +fast high-resolution clock for use by the telemetry system. + +_`.readership`: This document is intended for any MPS developer. + + +Requirements +------------ + +_`.req.monotonic`: Successive calls to ``EVENT_CLOCK()`` must yield +values that are monotonically increasing. (So that comparing the +timestamp on two events never gives false positives.) + +_`.req.fast`: ``EVENT_CLOCK()`` should take very little time; it +should not require a system call. (So that programs that use the MPS +remain usable when telemetry is turned on.) + +_`.req.high-resolution`: Successive calls to ``EVENT_CLOCK()`` should +yield values that are strictly monotonically increasing (so that +sorting the telemetry stream puts the events in the order they +happened). + + +Interface +--------- + +``EventClock`` + +_`.if.type`: The type of timestamps. It must be an unsigned 64-bit +integral type, for example a ``typedef`` for ``uint64_t`` or +``unsigned __int64``. + +``EVENT_CLOCK_MAKE(lvalue, low, high)`` + +_`.if.make`: Construct an ``EventClock`` timestamp from its two +halves. The first parameter is an lvalue with type ``EventClock``, and +the second and third parameters are 32-bit unsigned integers. The +macro must assign a timestamp to ``lvalue`` with the value ``(high +<< 32) + low``. + +``EVENT_CLOCK(lvalue)`` + +_`.if.get`: Assign an ``EventClock`` timestamp for the current time to +``lvalue``, which is an lvalue with type ``EventClock``. + +``EVENT_CLOCK_PRINT(FILE *stream, EventClock clock)`` + +_`.if.print`: Write the value of ``clock`` to the standard C output +file handle ``stream`` as 16 hexadecimal digits (with leading zeros, +and capital letters A to F). + +``EVENT_CLOCK_WRITE(mps_lib_FILE *stream, EventClock clock)`` + +_`.if.write`: Write the value of ``clock`` to the output stream +``stream`` as 16 hexadecimal digits (with leading zeros, and capital +letters A to F). The macro should be implemented using ``WriteF()``. + + +Implementation +-------------- + +_`.impl.tsc`: On IA-32 and x86-64, the `Time Stamp Counter +`_ returned by the +RDTSC instruction is a suitable clock for single-core CPUs, but on +multiple-core CPUs, different cores may have different values or tick at different speeds, and so it may fail to meet `.req.monotonic`_. + + +Document History +---------------- + +- 2016-03-06 GDR_ Created. + +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 2016 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 7e48b625319..9e0a1090cda 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -50,6 +50,7 @@ buffer_ Allocation buffers and allocation points cbs_ Coalescing block structures check_ Checking class-interface_ Pool class interface +clock_ Fast high-resolution clock collection_ Collection framework config_ MPS configuration critical-path_ The critical path through the MPS @@ -128,6 +129,7 @@ writef_ The WriteF function .. _buffer: buffer .. _cbs: cbs .. _check: check +.. _clock: clock .. _class-interface: class-interface .. _collection: collection .. _config: config @@ -237,7 +239,7 @@ Document History Copyright and License --------------------- -Copyright © 2002-2015 Ravenbrook Limited. All rights reserved. +Copyright © 2002-2016 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index b8da67a4333..1cea6c4861b 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -10,6 +10,7 @@ Design an bootstrap cbs + clock config critical-path exec-env diff --git a/mps/manual/source/extensions/mps/designs.py b/mps/manual/source/extensions/mps/designs.py index 0bf5039f866..ff991612fc5 100644 --- a/mps/manual/source/extensions/mps/designs.py +++ b/mps/manual/source/extensions/mps/designs.py @@ -20,9 +20,9 @@ AccessSet Accumulation Addr Align AllocFrame AllocPattern AP Arg Arena Attr Bool BootBlock BT Buffer BufferMode Byte Chain Chunk - Clock Compare Count Epoch FindDelete Format FrameState Fun GenDesc - Globals Index Land LD Lock LocusPref LocusPrefKind Message - MessageType MutatorFaultContext Page Pointer Pool PoolGen + Clock Compare Count Epoch EventClock FindDelete Format FrameState + Fun GenDesc Globals Index Land LD Lock LocusPref LocusPrefKind + Message MessageType MutatorFaultContext Page Pointer Pool PoolGen PThreadext Range Rank RankSet ReadonlyAddr Ref RefSet Res Reservoir Ring Root RootMode RootVar ScanState Seg SegBuf Serial Shift Sig Size Space SplayNode SplayTree StackContext Thread Trace diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index 54d4b019acc..0d04c04f3a4 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -31,6 +31,17 @@ partially functional or non-functional, but can be used as a starting point for a new port if none of the existing implementations is usable. +#. The **clock** module provides fast high-resolution clocks for use + by the :term:`telemetry system`. + + See :ref:`design-clock` for the design, and ``clock.h`` for the + interface. The interface consists only of type declarations and + macro definitions, so there is no implementation. + + The header falls back to the clock functions from the + :term:`plinth` if there is no platform-specific interface. See + :c:func:`mps_clock` and :c:func:`mps_clocks_per_sec`. + #. The **lock** module provides binary locks that ensure that only a single :term:`thread` may be running with a lock held, and recursive locks, where the same thread may safely take the lock @@ -270,7 +281,6 @@ this: !INCLUDE commpost.nmk - Porting strategy ---------------- From 2bc2b0b4d595c36a1321370592f4eeff171ca703 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 6 Mar 2016 21:58:06 +0000 Subject: [PATCH 207/337] Add index entries for all the design documents. Copied from Perforce Change: 189693 ServerID: perforce.ravenbrook.com --- mps/design/abq.txt | 3 ++- mps/design/bootstrap.txt | 2 +- mps/design/cbs.txt | 3 ++- mps/design/failover.txt | 3 ++- mps/design/land.txt | 3 ++- mps/design/poolmv.txt | 5 ++++- mps/design/poolmvt.txt | 5 ++++- mps/design/strategy.txt | 3 ++- mps/design/tests.txt | 3 ++- 9 files changed, 21 insertions(+), 9 deletions(-) diff --git a/mps/design/abq.txt b/mps/design/abq.txt index ec3c944355c..e3bd56a9bc8 100644 --- a/mps/design/abq.txt +++ b/mps/design/abq.txt @@ -9,6 +9,7 @@ Fixed-length queues :Status: complete design :Revision: $Id$ :Copyright: See section `Copyright and License`_. +:Index terms: pair: fixed-length queues; design Introduction @@ -119,7 +120,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2013-2016 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/bootstrap.txt b/mps/design/bootstrap.txt index 8615aee0f99..3a8dd8fde64 100644 --- a/mps/design/bootstrap.txt +++ b/mps/design/bootstrap.txt @@ -9,7 +9,7 @@ Bootstrapping :Status: incomplete design :Revision: $Id$ :Copyright: See section `Copyright and License`_. -:Index terms: pair: bootsrap; design +:Index terms: pair: bootstrap; design Introduction diff --git a/mps/design/cbs.txt b/mps/design/cbs.txt index 34c2eedd4cd..f004eedd90a 100644 --- a/mps/design/cbs.txt +++ b/mps/design/cbs.txt @@ -9,6 +9,7 @@ Coalescing block structures :Status: complete design :Revision: $Id$ :Copyright: See section `Copyright and License`_. +:Index terms: pair: coalescing block structures; design Introduction @@ -281,7 +282,7 @@ Document History Copyright and License --------------------- -Copyright © 1998-2014 Ravenbrook Limited. All rights reserved. +Copyright © 1998-2016 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/failover.txt b/mps/design/failover.txt index 1787da261a9..cdb7cf3a613 100644 --- a/mps/design/failover.txt +++ b/mps/design/failover.txt @@ -9,6 +9,7 @@ Fail-over allocator :Status: complete design :Revision: $Id$ :Copyright: See section `Copyright and License`_. +:Index terms: pair: fail-over allocator; design Introduction @@ -110,7 +111,7 @@ Document History Copyright and License --------------------- -Copyright © 2014 Ravenbrook Limited. All rights reserved. +Copyright © 2014-2016 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/land.txt b/mps/design/land.txt index df16fc922b9..15c1454882d 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -9,6 +9,7 @@ Lands :Status: complete design :Revision: $Id$ :Copyright: See section `Copyright and License`_. +:Index terms: pair: lands; design Introduction @@ -321,7 +322,7 @@ Document History Copyright and License --------------------- -Copyright © 2014-2015 Ravenbrook Limited. All rights reserved. +Copyright © 2014-2016 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/poolmv.txt b/mps/design/poolmv.txt index 628489b9cb0..1b25c441a27 100644 --- a/mps/design/poolmv.txt +++ b/mps/design/poolmv.txt @@ -9,6 +9,9 @@ MV pool class :Status: incomplete design :Revision: $Id$ :Copyright: See `Copyright and License`_. +:Index terms: + pair: MV pool class; design + single: pool class; MV design Implementation @@ -44,7 +47,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2013-2016 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/poolmvt.txt b/mps/design/poolmvt.txt index 73f289017b7..59939535604 100644 --- a/mps/design/poolmvt.txt +++ b/mps/design/poolmvt.txt @@ -10,6 +10,9 @@ Manual Variable Temporal (MVT) pool design :Status: incomplete design :Revision: $Id$ :Copyright: See section `C. Copyright and License`_. +:Index terms: + pair: MVT pool class; design + single: pool class; MVT design Introduction @@ -1021,7 +1024,7 @@ B. Document History C. Copyright and License ------------------------ -Copyright (C) 2002-2014 Ravenbrook Limited. All rights reserved. +Copyright (C) 2002-2016 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/strategy.txt b/mps/design/strategy.txt index 695813bed87..6e0472b04f5 100644 --- a/mps/design/strategy.txt +++ b/mps/design/strategy.txt @@ -9,6 +9,7 @@ MPS Strategy :Date: 2013-06-04 :Revision: $Id$ :Copyright: See section `Copyright and License`_. +:Index terms: pair: strategy; design Introduction @@ -555,7 +556,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2013-2016 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/tests.txt b/mps/design/tests.txt index f7cfb17a431..e1e9eb51e83 100644 --- a/mps/design/tests.txt +++ b/mps/design/tests.txt @@ -9,6 +9,7 @@ Tests :Status: incomplete design :Revision: $Id$ :Copyright: See `Copyright and License`_. +:Index terms: pair: tests; design Introduction @@ -75,7 +76,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2013-2016 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. From ef04eb17d124c1740c6578c4b93ee15ce0d9eaa2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 6 Mar 2016 22:19:00 +0000 Subject: [PATCH 208/337] Use https for wikipedia links. Copied from Perforce Change: 189697 ServerID: perforce.ravenbrook.com --- mps/design/config.txt | 4 ++-- mps/design/sig.txt | 4 ++-- mps/manual/source/glossary/c.rst | 2 +- mps/manual/source/mmref/credit.rst | 2 +- mps/manual/source/mmref/lang.rst | 4 ++-- mps/manual/source/topic/telemetry.rst | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mps/design/config.txt b/mps/design/config.txt index eff74388489..9d49a5889ce 100644 --- a/mps/design/config.txt +++ b/mps/design/config.txt @@ -75,7 +75,7 @@ _`.def.platform`: A *platform* is a combination of an architecture _`.def.arch`: An *architecture* is processor type with associated calling conventions and other binary interface stuff these days often called the -`ABI `_. +`ABI `_. Most importantly for the MPS it determines the layout of the register file, thread context, and thread stack. @@ -610,7 +610,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2013-2016 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/sig.txt b/mps/design/sig.txt index 992d0ba52d9..23f55a881a1 100644 --- a/mps/design/sig.txt +++ b/mps/design/sig.txt @@ -34,7 +34,7 @@ checking and dynamic scope checking. They are a simplified form of "Structure Marking", a technique used in the Multics filesystem [THVV_1995]_. -.. _`magic numbers`: http://en.wikipedia.org/wiki/Magic_number_(programming) +.. _`magic numbers`: https://en.wikipedia.org/wiki/Magic_number_(programming) Definitions @@ -177,7 +177,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2013-2016 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/manual/source/glossary/c.rst b/mps/manual/source/glossary/c.rst index 6fe83e370d0..2165bac2394 100644 --- a/mps/manual/source/glossary/c.rst +++ b/mps/manual/source/glossary/c.rst @@ -131,7 +131,7 @@ Memory Management Glossary: C A cactus stack is a :term:`stack` with branches. When diagrammed, its shape resembles that of a `saguaro cactus - `_. + `_. In languages that support :term:`continuations`, :term:`activation records` can have :term:`indefinite extent`. diff --git a/mps/manual/source/mmref/credit.rst b/mps/manual/source/mmref/credit.rst index 0ce0bd0c8b3..e6298f9b841 100644 --- a/mps/manual/source/mmref/credit.rst +++ b/mps/manual/source/mmref/credit.rst @@ -9,7 +9,7 @@ The Memory Management Reference is maintained by `Ravenbrook Limited`_. Most of it was originally written by memory management experts in the Adaptive Memory Management Group at `Harlequin Limited -`_: +`_: * Nick Barnes * Richard Brooksby diff --git a/mps/manual/source/mmref/lang.rst b/mps/manual/source/mmref/lang.rst index 569a5bae4e2..7462f89742b 100644 --- a/mps/manual/source/mmref/lang.rst +++ b/mps/manual/source/mmref/lang.rst @@ -233,7 +233,7 @@ Memory management in various languages Dylan is a modern programming language invented by Apple around 1993 and developed by `Harlequin - `_ + `_ and other partners. The language is a distillation of the best ideas in dynamic and object-oriented programming. Its ancestors include :term:`Lisp`, :term:`Smalltalk`, and @@ -583,7 +583,7 @@ Memory management in various languages .. link:: - `Harlequin RIP `_. + `Harlequin RIP `_. Prolog diff --git a/mps/manual/source/topic/telemetry.rst b/mps/manual/source/topic/telemetry.rst index 1cfc5476241..5ee6bb000e1 100644 --- a/mps/manual/source/topic/telemetry.rst +++ b/mps/manual/source/topic/telemetry.rst @@ -122,7 +122,7 @@ second column, and then addresses or other data related to the event in the remaining columns. The source of the timestamp depends on the platform; it may be a low-cost high-resolution processor timer, such as the `Time Stamp Counter -`_ on IA-32 and +`_ on IA-32 and x86-64, if one is available. All numbers are given in hexadecimal. :: 000AE03973336E3C 002B VMCreate vm:00000001003FC000 base:00000001003FD000 limit:00000001003FE000 From 3e9ddfeabc041ce673b9581bbf9094f9ab888c87 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 7 Mar 2016 15:26:57 +0000 Subject: [PATCH 209/337] Check root mode argument to root creation functions. Copied from Perforce Change: 189708 ServerID: perforce.ravenbrook.com --- mps/code/root.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mps/code/root.c b/mps/code/root.c index e4c8b3f81ab..63445f0ef21 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -1,7 +1,7 @@ /* root.c: ROOT IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * .purpose: This is the implementation of the root datatype. * @@ -181,6 +181,7 @@ static Res rootCreate(Root *rootReturn, Arena arena, AVER(rootReturn != NULL); AVERT(Arena, arena); AVERT(Rank, rank); + AVERT(RootMode, mode); AVERT(RootVar, type); globals = ArenaGlobals(arena); @@ -278,6 +279,7 @@ Res RootCreateArea(Root *rootReturn, Arena arena, AVER(rootReturn != NULL); AVERT(Arena, arena); AVERT(Rank, rank); + AVERT(RootMode, mode); AVER(base != 0); AVER(AddrIsAligned(base, sizeof(Word))); AVER(base < limit); @@ -304,6 +306,7 @@ Res RootCreateAreaTagged(Root *rootReturn, Arena arena, AVER(rootReturn != NULL); AVERT(Arena, arena); AVERT(Rank, rank); + AVERT(RootMode, mode); AVER(base != 0); AVER(base < limit); /* Can't check anything about mask or pattern, as they could mean @@ -387,6 +390,7 @@ Res RootCreateFmt(Root *rootReturn, Arena arena, AVER(rootReturn != NULL); AVERT(Arena, arena); AVERT(Rank, rank); + AVERT(RootMode, mode); AVER(FUNCHECK(scan)); AVER(base != 0); AVER(base < limit); @@ -793,7 +797,7 @@ Res RootsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2015 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From df50cf79cebc6621f03ea92b3bc8fbef49d95869 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 7 Mar 2016 17:18:21 +0000 Subject: [PATCH 210/337] Some mmqa tests only work in the cool variety. segregate these into the "coolonly" testset. Copied from Perforce Change: 189711 ServerID: perforce.ravenbrook.com --- mps/code/comm.gmk | 1 + mps/test/testsets/argerr | 42 +++++++++++++++++++++----------------- mps/test/testsets/conerr | 10 ++++++--- mps/test/testsets/coolonly | 34 ++++++++++++++++++++++++++++++ mps/test/testsets/passing | 7 ++++--- 5 files changed, 69 insertions(+), 25 deletions(-) create mode 100644 mps/test/testsets/coolonly diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index 0ac2c94256f..e5af99266ae 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -327,6 +327,7 @@ MMQA=perl test/qa -i ../code -l ../code/$(PFM)/$(VARIETY)/mps.o $(PFM)/$(VARIETY)/testmmqa: $(MAKE) -f $(PFM).gmk VARIETY=$(VARIETY) TARGET=mps.o variety + (if [ "$(VARIETY)" = "cool" ]; then cd ../test && $(MMQA) runset testsets/coolonly; fi) (cd ../test && $(MMQA) runset testsets/argerr) (cd ../test && $(MMQA) runset testsets/conerr) (cd ../test && $(MMQA) runset testsets/passing) diff --git a/mps/test/testsets/argerr b/mps/test/testsets/argerr index 990040192b4..8c587bae4f7 100644 --- a/mps/test/testsets/argerr +++ b/mps/test/testsets/argerr @@ -1,3 +1,7 @@ +% This testset contains all the "argerr" test cases that pass in +% both the cool and hot varieties, together with comments explaining +% why the other test cases fail. + argerr/0.c argerr/1.c argerr/2.c @@ -14,7 +18,7 @@ argerr/12.c argerr/13.c argerr/14.c argerr/15.c -argerr/16.c +% argerr/16.c -- assertion in different place in the hot variety argerr/17.c argerr/18.c argerr/19.c @@ -47,9 +51,9 @@ argerr/45.c argerr/46.c argerr/47.c argerr/48.c -argerr/49.c -argerr/50.c -argerr/51.c +% argerr/49.c -- AVERT(Rank) does nothing in hot variety +% argerr/50.c -- AVERT(Rank) does nothing in hot variety +% argerr/51.c -- AVERT(Rank) does nothing in hot variety argerr/52.c argerr/53.c argerr/54.c @@ -92,9 +96,9 @@ argerr/90.c argerr/91.c argerr/92.c argerr/93.c -argerr/94.c -argerr/95.c -argerr/96.c +% argerr/94.c -- AVERT(Rank) does nothing in hot variety +% argerr/95.c -- AVERT(Rank) does nothing in hot variety +% argerr/96.c -- AVERT(Rank) does nothing in hot variety argerr/97.c argerr/98.c argerr/99.c @@ -102,12 +106,12 @@ argerr/100.c argerr/101.c argerr/102.c argerr/103.c -argerr/104.c -argerr/105.c -argerr/106.c -argerr/107.c -argerr/108.c -argerr/109.c +% argerr/104.c -- AVERT(Rank) does nothing in hot variety +% argerr/105.c -- AVERT(Rank) does nothing in hot variety +% argerr/106.c -- AVERT(Rank) does nothing in hot variety +% argerr/107.c -- AVERT(RootMode) does nothing in hot variety +% argerr/108.c -- AVERT(RootMode) does nothing in hot variety +% argerr/109.c -- AVERT(RootMode) does nothing in hot variety argerr/110.c argerr/111.c argerr/112.c @@ -117,12 +121,12 @@ argerr/115.c argerr/116.c argerr/117.c argerr/118.c -argerr/119.c -argerr/120.c -argerr/121.c -argerr/122.c -argerr/123.c -argerr/124.c +% argerr/119.c -- AVERT(Rank) does nothing in hot variety +% argerr/120.c -- AVERT(Rank) does nothing in hot variety +% argerr/121.c -- AVERT(Rank) does nothing in hot variety +% argerr/122.c -- AVERT(RootMode) does nothing in hot variety +% argerr/123.c -- AVERT(RootMode) does nothing in hot variety +% argerr/124.c -- AVERT(RootMode) does nothing in hot variety argerr/125.c % argerr/126.c -- see argerr/127.c diff --git a/mps/test/testsets/conerr b/mps/test/testsets/conerr index 12966b681a0..1bf93cd0712 100644 --- a/mps/test/testsets/conerr +++ b/mps/test/testsets/conerr @@ -1,3 +1,7 @@ +% This testset contains all the "argerr" test cases that pass in +% both the cool and hot varieties, together with comments explaining +% why the other test cases fail. + conerr/0.c conerr/1.c conerr/2.c @@ -15,13 +19,13 @@ conerr/13.c conerr/14.c conerr/15.c conerr/16.c -conerr/17.c +% conerr/17.c -- fails in hot variety (assertion is on the critical path) conerr/18.c conerr/19.c conerr/20.c conerr/21.c -conerr/22.c -conerr/23.c +% conerr/22.c -- segfaults in hot variety (assertion is on the critical path) +% conerr/23.c -- segfaults in hot variety (assertion is on the critical path) conerr/24.c conerr/25.c conerr/26.c diff --git a/mps/test/testsets/coolonly b/mps/test/testsets/coolonly new file mode 100644 index 00000000000..3125dcbedb5 --- /dev/null +++ b/mps/test/testsets/coolonly @@ -0,0 +1,34 @@ +% This testset contains all the test cases that pass only in the cool +% variety, together with comments explaining why they fail in the hot +% variety. + +% Assertion in different place in the hot variety. +argerr/16.c + +% Rank is not a structure type, so AVERT(Rank) does nothing. +argerr/49.c +argerr/50.c +argerr/51.c +argerr/94.c +argerr/95.c +argerr/96.c +argerr/104.c +argerr/105.c +argerr/106.c +argerr/119.c +argerr/120.c +argerr/121.c + +% RootMode is not a structure type, so AVERT(Rootmode) does nothing. +argerr/107.c +argerr/108.c +argerr/109.c +argerr/122.c +argerr/123.c +argerr/124.c + +% Assertion is on the critical path. +conerr/17.c +conerr/22.c +conerr/23.c +function/72.c diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index c6893a54c30..85f880b07ce 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -1,5 +1,6 @@ -% Test status on OS X -% $Id$ +% This testset contains all the "function" test cases that pass in +% both the cool and hot varieties, together with comments explaining +% why the other test cases fail. function/0.c function/1.c @@ -72,7 +73,7 @@ function/67.c function/69.c function/70.c function/71.c -function/72.c +% function/72.c -- fails in hot variety (assertion is on the critical path) function/73.c function/74.c function/75.c From 8afda3c709033e539159590ff337f7c4028effab Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 7 Mar 2016 17:31:55 +0000 Subject: [PATCH 211/337] Move blatting to a function so that its local variables don't remain on the stack and pin down objects. Copied from Perforce Change: 189714 ServerID: perforce.ravenbrook.com --- mps/test/function/226.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/mps/test/function/226.c b/mps/test/function/226.c index 28b2a606ec0..185a4b97298 100644 --- a/mps/test/function/226.c +++ b/mps/test/function/226.c @@ -58,6 +58,18 @@ static void mergelds(int merge) { } } +static void blat(mps_ap_t apamc, int percent) { + int i; + for (i=0; i < MAXLDS; i++) { + if (ranint(100) < percent) { + obj_table[i] = allocone(apamc, ranint(1000), mps_rank_exact()); + mps_ld_reset(lds[i], arena); + mps_ld_add(lds[i], arena, (mps_addr_t) obj_table[i]); + addr_table[i] = obj_table[i]; + } + } +} + static void test(void) { mps_pool_t poolmv, poolawl, poolamc; mps_thr_t thread; @@ -129,25 +141,12 @@ static void test(void) { ldm[i] = (mps_ld_t) p; } - for (i=0; i < MAXLDS; i++) { - obj_table[i] = allocone(apamc, ranint(1000), mps_rank_exact()); - mps_ld_reset(lds[i], arena); - mps_ld_add(lds[i], arena, (mps_addr_t) obj_table[i]); - addr_table[i] = obj_table[i]; - } + blat(apamc, 100); for (merge = 1; merge <= MAXMERGE; merge++) { comment("Merge %d", merge); - for (i=0; i < MAXLDS; i++) { - if (ranint(100) < BLATPERCENT) { - obj_table[i] = allocone(apamc, ranint(1000), mps_rank_exact()); - mps_ld_reset(lds[i], arena); - mps_ld_add(lds[i], arena, (mps_addr_t) obj_table[i]); - addr_table[i] = obj_table[i]; - } - } - + blat(apamc, BLATPERCENT); mergelds(merge); stale = 0; From d1973da5f3e4aa2baa985b2b8030db418a970e9d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 7 Mar 2016 18:47:27 +0000 Subject: [PATCH 212/337] Avoid unusued variable warnings from clang 3.4.1. Copied from Perforce Change: 189717 ServerID: perforce.ravenbrook.com --- mps/test/conerr/15.c | 7 ------- mps/test/conerr/19.c | 7 ------- mps/test/conerr/25.c | 2 +- mps/test/conerr/43.c | 1 - mps/test/conerr/5.c | 1 - 5 files changed, 1 insertion(+), 17 deletions(-) diff --git a/mps/test/conerr/15.c b/mps/test/conerr/15.c index c4114d5b995..4bd52651fa3 100644 --- a/mps/test/conerr/15.c +++ b/mps/test/conerr/15.c @@ -16,13 +16,6 @@ static void test(void) { mps_arena_t arena; mps_pool_t pool = (mps_pool_t)1; - size_t extendBy; - size_t avgSize; - size_t maxSize; - - extendBy = (size_t) 4096; - avgSize = (size_t) 32; - maxSize = (size_t) 65536; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); diff --git a/mps/test/conerr/19.c b/mps/test/conerr/19.c index 3c8211c23dd..430d013c7f9 100644 --- a/mps/test/conerr/19.c +++ b/mps/test/conerr/19.c @@ -16,16 +16,9 @@ static void test(void) { mps_arena_t arena; mps_pool_t pool = (mps_pool_t)1; - size_t extendBy; - size_t avgSize; - size_t maxSize; mps_addr_t obj; - extendBy = (size_t) 4096; - avgSize = (size_t) 32; - maxSize = (size_t) 65536; - cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); /* diff --git a/mps/test/conerr/25.c b/mps/test/conerr/25.c index 480b382b8f4..35e4c5c03c7 100644 --- a/mps/test/conerr/25.c +++ b/mps/test/conerr/25.c @@ -31,7 +31,7 @@ static void test(void) cdie(mps_ap_create(&ap, pool), "create ap"); cdie(mps_reserve(&obj, ap, 152), "reserve"); - mps_commit(ap, &obj, 152); + (void)mps_commit(ap, &obj, 152); mps_free(pool, obj, 152); comment("Freed."); diff --git a/mps/test/conerr/43.c b/mps/test/conerr/43.c index 1532e2f9a88..ce29bc3cb69 100644 --- a/mps/test/conerr/43.c +++ b/mps/test/conerr/43.c @@ -19,7 +19,6 @@ static void test(void) { mps_arena_t arena; mps_root_t root = (mps_root_t)1; - mps_addr_t roottable[10]; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); diff --git a/mps/test/conerr/5.c b/mps/test/conerr/5.c index 09a1893f31d..f6559c4824e 100644 --- a/mps/test/conerr/5.c +++ b/mps/test/conerr/5.c @@ -18,7 +18,6 @@ static void test(void) { mps_arena_t arena; mps_fmt_t format; - mps_fmt_A_s fmtA; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); From 9ffa6f2740e0f8eff649acf2a692ed41586f9b72 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 7 Mar 2016 19:58:52 +0000 Subject: [PATCH 213/337] Add instructions for testing the hot variety. Copied from Perforce Change: 189720 ServerID: perforce.ravenbrook.com --- mps/test/README | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mps/test/README b/mps/test/README index 90edaf8857f..717f17601d7 100644 --- a/mps/test/README +++ b/mps/test/README @@ -6,15 +6,16 @@ to see what version of the harness you have (or look at the file "test/version"). -Testing on unix +Testing on Unix --------------- From the test directory:: PLATFORM=lii6ll # substitute your platform + VARIETY=cool # or hot 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" + make -B -C $CODE -f $PLATFORM.gmk VARIETY=$VARIETY $PLATFORM/$VARIETY/mps.o + alias qa="perl test/qa -i $CODE -l $CODE/$PLATFORM/$VARIETY/mps.o" qa clib qa run function/5.c qa runset testsets/passing From cc2c7db8ff4be5eeef659c4415b103742f51b5d0 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 8 Mar 2016 08:32:27 +0000 Subject: [PATCH 214/337] Bringing xcode project up to date with filename changes. Copied from Perforce Change: 189724 ServerID: perforce.ravenbrook.com --- mps/code/mps.xcodeproj/project.pbxproj | 142 +++++++++++++++++++++++-- 1 file changed, 134 insertions(+), 8 deletions(-) diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index 0a268989292..e36b800455b 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -1569,7 +1569,6 @@ 31160DB61899540D0071EB17 /* poolmvff.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = poolmvff.txt; path = ../design/poolmvff.txt; sourceTree = ""; }; 31160DB71899540D0071EB17 /* poolmvt.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = poolmvt.txt; path = ../design/poolmvt.txt; sourceTree = ""; }; 31160DB81899540D0071EB17 /* prot.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = prot.txt; path = ../design/prot.txt; sourceTree = ""; }; - 31160DB91899540D0071EB17 /* protan.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = protan.txt; path = ../design/protan.txt; sourceTree = ""; }; 31160DBA1899540D0071EB17 /* protli.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = protli.txt; path = ../design/protli.txt; sourceTree = ""; }; 31160DBB1899540D0071EB17 /* protocol.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = protocol.txt; path = ../design/protocol.txt; sourceTree = ""; }; 31160DBC1899540D0071EB17 /* protsu.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = protsu.txt; path = ../design/protsu.txt; sourceTree = ""; }; @@ -1594,7 +1593,6 @@ 31160DCF1899540D0071EB17 /* version-library.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "version-library.txt"; path = "../design/version-library.txt"; sourceTree = ""; }; 31160DD01899540D0071EB17 /* version.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = version.txt; path = ../design/version.txt; sourceTree = ""; }; 31160DD11899540D0071EB17 /* vm.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = vm.txt; path = ../design/vm.txt; sourceTree = ""; }; - 31160DD21899540D0071EB17 /* vman.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = vman.txt; path = ../design/vman.txt; sourceTree = ""; }; 31160DD31899540D0071EB17 /* vmo1.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = vmo1.txt; path = ../design/vmo1.txt; sourceTree = ""; }; 31160DD41899540D0071EB17 /* vmso.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = vmso.txt; path = ../design/vmso.txt; sourceTree = ""; }; 31160DD51899540D0071EB17 /* writef.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = writef.txt; path = ../design/writef.txt; sourceTree = ""; }; @@ -1606,7 +1604,6 @@ 311F2F5017398AD500C15B6A /* boot.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = boot.h; sourceTree = ""; }; 311F2F5117398AE900C15B6A /* bt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bt.h; sourceTree = ""; }; 311F2F5217398AE900C15B6A /* cbs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cbs.h; sourceTree = ""; }; - 311F2F5317398AE900C15B6A /* chain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = chain.h; sourceTree = ""; }; 311F2F5417398AE900C15B6A /* check.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = check.h; sourceTree = ""; }; 311F2F5517398AE900C15B6A /* clock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = clock.h; sourceTree = ""; }; 311F2F5617398AE900C15B6A /* config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; @@ -1615,7 +1612,6 @@ 311F2F5917398AE900C15B6A /* eventcom.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eventcom.h; sourceTree = ""; }; 311F2F5A17398AE900C15B6A /* eventdef.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eventdef.h; sourceTree = ""; }; 311F2F5C17398AE900C15B6A /* eventrep.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eventrep.h; sourceTree = ""; }; - 311F2F5D17398B0400C15B6A /* lo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lo.h; sourceTree = ""; }; 311F2F5E17398B0E00C15B6A /* lock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lock.h; sourceTree = ""; }; 311F2F5F17398B0E00C15B6A /* meter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = meter.h; sourceTree = ""; }; 311F2F6017398B0E00C15B6A /* misc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = misc.h; sourceTree = ""; }; @@ -1663,6 +1659,56 @@ 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 = ""; }; + 31942A671C8EC3FC001AAF32 /* locus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = locus.h; sourceTree = ""; }; + 31942A681C8EC445001AAF32 /* abq.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = abq.txt; path = ../design/abq.txt; sourceTree = ""; }; + 31942A6A1C8EC445001AAF32 /* an.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = an.txt; path = ../design/an.txt; sourceTree = ""; }; + 31942A6B1C8EC445001AAF32 /* arena.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = arena.txt; path = ../design/arena.txt; sourceTree = ""; }; + 31942A6D1C8EC445001AAF32 /* boot.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = boot.txt; path = ../design/boot.txt; sourceTree = ""; }; + 31942A6E1C8EC445001AAF32 /* bootstrap.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = bootstrap.txt; path = ../design/bootstrap.txt; sourceTree = ""; }; + 31942A6F1C8EC445001AAF32 /* bt.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = bt.txt; path = ../design/bt.txt; sourceTree = ""; }; + 31942A711C8EC445001AAF32 /* cbs.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = cbs.txt; path = ../design/cbs.txt; sourceTree = ""; }; + 31942A731C8EC445001AAF32 /* class-interface.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "class-interface.txt"; path = "../design/class-interface.txt"; sourceTree = ""; }; + 31942A741C8EC445001AAF32 /* clock.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = clock.txt; path = ../design/clock.txt; sourceTree = ""; }; + 31942A761C8EC445001AAF32 /* config.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = config.txt; path = ../design/config.txt; sourceTree = ""; }; + 31942A781C8EC445001AAF32 /* diag.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = diag.txt; path = ../design/diag.txt; sourceTree = ""; }; + 31942A791C8EC445001AAF32 /* exec-env.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "exec-env.txt"; path = "../design/exec-env.txt"; sourceTree = ""; }; + 31942A7B1C8EC445001AAF32 /* finalize.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = finalize.txt; path = ../design/finalize.txt; sourceTree = ""; }; + 31942A7D1C8EC445001AAF32 /* freelist.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = freelist.txt; path = ../design/freelist.txt; sourceTree = ""; }; + 31942A7F1C8EC445001AAF32 /* guide.impl.c.format.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = guide.impl.c.format.txt; path = ../design/guide.impl.c.format.txt; sourceTree = ""; }; + 31942A801C8EC445001AAF32 /* guide.impl.c.naming.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = guide.impl.c.naming.txt; path = ../design/guide.impl.c.naming.txt; sourceTree = ""; }; + 31942A811C8EC445001AAF32 /* guide.review.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = guide.review.txt; path = ../design/guide.review.txt; sourceTree = ""; }; + 31942A831C8EC445001AAF32 /* interface-c.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "interface-c.txt"; path = "../design/interface-c.txt"; sourceTree = ""; }; + 31942A851C8EC445001AAF32 /* keyword-arguments.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "keyword-arguments.txt"; path = "../design/keyword-arguments.txt"; sourceTree = ""; }; + 31942A871C8EC445001AAF32 /* lib.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = lib.txt; path = ../design/lib.txt; sourceTree = ""; }; + 31942A891C8EC445001AAF32 /* locus.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = locus.txt; path = ../design/locus.txt; sourceTree = ""; }; + 31942A8B1C8EC446001AAF32 /* message.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = message.txt; path = ../design/message.txt; sourceTree = ""; }; + 31942A8C1C8EC446001AAF32 /* nailboard-1.svg */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = "nailboard-1.svg"; path = "../design/nailboard-1.svg"; sourceTree = ""; }; + 31942A8D1C8EC446001AAF32 /* nailboard-2.svg */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = "nailboard-2.svg"; path = "../design/nailboard-2.svg"; sourceTree = ""; }; + 31942A8E1C8EC446001AAF32 /* nailboard-3.svg */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = "nailboard-3.svg"; path = "../design/nailboard-3.svg"; sourceTree = ""; }; + 31942A8F1C8EC446001AAF32 /* nailboard.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = nailboard.txt; path = ../design/nailboard.txt; sourceTree = ""; }; + 31942A911C8EC446001AAF32 /* pool.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = pool.txt; path = ../design/pool.txt; sourceTree = ""; }; + 31942A931C8EC446001AAF32 /* poolams.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = poolams.txt; path = ../design/poolams.txt; sourceTree = ""; }; + 31942A951C8EC446001AAF32 /* poollo.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = poollo.txt; path = ../design/poollo.txt; sourceTree = ""; }; + 31942A971C8EC446001AAF32 /* poolmrg.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = poolmrg.txt; path = ../design/poolmrg.txt; sourceTree = ""; }; + 31942A991C8EC446001AAF32 /* poolmvff.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = poolmvff.txt; path = ../design/poolmvff.txt; sourceTree = ""; }; + 31942A9B1C8EC446001AAF32 /* prmc.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = prmc.txt; path = ../design/prmc.txt; sourceTree = ""; }; + 31942A9C1C8EC446001AAF32 /* prot.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = prot.txt; path = ../design/prot.txt; sourceTree = ""; }; + 31942A9E1C8EC446001AAF32 /* protocol.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = protocol.txt; path = ../design/protocol.txt; sourceTree = ""; }; + 31942AA01C8EC446001AAF32 /* pthreadext.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = pthreadext.txt; path = ../design/pthreadext.txt; sourceTree = ""; }; + 31942AA21C8EC446001AAF32 /* reservoir.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = reservoir.txt; path = ../design/reservoir.txt; sourceTree = ""; }; + 31942AA41C8EC446001AAF32 /* root.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = root.txt; path = ../design/root.txt; sourceTree = ""; }; + 31942AA61C8EC446001AAF32 /* seg.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = seg.txt; path = ../design/seg.txt; sourceTree = ""; }; + 31942AA81C8EC446001AAF32 /* sig.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = sig.txt; path = ../design/sig.txt; sourceTree = ""; }; + 31942AA91C8EC446001AAF32 /* sp.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = sp.txt; path = ../design/sp.txt; sourceTree = ""; }; + 31942AAB1C8EC446001AAF32 /* ss.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = ss.txt; path = ../design/ss.txt; sourceTree = ""; }; + 31942AAC1C8EC446001AAF32 /* sso1al.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = sso1al.txt; path = ../design/sso1al.txt; sourceTree = ""; }; + 31942AAE1C8EC446001AAF32 /* telemetry.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = telemetry.txt; path = ../design/telemetry.txt; sourceTree = ""; }; + 31942AB01C8EC446001AAF32 /* testthr.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = testthr.txt; path = ../design/testthr.txt; sourceTree = ""; }; + 31942AB11C8EC446001AAF32 /* thread-manager.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "thread-manager.txt"; path = "../design/thread-manager.txt"; sourceTree = ""; }; + 31942AB31C8EC446001AAF32 /* trace.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = trace.txt; path = ../design/trace.txt; sourceTree = ""; }; + 31942AB51C8EC446001AAF32 /* version-library.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "version-library.txt"; path = "../design/version-library.txt"; sourceTree = ""; }; + 31942AB71C8EC446001AAF32 /* vm.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = vm.txt; path = ../design/vm.txt; sourceTree = ""; }; + 31942AB91C8EC446001AAF32 /* vmso.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = vmso.txt; path = ../design/vmso.txt; 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 = ""; }; @@ -2164,7 +2210,90 @@ 31160D90189953D50071EB17 /* Design */ = { isa = PBXGroup; children = ( + 31942A681C8EC445001AAF32 /* abq.txt */, + 31160D931899540D0071EB17 /* alloc-frame.txt */, + 31942A6A1C8EC445001AAF32 /* an.txt */, + 31942A6B1C8EC445001AAF32 /* arena.txt */, + 31160D951899540D0071EB17 /* arenavm.txt */, + 31942A6D1C8EC445001AAF32 /* boot.txt */, + 31942A6E1C8EC445001AAF32 /* bootstrap.txt */, + 31942A6F1C8EC445001AAF32 /* bt.txt */, + 31160D971899540D0071EB17 /* buffer.txt */, + 31942A711C8EC445001AAF32 /* cbs.txt */, + 31160D991899540D0071EB17 /* check.txt */, + 31942A731C8EC445001AAF32 /* class-interface.txt */, + 31942A741C8EC445001AAF32 /* clock.txt */, + 31160D9B1899540D0071EB17 /* collection.txt */, + 31942A761C8EC445001AAF32 /* config.txt */, + 31160D9D1899540D0071EB17 /* critical-path.txt */, + 31942A781C8EC445001AAF32 /* diag.txt */, + 31942A791C8EC445001AAF32 /* exec-env.txt */, + 22DD93E118ED815F00240DD2 /* failover.txt */, + 31942A7B1C8EC445001AAF32 /* finalize.txt */, + 31160DA01899540D0071EB17 /* fix.txt */, + 31942A7D1C8EC445001AAF32 /* freelist.txt */, + 31160DA21899540D0071EB17 /* guide.hex.trans.txt */, + 31942A7F1C8EC445001AAF32 /* guide.impl.c.format.txt */, + 31942A801C8EC445001AAF32 /* guide.impl.c.naming.txt */, + 31942A811C8EC445001AAF32 /* guide.review.txt */, + 31160DA41899540D0071EB17 /* index.txt */, + 31942A831C8EC445001AAF32 /* interface-c.txt */, + 31160DA61899540D0071EB17 /* io.txt */, + 31942A851C8EC445001AAF32 /* keyword-arguments.txt */, + 22DD93E218ED815F00240DD2 /* land.txt */, + 31942A871C8EC445001AAF32 /* lib.txt */, + 31160DA91899540D0071EB17 /* lock.txt */, + 31942A891C8EC445001AAF32 /* locus.txt */, + 31160DAB1899540D0071EB17 /* message-gc.txt */, + 31942A8B1C8EC446001AAF32 /* message.txt */, + 31942A8C1C8EC446001AAF32 /* nailboard-1.svg */, + 31942A8D1C8EC446001AAF32 /* nailboard-2.svg */, + 31942A8E1C8EC446001AAF32 /* nailboard-3.svg */, + 31942A8F1C8EC446001AAF32 /* nailboard.txt */, + 31160DAD1899540D0071EB17 /* object-debug.txt */, + 31942A911C8EC446001AAF32 /* pool.txt */, + 31160DAF1899540D0071EB17 /* poolamc.txt */, + 31942A931C8EC446001AAF32 /* poolams.txt */, + 31160DB11899540D0071EB17 /* poolawl.txt */, + 31942A951C8EC446001AAF32 /* poollo.txt */, + 31160DB31899540D0071EB17 /* poolmfs.txt */, + 31942A971C8EC446001AAF32 /* poolmrg.txt */, + 31160DB51899540D0071EB17 /* poolmv.txt */, + 31942A991C8EC446001AAF32 /* poolmvff.txt */, + 31160DB71899540D0071EB17 /* poolmvt.txt */, + 31942A9B1C8EC446001AAF32 /* prmc.txt */, + 31942A9C1C8EC446001AAF32 /* prot.txt */, + 31160DBA1899540D0071EB17 /* protli.txt */, + 31942A9E1C8EC446001AAF32 /* protocol.txt */, + 31160DBC1899540D0071EB17 /* protsu.txt */, + 31942AA01C8EC446001AAF32 /* pthreadext.txt */, + 31160DBE1899540D0071EB17 /* range.txt */, + 31942AA21C8EC446001AAF32 /* reservoir.txt */, + 31160DC01899540D0071EB17 /* ring.txt */, + 31942AA41C8EC446001AAF32 /* root.txt */, + 31160DC21899540D0071EB17 /* scan.txt */, + 31942AA61C8EC446001AAF32 /* seg.txt */, + 31160DC41899540D0071EB17 /* shield.txt */, + 31942AA81C8EC446001AAF32 /* sig.txt */, + 31942AA91C8EC446001AAF32 /* sp.txt */, + 31160DC61899540D0071EB17 /* splay.txt */, + 31942AAB1C8EC446001AAF32 /* ss.txt */, + 31942AAC1C8EC446001AAF32 /* sso1al.txt */, + 31160DC81899540D0071EB17 /* strategy.txt */, + 31942AAE1C8EC446001AAF32 /* telemetry.txt */, + 31160DCA1899540D0071EB17 /* tests.txt */, + 31942AB01C8EC446001AAF32 /* testthr.txt */, + 31942AB11C8EC446001AAF32 /* thread-manager.txt */, + 31160DCC1899540D0071EB17 /* thread-safety.txt */, + 31942AB31C8EC446001AAF32 /* trace.txt */, + 31160DCE1899540D0071EB17 /* type.txt */, + 31942AB51C8EC446001AAF32 /* version-library.txt */, + 31160DD01899540D0071EB17 /* version.txt */, + 31942AB71C8EC446001AAF32 /* vm.txt */, + 31160DD31899540D0071EB17 /* vmo1.txt */, + 31942AB91C8EC446001AAF32 /* vmso.txt */, 31160D921899540D0071EB17 /* abq.txt */, + 31160DD51899540D0071EB17 /* writef.txt */, 31160D931899540D0071EB17 /* alloc-frame.txt */, 31160D941899540D0071EB17 /* arena.txt */, 31160D951899540D0071EB17 /* arenavm.txt */, @@ -2205,7 +2334,6 @@ 31160DB61899540D0071EB17 /* poolmvff.txt */, 31160DB71899540D0071EB17 /* poolmvt.txt */, 31160DB81899540D0071EB17 /* prot.txt */, - 31160DB91899540D0071EB17 /* protan.txt */, 31160DBA1899540D0071EB17 /* protli.txt */, 31160DBB1899540D0071EB17 /* protocol.txt */, 31160DBC1899540D0071EB17 /* protsu.txt */, @@ -2230,7 +2358,6 @@ 31160DCF1899540D0071EB17 /* version-library.txt */, 31160DD01899540D0071EB17 /* version.txt */, 31160DD11899540D0071EB17 /* vm.txt */, - 31160DD21899540D0071EB17 /* vman.txt */, 31160DD31899540D0071EB17 /* vmo1.txt */, 31160DD41899540D0071EB17 /* vmso.txt */, 31160DD51899540D0071EB17 /* writef.txt */, @@ -2392,6 +2519,7 @@ 31EEABF4156AAF6500714D05 /* MPM Core */ = { isa = PBXGroup; children = ( + 31942A671C8EC3FC001AAF32 /* locus.h */, 3114A645156E9525001E0AA3 /* abq.c */, 2291A5EA175CB503001D4920 /* abq.h */, 31EEAC05156AB27B00714D05 /* arena.c */, @@ -2406,7 +2534,6 @@ 31EEAC19156AB2B200714D05 /* buffer.c */, 31EEAC40156AB32500714D05 /* cbs.c */, 311F2F5217398AE900C15B6A /* cbs.h */, - 311F2F5317398AE900C15B6A /* chain.h */, 311F2F5417398AE900C15B6A /* check.h */, 311F2F5517398AE900C15B6A /* clock.h */, 311F2F5617398AE900C15B6A /* config.h */, @@ -2524,7 +2651,6 @@ 31EEAC5A156AB40800714D05 /* Extra pools */ = { isa = PBXGroup; children = ( - 311F2F5D17398B0400C15B6A /* lo.h */, 31F6CCA91739B0CF00C48748 /* mpscamc.h */, 31CD33BB173A9F1500524741 /* mpscams.h */, 31F6CCAA1739B0CF00C48748 /* mpscawl.h */, From 90fef618cd8002aaa8c2fd0094897010f9503a17 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 8 Mar 2016 16:28:37 +0000 Subject: [PATCH 215/337] Removing mentions of closures from design documents, to bring them in to line with source code. Copied from Perforce Change: 189768 ServerID: perforce.ravenbrook.com --- mps/design/abq.txt | 18 +++++++++--------- mps/design/land.txt | 8 ++++---- mps/design/splay.txt | 33 ++++++++++++++++----------------- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/mps/design/abq.txt b/mps/design/abq.txt index e3bd56a9bc8..cc0cfe0159f 100644 --- a/mps/design/abq.txt +++ b/mps/design/abq.txt @@ -93,20 +93,20 @@ If the queue is full, return ``TRUE``, otherwise return ``FALSE``. Return the number of elements in the queue. -``typedef Bool (*ABQVisitor)(Bool *deleteReturn, void *element, void *closureP, Size closureS)`` +``typedef Bool (*ABQVisitor)(Bool *deleteReturn, void *element, void *closure)`` A callback function for ``ABQIterate()``. The parameter ``element`` is -an element in the queue, and ``closureP`` and ``closureS`` are the -values that were originally passed to ``ABQIterate()``. This function -must set ``*deleteReturn`` to ``FALSE`` if ``element`` must be kept in -the queue, or ``TRUE`` if ``element`` must be deleted from the queue. -It must return ``TRUE`` if the iteration must continue, or ``FALSE`` -if the iteration must stop after processing ``element``. +an element in the queue, and ``closure`` is the value originally +passed to ``ABQIterate()``. This function must set ``*deleteReturn`` +to ``FALSE`` if ``element`` must be kept in the queue, or ``TRUE`` if +``element`` must be deleted from the queue. It must return ``TRUE`` +if the iteration must continue, or ``FALSE`` if the iteration must +stop after processing ``element``. -``void ABQIterate(ABQ abq, ABQVisitor visitor, void *closureP, Size closureS)`` +``void ABQIterate(ABQ abq, ABQVisitor visitor, void *closure)`` Call ``visitor`` for each element in the queue, passing the element -and ``closureP``. See ``ABQVisitor`` for details. +and ``closure``. See ``ABQVisitor`` for details. Document History diff --git a/mps/design/land.txt b/mps/design/land.txt index 15c1454882d..ac3b4c011ad 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -78,14 +78,14 @@ Types _`.type.land`: The type of a generic land instance. -``typedef Bool (*LandVisitor)(Land land, Range range, void *closureP, Size closureS)`` +``typedef Bool (*LandVisitor)(Land land, Range range, void *closure)`` _`.type.visitor`: Type ``LandVisitor`` is a callback function that may be passed to ``LandIterate()``. It is called for every isolated contiguous range in address order. The function must return a ``Bool`` indicating whether to continue with the iteration. -``typedef Bool (*LandDeleteVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS)`` +``typedef Bool (*LandDeleteVisitor)(Bool *deleteReturn, Land land, Range range, void *closure)`` _`.type.deletevisitor`: Type ``LandDeleteVisitor`` is a callback function that may be passed to ``LandIterateAndDelete()``. It is called for every isolated @@ -172,7 +172,7 @@ strategy. _`.function.delete.alias`: It is acceptable for ``rangeReturn`` and ``range`` to share storage. -``Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)`` +``Bool LandIterate(Land land, LandVisitor visitor, void *closure)`` _`.function.iterate`: ``LandIterate()`` is the function used to iterate all isolated contiguous ranges in a land. It receives a @@ -182,7 +182,7 @@ function returns ``FALSE``, then iteration is terminated and ``LandIterate()`` returns ``FALSE``. If all iterator method calls return ``TRUE``, then ``LandIterate()`` returns ``TRUE`` -``Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS)`` +``Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closure)`` _`.function.iterate.and.delete`: As ``LandIterate()``, but the visitor function additionally returns a Boolean indicating whether the range diff --git a/mps/design/splay.txt b/mps/design/splay.txt index 0e77835f734..823a2dc72dd 100644 --- a/mps/design/splay.txt +++ b/mps/design/splay.txt @@ -219,16 +219,16 @@ the root of the splay tree. It is intended that the `.usage.client-tree`_ for an example). No convenience functions are provided for allocation or deallocation. -``typedef Bool (*SplayTestNodeFunction)(SplayTree splay, Tree tree, void *closureP, Size closureS)`` +``typedef Bool (*SplayTestNodeFunction)(SplayTree splay, Tree tree, void *closure)`` _`.type.splay.test.node.function`: A function of type ``SplayTestNodeFunction`` required to determine whether the node itself meets some client determined property (see `.prop`_ and -`.usage.test.node`_ for an example). Parameters ``closureP`` and -``closureS`` describe the environment for the function (see +`.usage.test.node`_ for an example). Parameter ``closure`` +describes the environment for the function (see `.function.splay.find.first`_ and `.function.splay.find.last`_). -``typedef Bool (*SplayTestTreeFunction)(SplayTree splay, Tree tree, void *closureP, Size closureS)`` +``typedef Bool (*SplayTestTreeFunction)(SplayTree splay, Tree tree, void *closure)`` _`.type.splay.test.tree.function`: A function of type ``SplayTestTreeFunction`` is required to determine whether any of the @@ -237,7 +237,7 @@ determined property (see `.prop`_ and `.usage.test.tree`_ for an example). In particular, it must be a precise (not conservative) indication of whether there are any nodes in the sub-tree for which the ``testNode`` function (see `.type.splay.test.node.function`_) would -return ``TRUE``. Parameters ``closureP`` and ``closureS`` describe the +return ``TRUE``. Parameter ``closure`` describes the environment for the function (see `.function.splay.find.first`_ and `.function.splay.find.last`_). @@ -348,18 +348,17 @@ splay tree, using ``nodeDescribe`` to print client-oriented representations of the nodes (see `.req.debug`_). Provided for debugging only. -``Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeFunction testNode, SplayTestTreeFunction testTree, void *closureP, Size closureS)`` +``Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeFunction testNode, SplayTestTreeFunction testTree, void *closure)`` _`.function.splay.find.first`: Find the first node in the tree that satisfies some client property, as determined by the ``testNode`` and -``testTree`` functions (see `.req.property.find`_). ``closureP`` and -``closureS`` are arbitrary values, and are passed to the ``testNode`` -and ``testTree`` functions which may use the values as closure -environments. If there is no satisfactory node, return ``FALSE``; +``testTree`` functions (see `.req.property.find`_). ``closure`` +is an arbitrary value, and is passed to the ``testNode`` +and ``testTree`` functions. If there is no satisfactory node, return ``FALSE``; otherwise set ``*nodeReturn`` to the node and return ``TRUE``. See `.usage.delete`_ for an example. -``Bool SplayFindLast(Tree *nodeReturn, SplayTree splay, SplayTestNodeFunction testNode, SplayTestTreeFunction testTree, void *closureP, Size closureS)`` +``Bool SplayFindLast(Tree *nodeReturn, SplayTree splay, SplayTestNodeFunction testNode, SplayTestTreeFunction testTree, void *closure)`` _`.function.splay.find.last`: As ``SplayFindFirst()``, but find the last node in the tree that satisfies the client property. @@ -521,12 +520,12 @@ _`.usage.test.tree`: Test tree function (see `.type.splay.test.tree.function`_):: Bool FreeBlockTestTree(SplayTree splay, Tree tree - void *closureP, Size closureS) { - /* Closure environment has wanted size as value of closureS. */ + void *closure) { + /* Closure environment has wanted size as value of *closure. */ /* Look at the cached value for the node to see if any */ /* blocks in the subtree are big enough. */ - Size size = closureS; + Size size = *(Size *)closure; FreeBlock freeNode = FreeBlockOfTree(tree); return freeNode->maxSize >= size; } @@ -535,11 +534,11 @@ _`.usage.test.node`: Test node function (see `.type.splay.test.node.function`_):: Bool FreeBlockTestNode(SplayTree splay, Tree tree - void *closureP, Size closureS) { - /* Closure environment has wanted size as value of closureS. */ + void *closure) { + /* Closure environment has wanted size as value of *closure. */ /* Look at the size of the node to see if is big enough. */ - Size size = closureS; + Size size = *(Size *)closure; FreeBlock freeNode = FreeBlockOfTree(tree); return freeNode->size >= size; } From a7e02655389c59c7d30f74db926105bbf06e4d7c Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 8 Mar 2016 18:25:07 +0000 Subject: [PATCH 216/337] Removing the commit limit from the amc and ams stress tests, since they hit it legitimately at random, and it isn't a good test of anything much. See for discussion and suggestions for better testing. Copied from Perforce Change: 189781 ServerID: perforce.ravenbrook.com --- mps/code/amcss.c | 22 +++++++++++----------- mps/code/amcsshe.c | 1 - mps/code/amsss.c | 1 - 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/mps/code/amcss.c b/mps/code/amcss.c index 294ce224b15..9888f9150f6 100644 --- a/mps/code/amcss.c +++ b/mps/code/amcss.c @@ -41,6 +41,7 @@ static mps_gen_param_s testChain[genCOUNT] = { #define objNULL ((mps_addr_t)MPS_WORD_CONST(0xDECEA5ED)) +static mps_arena_t arena; static mps_ap_t ap; static mps_addr_t exactRoots[exactRootsCOUNT]; static mps_addr_t ambigRoots[ambigRootsCOUNT]; @@ -51,7 +52,7 @@ static unsigned long nCollsDone; /* report -- report statistics from any messages */ -static void report(mps_arena_t arena) +static void report(void) { mps_message_type_t type; @@ -103,8 +104,10 @@ static mps_addr_t make(size_t rootsCount) do { MPS_RESERVE_BLOCK(res, p, ap, size); - if (res) + if (res) { + ArenaDescribe(arena, mps_lib_get_stderr(), 4); die(res, "MPS_RESERVE_BLOCK"); + } res = dylan_init(p, size, exactRoots, rootsCount); if (res) die(res, "dylan_init"); @@ -127,8 +130,7 @@ static void test_stepper(mps_addr_t object, mps_fmt_t fmt, mps_pool_t pool, /* test -- the body of the test */ -static void test(mps_arena_t arena, mps_pool_class_t pool_class, - size_t roots_count) +static void test(mps_pool_class_t pool_class, size_t roots_count) { mps_fmt_t format; mps_chain_t chain; @@ -180,7 +182,7 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class, while (collections < collectionsCOUNT) { size_t r; - report(arena); + report(); if (collections != nCollsStart) { if (!described) { die(ArenaDescribe(arena, mps_lib_get_stdout(), 0), "ArenaDescribe"); @@ -276,7 +278,7 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class, *(int*)busy_init = -1; /* check that the buffer is still there */ if (objs % 1024 == 0) { - report(arena); + report(); putchar('.'); (void)fflush(stdout); } @@ -299,7 +301,6 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class, int main(int argc, char *argv[]) { size_t i, grainSize; - mps_arena_t arena; mps_thr_t thread; testlib_init(argc, argv); @@ -312,16 +313,15 @@ 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_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_thread_reg(&thread, arena), "thread_reg"); - test(arena, mps_class_amc(), exactRootsCOUNT); - test(arena, mps_class_amcz(), 0); + test(mps_class_amc(), exactRootsCOUNT); + test(mps_class_amcz(), 0); mps_thread_dereg(thread); - report(arena); + report(); mps_arena_destroy(arena); printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); diff --git a/mps/code/amcsshe.c b/mps/code/amcsshe.c index bd3ea73d068..a01354193cc 100644 --- a/mps/code/amcsshe.c +++ b/mps/code/amcsshe.c @@ -251,7 +251,6 @@ 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_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/amsss.c b/mps/code/amsss.c index 223bd205aea..8083123f482 100644 --- a/mps/code/amsss.c +++ b/mps/code/amsss.c @@ -209,7 +209,6 @@ 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_COMMIT_LIMIT, 2 * testArenaSIZE); die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create"); } MPS_ARGS_END(args); From ef62b492ba754da602ca8cdaf5c0e2b63bd6ef0d Mon Sep 17 00:00:00 2001 From: Nick Barnes Date: Fri, 11 Mar 2016 12:06:52 +0000 Subject: [PATCH 217/337] Untabify. Copied from Perforce Change: 189851 ServerID: perforce.ravenbrook.com --- mps/code/ss.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/ss.h b/mps/code/ss.h index 75d939194e2..2704cfa1e23 100644 --- a/mps/code/ss.h +++ b/mps/code/ss.h @@ -36,7 +36,7 @@ extern Res StackScan(ScanState ss, Word *stackCold, mps_area_scan_t scan_area, void *closure); extern Res StackScanInner(ScanState ss, Word *stackCold, Word *stackHot, Count nSavedRegs, - mps_area_scan_t scan_area, void *closure); + mps_area_scan_t scan_area, void *closure); #endif /* ss_h */ From 86248c1e6dbb644596bc1baae218a40046576da1 Mon Sep 17 00:00:00 2001 From: Nick Barnes Date: Fri, 11 Mar 2016 12:25:04 +0000 Subject: [PATCH 218/337] Clean up residual closure mentions in design doc. Copied from Perforce Change: 189853 ServerID: perforce.ravenbrook.com --- mps/design/class-interface.txt | 2 +- mps/design/land.txt | 4 ++-- mps/design/splay.txt | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mps/design/class-interface.txt b/mps/design/class-interface.txt index 83e839cdc2f..65cc8accb2a 100644 --- a/mps/design/class-interface.txt +++ b/mps/design/class-interface.txt @@ -204,7 +204,7 @@ set the ``AttrGC`` attribute. _`.method.walk`: The ``walk`` method is used by the heap walker. The ``walk`` method should apply the visitor function (along with its -closure parameters and the object format) to all *black* objects in +closure parameter and the object format) to all *black* objects in the segment. Padding objects may or may not be included in the walk at the classes discretion, in any case in will be the responsibility of the client to do something sensible with padding objects. Forwarding diff --git a/mps/design/land.txt b/mps/design/land.txt index ac3b4c011ad..463126b2570 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -176,8 +176,8 @@ _`.function.delete.alias`: It is acceptable for ``rangeReturn`` and _`.function.iterate`: ``LandIterate()`` is the function used to iterate all isolated contiguous ranges in a land. It receives a -visitor function to invoke on every range, and a pointer, ``Size`` -closure pair to pass on to the visitor function. If the visitor +visitor function to invoke on every range, and a closure pointer +to pass on to the visitor function. If the visitor function returns ``FALSE``, then iteration is terminated and ``LandIterate()`` returns ``FALSE``. If all iterator method calls return ``TRUE``, then ``LandIterate()`` returns ``TRUE`` diff --git a/mps/design/splay.txt b/mps/design/splay.txt index 823a2dc72dd..3a2ed9fd546 100644 --- a/mps/design/splay.txt +++ b/mps/design/splay.txt @@ -224,8 +224,8 @@ provided for allocation or deallocation. _`.type.splay.test.node.function`: A function of type ``SplayTestNodeFunction`` required to determine whether the node itself meets some client determined property (see `.prop`_ and -`.usage.test.node`_ for an example). Parameter ``closure`` -describes the environment for the function (see +`.usage.test.node`_ for an example). The ``closure`` +parameter describes the environment for the function (see `.function.splay.find.first`_ and `.function.splay.find.last`_). ``typedef Bool (*SplayTestTreeFunction)(SplayTree splay, Tree tree, void *closure)`` @@ -237,7 +237,7 @@ determined property (see `.prop`_ and `.usage.test.tree`_ for an example). In particular, it must be a precise (not conservative) indication of whether there are any nodes in the sub-tree for which the ``testNode`` function (see `.type.splay.test.node.function`_) would -return ``TRUE``. Parameter ``closure`` describes the +return ``TRUE``. The ``closure`` parameter describes the environment for the function (see `.function.splay.find.first`_ and `.function.splay.find.last`_). @@ -519,7 +519,7 @@ _`.usage.compare`: Comparison function (see `.type.tree.compare.function`_):: _`.usage.test.tree`: Test tree function (see `.type.splay.test.tree.function`_):: - Bool FreeBlockTestTree(SplayTree splay, Tree tree + Bool FreeBlockTestTree(SplayTree splay, Tree tree, void *closure) { /* Closure environment has wanted size as value of *closure. */ /* Look at the cached value for the node to see if any */ @@ -533,7 +533,7 @@ _`.usage.test.tree`: Test tree function (see _`.usage.test.node`: Test node function (see `.type.splay.test.node.function`_):: - Bool FreeBlockTestNode(SplayTree splay, Tree tree + Bool FreeBlockTestNode(SplayTree splay, Tree tree, void *closure) { /* Closure environment has wanted size as value of *closure. */ /* Look at the size of the node to see if is big enough. */ @@ -609,7 +609,7 @@ block:: Bool found; /* look for the first node of at least the given size. */ - /* closureP parameter is not used. See `.function.splay.find.first.`_ */ + /* closure parameter is not used. See `.function.splay.find.first.`_ */ found = SplayFindFirst(&splayNode, splayTree, FreeBlockTestNode, FreeBlockTestTree, NULL, size); From 8c833d105775c9879708e4d7968afb99b1273907 Mon Sep 17 00:00:00 2001 From: David Lovemore Date: Fri, 11 Mar 2016 12:47:23 +0000 Subject: [PATCH 219/337] Branching master to branch/2016-03-11/shield-coalesce. Copied from Perforce Change: 189856 ServerID: perforce.ravenbrook.com From e75a851b3ab1f92acaa629f357d800adb98e2c88 Mon Sep 17 00:00:00 2001 From: Nick Barnes Date: Fri, 11 Mar 2016 12:51:46 +0000 Subject: [PATCH 220/337] Clear up a bit of closure description in the manual. Copied from Perforce Change: 189860 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/root.rst | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index c174568b446..417d26c2b56 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -79,7 +79,17 @@ reference>`, :term:`ambiguous ` or :term:`weak :term:`fix` references that point to memory not managed by the MPS. These will be ignored. -Roots can be deregistered at any time by calling +.. note:: + + Creating a root with a scanning function may require passing a + pointer to a :term:`closure` object. That closure object must + still be alive when the scanning function is called. If you + allocate it on the stack, make sure that the scanning function is + only going to be called while that stack frame is still active + (for example, by creating such a root from the function within + which your whole program runs). + + 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. @@ -580,8 +590,9 @@ Root interface ``scan_area`` is an tagged area scanning function that will be used to scan the area, for example :c:func:`mps_scan_area_tagged` - or :c:func:`mps_scan_area_tagged_or_zero`. See - :ref:`topic-scanning-area`. + or :c:func:`mps_scan_area_tagged_or_zero`. The ``closure`` + argument to ``scan_area`` is a :c:type:`mps_scan_tag_t` cast to + ``void *`` See :ref:`topic-scanning-area`. ``mask`` is a :term:`bitmask` that is passed to ``scan_area`` to be applied to the words in the vector to locate the :term:`tag`. From be7295d06cbbe74b417cbb0cf7cfc12285a82501 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 11 Mar 2016 14:44:43 +0000 Subject: [PATCH 221/337] Enabling keyword expansion on tool/branch. Copied from Perforce Change: 189864 ServerID: perforce.ravenbrook.com --- mps/tool/branch | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 mps/tool/branch diff --git a/mps/tool/branch b/mps/tool/branch old mode 100755 new mode 100644 From 2d98fb21188a9333ea35d6a4e5230544bab3dddf Mon Sep 17 00:00:00 2001 From: David Lovemore Date: Fri, 11 Mar 2016 15:07:48 +0000 Subject: [PATCH 222/337] Rename functions cache() and flush(). Copied from Perforce Change: 189868 ServerID: perforce.ravenbrook.com --- mps/code/shield.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/mps/code/shield.c b/mps/code/shield.c index 0dfc1945db6..326ffc18052 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -127,7 +127,7 @@ static void shieldSync(Arena arena, Seg seg) } -static void flush(Arena arena, Size i) +static void shieldFlushEntry(Arena arena, Size i) { Seg seg; AVERT(Arena, arena); @@ -153,7 +153,7 @@ static void flush(Arena arena, Size i) /* If the segment is out of sync, either sync it, or ensure * depth > 0, and the arena is suspended. */ -static void cache(Arena arena, Seg seg) +static void shieldCache(Arena arena, Seg seg) { /* */ AVERT_CRITICAL(Arena, arena); @@ -174,7 +174,7 @@ static void cache(Arena arena, Seg seg) AVER(SegDepth(seg) > 0); AVER(arena->shCacheLimit <= ShieldCacheSIZE); AVER(arena->shCacheI < arena->shCacheLimit); - flush(arena, arena->shCacheI); + shieldFlushEntry(arena, arena->shCacheI); arena->shCache[arena->shCacheI] = seg; ++arena->shCacheI; if (arena->shCacheI == ShieldCacheSIZE) @@ -197,7 +197,7 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode) SegSetSM(seg, SegSM(seg) | mode); /* inv.prot.shield preserved */ /* ensure inv.unsynced.suspended & inv.unsynced.depth */ - cache(arena, seg); + shieldCache(arena, seg); AVERT(Arena, arena); AVERT(Seg, seg); } @@ -241,6 +241,12 @@ void (ShieldEnter)(Arena arena) /* .shield.flush: Flush empties the shield cache. * This needs to be called before segments are destroyed as there * may be references to them in the cache. + * + * The memory for the segment may become spare, and not released back to + * the operating system. Since we keep track of protection on segments + * and not grains we have no way of keeping track of the protection + * state of spare grains. We therefore flush the protection to get it + * back into the default state (unprotected). */ void (ShieldFlush)(Arena arena) { @@ -249,7 +255,7 @@ void (ShieldFlush)(Arena arena) for(i = 0; i < arena->shCacheLimit; ++i) { if (arena->shDepth == 0) break; - flush(arena, i); + shieldFlushEntry(arena, i); } } @@ -333,7 +339,7 @@ void (ShieldCover)(Arena arena, Seg seg) --arena->shDepth; /* ensure inv.unsynced.depth */ - cache(arena, seg); + shieldCache(arena, seg); } From 3669ed07b88cec5988ea08bd03c4a578b6b90de5 Mon Sep 17 00:00:00 2001 From: David Lovemore Date: Fri, 11 Mar 2016 17:05:01 +0000 Subject: [PATCH 223/337] Basic coalescing of protects on shield flush. Copied from Perforce Change: 189871 ServerID: perforce.ravenbrook.com --- mps/code/shield.c | 102 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 2 deletions(-) diff --git a/mps/code/shield.c b/mps/code/shield.c index 326ffc18052..bd141bdb489 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -73,6 +73,7 @@ */ #include "mpm.h" +#include "stdlib.h" /* For qsort, move */ SRCID(shield, "$Id$"); @@ -150,6 +151,100 @@ static void shieldFlushEntry(Arena arena, Size i) } +/* We sort NULLs to the end, and otherwise sort by base address */ +static int shieldCacheEntryCompare(const void *a, const void *b) +{ + Seg segA = *(SegStruct * const *)a, segB = *(SegStruct * const *)b; + Addr baseA, baseB; + if (segA != NULL) + AVERT(Seg, segA); + if (segB != NULL) + AVERT(Seg, segB); + + if (segA == NULL) { + if (segB == NULL) return 0; + else return 1; + } + if (segB == NULL) { + AVER(segA != NULL); + return -1; + } + baseA = SegBase(segA); + baseB = SegBase(segB); + if (baseA < baseB) + return -1; + if (baseA > baseB) + return 1; + AVER(baseA == baseB); + return 0; +} + + +/* shieldFlushEntries -- flush cache coalescing protects + * + * base, limit and mode represent outstanding protection to be done. + */ + +static void shieldFlushEntries(Arena arena) +{ + Addr base = 0, limit = 0; + AccessSet mode = 0; + Seg seg; + Size i; + qsort(arena->shCache, arena->shCacheLimit, sizeof(arena->shCache[0]), + shieldCacheEntryCompare); + seg = arena->shCache[0]; + if (seg) { + AVERT(Seg, seg); + arena->shCache[0] = NULL; + + AVER(arena->shDepth > 0); + AVER(SegDepth(seg) > 0); + --arena->shDepth; + SegSetDepth(seg, SegDepth(seg) - 1); + + if (SegSM(seg) != SegPM(seg)) { + SegSetPM(seg, SegSM(seg)); + base = SegBase(seg); + limit = SegLimit(seg); + mode = SegSM(seg); + } + } + for (i=1; i < arena->shCacheLimit; ++i) { + if (arena->shDepth == 0) + break; + seg = arena->shCache[i]; + /* All the NULLs are sorted to the end */ + if (seg == NULL) + break; + AVERT(Seg, seg); + arena->shCache[i] = NULL; + + AVER(arena->shDepth > 0); + AVER(SegDepth(seg) > 0); + --arena->shDepth; + SegSetDepth(seg, SegDepth(seg) - 1); + + if (SegSM(seg) != SegPM(seg)) { + SegSetPM(seg, SegSM(seg)); + if (SegBase(seg) != limit || mode != SegSM(seg)) { + if (limit != 0) { + ProtSet(base, limit, mode); + } + base = SegBase(seg); + limit = SegLimit(seg); + mode = SegSM(seg); + } else { + limit = SegLimit(seg); + } + } + } + if (limit != 0) { + ProtSet(base, limit, mode); + } +} + + /* If the segment is out of sync, either sync it, or ensure * depth > 0, and the arena is suspended. */ @@ -229,7 +324,7 @@ void (ShieldEnter)(Arena arena) AVER(!arena->suspended); AVER(arena->shCacheLimit <= ShieldCacheSIZE); AVER(arena->shCacheI < arena->shCacheLimit); - for(i = 0; i < arena->shCacheLimit; i++) + for (i = 0; i < arena->shCacheLimit; i++) AVER(arena->shCache[i] == NULL); arena->shCacheI = (Size)0; @@ -252,7 +347,10 @@ void (ShieldFlush)(Arena arena) { Size i; - for(i = 0; i < arena->shCacheLimit; ++i) { + if(1) + shieldFlushEntries(arena); + + for (i = 0; i < arena->shCacheLimit; ++i) { if (arena->shDepth == 0) break; shieldFlushEntry(arena, i); From dbbea04f7fb656567af3d79131494ded5a9036f8 Mon Sep 17 00:00:00 2001 From: David Lovemore Date: Fri, 11 Mar 2016 17:05:45 +0000 Subject: [PATCH 224/337] Bigger shield cache, to make coalescing more useful. Copied from Perforce Change: 189872 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index 11d5a943a04..dcc5a1731e9 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -475,8 +475,8 @@ /* Shield Configuration -- see */ -#define ShieldCacheSIZE ((size_t)16) -#define ShieldDepthWIDTH (4) +#define ShieldCacheSIZE ((size_t)1024) +#define ShieldDepthWIDTH (10) /* VM Configuration -- see */ From e5576bed0ba72076441cceaa34c95da9e4a80a28 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 12 Mar 2016 08:43:02 +0000 Subject: [PATCH 225/337] Making closure warning more concise. Fixing format error. Copied from Perforce Change: 189879 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/root.rst | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index 417d26c2b56..325ef245830 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -79,17 +79,7 @@ reference>`, :term:`ambiguous ` or :term:`weak :term:`fix` references that point to memory not managed by the MPS. These will be ignored. -.. note:: - - Creating a root with a scanning function may require passing a - pointer to a :term:`closure` object. That closure object must - still be alive when the scanning function is called. If you - allocate it on the stack, make sure that the scanning function is - only going to be called while that stack frame is still active - (for example, by creating such a root from the function within - which your whole program runs). - - Roots can be deregistered at any time by calling +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. @@ -521,8 +511,9 @@ Root interface :c:func:`mps_scan_area`, or a similar user-defined function. See :ref:`topic-scanning-area`. - ``closure`` is an arbitrary pointer that will be passed to ``scan_area`` - and intended to point to any parameters it needs. + ``closure`` is an arbitrary pointer that will be passed to + ``scan_area`` and is intended to point to any parameters it needs. + Ensure anything it points to exists as long as the root exists. ``cold`` is a pointer to the :term:`cold end` of stack to be scanned. On platforms where the stack grows downwards (currently, @@ -561,6 +552,7 @@ Root interface ``closure`` is an arbitrary pointer that will be passed to ``scan_area`` and intended to point to any parameters it needs. + Ensure anything it points to exists as long as the root exists. Returns :c:macro:`MPS_RES_OK` if the root was registered successfully, :c:macro:`MPS_RES_MEMORY` if the new root From 3441f403a46ee5c33fdb66a0e90627e6a4f19ad0 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Mar 2016 15:45:05 +0000 Subject: [PATCH 226/337] Manual allocation should not longer start any traces, so test this. Copied from Perforce Change: 189894 ServerID: perforce.ravenbrook.com --- mps/code/apss.c | 2 ++ mps/code/mpmss.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/mps/code/apss.c b/mps/code/apss.c index 5192baada42..79a029f86b1 100644 --- a/mps/code/apss.c +++ b/mps/code/apss.c @@ -210,6 +210,8 @@ static void test(mps_arena_class_t arena_class, mps_arg_s arena_args[], mps_class_mvt(), args), "stress MVT"); } MPS_ARGS_END(args); + /* Manual allocation should not cause any garbage collections. */ + Insist(mps_collections(arena) == 0); mps_arena_destroy(arena); } diff --git a/mps/code/mpmss.c b/mps/code/mpmss.c index 2c746b7e34d..31616425a65 100644 --- a/mps/code/mpmss.c +++ b/mps/code/mpmss.c @@ -212,6 +212,8 @@ static void testInArena(mps_arena_class_t arena_class, mps_arg_s *arena_args, mps_class_mfs(), args), "stress MFS"); } MPS_ARGS_END(args); + /* Manual allocation should not cause any garbage collections. */ + Insist(mps_collections(arena) == 0); mps_arena_destroy(arena); } From d8c8e00f3ed2eac4206aa9d502346afde96b1cbd Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Mar 2016 18:27:38 +0000 Subject: [PATCH 227/337] Speed up mmqa test cases by reducing iterations. additionally: * Take test options as parameters=. * Rename BLAH to VERBOSE. * Clearer reporting of slotHigh, arenaHigh, firstFit options to MVFF. * Report times in seconds (not centiseconds). * Reduce the commit limit exponentially and stop when too small. * Ramp entering/leaving probabilities are scaled by iterations. Copied from Perforce Change: 189899 ServerID: perforce.ravenbrook.com --- mps/test/function/100.c | 6 ++-- mps/test/function/101.c | 6 ++-- mps/test/function/106.c | 5 ++-- mps/test/function/107.c | 5 ++-- mps/test/function/12.c | 32 ++++++++++----------- mps/test/function/12p.c | 32 ++++++++++----------- mps/test/function/13.c | 34 +++++++++++------------ mps/test/function/140.c | 23 ++++++++-------- mps/test/function/164.c | 20 +++++++------- mps/test/function/171.c | 14 ++++------ mps/test/function/200.c | 41 +++++++++++++-------------- mps/test/function/203.c | 51 +++++++++++++++++----------------- mps/test/function/204.c | 51 +++++++++++++++++----------------- mps/test/function/205.c | 51 +++++++++++++++++----------------- mps/test/function/206.c | 61 ++++++++++++++++------------------------- mps/test/function/207.c | 20 +++++++------- mps/test/function/215.c | 11 ++++---- mps/test/function/227.c | 11 ++++---- mps/test/function/25.c | 5 ++-- mps/test/function/29.c | 5 ++-- mps/test/function/45.c | 30 ++++++++++---------- 21 files changed, 244 insertions(+), 270 deletions(-) diff --git a/mps/test/function/100.c b/mps/test/function/100.c index edb9c1c0eb6..718bcda36b9 100644 --- a/mps/test/function/100.c +++ b/mps/test/function/100.c @@ -28,7 +28,7 @@ static void dotest(int kind, size_t unitSize, size_t extendBy, mps_pool_t pool; int i, hd; clock_t time0, time1; - int secs; + double secs; asserts(number <= MAXNUMBER, "number too big"); asserts(unitSize >= sizeof(int), "unitSize too small"); @@ -81,9 +81,9 @@ static void dotest(int kind, size_t unitSize, size_t extendBy, mps_pool_destroy(pool); time1=clock(); - secs=(int) 100*(time1-time0)/CLOCKS_PER_SEC; + secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %i, %i) in %i centisecs", + comment("%s test (%x, %x, %i, %i) in %.2f s", tdesc[kind], (int) extendBy, (int) unitSize, number, iter, secs); } diff --git a/mps/test/function/101.c b/mps/test/function/101.c index 6275259d3c5..92f68ad7a50 100644 --- a/mps/test/function/101.c +++ b/mps/test/function/101.c @@ -61,7 +61,7 @@ static void dt(int kind, int i, hd; clock_t time0, time1; size_t size; - int secs; + double secs; asserts(number <= MAXNUMBER, "number too big"); @@ -122,9 +122,9 @@ static void dt(int kind, mps_pool_destroy(pool); time1=clock(); - secs=(int) 100*(time1-time0)/CLOCKS_PER_SEC; + secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %x, %x, %i, %i) in %i centisecs", + comment("%s test (%x, %x, %x, %x, %x, %i, %i) in %.2f s", tdesc[kind], (int) extendBy, (int) avgSize, (int) maxSize, (int) mins, (int) maxs, number, iter, secs); } diff --git a/mps/test/function/106.c b/mps/test/function/106.c index 5f6811bbfaa..7689773b322 100644 --- a/mps/test/function/106.c +++ b/mps/test/function/106.c @@ -4,6 +4,7 @@ TEST_HEADER summary = string twiddling with an AMCZ pool language = c link = lofmt.o testlib.o + parameters = ITERATIONS=10000 END_HEADER */ @@ -14,8 +15,6 @@ END_HEADER #include "mpsavm.h" -#define MAXLEN 1000000; - #define genCOUNT (3) static mps_gen_param_s testChain[genCOUNT] = { @@ -97,7 +96,7 @@ static void test(void) (void)string_ch("Wibble wobble foo"); (void)string_ch("Ba "); - for (i=0; i<10000; i++) { + for (i=0; idata.tag = 0xD033E2A6; p[i]->data.id = nextid; ap_state[i] = 1; - commentif(BLAH, "%i: reserve %li at %p", i, nextid, q); + commentif(VERBOSE, "%i: reserve %li at %p", i, nextid, q); nextid +=1; break; case 1: - commentif(BLAH, "%i: init %li", i, p[i]->data.id); + commentif(VERBOSE, "%i: init %li", i, p[i]->data.id); p[i]->data.tag = MCdata; p[i]->data.numrefs = nrefs[i]; p[i]->data.size = s[i]; @@ -145,22 +143,22 @@ static void test(void) p[i]->data.ref[k].addr = pobj; p[i]->data.ref[k].id = (pobj==NULL ? 0 : pobj->data.id); } - commentif(BLAH, " ref %i -> %li", k, p[i]->data.ref[k].id); + commentif(VERBOSE, " ref %i -> %li", k, p[i]->data.ref[k].id); } break; case 2: - commentif(BLAH, "%i: begin commit %li", i, p[i]->data.id); + commentif(VERBOSE, "%i: begin commit %li", i, p[i]->data.id); ambig[i] = p[i]; ap[i]->init = ap[i]->alloc; ap_state[i] = 3; break; case 3: - commentif(BLAH, "%i: end commit %li", i, p[i]->data.id); + commentif(VERBOSE, "%i: end commit %li", i, p[i]->data.id); q = p[i]; if (ap[i]->limit != 0 || mps_ap_trip(ap[i], p[i], s[i])) { l = ranint(NCELLS); setref(cells, l, q); - commentif(BLAH, "%i -> %i", i, l); + commentif(VERBOSE, "%i -> %i", i, l); } ap_state[i] = 0; ambig[i] = NULL; @@ -176,15 +174,15 @@ static void test(void) for (i=0; idata.tag = MCdata; p[i]->data.numrefs = 0; p[i]->data.size = s[i]; case 2: - commentif(BLAH, "%i begin commit", i); + commentif(VERBOSE, "%i begin commit", i); ap[i]->init = ap[i]->alloc; case 3: - commentif(BLAH, "% end commit", i); + commentif(VERBOSE, "% end commit", i); (void) (ap[i]->limit != 0 || mps_ap_trip(ap[i], p[i], s[i])); } mps_ap_destroy(ap[i]); diff --git a/mps/test/function/12p.c b/mps/test/function/12p.c index db389e7f14f..c5987388e45 100644 --- a/mps/test/function/12p.c +++ b/mps/test/function/12p.c @@ -4,12 +4,13 @@ TEST_HEADER summary = lots of APs with interleaved reserve and 2-stage commit language = c link = testlib.o newfmt.o + parameters = VERBOSE=0 NCELLS=100 NAPS=100 ITERATIONS=100 END_HEADER */ /* This test needs some explanation. The object 'cells' contains - NCELL references to other objects. NAPS allocation points + NCELLS references to other objects. NAPS allocation points are created. At each step, we choose one and nudge it on a little. Each allocation point goes through the following cycle of steps: reserve, init, begin commit, end commit. @@ -35,11 +36,8 @@ static mps_gen_param_s testChain[genCOUNT] = { void *stackpointer; -#define NCELLS 100 -#define NAPS 100 #define PNULL (ranint(100)<25) #define NUMREFS (ranint(20)) -#define BLAH 0 mps_ap_t ap[NAPS]; size_t s[NAPS]; @@ -66,8 +64,8 @@ static void test(void) int nextid = 0x1000000; /* turn on comments about copying and scanning */ - formatcomments = BLAH; - fixcomments = BLAH; + formatcomments = VERBOSE; + fixcomments = VERBOSE; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -104,9 +102,9 @@ cells = allocone(ap[0], NCELLS); 0 after commit */ - for(h=0; h<100; h++) + for(h=0; hdata.tag = 0xD033E2A6; p[i]->data.id = nextid; ap_state[i] = 1; - commentif(BLAH, "%i: reserve %li at %p", i, nextid, q); + commentif(VERBOSE, "%i: reserve %li at %p", i, nextid, q); nextid +=1; break; case 1: - commentif(BLAH, "%i: init %li", i, p[i]->data.id); + commentif(VERBOSE, "%i: init %li", i, p[i]->data.id); p[i]->data.tag = MCdata; p[i]->data.numrefs = nrefs[i]; p[i]->data.size = s[i]; @@ -148,11 +146,11 @@ cells = allocone(ap[0], NCELLS); p[i]->data.ref[k].addr = pobj; p[i]->data.ref[k].id = (pobj==NULL ? 0 : pobj->data.id); } - commentif(BLAH, " ref %i -> %li", k, p[i]->data.ref[k].id); + commentif(VERBOSE, " ref %i -> %li", k, p[i]->data.ref[k].id); } break; case 2: - commentif(BLAH, "%i: begin commit %li", i, p[i]->data.id); + commentif(VERBOSE, "%i: begin commit %li", i, p[i]->data.id); ap[i]->init = ap[i]->alloc; ap_state[i] = 3; break; @@ -160,13 +158,13 @@ cells = allocone(ap[0], NCELLS); ap_state[i]+=1; break; case 10: - commentif(BLAH, "%i: end commit %li", i, p[i]->data.id); + commentif(VERBOSE, "%i: end commit %li", i, p[i]->data.id); q=p[i]; if (ap[i]->limit != 0 || mps_ap_trip(ap[i], p[i], s[i])) { l = ranint(NCELLS); setref(cells, l, q); - commentif(BLAH, "%i -> %i", i, l); + commentif(VERBOSE, "%i -> %i", i, l); } ap_state[i] = 0; break; @@ -182,15 +180,15 @@ cells = allocone(ap[0], NCELLS); switch (ap_state[i]) { case 1: - commentif(BLAH, "%i init", i); + commentif(VERBOSE, "%i init", i); p[i]->data.tag = MCdata; p[i]->data.numrefs = 0; p[i]->data.size = s[i]; case 2: - commentif(BLAH, "%i begin commit", i); + commentif(VERBOSE, "%i begin commit", i); ap[i]->init = ap[i]->alloc; case 3: - commentif(BLAH, "% end commit", i); + commentif(VERBOSE, "% end commit", i); (void) (ap[i]->limit != 0 || mps_ap_trip(ap[i], p[i], s[i])); } mps_ap_destroy(ap[i]); diff --git a/mps/test/function/13.c b/mps/test/function/13.c index aa5ca31b3ee..257e2a4978a 100644 --- a/mps/test/function/13.c +++ b/mps/test/function/13.c @@ -4,12 +4,13 @@ TEST_HEADER summary = interleaved APs (like 12, but produce comments for debugging) language = c link = testlib.o newfmt.o + parameters = VERBOSE=0 NCELLS=100 NAPS=100 ITERATIONS=100 END_HEADER */ /* This test needs some explanation. The object 'cells' contains - NCELL references to other objects. NAPS allocation points + NCELLS references to other objects. NAPS allocation points are created. At each step, we choose one and nudge it on a little. Each allocation point goes through the following cycle of steps: reserve, init, begin commit, end commit. @@ -35,11 +36,8 @@ static mps_gen_param_s testChain[genCOUNT] = { void *stackpointer; -#define NCELLS 100 -#define NAPS 100 #define PNULL (ranint(100)<25) #define NUMREFS (ranint(20)) -#define BLAH 1 mps_ap_t ap[NAPS]; mycell *p[NAPS]; @@ -66,8 +64,8 @@ static void test(void) int nextid = 0x1000000; /* turn on comments about copying and scanning */ - formatcomments = BLAH; - fixcomments = BLAH; + formatcomments = VERBOSE; + fixcomments = VERBOSE; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -104,9 +102,9 @@ cells = allocone(ap[0], NCELLS); 0 after commit */ - for(h=0; h<100; h++) + for(h=0; hdata.tag = 0xD033E2A6; p[i]->data.id = nextid; ap_state[i] = 1; - commentif(BLAH, "%i: reserve %li at %p", i, nextid, q); + commentif(VERBOSE, "%i: reserve %li at %p", i, nextid, q); nextid +=1; break; case 1: - commentif(BLAH, "%i: init %li", i, p[i]->data.id); + commentif(VERBOSE, "%i: init %li", i, p[i]->data.id); p[i]->data.tag = MCdata; p[i]->data.numrefs = nrefs[i]; p[i]->data.size = s[i]; @@ -147,22 +145,22 @@ cells = allocone(ap[0], NCELLS); p[i]->data.ref[k].addr = pobj; p[i]->data.ref[k].id = (pobj==NULL ? 0 : pobj->data.id); } - commentif(BLAH, " ref %i -> %li", k, p[i]->data.ref[k].id); + commentif(VERBOSE, " ref %i -> %li", k, p[i]->data.ref[k].id); } break; case 2: - commentif(BLAH, "%i: begin commit %li", i, p[i]->data.id); + commentif(VERBOSE, "%i: begin commit %li", i, p[i]->data.id); ap[i]->init = ap[i]->alloc; ap_state[i] = 3; break; case 3: - commentif(BLAH, "%i: end commit %li", i, p[i]->data.id); + commentif(VERBOSE, "%i: end commit %li", i, p[i]->data.id); q=p[i]; if (ap[i]->limit != 0 || mps_ap_trip(ap[i], p[i], s[i])) { l = ranint(NCELLS); setref(cells, l, q); - commentif(BLAH, "succeeded %i -> %i", i, l); + commentif(VERBOSE, "succeeded %i -> %i", i, l); } ap_state[i] = 0; break; @@ -171,22 +169,22 @@ cells = allocone(ap[0], NCELLS); checkfrom(cells); } - commentif(BLAH, "Finished main loop"); + commentif(VERBOSE, "Finished main loop"); for (i=0; idata.tag = MCdata; p[i]->data.numrefs = 0; p[i]->data.size = s[i]; case 2: - commentif(BLAH, "%i begin commit", i); + commentif(VERBOSE, "%i begin commit", i); ap[i]->init = ap[i]->alloc; case 3: - commentif(BLAH, "% end commit", i); + commentif(VERBOSE, "% end commit", i); (void) (ap[i]->limit != 0 || mps_ap_trip(ap[i], p[i], s[i])); } mps_ap_destroy(ap[i]); diff --git a/mps/test/function/140.c b/mps/test/function/140.c index 2ad53edc583..7502386c7f1 100644 --- a/mps/test/function/140.c +++ b/mps/test/function/140.c @@ -4,6 +4,7 @@ TEST_HEADER summary = MVFF low-memory test language = c link = testlib.o + parameters = QUEUES=1000 ITERATIONS=100000 END_HEADER */ @@ -66,7 +67,7 @@ static void dt(int kind, int i, hd; clock_t time0, time1; size_t size; - int secs; + double secs; asserts(number <= MAXNUMBER, "number too big"); @@ -113,11 +114,11 @@ static void dt(int kind, if (queue[hd].addr != NULL) { asserts(chkobj(queue[hd].addr, queue[hd].size, (unsigned char) (hd%256)), - "corrupt at %x (%s: %x, %x, %x, %x, %x, %i, %i, %i)", + "corrupt at %p (%s: %x, %x, %x, %c%c%c, %x, %x, %i, %i)", queue[hd].addr, tdesc[kind], (int) extendBy, (int) avgSize, (int) align, - (int) mins, (int) maxs, number, iter, - slotHigh*100+arenaHigh*10+firstFit); + slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', + (int) mins, (int) maxs, number, iter); commentif(comments, "Free %i at %x, size %x", hd, queue[hd].addr, queue[hd].size); mps_free(pool, queue[hd].addr, queue[hd].size); @@ -144,12 +145,12 @@ static void dt(int kind, mps_pool_destroy(pool); time1=clock(); - secs=(int) 100*(time1-time0)/CLOCKS_PER_SEC; + secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %x, %x, %i, %i, %i) in %i centisecs", + comment("%s test (%x, %x, %x, %c%c%c, %x, %x, %i, %i) in %.2f s", tdesc[kind], (int) extendBy, (int) avgSize, (int) align, - (int) mins, (int) maxs, number, iter, - slotHigh*100+arenaHigh*10+firstFit, secs); + slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', + (int) mins, (int) maxs, number, iter, secs); } static void test(void) @@ -162,8 +163,8 @@ static void test(void) cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - for (comlimit = 512*1024; comlimit > 0; comlimit -= 4*1024) { - mps_arena_commit_limit_set(arena, comlimit); + for (comlimit = 512*1024; comlimit > 0; comlimit /= 2) { + if (mps_arena_commit_limit_set(arena, comlimit) != MPS_RES_OK) break; report("limit", "%x", comlimit); symm = ranint(8); slotHigh = (symm >> 2) & 1; @@ -172,7 +173,7 @@ static void test(void) mins = ranrange(1, 16); - dt(RANGAP, 64*1024, 32, 8, 4*mins, 4*ranrange(mins, mins*100), 1000, 100000); + dt(RANGAP, 64*1024, 32, 8, 4*mins, 4*ranrange(mins, mins*100), QUEUES, ITERATIONS); } mps_thread_dereg(thread); diff --git a/mps/test/function/164.c b/mps/test/function/164.c index fa36db4045b..aece86397f2 100644 --- a/mps/test/function/164.c +++ b/mps/test/function/164.c @@ -64,7 +64,7 @@ static void dt(int kind, int i, hd; clock_t time0, time1; size_t size; - int secs; + double secs; asserts(number <= MAXNUMBER, "number too big"); @@ -107,11 +107,11 @@ static void dt(int kind, if (queue[hd].addr != NULL) { asserts(chkobj(queue[hd].addr, queue[hd].size, (unsigned char) (hd%256)), - "corrupt at %x (%s: %x, %x, %x, %x, %x, %i, %i, %i)", + "corrupt at %x (%s: %x, %x, %x, %c%c%c, %x, %x, %i, %i)", queue[hd].addr, tdesc[kind], (int) extendBy, (int) avgSize, (int) align, - (int) mins, (int) maxs, number, iter, - slotHigh*100+arenaHigh*10+firstFit); + slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', + (int) mins, (int) maxs, number, iter); commentif(comments, "Free %i at %x, size %x", hd, queue[hd].addr, queue[hd].size); mps_free(pool, queue[hd].addr, queue[hd].size); @@ -138,12 +138,12 @@ static void dt(int kind, mps_pool_destroy(pool); time1=clock(); - secs=(int) 100*(time1-time0)/CLOCKS_PER_SEC; + secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %x, %x, %i, %i, %i) in %i centisecs", + comment("%s test (%x, %x, %x, %c%c%c, %x, %x, %i, %i) in %.2f s", tdesc[kind], (int) extendBy, (int) avgSize, (int) align, - (int) mins, (int) maxs, number, iter, - slotHigh*100+arenaHigh*10+firstFit, secs); + slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', + (int) mins, (int) maxs, number, iter, secs); } static void test(void) @@ -156,8 +156,8 @@ static void test(void) cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - for (comlimit = 512*1024; comlimit > 0; comlimit -= 4*1024) { - mps_arena_commit_limit_set(arena, comlimit); + for (comlimit = 512*1024; comlimit > 0; comlimit /= 2) { + if (mps_arena_commit_limit_set(arena, comlimit) != MPS_RES_OK) break; report("limit", "%x", comlimit); symm = ranint(8); slotHigh = (symm >> 2) & 1; diff --git a/mps/test/function/171.c b/mps/test/function/171.c index 5be537d7580..3e16d32dd6f 100644 --- a/mps/test/function/171.c +++ b/mps/test/function/171.c @@ -4,7 +4,7 @@ TEST_HEADER summary = test of ramp allocation with tiny arena language = c link = testlib.o rankfmt.o - parameters = ARENA=1024*60 + parameters = ARENA=1024*60 ITERATIONS=10000 OUTPUT_SPEC result = pass END_HEADER @@ -17,16 +17,14 @@ END_HEADER #define ARENALIMIT (ARENA) -#define TABSIZE (50000) -#define ENTERRAMP (3000) -#define LEAVERAMP (10000) +#define TABSIZE (ITERATIONS * 5 / 10) +#define ENTERRAMP (ITERATIONS * 3 / 100) +#define LEAVERAMP (ITERATIONS / 10) #define BACKSIZE (128) #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (100000ul) - #define RAMP_INTERFACE /* #define COLLECT_WORLD @@ -44,7 +42,7 @@ mps_pool_t poolamc; mps_thr_t thread; mps_root_t root, root1; - mps_chain_t chain; +mps_chain_t chain; mps_fmt_t format; mps_ap_t apamc; @@ -100,7 +98,7 @@ static void test(void) { inramp = 0; for (i = 0; i < ITERATIONS; i++) { - if (i % 10000 == 0) { + if (i * 10 % ITERATIONS == 0) { comment("%ld of %ld", i, ITERATIONS); } alloc_back(); diff --git a/mps/test/function/200.c b/mps/test/function/200.c index 894c5c2ef6a..90e5494da92 100644 --- a/mps/test/function/200.c +++ b/mps/test/function/200.c @@ -4,6 +4,7 @@ TEST_HEADER summary = new MV allocation test language = c link = testlib.o + parameters = ITERATIONS=10000 END_HEADER */ @@ -62,7 +63,7 @@ static void dt(int kind, int i, hd; clock_t time0, time1; size_t size; - int secs; + double secs; asserts(number <= MAXNUMBER, "number too big"); @@ -123,9 +124,9 @@ static void dt(int kind, mps_pool_destroy(pool); time1=clock(); - secs=(int) 100*(time1-time0)/CLOCKS_PER_SEC; + secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %x, %x, %i, %i) in %i centisecs", + comment("%s test (%x, %x, %x, %x, %x, %i, %i) in %.2f s", tdesc[kind], (int) extendBy, (int) avgSize, (int) maxSize, (int) mins, (int) maxs, number, iter, secs); } @@ -140,26 +141,26 @@ static void test(void) mins = sizeof(int); - dt(SEQ, 4096, 32, 64*1024, 8, 9, 5, 1000); - dt(RANGAP, 64, 64, 64, 8, 128, 100, 100000); + dt(SEQ, 4096, 32, 64*1024, 8, 9, 5, ITERATIONS); + dt(RANGAP, 64, 64, 64, 8, 128, 100, ITERATIONS); - dt(DUMMY, 4096, 32, 64*1024, 8, 64, 1000, 1000000); - dt(SEQ, 4096, 32, 64*1024, 8, 64, 1000, 1000000); - dt(RAN, 4096, 32, 64*1024, 8, 64, 1000, 1000000); - dt(SEQGAP, 4096, 32, 64*1024, 8, 64, 1000, 1000000); - dt(RANGAP, 4096, 32, 64*1024, 8, 64, 1000, 1000000); + dt(DUMMY, 4096, 32, 64*1024, 8, 64, 1000, ITERATIONS); + dt(SEQ, 4096, 32, 64*1024, 8, 64, 1000, ITERATIONS); + dt(RAN, 4096, 32, 64*1024, 8, 64, 1000, ITERATIONS); + dt(SEQGAP, 4096, 32, 64*1024, 8, 64, 1000, ITERATIONS); + dt(RANGAP, 4096, 32, 64*1024, 8, 64, 1000, ITERATIONS); - dt(DUMMY, 4096, 1024, 64*1024, 100, 132, 1000, 1000000); - dt(SEQ, 4096, 1024, 64*1024, 100, 132, 1000, 1000000); - dt(RAN, 4096, 1024, 64*1024, 100, 132, 1000, 1000000); - dt(SEQGAP, 4096, 1024, 64*1024, 100, 132, 1000, 1000000); - dt(RANGAP, 4096, 1024, 64*1024, 100, 132, 1000, 1000000); + dt(DUMMY, 4096, 1024, 64*1024, 100, 132, 1000, ITERATIONS); + dt(SEQ, 4096, 1024, 64*1024, 100, 132, 1000, ITERATIONS); + dt(RAN, 4096, 1024, 64*1024, 100, 132, 1000, ITERATIONS); + dt(SEQGAP, 4096, 1024, 64*1024, 100, 132, 1000, ITERATIONS); + dt(RANGAP, 4096, 1024, 64*1024, 100, 132, 1000, ITERATIONS); - dt(DUMMY, 128*1024, 64*1024, 6400*1024, mins, 128*1024, 100, 10000); - dt(SEQ, 128*1024, 64*1024, 6400*1024, mins, 128*1024, 100, 10000); - dt(RAN, 128*1024, 64*1024, 6400*1024, mins, 128*1024, 100, 10000); - dt(SEQGAP, 128*1024, 64*1024, 6400*1024, mins, 128*1024, 100, 10000); - dt(RANGAP, 128*1024, 64*1024, 6400*1024, mins, 128*1024, 100, 10000); + dt(DUMMY, 128*1024, 64*1024, 6400*1024, mins, 128*1024, 100, ITERATIONS); + dt(SEQ, 128*1024, 64*1024, 6400*1024, mins, 128*1024, 100, ITERATIONS); + dt(RAN, 128*1024, 64*1024, 6400*1024, mins, 128*1024, 100, ITERATIONS); + dt(SEQGAP, 128*1024, 64*1024, 6400*1024, mins, 128*1024, 100, ITERATIONS); + dt(RANGAP, 128*1024, 64*1024, 6400*1024, mins, 128*1024, 100, ITERATIONS); mps_thread_dereg(thread); mps_arena_destroy(arena); diff --git a/mps/test/function/203.c b/mps/test/function/203.c index 207937d1d35..479ab25cbda 100644 --- a/mps/test/function/203.c +++ b/mps/test/function/203.c @@ -4,6 +4,7 @@ TEST_HEADER summary = new MVT allocation test language = c link = testlib.o + parameters = ITERATIONS=1000 END_HEADER */ @@ -77,7 +78,7 @@ static void dt(int kind, int i, hd; clock_t time0, time1; size_t size; - int secs; + double secs; asserts(number <= MAXNUMBER, "number too big"); @@ -142,9 +143,9 @@ static void dt(int kind, mps_pool_destroy(pool); time1=clock(); - secs=(int) 100*(time1-time0)/CLOCKS_PER_SEC; + secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %i, %i, %x, %x, %i, %i) in %i centisecs", + comment("%s test (%x, %x, %x, %i, %i, %x, %x, %i, %i) in %.2f s", tdesc[kind], (int) minSize, (int) avgSize, (int) maxSize, (int) depth, (int) fragLimit, (int) mins, (int) maxs, number, iter, secs); @@ -167,34 +168,34 @@ static void test(void) comment("Frag: %i", frag); - dt(SEQ, 8, 8, 9, dep, frag, 8, 9, 5, 100); - dt(RANGAP, 64, 64, 64, dep, frag, 8, 128, 100, 10000); + dt(SEQ, 8, 8, 9, dep, frag, 8, 9, 5, ITERATIONS); + dt(RANGAP, 64, 64, 64, dep, frag, 8, 128, 100, ITERATIONS); - dt(DUMMY, 8, 32, 64, dep, frag, 8, 64, 1000, 100000); - dt(SEQ, 8, 32, 64, dep, frag, 8, 64, 1000, 100000); - dt(RAN, 8, 32, 64, dep, frag, 8, 64, 1000, 100000); - dt(SEQGAP, 8, 32, 64, dep, frag, 8, 64, 1000, 100000); - dt(RANGAP, 8, 32, 64, dep, frag, 8, 64, 1000, 100000); + dt(DUMMY, 8, 32, 64, dep, frag, 8, 64, 1000, ITERATIONS); + dt(SEQ, 8, 32, 64, dep, frag, 8, 64, 1000, ITERATIONS); + dt(RAN, 8, 32, 64, dep, frag, 8, 64, 1000, ITERATIONS); + dt(SEQGAP, 8, 32, 64, dep, frag, 8, 64, 1000, ITERATIONS); + dt(RANGAP, 8, 32, 64, dep, frag, 8, 64, 1000, ITERATIONS); - dt(DUMMY, 100, 116, 132, dep, frag, 100, 132, 1000, 100000); - dt(SEQ, 100, 116, 132, dep, frag, 100, 132, 1000, 100000); - dt(RAN, 100, 116, 132, dep, frag, 100, 132, 1000, 100000); - dt(SEQGAP, 100, 116, 132, dep, frag, 100, 132, 1000, 100000); - dt(RANGAP, 100, 116, 132, dep, frag, 100, 132, 1000, 100000); + dt(DUMMY, 100, 116, 132, dep, frag, 100, 132, 1000, ITERATIONS); + dt(SEQ, 100, 116, 132, dep, frag, 100, 132, 1000, ITERATIONS); + dt(RAN, 100, 116, 132, dep, frag, 100, 132, 1000, ITERATIONS); + dt(SEQGAP, 100, 116, 132, dep, frag, 100, 132, 1000, ITERATIONS); + dt(RANGAP, 100, 116, 132, dep, frag, 100, 132, 1000, ITERATIONS); - dt(DUMMY, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(SEQ, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(RAN, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(SEQGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(RANGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 1000); + dt(DUMMY, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(SEQ, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(RAN, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(SEQGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(RANGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); /* try again using exceptional obj for anything over 16K */ - dt(DUMMY, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(SEQ, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(RAN, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(SEQGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(RANGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 1000); + dt(DUMMY, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(SEQ, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(RAN, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(SEQGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(RANGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); } diff --git a/mps/test/function/204.c b/mps/test/function/204.c index d1a00731086..52af542c913 100644 --- a/mps/test/function/204.c +++ b/mps/test/function/204.c @@ -4,6 +4,7 @@ TEST_HEADER summary = new MVT allocation test, extra shallow language = c link = testlib.o + parameters = ITERATIONS=1000 END_HEADER */ @@ -77,7 +78,7 @@ static void dt(int kind, int i, hd; clock_t time0, time1; size_t size; - int secs; + double secs; asserts(number <= MAXNUMBER, "number too big"); @@ -142,9 +143,9 @@ static void dt(int kind, mps_pool_destroy(pool); time1=clock(); - secs=(int) 100*(time1-time0)/CLOCKS_PER_SEC; + secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %i, %i, %x, %x, %i, %i) in %i centisecs", + comment("%s test (%x, %x, %x, %i, %i, %x, %x, %i, %i) in %.2f s", tdesc[kind], (int) minSize, (int) avgSize, (int) maxSize, (int) depth, (int) fragLimit, (int) mins, (int) maxs, number, iter, secs); @@ -167,34 +168,34 @@ static void test(void) comment("Frag: %i", frag); - dt(SEQ, 8, 8, 9, dep, frag, 8, 9, 5, 100); - dt(RANGAP, 64, 64, 64, dep, frag, 8, 128, 100, 10000); + dt(SEQ, 8, 8, 9, dep, frag, 8, 9, 5, ITERATIONS); + dt(RANGAP, 64, 64, 64, dep, frag, 8, 128, 100, ITERATIONS); - dt(DUMMY, 8, 32, 64, dep, frag, 8, 64, 1000, 100000); - dt(SEQ, 8, 32, 64, dep, frag, 8, 64, 1000, 100000); - dt(RAN, 8, 32, 64, dep, frag, 8, 64, 1000, 100000); - dt(SEQGAP, 8, 32, 64, dep, frag, 8, 64, 1000, 100000); - dt(RANGAP, 8, 32, 64, dep, frag, 8, 64, 1000, 100000); + dt(DUMMY, 8, 32, 64, dep, frag, 8, 64, 1000, ITERATIONS); + dt(SEQ, 8, 32, 64, dep, frag, 8, 64, 1000, ITERATIONS); + dt(RAN, 8, 32, 64, dep, frag, 8, 64, 1000, ITERATIONS); + dt(SEQGAP, 8, 32, 64, dep, frag, 8, 64, 1000, ITERATIONS); + dt(RANGAP, 8, 32, 64, dep, frag, 8, 64, 1000, ITERATIONS); - dt(DUMMY, 100, 116, 132, dep, frag, 100, 132, 1000, 100000); - dt(SEQ, 100, 116, 132, dep, frag, 100, 132, 1000, 100000); - dt(RAN, 100, 116, 132, dep, frag, 100, 132, 1000, 100000); - dt(SEQGAP, 100, 116, 132, dep, frag, 100, 132, 1000, 100000); - dt(RANGAP, 100, 116, 132, dep, frag, 100, 132, 1000, 100000); + dt(DUMMY, 100, 116, 132, dep, frag, 100, 132, 1000, ITERATIONS); + dt(SEQ, 100, 116, 132, dep, frag, 100, 132, 1000, ITERATIONS); + dt(RAN, 100, 116, 132, dep, frag, 100, 132, 1000, ITERATIONS); + dt(SEQGAP, 100, 116, 132, dep, frag, 100, 132, 1000, ITERATIONS); + dt(RANGAP, 100, 116, 132, dep, frag, 100, 132, 1000, ITERATIONS); - dt(DUMMY, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(SEQ, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(RAN, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(SEQGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(RANGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 1000); + dt(DUMMY, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(SEQ, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(RAN, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(SEQGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(RANGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); /* try again using exceptional obj for anything over 16K */ - dt(DUMMY, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(SEQ, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(RAN, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(SEQGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(RANGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 1000); + dt(DUMMY, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(SEQ, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(RAN, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(SEQGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(RANGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); } diff --git a/mps/test/function/205.c b/mps/test/function/205.c index d067d6a5ada..16ff013c766 100644 --- a/mps/test/function/205.c +++ b/mps/test/function/205.c @@ -4,6 +4,7 @@ TEST_HEADER summary = new MVT allocation test, extra deep language = c link = testlib.o + parameters = ITERATIONS=1000 END_HEADER */ @@ -77,7 +78,7 @@ static void dt(int kind, int i, hd; clock_t time0, time1; size_t size; - int secs; + double secs; asserts(number <= MAXNUMBER, "number too big"); @@ -142,9 +143,9 @@ static void dt(int kind, mps_pool_destroy(pool); time1=clock(); - secs=(int) 100*(time1-time0)/CLOCKS_PER_SEC; + secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %i, %i, %x, %x, %i, %i) in %i centisecs", + comment("%s test (%x, %x, %x, %i, %i, %x, %x, %i, %i) in %.2f s", tdesc[kind], (int) minSize, (int) avgSize, (int) maxSize, (int) depth, (int) fragLimit, (int) mins, (int) maxs, number, iter, secs); @@ -167,34 +168,34 @@ static void test(void) comment("Frag: %i", frag); - dt(SEQ, 8, 8, 9, dep, frag, 8, 9, 5, 100); - dt(RANGAP, 64, 64, 64, dep, frag, 8, 128, 100, 10000); + dt(SEQ, 8, 8, 9, dep, frag, 8, 9, 5, ITERATIONS); + dt(RANGAP, 64, 64, 64, dep, frag, 8, 128, 100, ITERATIONS); - dt(DUMMY, 8, 32, 64, dep, frag, 8, 64, 1000, 100000); - dt(SEQ, 8, 32, 64, dep, frag, 8, 64, 1000, 100000); - dt(RAN, 8, 32, 64, dep, frag, 8, 64, 1000, 100000); - dt(SEQGAP, 8, 32, 64, dep, frag, 8, 64, 1000, 100000); - dt(RANGAP, 8, 32, 64, dep, frag, 8, 64, 1000, 100000); + dt(DUMMY, 8, 32, 64, dep, frag, 8, 64, 1000, ITERATIONS); + dt(SEQ, 8, 32, 64, dep, frag, 8, 64, 1000, ITERATIONS); + dt(RAN, 8, 32, 64, dep, frag, 8, 64, 1000, ITERATIONS); + dt(SEQGAP, 8, 32, 64, dep, frag, 8, 64, 1000, ITERATIONS); + dt(RANGAP, 8, 32, 64, dep, frag, 8, 64, 1000, ITERATIONS); - dt(DUMMY, 100, 116, 132, dep, frag, 100, 132, 1000, 100000); - dt(SEQ, 100, 116, 132, dep, frag, 100, 132, 1000, 100000); - dt(RAN, 100, 116, 132, dep, frag, 100, 132, 1000, 100000); - dt(SEQGAP, 100, 116, 132, dep, frag, 100, 132, 1000, 100000); - dt(RANGAP, 100, 116, 132, dep, frag, 100, 132, 1000, 100000); + dt(DUMMY, 100, 116, 132, dep, frag, 100, 132, 1000, ITERATIONS); + dt(SEQ, 100, 116, 132, dep, frag, 100, 132, 1000, ITERATIONS); + dt(RAN, 100, 116, 132, dep, frag, 100, 132, 1000, ITERATIONS); + dt(SEQGAP, 100, 116, 132, dep, frag, 100, 132, 1000, ITERATIONS); + dt(RANGAP, 100, 116, 132, dep, frag, 100, 132, 1000, ITERATIONS); - dt(DUMMY, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(SEQ, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(RAN, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(SEQGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(RANGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 1000); + dt(DUMMY, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(SEQ, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(RAN, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(SEQGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(RANGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); /* try again using exceptional obj for anything over 16K */ - dt(DUMMY, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(SEQ, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(RAN, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(SEQGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 1000); - dt(RANGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 1000); + dt(DUMMY, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(SEQ, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(RAN, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(SEQGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); + dt(RANGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, ITERATIONS); } diff --git a/mps/test/function/206.c b/mps/test/function/206.c index 95812038290..a5bc71ff4b3 100644 --- a/mps/test/function/206.c +++ b/mps/test/function/206.c @@ -4,6 +4,7 @@ TEST_HEADER summary = new MVFF allocation test language = c link = testlib.o + parameters = QUEUES=100 ITERATIONS=10000 END_HEADER */ @@ -64,7 +65,7 @@ static void dt(int kind, int i, hd; clock_t time0, time1; size_t size; - int secs; + double secs; asserts(number <= MAXNUMBER, "number too big"); @@ -102,11 +103,11 @@ static void dt(int kind, if (queue[hd].addr != NULL) { asserts(chkobj(queue[hd].addr, queue[hd].size, (unsigned char) (hd%256)), - "corrupt at %x (%s: %x, %x, %x, %x, %x, %i, %i, %i)", + "corrupt at %p (%s: %x, %x, %x, %c%c%c, %x, %x, %i, %i)", queue[hd].addr, tdesc[kind], (int) extendBy, (int) avgSize, (int) align, - (int) mins, (int) maxs, number, iter, - slotHigh*100+arenaHigh*10+firstFit); + slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', + (int) mins, (int) maxs, number, iter); mps_free(pool, queue[hd].addr, queue[hd].size); } size = ranrange(mins, maxs); @@ -126,52 +127,36 @@ static void dt(int kind, mps_pool_destroy(pool); time1=clock(); - secs=(int) 100*(time1-time0)/CLOCKS_PER_SEC; + secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %x, %x, %i, %i, %i) in %i centisecs", + comment("%s test (%x, %x, %x, %c%c%c, %x, %x, %i, %i) in %.2f s", tdesc[kind], (int) extendBy, (int) avgSize, (int) align, - (int) mins, (int) maxs, number, iter, - slotHigh*100+arenaHigh*10+firstFit, secs); + slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', + (int) mins, (int) maxs, number, iter, secs); } static void test(void) { mps_thr_t thread; - size_t mins; - int symm; + size_t extendBy, avgSize, maxSize; + size_t align = sizeof(void*); + size_t minSize = sizeof(int); + int i, j, kind; cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - mins = sizeof(int); - - for (symm = 0; symm < 8; symm++) { - - slotHigh = (symm >> 2) & 1; - arenaHigh = (symm >> 1) & 1; - firstFit = (symm & 1); - - dt(SEQ, 4096, 32, 8, 8, 9, 5, 1000); - dt(RANGAP, 64, 64, 8, 8, 128, 100, 100000); - - dt(DUMMY, 4096, 32, 8, 8, 64, 1000, 1000000); - dt(SEQ, 4096, 32, 8, 8, 64, 1000, 1000000); - dt(RAN, 4096, 32, 8, 8, 64, 1000, 1000000); - dt(SEQGAP, 4096, 32, 8, 8, 64, 1000, 1000000); - dt(RANGAP, 4096, 32, 8, 8, 64, 1000, 1000000); - - dt(DUMMY, 4096, 1024, 8, 100, 132, 1000, 1000000); - dt(SEQ, 4096, 1024, 8, 100, 132, 1000, 1000000); - dt(RAN, 4096, 1024, 8, 100, 132, 1000, 1000000); - dt(SEQGAP, 4096, 1024, 8, 100, 132, 1000, 1000000); - dt(RANGAP, 4096, 1024, 8, 100, 132, 1000, 1000000); - - dt(DUMMY, 128*1024, 64*1024, 8, mins, 128*1024, 100, 10000); - dt(SEQ, 128*1024, 64*1024, 8, mins, 128*1024, 100, 10000); - dt(RAN, 128*1024, 64*1024, 8, mins, 128*1024, 100, 10000); - dt(SEQGAP, 128*1024, 64*1024, 8, mins, 128*1024, 100, 10000); - dt(RANGAP, 128*1024, 64*1024, 8, mins, 128*1024, 100, 10000); + for (i = 0; i < 5 * 2 * 2 * 2 * 2 * 2; ++i) { + j = i; + slotHigh = j % 2; j /= 2; + arenaHigh = j % 2; j /= 2; + firstFit = j % 2; j /= 2; + extendBy = j % 2 ? 4096 : 65536; j /= 2; + avgSize = j % 2 ? 32 : extendBy / 2; + maxSize = j % 2 ? 64 : extendBy; j /= 2; + kind = j % 5; j /= 5; + dt(kind, extendBy, avgSize, align, minSize, maxSize, QUEUES, ITERATIONS); } mps_thread_dereg(thread); diff --git a/mps/test/function/207.c b/mps/test/function/207.c index bb3c4a2b619..6d73d87d4bd 100644 --- a/mps/test/function/207.c +++ b/mps/test/function/207.c @@ -64,7 +64,7 @@ static void dt(int kind, int i, hd; clock_t time0, time1; size_t size; - int secs; + double secs; asserts(number <= MAXNUMBER, "number too big"); @@ -107,11 +107,11 @@ static void dt(int kind, if (queue[hd].addr != NULL) { asserts(chkobj(queue[hd].addr, queue[hd].size, (unsigned char) (hd%256)), - "corrupt at %x (%s: %x, %x, %x, %x, %x, %i, %i, %i)", + "corrupt at %x (%s: %x, %x, %x, %c%c%c, %x, %x, %i, %i)", queue[hd].addr, tdesc[kind], (int) extendBy, (int) avgSize, (int) align, - (int) mins, (int) maxs, number, iter, - slotHigh*100+arenaHigh*10+firstFit); + slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', + (int) mins, (int) maxs, number, iter); commentif(comments, "Free %i at %x, size %x", hd, queue[hd].addr, queue[hd].size); mps_free(pool, queue[hd].addr, queue[hd].size); @@ -138,12 +138,12 @@ static void dt(int kind, mps_pool_destroy(pool); time1=clock(); - secs=(int) 100*(time1-time0)/CLOCKS_PER_SEC; + secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %x, %x, %i, %i, %i) in %i centisecs", + comment("%s test (%x, %x, %x, %c%c%c, %x, %x, %i, %i) in %.2f s", tdesc[kind], (int) extendBy, (int) avgSize, (int) align, - (int) mins, (int) maxs, number, iter, - slotHigh*100+arenaHigh*10+firstFit, secs); + slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', + (int) mins, (int) maxs, number, iter, secs); } static void test(void) @@ -156,8 +156,8 @@ static void test(void) cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - for (comlimit = 512*1024; comlimit > 0; comlimit -= 4*1024) { - mps_arena_commit_limit_set(arena, comlimit); + for (comlimit = 512*1024; comlimit > 0; comlimit /= 2) { + if (mps_arena_commit_limit_set(arena, comlimit) != MPS_RES_OK) break; report("limit", "%x", comlimit); symm = ranint(8); slotHigh = (symm >> 2) & 1; diff --git a/mps/test/function/215.c b/mps/test/function/215.c index 14ad7a1b808..a64dafdf559 100644 --- a/mps/test/function/215.c +++ b/mps/test/function/215.c @@ -4,6 +4,7 @@ TEST_HEADER summary = test of ramp allocation language = c link = testlib.o rankfmt.o + parameters = ITERATIONS=100000 OUTPUT_SPEC result = pass END_HEADER @@ -16,16 +17,14 @@ END_HEADER #define ARENALIMIT (200) -#define TABSIZE (50000) -#define ENTERRAMP (30000) -#define LEAVERAMP (100000) +#define TABSIZE (ITERATIONS * 5 / 10) +#define ENTERRAMP (ITERATIONS * 3 / 100) +#define LEAVERAMP (ITERATIONS / 10) #define BACKSIZE (128) #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (1000000ul) - #define RAMP_INTERFACE /* #define COLLECT_WORLD @@ -102,7 +101,7 @@ static void test(void) { inramp = 0; for (i = 0; i < ITERATIONS; i++) { - if (i % 10000 == 0) { + if (i * 10 % ITERATIONS == 0) { comment("%ld of %ld", i, ITERATIONS); } alloc_back(); diff --git a/mps/test/function/227.c b/mps/test/function/227.c index 09b8cb98e30..b86a958ed2e 100644 --- a/mps/test/function/227.c +++ b/mps/test/function/227.c @@ -4,6 +4,7 @@ TEST_HEADER summary = allocate in 2 arenas language = c link = testlib.o rankfmt.o + parameters = ITERATIONS=100000 OUTPUT_SPEC result = pass END_HEADER @@ -20,16 +21,14 @@ END_HEADER #define ARENALIMIT (100) -#define TABSIZE (50000) -#define ENTERRAMP (30000) -#define LEAVERAMP (100000) +#define TABSIZE (ITERATIONS * 5 / 10) +#define ENTERRAMP (ITERATIONS * 3 / 100) +#define LEAVERAMP (ITERATIONS / 10) #define BACKSIZE (32) #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (1000000ul) - #define RAMP_INTERFACE /* #define COLLECT_WORLD @@ -117,7 +116,7 @@ static void test(void) { inramp = 0; for (i = 0; i < ITERATIONS; i++) { - if (i % 10000 == 0) { + if (i * 10 % ITERATIONS == 0) { comment("%ld of %ld", i, ITERATIONS); } alloc_back(); diff --git a/mps/test/function/25.c b/mps/test/function/25.c index 5e4b2e37d71..f6450b95153 100644 --- a/mps/test/function/25.c +++ b/mps/test/function/25.c @@ -4,6 +4,7 @@ TEST_HEADER summary = string twiddling with an LO pool language = c link = lofmt.o testlib.o + parameters = ITERATIONS=10000 END_HEADER */ @@ -16,8 +17,6 @@ END_HEADER void *stackpointer; mps_ap_t ap; -#define MAXLEN 1000000; - static locell *string_ch(char* x) { size_t len; @@ -89,7 +88,7 @@ static void test(void) { (void)string_ch("Wibble wobble foo"); (void)string_ch("Ba "); - for (i=0; i<10000; i++) { + for (i=0; idata.tag = 0xD033E2A6; p[i]->data.id = nextid; ap_state[i] = 1; - commentif(BLAH, "%i: reserve %li at %p", i, nextid, q); + commentif(VERBOSE, "%i: reserve %li at %p", i, nextid, q); nextid +=1; break; case 1: - commentif(BLAH, "%i: init %li", i, p[i]->data.id); + commentif(VERBOSE, "%i: init %li", i, p[i]->data.id); p[i]->data.tag = MCdata; p[i]->data.numrefs = nrefs[i]; p[i]->data.size = s[i]; @@ -144,22 +142,22 @@ static void test(void) p[i]->data.ref[k].addr = pobj; p[i]->data.ref[k].id = (pobj==NULL ? 0 : pobj->data.id); } - commentif(BLAH, " ref %i -> %li", k, p[i]->data.ref[k].id); + commentif(VERBOSE, " ref %i -> %li", k, p[i]->data.ref[k].id); } break; case 2: - commentif(BLAH, "%i: begin commit %li", i, p[i]->data.id); + commentif(VERBOSE, "%i: begin commit %li", i, p[i]->data.id); ambig[i] = p[i]; ap[i]->init = ap[i]->alloc; ap_state[i] = 3; break; case 3: - commentif(BLAH, "%i: end commit %li", i, p[i]->data.id); + commentif(VERBOSE, "%i: end commit %li", i, p[i]->data.id); q=p[i]; if (ap[i]->limit != 0 || mps_ap_trip(ap[i], p[i], s[i])) { l = ranint(NCELLS); setref(cells, l, q); - commentif(BLAH, "%i -> %i", i, l); + commentif(VERBOSE, "%i -> %i", i, l); } ap_state[i] = 0; ambig[i] = NULL; @@ -178,15 +176,15 @@ static void test(void) for (i=0; idata.tag = MCdata; p[i]->data.numrefs = 0; p[i]->data.size = s[i]; case 2: - commentif(BLAH, "%i begin commit", i); + commentif(VERBOSE, "%i begin commit", i); ap[i]->init = ap[i]->alloc; case 3: - commentif(BLAH, "% end commit", i); + commentif(VERBOSE, "% end commit", i); (void) (ap[i]->limit != 0 || mps_ap_trip(ap[i], p[i], s[i])); } mps_ap_destroy(ap[i]); From 741cffbc75cdb6082790fe9728b94528ad279457 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Mar 2016 18:38:59 +0000 Subject: [PATCH 228/337] Make branch script executable. Copied from Perforce Change: 189902 ServerID: perforce.ravenbrook.com --- mps/tool/branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 mps/tool/branch diff --git a/mps/tool/branch b/mps/tool/branch old mode 100644 new mode 100755 index 5bb9b21c3ec..7de38f08d29 --- a/mps/tool/branch +++ b/mps/tool/branch @@ -4,7 +4,7 @@ # Gareth Rees, Ravenbrook Limited, 2014-03-18 # # $Id$ -# Copyright (c) 2014 Ravenbrook Limited. See end of file for license. +# Copyright (c) 2014-2016 Ravenbrook Limited. See end of file for license. # # # 1. INTRODUCTION From c1c71ea304139f836cc14887628968eb188529a2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Mar 2016 18:46:24 +0000 Subject: [PATCH 229/337] Branching master to branch/2016-03-12/pause. Copied from Perforce Change: 189904 ServerID: perforce.ravenbrook.com From 5460235a2c09076f6d24b66ba28bbb1dd0f3bcc4 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Mar 2016 20:07:49 +0000 Subject: [PATCH 230/337] =?UTF-8?q?Remove=20the=20commit=20limit=20from=20?= =?UTF-8?q?the=20amc=20and=20ams=20stress=20tests,=20since=20they=20hit=20?= =?UTF-8?q?it=20legitimately=20at=20random.=20see=20?= =?UTF-8?q?=20for=20discussion=20and=20suggestions=20for=20better=20testin?= =?UTF-8?q?g.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copied from Perforce Change: 189912 ServerID: perforce.ravenbrook.com --- mps/code/amcssth.c | 44 +++++++++++++------------------------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c index 596d818bc0b..3ce82054931 100644 --- a/mps/code/amcssth.c +++ b/mps/code/amcssth.c @@ -1,21 +1,13 @@ /* amcssth.c: POOL CLASS AMC STRESS TEST WITH TWO THREADS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (c) 2002 Global Graphics Software. * - * .mode: This test case has two modes: - * - * .mode.walk: In this mode, the main thread parks the arena half way - * through the test case and runs mps_arena_formatted_objects_walk(). - * This checks that walking works while the other threads continue to - * allocate in the background. - * - * .mode.commit: In this mode, the arena's commit limit is set. This - * checks that the MPS can make progress inside a tight limit in the - * presence of allocation on multiple threads. But this is - * incompatible with .mode.walk: if the arena is parked, then the - * arena has no chance to make progress. + * The main thread parks the arena half way through the test case and + * runs mps_arena_formatted_objects_walk(). This checks that walking + * works while the other threads continue to allocate in the + * background. */ #include "fmtdy.h" @@ -28,11 +20,6 @@ #include /* fflush, printf, putchar */ -enum { - ModeWALK = 0, /* .mode.walk */ - ModeCOMMIT = 1 /* .mode.commit */ -}; - /* These values have been tuned in the hope of getting one dynamic collection. */ #define testArenaSIZE ((size_t)1000*1024) @@ -157,8 +144,7 @@ static void *kid_thread(void *arg) /* test -- the body of the test */ -static void test_pool(const char *name, 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) { size_t i; mps_word_t rampSwitch; @@ -170,8 +156,7 @@ static void test_pool(const char *name, mps_pool_t pool, size_t roots_count, closure_s cl; int walked = FALSE, ramped = FALSE; - printf("\n------ mode: %s pool: %s-------\n", - mode == ModeWALK ? "WALK" : "COMMIT", name); + printf("\n------ pool: %s-------\n", name); cl.pool = pool; cl.roots_count = roots_count; @@ -217,7 +202,7 @@ static void test_pool(const char *name, mps_pool_t pool, size_t roots_count, cdie(exactRoots[i] == objNULL || dylan_check(exactRoots[i]), "all roots check"); - if (mode == ModeWALK && collections >= collectionsCOUNT / 2 && !walked) + if (collections >= collectionsCOUNT / 2 && !walked) { unsigned long count = 0; mps_arena_park(arena); @@ -278,7 +263,7 @@ static void test_pool(const char *name, mps_pool_t pool, size_t roots_count, testthr_join(&kids[i], NULL); } -static void test_arena(int mode) +static void test_arena(void) { size_t i; mps_fmt_t format; @@ -291,8 +276,6 @@ 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_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()); @@ -324,8 +307,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", amc_pool, exactRootsCOUNT, mode); - test_pool("AMCZ", amcz_pool, 0, mode); + test_pool("AMC", amc_pool, exactRootsCOUNT); + test_pool("AMCZ", amcz_pool, 0); mps_arena_park(arena); mps_pool_destroy(amc_pool); @@ -342,8 +325,7 @@ static void test_arena(int mode) int main(int argc, char *argv[]) { testlib_init(argc, argv); - test_arena(ModeWALK); - test_arena(ModeCOMMIT); + test_arena(); printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); return 0; @@ -352,7 +334,7 @@ int main(int argc, char *argv[]) /* C. COPYRIGHT AND LICENSE * - * Copyright (c) 2001-2014 Ravenbrook Limited . + * Copyright (c) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From f9041d9a20f2aa9b8f6cd33eaaaec8593c162a83 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Mar 2016 20:25:33 +0000 Subject: [PATCH 231/337] Documentation and interface for pause time control (no implementation yet). Copied from Perforce Change: 189915 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 20 +++++++++ mps/code/arg.c | 4 +- mps/code/config.h | 7 ++- mps/code/eventdef.h | 11 +++-- mps/code/mpm.h | 2 + mps/code/mpmst.h | 1 + mps/code/mps.h | 6 +++ mps/code/mpsi.c | 19 ++++++++ mps/design/arena.txt | 11 +++++ mps/manual/source/release.rst | 9 ++++ mps/manual/source/topic/arena.rst | 69 +++++++++++++++++++++++++++-- mps/manual/source/topic/keyword.rst | 1 + 12 files changed, 151 insertions(+), 9 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 860715c5059..ec235c995a2 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -149,6 +149,7 @@ Bool ArenaCheck(Arena arena) */ CHECKL(arena->committed <= arena->commitLimit); CHECKL(arena->spareCommitted <= arena->committed); + CHECKL(0.0 <= arena->pauseTime); CHECKL(ShiftCheck(arena->zoneShift)); CHECKL(ArenaGrainSizeCheck(arena->grainSize)); @@ -199,6 +200,7 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) Bool zoned = ARENA_DEFAULT_ZONED; Size commitLimit = ARENA_DEFAULT_COMMIT_LIMIT; Size spareCommitLimit = ARENA_DEFAULT_SPARE_COMMIT_LIMIT; + double pauseTime = ARENA_DEFAULT_PAUSE_TIME; mps_arg_s arg; AVER(arena != NULL); @@ -211,6 +213,8 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) commitLimit = arg.val.size; if (ArgPick(&arg, args, MPS_KEY_SPARE_COMMIT_LIMIT)) spareCommitLimit = arg.val.size; + if (ArgPick(&arg, args, MPS_KEY_PAUSE_TIME)) + pauseTime = arg.val.d; arena->class = class; @@ -219,6 +223,7 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) arena->commitLimit = commitLimit; arena->spareCommitted = (Size)0; arena->spareCommitLimit = spareCommitLimit; + arena->pauseTime = pauseTime; arena->grainSize = grainSize; /* zoneShift is usually overridden by init */ arena->zoneShift = ARENA_ZONESHIFT; @@ -294,6 +299,7 @@ ARG_DEFINE_KEY(ARENA_SIZE, Size); ARG_DEFINE_KEY(ARENA_ZONED, Bool); ARG_DEFINE_KEY(COMMIT_LIMIT, Size); ARG_DEFINE_KEY(SPARE_COMMIT_LIMIT, Size); +ARG_DEFINE_KEY(PAUSE_TIME, double); static Res arenaFreeLandInit(Arena arena) { @@ -1242,6 +1248,20 @@ void ArenaSetSpareCommitLimit(Arena arena, Size limit) EVENT2(SpareCommitLimitSet, arena, limit); } +double ArenaPauseTime(Arena arena) +{ + AVERT(Arena, arena); + return arena->pauseTime; +} + +void ArenaSetPauseTime(Arena arena, double pauseTime) +{ + AVERT(Arena, arena); + AVER(0.0 <= pauseTime); + arena->pauseTime = pauseTime; + EVENT2(PauseTimeSet, arena, pauseTime); +} + /* Used by arenas which don't use spare committed memory */ Size ArenaNoPurgeSpare(Arena arena, Size size) { diff --git a/mps/code/arg.c b/mps/code/arg.c index 4721c415ccb..82f936b92cb 100644 --- a/mps/code/arg.c +++ b/mps/code/arg.c @@ -93,8 +93,8 @@ Bool ArgCheckRank(Arg arg) { } Bool ArgCheckdouble(Arg arg) { - /* It would be nice if we could check doubles with C89, but - it doesn't have isfinite() etc. which are in C99. */ + /* Don't call isfinite() here because it's not in C89, and because + infinity is a valid value for MPS_KEY_PAUSE_TIME. */ UNUSED(arg); return TRUE; } diff --git a/mps/code/config.h b/mps/code/config.h index 11d5a943a04..5c751ca5636 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -408,9 +408,14 @@ /* 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. */ + * documentation changes. */ #define ARENA_DEFAULT_SPARE_COMMIT_LIMIT ((Size)10uL*1024uL*1024uL) +/* ARENA_DEFAULT_PAUSE_TIME is the maximum time (in seconds) that the + * arena that operations within the arena may pause the mutator for. */ + +#define ARENA_DEFAULT_PAUSE_TIME (0.0) + #define ARENA_DEFAULT_ZONED TRUE /* ARENA_MINIMUM_COLLECTABLE_SIZE is the minimum size (in bytes) of diff --git a/mps/code/eventdef.h b/mps/code/eventdef.h index 081b45de7c2..c24fdbad2e6 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) @@ -67,7 +67,7 @@ */ #define EventNameMAX ((size_t)19) -#define EventCodeMAX ((EventCode)0x0086) +#define EventCodeMAX ((EventCode)0x0087) #define EVENT_LIST(EVENT, X) \ /* 0123456789012345678 <- don't exceed without changing EventNameMAX */ \ @@ -192,7 +192,8 @@ EVENT(X, TraceCondemnZones , 0x0083, TRUE, Trace) \ EVENT(X, ArenaGenZoneAdd , 0x0084, TRUE, Arena) \ EVENT(X, ArenaUseFreeZone , 0x0085, TRUE, Arena) \ - /* EVENT(X, ArenaBlacklistZone , 0x0086, TRUE, Arena) */ + /* EVENT(X, ArenaBlacklistZone , 0x0086, TRUE, Arena) */ \ + EVENT(X, PauseTimeSet , 0x0087, TRUE, Arena) /* Remember to update EventNameMAX and EventCodeMAX above! @@ -740,6 +741,10 @@ PARAM(X, 0, P, arena) /* the arena */ \ PARAM(X, 1, W, zoneSet) /* zones that aren't free any longer */ +#define EVENT_PauseTimeSet_PARAMS(PARAM, X) \ + PARAM(X, 0, P, arena) /* the arena */ \ + PARAM(X, 1, D, pauseTime) /* the new maximum pause time, in seconds */ + #endif /* eventdef_h */ diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 118d8ff070e..4ee3453a0fc 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -621,6 +621,8 @@ 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 double ArenaPauseTime(Arena arena); +extern void ArenaSetPauseTime(Arena arena, double pauseTime); extern Size ArenaNoPurgeSpare(Arena arena, Size size); extern Res ArenaNoGrow(Arena arena, LocusPref pref, Size size); diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 8b76dec162a..b6c1914de6b 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -719,6 +719,7 @@ typedef struct mps_arena_s { Size spareCommitted; /* Amount of memory in hysteresis fund */ Size spareCommitLimit; /* Limit on spareCommitted */ + double pauseTime; /* Maximum pause time, in seconds. */ Shift zoneShift; /* see also */ Size grainSize; /* */ diff --git a/mps/code/mps.h b/mps/code/mps.h index 05b2644ec8e..7526d629945 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -189,6 +189,9 @@ extern const struct mps_key_s _mps_key_COMMIT_LIMIT; 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_PAUSE_TIME; +#define MPS_KEY_PAUSE_TIME (&_mps_key_PAUSE_TIME) +#define MPS_KEY_PAUSE_TIME_FIELD d extern const struct mps_key_s _mps_key_EXTEND_BY; #define MPS_KEY_EXTEND_BY (&_mps_key_EXTEND_BY) @@ -457,6 +460,9 @@ extern mps_res_t mps_arena_commit_limit_set(mps_arena_t, size_t); extern void mps_arena_spare_commit_limit_set(mps_arena_t, size_t); extern size_t mps_arena_spare_commit_limit(mps_arena_t); +extern double mps_arena_pause_time(mps_arena_t); +extern void mps_arena_pause_time_set(mps_arena_t, double); + extern mps_bool_t mps_arena_has_addr(mps_arena_t, mps_addr_t); extern mps_bool_t mps_addr_pool(mps_pool_t *, mps_arena_t, mps_addr_t); extern mps_bool_t mps_addr_fmt(mps_fmt_t *, mps_arena_t, mps_addr_t); diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index a6e24f0c63a..785500a4252 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -217,6 +217,25 @@ size_t mps_arena_spare_commit_limit(mps_arena_t arena) return limit; } +double mps_arena_pause_time(mps_arena_t arena) +{ + double pause_time; + + ArenaEnter(arena); + pause_time = ArenaPauseTime(arena); + ArenaLeave(arena); + + return pause_time; +} + +void mps_arena_pause_time_set(mps_arena_t arena, double pause_time) +{ + ArenaEnter(arena); + ArenaSetPauseTime(arena, pause_time); + ArenaLeave(arena); +} + + void mps_arena_clamp(mps_arena_t arena) { ArenaEnter(arena); diff --git a/mps/design/arena.txt b/mps/design/arena.txt index 2a94bb05b39..1d7f412dd86 100644 --- a/mps/design/arena.txt +++ b/mps/design/arena.txt @@ -447,6 +447,17 @@ than the amount of spare committed memory (stored in ``spareCommitExceeded`` is called. +Pause time control +.................. + +_`.pause-time`: The generic arena structure contains the field +``pauseTime`` for the maximum time any operation in the arena may take +before returning to the mutator. This value is used by +``PolicyPollAgain()`` to decide whether to do another unit of tracing +work. The MPS interface provides getter (``mps_arena_pause_time()``) +and setter (``mps_arena_pause_time_set()``) functions. + + Locks ..... diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index f95aaba331e..2e12f215135 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -12,6 +12,14 @@ Release 1.115.0 New features ............ +#. The MPS now provides control over the maximum time that operations + within an arena may pause the :term:`client program` for. This can + be specified by the new function :c:func:`mps_arena_pause_time_set` + or by passing the new keyword argument + :c:macro:`MPS_KEY_PAUSE_TIME` to :c:func:`mps_arena_create_k`. The + current value can be retrieved by the new function + :c:func:`mps_arena_pause_time`. + #. 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 @@ -41,6 +49,7 @@ New features :c:func:`mps_root_create_area_tagged` for areas of memory that can be scanned by area scanning functions. + Interface changes ................. diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index f98de4ba56d..d778681cadf 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -139,7 +139,7 @@ Client arenas * :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type:`size_t`) is its size. - It also accepts two optional keyword arguments: + It also accepts three optional keyword arguments: * :c:macro:`MPS_KEY_COMMIT_LIMIT` (type :c:type:`size_t`) is the maximum amount of memory, in :term:`bytes (1)`, that the MPS @@ -154,6 +154,11 @@ Client arenas granularity reduces overheads, but increases :term:`fragmentation` and :term:`retention`. + * :c:macro:`MPS_KEY_PAUSE_TIME` (type :c:type:`double`, default + 0.0) is the maximum time, in seconds, that operations within the + arena may pause the :term:`client program` for. See + :c:func:`mps_arena_pause_time_set` for details. + For example:: MPS_ARGS_BEGIN(args) { @@ -213,7 +218,7 @@ Virtual memory arenas more efficient. When creating a virtual memory arena, :c:func:`mps_arena_create_k` - accepts four optional :term:`keyword arguments` on all platforms: + accepts five 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 @@ -262,7 +267,12 @@ Virtual memory arenas :term:`bytes (1)`. See :c:func:`mps_arena_spare_commit_limit` for details. - A fifth optional :term:`keyword argument` may be passed, but it + * :c:macro:`MPS_KEY_PAUSE_TIME` (type :c:type:`double`, default + 0.0) is the maximum time, in seconds, that operations within the + arena may pause the :term:`client program` for. See + :c:func:`mps_arena_pause_time_set` for details. + + A sixth 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`, @@ -424,6 +434,59 @@ Arena properties :c:func:`mps_arena_commit_limit`. +.. c:function:: double mps_arena_pause_time(mps_arena_t arena) + + Return the maximum time, in seconds, that operations within the + arena may pause the :term:`client program` for. + + ``arena`` is the arena. + + See :c:func:`mps_arena_pause_time_set` for details. + + +.. c:function:: void mps_arena_pause_time_set(mps_arena_t arena, double pause_time) + + Set the maximum time, in seconds, that operations within an arena + may pause the :term:`client program` for. + + ``arena`` is the arena. + + ``pause_time`` is the new maximum pause time, in seconds. It must + be non-negative. + + The pause time may be set to zero, in which case the MPS returns + as soon as it can do so. The consequence is that the MPS will need + to take more slices of time in order to make :term:`garbage + collection` progress. This value is suitable for interactive + applications where latency needs to be minimized, but where there + is plenty of CPU time available. + + The pause time may be set to infinity, in which case the MPS + completes all outstanding :term:`garbage collection` work before + returning from an operation. The consequence is that the MPS will + be able to save on the overheads due to :term:`incremental + collection`, leading to lower total time spent in collection. This + value is suitable for non-interactive applications where total + time is important. + + The MPS makes a best effort to return to the :term:`client + program` from any operation on the arena within the maximum pause + time, but does not guarantee to do so. This is for three reasons: + + 1. many operations in the MPS necessarily take some minimum amount + time that's logarithmic in the amount of :term:`memory (2)` + being managed (so if you set the maximum pause time to zero, + then every operation will exceed it); + + 2. some operations in the MPS call functions in the :term:`client + program` (for example, the :term:`format methods`), and the MPS + has no control over how long these functions take; + + 3. none of the operating systems supported by the MPS provide + real-time guarantees (for example, the process may have to wait + for :term:`memory (2)` to be :term:`paged in`). + + .. c:function:: size_t mps_arena_reserved(mps_arena_t arena) Return the total :term:`address space` reserved by an diff --git a/mps/manual/source/topic/keyword.rst b/mps/manual/source/topic/keyword.rst index ddbfbfd57ac..396abb92cd8 100644 --- a/mps/manual/source/topic/keyword.rst +++ b/mps/manual/source/topic/keyword.rst @@ -115,6 +115,7 @@ now :c:macro:`MPS_KEY_ARGS_END`. :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_PAUSE_TIME` :c:type:`double` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` :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` From 167408b7e04cc1e0c0576acf43e0c889fc1da80b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Mar 2016 22:08:26 +0000 Subject: [PATCH 232/337] Implement pause time control. Copied from Perforce Change: 189921 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 6 ++--- mps/code/gcbench.c | 14 +++++++++-- mps/code/global.c | 4 +--- mps/code/mpm.h | 2 +- mps/code/policy.c | 39 +++++++++++++++++-------------- mps/design/strategy.txt | 14 ++++++----- mps/manual/source/release.rst | 4 ++++ mps/manual/source/topic/arena.rst | 4 ++-- 8 files changed, 53 insertions(+), 34 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index 5f1aace70c5..adee968a8f6 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -411,10 +411,10 @@ * documentation changes. */ #define ARENA_DEFAULT_SPARE_COMMIT_LIMIT ((Size)10uL*1024uL*1024uL) -/* ARENA_DEFAULT_PAUSE_TIME is the maximum time (in seconds) that the - * arena that operations within the arena may pause the mutator for. */ +/* ARENA_DEFAULT_PAUSE_TIME is the maximum time (in seconds) that + * operations within the arena may pause the mutator for. */ -#define ARENA_DEFAULT_PAUSE_TIME (0.0) +#define ARENA_DEFAULT_PAUSE_TIME (0.1) #define ARENA_DEFAULT_ZONED TRUE diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c index 8624637da4a..67cabfce1b4 100644 --- a/mps/code/gcbench.c +++ b/mps/code/gcbench.c @@ -55,6 +55,7 @@ static size_t arena_size = 256ul * 1024 * 1024; /* arena size */ static size_t arena_grain_size = 1; /* arena grain size */ static unsigned pinleaf = FALSE; /* are leaf objects pinned at start */ static mps_bool_t zoned = TRUE; /* arena allocates using zones */ +static double pause_time = ARENA_DEFAULT_PAUSE_TIME; /* maximum pause time */ typedef struct gcthread_s *gcthread_t; @@ -235,6 +236,7 @@ static void arena_setup(gcthread_fn_t fn, MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, arena_size); MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, arena_grain_size); MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, zoned); + MPS_ARGS_ADD(args, MPS_KEY_PAUSE_TIME, pause_time); RESMUST(mps_arena_create_k(&arena, mps_arena_class_vm(), args)); } MPS_ARGS_END(args); RESMUST(dylan_fmt(&format, arena)); @@ -278,6 +280,7 @@ static struct option longopts[] = { {"pin-leaf", no_argument, NULL, 'l'}, {"seed", required_argument, NULL, 'x'}, {"arena-unzoned", no_argument, NULL, 'z'}, + {"pause-time", required_argument, NULL, 'P'}, {NULL, 0, NULL, 0 } }; @@ -307,7 +310,8 @@ int main(int argc, char *argv[]) { } putchar('\n'); - while ((ch = getopt_long(argc, argv, "ht:i:p:g:m:a:w:d:r:u:lx:z", longopts, NULL)) != -1) + while ((ch = getopt_long(argc, argv, "ht:i:p:g:m:a:w:d:r:u:lx:zP:", + longopts, NULL)) != -1) switch (ch) { case 't': nthreads = (unsigned)strtoul(optarg, NULL, 10); @@ -396,6 +400,9 @@ int main(int argc, char *argv[]) { case 'z': zoned = FALSE; break; + case 'P': + pause_time = strtod(optarg, NULL); + break; default: /* This is printed in parts to keep within the 509 character limit for string literals in portable standard C. */ @@ -441,9 +448,12 @@ int main(int argc, char *argv[]) { fprintf(stderr, " -z, --arena-unzoned\n" " Disable zoned allocation in the arena\n" + " -P t, --pause-time\n" + " Maximum pause time in seconds (default %f) \n" "Tests:\n" " amc pool class AMC\n" - " ams pool class AMS\n"); + " ams pool class AMS\n", + pause_time); return EXIT_FAILURE; } argc -= optind; diff --git a/mps/code/global.c b/mps/code/global.c index fae5b0bb2dd..b00e108e697 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -735,15 +735,13 @@ void (ArenaPoll)(Globals globals) if (moreWork) { workWasDone = TRUE; } - } while (PolicyPollAgain(arena, moreWork, tracedWork)); + } while (PolicyPollAgain(arena, start, moreWork, tracedWork)); /* Don't count time spent checking for work, if there was no work to do. */ if (workWasDone) { ArenaAccumulateTime(arena, start); } - AVER(!PolicyPoll(arena)); - EVENT3(ArenaPoll, arena, start, BOOLOF(workWasDone)); globals->insidePoll = FALSE; diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 1a075129f79..d20c8261acf 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -670,7 +670,7 @@ extern Bool PolicyShouldCollectWorld(Arena arena, double availableTime, Clock now, Clock clocks_per_sec); extern Bool PolicyStartTrace(Trace *traceReturn, Arena arena); extern Bool PolicyPoll(Arena arena); -extern Bool PolicyPollAgain(Arena arena, Bool moreWork, Work tracedWork); +extern Bool PolicyPollAgain(Arena arena, Clock start, Bool moreWork, Work tracedWork); /* Locus interface */ diff --git a/mps/code/policy.c b/mps/code/policy.c index 82709f7376f..112ede4f335 100644 --- a/mps/code/policy.c +++ b/mps/code/policy.c @@ -367,28 +367,33 @@ Bool PolicyPoll(Arena arena) * moreWork and tracedWork are the results of the last call to TracePoll. */ -Bool PolicyPollAgain(Arena arena, Bool moreWork, Work tracedWork) +Bool PolicyPollAgain(Arena arena, Clock start, Bool moreWork, Work tracedWork) { - Globals globals; - double nextPollThreshold; - AVERT(Arena, arena); - globals = ArenaGlobals(arena); UNUSED(tracedWork); - - if (!moreWork) { - /* No more work to do. Sleep until NOW + a bit. */ - nextPollThreshold = globals->fillMutatorSize + ArenaPollALLOCTIME; + + /* Is there more work to do and more time to do it in? */ + if ((moreWork || ArenaEmergency(arena)) + && ClockNow() < start + ArenaPauseTime(arena)) + { + return TRUE; } else { - /* We did one quantum of work; consume one unit of 'time'. */ - nextPollThreshold = globals->pollThreshold + ArenaPollALLOCTIME; + Globals globals = ArenaGlobals(arena); + double nextPollThreshold; + + if (moreWork) { + /* We did one quantum of work; consume one unit of 'time'. */ + nextPollThreshold = globals->pollThreshold + ArenaPollALLOCTIME; + } else { + /* No more work to do. Sleep until NOW + a bit. */ + nextPollThreshold = globals->fillMutatorSize + ArenaPollALLOCTIME; + } + + /* Advance pollThreshold; check: enough precision? */ + AVER(nextPollThreshold > globals->pollThreshold); + globals->pollThreshold = nextPollThreshold; + return FALSE; } - - /* Advance pollThreshold; check: enough precision? */ - AVER(nextPollThreshold > globals->pollThreshold); - globals->pollThreshold = nextPollThreshold; - - return ArenaEmergency(arena) || PolicyPoll(arena); } diff --git a/mps/design/strategy.txt b/mps/design/strategy.txt index 4d989435e88..51b32e9e31a 100644 --- a/mps/design/strategy.txt +++ b/mps/design/strategy.txt @@ -517,16 +517,18 @@ Trace progress _`.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)`` +``Bool PolicyPollAgain(Arena arena, Clock start, Bool moreWork, Work tracedWork)`` _`.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()``. +clock time when the MPS was entered; ``moreWork`` and ``tracedWork`` +are the results of the last call to ``TracePoll()``. -_`.policy.poll.impl`: The implementation balances collection work -against mutator allocation so that there is approximately one call to -``TracePoll()`` for every ``ArenaPollALLOCTIME`` bytes of allocation. +_`.policy.poll.impl`: The implementation keep doing work until either +the maximum pause time is exceeded (see design.mps.arena.pause-time_), +or there is no more work to do. Then it schedules the next collection +so that there is approximately one call to ``TracePoll()`` for every +``ArenaPollALLOCTIME`` bytes of allocation. References diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 2e12f215135..6f4a3ed199a 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -20,6 +20,10 @@ New features current value can be retrieved by the new function :c:func:`mps_arena_pause_time`. + The maximum pause time defaults to 0.1 seconds. For the old + behaviour (whereby the MPS always returned to the :term:`client + program` as soon as possible), set it to zero. + #. 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 diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index d778681cadf..44e14c801c4 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -155,7 +155,7 @@ Client arenas :term:`fragmentation` and :term:`retention`. * :c:macro:`MPS_KEY_PAUSE_TIME` (type :c:type:`double`, default - 0.0) is the maximum time, in seconds, that operations within the + 0.1) is the maximum time, in seconds, that operations within the arena may pause the :term:`client program` for. See :c:func:`mps_arena_pause_time_set` for details. @@ -268,7 +268,7 @@ Virtual memory arenas for details. * :c:macro:`MPS_KEY_PAUSE_TIME` (type :c:type:`double`, default - 0.0) is the maximum time, in seconds, that operations within the + 0.1) is the maximum time, in seconds, that operations within the arena may pause the :term:`client program` for. See :c:func:`mps_arena_pause_time_set` for details. From 586953ef90d78d51df3d50508da1ca210b256e08 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Mar 2016 22:26:28 +0000 Subject: [PATCH 233/337] Field corresponding to "double" id "d". Copied from Perforce Change: 189924 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/keyword.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/manual/source/topic/keyword.rst b/mps/manual/source/topic/keyword.rst index 396abb92cd8..d473c1acec0 100644 --- a/mps/manual/source/topic/keyword.rst +++ b/mps/manual/source/topic/keyword.rst @@ -115,7 +115,7 @@ now :c:macro:`MPS_KEY_ARGS_END`. :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_PAUSE_TIME` :c:type:`double` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` + :c:macro:`MPS_KEY_PAUSE_TIME` :c:type:`double` ``d`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` :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` From d08cfa1892b086306d625d9a8210c02ea1ed1eb3 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Mar 2016 22:56:52 +0000 Subject: [PATCH 234/337] Don't forget to multiply by clockspersec! Copied from Perforce Change: 189927 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 112ede4f335..d0d0a72dfde 100644 --- a/mps/code/policy.c +++ b/mps/code/policy.c @@ -374,7 +374,7 @@ Bool PolicyPollAgain(Arena arena, Clock start, Bool moreWork, Work tracedWork) /* Is there more work to do and more time to do it in? */ if ((moreWork || ArenaEmergency(arena)) - && ClockNow() < start + ArenaPauseTime(arena)) + && (ClockNow() - start) < ArenaPauseTime(arena) * ClocksPerSec()) { return TRUE; } else { From 7ac27197397e6df782095d348ea4f984b75da13b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 13 Mar 2016 01:36:34 +0000 Subject: [PATCH 235/337] Turn on keyword expansion. Copied from Perforce Change: 189936 ServerID: perforce.ravenbrook.com --- mps/code/airtest.c | 6 +++--- mps/code/fmtscheme.c | 6 +++--- mps/code/fmtscheme.h | 6 +++--- mps/code/nailboardtest.c | 6 +++--- mps/code/prot.h | 6 +++--- mps/code/sp.h | 6 +++--- mps/code/tagtest.c | 4 ++-- mps/code/testthr.h | 6 +++--- mps/code/testthrix.c | 6 +++--- mps/code/testthrw3.c | 6 +++--- mps/design/clock.txt | 2 +- mps/design/exec-env.txt | 2 +- mps/design/guide.review.txt | 2 +- 13 files changed, 32 insertions(+), 32 deletions(-) diff --git a/mps/code/airtest.c b/mps/code/airtest.c index ad0ec456b99..8b5a6ac8a5c 100644 --- a/mps/code/airtest.c +++ b/mps/code/airtest.c @@ -1,7 +1,7 @@ /* airtest.c: AMBIGUOUS INTERIOR REFERENCE TEST * - * $Id: //info.ravenbrook.com/project/mps/branch/2014-01-15/nailboard/code/fotest.c#1 $ - * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * $Id$ + * Copyright (c) 2014-2016 Ravenbrook Limited. See end of file for license. * * .overview: This test case creates a bunch of vectors, registers * them for finalization, and then discards the base pointers to those @@ -163,7 +163,7 @@ int main(int argc, char *argv[]) /* C. COPYRIGHT AND LICENSE * - * Copyright (c) 2014 Ravenbrook Limited . + * Copyright (c) 2014-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/fmtscheme.c b/mps/code/fmtscheme.c index 24fa06db871..979672c9de3 100644 --- a/mps/code/fmtscheme.c +++ b/mps/code/fmtscheme.c @@ -1,7 +1,7 @@ /* fmtscheme.c: SCHEME OBJECT FORMAT IMPLEMENTATION * - * $Id: //info.ravenbrook.com/project/mps/branch/2014-01-15/nailboard/code/fmtdy.c#1 $ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * $Id$ + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. */ #include @@ -460,7 +460,7 @@ void scheme_fmt(mps_fmt_t *fmt) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/fmtscheme.h b/mps/code/fmtscheme.h index 1149d9496a1..92d4c270bb6 100644 --- a/mps/code/fmtscheme.h +++ b/mps/code/fmtscheme.h @@ -1,7 +1,7 @@ /* fmtscheme.h: SCHEME OBJECT FORMAT INTERFACE * - * $Id: //info.ravenbrook.com/project/mps/branch/2014-01-15/nailboard/code/fmtdy.h#1 $ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * $Id$ + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. */ #ifndef fmtscheme_h @@ -193,7 +193,7 @@ extern mps_ap_t obj_ap; /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/nailboardtest.c b/mps/code/nailboardtest.c index e1c071f3ac1..aae9dc7be32 100644 --- a/mps/code/nailboardtest.c +++ b/mps/code/nailboardtest.c @@ -1,7 +1,7 @@ /* nailboardtest.c: NAILBOARD TEST * - * $Id: //info.ravenbrook.com/project/mps/branch/2014-01-15/nailboard/code/fotest.c#1 $ - * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * $Id$ + * Copyright (c) 2014-2016 Ravenbrook Limited. See end of file for license. * */ @@ -73,7 +73,7 @@ int main(int argc, char **argv) /* C. COPYRIGHT AND LICENSE * - * Copyright (c) 2014 Ravenbrook Limited . + * Copyright (c) 2014-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/prot.h b/mps/code/prot.h index f3104cb27b7..18b89361682 100644 --- a/mps/code/prot.h +++ b/mps/code/prot.h @@ -1,7 +1,7 @@ /* prot.h: MEMORY PROTECTION INTERFACE * - * $Id: //info.ravenbrook.com/project/mps/master/code/prot.h#1 $ - * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * $Id$ + * Copyright (c) 2014-2016 Ravenbrook Limited. See end of file for license. * * See for the design of the generic interface including * the contracts for these functions. @@ -40,7 +40,7 @@ extern Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc, /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2014 Ravenbrook Limited . + * Copyright (C) 2014-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/sp.h b/mps/code/sp.h index e2a8bef4507..e1c2e12de06 100644 --- a/mps/code/sp.h +++ b/mps/code/sp.h @@ -1,7 +1,7 @@ /* sp.h: STACK PROBE INTERFACE * - * $Id: //info.ravenbrook.com/project/mps/master/code/sp.h#1 $ - * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * $Id$ + * Copyright (c) 2014-2016 Ravenbrook Limited. See end of file for license. */ #ifndef sp_h @@ -29,7 +29,7 @@ extern void StackProbe(Size depth); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2014 Ravenbrook Limited . + * Copyright (C) 2014-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/tagtest.c b/mps/code/tagtest.c index fda27efd9b7..62df8ee2b1d 100644 --- a/mps/code/tagtest.c +++ b/mps/code/tagtest.c @@ -1,7 +1,7 @@ /* tagtest.c: TAGGED POINTER TEST * * $Id$ - * Copyright (c) 2015 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2015-2016 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 tagged area scanning. @@ -267,7 +267,7 @@ int main(int argc, char *argv[]) /* C. COPYRIGHT AND LICENSE * - * Copyright (c) 2015 Ravenbrook Limited . + * Copyright (c) 2015-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/testthr.h b/mps/code/testthr.h index 75602bcc56f..3edceda068c 100644 --- a/mps/code/testthr.h +++ b/mps/code/testthr.h @@ -1,7 +1,7 @@ /* testthr.h: MULTI-THREADED TEST INTERFACE * - * $Id: //info.ravenbrook.com/project/mps/master/code/testlib.h#30 $ - * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * $Id$ + * Copyright (c) 2014-2016 Ravenbrook Limited. See end of file for license. * * .purpose: Simple interface to threads that makes it possible to * write test cases that are portable between Windows (using the @@ -83,7 +83,7 @@ void testthr_join(testthr_t *thread, void **result_o); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2014 Ravenbrook Limited . + * Copyright (C) 2014-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/testthrix.c b/mps/code/testthrix.c index f4c544e0b8a..90849158b2d 100644 --- a/mps/code/testthrix.c +++ b/mps/code/testthrix.c @@ -1,7 +1,7 @@ /* testthrix.c: MULTI-THREADED TEST IMPLEMENTATION (POSIX THREADS) * - * $Id: //info.ravenbrook.com/project/mps/master/code/testlib.h#30 $ - * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * $Id$ + * Copyright (c) 2014-2016 Ravenbrook Limited. See end of file for license. */ #include "testlib.h" @@ -26,7 +26,7 @@ void testthr_join(testthr_t *thread, void **result_o) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2014 Ravenbrook Limited . + * Copyright (C) 2014-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/testthrw3.c b/mps/code/testthrw3.c index cd5cf54ae79..db7fc88709a 100644 --- a/mps/code/testthrw3.c +++ b/mps/code/testthrw3.c @@ -1,7 +1,7 @@ /* testthrw3.c: MULTI-THREADED TEST IMPLEMENTATION (WINDOWS) * - * $Id: //info.ravenbrook.com/project/mps/master/code/testlib.h#30 $ - * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * $Id$ + * Copyright (c) 2014-2016 Ravenbrook Limited. See end of file for license. */ #include "testlib.h" @@ -40,7 +40,7 @@ void testthr_join(testthr_t *thread, void **result_o) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2014 Ravenbrook Limited . + * Copyright (C) 2014-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/design/clock.txt b/mps/design/clock.txt index 9cb4c683049..d9b73d43081 100644 --- a/mps/design/clock.txt +++ b/mps/design/clock.txt @@ -7,7 +7,7 @@ Fast high-resolution clock :Author: Gareth Rees :Date: 2016-03-06 :Status: complete design -:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/abq.txt#5 $ +:Revision: $Id$ :Copyright: See section `Copyright and License`_. :Index terms: pair: clock; design diff --git a/mps/design/exec-env.txt b/mps/design/exec-env.txt index 65de1dd228f..29576212b4a 100644 --- a/mps/design/exec-env.txt +++ b/mps/design/exec-env.txt @@ -149,7 +149,7 @@ Document History Copyright and License --------------------- -Copyright © 1996-2015 Ravenbrook Limited. All rights reserved. +Copyright © 1996-2016 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/guide.review.txt b/mps/design/guide.review.txt index b1298b26b90..4bed3049842 100644 --- a/mps/design/guide.review.txt +++ b/mps/design/guide.review.txt @@ -56,7 +56,7 @@ Document History Copyright and License --------------------- -Copyright © 2015 Ravenbrook Limited. All rights reserved. +Copyright © 2015-2016 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. From 40dadc912b523a54b9eb08675186a45475990186 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 13 Mar 2016 11:10:00 +0000 Subject: [PATCH 236/337] Branching master to branch/2016-03-13/defer-write-barrier. Copied from Perforce Change: 189939 ServerID: perforce.ravenbrook.com From c2e71054c9a94fe4939c2d0d59de9af16bda9c15 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 13 Mar 2016 11:42:32 +0000 Subject: [PATCH 237/337] Speed up more mmqa test cases. on my laptop, the whole mmqa test suite (or at least the passing subset) now takes 5 minutes in the hot variety and 11 minutes in the cool variety. Copied from Perforce Change: 189947 ServerID: perforce.ravenbrook.com --- mps/test/function/104.c | 7 ++++--- mps/test/function/109.c | 22 +++++++++++----------- mps/test/function/113.c | 7 ++++--- mps/test/function/114.c | 2 +- mps/test/function/124.c | 11 +++++------ mps/test/function/125.c | 6 +++++- mps/test/function/127.c | 13 ++++++------- mps/test/function/128.c | 11 +++++------ mps/test/function/129.c | 13 ++++++------- mps/test/function/134.c | 13 ++++++------- mps/test/function/223.c | 11 +++++------ mps/test/function/226.c | 2 +- mps/test/function/30.c | 7 ++++--- mps/test/function/35.c | 5 +++-- mps/test/function/36.c | 6 +----- mps/test/function/41.c | 8 ++++---- mps/test/function/42.c | 8 ++++---- mps/test/function/43.c | 10 +++++----- mps/test/function/44.c | 14 +++++++------- mps/test/function/45.c | 4 ++-- mps/test/function/48.c | 12 ++++++------ mps/test/function/49.c | 8 ++++---- mps/test/function/55.c | 21 +++++++++++---------- mps/test/function/60.c | 4 ++-- mps/test/function/61.c | 5 +++-- mps/test/function/77.c | 2 +- mps/test/function/78.c | 21 +++++++++++---------- mps/test/function/96.c | 18 ++++++------------ mps/test/function/97.c | 5 +++-- mps/test/function/99.c | 4 ++-- mps/test/testsets/passing | 2 +- 31 files changed, 139 insertions(+), 143 deletions(-) diff --git a/mps/test/function/104.c b/mps/test/function/104.c index 6faba1afab9..f5ac595dcfe 100644 --- a/mps/test/function/104.c +++ b/mps/test/function/104.c @@ -4,6 +4,7 @@ TEST_HEADER summary = test of mps_arena_formatted_objects_walk, inc AMCZ language = c link = testlib.o rankfmt.o + parameters = VERBOSE=0 END_HEADER some kinds of errors that could occur in the walker: @@ -98,7 +99,7 @@ static void stepper(mps_addr_t addr, mps_fmt_t fmt, mps_pool_t pool, appcount += 1; asserts(a->data.checkedflag != newstamp, "III/IV. step on object again at %p", a); - commentif(a->data.checkedflag != oldstamp, + commentif(VERBOSE && a->data.checkedflag != oldstamp, "*. step on unreachable object at %p", a); asserts(oldstamp - a->data.checkedflag < 3, "IV. unreachable object %d stayed alive at %p", a->data.id, a); @@ -169,9 +170,9 @@ static void test(void) for (j=0; j<100; j++) { - comment("%i of 100", j); + comment("%i of 100", j+1); - for (i=0; i<10000; i++) { + for (i=0; i<1000; i++) { k = ranint(4); die(allocrdumb(&a[k], aplo, 64, mps_rank_exact()), "alloc failed"); a[k]->data.checkedflag = newstamp; diff --git a/mps/test/function/109.c b/mps/test/function/109.c index bccb5cfec7f..b92ad2ff0ef 100644 --- a/mps/test/function/109.c +++ b/mps/test/function/109.c @@ -121,19 +121,19 @@ static void finalpoll(mycell **ref, int faction) static void test(void) { - mps_pool_t poolamc, poolawl, poollo; + mps_pool_t poolamc, poolawl, poolamcz; mps_thr_t thread; mps_root_t root0, root1; mps_fmt_t format; mps_chain_t chain; - mps_ap_t apamc, apawl, aplo; + mps_ap_t apamc, apawl, apamcz; mycell *a, *b, *c, *d, *z; long int j; - cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t)1024*1024*30), + cdie(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); @@ -157,7 +157,7 @@ static void test(void) cdie(mps_pool_create(&poolawl, arena, mps_class_awl(), format, getassociated), "create pool(awl)"); - cdie(mmqa_pool_create_chain(&poollo, arena, mps_class_amcz(), format, chain), + cdie(mmqa_pool_create_chain(&poolamcz, arena, mps_class_amcz(), format, chain), "create pool(amcz)"); cdie(mps_ap_create(&apawl, poolawl, mps_rank_weak()), @@ -166,7 +166,7 @@ static void test(void) cdie(mps_ap_create(&apamc, poolamc, mps_rank_exact()), "create ap(amc)"); - cdie(mps_ap_create(&aplo, poollo, mps_rank_exact()), + cdie(mps_ap_create(&apamcz, poolamcz, mps_rank_exact()), "create ap(amcz)"); mps_message_type_enable(arena, mps_message_type_finalization()); @@ -179,7 +179,7 @@ static void test(void) for (j=0; j<1000; j++) { a = allocone(apamc, 2, mps_rank_exact()); c = allocone(apawl, 2, mps_rank_weak()); - d = allocone(aplo, 2, mps_rank_exact()); /* rank irrelevant here! */ + d = allocone(apamcz, 2, mps_rank_exact()); /* rank irrelevant here! */ mps_finalize(arena, (mps_addr_t*)&a); mps_finalize(arena, (mps_addr_t*)&c); mps_finalize(arena, (mps_addr_t*)&d); @@ -211,7 +211,7 @@ static void test(void) /* now to test leaving messages open for a long time! */ for (j=0; j<1000; j++) { - comment("%d of 1000", j); + comment("%d of 1000", j+1); a = allocone(apamc, 10000, mps_rank_exact()); mps_finalize(arena, (mps_addr_t*)&a); final_count +=1; @@ -222,7 +222,7 @@ static void test(void) comment("reregister"); for (j=0; j<500; j++) { - comment("%d of 500", j); + comment("%d of 500", j+1); qpoll(&z, FINAL_REREGISTER); } @@ -230,7 +230,7 @@ static void test(void) z = a; for (j=0; j<1000; j++) { - comment("%d of 1000", j); + comment("%d of 1000", j+1); finalpoll(&z, FINAL_QUEUE); qpoll(&z, FINAL_STORE); a = allocone(apamc, 2, mps_rank_exact()); @@ -270,12 +270,12 @@ static void test(void) mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); - mps_ap_destroy(aplo); + mps_ap_destroy(apamcz); comment("Destroyed aps."); mps_pool_destroy(poolamc); mps_pool_destroy(poolawl); - mps_pool_destroy(poollo); + mps_pool_destroy(poolamcz); comment("Destroyed pools."); mps_chain_destroy(chain); diff --git a/mps/test/function/113.c b/mps/test/function/113.c index a897c7fb60a..107ec68578a 100644 --- a/mps/test/function/113.c +++ b/mps/test/function/113.c @@ -4,6 +4,7 @@ TEST_HEADER summary = AWL and AWL performance language = c link = testlib.o fastfmt.o + parameters = ITERATIONS=10 END_HEADER */ @@ -73,9 +74,9 @@ static void test(void) b = allocone(apamc, 1, mps_rank_exact()); - for (j=1; j<=10; j++) + for (j=1; j<=ITERATIONS; j++) { - comment("%i of 10.", j); + comment("%i of %i.", j, ITERATIONS); a = allocone(apamc, 5, mps_rank_exact()); b = a; c = a; @@ -84,7 +85,7 @@ static void test(void) f = a; g = a; - for (i=1; i<5000; i++) + for (i=1; i<=1000; i++) { c = allocone(apamc, 20, mps_rank_exact()); d = allocone(apawl, 20, mps_rank_exact()); diff --git a/mps/test/function/114.c b/mps/test/function/114.c index c273f30cd52..f2f1b022bbf 100644 --- a/mps/test/function/114.c +++ b/mps/test/function/114.c @@ -84,7 +84,7 @@ static void test(void) f = a; g = a; - for (i=1; i<5000; i++) + for (i=0; i<1000; i++) { c = allocone(apamc, 20, mps_rank_exact()); d = allocone(apawl, 20, mps_rank_exact()); diff --git a/mps/test/function/124.c b/mps/test/function/124.c index cb4620b49de..dae58c55624 100644 --- a/mps/test/function/124.c +++ b/mps/test/function/124.c @@ -4,6 +4,7 @@ TEST_HEADER summary = test of ramp allocation language = c link = testlib.o rankfmt.o + parameters = ITERATIONS=50000 OUTPUT_SPEC result = pass END_HEADER @@ -22,16 +23,14 @@ static mps_gen_param_s testChain[genCOUNT] = { #define ARENALIMIT (200) -#define TABSIZE (50000) -#define ENTERRAMP (30000) -#define LEAVERAMP (100000) +#define TABSIZE (ITERATIONS / 2) +#define ENTERRAMP (ITERATIONS / 10) +#define LEAVERAMP (ITERATIONS / 10) #define BACKSIZE (128) #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (100000ul) - #define RAMP_INTERFACE /* #define COLLECT_WORLD @@ -99,7 +98,7 @@ static void test(void) /* the compiler doesn't know this. */ for (i = 0; i < ITERATIONS; i++) { - if (i % 10000 == 0) { + if (i * 10 % ITERATIONS == 0) { comment("%ld of %ld", i, ITERATIONS); } alloc_back(); diff --git a/mps/test/function/125.c b/mps/test/function/125.c index 1ca2f61fe4a..52f06f91ec9 100644 --- a/mps/test/function/125.c +++ b/mps/test/function/125.c @@ -66,9 +66,12 @@ static void test(void) /* allocate lots of little objects */ - while (mps_arena_committed(arena) < 1024ul*1024ul*20) { + for (;;) { comment("reserved %ld, committed %ld", mps_arena_reserved(arena), mps_arena_committed(arena)); + if (mps_arena_committed(arena) > 1024ul*1024ul*10) { + break; + } for (j=0; j<10000; j++) { a = allocone(ap, 2, mps_rank_exact()); setref(a, 0, b); @@ -77,6 +80,7 @@ static void test(void) setref(b, 1, a); } mps_arena_collect(arena); + mps_arena_release(arena); } mps_arena_park(arena); diff --git a/mps/test/function/127.c b/mps/test/function/127.c index 55c67961987..7ab03a0f69e 100644 --- a/mps/test/function/127.c +++ b/mps/test/function/127.c @@ -4,6 +4,7 @@ TEST_HEADER summary = test of ramp allocation -- with collect world instead of ramps language = c link = testlib.o rankfmt.o + parameters = ITERATIONS=50000 OUTPUT_SPEC result = pass END_HEADER @@ -16,16 +17,14 @@ END_HEADER #define ARENALIMIT (200) -#define TABSIZE (50000) -#define ENTERRAMP (30000) -#define LEAVERAMP (100000) +#define TABSIZE (ITERATIONS / 2) +#define ENTERRAMP (ITERATIONS / 10) +#define LEAVERAMP (ITERATIONS / 10) #define BACKSIZE (128) #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (100000ul) - /* #define RAMP_INTERFACE */ @@ -99,8 +98,8 @@ static void test(void) { inramp = 0; for (i = 0; i < ITERATIONS; i++) { - if (i % 10000 == 0) { - comment("%ld of %ld", i, ITERATIONS); + if (i * 10 % ITERATIONS == 0) { + comment("%ld of %ld", i+1, ITERATIONS); } alloc_back(); if (inramp) { diff --git a/mps/test/function/128.c b/mps/test/function/128.c index 6414e41d976..a2c59850ee0 100644 --- a/mps/test/function/128.c +++ b/mps/test/function/128.c @@ -4,6 +4,7 @@ TEST_HEADER summary = test of ramp allocation -- no collect world or ramps language = c link = testlib.o rankfmt.o + parameters = ITERATIONS=50000 OUTPUT_SPEC result = pass END_HEADER @@ -16,16 +17,14 @@ END_HEADER #define ARENALIMIT (200) -#define TABSIZE (50000) -#define ENTERRAMP (30000) -#define LEAVERAMP (100000) +#define TABSIZE (ITERATIONS / 2) +#define ENTERRAMP (ITERATIONS / 10) +#define LEAVERAMP (ITERATIONS / 10) #define BACKSIZE (128) #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (100000ul) - /* #define RAMP_INTERFACE #define COLLECT_WORLD @@ -99,7 +98,7 @@ static void test(void) { inramp = 0; for (i = 0; i < ITERATIONS; i++) { - if (i % 10000 == 0) { + if (i * 10 % ITERATIONS == 0) { comment("%ld of %ld", i, ITERATIONS); } alloc_back(); diff --git a/mps/test/function/129.c b/mps/test/function/129.c index 94512cf6e16..eb94f3f7e20 100644 --- a/mps/test/function/129.c +++ b/mps/test/function/129.c @@ -4,6 +4,7 @@ TEST_HEADER summary = test of ramp allocation with small arena language = c link = testlib.o rankfmt.o + parameters = ITERATIONS=10000 OUTPUT_SPEC result = pass END_HEADER @@ -16,16 +17,14 @@ END_HEADER #define ARENALIMIT (2) -#define TABSIZE (50000) -#define ENTERRAMP (30000) -#define LEAVERAMP (100000) +#define TABSIZE (ITERATIONS * 5 / 10) +#define ENTERRAMP (ITERATIONS / 10) +#define LEAVERAMP (ITERATIONS / 10) #define BACKSIZE (128) #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (100000ul) - #define RAMP_INTERFACE /* #define COLLECT_WORLD @@ -43,7 +42,7 @@ mps_pool_t poolamc; mps_thr_t thread; mps_root_t root, root1; - mps_chain_t chain; +mps_chain_t chain; mps_fmt_t format; mps_ap_t apamc; @@ -98,7 +97,7 @@ static void test(void) { inramp = 0; for (i = 0; i < ITERATIONS; i++) { - if (i % 10000 == 0) { + if (i * 10 % ITERATIONS == 0) { comment("%ld of %ld", i, ITERATIONS); } alloc_back(); diff --git a/mps/test/function/134.c b/mps/test/function/134.c index 5eee39e5c4f..bc29777ddf1 100644 --- a/mps/test/function/134.c +++ b/mps/test/function/134.c @@ -4,6 +4,7 @@ TEST_HEADER summary = test of ramp allocation with smallish arena (64MB) language = c link = testlib.o rankfmt.o + parameters = ITERATIONS=50000 OUTPUT_SPEC result = pass END_HEADER @@ -16,16 +17,14 @@ END_HEADER #define ARENALIMIT (64) -#define TABSIZE (50000) -#define ENTERRAMP (30000) -#define LEAVERAMP (100000) +#define TABSIZE (ITERATIONS / 2) +#define ENTERRAMP (ITERATIONS / 10) +#define LEAVERAMP (ITERATIONS / 10) #define BACKSIZE (128) #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (100000ul) - #define RAMP_INTERFACE /* #define COLLECT_WORLD @@ -43,7 +42,7 @@ mps_pool_t poolamc; mps_thr_t thread; mps_root_t root, root1; - mps_chain_t chain; +mps_chain_t chain; mps_fmt_t format; mps_ap_t apamc; @@ -99,7 +98,7 @@ static void test(void) { inramp = 0; for (i = 0; i < ITERATIONS; i++) { - if (i % 10000 == 0) { + if (i * 10 % ITERATIONS == 0) { comment("%ld of %ld", i, ITERATIONS); } alloc_back(); diff --git a/mps/test/function/223.c b/mps/test/function/223.c index 6a402d1c831..6fb7a4357fa 100644 --- a/mps/test/function/223.c +++ b/mps/test/function/223.c @@ -4,6 +4,7 @@ TEST_HEADER summary = test of ramp allocation language = c link = testlib.o rankfmt.o + parameters = ITERATIONS=50000 OUTPUT_SPEC result = pass END_HEADER @@ -16,16 +17,14 @@ END_HEADER #define ARENALIMIT (200) -#define TABSIZE (50000) -#define ENTERRAMP (30000) -#define LEAVERAMP (100000) +#define TABSIZE (ITERATIONS / 2) +#define ENTERRAMP (ITERATIONS / 10) +#define LEAVERAMP (ITERATIONS / 10) #define BACKSIZE (128) #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (100000ul) - #define RAMP_INTERFACE /* #define COLLECT_WORLD @@ -102,7 +101,7 @@ static void test(void) { inramp = 0; for (i = 0; i < ITERATIONS; i++) { - if (i % 10000 == 0) { + if (i * 10 % ITERATIONS == 0) { comment("%ld of %ld", i, ITERATIONS); } alloc_back(); diff --git a/mps/test/function/226.c b/mps/test/function/226.c index 185a4b97298..ea6607498a2 100644 --- a/mps/test/function/226.c +++ b/mps/test/function/226.c @@ -5,7 +5,7 @@ TEST_HEADER language = c link = testlib.o rankfmt.o harness = 3.0 - parameters = MAXLDS=1000 MAXMERGE=100 BLATPERCENT=90 JUNK=100 AMBIGHOLD=900 + parameters = MAXLDS=1000 MAXMERGE=20 BLATPERCENT=90 JUNK=100 AMBIGHOLD=900 END_HEADER */ diff --git a/mps/test/function/30.c b/mps/test/function/30.c index 583429d8bc2..416c41323ff 100644 --- a/mps/test/function/30.c +++ b/mps/test/function/30.c @@ -4,6 +4,7 @@ TEST_HEADER summary = test my format for checking the graph language = c link = testlib.o awlfmt.o + parameters = ITERATIONS=50 END_HEADER */ @@ -48,8 +49,8 @@ static void test(void) cdie(mps_ap_create(&ap, pool, mps_rank_exact()), "create ap"); - for (j = 1; j < 100; j++) { - comment("%i of 100.", j); + for (j = 1; j <= ITERATIONS; j++) { + comment("%i of %i.", j, ITERATIONS); UC; a = allocone(ap, 5, 1); b = a; @@ -59,7 +60,7 @@ static void test(void) f = a; g = a; - for (i = 1; i < 100; i++) { + for (i = 0; i < 100; i++) { UC; c = allocone(ap, 1000, 1); if (ranint(8) == 0) d = c; diff --git a/mps/test/function/35.c b/mps/test/function/35.c index 42def83780a..1e441c5ec58 100644 --- a/mps/test/function/35.c +++ b/mps/test/function/35.c @@ -4,6 +4,7 @@ TEST_HEADER summary = provoke segsummary assertion (request.dylan.170450) language = c link = testlib.o awlfmt.o + parameters = ITERATIONS=10 END_HEADER */ @@ -67,9 +68,9 @@ static void test(void) mps_ap_create(&ap, pool, mps_rank_exact()), "create ap"); - for (j=1; j<100; j++) + for (j=1; j<=ITERATIONS; j++) { - comment("%i of 100.", j); + comment("%i of %i.", j, ITERATIONS); UC; *a = allocone(ap, 5, 1); *b = *a; diff --git a/mps/test/function/36.c b/mps/test/function/36.c index 609d9f9210b..c3f0de5961e 100644 --- a/mps/test/function/36.c +++ b/mps/test/function/36.c @@ -40,10 +40,6 @@ static void test(void) int j; int k,z; - alloccomments = 1; - skipcomments = 1; - formatcomments = 1; - cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -76,7 +72,7 @@ static void test(void) for(i=0; i<10000; i++) { j = ranint(100); - k = 5 + ranint(500); + k = 5 + ranint(100); if (ranint(2)==1) { apran = apawl; } else { diff --git a/mps/test/function/41.c b/mps/test/function/41.c index 8fcdb372a6d..98ef3a51d46 100644 --- a/mps/test/function/41.c +++ b/mps/test/function/41.c @@ -71,7 +71,7 @@ static void test(void) b = allocone(apamc, 1, 1); - for (j=1; j<10; j++) { + for (j=1; j<=10; j++) { comment("%i of 10.", j); UC; a = allocone(apawl, 5, 1); @@ -84,10 +84,10 @@ static void test(void) f = a; g = a; - for (i=1; i<1000; i++) { + for (i=0; i<100; i++) { UC; - c = allocone(apamc, 10000, 1); - c = allocone(apawl, 10000, 1); + c = allocone(apamc, 1000, 1); + c = allocone(apawl, 1000, 1); c->data.assoc = stackpointer; if (ranint(8) == 0) d = c; if (ranint(8) == 0) e = c; diff --git a/mps/test/function/42.c b/mps/test/function/42.c index b56a61f2a09..85810297675 100644 --- a/mps/test/function/42.c +++ b/mps/test/function/42.c @@ -69,7 +69,7 @@ static void test(void) b = allocone(apamc, 1, 1); - for (j=1; j<10; j++) { + for (j=1; j<=10; j++) { comment("%i of 10.", j); UC; a = allocone(apawl, 5, 1); @@ -81,10 +81,10 @@ static void test(void) f = a; g = a; - for (i=1; i<1000; i++) { + for (i=0; i<1000; i++) { UC; - c = allocone(apamc, 100, 1); - c = allocone(apawl, 100, 1); + c = allocone(apamc, 50, 1); + c = allocone(apawl, 50, 1); if (ranint(8) == 0) d = c; if (ranint(8) == 0) e = c; if (ranint(8) == 0) f = c; diff --git a/mps/test/function/43.c b/mps/test/function/43.c index 1b955f268b7..106b7b7e10f 100644 --- a/mps/test/function/43.c +++ b/mps/test/function/43.c @@ -73,7 +73,7 @@ static void test(void) b = allocone(apamc, 1, 1); - for (j=1; j<10; j++) { + for (j=1; j<=10; j++) { comment("%i of 10.", j); UC; a = allocone(apexact, 5, 1); @@ -85,13 +85,13 @@ static void test(void) f = a; g = a; - for (i=1; i<1000; i++) { + for (i=0; i<1000; i++) { UC; - c = allocone(apamc, 1000, 0); + c = allocone(apamc, 50, 0); if (ranint(2) == 0) { - c = allocone(apweak, 100, 1); + c = allocone(apweak, 50, 1); } else { - c = allocone(apexact, 100, 1); + c = allocone(apexact, 50, 1); } if (ranint(8) == 0) d = c; if (ranint(8) == 0) e = c; diff --git a/mps/test/function/44.c b/mps/test/function/44.c index f38e36a06e0..e99717e0230 100644 --- a/mps/test/function/44.c +++ b/mps/test/function/44.c @@ -81,7 +81,7 @@ static void test(void) b = allocone(apamc, 1, 1); - for (j=1; j<10; j++) { + for (j=1; j<=10; j++) { comment("%i of 10.", j); a = allocone(apawl, 5, 1); setref(b, 0, a); @@ -91,14 +91,14 @@ static void test(void) e = a; f = a; g = a; - for (i=1; i<1000; i++) { + for (i=1; i<=1000; i++) { if (i%100 == 0) { comment(" %i", i); } if (ranint(2)) { - c = allocone(apamc, 1000, 1); + c = allocone(apamc, 100, 1); } else { - c = allocone(apawl, 1000, 1); + c = allocone(apawl, 100, 1); } if (ranint(8) == 0) d = c; if (ranint(8) == 0) e = c; @@ -129,14 +129,14 @@ static void test(void) comment("clamping..."); mps_arena_park(arena); RC; - for (i=1; i<1000; i++) { + for (i=1; i<=1000; i++) { if (i%100 == 0) { comment(" %i", i); } if (ranint(2)) { - c = allocone(apamc, 1000, 1); + c = allocone(apamc, 100, 1); } else { - c = allocone(apawl, 1000, 1); + c = allocone(apawl, 100, 1); } if (ranint(8) == 0) d = c; if (ranint(8) == 0) e = c; diff --git a/mps/test/function/45.c b/mps/test/function/45.c index ec673c595b6..8001b47f362 100644 --- a/mps/test/function/45.c +++ b/mps/test/function/45.c @@ -4,7 +4,7 @@ TEST_HEADER summary = arena_collect when lots of APs are in mid-cycle language = c link = testlib.o newfmt.o - parameters = VERBOSE=0 NCELLS 100 NAPS=100 ITERATIONS=100 + parameters = VERBOSE=0 NCELLS=100 NAPS=100 ITERATIONS=10 END_HEADER */ @@ -184,7 +184,7 @@ static void test(void) commentif(VERBOSE, "%i begin commit", i); ap[i]->init = ap[i]->alloc; case 3: - commentif(VERBOSE, "% end commit", i); + commentif(VERBOSE, "%i end commit", i); (void) (ap[i]->limit != 0 || mps_ap_trip(ap[i], p[i], s[i])); } mps_ap_destroy(ap[i]); diff --git a/mps/test/function/48.c b/mps/test/function/48.c index 3343684fdbf..cdc1c66737f 100644 --- a/mps/test/function/48.c +++ b/mps/test/function/48.c @@ -41,7 +41,7 @@ static void test(void) RC; - cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), + cdie(mps_arena_create(&arena, mps_arena_class_vm(), 1ul<<30), "create arena"); die(mps_thread_reg(&thread, arena), "register thread"); @@ -73,7 +73,7 @@ static void test(void) b = allocone(apamc, 1, 1); - for (j=1; j<10; j++) { + for (j=1; j<=10; j++) { comment("%i of 10.", j); UC; a = allocone(apawl, 5, mps_rank_exact()); @@ -85,14 +85,14 @@ static void test(void) f = a; g = a; - for (i=1; i<1000; i++) { + for (i=1; i<=1000; i++) { UC; if (ranint(3) == 0) { - c = allocone(apawl, 500, mps_rank_exact()); + c = allocone(apawl, 100, mps_rank_exact()); } else if (ranint(2) == 0) { - c = allocone(apweak, 500, mps_rank_weak()); + c = allocone(apweak, 100, mps_rank_weak()); } else { - c = allocone(apamc, 500, mps_rank_exact()); + c = allocone(apamc, 100, mps_rank_exact()); } if (ranint(8) == 0) d = c; if (ranint(8) == 0) e = c; diff --git a/mps/test/function/49.c b/mps/test/function/49.c index 27864e380e9..b7db41d475d 100644 --- a/mps/test/function/49.c +++ b/mps/test/function/49.c @@ -135,7 +135,7 @@ static void test(void) long int j; - cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t)1024*1024*30), + cdie(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); @@ -217,7 +217,7 @@ static void test(void) for (j=0; j<1000; j++) { if (j % 50 == 0) - comment("%d of 1000", j); + comment("%d of 1000", j+1); a = allocone(apamc, 10000, mps_rank_exact()); mps_finalize(arena, (mps_addr_t*)&a); final_count +=1; @@ -228,7 +228,7 @@ static void test(void) comment("reregister"); for (j=0; j<500; j++) { - comment("%d of 500", j); + comment("%d of 500", j+1); qpoll(&z, FINAL_REREGISTER); } @@ -236,7 +236,7 @@ static void test(void) z = a; for (j=0; j<1000; j++) { - comment("%d of 1000", j); + comment("%d of 1000", j+1); finalpoll(&z, FINAL_QUEUE); qpoll(&z, FINAL_STORE); a = allocone(apamc, 2, mps_rank_exact()); diff --git a/mps/test/function/55.c b/mps/test/function/55.c index f34a2fb1856..a5a4d3e5f07 100644 --- a/mps/test/function/55.c +++ b/mps/test/function/55.c @@ -4,6 +4,7 @@ TEST_HEADER summary = use AMC and LO without inactive LO pool language = c link = testlib.o awlfmt.o + parameters = ITERATIONS=10 END_HEADER */ @@ -26,13 +27,13 @@ void *stackpointer; static void test(void) { mps_arena_t arena; - mps_pool_t poolamc, poolawl; + mps_pool_t poolamc, poollo; mps_thr_t thread; mps_root_t root; mps_fmt_t format; mps_chain_t chain; - mps_ap_t apamc, apawl; + mps_ap_t apamc, aplo; mycell *a, *b, *c, *d, *e, *f, *g; @@ -56,11 +57,11 @@ static void test(void) "create pool(amc)"); cdie( - mps_pool_create(&poolawl, arena, mps_class_lo(), format), + mps_pool_create(&poollo, arena, mps_class_lo(), format), "create pool"); cdie( - mps_ap_create(&apawl, poolawl, mps_rank_exact()), + mps_ap_create(&aplo, poollo, mps_rank_exact()), "create ap"); cdie( @@ -69,8 +70,8 @@ static void test(void) b = allocone(apamc, 1, 1); - for (j = 1; j < 100; j++) { - comment("%i of 100.", j); + for (j = 1; j <= ITERATIONS; j++) { + comment("%i of %i.", j, ITERATIONS); UC; a = allocone(apamc, 5, 1); b = a; @@ -80,10 +81,10 @@ static void test(void) f = a; g = a; - for (i = 1; i < 5000; i++) { + for (i = 0; i < 5000; i++) { UC; c = allocone(apamc, 20, 1); - d = allocone(apawl, 20, 1); + d = allocone(aplo, 20, 1); if (ranint(8) == 0) e = c; if (ranint(8) == 0) f = c; if (ranint(8) == 0) g = c; @@ -105,10 +106,10 @@ static void test(void) } mps_arena_park(arena); - mps_ap_destroy(apawl); + mps_ap_destroy(aplo); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); - mps_pool_destroy(poolawl); + mps_pool_destroy(poollo); mps_chain_destroy(chain); mps_fmt_destroy(format); mps_root_destroy(root); diff --git a/mps/test/function/60.c b/mps/test/function/60.c index b075e0b938e..25eb6da8118 100644 --- a/mps/test/function/60.c +++ b/mps/test/function/60.c @@ -75,8 +75,8 @@ static void test(void) for (i=1; i<=1000; i++) { UC; - a = allocone(ap1, 100, 1); - b = allocone(ap2, 100, 1); + a = allocone(ap1, 50, 1); + b = allocone(ap2, 50, 1); setref(a, 0, b); setref(b, 0, a); UC; diff --git a/mps/test/function/61.c b/mps/test/function/61.c index 9ccd97d77de..37b66fa5ea3 100644 --- a/mps/test/function/61.c +++ b/mps/test/function/61.c @@ -4,6 +4,7 @@ TEST_HEADER summary = loops between two AMC pools language = c link = testlib.o awlfmt.o + parameters = ITERATIONS=20 END_HEADER */ @@ -64,8 +65,8 @@ static void test(void) mps_ap_create(&ap2, poolamc2, mps_rank_exact()), "create ap"); - for (j = 1; j < 100; j++) { - comment("%i of 100.", j); + for (j = 1; j <= ITERATIONS; j++) { + comment("%i of %i.", j, ITERATIONS); for (i = 1; i < 10000; i++) { UC; diff --git a/mps/test/function/77.c b/mps/test/function/77.c index f57ea4bc2f6..ac8cfbbedd0 100644 --- a/mps/test/function/77.c +++ b/mps/test/function/77.c @@ -79,7 +79,7 @@ static void test(void) f = a; g = a; - for (i=1; i<5000; i++) { + for (i=1; i<=3000; i++) { c = allocone(apamc, 20, mps_rank_exact()); d = allocone(apawl, 20, mps_rank_exact()); if (ranint(8) == 0) e = c; diff --git a/mps/test/function/78.c b/mps/test/function/78.c index 331c0f2b2be..8c53f0035fb 100644 --- a/mps/test/function/78.c +++ b/mps/test/function/78.c @@ -4,6 +4,7 @@ TEST_HEADER summary = AMC and LO performance language = c link = testlib.o fastfmt.o + parameters = ITERATIONS=10 END_HEADER */ @@ -27,13 +28,13 @@ void *stackpointer; static void test(void) { mps_arena_t arena; - mps_pool_t poolamc, poolawl; + mps_pool_t poolamc, poollo; mps_thr_t thread; mps_root_t root, root1; mps_fmt_t format; mps_chain_t chain; - mps_ap_t apamc, apawl; + mps_ap_t apamc, aplo; mycell *a, *b, *c, *d, *e, *f, *g; @@ -59,11 +60,11 @@ static void test(void) "create pool(amc)"); cdie( - mps_pool_create(&poolawl, arena, mps_class_lo(), format), + mps_pool_create(&poollo, arena, mps_class_lo(), format), "create pool"); cdie( - mps_ap_create(&apawl, poolawl, mps_rank_exact()), + mps_ap_create(&aplo, poollo, mps_rank_exact()), "create ap"); cdie( @@ -72,8 +73,8 @@ static void test(void) b = allocone(apamc, 1, mps_rank_exact()); - for (j = 1; j < 100; j++) { - comment("%i of 100.", j); + for (j = 1; j <= ITERATIONS; j++) { + comment("%i of %i.", j, ITERATIONS); a = allocone(apamc, 5, mps_rank_exact()); b = a; c = a; @@ -82,9 +83,9 @@ static void test(void) f = a; g = a; - for (i = 1; i < 5000; i++) { + for (i = 0; i < 5000; i++) { c = allocone(apamc, 20, mps_rank_exact()); - d = allocone(apawl, 20, mps_rank_exact()); + d = allocone(aplo, 20, mps_rank_exact()); if (ranint(8) == 0) e = c; if (ranint(8) == 0) f = c; if (ranint(8) == 0) g = c; @@ -98,10 +99,10 @@ static void test(void) } mps_arena_park(arena); - mps_ap_destroy(apawl); + mps_ap_destroy(aplo); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); - mps_pool_destroy(poolawl); + mps_pool_destroy(poollo); mps_chain_destroy(chain); mps_fmt_destroy(format); mps_root_destroy(root); diff --git a/mps/test/function/96.c b/mps/test/function/96.c index 6504674cf41..887d0e67759 100644 --- a/mps/test/function/96.c +++ b/mps/test/function/96.c @@ -35,15 +35,9 @@ static void fillup(void) 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) { - for(b=a; b<(char *)a+size; b++) { - *b = 97; - } - } - size = size / 2; - } + for (size=1024ul*1024ul; size >= 4096ul; size /= 2) + while (mps_alloc(&a, poolmv, size)==MPS_RES_OK) + ; } @@ -115,10 +109,10 @@ static void test(void) empty(); - for (j=0; j<1000*1024; j++) { - res=allocrdumb(&a, ap, 1024, mps_rank_exact()); + for (j=0; j<1000; j++) { + res=allocrdumb(&a, ap, 1024*1024, mps_rank_exact()); if (res == MPS_RES_OK) { - if (j % 100000 == 0) { + if (j % 100 == 0) { comment("%i ok", j); } } else { diff --git a/mps/test/function/97.c b/mps/test/function/97.c index 3e5f3b8d30f..1ccb6996483 100644 --- a/mps/test/function/97.c +++ b/mps/test/function/97.c @@ -4,6 +4,7 @@ TEST_HEADER summary = test of mps_arena_formatted_objects_walk language = c link = testlib.o rankfmt.o + parameters = VERBOSE=0 END_HEADER some kinds of errors that could occur in the walker: @@ -98,7 +99,7 @@ static void stepper(mps_addr_t addr, mps_fmt_t fmt, mps_pool_t pool, appcount += 1; asserts(a->data.checkedflag != newstamp, "III/IV. step on object again at %p", a); - commentif(a->data.checkedflag != oldstamp, + commentif(VERBOSE && a->data.checkedflag != oldstamp, "*. step on unreachable object at %p", a); a->data.checkedflag = newstamp; } else { @@ -179,7 +180,7 @@ static void test(void) comment("%i of 100", j); - for (i=0; i<10000; i++) { + for (i=0; i<1000; i++) { k = ranint(4); addr = &a[k]; die(allocrdumb(addr, aplo, 64, mps_rank_exact()), "alloc failed"); diff --git a/mps/test/function/99.c b/mps/test/function/99.c index 939991c1551..c776c17bcc1 100644 --- a/mps/test/function/99.c +++ b/mps/test/function/99.c @@ -69,7 +69,7 @@ static void test(void) b = allocone(apamc, 1, mps_rank_exact()); - for (j =1 ; j < 100; j++) { + for (j =1 ; j <= 100; j++) { comment("%i of 100.", j); a = allocone(apamc, 5, mps_rank_exact()); b = a; @@ -79,7 +79,7 @@ static void test(void) f = a; g = a; - for (i = 1; i < 5000; i++) { + for (i = 0; i < 5000; i++) { c = allocone(apamc, 20, mps_rank_exact()); d = allocone(apamcz, 20, mps_rank_exact()); if (ranint(8) == 0) e = c; diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index 85f880b07ce..eae2836a8ce 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -71,7 +71,7 @@ function/66.c function/67.c % function/68.c -- infinite loop function/69.c -function/70.c +% function/70.c -- interactive test, no point in running unattended function/71.c % function/72.c -- fails in hot variety (assertion is on the critical path) function/73.c From 89a83ac39e2aac3f3363afde47cc5d431405f24c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 13 Mar 2016 11:42:53 +0000 Subject: [PATCH 238/337] A few more mmqa speedups. Copied from Perforce Change: 189948 ServerID: perforce.ravenbrook.com --- mps/test/function/12.c | 2 +- mps/test/function/12p.c | 2 +- mps/test/function/13.c | 2 +- mps/test/function/206.c | 4 ++-- mps/test/function/215.c | 2 +- mps/test/function/227.c | 6 +++--- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mps/test/function/12.c b/mps/test/function/12.c index f1c15731a04..d9f2de7fedb 100644 --- a/mps/test/function/12.c +++ b/mps/test/function/12.c @@ -182,7 +182,7 @@ static void test(void) commentif(VERBOSE, "%i begin commit", i); ap[i]->init = ap[i]->alloc; case 3: - commentif(VERBOSE, "% end commit", i); + commentif(VERBOSE, "%i end commit", i); (void) (ap[i]->limit != 0 || mps_ap_trip(ap[i], p[i], s[i])); } mps_ap_destroy(ap[i]); diff --git a/mps/test/function/12p.c b/mps/test/function/12p.c index c5987388e45..e5556c75ecb 100644 --- a/mps/test/function/12p.c +++ b/mps/test/function/12p.c @@ -188,7 +188,7 @@ cells = allocone(ap[0], NCELLS); commentif(VERBOSE, "%i begin commit", i); ap[i]->init = ap[i]->alloc; case 3: - commentif(VERBOSE, "% end commit", i); + commentif(VERBOSE, "%i end commit", i); (void) (ap[i]->limit != 0 || mps_ap_trip(ap[i], p[i], s[i])); } mps_ap_destroy(ap[i]); diff --git a/mps/test/function/13.c b/mps/test/function/13.c index 257e2a4978a..9a629ea1792 100644 --- a/mps/test/function/13.c +++ b/mps/test/function/13.c @@ -184,7 +184,7 @@ cells = allocone(ap[0], NCELLS); commentif(VERBOSE, "%i begin commit", i); ap[i]->init = ap[i]->alloc; case 3: - commentif(VERBOSE, "% end commit", i); + commentif(VERBOSE, "%i end commit", i); (void) (ap[i]->limit != 0 || mps_ap_trip(ap[i], p[i], s[i])); } mps_ap_destroy(ap[i]); diff --git a/mps/test/function/206.c b/mps/test/function/206.c index a5bc71ff4b3..64d5517944d 100644 --- a/mps/test/function/206.c +++ b/mps/test/function/206.c @@ -4,7 +4,7 @@ TEST_HEADER summary = new MVFF allocation test language = c link = testlib.o - parameters = QUEUES=100 ITERATIONS=10000 + parameters = QUEUES=100 ITERATIONS=1000 END_HEADER */ @@ -75,7 +75,7 @@ static void dt(int kind, die( mps_pool_create(&pool, arena, mps_class_mvff(), extendBy, avgSize, align, slotHigh, arenaHigh, firstFit), - "create EPDR pool"); + "create MVFF pool"); for(hd=0; hd Date: Sun, 13 Mar 2016 12:06:38 +0000 Subject: [PATCH 239/337] Remove duplicate file entries in the xcode project. Copied from Perforce Change: 189952 ServerID: perforce.ravenbrook.com --- mps/code/mps.xcodeproj/project.pbxproj | 130 +++---------------------- 1 file changed, 14 insertions(+), 116 deletions(-) diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index e36b800455b..d1c8e92c431 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -1660,55 +1660,21 @@ 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 = ""; }; 31942A671C8EC3FC001AAF32 /* locus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = locus.h; sourceTree = ""; }; - 31942A681C8EC445001AAF32 /* abq.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = abq.txt; path = ../design/abq.txt; sourceTree = ""; }; 31942A6A1C8EC445001AAF32 /* an.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = an.txt; path = ../design/an.txt; sourceTree = ""; }; - 31942A6B1C8EC445001AAF32 /* arena.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = arena.txt; path = ../design/arena.txt; sourceTree = ""; }; 31942A6D1C8EC445001AAF32 /* boot.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = boot.txt; path = ../design/boot.txt; sourceTree = ""; }; 31942A6E1C8EC445001AAF32 /* bootstrap.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = bootstrap.txt; path = ../design/bootstrap.txt; sourceTree = ""; }; - 31942A6F1C8EC445001AAF32 /* bt.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = bt.txt; path = ../design/bt.txt; sourceTree = ""; }; - 31942A711C8EC445001AAF32 /* cbs.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = cbs.txt; path = ../design/cbs.txt; sourceTree = ""; }; - 31942A731C8EC445001AAF32 /* class-interface.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "class-interface.txt"; path = "../design/class-interface.txt"; sourceTree = ""; }; 31942A741C8EC445001AAF32 /* clock.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = clock.txt; path = ../design/clock.txt; sourceTree = ""; }; - 31942A761C8EC445001AAF32 /* config.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = config.txt; path = ../design/config.txt; sourceTree = ""; }; - 31942A781C8EC445001AAF32 /* diag.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = diag.txt; path = ../design/diag.txt; sourceTree = ""; }; 31942A791C8EC445001AAF32 /* exec-env.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "exec-env.txt"; path = "../design/exec-env.txt"; sourceTree = ""; }; - 31942A7B1C8EC445001AAF32 /* finalize.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = finalize.txt; path = ../design/finalize.txt; sourceTree = ""; }; - 31942A7D1C8EC445001AAF32 /* freelist.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = freelist.txt; path = ../design/freelist.txt; sourceTree = ""; }; - 31942A7F1C8EC445001AAF32 /* guide.impl.c.format.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = guide.impl.c.format.txt; path = ../design/guide.impl.c.format.txt; sourceTree = ""; }; 31942A801C8EC445001AAF32 /* guide.impl.c.naming.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = guide.impl.c.naming.txt; path = ../design/guide.impl.c.naming.txt; sourceTree = ""; }; 31942A811C8EC445001AAF32 /* guide.review.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = guide.review.txt; path = ../design/guide.review.txt; sourceTree = ""; }; - 31942A831C8EC445001AAF32 /* interface-c.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "interface-c.txt"; path = "../design/interface-c.txt"; sourceTree = ""; }; - 31942A851C8EC445001AAF32 /* keyword-arguments.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "keyword-arguments.txt"; path = "../design/keyword-arguments.txt"; sourceTree = ""; }; - 31942A871C8EC445001AAF32 /* lib.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = lib.txt; path = ../design/lib.txt; sourceTree = ""; }; - 31942A891C8EC445001AAF32 /* locus.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = locus.txt; path = ../design/locus.txt; sourceTree = ""; }; - 31942A8B1C8EC446001AAF32 /* message.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = message.txt; path = ../design/message.txt; sourceTree = ""; }; 31942A8C1C8EC446001AAF32 /* nailboard-1.svg */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = "nailboard-1.svg"; path = "../design/nailboard-1.svg"; sourceTree = ""; }; 31942A8D1C8EC446001AAF32 /* nailboard-2.svg */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = "nailboard-2.svg"; path = "../design/nailboard-2.svg"; sourceTree = ""; }; 31942A8E1C8EC446001AAF32 /* nailboard-3.svg */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = "nailboard-3.svg"; path = "../design/nailboard-3.svg"; sourceTree = ""; }; 31942A8F1C8EC446001AAF32 /* nailboard.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = nailboard.txt; path = ../design/nailboard.txt; sourceTree = ""; }; - 31942A911C8EC446001AAF32 /* pool.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = pool.txt; path = ../design/pool.txt; sourceTree = ""; }; - 31942A931C8EC446001AAF32 /* poolams.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = poolams.txt; path = ../design/poolams.txt; sourceTree = ""; }; - 31942A951C8EC446001AAF32 /* poollo.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = poollo.txt; path = ../design/poollo.txt; sourceTree = ""; }; - 31942A971C8EC446001AAF32 /* poolmrg.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = poolmrg.txt; path = ../design/poolmrg.txt; sourceTree = ""; }; - 31942A991C8EC446001AAF32 /* poolmvff.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = poolmvff.txt; path = ../design/poolmvff.txt; sourceTree = ""; }; 31942A9B1C8EC446001AAF32 /* prmc.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = prmc.txt; path = ../design/prmc.txt; sourceTree = ""; }; - 31942A9C1C8EC446001AAF32 /* prot.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = prot.txt; path = ../design/prot.txt; sourceTree = ""; }; - 31942A9E1C8EC446001AAF32 /* protocol.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = protocol.txt; path = ../design/protocol.txt; sourceTree = ""; }; - 31942AA01C8EC446001AAF32 /* pthreadext.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = pthreadext.txt; path = ../design/pthreadext.txt; sourceTree = ""; }; - 31942AA21C8EC446001AAF32 /* reservoir.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = reservoir.txt; path = ../design/reservoir.txt; sourceTree = ""; }; - 31942AA41C8EC446001AAF32 /* root.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = root.txt; path = ../design/root.txt; sourceTree = ""; }; - 31942AA61C8EC446001AAF32 /* seg.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = seg.txt; path = ../design/seg.txt; sourceTree = ""; }; - 31942AA81C8EC446001AAF32 /* sig.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = sig.txt; path = ../design/sig.txt; sourceTree = ""; }; 31942AA91C8EC446001AAF32 /* sp.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = sp.txt; path = ../design/sp.txt; sourceTree = ""; }; 31942AAB1C8EC446001AAF32 /* ss.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = ss.txt; path = ../design/ss.txt; sourceTree = ""; }; - 31942AAC1C8EC446001AAF32 /* sso1al.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = sso1al.txt; path = ../design/sso1al.txt; sourceTree = ""; }; - 31942AAE1C8EC446001AAF32 /* telemetry.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = telemetry.txt; path = ../design/telemetry.txt; sourceTree = ""; }; 31942AB01C8EC446001AAF32 /* testthr.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = testthr.txt; path = ../design/testthr.txt; sourceTree = ""; }; - 31942AB11C8EC446001AAF32 /* thread-manager.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "thread-manager.txt"; path = "../design/thread-manager.txt"; sourceTree = ""; }; - 31942AB31C8EC446001AAF32 /* trace.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = trace.txt; path = ../design/trace.txt; sourceTree = ""; }; - 31942AB51C8EC446001AAF32 /* version-library.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "version-library.txt"; path = "../design/version-library.txt"; sourceTree = ""; }; - 31942AB71C8EC446001AAF32 /* vm.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = vm.txt; path = ../design/vm.txt; sourceTree = ""; }; - 31942AB91C8EC446001AAF32 /* vmso.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = vmso.txt; path = ../design/vmso.txt; 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 = ""; }; @@ -2210,108 +2176,32 @@ 31160D90189953D50071EB17 /* Design */ = { isa = PBXGroup; children = ( - 31942A681C8EC445001AAF32 /* abq.txt */, + 31160D921899540D0071EB17 /* abq.txt */, 31160D931899540D0071EB17 /* alloc-frame.txt */, 31942A6A1C8EC445001AAF32 /* an.txt */, - 31942A6B1C8EC445001AAF32 /* arena.txt */, + 31160D941899540D0071EB17 /* arena.txt */, 31160D951899540D0071EB17 /* arenavm.txt */, 31942A6D1C8EC445001AAF32 /* boot.txt */, 31942A6E1C8EC445001AAF32 /* bootstrap.txt */, - 31942A6F1C8EC445001AAF32 /* bt.txt */, - 31160D971899540D0071EB17 /* buffer.txt */, - 31942A711C8EC445001AAF32 /* cbs.txt */, - 31160D991899540D0071EB17 /* check.txt */, - 31942A731C8EC445001AAF32 /* class-interface.txt */, - 31942A741C8EC445001AAF32 /* clock.txt */, - 31160D9B1899540D0071EB17 /* collection.txt */, - 31942A761C8EC445001AAF32 /* config.txt */, - 31160D9D1899540D0071EB17 /* critical-path.txt */, - 31942A781C8EC445001AAF32 /* diag.txt */, - 31942A791C8EC445001AAF32 /* exec-env.txt */, - 22DD93E118ED815F00240DD2 /* failover.txt */, - 31942A7B1C8EC445001AAF32 /* finalize.txt */, - 31160DA01899540D0071EB17 /* fix.txt */, - 31942A7D1C8EC445001AAF32 /* freelist.txt */, - 31160DA21899540D0071EB17 /* guide.hex.trans.txt */, - 31942A7F1C8EC445001AAF32 /* guide.impl.c.format.txt */, - 31942A801C8EC445001AAF32 /* guide.impl.c.naming.txt */, - 31942A811C8EC445001AAF32 /* guide.review.txt */, - 31160DA41899540D0071EB17 /* index.txt */, - 31942A831C8EC445001AAF32 /* interface-c.txt */, - 31160DA61899540D0071EB17 /* io.txt */, - 31942A851C8EC445001AAF32 /* keyword-arguments.txt */, - 22DD93E218ED815F00240DD2 /* land.txt */, - 31942A871C8EC445001AAF32 /* lib.txt */, - 31160DA91899540D0071EB17 /* lock.txt */, - 31942A891C8EC445001AAF32 /* locus.txt */, - 31160DAB1899540D0071EB17 /* message-gc.txt */, - 31942A8B1C8EC446001AAF32 /* message.txt */, - 31942A8C1C8EC446001AAF32 /* nailboard-1.svg */, - 31942A8D1C8EC446001AAF32 /* nailboard-2.svg */, - 31942A8E1C8EC446001AAF32 /* nailboard-3.svg */, - 31942A8F1C8EC446001AAF32 /* nailboard.txt */, - 31160DAD1899540D0071EB17 /* object-debug.txt */, - 31942A911C8EC446001AAF32 /* pool.txt */, - 31160DAF1899540D0071EB17 /* poolamc.txt */, - 31942A931C8EC446001AAF32 /* poolams.txt */, - 31160DB11899540D0071EB17 /* poolawl.txt */, - 31942A951C8EC446001AAF32 /* poollo.txt */, - 31160DB31899540D0071EB17 /* poolmfs.txt */, - 31942A971C8EC446001AAF32 /* poolmrg.txt */, - 31160DB51899540D0071EB17 /* poolmv.txt */, - 31942A991C8EC446001AAF32 /* poolmvff.txt */, - 31160DB71899540D0071EB17 /* poolmvt.txt */, - 31942A9B1C8EC446001AAF32 /* prmc.txt */, - 31942A9C1C8EC446001AAF32 /* prot.txt */, - 31160DBA1899540D0071EB17 /* protli.txt */, - 31942A9E1C8EC446001AAF32 /* protocol.txt */, - 31160DBC1899540D0071EB17 /* protsu.txt */, - 31942AA01C8EC446001AAF32 /* pthreadext.txt */, - 31160DBE1899540D0071EB17 /* range.txt */, - 31942AA21C8EC446001AAF32 /* reservoir.txt */, - 31160DC01899540D0071EB17 /* ring.txt */, - 31942AA41C8EC446001AAF32 /* root.txt */, - 31160DC21899540D0071EB17 /* scan.txt */, - 31942AA61C8EC446001AAF32 /* seg.txt */, - 31160DC41899540D0071EB17 /* shield.txt */, - 31942AA81C8EC446001AAF32 /* sig.txt */, - 31942AA91C8EC446001AAF32 /* sp.txt */, - 31160DC61899540D0071EB17 /* splay.txt */, - 31942AAB1C8EC446001AAF32 /* ss.txt */, - 31942AAC1C8EC446001AAF32 /* sso1al.txt */, - 31160DC81899540D0071EB17 /* strategy.txt */, - 31942AAE1C8EC446001AAF32 /* telemetry.txt */, - 31160DCA1899540D0071EB17 /* tests.txt */, - 31942AB01C8EC446001AAF32 /* testthr.txt */, - 31942AB11C8EC446001AAF32 /* thread-manager.txt */, - 31160DCC1899540D0071EB17 /* thread-safety.txt */, - 31942AB31C8EC446001AAF32 /* trace.txt */, - 31160DCE1899540D0071EB17 /* type.txt */, - 31942AB51C8EC446001AAF32 /* version-library.txt */, - 31160DD01899540D0071EB17 /* version.txt */, - 31942AB71C8EC446001AAF32 /* vm.txt */, - 31160DD31899540D0071EB17 /* vmo1.txt */, - 31942AB91C8EC446001AAF32 /* vmso.txt */, - 31160D921899540D0071EB17 /* abq.txt */, - 31160DD51899540D0071EB17 /* writef.txt */, - 31160D931899540D0071EB17 /* alloc-frame.txt */, - 31160D941899540D0071EB17 /* arena.txt */, - 31160D951899540D0071EB17 /* arenavm.txt */, 31160D961899540D0071EB17 /* bt.txt */, 31160D971899540D0071EB17 /* buffer.txt */, 31160D981899540D0071EB17 /* cbs.txt */, 31160D991899540D0071EB17 /* check.txt */, 31160D9A1899540D0071EB17 /* class-interface.txt */, + 31942A741C8EC445001AAF32 /* clock.txt */, 31160D9B1899540D0071EB17 /* collection.txt */, 31160D9C1899540D0071EB17 /* config.txt */, 31160D9D1899540D0071EB17 /* critical-path.txt */, 31160D9E1899540D0071EB17 /* diag.txt */, + 31942A791C8EC445001AAF32 /* exec-env.txt */, 22DD93E118ED815F00240DD2 /* failover.txt */, 31160D9F1899540D0071EB17 /* finalize.txt */, 31160DA01899540D0071EB17 /* fix.txt */, 31160DA11899540D0071EB17 /* freelist.txt */, 31160DA21899540D0071EB17 /* guide.hex.trans.txt */, 31160DA31899540D0071EB17 /* guide.impl.c.format.txt */, + 31942A801C8EC445001AAF32 /* guide.impl.c.naming.txt */, + 31942A811C8EC445001AAF32 /* guide.review.txt */, 31160DA41899540D0071EB17 /* index.txt */, 31160DA51899540D0071EB17 /* interface-c.txt */, 31160DA61899540D0071EB17 /* io.txt */, @@ -2322,6 +2212,10 @@ 31160DAA1899540D0071EB17 /* locus.txt */, 31160DAB1899540D0071EB17 /* message-gc.txt */, 31160DAC1899540D0071EB17 /* message.txt */, + 31942A8C1C8EC446001AAF32 /* nailboard-1.svg */, + 31942A8D1C8EC446001AAF32 /* nailboard-2.svg */, + 31942A8E1C8EC446001AAF32 /* nailboard-3.svg */, + 31942A8F1C8EC446001AAF32 /* nailboard.txt */, 31160DAD1899540D0071EB17 /* object-debug.txt */, 31160DAE1899540D0071EB17 /* pool.txt */, 31160DAF1899540D0071EB17 /* poolamc.txt */, @@ -2333,6 +2227,7 @@ 31160DB51899540D0071EB17 /* poolmv.txt */, 31160DB61899540D0071EB17 /* poolmvff.txt */, 31160DB71899540D0071EB17 /* poolmvt.txt */, + 31942A9B1C8EC446001AAF32 /* prmc.txt */, 31160DB81899540D0071EB17 /* prot.txt */, 31160DBA1899540D0071EB17 /* protli.txt */, 31160DBB1899540D0071EB17 /* protocol.txt */, @@ -2346,11 +2241,14 @@ 31160DC31899540D0071EB17 /* seg.txt */, 31160DC41899540D0071EB17 /* shield.txt */, 31160DC51899540D0071EB17 /* sig.txt */, + 31942AA91C8EC446001AAF32 /* sp.txt */, 31160DC61899540D0071EB17 /* splay.txt */, + 31942AAB1C8EC446001AAF32 /* ss.txt */, 31160DC71899540D0071EB17 /* sso1al.txt */, 31160DC81899540D0071EB17 /* strategy.txt */, 31160DC91899540D0071EB17 /* telemetry.txt */, 31160DCA1899540D0071EB17 /* tests.txt */, + 31942AB01C8EC446001AAF32 /* testthr.txt */, 31160DCB1899540D0071EB17 /* thread-manager.txt */, 31160DCC1899540D0071EB17 /* thread-safety.txt */, 31160DCD1899540D0071EB17 /* trace.txt */, From 17b529001bd50465b8cbf244192678f6837b7254 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 13 Mar 2016 12:16:01 +0000 Subject: [PATCH 240/337] Fixing incomplete merge that missed out disabling the write barrier, but corrupted the segment summaries. Copied from Perforce Change: 189954 ServerID: perforce.ravenbrook.com --- mps/code/trace.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mps/code/trace.c b/mps/code/trace.c index acbf4ba7d20..f8a9494067f 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1153,6 +1153,8 @@ static Res traceScanSegRes(TraceSet ts, Rank rank, Arena arena, Seg seg) /* scanned summary should replace the segment summary. */ SegSetSummary(seg, ScanStateSummary(ss)); } + } else { + SegSetSummary(seg, RefSetUNIV); } ScanStateFinish(ss); From e976a17eb89161801d66d87e821b653269629335 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 13 Mar 2016 12:57:02 +0000 Subject: [PATCH 241/337] Regular testing of mmqa: "make test-make-build" at top level now runs mmqa, hence so does "make test" on linux and freebsd. the whole test suite, including testci, testmmqa, testansi, and testpollnone, takes 26 minutes on my laptop. MMQA "run" and "runset" commands now exit with non-zero status if any of the tests failed, so that test failures can be identifed by the calling program (for example, make). Add missing license to files that state "See end of file for license." Copied from Perforce Change: 189957 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 45 ++++++++++++++++++++++++++++++++++-- mps/configure.ac | 43 +++++++++++++++++++++++++++++++++- mps/test/test/qa | 3 ++- mps/test/test/script/runtest | 8 +++++++ 4 files changed, 95 insertions(+), 4 deletions(-) diff --git a/mps/Makefile.in b/mps/Makefile.in index fe33a4d49f6..32fd3406530 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -1,7 +1,7 @@ # Makefile.in -- source for autoconf Makefile # # $Id$ -# Copyright (C) 2012-2014 Ravenbrook Limited. See end of file for license. +# Copyright (C) 2012-2016 Ravenbrook Limited. See end of file for license. # # YOU DON'T NEED AUTOCONF TO BUILD THE MPS # This is just here for people who want or expect a configure script. @@ -71,7 +71,7 @@ make-install-dirs: install: @INSTALL_TARGET@ test-make-build: - $(MAKE) $(TARGET_OPTS) testci + $(MAKE) $(TARGET_OPTS) testci testmmqa $(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 testpollnone @@ -80,3 +80,44 @@ test-xcode-build: $(XCODEBUILD) -config Release -target testci test: @TEST_TARGET@ + + +# C. COPYRIGHT AND LICENSE +# +# Copyright (C) 2012-2016 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/configure.ac b/mps/configure.ac index 940ca852cc2..c7928ec14bb 100644 --- a/mps/configure.ac +++ b/mps/configure.ac @@ -1,7 +1,7 @@ # configure.ac -- autoconf configuration for the MPS -*- Autoconf -*- # # $Id$ -# Copyright (C) 2012-2014 Ravenbrook Limited. See end of file for license. +# Copyright (C) 2012-2016 Ravenbrook Limited. See end of file for license. # # YOU DON'T NEED AUTOCONF TO BUILD THE MPS # This is just here for people who want or expect a configure script. @@ -170,3 +170,44 @@ AC_CONFIG_FILES(Makefile example/scheme/Makefile) AC_OUTPUT echo 1>&2 "CONFIGURE/MAKE IS NOT THE BEST WAY TO BUILD THE MPS -- see " + + +# C. COPYRIGHT AND LICENSE +# +# Copyright (C) 2012-2016 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/test/test/qa b/mps/test/test/qa index a4a40f26451..c17d3e1dca6 100644 --- a/mps/test/test/qa +++ b/mps/test/test/qa @@ -71,6 +71,7 @@ unless (-e "$script_dir/commands/".$qa_command) { die "Unknown command '".$qa_command."' -- 'qa help' for info.\n"; } +$exitstatus = 0; do "commands/".$qa_command; if ($@) {print $@}; - +exit $exitstatus; diff --git a/mps/test/test/script/runtest b/mps/test/test/script/runtest index 64269c4382d..308a1a10b2a 100644 --- a/mps/test/test/script/runtest +++ b/mps/test/test/script/runtest @@ -144,6 +144,10 @@ sub run_test { die "Don't know how to run tests in the $lang language.\n"; } + + if ($testconclusion eq "FAIL") { + $exitstatus = 1; + } } sub run_from_testset { @@ -216,6 +220,10 @@ sub run_from_testset { close(LOG_VERBOSE); &mailfile("$LOG_DIR/last.log", "$MAIL_SUBJECT $testid $testconclusion"); } + + if ($testconclusion eq "FAIL") { + $exitstatus = 1; + } } sub run_testset { From 47dbed0eee381d90f92c2f98459b14ab04e039e5 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 13 Mar 2016 13:26:24 +0000 Subject: [PATCH 242/337] Tidying up naming of write barrier deferral. Copied from Perforce Change: 189960 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 28 ++++++++++++++++++++-------- mps/code/mpmst.h | 2 +- mps/code/seg.c | 2 +- mps/code/trace.c | 42 ++++++++++++++++++++++++------------------ 4 files changed, 46 insertions(+), 28 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index 50cb0aece82..5204171795b 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -659,20 +659,32 @@ { 36 * 1024, 0.45 } /* second gen, after which dynamic */ \ } -/* Experimental Scan Barrier threshold +/* Write barrier deferral * + * Defer using the write barrier for the remembered set until a number + * of unnecessary scans have been performed on a segment. Avoids + * memory protection costs when scanning might be cheaper. See job003975. + * + * TODO: These settings were determined by trial and error, but should + * be based on measurement of the protection overhead on each + * platform. We know it's extremely different between OS X and + * Windows, for example. + * + * TODO: Consider basing the count on the amount of time that has + * passed in the mutator rather than the number of scans. */ -/* Number of bits needed to keep the seg scan count */ -#define SEG_SCANS_BITS 10 + +/* Number of bits needed to keep the write barrier deferral count */ +#define WB_DEFER_BITS 3 /* The number of unecessary scans performed, before raising the write - * barrier to remember the refset summary. */ -#define SEG_SCANS_INIT 3 + barrier to maintian the remembered set. */ +#define WB_DEFER_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 + barrier to remember the refset summary, after a necessary scan */ +#define WB_DEFER_DELAY WB_DEFER_INIT /* 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 +#define WB_DEFER_AFTER_HIT 1 #endif /* config_h */ diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 5636bf22b28..48f80eb2255 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -281,7 +281,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 */ + Count defer : WB_DEFER_BITS; /* defer write barrier for this many scans */ } SegStruct; diff --git a/mps/code/seg.c b/mps/code/seg.c index 1e693d8a48d..31ef5bd8b64 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -160,7 +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->defer = WB_DEFER_INIT; seg->depth = 0; seg->firstTract = NULL; diff --git a/mps/code/trace.c b/mps/code/trace.c index f8a9494067f..bd3175fc5aa 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1089,6 +1089,7 @@ static Res traceScanSegRes(TraceSet ts, Rank rank, Arena arena, Seg seg) Bool wasTotal; ZoneSet white; Res res; + RefSet summary; /* The reason for scanning a segment is that it's grey. */ AVER(TraceSetInter(ts, SegGrey(seg)) != TraceSetEMPTY); @@ -1134,28 +1135,33 @@ static Res traceScanSegRes(TraceSet ts, Rank rank, Arena arena, Seg seg) * scan, consistent with the recorded SegSummary? */ AVER(RefSetSub(ScanStateUnfixedSummary(ss), SegSummary(seg))); + + /* Remembered set and write barrier */ + /* Was the scan necessary? Did the segment refer to the white set */ if (ZoneSetInter(ScanStateUnfixedSummary(ss), white) == ZoneSetEMPTY) { - /* a scan was not necessary */ - if (seg->scans > 0) - seg->scans--; + if (seg->defer > 0) + --seg->defer; } else { - if (seg->scans < SEG_SCANS_AFTER_NEEDED_SCAN) - seg->scans = SEG_SCANS_AFTER_NEEDED_SCAN; + if (seg->defer < WB_DEFER_DELAY) + seg->defer = WB_DEFER_DELAY; } - - if (seg->scans == 0) { - 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)); - } + + /* Only apply the write barrier if it is not deferred. */ + /* TODO: This discards information we collected during + scanning. Consider keeping the summary but changing the + invariant on shielding instead. */ + if (seg->defer == 0) { + /* If we scanned every reference in the segment then we have a + complete summary we can set. Otherwise, we just have + information about more zones that the segment refers to. */ + if (res == ResOK && wasTotal) + summary = ScanStateSummary(ss); + else + summary = RefSetUnion(SegSummary(seg), ScanStateSummary(ss)); } else { - SegSetSummary(seg, RefSetUNIV); + summary = RefSetUNIV; } + SegSetSummary(seg, summary); ScanStateFinish(ss); } @@ -1215,7 +1221,7 @@ 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; + seg->defer = WB_DEFER_AFTER_HIT; if((mode & SegSM(seg) & AccessREAD) != 0) { /* read barrier? */ Trace trace; From ca73a994c09247a18b611149300bbfc48059f5cd Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 13 Mar 2016 14:09:38 +0000 Subject: [PATCH 243/337] Simplifying segsetsummary by not requiring it to calculate the previous shield mode. Copied from Perforce Change: 189963 ServerID: perforce.ravenbrook.com --- mps/code/seg.c | 29 ++++++++++++----------------- mps/code/shield.c | 2 -- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/mps/code/seg.c b/mps/code/seg.c index 31ef5bd8b64..12e7fc10737 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -740,6 +740,7 @@ Bool SegCheck(Seg seg) /* write shielded. */ /* CHECKL(seg->_summary == RefSetUNIV || (seg->_sm & AccessWRITE)); */ /* @@@@ What can be checked about the read barrier? */ + /* FIXME: Need gcSegCheck? CHECKL(seg->defer == 0 || seg->summary == RefSetUNIV); */ } return TRUE; } @@ -1345,7 +1346,6 @@ static void gcSegSetRankSet(Seg seg, RankSet rankSet) static void gcSegSetSummary(Seg seg, RefSet summary) { GCSeg gcseg; - RefSet oldSummary; Arena arena; AVERT_CRITICAL(Seg, seg); /* .seg.method.check */ @@ -1354,19 +1354,16 @@ static void gcSegSetSummary(Seg seg, RefSet summary) AVER_CRITICAL(&gcseg->segStruct == seg); arena = PoolArena(SegPool(seg)); - oldSummary = gcseg->summary; gcseg->summary = summary; AVER(seg->rankSet != RankSetEMPTY); /* Note: !RefSetSuper is a test for a strict subset */ - if (!RefSetSuper(summary, RefSetUNIV)) { - if (RefSetSuper(oldSummary, RefSetUNIV)) - ShieldRaise(arena, seg, AccessWRITE); - } else { - if (!RefSetSuper(oldSummary, RefSetUNIV)) - ShieldLower(arena, seg, AccessWRITE); - } + /* FIXME: Duplicate code with gcSegSetRankSummary. */ + if (!RefSetSuper(summary, RefSetUNIV)) + ShieldRaise(arena, seg, AccessWRITE); + else + ShieldLower(arena, seg, AccessWRITE); } @@ -1375,7 +1372,6 @@ static void gcSegSetSummary(Seg seg, RefSet summary) static void gcSegSetRankSummary(Seg seg, RankSet rankSet, RefSet summary) { GCSeg gcseg; - Bool wasShielded, willbeShielded; Arena arena; AVERT_CRITICAL(Seg, seg); /* .seg.method.check */ @@ -1391,16 +1387,15 @@ static void gcSegSetRankSummary(Seg seg, RankSet rankSet, RefSet summary) arena = PoolArena(SegPool(seg)); - wasShielded = (seg->rankSet != RankSetEMPTY && gcseg->summary != RefSetUNIV); - willbeShielded = (rankSet != RankSetEMPTY && summary != RefSetUNIV); - seg->rankSet = BS_BITFIELD(Rank, rankSet); gcseg->summary = summary; - if (willbeShielded && !wasShielded) { - ShieldRaise(arena, seg, AccessWRITE); - } else if (wasShielded && !willbeShielded) { - ShieldLower(arena, seg, AccessWRITE); + if (rankSet != RankSetEMPTY) { + /* FIXME: Duplicate code with gcSegSetSummary. */ + if (!RefSetSuper(summary, RefSetUNIV)) + ShieldRaise(arena, seg, AccessWRITE); + else + ShieldLower(arena, seg, AccessWRITE); } } diff --git a/mps/code/shield.c b/mps/code/shield.c index 0dfc1945db6..56c00d76be9 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -193,7 +193,6 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode) /* segs in the cache. */ AVERT(AccessSet, mode); - AVER((SegSM(seg) & mode) == AccessSetEMPTY); SegSetSM(seg, SegSM(seg) | mode); /* inv.prot.shield preserved */ /* ensure inv.unsynced.suspended & inv.unsynced.depth */ @@ -207,7 +206,6 @@ 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 * Also inv.prot.shield preserved From dfa7354873f517a95f18a0fe4e075da51d113007 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 13 Mar 2016 14:16:39 +0000 Subject: [PATCH 244/337] Avoid warnings when compiling argerr/{146,147,148}.c with gcc. Test cases conerr/{53,54}.c rely on junk in uninitialized local variables, so ensure that there is some. Test case function/72.c relies on an object moving, but it might be pinned by an ambiguous reference from the stack, so don't register the stack as a root. Copied from Perforce Change: 189964 ServerID: perforce.ravenbrook.com --- mps/test/argerr/146.c | 69 ++--------------------------------------- mps/test/argerr/147.c | 69 ++--------------------------------------- mps/test/argerr/148.c | 70 ++---------------------------------------- mps/test/conerr/53.c | 5 +++ mps/test/conerr/54.c | 5 +++ mps/test/function/72.c | 48 ++++++++++++++--------------- 6 files changed, 40 insertions(+), 226 deletions(-) diff --git a/mps/test/argerr/146.c b/mps/test/argerr/146.c index c6d465671eb..55880de0267 100644 --- a/mps/test/argerr/146.c +++ b/mps/test/argerr/146.c @@ -142,41 +142,7 @@ struct mps_fmt_A_s fmtA = the allocated object to have */ -mycell *allocdumb(mps_ap_t ap, size_t size) -{ - mps_addr_t p; - mycell *q; - size_t bytes; - size_t alignment; - - bytes = offsetof(struct data, ref) + size; - - alignment = MPS_PF_ALIGN; /* needed to make it as wide as size_t */ - -/* twiddle the value of size to make it aligned */ - bytes = (bytes+alignment-1) & ~(alignment-1); - - do - { - die(mps_reserve(&p, ap, bytes), "Reserve: "); - INCCOUNT(RESERVE_COUNT); - q=p; - q->data.tag = MCdata; - q->data.id = nextid; - q->data.copycount = 0; - q->data.numrefs = 0; - q->data.checkedflag = 0; - q->data.size = bytes; - } - while (!mps_commit(ap, p, bytes)); - INCCOUNT(ALLOC_COUNT); - commentif(alloccomments, "allocated id %li at %p.", nextid, q); - nextid += 1; - - return q; -} - -mycell *allocone(mps_ap_t ap, int size) +static mycell *allocone(mps_ap_t ap, int size) { mps_addr_t p; mycell *q; @@ -222,7 +188,6 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) int i; INCCOUNT(SCANCALL_COUNT); - MPS_SCAN_BEGIN(ss) { while (base < limit) { @@ -273,7 +238,6 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) } } } - MPS_SCAN_END(ss); return MPS_RES_OK; } @@ -390,7 +354,7 @@ static void myfwd(mps_addr_t object, mps_addr_t to) /* set the nth reference of obj to to (n from 0 to size-1) */ -void setref(mycell *obj, int n, mycell *to) +static void setref(mycell *obj, int n, mycell *to) { asserts(obj->tag = MCdata, "setref: from non-data object."); asserts(to->tag = MCdata, "setref: to non-data object."); @@ -400,35 +364,6 @@ void setref(mycell *obj, int n, mycell *to) obj->data.ref[n].id = to->data.id; } -mycell *getref(mycell *obj, int n) -{ - asserts(obj->tag = MCdata, "getref: from non-data object."); - asserts(obj->data.numrefs > n, "getref: access beyond object size."); - return obj->data.ref[n].addr; -} - -mps_addr_t getdata(mycell *obj) -{ - return (mps_addr_t) &(obj->data.ref[0]); -} - -long int getid(mycell *obj) -{ - asserts(obj->tag = MCdata, "getid: non-data object."); - return obj->data.id; -} - -long int getcopycount(mycell *obj) -{ - asserts(obj->tag = MCdata, "getcopycount: non-data object."); - return obj->data.copycount; -} - -long int getsize(mycell *obj) -{ - asserts(obj->tag = MCdata, "getsize: non-data object."); - return obj->data.numrefs; -} /* ---- Now the test itself! ---- */ diff --git a/mps/test/argerr/147.c b/mps/test/argerr/147.c index 0b11507cc81..0b17ec430fe 100644 --- a/mps/test/argerr/147.c +++ b/mps/test/argerr/147.c @@ -142,41 +142,8 @@ struct mps_fmt_A_s fmtA = the allocated object to have */ -mycell *allocdumb(mps_ap_t ap, size_t size) -{ - mps_addr_t p; - mycell *q; - size_t bytes; - size_t alignment; - bytes = offsetof(struct data, ref) + size; - - alignment = MPS_PF_ALIGN; /* needed to make it as wide as size_t */ - -/* twiddle the value of size to make it aligned */ - bytes = (bytes+alignment-1) & ~(alignment-1); - - do - { - die(mps_reserve(&p, ap, bytes), "Reserve: "); - INCCOUNT(RESERVE_COUNT); - q=p; - q->data.tag = MCdata; - q->data.id = nextid; - q->data.copycount = 0; - q->data.numrefs = 0; - q->data.checkedflag = 0; - q->data.size = bytes; - } - while (!mps_commit(ap, p, bytes)); - INCCOUNT(ALLOC_COUNT); - commentif(alloccomments, "allocated id %li at %p.", nextid, q); - nextid += 1; - - return q; -} - -mycell *allocone(mps_ap_t ap, int size) +static mycell *allocone(mps_ap_t ap, int size) { mps_addr_t p; mycell *q; @@ -222,7 +189,6 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) int i; INCCOUNT(SCANCALL_COUNT); - MPS_SCAN_BEGIN(ss) { while (base < limit) { @@ -273,7 +239,6 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) } } } - MPS_SCAN_END(ss); return MPS_RES_OK; } @@ -390,7 +355,7 @@ static void myfwd(mps_addr_t object, mps_addr_t to) /* set the nth reference of obj to to (n from 0 to size-1) */ -void setref(mycell *obj, int n, mycell *to) +static void setref(mycell *obj, int n, mycell *to) { asserts(obj->tag = MCdata, "setref: from non-data object."); asserts(to->tag = MCdata, "setref: to non-data object."); @@ -400,36 +365,6 @@ void setref(mycell *obj, int n, mycell *to) obj->data.ref[n].id = to->data.id; } -mycell *getref(mycell *obj, int n) -{ - asserts(obj->tag = MCdata, "getref: from non-data object."); - asserts(obj->data.numrefs > n, "getref: access beyond object size."); - return obj->data.ref[n].addr; -} - -mps_addr_t getdata(mycell *obj) -{ - return (mps_addr_t) &(obj->data.ref[0]); -} - -long int getid(mycell *obj) -{ - asserts(obj->tag = MCdata, "getid: non-data object."); - return obj->data.id; -} - -long int getcopycount(mycell *obj) -{ - asserts(obj->tag = MCdata, "getcopycount: non-data object."); - return obj->data.copycount; -} - -long int getsize(mycell *obj) -{ - asserts(obj->tag = MCdata, "getsize: non-data object."); - return obj->data.numrefs; -} - /* ---- Now the test itself! ---- */ #define genCOUNT (3) diff --git a/mps/test/argerr/148.c b/mps/test/argerr/148.c index 814429c1cdb..ca66e2b348f 100644 --- a/mps/test/argerr/148.c +++ b/mps/test/argerr/148.c @@ -142,41 +142,7 @@ struct mps_fmt_A_s fmtA = the allocated object to have */ -mycell *allocdumb(mps_ap_t ap, size_t size) -{ - mps_addr_t p; - mycell *q; - size_t bytes; - size_t alignment; - - bytes = offsetof(struct data, ref) + size; - - alignment = MPS_PF_ALIGN; /* needed to make it as wide as size_t */ - -/* twiddle the value of size to make it aligned */ - bytes = (bytes+alignment-1) & ~(alignment-1); - - do - { - die(mps_reserve(&p, ap, bytes), "Reserve: "); - INCCOUNT(RESERVE_COUNT); - q=p; - q->data.tag = MCdata; - q->data.id = nextid; - q->data.copycount = 0; - q->data.numrefs = 0; - q->data.checkedflag = 0; - q->data.size = bytes; - } - while (!mps_commit(ap, p, bytes)); - INCCOUNT(ALLOC_COUNT); - commentif(alloccomments, "allocated id %li at %p.", nextid, q); - nextid += 1; - - return q; -} - -mycell *allocone(mps_ap_t ap, int size) +static mycell *allocone(mps_ap_t ap, int size) { mps_addr_t p; mycell *q; @@ -222,7 +188,6 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) int i; INCCOUNT(SCANCALL_COUNT); - MPS_SCAN_BEGIN(ss) { while (base < limit) { @@ -273,7 +238,6 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) } } } - MPS_SCAN_END(ss); return MPS_RES_OK; } @@ -390,7 +354,7 @@ static void myfwd(mps_addr_t object, mps_addr_t to) /* set the nth reference of obj to to (n from 0 to size-1) */ -void setref(mycell *obj, int n, mycell *to) +static void setref(mycell *obj, int n, mycell *to) { asserts(obj->tag = MCdata, "setref: from non-data object."); asserts(to->tag = MCdata, "setref: to non-data object."); @@ -400,36 +364,6 @@ void setref(mycell *obj, int n, mycell *to) obj->data.ref[n].id = to->data.id; } -mycell *getref(mycell *obj, int n) -{ - asserts(obj->tag = MCdata, "getref: from non-data object."); - asserts(obj->data.numrefs > n, "getref: access beyond object size."); - return obj->data.ref[n].addr; -} - -mps_addr_t getdata(mycell *obj) -{ - return (mps_addr_t) &(obj->data.ref[0]); -} - -long int getid(mycell *obj) -{ - asserts(obj->tag = MCdata, "getid: non-data object."); - return obj->data.id; -} - -long int getcopycount(mycell *obj) -{ - asserts(obj->tag = MCdata, "getcopycount: non-data object."); - return obj->data.copycount; -} - -long int getsize(mycell *obj) -{ - asserts(obj->tag = MCdata, "getsize: non-data object."); - return obj->data.numrefs; -} - /* ---- Now the test itself! ---- */ #define genCOUNT (3) diff --git a/mps/test/conerr/53.c b/mps/test/conerr/53.c index 0cd7a08ac37..d156e3d7f05 100644 --- a/mps/test/conerr/53.c +++ b/mps/test/conerr/53.c @@ -11,6 +11,8 @@ OUTPUT_SPEC END_HEADER */ +#include + #include "testlib.h" #include "mpscamc.h" #include "myfmt.h" @@ -20,6 +22,9 @@ static void test(void) mps_arena_t arena; mps_ld_s ld; + /* overwrite ld with junk */ + memset(&ld, 0xff, sizeof ld); + cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); /* diff --git a/mps/test/conerr/54.c b/mps/test/conerr/54.c index 994a5f73b7d..f5474c6e318 100644 --- a/mps/test/conerr/54.c +++ b/mps/test/conerr/54.c @@ -11,6 +11,8 @@ OUTPUT_SPEC END_HEADER */ +#include + #include "testlib.h" #include "mpscamc.h" #include "myfmt.h" @@ -20,6 +22,9 @@ static void test(void) mps_arena_t arena; mps_ld_s ld; + /* overwrite ld with junk */ + memset(&ld, 0xff, sizeof ld); + cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); /* diff --git a/mps/test/function/72.c b/mps/test/function/72.c index 6a761742cc2..c1d3c158f2d 100644 --- a/mps/test/function/72.c +++ b/mps/test/function/72.c @@ -15,35 +15,33 @@ END_HEADER #include "mpscamc.h" #include "exfmt.h" +void *stackpointer; + #define genCOUNT (3) static mps_gen_param_s testChain[genCOUNT] = { { 6000, 0.90 }, { 8000, 0.65 }, { 16000, 0.50 } }; -void *stackpointer; -mycell *z; - static void test(void) { mps_arena_t arena; mps_pool_t pool; - mps_thr_t thread; mps_root_t root; mps_chain_t chain; mps_fmt_t format; mps_ap_t ap; - mycell *a, *b; + mycell *a[3], *bad; + int i; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - cdie(mps_thread_reg(&thread, arena), "register thread"); + /* Clamp the arena so that we can be sure that objects don't move. */ + mps_arena_clamp(arena); - cdie( - mps_root_create_reg(&root, arena, mps_rank_ambig(), 0, thread, - mps_stack_scan_ambig, stackpointer, 0), - "create root"); + cdie(mps_root_create_area(&root, arena, mps_rank_exact(), 0, &a[0], &a[3], + mps_scan_area, NULL), "create area"); cdie( mps_fmt_create_A(&format, arena, &fmtA), @@ -59,22 +57,27 @@ static void test(void) mps_ap_create(&ap, pool, mps_rank_exact()), "create ap"); - a = allocone(ap, 1024, 1); - z = a; - - b = allocone(ap, 1024, 1); - setref(b, 0, a); - - a = allocdumb(ap, 1024*64, 1); - a = allocdumb(ap, 1024*64, 1); + /* Remember the first allocation at a[0] (which is a root) and also + * at bad (which is not reachable). */ + bad = a[0] = a[1] = allocone(ap, 1, 1); + for (i = 0; i < 1000; ++i) { + a[2] = allocone(ap, 1, 1); + setref(a[2], 0, a[1]); + a[1] = a[2]; + } + /* The first collection will cause a[0] to move, but because bad + * isn't scanned it doesn't get updated, and ends up pointing to + * oldspace. */ comment("Collecting..."); mps_arena_collect(arena); - asserts(z != a, "Didn't move!"); + asserts(bad != a[0], "Didn't move!"); + /* Write the bad pointer into a scannable part of the heap. The MPS + * should spot this when it collects. Note that we can't use setref + * here because we need to bypass the check. */ comment("Writing bad pointer..."); - - b->data.ref[0].addr = z; + a[0]->data.ref[0].addr = bad; mps_arena_collect(arena); comment("Bad pointer not spotted in collection"); @@ -96,9 +99,6 @@ static void test(void) mps_root_destroy(root); comment("Destroyed root."); - mps_thread_dereg(thread); - comment("Deregistered thread."); - mps_arena_destroy(arena); comment("Destroyed arena."); From e89429df8b98031a22da892f3046bef442b8543a Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 13 Mar 2016 14:23:41 +0000 Subject: [PATCH 245/337] Can't use count as a bitfield. Copied from Perforce Change: 189965 ServerID: perforce.ravenbrook.com --- mps/code/mpmst.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 48f80eb2255..f998da4da21 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -281,7 +281,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 */ - Count defer : WB_DEFER_BITS; /* defer write barrier for this many scans */ + unsigned defer : WB_DEFER_BITS; /* defer write barrier for this many scans */ } SegStruct; From 02df4ccedb3c3ba326022bfcd71149a4d50c008f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 13 Mar 2016 14:46:28 +0000 Subject: [PATCH 246/337] Make uuid generation portable between python 2.7 and python 3 (at least for ascii branch names). Copied from Perforce Change: 189971 ServerID: perforce.ravenbrook.com --- mps/tool/branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/tool/branch b/mps/tool/branch index 7de38f08d29..c8456ea3362 100755 --- a/mps/tool/branch +++ b/mps/tool/branch @@ -276,7 +276,7 @@ def main(argv): # Invent a UUID to use as the section title for the branch in # the Git Fusion configuration files. - args.uuid = uuid.uuid5(uuid.NAMESPACE_URL, args.child.encode('utf7')) + args.uuid = uuid.uuid5(uuid.NAMESPACE_URL, str(args.child)) print(fmt("uuid={uuid}")) for repo in GF_REPOS: From 56778dd360a9255a8ab6e6c94908cc5c883776d1 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 13 Mar 2016 14:58:09 +0000 Subject: [PATCH 247/337] Avoid unused variable warnings. Copied from Perforce Change: 189978 ServerID: perforce.ravenbrook.com --- mps/test/function/120.c | 1 - mps/test/function/96.c | 1 - 2 files changed, 2 deletions(-) diff --git a/mps/test/function/120.c b/mps/test/function/120.c index 032fa722c3f..02399ab059b 100644 --- a/mps/test/function/120.c +++ b/mps/test/function/120.c @@ -34,7 +34,6 @@ 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 diff --git a/mps/test/function/96.c b/mps/test/function/96.c index 887d0e67759..30ead894afd 100644 --- a/mps/test/function/96.c +++ b/mps/test/function/96.c @@ -30,7 +30,6 @@ static void fillup(void) { size_t size; mps_addr_t a; - char *b; die(mps_pool_create(&poolmv, arena, mps_class_mv(), (size_t)64, (size_t)64, (size_t)64), From 330eef03b79515a8ce648bb86da07a1b199dd0b8 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 13 Mar 2016 20:16:29 +0000 Subject: [PATCH 248/337] Branching master to branch/2016-03-13/without-reservation. Copied from Perforce Change: 189990 ServerID: perforce.ravenbrook.com From ca7dcd913e830f7b57e1ad946aa4af68d13a99b4 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 13 Mar 2016 20:32:24 +0000 Subject: [PATCH 249/337] Basic removal of the reservoir pool from code and design. Copied from Perforce Change: 190000 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 51 +-- mps/code/comm.gmk | 1 - mps/code/commpre.nmk | 1 - mps/code/global.c | 9 +- mps/code/mpm.h | 14 - mps/code/mpmst.h | 23 -- mps/code/mpmtypes.h | 1 - mps/code/mps.c | 1 - mps/code/mps.h | 14 +- mps/code/mps.xcodeproj/project.pbxproj | 4 - mps/code/mpsi.c | 67 +--- mps/code/mpsicv.c | 50 --- mps/code/poolmrg.c | 1 - mps/code/reserv.c | 458 ------------------------- mps/design/index.txt | 2 - mps/design/reservoir.txt | 170 --------- mps/design/seg.txt | 9 +- mps/manual/source/code-index.rst | 2 - mps/manual/source/design/old.rst | 1 - 19 files changed, 22 insertions(+), 857 deletions(-) delete mode 100644 mps/code/reserv.c delete mode 100644 mps/design/reservoir.txt diff --git a/mps/code/arena.c b/mps/code/arena.c index 860715c5059..e34fc3f6fc6 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -138,7 +138,6 @@ Bool ArenaCheck(Arena arena) CHECKL(BoolCheck(arena->poolReady)); if (arena->poolReady) { /* */ CHECKD(MV, &arena->controlPoolStruct); - CHECKD(Reservoir, &arena->reservoirStruct); } /* .reserved.check: Would like to check that arena->committed <= @@ -259,16 +258,9 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) if (res != ResOK) goto failMFSInit; - /* initialize the reservoir, */ - res = ReservoirInit(&arena->reservoirStruct, arena); - if (res != ResOK) - goto failReservoirInit; - AVERT(Arena, arena); return ResOK; -failReservoirInit: - PoolFinish(ArenaCBSBlockPool(arena)); failMFSInit: GlobalsFinish(ArenaGlobals(arena)); failGlobalsInit: @@ -394,7 +386,6 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args) void ArenaFinish(Arena arena) { PoolFinish(ArenaCBSBlockPool(arena)); - ReservoirFinish(ArenaReservoir(arena)); arena->sig = SigInvalid; GlobalsFinish(ArenaGlobals(arena)); LocusFinish(arena); @@ -441,9 +432,6 @@ void ArenaDestroy(Arena arena) GlobalsPrepareToDestroy(ArenaGlobals(arena)); - /* Empty the reservoir - see */ - ReservoirSetLimit(ArenaReservoir(arena), 0); - ControlFinish(arena); /* We must tear down the free land before the chunks, because pages @@ -1095,7 +1083,6 @@ Res ArenaAlloc(Addr *baseReturn, LocusPref pref, Size size, Pool pool, Arena arena; Addr base; Tract tract; - Reservoir reservoir; AVER(baseReturn != NULL); AVERT(LocusPref, pref); @@ -1106,27 +1093,10 @@ Res ArenaAlloc(Addr *baseReturn, LocusPref pref, Size size, Pool pool, arena = PoolArena(pool); AVERT(Arena, arena); AVER(SizeIsArenaGrains(size, arena)); - reservoir = ArenaReservoir(arena); - AVERT(Reservoir, reservoir); - - if (pool != ReservoirPool(reservoir)) { - res = ReservoirEnsureFull(reservoir); - if (res != ResOK) { - AVER(ResIsAllocFailure(res)); - if (!withReservoirPermit) - return res; - } - } res = PolicyAlloc(&tract, arena, pref, size, pool); - if (res != ResOK) { - if (withReservoirPermit) { - Res resRes = ReservoirWithdraw(&base, &tract, reservoir, size, pool); - if (resRes != ResOK) - goto allocFail; - } else - goto allocFail; - } + if (res != ResOK) + goto allocFail; base = TractBase(tract); @@ -1151,8 +1121,6 @@ void ArenaFree(Addr base, Size size, Pool pool) { Arena arena; Addr limit; - Reservoir reservoir; - Res res; Addr wholeBase; Size wholeSize; RangeStruct range, oldRange; @@ -1162,8 +1130,6 @@ void ArenaFree(Addr base, Size size, Pool pool) AVER(size > (Size)0); arena = PoolArena(pool); AVERT(Arena, arena); - reservoir = ArenaReservoir(arena); - AVERT(Reservoir, reservoir); AVER(AddrIsArenaGrain(base, arena)); AVER(SizeIsArenaGrains(size, arena)); @@ -1177,18 +1143,6 @@ void ArenaFree(Addr base, Size size, Pool pool) wholeBase = base; wholeSize = size; - if (pool != ReservoirPool(reservoir)) { - res = ReservoirEnsureFull(reservoir); - if (res != ResOK) { - AVER(ResIsAllocFailure(res)); - if (!ReservoirDeposit(reservoir, &base, &size)) - goto allDeposited; - } - } - - /* Just in case the shenanigans with the reservoir mucked this up. */ - AVER(limit == AddrAdd(base, size)); - RangeInit(&range, base, limit); arenaFreeLandInsertSteal(&oldRange, arena, &range); /* may update range */ @@ -1198,7 +1152,6 @@ void ArenaFree(Addr base, Size size, Pool pool) /* Freeing memory might create spare pages, but not more than this. */ CHECKL(arena->spareCommitted <= arena->spareCommitLimit); -allDeposited: EVENT3(ArenaFree, arena, wholeBase, wholeSize); return; } diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index e5af99266ae..65c88abc9cf 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -196,7 +196,6 @@ MPMCOMMON = \ protocol.c \ range.c \ ref.c \ - reserv.c \ ring.c \ root.c \ sa.c \ diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index e3d2443fe21..d1aa7e49d6e 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -156,7 +156,6 @@ MPMCOMMON=\ [protocol] \ [range] \ [ref] \ - [reserv] \ [ring] \ [root] \ [sa] \ diff --git a/mps/code/global.c b/mps/code/global.c index 354adb54a9a..78821c9562c 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -505,12 +505,11 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) /* At this point the following pools still exist: * 0. arena->freeCBSBlockPoolStruct - * 1. arena->reservoirStruct - * 2. arena->controlPoolStruct - * 3. arena->controlPoolStruct.blockPoolStruct - * 4. arena->controlPoolStruct.spanPoolStruct + * 1. arena->controlPoolStruct + * 2. arena->controlPoolStruct.blockPoolStruct + * 3. arena->controlPoolStruct.spanPoolStruct */ - AVER(RingLength(&arenaGlobals->poolRing) == 5); + AVER(RingLength(&arenaGlobals->poolRing) == 4); } diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 118d8ff070e..3dfa4bf5e67 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -634,20 +634,6 @@ extern void ArenaCompact(Arena arena, Trace trace); extern Res ArenaFinalize(Arena arena, Ref obj); extern Res ArenaDefinalize(Arena arena, Ref obj); -#define ArenaReservoir(arena) (&(arena)->reservoirStruct) -#define ReservoirPool(reservoir) (&(reservoir)->poolStruct) - -extern Bool ReservoirCheck(Reservoir reservoir); -extern Res ReservoirInit(Reservoir reservoir, Arena arena); -extern void ReservoirFinish (Reservoir reservoir); -extern Size ReservoirLimit(Reservoir reservoir); -extern void ReservoirSetLimit(Reservoir reservoir, Size size); -extern Size ReservoirAvailable(Reservoir reservoir); -extern Res ReservoirEnsureFull(Reservoir reservoir); -extern Bool ReservoirDeposit(Reservoir reservoir, Addr *baseIO, Size *sizeIO); -extern Res ReservoirWithdraw(Addr *baseReturn, Tract *baseTractReturn, - Reservoir reservoir, Size size, Pool pool); - extern Res ArenaAlloc(Addr *baseReturn, LocusPref pref, Size size, Pool pool, Bool withReservoirPermit); extern Res ArenaFreeLandAlloc(Tract *tractReturn, Arena arena, ZoneSet zones, diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 8b76dec162a..778dc50c30a 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -165,27 +165,6 @@ typedef struct MVStruct { /* MV pool outer structure */ } MVStruct; -/* ReservoirStruct -- Reservoir structure - * - * .reservoir: See , . - * - * The Reservoir structure is declared here because it is in-lined in - * the arena for storing segments for the low-memory reservoir. It is - * implemented as a pool - but doesn't follow the normal pool naming - * conventions because it's not intended for general use and the use of - * a pool is an incidental detail. */ - -#define ReservoirSig ((Sig)0x5196e599) /* SIGnature REServoir */ - -typedef struct ReservoirStruct { /* Reservoir structure */ - PoolStruct poolStruct; /* generic pool structure */ - Tract reserve; /* linked list of reserve tracts */ - Size reservoirLimit; /* desired reservoir size */ - Size reservoirSize; /* actual reservoir size */ - Sig sig; /* */ -} ReservoirStruct; - - /* MessageClassStruct -- Message Class structure * * See (and , @@ -711,8 +690,6 @@ typedef struct mps_arena_s { Bool poolReady; /* */ MVStruct controlPoolStruct; /* */ - ReservoirStruct reservoirStruct; /* */ - Size reserved; /* total reserved address space */ Size committed; /* total committed memory */ Size commitLimit; /* client-configurable commit limit */ diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 7232f081a39..747b041bf85 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -106,7 +106,6 @@ typedef struct MutatorFaultContextStruct typedef struct PoolDebugMixinStruct *PoolDebugMixin; typedef struct AllocPatternStruct *AllocPattern; typedef struct AllocFrameStruct *AllocFrame; /* */ -typedef struct ReservoirStruct *Reservoir; /* */ typedef struct StackContextStruct *StackContext; typedef struct RangeStruct *Range; /* */ typedef struct LandStruct *Land; /* */ diff --git a/mps/code/mps.c b/mps/code/mps.c index 48028242a92..abc1535572e 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -39,7 +39,6 @@ #include "locus.c" #include "tract.c" #include "walk.c" -#include "reserv.c" #include "protocol.c" #include "pool.c" #include "poolabs.c" diff --git a/mps/code/mps.h b/mps/code/mps.h index 05b2644ec8e..ccb1173fb42 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -609,7 +609,7 @@ extern void mps_sac_empty(mps_sac_t, mps_addr_t, size_t); #define MPS_SAC_FREE(sac, p, size) MPS_SAC_FREE_FAST(sac, p, size) -/* Low memory reservoir */ +/* Low memory reservoir (deprecated) */ extern void mps_reservoir_limit_set(mps_arena_t, size_t); extern size_t mps_reservoir_limit(mps_arena_t); @@ -645,17 +645,7 @@ extern mps_res_t mps_reserve_with_reservoir_permit(mps_addr_t *, MPS_END -#define MPS_RESERVE_WITH_RESERVOIR_PERMIT_BLOCK(_res_v, _p_v, _mps_ap, _size) \ - MPS_BEGIN \ - char *_alloc = (char *)(_mps_ap)->alloc; \ - char *_next = _alloc + (_size); \ - if(_next > _alloc && _next <= (char *)(_mps_ap)->limit) { \ - (_mps_ap)->alloc = (mps_addr_t)_next; \ - (_p_v) = (_mps_ap)->init; \ - (_res_v) = MPS_RES_OK; \ - } else \ - (_res_v) = mps_ap_fill_with_reservoir_permit(&(_p_v), _mps_ap, _size); \ - MPS_END +#define MPS_RESERVE_WITH_RESERVOIR_PERMIT_BLOCK MPS_RESERVE_BLOCK /* Commit Macros */ diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index d1c8e92c431..9cfea1da0d3 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -1574,7 +1574,6 @@ 31160DBC1899540D0071EB17 /* protsu.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = protsu.txt; path = ../design/protsu.txt; sourceTree = ""; }; 31160DBD1899540D0071EB17 /* pthreadext.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = pthreadext.txt; path = ../design/pthreadext.txt; sourceTree = ""; }; 31160DBE1899540D0071EB17 /* range.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = range.txt; path = ../design/range.txt; sourceTree = ""; }; - 31160DBF1899540D0071EB17 /* reservoir.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = reservoir.txt; path = ../design/reservoir.txt; sourceTree = ""; }; 31160DC01899540D0071EB17 /* ring.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = ring.txt; path = ../design/ring.txt; sourceTree = ""; }; 31160DC11899540D0071EB17 /* root.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = root.txt; path = ../design/root.txt; sourceTree = ""; }; 31160DC21899540D0071EB17 /* scan.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = scan.txt; path = ../design/scan.txt; sourceTree = ""; }; @@ -1706,7 +1705,6 @@ 31EEAC09156AB27B00714D05 /* pool.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pool.c; sourceTree = ""; }; 31EEAC0A156AB27B00714D05 /* poolabs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = poolabs.c; sourceTree = ""; }; 31EEAC0B156AB27B00714D05 /* protocol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = protocol.c; sourceTree = ""; }; - 31EEAC0C156AB27B00714D05 /* reserv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = reserv.c; sourceTree = ""; }; 31EEAC0D156AB27B00714D05 /* tract.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tract.c; sourceTree = ""; }; 31EEAC0E156AB27B00714D05 /* walk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = walk.c; sourceTree = ""; }; 31EEAC19156AB2B200714D05 /* buffer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = buffer.c; sourceTree = ""; }; @@ -2234,7 +2232,6 @@ 31160DBC1899540D0071EB17 /* protsu.txt */, 31160DBD1899540D0071EB17 /* pthreadext.txt */, 31160DBE1899540D0071EB17 /* range.txt */, - 31160DBF1899540D0071EB17 /* reservoir.txt */, 31160DC01899540D0071EB17 /* ring.txt */, 31160DC11899540D0071EB17 /* root.txt */, 31160DC21899540D0071EB17 /* scan.txt */, @@ -2493,7 +2490,6 @@ 2291A5EB175CB53E001D4920 /* range.c */, 2291A5EC175CB53E001D4920 /* range.h */, 31EEAC1B156AB2B200714D05 /* ref.c */, - 31EEAC0C156AB27B00714D05 /* reserv.c */, 31EEAC30156AB2F200714D05 /* ring.c */, 311F2F7317398B7100C15B6A /* ring.h */, 31EEAC1C156AB2B200714D05 /* root.c */, diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index a6e24f0c63a..b97c6c4dc2b 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -894,17 +894,7 @@ mps_res_t (mps_reserve)(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size) mps_res_t mps_reserve_with_reservoir_permit(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size) { - mps_res_t res; - - AVER(p_o != NULL); - AVER(size > 0); - AVER(mps_ap != NULL); - AVER(TESTT(Buffer, BufferOfAP(mps_ap))); - AVER(mps_ap->init == mps_ap->alloc); - - MPS_RESERVE_WITH_RESERVOIR_PERMIT_BLOCK(res, *p_o, mps_ap, size); - - return res; + return mps_reserve(p_o, mps_ap, size); } @@ -1059,32 +1049,7 @@ mps_res_t mps_ap_fill(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size) mps_res_t mps_ap_fill_with_reservoir_permit(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size) { - Buffer buf = BufferOfAP(mps_ap); - Arena arena; - Addr p; - Res res; - - AVER(mps_ap != NULL); - AVER(TESTT(Buffer, buf)); - arena = BufferArena(buf); - - ArenaEnter(arena); - - ArenaPoll(ArenaGlobals(arena)); /* .poll */ - - AVER(p_o != NULL); - AVERT(Buffer, buf); - AVER(size > 0); - AVER(SizeIsAligned(size, BufferPool(buf)->alignment)); - - res = BufferFill(&p, buf, size, TRUE); - - ArenaLeave(arena); - - if (res != ResOK) - return (mps_res_t)res; - *p_o = (mps_addr_t)p; - return MPS_RES_OK; + return mps_ap_fill(p_o, mps_ap, size); } @@ -2058,16 +2023,16 @@ mps_res_t mps_ap_alloc_pattern_reset(mps_ap_t mps_ap) } -/* Low memory reservoir */ +/* Low memory reservoir (deprecated -- see job003985) */ /* mps_reservoir_limit_set -- set the reservoir size */ void mps_reservoir_limit_set(mps_arena_t arena, size_t size) { - ArenaEnter(arena); - ReservoirSetLimit(ArenaReservoir(arena), size); - ArenaLeave(arena); + UNUSED(arena); + UNUSED(size); + NOOP; } @@ -2075,14 +2040,8 @@ void mps_reservoir_limit_set(mps_arena_t arena, size_t size) size_t mps_reservoir_limit(mps_arena_t arena) { - Size size; - - ArenaEnter(arena); - - size = ReservoirLimit(ArenaReservoir(arena)); - - ArenaLeave(arena); - return size; + UNUSED(arena); + return 0; } @@ -2090,14 +2049,8 @@ size_t mps_reservoir_limit(mps_arena_t arena) size_t mps_reservoir_available(mps_arena_t arena) { - Size size; - - ArenaEnter(arena); - - size = ReservoirAvailable(ArenaReservoir(arena)); - - ArenaLeave(arena); - return size; + UNUSED(arena); + return 0; } diff --git a/mps/code/mpsicv.c b/mps/code/mpsicv.c index 7eae7eb497c..f0415f4e847 100644 --- a/mps/code/mpsicv.c +++ b/mps/code/mpsicv.c @@ -143,31 +143,6 @@ static mps_addr_t make(void) } -/* make_with_permit -- allocate an object, with reservoir permit */ - -static mps_addr_t make_with_permit(void) -{ - size_t length = rnd() % 20; - size_t sizeCli = (length+2)*sizeof(mps_word_t); - size_t sizeMps = SizeCli2Mps(sizeCli); - mps_addr_t pMps, pCli; - mps_res_t res; - - do { - MPS_RESERVE_WITH_RESERVOIR_PERMIT_BLOCK(res, pMps, ap, sizeMps); - if (res != MPS_RES_OK) - die(res, "MPS_RESERVE_WITH_RESERVOIR_PERMIT_BLOCK"); - HeaderInit(pMps); - pCli = PtrMps2Cli(pMps); - res = dylan_init(pCli, sizeCli, exactRoots, exactRootsCOUNT); - if (res != MPS_RES_OK) - die(res, "dylan_init"); - } while(!mps_commit(ap, pMps, sizeMps)); - - return pCli; -} - - /* make_no_inline -- allocate an object, using non-inlined interface */ static mps_addr_t make_no_inline(void) @@ -358,30 +333,6 @@ static void arena_commit_test(mps_arena_t arena) } -/* reservoir_test -- Test the reservoir interface - * - * This has not been tuned to actually dip into the reservoir. See - * QA test 132 for that. - */ - -#define reservoirSIZE ((size_t)128 * 1024) - -static void reservoir_test(mps_arena_t arena) -{ - (void)make_with_permit(); - cdie(mps_reservoir_available(arena) == 0, "empty reservoir"); - cdie(mps_reservoir_limit(arena) == 0, "no reservoir"); - mps_reservoir_limit_set(arena, reservoirSIZE); - cdie(mps_reservoir_limit(arena) >= reservoirSIZE, "reservoir limit set"); - cdie(mps_reservoir_available(arena) >= reservoirSIZE, "got reservoir"); - (void)make_with_permit(); - mps_reservoir_limit_set(arena, 0); - cdie(mps_reservoir_available(arena) == 0, "empty reservoir"); - cdie(mps_reservoir_limit(arena) == 0, "no reservoir"); - (void)make_with_permit(); -} - - static void *test(void *arg, size_t s) { mps_arena_t arena; @@ -555,7 +506,6 @@ static void *test(void *arg, size_t s) } arena_commit_test(arena); - reservoir_test(arena); alignmentTest(arena); die(mps_arena_collect(arena), "collect"); diff --git a/mps/code/poolmrg.c b/mps/code/poolmrg.c index 2cb5e7a2f21..ec48151ab4e 100644 --- a/mps/code/poolmrg.c +++ b/mps/code/poolmrg.c @@ -722,7 +722,6 @@ Res MRGRegister(Pool pool, Ref ref) /* */ if (RingIsSingle(&mrg->freeRing)) { - /* @@@@ Should the client be able to use the reservoir for this? */ res = MRGSegPairCreate(&junk, mrg, /* withReservoirPermit */ FALSE); if (res != ResOK) return res; diff --git a/mps/code/reserv.c b/mps/code/reserv.c deleted file mode 100644 index 91a2fd52559..00000000000 --- a/mps/code/reserv.c +++ /dev/null @@ -1,458 +0,0 @@ -/* reserv.c: ARENA RESERVOIR - * - * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. - * - * IMPROVEMENTS - * - * .improve.contiguous: There should be a means of grouping contiguous - * tracts together so that there's a likelihood of being able to meet - * requests for regions larger than the arena grain size. */ - -#include "mpm.h" - -SRCID(reserv, "$Id$"); - - -/* The reservoir pool is defined here. See */ - -#define PoolReservoir(pool) PARENT(ReservoirStruct, poolStruct, pool) - - -/* Management of tracts - * - * The reservoir maintains a linked list of tracts in arbitrary order. - * (see .improve.contiguous) - * - * Tracts are chained using the TractP field. */ - -#define resTractNext(tract) ((Tract)TractP((tract))) -#define resTractSetNext(tract, next) (TractSetP((tract), (void*)(next))) - - -#define reservoirArena(reservoir) (PoolArena(ReservoirPool(reservoir))) - - -/* ResPoolInit -- Reservoir pool init method */ - -static Res ResPoolInit(Pool pool, ArgList arg) -{ - AVER(pool != NULL); - - UNUSED(arg); - /* Caller will set sig and AVERT. */ - EVENT3(PoolInit, pool, PoolArena(pool), ClassOfPool(pool)); - return ResOK; -} - - -/* ResPoolFinish -- Reservoir pool finish method - * - * .reservoir.finish: This might be called from ArenaFinish, so the - * arena cannot be checked at this time. In order to avoid the check, - * insist that the reservoir is empty, by AVERing that the reserve list - * is NULL. */ - -static void ResPoolFinish(Pool pool) -{ - Reservoir reservoir; - - AVERT(Pool, pool); - reservoir = PoolReservoir(pool); - AVERT(Reservoir, reservoir); - AVER(reservoir->reserve == NULL); /* .reservoir.finish */ -} - - -/* ReservoirPoolClass -- Class definition */ - -DEFINE_POOL_CLASS(ReservoirPoolClass, this) -{ - INHERIT_CLASS(this, AbstractPoolClass); - this->name = "Reservoir"; - this->size = sizeof(ReservoirStruct); - this->offset = offsetof(ReservoirStruct, poolStruct); - this->init = ResPoolInit; - this->finish = ResPoolFinish; - AVERT(PoolClass, this); -} - - -/* ReservoirCheck -- Reservoir check method */ - -Bool ReservoirCheck(Reservoir reservoir) -{ - ReservoirPoolClass reservoircl = EnsureReservoirPoolClass(); - Arena arena; - Tract tract; - - CHECKS(Reservoir, reservoir); - CHECKD(Pool, ReservoirPool(reservoir)); - CHECKL(ReservoirPool(reservoir)->class == reservoircl); - UNUSED(reservoircl); /* */ - arena = reservoirArena(reservoir); - CHECKU(Arena, arena); - /* could call ReservoirIsConsistent, but it's costly. */ - tract = reservoir->reserve; - if (tract != NULL) { - CHECKD_NOSIG(Tract, tract); - CHECKL(TractPool(tract) == ReservoirPool(reservoir)); - } - CHECKL(SizeIsArenaGrains(reservoir->reservoirLimit, arena)); - CHECKL(SizeIsArenaGrains(reservoir->reservoirSize, arena)); - CHECKL(reservoir->reservoirSize <= reservoir->reservoirLimit); - - return TRUE; -} - - -/* reservoirIsConsistent -- returns FALSE if the reservoir is corrupt */ - -ATTRIBUTE_UNUSED -static Bool reservoirIsConsistent(Reservoir reservoir) -{ - Size grainSize, size = 0; - Tract tract; - Pool pool; - Arena arena; - - arena = reservoirArena(reservoir); - pool = ReservoirPool(reservoir); - - /* Check that the size of the tracts matches reservoirSize */ - grainSize = ArenaGrainSize(arena); - tract = reservoir->reserve; - while (tract != NULL) { - AVERT(Tract, tract); - AVER(TractPool(tract) == pool); - tract = resTractNext(tract); - size += grainSize; - } - - if (size != reservoir->reservoirSize) - return FALSE; - - /* */ - return SizeIsAligned(reservoir->reservoirLimit, grainSize) - && SizeIsAligned(reservoir->reservoirSize, grainSize) - && (reservoir->reservoirLimit >= reservoir->reservoirSize); -} - - -/* ReservoirEnsureFull - * - * Ensures that the reservoir is the right size, by topping it up with - * fresh memory from the arena if possible. */ - -Res ReservoirEnsureFull(Reservoir reservoir) -{ - Size limit, size; - Pool pool; - Arena arena; - AVERT(Reservoir, reservoir); - arena = reservoirArena(reservoir); - - AVERT(Arena, arena); - size = ArenaGrainSize(arena); - limit = reservoir->reservoirLimit; - - /* optimize the common case of a full reservoir */ - if (reservoir->reservoirSize == limit) - return ResOK; - - pool = ReservoirPool(reservoir); - - /* really ought to try hard to allocate contiguous tracts */ - /* see .improve.contiguous */ - while (reservoir->reservoirSize < limit) { - Res res; - Addr base; - Tract tract; - res = ArenaAlloc(&base, LocusPrefDefault(), size, pool, FALSE); - if (res != ResOK) { - AVER(reservoirIsConsistent(reservoir)); - return res; - } - tract = TractOfBaseAddr(arena, base); - reservoir->reservoirSize += size; - resTractSetNext(tract, reservoir->reserve); - reservoir->reserve = tract; - } - AVER(reservoirIsConsistent(reservoir)); - return ResOK; -} - - -/* reservoirShrink -- Reduce the size of the reservoir */ - -static void reservoirShrink(Reservoir reservoir, Size want) -{ - Arena arena; - Pool pool; - Size size; - - pool = ReservoirPool(reservoir); - arena = reservoirArena(reservoir); - AVER(SizeIsArenaGrains(want, arena)); - AVER(reservoir->reservoirSize >= want); - - if (reservoir->reservoirSize == want) - return; - - /* Iterate over tracts, freeing them while reservoir is too big */ - size = ArenaGrainSize(arena); - while (reservoir->reservoirSize > want) { - Tract tract = reservoir->reserve; - AVER(tract != NULL); - reservoir->reserve = resTractNext(tract); - ArenaFree(TractBase(tract), size, pool); - reservoir->reservoirSize -= size; - } - AVER(reservoir->reservoirSize == want); - AVER(reservoirIsConsistent(reservoir)); -} - - -/* ReservoirWithdraw -- Attempt to supply memory from the reservoir */ - -Res ReservoirWithdraw(Addr *baseReturn, Tract *baseTractReturn, - Reservoir reservoir, Size size, Pool pool) -{ - Arena arena; - - AVER(baseReturn != NULL); - AVER(baseTractReturn != NULL); - AVERT(Reservoir, reservoir); - arena = reservoirArena(reservoir); - AVERT(Arena, arena); - AVER(SizeIsArenaGrains(size, arena)); - AVER(size > 0); - AVERT(Pool, pool); - - /* @@@@ As a short-term measure, we only permit the reservoir to */ - /* allocate single-page regions. */ - /* See .improve.contiguous & change.dylan.jackdaw.160125 */ - if (size != ArenaGrainSize(arena)) - return ResMEMORY; - - if (size <= reservoir->reservoirSize) { - /* Return the first tract */ - Tract tract = reservoir->reserve; - Addr base; - AVER(tract != NULL); - base = TractBase(tract); - reservoir->reserve = resTractNext(tract); - reservoir->reservoirSize -= ArenaGrainSize(arena); - TractFinish(tract); - TractInit(tract, pool, base); - AVER(reservoirIsConsistent(reservoir)); - *baseReturn = base; - *baseTractReturn = tract; - return ResOK; - } - - AVER(reservoirIsConsistent(reservoir)); - return ResMEMORY; /* no suitable region in the reservoir */ -} - - -/* ReservoirDeposit -- Top up the reservoir */ - -Bool ReservoirDeposit(Reservoir reservoir, Addr *baseIO, Size *sizeIO) -{ - Pool respool; - Addr addr, limit; - Size reslimit; - Arena arena; - Tract tract; - Addr base; - Size size; - - AVERT(Reservoir, reservoir); - arena = reservoirArena(reservoir); - AVERT(Arena, arena); - respool = ReservoirPool(reservoir); - AVER(baseIO != NULL); - AVER(sizeIO != NULL); - base = *baseIO; - size = *sizeIO; - AVER(AddrIsArenaGrain(base, arena)); - AVER(SizeIsArenaGrains(size, arena)); - limit = AddrAdd(base, size); - reslimit = reservoir->reservoirLimit; - - /* put as many pages as necessary into the reserve & free the rest */ - TRACT_FOR(tract, addr, arena, base, limit) { - AVERT(Tract, tract); - if (reservoir->reservoirSize < reslimit) { - /* Reassign the tract to the reservoir pool */ - TractFinish(tract); - TractInit(tract, respool, addr); - reservoir->reservoirSize += ArenaGrainSize(arena); - resTractSetNext(tract, reservoir->reserve); - reservoir->reserve = tract; - } else { - *baseIO = addr; - *sizeIO = AddrOffset(base, limit); - AVER(reservoirIsConsistent(reservoir)); - return TRUE; - } - } - AVER(addr == limit); - AVER(reservoirIsConsistent(reservoir)); - return FALSE; -} - - -/* mutatorBufferCount -- returns the number of mutator buffers for the arena - * - * This should probably be in the pool module, but it's only used here. */ - -static Count mutatorBufferCount(Globals arena) -{ - Ring nodep, nextp; - Count count = 0; - - /* Iterate over all pools, and count the mutator buffers in each */ - RING_FOR(nodep, &arena->poolRing, nextp) { - Pool pool = RING_ELT(Pool, arenaRing, nodep); - Ring nodeb, nextb; - - AVERT(Pool, pool); - RING_FOR(nodeb, &pool->bufferRing, nextb) { - Buffer buff = RING_ELT(Buffer, poolRing, nodeb); - if (buff->isMutator) - count++; - } - } - return count; -} - - -/* ReservoirSetLimit -- Set the reservoir limit */ - -void ReservoirSetLimit(Reservoir reservoir, Size size) -{ - Size needed; - Arena arena; - AVERT(Reservoir, reservoir); - arena = reservoirArena(reservoir); - AVERT(Arena, arena); - - if (size > 0) { - Size wastage; - /* */ - wastage = ArenaGrainSize(arena) * mutatorBufferCount(ArenaGlobals(arena)); - /* */ - needed = SizeArenaGrains(size, arena) + wastage; - } else { - needed = 0; /* */ - } - - AVER(SizeIsArenaGrains(needed, arena)); - /* Emit event now, so subsequent change can be ascribed to it. */ - EVENT2(ReservoirLimitSet, arena, size); - - if (needed > reservoir->reservoirSize) { - /* Try to grow the reservoir */ - reservoir->reservoirLimit = needed; - (void)ReservoirEnsureFull(reservoir); - } else { - /* Shrink the reservoir */ - reservoirShrink(reservoir, needed); - reservoir->reservoirLimit = needed; - AVER(reservoirIsConsistent(reservoir)); - } -} - - -/* ReservoirLimit -- Return the reservoir limit */ - -Size ReservoirLimit(Reservoir reservoir) -{ - AVERT(Reservoir, reservoir); - AVER(reservoirIsConsistent(reservoir)); - return reservoir->reservoirLimit; -} - - -/* ReservoirAvailable -- Return the amount in the reservoir */ - -Size ReservoirAvailable(Reservoir reservoir) -{ - AVERT(Reservoir, reservoir); - (void)ReservoirEnsureFull(reservoir); - return reservoir->reservoirSize; -} - - -/* ReservoirInit -- Initialize a reservoir */ - -Res ReservoirInit(Reservoir reservoir, Arena arena) -{ - Res res; - - /* reservoir and arena are not initialized and can't be checked */ - reservoir->reservoirLimit = (Size)0; - reservoir->reservoirSize = (Size)0; - reservoir->reserve = NULL; - reservoir->sig = ReservoirSig; - /* initialize the reservoir pool, */ - res = PoolInit(ReservoirPool(reservoir), - arena, EnsureReservoirPoolClass(), argsNone); - if (res == ResOK) { - AVERT(Reservoir, reservoir); - } - return res; -} - - -/* ReservoirFinish -- Finish a reservoir */ - -void ReservoirFinish (Reservoir reservoir) -{ - PoolFinish(ReservoirPool(reservoir)); - reservoir->sig = SigInvalid; -} - - -/* 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/design/index.txt b/mps/design/index.txt index 9e0a1090cda..cde852448bb 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -92,7 +92,6 @@ protocol_ Protocol inheritance protsu_ SunOS 4 implementation of protection module pthreadext_ POSIX thread extensions range_ Ranges of addresses -reservoir_ The low-memory reservoir ring_ Ring data structure root_ Root manager scan_ The generic scanner @@ -172,7 +171,6 @@ writef_ The WriteF function .. _protsu: protsu .. _pthreadext: pthreadext .. _range: range -.. _reservoir: reservoir .. _ring: ring .. _root: root .. _scan: scan diff --git a/mps/design/reservoir.txt b/mps/design/reservoir.txt deleted file mode 100644 index 1c9e8c6fe1e..00000000000 --- a/mps/design/reservoir.txt +++ /dev/null @@ -1,170 +0,0 @@ -.. mode: -*- rst -*- - -The low-memory reservoir -======================== - -:Tag: design.mps.reservoir -:Author: Tony Mann -:Date: 1998-07-30 -:Status: incomplete design -:Revision: $Id$ -:Copyright: See `Copyright and License`_. -:Index terms: pair: reservoir; design - - -Introduction ------------- - -_`.intro`: The low-memory reservoir provides client support for -implementing handlers for low-memory situations which allocate. The -reservoir is implemented inside the arena as a pool of unallocatable -segments. - - -Architecture ------------- - -``typedef struct ReservoirStruct *Reservoir`` - -_`.adt`: The reservoir interface looks (almost) like an abstract data -type of type ``Reservoir``. It's not quite abstract because the arena -embeds the structure of the reservoir (of type ``ReservoirStruct``) -into its own structure, for simplicity of initialization. - -_`.align`: The reservoir is implemented as a pool of available tracts, -along with a size and limit which must always be aligned to the arena -alignment. The size corresponds to the amount of memory currently -maintained in the reservoir. The limit is the maximum amount that it -is desired to maintain. - -_`.wastage`: When the reservoir limit is set by the client, the actual -limit should be increased by one arena grain for every active mutator -buffer. - -_`.really-empty`: When the reservoir limit is set to 0, assume that -the client really doesn't have a need for a reservoir at all. In this -case, the client won't even want an allowance to be made for wastage -in active buffers. - - -Implementation --------------- - -_`.interface`: The following functions comprise the interface to the -reservoir module: - -``Bool ReservoirCheck(Reservoir reservoir)`` - -_`.interface.check`: ``ReservoirCheck()`` checks the reservoir for -consistency. - -``Res ReservoirInit(Reservoir reservoir, Arena arena)`` - -_`.interface.init`: ``ReservoirInit()`` initializes the reservoir and -its associated pool, setting the size and limit to 0. - -``void ReservoirFinish (Reservoir reservoir)`` - -_`.interface.finish`: ``ReservoirFinish()`` de-initializes the reservoir -and its associated pool: - -``Size ReservoirLimit(Reservoir reservoir)`` - -_`.interface.limit`: ``ReservoirLimit()`` returns the limit of the -reservoir: - -``void ReservoirSetLimit(Reservoir reservoir, Size size)`` - -_`.interface.set-limit`: ``ReservoirSetLimit()`` sets the limit of the -reservoir, making an allowance for wastage in mutator buffers: - -``Size ReservoirAvailable(Reservoir reservoir)`` - -_`.interface.available`: ``ReservoirAvailable()`` returns the available -size of the reservoir: - -``Res ReservoirEnsureFull(Reservoir reservoir)`` - -_`.interface.ensure-full`: ``ReservoirEnsureFull()`` attempts to fill -the reservoir with memory from the arena, until it is full: - -``void ReservoirDeposit(Reservoir reservoir, Addr base, Size size)`` - -_`.interface.deposit`: ``ReservoirDeposit()`` attempts to fill the -reservoir with memory in the supplied range, until it is full. This is -called by the arena from ``ArenaFree()`` if the reservoir is not known -to be full. Any memory which is not added to the reservoir (because -the reservoir is full) is freed via the arena class's free method. - -``Res ReservoirWithdraw(Addr *baseReturn, Tract *baseTractReturn, Reservoir reservoir, Size size, Pool pool)`` - -_`.interface.withdraw`: ``ReservoirWithdraw()`` attempts to allocate -memory of the specified size to the specified pool to the reservoir. -If no suitable memory can be found it returns ``ResMEMORY``. - -_`.interface.withdraw.align`: Currently, ``ReservoirWithdraw()`` can -only withdraw a single arena grain at a time. This is because the -reservoir doesn't attempt to coalesce adjacent memory blocks. This -deficiency should be fixed in the future. - -_`.pool`: The memory managed by the reservoir is owned by the -reservoir pool. This memory is never sub-allocated. Each tract -belonging to the pool is linked onto a list. The head of the list is -in the ``Reservoir`` object. Links are stored in the ``TractP`` fields -of each tract object. - - -Document History ----------------- - -- 1998-07-30 Tony Mann. Incomplete design. - -- 2002-06-07 RB_ Converted from MMInfo database design document. - -- 2013-05-22 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/seg.txt b/mps/design/seg.txt index db797f233c0..c8cad89137b 100644 --- a/mps/design/seg.txt +++ b/mps/design/seg.txt @@ -242,9 +242,8 @@ split. The method is responsible for destructively modifying ``seg`` and initializing ``segHi`` so that on exit ``seg`` is a segment with region ``[base,mid)`` and ``segHi`` is a segment with region ``[mid,limit)``. Usually a method would only directly modify the -fields defined for the segment subclass. This might involve -allocation, which may use the reservoir if ``withReservoirPermit`` is -``TRUE``. +fields defined for the segment subclass. ``withReservoirPermit`` is +ignored (see job003985). _`.method.split.next`: A split method should always call the next method, either before or after any class-specific code (see @@ -261,8 +260,8 @@ segment with region ``[mid,limit)``, The method is responsible for destructively modifying ``seg`` and finishing ``segHi`` so that on exit ``seg`` is a segment with region ``[base,limit)`` and ``segHi`` is garbage. Usually a method would only modify the fields defined for -the segment subclass. This might involve allocation, which may use the -reservoir if ``withReservoirPermit`` is ``TRUE``. +the segment subclass. ``withReservoirPermit`` is ignored (see +job003985). _`.method.merge.next`: A merge method should always call the next method, either before or after any class-specific code (see diff --git a/mps/manual/source/code-index.rst b/mps/manual/source/code-index.rst index c38dff4a9cf..967ed0355bf 100644 --- a/mps/manual/source/code-index.rst +++ b/mps/manual/source/code-index.rst @@ -125,7 +125,6 @@ protocol.h Inheritance protocol interface. See design.mps.protocol_. range.c Address ranges implementation. See design.mps.range_. range.h Address ranges interface. See design.mps.range_. ref.c Ranks and zones implementation. -reserv.c Reservoir pool implementation. See design.mps.reservoir_. ring.c Ring implementation. See design.mps.ring_. ring.h Ring interface. See design.mps.ring_. root.c :ref:`topic-root` implementation. @@ -431,7 +430,6 @@ xci6ll.gmk GNU makefile for platform XCI6LL. .. _design.mps.protocol: design/protocol.html .. _design.mps.prot: design/prot.html .. _design.mps.range: design/range.html -.. _design.mps.reservoir: design/reservoir.html .. _design.mps.ring: design/ring.html .. _design.mps.seg: design/seg.html .. _design.mps.shield: design/shield.html diff --git a/mps/manual/source/design/old.rst b/mps/manual/source/design/old.rst index 8a8e71be1a6..69c872c773c 100644 --- a/mps/manual/source/design/old.rst +++ b/mps/manual/source/design/old.rst @@ -45,7 +45,6 @@ Old design protsu protocol pthreadext - reservoir root scan seg From 07987ab5799da7e6d0b8d05d2ea033e02685b918 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 13 Mar 2016 21:04:01 +0000 Subject: [PATCH 250/337] Eliminating withreservoirpermit and all its variants. Copied from Perforce Change: 190005 ServerID: perforce.ravenbrook.com --- mps/code/abq.c | 3 +- mps/code/arena.c | 11 ++---- mps/code/arenacv.c | 4 +- mps/code/bt.c | 3 +- mps/code/buffer.c | 16 +++----- mps/code/cbs.c | 3 +- mps/code/dbgpool.c | 33 ++++++---------- mps/code/eventdef.h | 3 +- mps/code/fbmtest.c | 3 +- mps/code/format.c | 3 +- mps/code/fotest.c | 4 +- mps/code/global.c | 4 +- mps/code/land.c | 3 +- mps/code/landtest.c | 3 +- mps/code/locus.c | 10 ++--- mps/code/locus.h | 2 +- mps/code/messtest.c | 2 +- mps/code/mpm.h | 38 +++++++------------ mps/code/mpmtypes.h | 14 +++---- mps/code/mpsi.c | 7 ++-- mps/code/nailboard.c | 2 +- mps/code/pool.c | 9 ++--- mps/code/poolabs.c | 18 +++------ mps/code/poolamc.c | 19 ++++------ mps/code/poolams.c | 31 ++++++--------- mps/code/poolawl.c | 26 +++++-------- mps/code/poollo.c | 24 +++++------- mps/code/poolmfs.c | 7 +--- mps/code/poolmrg.c | 20 ++++------ mps/code/poolmv.c | 16 +++----- mps/code/poolmv2.c | 29 ++++++-------- mps/code/poolmvff.c | 37 ++++++------------ mps/code/pooln.c | 8 +--- mps/code/poolncv.c | 2 +- mps/code/poolsnc.c | 12 ++---- mps/code/root.c | 2 +- mps/code/sac.c | 8 ++-- mps/code/sac.h | 2 +- mps/code/seg.c | 75 ++++++++++++------------------------- mps/code/segsmss.c | 38 +++++++------------ mps/code/than.c | 3 +- mps/code/thix.c | 3 +- mps/code/thw3.c | 3 +- mps/code/thxc.c | 3 +- mps/code/traceanc.c | 6 +-- mps/design/object-debug.txt | 11 ++---- 46 files changed, 206 insertions(+), 377 deletions(-) diff --git a/mps/code/abq.c b/mps/code/abq.c index 7a3df81408e..c6620be89da 100644 --- a/mps/code/abq.c +++ b/mps/code/abq.c @@ -41,8 +41,7 @@ Res ABQInit(Arena arena, ABQ abq, void *owner, Count elements, Size elementSize) "empty" from "full" */ elements = elements + 1; - res = ControlAlloc(&p, arena, ABQQueueSize(elements, elementSize), - /* withReservoirPermit */ FALSE); + res = ControlAlloc(&p, arena, ABQQueueSize(elements, elementSize)); if (res != ResOK) return res; diff --git a/mps/code/arena.c b/mps/code/arena.c index e34fc3f6fc6..a74201c75d4 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -632,8 +632,7 @@ Res ArenaDescribeTracts(Arena arena, mps_lib_FILE *stream, Count depth) * with void* (), ControlAlloc must take care of * allocating so that the block can be addressed with a void*. */ -Res ControlAlloc(void **baseReturn, Arena arena, size_t size, - Bool withReservoirPermit) +Res ControlAlloc(void **baseReturn, Arena arena, size_t size) { Addr base; Res res; @@ -641,11 +640,9 @@ Res ControlAlloc(void **baseReturn, Arena arena, size_t size, AVERT(Arena, arena); AVER(baseReturn != NULL); AVER(size > 0); - AVERT(Bool, withReservoirPermit); AVER(arena->poolReady); - res = PoolAlloc(&base, ArenaControlPool(arena), (Size)size, - withReservoirPermit); + res = PoolAlloc(&base, ArenaControlPool(arena), (Size)size); if (res != ResOK) return res; @@ -1076,8 +1073,7 @@ Res ArenaFreeLandAlloc(Tract *tractReturn, Arena arena, ZoneSet zones, /* ArenaAlloc -- allocate some tracts from the arena */ -Res ArenaAlloc(Addr *baseReturn, LocusPref pref, Size size, Pool pool, - Bool withReservoirPermit) +Res ArenaAlloc(Addr *baseReturn, LocusPref pref, Size size, Pool pool) { Res res; Arena arena; @@ -1088,7 +1084,6 @@ Res ArenaAlloc(Addr *baseReturn, LocusPref pref, Size size, Pool pool, AVERT(LocusPref, pref); AVER(size > (Size)0); AVERT(Pool, pool); - AVERT(Bool, withReservoirPermit); arena = PoolArena(pool); AVERT(Arena, arena); diff --git a/mps/code/arenacv.c b/mps/code/arenacv.c index 7b02c11bcc2..0d7e4edf6f8 100644 --- a/mps/code/arenacv.c +++ b/mps/code/arenacv.c @@ -161,7 +161,7 @@ static Res allocAsTract(AllocInfoStruct *aiReturn, LocusPref pref, { Res res; Addr base; - res = ArenaAlloc(&base, pref, size, pool, FALSE); + res = ArenaAlloc(&base, pref, size, pool); if (res == ResOK) { aiReturn->the.tractData.base = base; aiReturn->the.tractData.size = size; @@ -249,7 +249,7 @@ static Res allocAsSeg(AllocInfoStruct *aiReturn, LocusPref pref, { Res res; Seg seg; - res = SegAlloc(&seg, SegClassGet(), pref, size, pool, FALSE, argsNone); + res = SegAlloc(&seg, SegClassGet(), pref, size, pool, argsNone); if (res == ResOK) { aiReturn->the.segData.seg = seg; } diff --git a/mps/code/bt.c b/mps/code/bt.c index 1a79b82f5f3..844846ba723 100644 --- a/mps/code/bt.c +++ b/mps/code/bt.c @@ -191,8 +191,7 @@ Res BTCreate(BT *btReturn, Arena arena, Count length) AVERT(Arena, arena); AVER(length > 0); - res = ControlAlloc(&p, arena, BTSize(length), - /* withReservoirPermit */ FALSE); + res = ControlAlloc(&p, arena, BTSize(length)); if (res != ResOK) return res; bt = (BT)p; diff --git a/mps/code/buffer.c b/mps/code/buffer.c index edef611c217..c98751ca558 100644 --- a/mps/code/buffer.c +++ b/mps/code/buffer.c @@ -279,8 +279,7 @@ Res BufferCreate(Buffer *bufferReturn, BufferClass class, arena = PoolArena(pool); /* Allocate memory for the buffer descriptor structure. */ - res = ControlAlloc(&p, arena, class->size, - /* withReservoirPermit */ FALSE); + res = ControlAlloc(&p, arena, class->size); if (res != ResOK) goto failAlloc; buffer = p; @@ -588,8 +587,7 @@ Res BufferFramePop(Buffer buffer, AllocFrame frame) * * .reserve: Keep in sync with . */ -Res BufferReserve(Addr *pReturn, Buffer buffer, Size size, - Bool withReservoirPermit) +Res BufferReserve(Addr *pReturn, Buffer buffer, Size size) { Addr next; @@ -598,7 +596,6 @@ Res BufferReserve(Addr *pReturn, Buffer buffer, Size size, AVER(size > 0); AVER(SizeIsAligned(size, BufferPool(buffer)->alignment)); AVER(BufferIsReady(buffer)); - AVERT(Bool, withReservoirPermit); /* Is there enough room in the unallocated portion of the buffer to */ /* satisfy the request? If so, just increase the alloc marker and */ @@ -612,7 +609,7 @@ Res BufferReserve(Addr *pReturn, Buffer buffer, Size size, } /* If the buffer can't accommodate the request, call "fill". */ - return BufferFill(pReturn, buffer, size, withReservoirPermit); + return BufferFill(pReturn, buffer, size); } @@ -673,8 +670,7 @@ void BufferAttach(Buffer buffer, Addr base, Addr limit, * allocation request. This might be because the buffer has been * trapped and "limit" has been set to zero. */ -Res BufferFill(Addr *pReturn, Buffer buffer, Size size, - Bool withReservoirPermit) +Res BufferFill(Addr *pReturn, Buffer buffer, Size size) { Res res; Pool pool; @@ -721,9 +717,7 @@ Res BufferFill(Addr *pReturn, Buffer buffer, Size size, BufferDetach(buffer, pool); /* Ask the pool for some memory. */ - res = (*pool->class->bufferFill)(&base, &limit, - pool, buffer, size, - withReservoirPermit); + res = (*pool->class->bufferFill)(&base, &limit, pool, buffer, size); if (res != ResOK) return res; diff --git a/mps/code/cbs.c b/mps/code/cbs.c index 6fb96b6940f..966c4babbc0 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -402,8 +402,7 @@ static Res cbsBlockAlloc(CBSBlock *blockReturn, CBS cbs, Range range) AVERT(CBS, cbs); AVERT(Range, range); - res = PoolAlloc(&p, cbsBlockPool(cbs), cbs->blockStructSize, - /* withReservoirPermit */ FALSE); + res = PoolAlloc(&p, cbsBlockPool(cbs), cbs->blockStructSize); if (res != ResOK) goto failPoolAlloc; block = (CBSBlock)p; diff --git a/mps/code/dbgpool.c b/mps/code/dbgpool.c index 6a8417595f7..48fe846cc0d 100644 --- a/mps/code/dbgpool.c +++ b/mps/code/dbgpool.c @@ -397,14 +397,14 @@ static Bool freeCheck(PoolDebugMixin debug, Pool pool, Addr base, Addr limit) /* freeCheckAlloc -- allocation wrapper for free-checking */ static Res freeCheckAlloc(Addr *aReturn, PoolDebugMixin debug, Pool pool, - Size size, Bool withReservoir) + Size size) { Res res; Addr new; AVER(aReturn != NULL); - res = SuperclassOfPool(pool)->alloc(&new, pool, size, withReservoir); + res = SuperclassOfPool(pool)->alloc(&new, pool, size); if (res != ResOK) return res; if (debug->freeSize != 0) @@ -445,7 +445,7 @@ static void freeCheckFree(PoolDebugMixin debug, */ static Res fenceAlloc(Addr *aReturn, PoolDebugMixin debug, Pool pool, - Size size, Bool withReservoir) + Size size) { Res res; Addr obj, startFence, clientNew, clientLimit, limit; @@ -458,8 +458,7 @@ static Res fenceAlloc(Addr *aReturn, PoolDebugMixin debug, Pool pool, alignedFenceSize = SizeAlignUp(debug->fenceSize, PoolAlignment(pool)); alignedSize = SizeAlignUp(size, PoolAlignment(pool)); res = freeCheckAlloc(&obj, debug, pool, - alignedSize + 2 * alignedFenceSize, - withReservoir); + alignedSize + 2 * alignedFenceSize); if (res != ResOK) return res; @@ -526,7 +525,7 @@ static void fenceFree(PoolDebugMixin debug, /* tagAlloc -- allocation wrapper for tagged pools */ static Res tagAlloc(PoolDebugMixin debug, - Pool pool, Addr new, Size size, Bool withReservoir) + Pool pool, Addr new, Size size) { Tag tag; Res res; @@ -534,15 +533,9 @@ static Res tagAlloc(PoolDebugMixin debug, Addr addr; UNUSED(pool); - res = PoolAlloc(&addr, debug->tagPool, debug->tagSize, FALSE); - if (res != ResOK) { - if (withReservoir) { /* missingTags++; - return ResOK; - } else { - return res; - } - } + res = PoolAlloc(&addr, debug->tagPool, debug->tagSize); + if (res != ResOK) + return res; tag = (Tag)addr; tag->addr = new; tag->size = size; TreeInit(TagTree(tag)); @@ -585,8 +578,7 @@ static void tagFree(PoolDebugMixin debug, Pool pool, Addr old, Size size) * Eventually, tag init args will need to be handled somewhere here. */ -static Res DebugPoolAlloc(Addr *aReturn, - Pool pool, Size size, Bool withReservoir) +static Res DebugPoolAlloc(Addr *aReturn, Pool pool, Size size) { Res res; Addr new = NULL; /* suppress "may be used uninitialized" warning */ @@ -595,20 +587,19 @@ static Res DebugPoolAlloc(Addr *aReturn, AVER(aReturn != NULL); AVERT(Pool, pool); AVER(size > 0); - AVERT(Bool, withReservoir); debug = DebugPoolDebugMixin(pool); AVER(debug != NULL); AVERT(PoolDebugMixin, debug); if (debug->fenceSize != 0) - res = fenceAlloc(&new, debug, pool, size, withReservoir); + res = fenceAlloc(&new, debug, pool, size); else - res = freeCheckAlloc(&new, debug, pool, size, withReservoir); + res = freeCheckAlloc(&new, debug, pool, size); if (res != ResOK) return res; /* Allocate object first, so it fits even when the tag doesn't. */ if (debug->tagInit != NULL) { - res = tagAlloc(debug, pool, new, size, withReservoir); + res = tagAlloc(debug, pool, new, size); if (res != ResOK) goto tagFail; } diff --git a/mps/code/eventdef.h b/mps/code/eventdef.h index 081b45de7c2..9ef997213ee 100644 --- a/mps/code/eventdef.h +++ b/mps/code/eventdef.h @@ -583,8 +583,7 @@ #define EVENT_SegMerge_PARAMS(PARAM, X) \ PARAM(X, 0, P, segLo) \ - PARAM(X, 1, P, segHi) \ - PARAM(X, 2, B, withReservoirPermit) + PARAM(X, 1, P, segHi) #define EVENT_SegSplit_PARAMS(PARAM, X) \ PARAM(X, 0, P, seg) \ diff --git a/mps/code/fbmtest.c b/mps/code/fbmtest.c index 0ef954d071d..601cee57918 100644 --- a/mps/code/fbmtest.c +++ b/mps/code/fbmtest.c @@ -576,8 +576,7 @@ extern int main(int argc, char *argv[]) /* We're not going to use this block, but I feel unhappy just */ /* inventing addresses. */ - die((mps_res_t)ControlAlloc(&p, arena, ArraySize * align, - /* withReservoirPermit */ FALSE), + die((mps_res_t)ControlAlloc(&p, arena, ArraySize * align); "failed to allocate block"); dummyBlock = p; /* avoid pun */ diff --git a/mps/code/format.c b/mps/code/format.c index 26b3e4bb751..351c150208a 100644 --- a/mps/code/format.c +++ b/mps/code/format.c @@ -133,8 +133,7 @@ Res FormatCreate(Format *formatReturn, Arena arena, ArgList args) if (ArgPick(&arg, args, MPS_KEY_FMT_CLASS)) fmtClass = arg.val.fmt_class; - res = ControlAlloc(&p, arena, sizeof(FormatStruct), - /* withReservoirPermit */ FALSE); + res = ControlAlloc(&p, arena, sizeof(FormatStruct)); if(res != ResOK) return res; format = (Format)p; /* avoid pun */ diff --git a/mps/code/fotest.c b/mps/code/fotest.c index 750883f61a4..2a3551452a9 100644 --- a/mps/code/fotest.c +++ b/mps/code/fotest.c @@ -45,13 +45,11 @@ extern Land _mps_mvt_cbs(Pool); /* "OOM" pool class -- dummy alloc/free pool class whose alloc() * method always fails and whose free method does nothing. */ -static Res oomAlloc(Addr *pReturn, Pool pool, Size size, - Bool withReservoirPermit) +static Res oomAlloc(Addr *pReturn, Pool pool, Size size) { UNUSED(pReturn); UNUSED(pool); UNUSED(size); - UNUSED(withReservoirPermit); switch (rnd() % 3) { case 0: return ResRESOURCE; diff --git a/mps/code/global.c b/mps/code/global.c index 78821c9562c..48f8ccb7188 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -352,7 +352,7 @@ Res GlobalsCompleteCreate(Globals arenaGlobals) { void *v; - res = ControlAlloc(&v, arena, BTSize(MessageTypeLIMIT), FALSE); + res = ControlAlloc(&v, arena, BTSize(MessageTypeLIMIT)); if (res != ResOK) return res; arena->enabledMessageTypes = v; @@ -366,7 +366,7 @@ Res GlobalsCompleteCreate(Globals arenaGlobals) return res; TRACE_SET_ITER_END(ti, trace, TraceSetUNIV, arena); - res = ControlAlloc(&p, arena, LockSize(), FALSE); + res = ControlAlloc(&p, arena, LockSize()); if (res != ResOK) return res; arenaGlobals->lock = (Lock)p; diff --git a/mps/code/land.c b/mps/code/land.c index 1853b4a6ad5..7a2101cc673 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -117,8 +117,7 @@ Res LandCreate(Land *landReturn, Arena arena, LandClass class, Align alignment, AVERT(Arena, arena); AVERT(LandClass, class); - res = ControlAlloc(&p, arena, class->size, - /* withReservoirPermit */ FALSE); + res = ControlAlloc(&p, arena, class->size); if (res != ResOK) goto failAlloc; land = p; diff --git a/mps/code/landtest.c b/mps/code/landtest.c index 7ec55461d1e..df09e17f490 100644 --- a/mps/code/landtest.c +++ b/mps/code/landtest.c @@ -459,8 +459,7 @@ extern int main(int argc, char *argv[]) die((mps_res_t)BTCreate(&state.allocTable, arena, state.size), "failed to create alloc table"); - die((mps_res_t)ControlAlloc(&p, arena, (state.size + 1) * state.align, - /* withReservoirPermit */ FALSE), + die((mps_res_t)ControlAlloc(&p, arena, (state.size + 1) * state.align), "failed to allocate block"); state.block = AddrAlignUp(p, state.align); diff --git a/mps/code/locus.c b/mps/code/locus.c index cc367b15a6c..e590b410a24 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -205,7 +205,7 @@ Res ChainCreate(Chain *chainReturn, Arena arena, size_t genCount, AVER(params[i].mortality < 1.0); } - res = ControlAlloc(&p, arena, genCount * sizeof(GenDescStruct), FALSE); + res = ControlAlloc(&p, arena, genCount * sizeof(GenDescStruct)); if (res != ResOK) return res; gens = (GenDescStruct *)p; @@ -219,7 +219,7 @@ Res ChainCreate(Chain *chainReturn, Arena arena, size_t genCount, AVERT(GenDesc, &gens[i]); } - res = ControlAlloc(&p, arena, sizeof(ChainStruct), FALSE); + res = ControlAlloc(&p, arena, sizeof(ChainStruct)); if (res != ResOK) goto failChainAlloc; chain = (Chain)p; @@ -313,7 +313,7 @@ GenDesc ChainGen(Chain chain, Index gen) */ Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size, - Bool withReservoirPermit, ArgList args) + ArgList args) { LocusPrefStruct pref; Res res; @@ -326,7 +326,6 @@ Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size, AVERT(PoolGen, pgen); AVERT(SegClass, class); AVER(size > 0); - AVERT(Bool, withReservoirPermit); AVERT(ArgList, args); arena = PoolArena(pgen->pool); @@ -337,8 +336,7 @@ Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size, pref.high = FALSE; pref.zones = zones; pref.avoid = ZoneSetBlacklist(arena); - res = SegAlloc(&seg, class, &pref, size, pgen->pool, withReservoirPermit, - args); + res = SegAlloc(&seg, class, &pref, size, pgen->pool, args); if (res != ResOK) return res; diff --git a/mps/code/locus.h b/mps/code/locus.h index d1d9716303e..649820a1433 100644 --- a/mps/code/locus.h +++ b/mps/code/locus.h @@ -96,7 +96,7 @@ extern Bool PoolGenCheck(PoolGen pgen); extern Res PoolGenInit(PoolGen pgen, GenDesc gen, Pool pool); extern void PoolGenFinish(PoolGen pgen); extern Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, - Size size, Bool withReservoirPermit, ArgList args); + Size size, ArgList args); extern void PoolGenFree(PoolGen pgen, Seg seg, Size freeSize, Size oldSize, Size newSize, Bool deferred); extern void PoolGenAccountForFill(PoolGen pgen, Size size, Bool deferred); diff --git a/mps/code/messtest.c b/mps/code/messtest.c index 96deeebfc58..5090a5d4c11 100644 --- a/mps/code/messtest.c +++ b/mps/code/messtest.c @@ -77,7 +77,7 @@ static void postDummyMessage(Arena arena, MessageClass class, void *p; Message message; - die((mps_res_t)ControlAlloc(&p, arena, sizeof(MessageStruct), FALSE), + die((mps_res_t)ControlAlloc(&p, arena, sizeof(MessageStruct)), "AllocMessage"); message = (Message)p; MessageInit(arena, message, class, type); diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 3dfa4bf5e67..03d65699f1c 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -208,8 +208,7 @@ extern Res PoolCreate(Pool *poolReturn, Arena arena, PoolClass class, ArgList args); extern void PoolDestroy(Pool pool); extern BufferClass PoolDefaultBufferClass(Pool pool); -extern Res PoolAlloc(Addr *pReturn, Pool pool, Size size, - Bool withReservoirPermit); +extern Res PoolAlloc(Addr *pReturn, Pool pool, Size size); extern void PoolFree(Pool pool, Addr old, Size size); extern Res PoolTraceBegin(Pool pool, Trace trace); extern Res PoolAccess(Pool pool, Seg seg, Addr addr, @@ -233,18 +232,14 @@ extern Size PoolFreeSize(Pool pool); extern Res PoolTrivInit(Pool pool, ArgList arg); extern void PoolTrivFinish(Pool pool); -extern Res PoolNoAlloc(Addr *pReturn, Pool pool, Size size, - Bool withReservoirPermit); -extern Res PoolTrivAlloc(Addr *pReturn, Pool pool, Size size, - Bool withReservoirPermit); +extern Res PoolNoAlloc(Addr *pReturn, Pool pool, Size size); +extern Res PoolTrivAlloc(Addr *pReturn, Pool pool, Size size); extern void PoolNoFree(Pool pool, Addr old, Size size); extern void PoolTrivFree(Pool pool, Addr old, Size size); extern Res PoolNoBufferFill(Addr *baseReturn, Addr *limitReturn, - Pool pool, Buffer buffer, Size size, - Bool withReservoirPermit); + Pool pool, Buffer buffer, Size size); extern Res PoolTrivBufferFill(Addr *baseReturn, Addr *limitReturn, - Pool pool, Buffer buffer, Size size, - Bool withReservoirPermit); + Pool pool, Buffer buffer, Size size); extern void PoolNoBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit); extern void PoolTrivBufferEmpty(Pool pool, Buffer buffer, @@ -576,8 +571,7 @@ extern Bool ArenaEmergency(Arena arean); extern Res ControlInit(Arena arena); extern void ControlFinish(Arena arena); -extern Res ControlAlloc(void **baseReturn, Arena arena, size_t size, - Bool withReservoirPermit); +extern Res ControlAlloc(void **baseReturn, Arena arena, size_t size); extern void ControlFree(Arena arena, void *base, size_t size); extern Res ControlDescribe(Arena arena, mps_lib_FILE *stream, Count depth); @@ -635,7 +629,7 @@ extern Res ArenaFinalize(Arena arena, Ref obj); extern Res ArenaDefinalize(Arena arena, Ref obj); extern Res ArenaAlloc(Addr *baseReturn, LocusPref pref, - Size size, Pool pool, Bool withReservoirPermit); + Size size, Pool pool); extern Res ArenaFreeLandAlloc(Tract *tractReturn, Arena arena, ZoneSet zones, Bool high, Size size, Pool pool); extern void ArenaFree(Addr base, Size size, Pool pool); @@ -671,7 +665,7 @@ extern Bool LocusCheck(Arena arena); /* Segment interface */ extern Res SegAlloc(Seg *segReturn, SegClass class, LocusPref pref, - Size size, Pool pool, Bool withReservoirPermit, + Size size, Pool pool, ArgList args); extern void SegFree(Seg seg); extern Bool SegOfAddr(Seg *segReturn, Arena arena, Addr addr); @@ -682,10 +676,8 @@ extern void SegSetWhite(Seg seg, TraceSet white); extern void SegSetGrey(Seg seg, TraceSet grey); extern void SegSetRankSet(Seg seg, RankSet rankSet); extern void SegSetRankAndSummary(Seg seg, RankSet rankSet, RefSet summary); -extern Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi, - Bool withReservoirPermit); -extern Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at, - Bool withReservoirPermit); +extern Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi); +extern Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at); extern Res SegDescribe(Seg seg, mps_lib_FILE *stream, Count depth); extern void SegSetSummary(Seg seg, RefSet summary); extern Buffer SegBuffer(Seg seg); @@ -746,21 +738,19 @@ extern void BufferDestroy(Buffer buffer); extern Bool BufferCheck(Buffer buffer); extern Bool SegBufCheck(SegBuf segbuf); extern Res BufferDescribe(Buffer buffer, mps_lib_FILE *stream, Count depth); -extern Res BufferReserve(Addr *pReturn, Buffer buffer, Size size, - Bool withReservoirPermit); +extern Res BufferReserve(Addr *pReturn, Buffer buffer, Size size); /* macro equivalent for BufferReserve, keep in sync with */ /* TODO: Perhaps this isn't really necessary now that we build the MPS with more global optimisation and inlining. RB 2012-09-07 */ -#define BUFFER_RESERVE(pReturn, buffer, size, withReservoirPermit) \ +#define BUFFER_RESERVE(pReturn, buffer, size) \ (AddrAdd(BufferAlloc(buffer), size) > BufferAlloc(buffer) && \ AddrAdd(BufferAlloc(buffer), size) <= (Addr)BufferAP(buffer)->limit ? \ (*(pReturn) = BufferAlloc(buffer), \ BufferAP(buffer)->alloc = AddrAdd(BufferAlloc(buffer), size), \ ResOK) : \ - BufferFill(pReturn, buffer, size, withReservoirPermit)) + BufferFill(pReturn, buffer, size)) -extern Res BufferFill(Addr *pReturn, Buffer buffer, Size size, - Bool withReservoirPermit); +extern Res BufferFill(Addr *pReturn, Buffer buffer, Size size); extern Bool BufferCommit(Buffer buffer, Addr p, Size size); /* macro equivalent for BufferCommit, keep in sync with */ diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 747b041bf85..c375e0a507f 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -156,7 +156,7 @@ typedef void (*FreeBlockVisitor)(Addr base, Addr limit, Pool pool, void *p); /* Seg*Method -- see */ typedef Res (*SegInitMethod)(Seg seg, Pool pool, Addr base, Size size, - Bool withReservoirPermit, ArgList args); + ArgList args); typedef void (*SegFinishMethod)(Seg seg); typedef void (*SegSetGreyMethod)(Seg seg, TraceSet grey); typedef void (*SegSetWhiteMethod)(Seg seg, TraceSet white); @@ -168,11 +168,9 @@ typedef Buffer (*SegBufferMethod)(Seg seg); typedef void (*SegSetBufferMethod)(Seg seg, Buffer buffer); typedef Res (*SegDescribeMethod)(Seg seg, mps_lib_FILE *stream, Count depth); typedef Res (*SegMergeMethod)(Seg seg, Seg segHi, - Addr base, Addr mid, Addr limit, - Bool withReservoirPermit); + Addr base, Addr mid, Addr limit); typedef Res (*SegSplitMethod)(Seg seg, Seg segHi, - Addr base, Addr mid, Addr limit, - Bool withReservoirPermit); + Addr base, Addr mid, Addr limit); /* Buffer*Method -- see */ @@ -196,12 +194,10 @@ typedef Res (*BufferDescribeMethod)(Buffer buffer, mps_lib_FILE *stream, Count d typedef void (*PoolVarargsMethod)(ArgStruct args[], va_list varargs); typedef Res (*PoolInitMethod)(Pool pool, ArgList args); typedef void (*PoolFinishMethod)(Pool pool); -typedef Res (*PoolAllocMethod)(Addr *pReturn, Pool pool, Size size, - Bool withReservoirPermit); +typedef Res (*PoolAllocMethod)(Addr *pReturn, Pool pool, Size size); typedef void (*PoolFreeMethod)(Pool pool, Addr old, Size size); typedef Res (*PoolBufferFillMethod)(Addr *baseReturn, Addr *limitReturn, - Pool pool, Buffer buffer, Size size, - Bool withReservoirPermit); + Pool pool, Buffer buffer, Size size); typedef void (*PoolBufferEmptyMethod)(Pool pool, Buffer buffer, Addr init, Addr limit); typedef Res (*PoolTraceBeginMethod)(Pool pool, Trace trace); diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index b97c6c4dc2b..8e73a908395 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -742,7 +742,7 @@ mps_res_t mps_alloc(mps_addr_t *p_o, mps_pool_t pool, size_t size) /* @@@@ There is currently no requirement for reservoirs to work */ /* with unbuffered allocation. */ - res = PoolAlloc(&p, pool, size, FALSE); + res = PoolAlloc(&p, pool, size); ArenaLeave(arena); @@ -1035,7 +1035,7 @@ mps_res_t mps_ap_fill(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size) AVER(size > 0); AVER(SizeIsAligned(size, BufferPool(buf)->alignment)); - res = BufferFill(&p, buf, size, FALSE); + res = BufferFill(&p, buf, size); ArenaLeave(arena); @@ -1158,10 +1158,11 @@ mps_res_t mps_sac_fill(mps_addr_t *p_o, mps_sac_t mps_sac, size_t size, AVER(p_o != NULL); AVER(TESTT(SAC, sac)); arena = SACArena(sac); + UNUSED(has_reservoir_permit); /* FIXME */ ArenaEnter(arena); - res = SACFill(&p, sac, size, (has_reservoir_permit != 0)); + res = SACFill(&p, sac, size); ArenaLeave(arena); diff --git a/mps/code/nailboard.c b/mps/code/nailboard.c index 0b91ab35e13..90d26c84295 100644 --- a/mps/code/nailboard.c +++ b/mps/code/nailboard.c @@ -127,7 +127,7 @@ Res NailboardCreate(Nailboard *boardReturn, Arena arena, Align alignment, alignShift = SizeLog2((Size)alignment); nails = AddrOffset(base, limit) >> alignShift; levels = nailboardLevels(nails); - res = ControlAlloc(&p, arena, nailboardSize(nails, levels), FALSE); + res = ControlAlloc(&p, arena, nailboardSize(nails, levels)); if (res != ResOK) return res; diff --git a/mps/code/pool.c b/mps/code/pool.c index f939bca84e9..a1508908f14 100644 --- a/mps/code/pool.c +++ b/mps/code/pool.c @@ -195,8 +195,7 @@ Res PoolCreate(Pool *poolReturn, Arena arena, /* .space.alloc: Allocate the pool instance structure with the size */ /* requested in the pool class. See .space.free */ - res = ControlAlloc(&base, arena, class->size, - /* withReservoirPermit */ FALSE); + res = ControlAlloc(&base, arena, class->size); if (res != ResOK) goto failControlAlloc; @@ -274,17 +273,15 @@ BufferClass PoolDefaultBufferClass(Pool pool) /* PoolAlloc -- allocate a block of memory from a pool */ -Res PoolAlloc(Addr *pReturn, Pool pool, Size size, - Bool withReservoirPermit) +Res PoolAlloc(Addr *pReturn, Pool pool, Size size) { Res res; AVER(pReturn != NULL); AVERT(Pool, pool); AVER(size > 0); - AVERT(Bool, withReservoirPermit); - res = (*pool->class->alloc)(pReturn, pool, size, withReservoirPermit); + res = (*pool->class->alloc)(pReturn, pool, size); if (res != ResOK) return res; /* Make sure that the allocated address was in the pool's memory. */ diff --git a/mps/code/poolabs.c b/mps/code/poolabs.c index 30f5d0f999e..92f10752f97 100644 --- a/mps/code/poolabs.c +++ b/mps/code/poolabs.c @@ -196,24 +196,20 @@ Res PoolTrivInit(Pool pool, ArgList args) return ResOK; } -Res PoolNoAlloc(Addr *pReturn, Pool pool, Size size, - Bool withReservoirPermit) +Res PoolNoAlloc(Addr *pReturn, Pool pool, Size size) { AVER(pReturn != NULL); AVERT(Pool, pool); AVER(size > 0); - AVERT(Bool, withReservoirPermit); NOTREACHED; return ResUNIMPL; } -Res PoolTrivAlloc(Addr *pReturn, Pool pool, Size size, - Bool withReservoirPermit) +Res PoolTrivAlloc(Addr *pReturn, Pool pool, Size size) { AVER(pReturn != NULL); AVERT(Pool, pool); AVER(size > 0); - AVERT(Bool, withReservoirPermit); return ResLIMIT; } @@ -235,22 +231,19 @@ void PoolTrivFree(Pool pool, Addr old, Size size) Res PoolNoBufferFill(Addr *baseReturn, Addr *limitReturn, - Pool pool, Buffer buffer, Size size, - Bool withReservoirPermit) + Pool pool, Buffer buffer, Size size) { AVER(baseReturn != NULL); AVER(limitReturn != NULL); AVERT(Pool, pool); AVERT(Buffer, buffer); AVER(size > 0); - AVERT(Bool, withReservoirPermit); NOTREACHED; return ResUNIMPL; } Res PoolTrivBufferFill(Addr *baseReturn, Addr *limitReturn, - Pool pool, Buffer buffer, Size size, - Bool withReservoirPermit) + Pool pool, Buffer buffer, Size size) { Res res; Addr p; @@ -260,9 +253,8 @@ Res PoolTrivBufferFill(Addr *baseReturn, Addr *limitReturn, AVERT(Pool, pool); AVERT(Buffer, buffer); AVER(size > 0); - AVERT(Bool, withReservoirPermit); - res = PoolAlloc(&p, pool, size, withReservoirPermit); + res = PoolAlloc(&p, pool, size); if (res != ResOK) return res; diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 7b625c4dac4..0d4228c7093 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -123,8 +123,7 @@ static Bool amcSegCheck(amcSeg amcseg) ARG_DEFINE_KEY(amc_seg_gen, Pointer); #define amcKeySegGen (&_mps_key_amc_seg_gen) -static Res AMCSegInit(Seg seg, Pool pool, Addr base, Size size, - Bool reservoirPermit, ArgList args) +static Res AMCSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) { amcGen amcgen; SegClass super; @@ -138,11 +137,10 @@ static Res AMCSegInit(Seg seg, Pool pool, Addr base, Size size, AVERT(Seg, seg); amcseg = Seg2amcSeg(seg); /* no useful checks for base and size */ - AVERT(Bool, reservoirPermit); /* Initialize the superclass fields first via next-method call */ super = SEG_SUPERCLASS(amcSegClass); - res = super->init(seg, pool, base, size, reservoirPermit, args); + res = super->init(seg, pool, base, size, args); if(res != ResOK) return res; @@ -592,7 +590,7 @@ static Res amcGenCreate(amcGen *genReturn, AMC amc, GenDesc gen) pool = AMCPool(amc); arena = pool->arena; - res = ControlAlloc(&p, arena, sizeof(amcGenStruct), FALSE); + res = ControlAlloc(&p, arena, sizeof(amcGenStruct)); if(res != ResOK) goto failControlAlloc; amcgen = (amcGen)p; @@ -807,7 +805,7 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args) /* One gen for each one in the chain plus dynamic gen. */ genArraySize = sizeof(amcGen) * (genCount + 1); - res = ControlAlloc(&p, arena, genArraySize, FALSE); + res = ControlAlloc(&p, arena, genArraySize); if(res != ResOK) goto failGensAlloc; amc->gen = p; @@ -916,8 +914,7 @@ static void AMCFinish(Pool pool) * See . */ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn, - Pool pool, Buffer buffer, Size size, - Bool withReservoirPermit) + Pool pool, Buffer buffer, Size size) { Seg seg; AMC amc; @@ -938,7 +935,6 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn, AVER(BufferIsReset(buffer)); AVER(size > 0); AVER(SizeIsAligned(size, PoolAlignment(pool))); - AVERT(Bool, withReservoirPermit); arena = PoolArena(pool); gen = amcBufGen(buffer); @@ -957,8 +953,7 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn, } MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD_FIELD(args, amcKeySegGen, p, gen); - res = PoolGenAlloc(&seg, pgen, amcSegClassGet(), grainsSize, - withReservoirPermit, args); + res = PoolGenAlloc(&seg, pgen, amcSegClassGet(), grainsSize, args); } MPS_ARGS_END(args); if(res != ResOK) return res; @@ -1642,7 +1637,7 @@ static Res AMCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO) STATISTIC_STAT(++ss->forwardedCount); ss->forwardedSize += length; do { - res = BUFFER_RESERVE(&newBase, buffer, length, FALSE); + res = BUFFER_RESERVE(&newBase, buffer, length); if (res != ResOK) goto returnRes; newRef = AddrAdd(newBase, headerSize); diff --git a/mps/code/poolams.c b/mps/code/poolams.c index 40ca5f65426..71701be7bee 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -215,8 +215,7 @@ static void amsDestroyTables(AMS ams, BT allocTable, /* AMSSegInit -- Init method for AMS segments */ -static Res AMSSegInit(Seg seg, Pool pool, Addr base, Size size, - Bool reservoirPermit, ArgList args) +static Res AMSSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) { SegClass super; AMSSeg amsseg; @@ -231,11 +230,10 @@ static Res AMSSegInit(Seg seg, Pool pool, Addr base, Size size, AVERT(AMS, ams); arena = PoolArena(pool); /* no useful checks for base and size */ - AVERT(Bool, reservoirPermit); /* Initialize the superclass fields first via next-method call */ super = SEG_SUPERCLASS(AMSSegClass); - res = super->init(seg, pool, base, size, reservoirPermit, args); + res = super->init(seg, pool, base, size, args); if (res != ResOK) goto failNextMethod; @@ -328,8 +326,7 @@ static void AMSSegFinish(Seg seg) */ static Res AMSSegMerge(Seg seg, Seg segHi, - Addr base, Addr mid, Addr limit, - Bool withReservoirPermit) + Addr base, Addr mid, Addr limit) { SegClass super; Count loGrains, hiGrains, allGrains; @@ -367,8 +364,7 @@ static Res AMSSegMerge(Seg seg, Seg segHi, /* Merge the superclass fields via next-method call */ super = SEG_SUPERCLASS(AMSSegClass); - res = super->merge(seg, segHi, base, mid, limit, - withReservoirPermit); + res = super->merge(seg, segHi, base, mid, limit); if (res != ResOK) goto failSuper; @@ -414,8 +410,7 @@ static Res AMSSegMerge(Seg seg, Seg segHi, static Res AMSSegSplit(Seg seg, Seg segHi, - Addr base, Addr mid, Addr limit, - Bool withReservoirPermit) + Addr base, Addr mid, Addr limit) { SegClass super; Count loGrains, hiGrains, allGrains; @@ -462,7 +457,7 @@ static Res AMSSegSplit(Seg seg, Seg segHi, /* Split the superclass fields via next-method call */ super = SEG_SUPERCLASS(AMSSegClass); - res = super->split(seg, segHi, base, mid, limit, withReservoirPermit); + res = super->split(seg, segHi, base, mid, limit); if (res != ResOK) goto failSuper; @@ -682,7 +677,7 @@ static Res AMSSegSizePolicy(Size *sizeReturn, /* AMSSegCreate -- create a single AMSSeg */ static Res AMSSegCreate(Seg *segReturn, Pool pool, Size size, - RankSet rankSet, Bool withReservoirPermit) + RankSet rankSet) { Seg seg; AMS ams; @@ -694,7 +689,6 @@ static Res AMSSegCreate(Seg *segReturn, Pool pool, Size size, AVERT(Pool, pool); AVER(size > 0); AVERT(RankSet, rankSet); - AVERT(Bool, withReservoirPermit); ams = PoolAMS(pool); AVERT(AMS,ams); @@ -705,13 +699,13 @@ static Res AMSSegCreate(Seg *segReturn, Pool pool, Size size, goto failSize; res = PoolGenAlloc(&seg, &ams->pgen, (*ams->segClass)(), prefSize, - withReservoirPermit, argsNone); + argsNone); if (res != ResOK) { /* try to allocate one that's just large enough */ Size minSize = SizeArenaGrains(size, arena); if (minSize == prefSize) goto failSeg; res = PoolGenAlloc(&seg, &ams->pgen, (*ams->segClass)(), prefSize, - withReservoirPermit, argsNone); + argsNone); if (res != ResOK) goto failSeg; } @@ -946,8 +940,7 @@ static Bool amsSegAlloc(Index *baseReturn, Index *limitReturn, * . */ static Res AMSBufferFill(Addr *baseReturn, Addr *limitReturn, - Pool pool, Buffer buffer, Size size, - Bool withReservoirPermit) + Pool pool, Buffer buffer, Size size) { Res res; AMS ams; @@ -967,7 +960,6 @@ static Res AMSBufferFill(Addr *baseReturn, Addr *limitReturn, AVERT(Buffer, buffer); AVER(size > 0); AVER(SizeIsAligned(size, PoolAlignment(pool))); - AVERT(Bool, withReservoirPermit); /* Check that we're not in the grey mutator phase (see */ /* ). */ @@ -996,8 +988,7 @@ static Res AMSBufferFill(Addr *baseReturn, Addr *limitReturn, } /* No suitable segment found; make a new one. */ - res = AMSSegCreate(&seg, pool, size, rankSet, - withReservoirPermit); + res = AMSSegCreate(&seg, pool, size, rankSet); if (res != ResOK) return res; b = amsSegAlloc(&base, &limit, seg, size); diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 6d7c4d6efb2..42460f97056 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -172,8 +172,7 @@ static void awlStatTotalInit(AWL awl) ARG_DEFINE_KEY(awl_seg_rank_set, RankSet); #define awlKeySegRankSet (&_mps_key_awl_seg_rank_set) -static Res AWLSegInit(Seg seg, Pool pool, Addr base, Size size, - Bool reservoirPermit, ArgList args) +static Res AWLSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) { SegClass super; AWLSeg awlseg; @@ -191,7 +190,6 @@ static Res AWLSegInit(Seg seg, Pool pool, Addr base, Size size, AVERT(Pool, pool); arena = PoolArena(pool); /* no useful checks for base and size */ - AVERT(Bool, reservoirPermit); ArgRequire(&arg, args, awlKeySegRankSet); rankSet = arg.val.u; AVERT(RankSet, rankSet); @@ -204,21 +202,21 @@ static Res AWLSegInit(Seg seg, Pool pool, Addr base, Size size, /* Initialize the superclass fields first via next-method call */ super = SEG_SUPERCLASS(AWLSegClass); - res = super->init(seg, pool, base, size, reservoirPermit, args); + res = super->init(seg, pool, base, size, args); if (res != ResOK) return res; bits = size >> awl->alignShift; tableSize = BTSize(bits); - res = ControlAlloc(&v, arena, tableSize, reservoirPermit); + res = ControlAlloc(&v, arena, tableSize); if (res != ResOK) goto failControlAllocMark; awlseg->mark = v; - res = ControlAlloc(&v, arena, tableSize, reservoirPermit); + res = ControlAlloc(&v, arena, tableSize); if (res != ResOK) goto failControlAllocScanned; awlseg->scanned = v; - res = ControlAlloc(&v, arena, tableSize, reservoirPermit); + res = ControlAlloc(&v, arena, tableSize); if (res != ResOK) goto failControlAllocAlloc; awlseg->alloc = v; @@ -451,8 +449,7 @@ static void AWLNoteScan(AWL awl, Seg seg, ScanState ss) /* AWLSegCreate -- Create a new segment of at least given size */ static Res AWLSegCreate(AWLSeg *awlsegReturn, - RankSet rankSet, Pool pool, Size size, - Bool reservoirPermit) + RankSet rankSet, Pool pool, Size size) { AWL awl; Seg seg; @@ -464,7 +461,6 @@ static Res AWLSegCreate(AWLSeg *awlsegReturn, AVERT(RankSet, rankSet); AVERT(Pool, pool); AVER(size > 0); - AVERT(Bool, reservoirPermit); awl = PoolAWL(pool); AVERT(AWL, awl); @@ -478,8 +474,7 @@ static Res AWLSegCreate(AWLSeg *awlsegReturn, return ResMEMORY; MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD_FIELD(args, awlKeySegRankSet, u, rankSet); - res = PoolGenAlloc(&seg, &awl->pgen, AWLSegClassGet(), size, - reservoirPermit, args); + res = PoolGenAlloc(&seg, &awl->pgen, AWLSegClassGet(), size, args); } MPS_ARGS_END(args); if (res != ResOK) return res; @@ -636,8 +631,7 @@ static void AWLFinish(Pool pool) /* AWLBufferFill -- BufferFill method for AWL */ static Res AWLBufferFill(Addr *baseReturn, Addr *limitReturn, - Pool pool, Buffer buffer, Size size, - Bool reservoirPermit) + Pool pool, Buffer buffer, Size size) { Addr base, limit; AWLSeg awlseg; @@ -650,7 +644,6 @@ static Res AWLBufferFill(Addr *baseReturn, Addr *limitReturn, AVERT(Pool, pool); AVERT(Buffer, buffer); AVER(size > 0); - AVERT(Bool, reservoirPermit); awl = PoolAWL(pool); AVERT(AWL, awl); @@ -674,8 +667,7 @@ static Res AWLBufferFill(Addr *baseReturn, Addr *limitReturn, /* No free space in existing awlsegs, so create new awlseg */ - res = AWLSegCreate(&awlseg, BufferRankSet(buffer), pool, size, - reservoirPermit); + res = AWLSegCreate(&awlseg, BufferRankSet(buffer), pool, size); if (res != ResOK) return res; base = SegBase(AWLSeg2Seg(awlseg)); diff --git a/mps/code/poollo.c b/mps/code/poollo.c index a1a3f328468..23c73e38cfa 100644 --- a/mps/code/poollo.c +++ b/mps/code/poollo.c @@ -59,8 +59,7 @@ typedef struct LOSegStruct { /* forward decls */ -static Res loSegInit(Seg seg, Pool pool, Addr base, Size size, - Bool reservoirPermit, ArgList args); +static Res loSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args); static void loSegFinish(Seg seg); static Count loSegGrains(LOSeg loseg); @@ -98,8 +97,7 @@ static Bool LOSegCheck(LOSeg loseg) /* loSegInit -- Init method for LO segments */ -static Res loSegInit(Seg seg, Pool pool, Addr base, Size size, - Bool reservoirPermit, ArgList args) +static Res loSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) { SegClass super; LOSeg loseg; @@ -116,13 +114,12 @@ static Res loSegInit(Seg seg, Pool pool, Addr base, Size size, AVERT(Pool, pool); arena = PoolArena(pool); /* no useful checks for base and size */ - AVERT(Bool, reservoirPermit); lo = PoolPoolLO(pool); AVERT(LO, lo); /* Initialize the superclass fields first via next-method call */ super = SEG_SUPERCLASS(LOSegClass); - res = super->init(seg, pool, base, size, reservoirPermit, args); + res = super->init(seg, pool, base, size, args); if(res != ResOK) return res; @@ -130,11 +127,11 @@ static Res loSegInit(Seg seg, Pool pool, Addr base, Size size, grains = size >> lo->alignShift; tablebytes = BTSize(grains); - res = ControlAlloc(&p, arena, tablebytes, reservoirPermit); + res = ControlAlloc(&p, arena, tablebytes); if(res != ResOK) goto failMarkTable; loseg->mark = p; - res = ControlAlloc(&p, arena, tablebytes, reservoirPermit); + res = ControlAlloc(&p, arena, tablebytes); if(res != ResOK) goto failAllocTable; loseg->alloc = p; @@ -280,8 +277,7 @@ static Bool loSegFindFree(Addr *bReturn, Addr *lReturn, * Segments will be multiples of ArenaGrainSize. */ -static Res loSegCreate(LOSeg *loSegReturn, Pool pool, Size size, - Bool withReservoirPermit) +static Res loSegCreate(LOSeg *loSegReturn, Pool pool, Size size) { LO lo; Seg seg; @@ -290,13 +286,12 @@ static Res loSegCreate(LOSeg *loSegReturn, Pool pool, Size size, AVER(loSegReturn != NULL); AVERT(Pool, pool); AVER(size > 0); - AVERT(Bool, withReservoirPermit); lo = PoolPoolLO(pool); AVERT(LO, lo); res = PoolGenAlloc(&seg, &lo->pgen, EnsureLOSegClass(), SizeArenaGrains(size, PoolArena(pool)), - withReservoirPermit, argsNone); + argsNone); if (res != ResOK) return res; @@ -556,7 +551,7 @@ static void LOFinish(Pool pool) static Res LOBufferFill(Addr *baseReturn, Addr *limitReturn, Pool pool, Buffer buffer, - Size size, Bool withReservoirPermit) + Size size) { Res res; Ring node, nextNode; @@ -574,7 +569,6 @@ static Res LOBufferFill(Addr *baseReturn, Addr *limitReturn, AVER(BufferRankSet(buffer) == RankSetEMPTY); AVER(size > 0); AVER(SizeIsAligned(size, PoolAlignment(pool))); - AVERT(Bool, withReservoirPermit); /* Try to find a segment with enough space already. */ RING_FOR(node, &pool->segRing, nextNode) { @@ -587,7 +581,7 @@ static Res LOBufferFill(Addr *baseReturn, Addr *limitReturn, } /* No segment had enough space, so make a new one. */ - res = loSegCreate(&loseg, pool, size, withReservoirPermit); + res = loSegCreate(&loseg, pool, size); if(res != ResOK) { goto failCreate; } diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c index 4ce6e66ed1c..6841517d846 100644 --- a/mps/code/poolmfs.c +++ b/mps/code/poolmfs.c @@ -225,8 +225,7 @@ void MFSExtend(Pool pool, Addr base, Size size) * arena. */ -static Res MFSAlloc(Addr *pReturn, Pool pool, Size size, - Bool withReservoirPermit) +static Res MFSAlloc(Addr *pReturn, Pool pool, Size size) { Header f; Res res; @@ -238,7 +237,6 @@ static Res MFSAlloc(Addr *pReturn, Pool pool, Size size, AVER(pReturn != NULL); AVER(size == mfs->unroundedUnitSize); - AVERT(Bool, withReservoirPermit); f = mfs->freeList; @@ -253,8 +251,7 @@ static Res MFSAlloc(Addr *pReturn, Pool pool, Size size, return ResLIMIT; /* Create a new region and attach it to the pool. */ - res = ArenaAlloc(&base, LocusPrefDefault(), mfs->extendBy, pool, - withReservoirPermit); + res = ArenaAlloc(&base, LocusPrefDefault(), mfs->extendBy, pool); if(res != ResOK) return res; diff --git a/mps/code/poolmrg.c b/mps/code/poolmrg.c index ec48151ab4e..18eef9fe271 100644 --- a/mps/code/poolmrg.c +++ b/mps/code/poolmrg.c @@ -215,7 +215,7 @@ static Bool MRGRefSegCheck(MRGRefSeg refseg) /* MRGLinkSegInit -- initialise a link segment */ static Res MRGLinkSegInit(Seg seg, Pool pool, Addr base, Size size, - Bool reservoirPermit, ArgList args) + ArgList args) { SegClass super; MRGLinkSeg linkseg; @@ -228,11 +228,10 @@ static Res MRGLinkSegInit(Seg seg, Pool pool, Addr base, Size size, mrg = PoolMRG(pool); AVERT(MRG, mrg); /* no useful checks for base and size */ - AVERT(Bool, reservoirPermit); /* Initialize the superclass fields first via next-method call */ super = SEG_SUPERCLASS(MRGLinkSegClass); - res = super->init(seg, pool, base, size, reservoirPermit, args); + res = super->init(seg, pool, base, size, args); if (res != ResOK) return res; linkseg->refSeg = NULL; /* .link.nullref */ @@ -248,8 +247,7 @@ static Res MRGLinkSegInit(Seg seg, Pool pool, Addr base, Size size, ARG_DEFINE_KEY(mrg_seg_link_seg, Pointer); #define mrgKeyLinkSeg (&_mps_key_mrg_seg_link_seg) -static Res MRGRefSegInit(Seg seg, Pool pool, Addr base, Size size, - Bool reservoirPermit, ArgList args) +static Res MRGRefSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) { MRGLinkSeg linkseg; MRGRefSeg refseg; @@ -271,12 +269,11 @@ static Res MRGRefSegInit(Seg seg, Pool pool, Addr base, Size size, mrg = PoolMRG(pool); AVERT(MRG, mrg); /* no useful checks for base and size */ - AVERT(Bool, reservoirPermit); AVERT(MRGLinkSeg, linkseg); /* Initialize the superclass fields first via next-method call */ super = SEG_SUPERCLASS(MRGRefSegClass); - res = super->init(seg, pool, base, size, reservoirPermit, args); + res = super->init(seg, pool, base, size, args); if (res != ResOK) return res; @@ -499,8 +496,7 @@ static void MRGSegPairDestroy(MRGRefSeg refseg) /* MRGSegPairCreate -- create a pair of segments (link & ref) */ -static Res MRGSegPairCreate(MRGRefSeg *refSegReturn, MRG mrg, - Bool withReservoirPermit) +static Res MRGSegPairCreate(MRGRefSeg *refSegReturn, MRG mrg) { RefPart refPartBase; Count nGuardians; /* guardians per seg */ @@ -525,7 +521,7 @@ static Res MRGSegPairCreate(MRGRefSeg *refSegReturn, MRG mrg, res = SegAlloc(&segLink, EnsureMRGLinkSegClass(), LocusPrefDefault(), linkSegSize, pool, - withReservoirPermit, argsNone); + argsNone); if (res != ResOK) goto failLinkSegAlloc; linkseg = Seg2LinkSeg(segLink); @@ -534,7 +530,7 @@ static Res MRGSegPairCreate(MRGRefSeg *refSegReturn, MRG mrg, MPS_ARGS_ADD_FIELD(args, mrgKeyLinkSeg, p, linkseg); /* .ref.initarg */ res = SegAlloc(&segRefPart, EnsureMRGRefSegClass(), LocusPrefDefault(), mrg->extendBy, pool, - withReservoirPermit, args); + args); } MPS_ARGS_END(args); if (res != ResOK) goto failRefPartSegAlloc; @@ -722,7 +718,7 @@ Res MRGRegister(Pool pool, Ref ref) /* */ if (RingIsSingle(&mrg->freeRing)) { - res = MRGSegPairCreate(&junk, mrg, /* withReservoirPermit */ FALSE); + res = MRGSegPairCreate(&junk, mrg); if (res != ResOK) return res; } diff --git a/mps/code/poolmv.c b/mps/code/poolmv.c index 19b3c2bb443..719cba6d7df 100644 --- a/mps/code/poolmv.c +++ b/mps/code/poolmv.c @@ -458,8 +458,7 @@ static Res MVSpanFree(MVSpan span, Addr base, Addr limit, Pool blockPool) /* The freed area is buried in the middle of the block, so the */ /* block must be split into two parts. */ - res = PoolAlloc(&addr, blockPool, sizeof(MVBlockStruct), - /* withReservoirPermit */ FALSE); + res = PoolAlloc(&addr, blockPool, sizeof(MVBlockStruct)); if (res != ResOK) return res; new = (MVBlock)addr; @@ -513,8 +512,7 @@ static Res MVSpanFree(MVSpan span, Addr base, Addr limit, Pool blockPool) /* MVAlloc -- allocate method for class MV */ -static Res MVAlloc(Addr *pReturn, Pool pool, Size size, - Bool withReservoirPermit) +static Res MVAlloc(Addr *pReturn, Pool pool, Size size) { Res res; MVSpan span; @@ -530,7 +528,6 @@ static Res MVAlloc(Addr *pReturn, Pool pool, Size size, mv = PoolMV(pool); AVERT(MV, mv); AVER(size > 0); - AVERT(Bool, withReservoirPermit); size = SizeAlignUp(size, pool->alignment); @@ -556,8 +553,7 @@ static Res MVAlloc(Addr *pReturn, Pool pool, Size size, /* pool with a new region which will hold the requested allocation. */ /* Allocate a new span descriptor and initialize it to point at the */ /* region. */ - res = PoolAlloc(&addr, mvSpanPool(mv), sizeof(MVSpanStruct), - withReservoirPermit); + res = PoolAlloc(&addr, mvSpanPool(mv), sizeof(MVSpanStruct)); if(res != ResOK) return res; span = (MVSpan)addr; @@ -570,12 +566,10 @@ static Res MVAlloc(Addr *pReturn, Pool pool, Size size, arena = PoolArena(pool); regionSize = SizeArenaGrains(regionSize, arena); - res = ArenaAlloc(&base, LocusPrefDefault(), regionSize, pool, - withReservoirPermit); + res = ArenaAlloc(&base, LocusPrefDefault(), regionSize, pool); if(res != ResOK) { /* try again with a region big enough for this object */ regionSize = SizeArenaGrains(size, arena); - res = ArenaAlloc(&base, LocusPrefDefault(), regionSize, pool, - withReservoirPermit); + res = ArenaAlloc(&base, LocusPrefDefault(), regionSize, pool); if (res != ResOK) { PoolFree(mvSpanPool(mv), (Addr)span, sizeof(MVSpanStruct)); return res; diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index 1189f7d73e1..dc352d6eb81 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -35,15 +35,13 @@ static Res MVTInit(Pool pool, ArgList arg); static Bool MVTCheck(MVT mvt); static void MVTFinish(Pool pool); static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn, - Pool pool, Buffer buffer, Size minSize, - Bool withReservoirPermit); + Pool pool, Buffer buffer, Size minSize); static void MVTBufferEmpty(Pool pool, Buffer buffer, Addr base, Addr limit); static void MVTFree(Pool pool, Addr base, Size size); static Res MVTDescribe(Pool pool, mps_lib_FILE *stream, Count depth); static Size MVTTotalSize(Pool pool); static Size MVTFreeSize(Pool pool); -static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size, - Bool withReservoirPermit); +static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size); static void MVTSegFree(MVT mvt, Seg seg); static Bool MVTReturnSegs(MVT mvt, Range range, Arena arena); @@ -491,8 +489,7 @@ static void MVTNoteFill(MVT mvt, Addr base, Addr limit, Size minSize) { static Res MVTOversizeFill(Addr *baseReturn, Addr *limitReturn, MVT mvt, - Size minSize, - Bool withReservoirPermit) + Size minSize) { Res res; Seg seg; @@ -501,7 +498,7 @@ static Res MVTOversizeFill(Addr *baseReturn, alignedSize = SizeArenaGrains(minSize, PoolArena(MVTPool(mvt))); - res = MVTSegAlloc(&seg, mvt, alignedSize, withReservoirPermit); + res = MVTSegAlloc(&seg, mvt, alignedSize); if (res != ResOK) return res; @@ -660,14 +657,13 @@ static Bool MVTContingencyFill(Addr *baseReturn, Addr *limitReturn, static Res MVTSegFill(Addr *baseReturn, Addr *limitReturn, MVT mvt, Size fillSize, - Size minSize, - Bool withReservoirPermit) + Size minSize) { Res res; Seg seg; Addr base, limit; - res = MVTSegAlloc(&seg, mvt, fillSize, withReservoirPermit); + res = MVTSegAlloc(&seg, mvt, fillSize); if (res != ResOK) return res; @@ -686,8 +682,7 @@ static Res MVTSegFill(Addr *baseReturn, Addr *limitReturn, * See */ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn, - Pool pool, Buffer buffer, Size minSize, - Bool withReservoirPermit) + Pool pool, Buffer buffer, Size minSize) { MVT mvt; Res res; @@ -701,13 +696,12 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn, AVER(BufferIsReset(buffer)); AVER(minSize > 0); AVER(SizeIsAligned(minSize, pool->alignment)); - AVERT(Bool, withReservoirPermit); /* Allocate oversize blocks exactly, directly from the arena. */ if (minSize > mvt->fillSize) { return MVTOversizeFill(baseReturn, limitReturn, mvt, - minSize, withReservoirPermit); + minSize); } /* Use any splinter, if available. @@ -732,7 +726,7 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn, /* Attempt to request a block from the arena. */ res = MVTSegFill(baseReturn, limitReturn, - mvt, mvt->fillSize, minSize, withReservoirPermit); + mvt, mvt->fillSize, minSize); if (res == ResOK) return ResOK; @@ -1133,11 +1127,10 @@ mps_pool_class_t mps_class_mvt(void) /* MVTSegAlloc -- encapsulates SegAlloc with associated accounting and * metering */ -static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size, - Bool withReservoirPermit) +static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size) { Res res = SegAlloc(segReturn, SegClassGet(), LocusPrefDefault(), size, - MVTPool(mvt), withReservoirPermit, argsNone); + MVTPool(mvt), argsNone); if (res == ResOK) { Size segSize = SegSize(*segReturn); diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 1125f018a07..82d5c072ff3 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -189,13 +189,11 @@ static void MVFFReduce(MVFF mvff) /* MVFFExtend -- allocate a new range from the arena * - * Allocate a new range from the arena (with the given - * withReservoirPermit flag) of at least the specified size. The - * specified size should be pool-aligned. Add it to the allocated and - * free lists. + * Allocate a new range from the arena of at least the specified + * size. The specified size should be pool-aligned. Add it to the + * allocated and free lists. */ -static Res MVFFExtend(Range rangeReturn, MVFF mvff, Size size, - Bool withReservoirPermit) +static Res MVFFExtend(Range rangeReturn, MVFF mvff, Size size) { Pool pool; Arena arena; @@ -206,7 +204,6 @@ static Res MVFFExtend(Range rangeReturn, MVFF mvff, Size size, AVERT(MVFF, mvff); AVER(size > 0); - AVERT(Bool, withReservoirPermit); pool = MVFFPool(mvff); arena = PoolArena(pool); @@ -222,14 +219,12 @@ static Res MVFFExtend(Range rangeReturn, MVFF mvff, Size size, allocSize = SizeArenaGrains(allocSize, arena); - res = ArenaAlloc(&base, MVFFLocusPref(mvff), allocSize, pool, - withReservoirPermit); + res = ArenaAlloc(&base, MVFFLocusPref(mvff), allocSize, pool); if (res != ResOK) { /* try again with a range just large enough for object */ /* see */ allocSize = SizeArenaGrains(size, arena); - res = ArenaAlloc(&base, MVFFLocusPref(mvff), allocSize, pool, - withReservoirPermit); + res = ArenaAlloc(&base, MVFFLocusPref(mvff), allocSize, pool); if (res != ResOK) return res; } @@ -262,8 +257,7 @@ static Res MVFFExtend(Range rangeReturn, MVFF mvff, Size size, * If there is no suitable free block, try extending the pool. */ static Res mvffFindFree(Range rangeReturn, MVFF mvff, Size size, - LandFindMethod findMethod, FindDelete findDelete, - Bool withReservoirPermit) + LandFindMethod findMethod, FindDelete findDelete) { Bool found; RangeStruct oldRange; @@ -275,14 +269,13 @@ static Res mvffFindFree(Range rangeReturn, MVFF mvff, Size size, AVER(SizeIsAligned(size, PoolAlignment(MVFFPool(mvff)))); AVER(FUNCHECK(findMethod)); AVERT(FindDelete, findDelete); - AVERT(Bool, withReservoirPermit); land = MVFFFreeLand(mvff); found = (*findMethod)(rangeReturn, &oldRange, land, size, findDelete); if (!found) { RangeStruct newRange; Res res; - res = MVFFExtend(&newRange, mvff, size, withReservoirPermit); + res = MVFFExtend(&newRange, mvff, size); if (res != ResOK) return res; found = (*findMethod)(rangeReturn, &oldRange, land, size, findDelete); @@ -300,8 +293,7 @@ static Res mvffFindFree(Range rangeReturn, MVFF mvff, Size size, /* MVFFAlloc -- Allocate a block */ -static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size, - Bool withReservoirPermit) +static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size) { Res res; MVFF mvff; @@ -314,14 +306,12 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size, mvff = PoolMVFF(pool); AVERT(MVFF, mvff); AVER(size > 0); - AVERT(Bool, withReservoirPermit); size = SizeAlignUp(size, PoolAlignment(pool)); findMethod = mvff->firstFit ? LandFindFirst : LandFindLast; findDelete = mvff->slotHigh ? FindDeleteHIGH : FindDeleteLOW; - res = mvffFindFree(&range, mvff, size, findMethod, findDelete, - withReservoirPermit); + res = mvffFindFree(&range, mvff, size, findMethod, findDelete); if (res != ResOK) return res; @@ -361,8 +351,7 @@ static void MVFFFree(Pool pool, Addr old, Size size) * allocation policy; see . */ static Res MVFFBufferFill(Addr *baseReturn, Addr *limitReturn, - Pool pool, Buffer buffer, Size size, - Bool withReservoirPermit) + Pool pool, Buffer buffer, Size size) { Res res; MVFF mvff; @@ -376,10 +365,8 @@ static Res MVFFBufferFill(Addr *baseReturn, Addr *limitReturn, AVERT(Buffer, buffer); AVER(size > 0); AVER(SizeIsAligned(size, PoolAlignment(pool))); - AVERT(Bool, withReservoirPermit); - res = mvffFindFree(&range, mvff, size, LandFindLargest, FindDeleteENTIRE, - withReservoirPermit); + res = mvffFindFree(&range, mvff, size, LandFindLargest, FindDeleteENTIRE); if (res != ResOK) return res; AVER(RangeSize(&range) >= size); diff --git a/mps/code/pooln.c b/mps/code/pooln.c index cfb7bc0b61d..4a3e7d72ffc 100644 --- a/mps/code/pooln.c +++ b/mps/code/pooln.c @@ -60,8 +60,7 @@ static void NFinish(Pool pool) /* NAlloc -- alloc method for class N */ -static Res NAlloc(Addr *pReturn, Pool pool, Size size, - Bool withReservoirPermit) +static Res NAlloc(Addr *pReturn, Pool pool, Size size) { PoolN poolN; @@ -71,7 +70,6 @@ static Res NAlloc(Addr *pReturn, Pool pool, Size size, AVER(pReturn != NULL); AVER(size > 0); - AVERT(Bool, withReservoirPermit); return ResLIMIT; /* limit of nil blocks exceeded */ } @@ -97,8 +95,7 @@ static void NFree(Pool pool, Addr old, Size size) /* NBufferFill -- buffer fill method for class N */ static Res NBufferFill(Addr *baseReturn, Addr *limitReturn, - Pool pool, Buffer buffer, Size size, - Bool withReservoirPermit) + Pool pool, Buffer buffer, Size size) { PoolN poolN; @@ -110,7 +107,6 @@ static Res NBufferFill(Addr *baseReturn, Addr *limitReturn, AVERT(Buffer, buffer); AVER(BufferIsReset(buffer)); AVER(size > 0); - AVERT(Bool, withReservoirPermit); NOTREACHED; /* can't create buffers, so shouldn't fill them */ return ResUNIMPL; diff --git a/mps/code/poolncv.c b/mps/code/poolncv.c index a3f85342cb8..a8173246589 100644 --- a/mps/code/poolncv.c +++ b/mps/code/poolncv.c @@ -23,7 +23,7 @@ static void testit(ArenaClass class, ArgList args) die(ArenaCreate(&arena, class, args), "ArenaCreate"); die(PoolCreate(&pool, arena, PoolClassN(), argsNone), "PoolNCreate"); - res = PoolAlloc(&p, pool, 1, /* withReservoirPermit */ FALSE); + res = PoolAlloc(&p, pool, 1); if (res == ResOK) { error("Error: Unexpectedly succeeded in" "allocating block from PoolN\n"); diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c index ef295fc7d9a..db0985dc795 100644 --- a/mps/code/poolsnc.c +++ b/mps/code/poolsnc.c @@ -226,8 +226,7 @@ static Bool SNCSegCheck(SNCSeg sncseg) /* sncSegInit -- Init method for SNC segments */ -static Res sncSegInit(Seg seg, Pool pool, Addr base, Size size, - Bool reservoirPermit, ArgList args) +static Res sncSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) { SegClass super; SNCSeg sncseg; @@ -237,11 +236,10 @@ static Res sncSegInit(Seg seg, Pool pool, Addr base, Size size, sncseg = SegSNCSeg(seg); AVERT(Pool, pool); /* no useful checks for base and size */ - AVERT(Bool, reservoirPermit); /* Initialize the superclass fields first via next-method call */ super = SEG_SUPERCLASS(SNCSegClass); - res = super->init(seg, pool, base, size, reservoirPermit, args); + res = super->init(seg, pool, base, size, args); if (res != ResOK) return res; @@ -419,8 +417,7 @@ static void SNCFinish(Pool pool) static Res SNCBufferFill(Addr *baseReturn, Addr *limitReturn, - Pool pool, Buffer buffer, Size size, - Bool withReservoirPermit) + Pool pool, Buffer buffer, Size size) { SNC snc; Arena arena; @@ -433,7 +430,6 @@ static Res SNCBufferFill(Addr *baseReturn, Addr *limitReturn, AVERT(Pool, pool); AVERT(Buffer, buffer); AVER(size > 0); - AVERT(Bool, withReservoirPermit); AVER(BufferIsReset(buffer)); snc = PoolSNC(pool); @@ -448,7 +444,7 @@ static Res SNCBufferFill(Addr *baseReturn, Addr *limitReturn, arena = PoolArena(pool); asize = SizeArenaGrains(size, arena); res = SegAlloc(&seg, SNCSegClassGet(), LocusPrefDefault(), - asize, pool, withReservoirPermit, argsNone); + asize, pool, argsNone); if (res != ResOK) return res; diff --git a/mps/code/root.c b/mps/code/root.c index 63445f0ef21..c241430ab63 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -185,7 +185,7 @@ static Res rootCreate(Root *rootReturn, Arena arena, AVERT(RootVar, type); globals = ArenaGlobals(arena); - res = ControlAlloc(&p, arena, sizeof(RootStruct), FALSE); + res = ControlAlloc(&p, arena, sizeof(RootStruct)); if (res != ResOK) return res; root = (Root)p; /* Avoid pun */ diff --git a/mps/code/sac.c b/mps/code/sac.c index ab8bf867e3f..e7b13327ea1 100644 --- a/mps/code/sac.c +++ b/mps/code/sac.c @@ -149,8 +149,7 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount, middleIndex = i + 1; /* there must exist another class at i+1 */ /* Allocate SAC */ - res = ControlAlloc(&p, PoolArena(pool), sacSize(middleIndex, classesCount), - FALSE); + res = ControlAlloc(&p, PoolArena(pool), sacSize(middleIndex, classesCount)); if(res != ResOK) goto failSACAlloc; sac = p; @@ -245,7 +244,7 @@ static void sacFind(Index *iReturn, Size *blockSizeReturn, /* SACFill -- alloc an object, and perhaps fill the cache */ -Res SACFill(Addr *p_o, SAC sac, Size size, Bool hasReservoirPermit) +Res SACFill(Addr *p_o, SAC sac, Size size) { Index i; Count blockCount, j; @@ -257,7 +256,6 @@ Res SACFill(Addr *p_o, SAC sac, Size size, Bool hasReservoirPermit) AVER(p_o != NULL); AVERT(SAC, sac); AVER(size != 0); - AVERT(Bool, hasReservoirPermit); esac = ExternalSACOfSAC(sac); sacFind(&i, &blockSize, sac, size); @@ -272,7 +270,7 @@ Res SACFill(Addr *p_o, SAC sac, Size size, Bool hasReservoirPermit) blockSize = SizeAlignUp(size, PoolAlignment(sac->pool)); for (j = 0, fl = esac->_freelists[i]._blocks; j <= blockCount; ++j) { - res = PoolAlloc(&p, sac->pool, blockSize, hasReservoirPermit); + res = PoolAlloc(&p, sac->pool, blockSize); if (res != ResOK) break; /* @@@@ ignoring shields for now */ diff --git a/mps/code/sac.h b/mps/code/sac.h index bd52a35daff..b60047e9ee3 100644 --- a/mps/code/sac.h +++ b/mps/code/sac.h @@ -44,7 +44,7 @@ typedef struct mps_sac_classes_s *SACClasses; extern Res SACCreate(SAC *sac_o, Pool pool, Count classesCount, SACClasses classes); extern void SACDestroy(SAC sac); -extern Res SACFill(Addr *p_o, SAC sac, Size size, Bool hasReservoirPermit); +extern Res SACFill(Addr *p_o, SAC sac, Size size); extern void SACEmpty(SAC sac, Addr p, Size size); extern void SACFlush(SAC sac); diff --git a/mps/code/seg.c b/mps/code/seg.c index 7007bca62b7..04785652e90 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -46,7 +46,7 @@ SRCID(seg, "$Id$"); static void SegFinish(Seg seg); static Res SegInit(Seg seg, Pool pool, Addr base, Size size, - Bool withReservoirPermit, ArgList args); + ArgList args); /* Generic interface support */ @@ -55,7 +55,7 @@ static Res SegInit(Seg seg, Pool pool, Addr base, Size size, /* SegAlloc -- allocate a segment from the arena */ Res SegAlloc(Seg *segReturn, SegClass class, LocusPref pref, - Size size, Pool pool, Bool withReservoirPermit, ArgList args) + Size size, Pool pool, ArgList args) { Res res; Arena arena; @@ -68,25 +68,24 @@ Res SegAlloc(Seg *segReturn, SegClass class, LocusPref pref, AVERT(LocusPref, pref); AVER(size > (Size)0); AVERT(Pool, pool); - AVERT(Bool, withReservoirPermit); arena = PoolArena(pool); AVERT(Arena, arena); AVER(SizeIsArenaGrains(size, arena)); /* allocate the memory from the arena */ - res = ArenaAlloc(&base, pref, size, pool, withReservoirPermit); + res = ArenaAlloc(&base, pref, size, pool); if (res != ResOK) goto failArena; /* allocate the segment object from the control pool */ - res = ControlAlloc(&p, arena, class->size, withReservoirPermit); + res = ControlAlloc(&p, arena, class->size); if (res != ResOK) goto failControl; seg = p; seg->class = class; - res = SegInit(seg, pool, base, size, withReservoirPermit, args); + res = SegInit(seg, pool, base, size, args); if (res != ResOK) goto failInit; @@ -134,8 +133,7 @@ void SegFree(Seg seg) /* SegInit -- initialize a segment */ -static Res SegInit(Seg seg, Pool pool, Addr base, Size size, - Bool withReservoirPermit, ArgList args) +static Res SegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) { Tract tract; Addr addr, limit; @@ -150,7 +148,6 @@ static Res SegInit(Seg seg, Pool pool, Addr base, Size size, AVER(SizeIsArenaGrains(size, arena)); class = seg->class; AVERT(SegClass, class); - AVERT(Bool, withReservoirPermit); limit = AddrAdd(base, size); seg->limit = limit; @@ -183,7 +180,7 @@ static Res SegInit(Seg seg, Pool pool, Addr base, Size size, RingInit(SegPoolRing(seg)); /* Class specific initialization comes last */ - res = class->init(seg, pool, base, size, withReservoirPermit, args); + res = class->init(seg, pool, base, size, args); if (res != ResOK) goto failInit; @@ -556,8 +553,7 @@ Bool SegNext(Seg *segReturn, Arena arena, Seg seg) * See */ -Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi, - Bool withReservoirPermit) +Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi) { SegClass class; Addr base, mid, limit; @@ -574,18 +570,16 @@ Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi, mid = SegLimit(segLo); limit = SegLimit(segHi); AVER(SegBase(segHi) == SegLimit(segLo)); - AVERT(Bool, withReservoirPermit); arena = PoolArena(SegPool(segLo)); ShieldFlush(arena); /* see */ /* Invoke class-specific methods to do the merge */ - res = class->merge(segLo, segHi, base, mid, limit, - withReservoirPermit); + res = class->merge(segLo, segHi, base, mid, limit); if (ResOK != res) goto failMerge; - EVENT3(SegMerge, segLo, segHi, BOOLOF(withReservoirPermit)); + EVENT2(SegMerge, segLo, segHi); /* Deallocate segHi object */ ControlFree(arena, segHi, class->size); AVERT(Seg, segLo); @@ -605,8 +599,7 @@ Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi, * See */ -Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at, - Bool withReservoirPermit) +Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at) { Addr base, limit; SegClass class; @@ -626,7 +619,6 @@ Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at, AVER(AddrIsArenaGrain(at, arena)); AVER(at > base); AVER(at < limit); - AVERT(Bool, withReservoirPermit); /* Can only split a buffered segment if the entire buffer is below * the split point. */ @@ -635,14 +627,13 @@ Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at, ShieldFlush(arena); /* see */ /* Allocate the new segment object from the control pool */ - res = ControlAlloc(&p, arena, class->size, withReservoirPermit); + res = ControlAlloc(&p, arena, class->size); if (ResOK != res) goto failControl; segNew = p; /* Invoke class-specific methods to do the split */ - res = class->split(seg, segNew, base, at, limit, - withReservoirPermit); + res = class->split(seg, segNew, base, at, limit); if (ResOK != res) goto failSplit; @@ -746,8 +737,7 @@ Bool SegCheck(Seg seg) /* segTrivInit -- method to initialize the base fields of a segment */ -static Res segTrivInit(Seg seg, Pool pool, Addr base, Size size, - Bool reservoirPermit, ArgList args) +static Res segTrivInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) { /* all the initialization happens in SegInit so checks are safe */ Arena arena; @@ -760,7 +750,6 @@ static Res segTrivInit(Seg seg, Pool pool, Addr base, Size size, AVER(SegBase(seg) == base); AVER(SegSize(seg) == size); AVER(SegPool(seg) == pool); - AVERT(Bool, reservoirPermit); AVERT(ArgList, args); UNUSED(args); return ResOK; @@ -853,8 +842,7 @@ static void segNoSetBuffer(Seg seg, Buffer buffer) /* segNoMerge -- merge method for segs which don't support merge */ static Res segNoMerge(Seg seg, Seg segHi, - Addr base, Addr mid, Addr limit, - Bool withReservoirPermit) + Addr base, Addr mid, Addr limit) { AVERT(Seg, seg); AVERT(Seg, segHi); @@ -862,7 +850,6 @@ static Res segNoMerge(Seg seg, Seg segHi, AVER(SegLimit(seg) == mid); AVER(SegBase(segHi) == mid); AVER(SegLimit(segHi) == limit); - AVERT(Bool, withReservoirPermit); NOTREACHED; return ResFAIL; } @@ -875,8 +862,7 @@ static Res segNoMerge(Seg seg, Seg segHi, */ static Res segTrivMerge(Seg seg, Seg segHi, - Addr base, Addr mid, Addr limit, - Bool withReservoirPermit) + Addr base, Addr mid, Addr limit) { Pool pool; Arena arena; @@ -896,7 +882,6 @@ static Res segTrivMerge(Seg seg, Seg segHi, AVER(SegLimit(seg) == mid); AVER(SegBase(segHi) == mid); AVER(SegLimit(segHi) == limit); - AVERT(Bool, withReservoirPermit); /* .similar. */ AVER(seg->rankSet == segHi->rankSet); @@ -935,8 +920,7 @@ static Res segTrivMerge(Seg seg, Seg segHi, /* segNoSplit -- split method for segs which don't support splitting */ static Res segNoSplit(Seg seg, Seg segHi, - Addr base, Addr mid, Addr limit, - Bool withReservoirPermit) + Addr base, Addr mid, Addr limit) { AVERT(Seg, seg); AVER(segHi != NULL); /* can't check fully, it's not initialized */ @@ -944,7 +928,6 @@ static Res segNoSplit(Seg seg, Seg segHi, AVER(mid < limit); AVER(SegBase(seg) == base); AVER(SegLimit(seg) == limit); - AVERT(Bool, withReservoirPermit); NOTREACHED; return ResFAIL; @@ -954,8 +937,7 @@ static Res segNoSplit(Seg seg, Seg segHi, /* segTrivSplit -- Basic Seg split method */ static Res segTrivSplit(Seg seg, Seg segHi, - Addr base, Addr mid, Addr limit, - Bool withReservoirPermit) + Addr base, Addr mid, Addr limit) { Tract tract; Pool pool; @@ -973,7 +955,6 @@ static Res segTrivSplit(Seg seg, Seg segHi, AVER(mid < limit); AVER(SegBase(seg) == base); AVER(SegLimit(seg) == limit); - AVERT(Bool, withReservoirPermit); /* Segment may not be exposed, or in the shield cache */ /* See & */ @@ -1084,8 +1065,7 @@ Bool GCSegCheck(GCSeg gcseg) /* gcSegInit -- method to initialize a GC segment */ -static Res gcSegInit(Seg seg, Pool pool, Addr base, Size size, - Bool withReservoirPermit, ArgList args) +static Res gcSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) { SegClass super; GCSeg gcseg; @@ -1099,11 +1079,10 @@ static Res gcSegInit(Seg seg, Pool pool, Addr base, Size size, AVER(SizeIsArenaGrains(size, arena)); gcseg = SegGCSeg(seg); AVER(&gcseg->segStruct == seg); - AVERT(Bool, withReservoirPermit); /* Initialize the superclass fields first via next-method call */ super = SEG_SUPERCLASS(GCSegClass); - res = super->init(seg, pool, base, size, withReservoirPermit, args); + res = super->init(seg, pool, base, size, args); if (ResOK != res) return res; @@ -1443,8 +1422,7 @@ static void gcSegSetBuffer(Seg seg, Buffer buffer) */ static Res gcSegMerge(Seg seg, Seg segHi, - Addr base, Addr mid, Addr limit, - Bool withReservoirPermit) + Addr base, Addr mid, Addr limit) { SegClass super; GCSeg gcseg, gcsegHi; @@ -1465,7 +1443,6 @@ static Res gcSegMerge(Seg seg, Seg segHi, AVER(SegLimit(seg) == mid); AVER(SegBase(segHi) == mid); AVER(SegLimit(segHi) == limit); - AVERT(Bool, withReservoirPermit); buf = gcsegHi->buffer; /* any buffer on segHi must be reassigned */ AVER(buf == NULL || gcseg->buffer == NULL); /* See .buffer */ @@ -1474,8 +1451,7 @@ static Res gcSegMerge(Seg seg, Seg segHi, /* Merge the superclass fields via next-method call */ super = SEG_SUPERCLASS(GCSegClass); - res = super->merge(seg, segHi, base, mid, limit, - withReservoirPermit); + res = super->merge(seg, segHi, base, mid, limit); if (res != ResOK) goto failSuper; @@ -1513,8 +1489,7 @@ static Res gcSegMerge(Seg seg, Seg segHi, /* gcSegSplit -- GCSeg split method */ static Res gcSegSplit(Seg seg, Seg segHi, - Addr base, Addr mid, Addr limit, - Bool withReservoirPermit) + Addr base, Addr mid, Addr limit) { SegClass super; GCSeg gcseg, gcsegHi; @@ -1531,7 +1506,6 @@ static Res gcSegSplit(Seg seg, Seg segHi, AVER(mid < limit); AVER(SegBase(seg) == base); AVER(SegLimit(seg) == limit); - AVERT(Bool, withReservoirPermit); grey = SegGrey(seg); buf = gcseg->buffer; /* Look for buffer to reassign to segHi */ @@ -1546,8 +1520,7 @@ static Res gcSegSplit(Seg seg, Seg segHi, /* Split the superclass fields via next-method call */ super = SEG_SUPERCLASS(GCSegClass); - res = super->split(seg, segHi, base, mid, limit, - withReservoirPermit); + res = super->split(seg, segHi, base, mid, limit); if (res != ResOK) goto failSuper; diff --git a/mps/code/segsmss.c b/mps/code/segsmss.c index 73f3f79461b..746c253f321 100644 --- a/mps/code/segsmss.c +++ b/mps/code/segsmss.c @@ -111,8 +111,7 @@ static Bool AMSTSegCheck(AMSTSeg amstseg) /* amstSegInit -- initialise an amst segment */ -static Res amstSegInit(Seg seg, Pool pool, Addr base, Size size, - Bool reservoirPermit, ArgList args) +static Res amstSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) { SegClass super; AMSTSeg amstseg; @@ -125,11 +124,10 @@ static Res amstSegInit(Seg seg, Pool pool, Addr base, Size size, amst = PoolAMST(pool); AVERT(AMST, amst); /* no useful checks for base and size */ - AVERT(Bool, reservoirPermit); /* Initialize the superclass fields first via next-method call */ super = SEG_SUPERCLASS(AMSTSegClass); - res = super->init(seg, pool, base, size, reservoirPermit, args); + res = super->init(seg, pool, base, size, args); if (res != ResOK) return res; @@ -176,8 +174,7 @@ static void amstSegFinish(Seg seg) * anti-method. */ static Res amstSegMerge(Seg seg, Seg segHi, - Addr base, Addr mid, Addr limit, - Bool withReservoirPermit) + Addr base, Addr mid, Addr limit) { SegClass super; AMST amst; @@ -194,8 +191,7 @@ static Res amstSegMerge(Seg seg, Seg segHi, /* Merge the superclass fields via direct next-method call */ super = SEG_SUPERCLASS(AMSTSegClass); - res = super->merge(seg, segHi, base, mid, limit, - withReservoirPermit); + res = super->merge(seg, segHi, base, mid, limit); if (res != ResOK) goto failSuper; @@ -214,8 +210,7 @@ static Res amstSegMerge(Seg seg, Seg segHi, failDeliberate: /* Call the anti-method (see .fail) */ - res = super->split(seg, segHi, base, mid, limit, - withReservoirPermit); + res = super->split(seg, segHi, base, mid, limit); AVER(res == ResOK); res = ResFAIL; failSuper: @@ -228,8 +223,7 @@ static Res amstSegMerge(Seg seg, Seg segHi, /* amstSegSplit -- AMSTSeg split method */ static Res amstSegSplit(Seg seg, Seg segHi, - Addr base, Addr mid, Addr limit, - Bool withReservoirPermit) + Addr base, Addr mid, Addr limit) { SegClass super; AMST amst; @@ -245,8 +239,7 @@ static Res amstSegSplit(Seg seg, Seg segHi, /* Split the superclass fields via direct next-method call */ super = SEG_SUPERCLASS(AMSTSegClass); - res = super->split(seg, segHi, base, mid, limit, - withReservoirPermit); + res = super->split(seg, segHi, base, mid, limit); if (res != ResOK) goto failSuper; @@ -269,8 +262,7 @@ static Res amstSegSplit(Seg seg, Seg segHi, failDeliberate: /* Call the anti-method. (see .fail) */ - res = super->merge(seg, segHi, base, mid, limit, - withReservoirPermit); + res = super->merge(seg, segHi, base, mid, limit); AVER(res == ResOK); res = ResFAIL; failSuper: @@ -526,8 +518,7 @@ static void AMSAllocateRange(AMS ams, Seg seg, Addr base, Addr limit) * meet the request. */ static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn, - Pool pool, Buffer buffer, Size size, - Bool withReservoirPermit) + Pool pool, Buffer buffer, Size size) { PoolClass super; Addr base, limit; @@ -549,8 +540,7 @@ static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn, /* call next method */ super = POOL_SUPERCLASS(AMSTPoolClass); - res = super->bufferFill(&base, &limit, pool, buffer, size, - withReservoirPermit); + res = super->bufferFill(&base, &limit, pool, buffer, size); if (res != ResOK) return res; @@ -567,7 +557,7 @@ static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn, Res mres; AMSUnallocateRange(ams, seg, base, limit); - mres = SegMerge(&mergedSeg, segLo, seg, withReservoirPermit); + mres = SegMerge(&mergedSeg, segLo, seg); if (ResOK == mres) { /* successful merge */ AMSAllocateRange(ams, mergedSeg, base, limit); /* leave range as-is */ @@ -585,7 +575,7 @@ static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn, Seg segLo, segHi; Res sres; AMSUnallocateRange(ams, seg, mid, limit); - sres = SegSplit(&segLo, &segHi, seg, mid, withReservoirPermit); + sres = SegSplit(&segLo, &segHi, seg, mid); if (ResOK == sres) { /* successful split */ limit = mid; /* range is lower segment */ } else { /* failed to split */ @@ -639,7 +629,7 @@ static void AMSTStressBufferedSeg(Seg seg, Buffer buffer) /* .bmerge */ Seg mergedSeg; Res res; - res = SegMerge(&mergedSeg, seg, segHi, FALSE); + res = SegMerge(&mergedSeg, seg, segHi); if (ResOK == res) { amst->bmerges++; printf("J"); @@ -656,7 +646,7 @@ static void AMSTStressBufferedSeg(Seg seg, Buffer buffer) /* .bsplit */ Seg segLo, segHi; Res res; - res = SegSplit(&segLo, &segHi, seg, limit, FALSE); + res = SegSplit(&segLo, &segHi, seg, limit); if (ResOK == res) { amst->bsplits++; printf("C"); diff --git a/mps/code/than.c b/mps/code/than.c index 3e2dbaa81a0..dc4781dd6cd 100644 --- a/mps/code/than.c +++ b/mps/code/than.c @@ -47,8 +47,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena) AVER(threadReturn != NULL); - res = ControlAlloc(&p, arena, sizeof(ThreadStruct), - /* withReservoirPermit */ FALSE); + res = ControlAlloc(&p, arena, sizeof(ThreadStruct)); if (res != ResOK) return res; thread = (Thread)p; diff --git a/mps/code/thix.c b/mps/code/thix.c index 219ae33bcdd..a5b4559f3db 100644 --- a/mps/code/thix.c +++ b/mps/code/thix.c @@ -86,8 +86,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena) AVER(threadReturn != NULL); AVERT(Arena, arena); - res = ControlAlloc(&p, arena, sizeof(ThreadStruct), - /* withReservoirPermit */ FALSE); + res = ControlAlloc(&p, arena, sizeof(ThreadStruct)); if(res != ResOK) return res; thread = (Thread)p; diff --git a/mps/code/thw3.c b/mps/code/thw3.c index b8b8b106680..af44eb33018 100644 --- a/mps/code/thw3.c +++ b/mps/code/thw3.c @@ -83,8 +83,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena) AVER(threadReturn != NULL); AVERT(Arena, arena); - res = ControlAlloc(&p, arena, sizeof(ThreadStruct), - /* withReservoirPermit */ FALSE); + res = ControlAlloc(&p, arena, sizeof(ThreadStruct)); if(res != ResOK) return res; thread = (Thread)p; /* avoid pun */ diff --git a/mps/code/thxc.c b/mps/code/thxc.c index 3bb449d46fe..190c94fb92c 100644 --- a/mps/code/thxc.c +++ b/mps/code/thxc.c @@ -69,8 +69,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena) AVER(threadReturn != NULL); - res = ControlAlloc(&p, arena, sizeof(ThreadStruct), - /* withReservoirPermit */ FALSE); + res = ControlAlloc(&p, arena, sizeof(ThreadStruct)); if (res != ResOK) return res; thread = (Thread)p; diff --git a/mps/code/traceanc.c b/mps/code/traceanc.c index c57500c0b65..9212a633ba1 100644 --- a/mps/code/traceanc.c +++ b/mps/code/traceanc.c @@ -467,12 +467,12 @@ Res TraceIdMessagesCreate(Arena arena, TraceId ti) AVER(!arena->tsMessage[ti]); AVER(!arena->tMessage[ti]); - res = ControlAlloc(&p, arena, sizeof(TraceStartMessageStruct), FALSE); + res = ControlAlloc(&p, arena, sizeof(TraceStartMessageStruct)); if(res != ResOK) goto failTraceStartMessage; tsMessage = p; - res = ControlAlloc(&p, arena, sizeof(TraceMessageStruct), FALSE); + res = ControlAlloc(&p, arena, sizeof(TraceMessageStruct)); if(res != ResOK) goto failTraceMessage; tMessage = p; @@ -674,7 +674,7 @@ static Res arenaRememberSummaryOne(Globals global, Addr base, RefSet summary) RememberedSummaryBlock newBlock; int res; - res = ControlAlloc(&p, arena, sizeof *newBlock, FALSE); + res = ControlAlloc(&p, arena, sizeof *newBlock); if(res != ResOK) { return res; } diff --git a/mps/design/object-debug.txt b/mps/design/object-debug.txt index df89b5cf21c..1c9a03cb9ad 100644 --- a/mps/design/object-debug.txt +++ b/mps/design/object-debug.txt @@ -291,13 +291,10 @@ protocol. This will be improved, when we figure out formatted pools -- they don't need tags for fenceposting. -_`.out-of-space`: If there's no room for tags, we will not dip into -the reservoir, just fail to allocate the tag. If the alloc call had a -reservoir permit, we let it succeed even without a tag, and just make -sure the free method will not complain if it can't find a tag. If the -call didn't have a reservoir permit, we free the block allocated for -the object and fail the allocation, so that the client gets a chance -to do whatever low-memory actions they might want to do. +_`.out-of-space`: If there's no room for tags, we just fail to +allocate the tag. We free the block allocated for the object and fail +the allocation, so that the client gets a chance to do whatever +low-memory actions they might want to do. .. note:: From d1dd0c9105cba2caec73fe30a1947062b63c934b Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 13 Mar 2016 21:49:23 +0000 Subject: [PATCH 251/337] Updating conerr/4 to know the correct number of pools, now that the reservoir is gone. Copied from Perforce Change: 190010 ServerID: perforce.ravenbrook.com --- mps/test/conerr/4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/test/conerr/4.c b/mps/test/conerr/4.c index 38451258bdf..995f46160c9 100644 --- a/mps/test/conerr/4.c +++ b/mps/test/conerr/4.c @@ -7,7 +7,7 @@ TEST_HEADER OUTPUT_SPEC assert = true assertfile P= global.c - assertcond = RingLength(&arenaGlobals->poolRing) == 5 + assertcond = RingLength(&arenaGlobals->poolRing) == 4 END_HEADER */ From 69c312d1797e447cae4301a3c87dfbbf9e4cf8b2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 13 Mar 2016 21:49:36 +0000 Subject: [PATCH 252/337] Use a regular expression in case the number of built-in pools changes. Copied from Perforce Change: 190011 ServerID: perforce.ravenbrook.com --- mps/test/conerr/4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/test/conerr/4.c b/mps/test/conerr/4.c index 38451258bdf..396b7655b1a 100644 --- a/mps/test/conerr/4.c +++ b/mps/test/conerr/4.c @@ -7,7 +7,7 @@ TEST_HEADER OUTPUT_SPEC assert = true assertfile P= global.c - assertcond = RingLength(&arenaGlobals->poolRing) == 5 + assertcond =~ RingLength\(&arenaGlobals->poolRing\) == \d+ END_HEADER */ From c350ec44ca8328d362c2107fbfe8d18e3250ee6c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 13 Mar 2016 22:41:29 +0000 Subject: [PATCH 253/337] Remove some remaining mentions of the reservoir. Copied from Perforce Change: 190017 ServerID: perforce.ravenbrook.com --- mps/design/object-debug.txt | 4 ---- mps/design/poolawl.txt | 2 +- mps/design/protocol.txt | 6 ++--- mps/manual/source/topic/telemetry.rst | 32 +++++++++++++-------------- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/mps/design/object-debug.txt b/mps/design/object-debug.txt index 1c9a03cb9ad..627f8352c3a 100644 --- a/mps/design/object-debug.txt +++ b/mps/design/object-debug.txt @@ -296,10 +296,6 @@ allocate the tag. We free the block allocated for the object and fail the allocation, so that the client gets a chance to do whatever low-memory actions they might want to do. -.. note:: - - Should this depend on whether there is anything in the reservoir? - This breaks the one-to-one relationship between tags and objects, so some checks cannot be made, but we do count the "lost" tags. diff --git a/mps/design/poolawl.txt b/mps/design/poolawl.txt index b8b74820645..609d236320e 100644 --- a/mps/design/poolawl.txt +++ b/mps/design/poolawl.txt @@ -481,7 +481,7 @@ _`.fun.awlsegcreate.where`: The segment is allocated using a generation preference, using the generation number stored in the ``AWLStruct`` (the ``gen`` field), see `.poolstruct.gen`_ above. -``Res awlSegInit(Seg seg, Pool pool, Addr base, Size size, Bool reservoirPermit, va_list args)`` +``Res awlSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args)`` _`.fun.awlseginit`: Init method for ``AWLSegClass``, called for ``SegAlloc()`` whenever an ``AWLSeg`` is created (see diff --git a/mps/design/protocol.txt b/mps/design/protocol.txt index bddebf3f2a3..4dca17bcf97 100644 --- a/mps/design/protocol.txt +++ b/mps/design/protocol.txt @@ -417,7 +417,7 @@ failure-case code for an "init" method, making use of the "finish" anti-method:: static Res mySegInit(Seg seg, Pool pool, Addr base, Size size, - Bool reservoirPermit, va_list args) + ArgList args) { SegClass super; MYSeg myseg; @@ -437,12 +437,12 @@ anti-method:: /* Initialize the superclass fields first via next-method call */ super = (SegClass)SUPERCLASS(MYSegClass); - res = super->init(seg, pool, base, size, reservoirPermit, args); + res = super->init(seg, pool, base, size, args); if(res != ResOK) goto failNextMethods; /* Create an object after the next-method call */ - res = ControlAlloc(&obj1, arena, sizeof(OBJ1Struct), reservoirPermit); + res = ControlAlloc(&obj1, arena, sizeof(OBJ1Struct)); if(res != ResOK) goto failObj1; diff --git a/mps/manual/source/topic/telemetry.rst b/mps/manual/source/topic/telemetry.rst index 5ee6bb000e1..0f107985c20 100644 --- a/mps/manual/source/topic/telemetry.rst +++ b/mps/manual/source/topic/telemetry.rst @@ -125,14 +125,14 @@ as the `Time Stamp Counter `_ on IA-32 and x86-64, if one is available. All numbers are given in hexadecimal. :: - 000AE03973336E3C 002B VMCreate vm:00000001003FC000 base:00000001003FD000 limit:00000001003FE000 - 000AE0397333BC6D 002D VMMap vm:00000001003FC000 base:00000001003FD000 limit:00000001003FE000 - 000AE0397334DF9F 001A Intern stringId:0000000000000002 string:"Reservoir" - 000AE0397334E0A0 001B Label address:00000001078C85B8["Reservoir"] stringId:0000000000000002 - 000AE03973352375 0015 PoolInit pool:00000001003FD328 arena:00000001003FD000 poolClass:00000001078C85B8["Reservoir"] - 000AE039733592F9 002B VMCreate vm:00000001003FE000 base:00000001003FF000 limit:000000010992F000 - 000AE0397335C8B5 002D VMMap vm:00000001003FE000 base:00000001003FF000 limit:0000000107930000 - 000AE03973361D5A 0005 ArenaCreateVM arena:00000001003FD000 userSize:0000000002000000 chunkSize:0000000002000000 + 000021C9DB3812C7 0075 EventClockSync clock:0000000000001EE3 + 000021C9DB39E2FB 002B VMInit vm:00007FFF5429C4B8 base:000000010BA4A000 limit:000000010BA4B000 + 000021C9DB3A5630 002D VMMap vm:00007FFF5429C4B8 base:000000010BA4A000 limit:000000010BA4B000 + 000021C9DB3E6BAA 001A Intern stringId:0000000000000002 string:"MFS" + 000021C9DB3E6E17 001B Label address:000000010BA0C5D8["MFS"] stringId:0000000000000002 + 000021C9DB3EB6F8 0044 PoolInitMFS pool:000000010BA4A360 arena:000000010BA4A000 extendBy:0000000000001000 extendSelf:False unitSize:0000000000000030 + 000021C9DB3EFE3B 002B VMInit vm:00007FFF5429C3D0 base:000000010BC84000 limit:000000010CC24000 + 000021C9DB3F33F3 002D VMMap vm:00007FFF5429C3D0 base:000000010BC84000 limit:000000010BC85000 You can search through the telemetry for events related to particular addresses of interest. @@ -269,14 +269,14 @@ Here's some example output. The first column contains the timestamp of the event, the second column contains the event type, and remaining columns contain parameters related to the event. :: - 000AE03973336E3C 2B 1003FC000 1003FD000 1003FE000 - 000AE0397333BC6D 2D 1003FC000 1003FD000 1003FE000 - 000AE0397334DF9F 1A 2 "Reservoir" - 000AE0397334E0A0 1B 1078C85B8 2 - 000AE03973352375 15 1003FD328 1003FD000 1078C85B8 - 000AE039733592F9 2B 1003FE000 1003FF000 10992F000 - 000AE0397335C8B5 2D 1003FE000 1003FF000 107930000 - 000AE03973361D5A 5 1003FD000 2000000 2000000 + 000021C9DB3812C7 75 1EE3 + 000021C9DB39E2FB 2B 7FFF5429C4B8 10BA4A000 10BA4B000 + 000021C9DB3A5630 2D 7FFF5429C4B8 10BA4A000 10BA4B000 + 000021C9DB3E6BAA 1A 2 "MFS" + 000021C9DB3E6E17 1B 10BA0C5D8 2 + 000021C9DB3EB6F8 44 10BA4A360 10BA4A000 1000 0 30 + 000021C9DB3EFE3B 2B 7FFF5429C3D0 10BC84000 10CC24000 + 000021C9DB3F33F3 2D 7FFF5429C3D0 10BC84000 10BC85000 .. index:: From f1fe190638df56f77d8d00ae18715e0cd6489223 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 13 Mar 2016 22:44:49 +0000 Subject: [PATCH 254/337] Remove mmqa test cases for the reservoir. Copied from Perforce Change: 190018 ServerID: perforce.ravenbrook.com --- mps/test/function/132.c | 189 ------------------------------------ mps/test/function/133.c | 151 ----------------------------- mps/test/function/149.c | 199 -------------------------------------- mps/test/testsets/passing | 5 +- 4 files changed, 2 insertions(+), 542 deletions(-) delete mode 100644 mps/test/function/132.c delete mode 100644 mps/test/function/133.c delete mode 100644 mps/test/function/149.c diff --git a/mps/test/function/132.c b/mps/test/function/132.c deleted file mode 100644 index b69e6cbcecf..00000000000 --- a/mps/test/function/132.c +++ /dev/null @@ -1,189 +0,0 @@ -/* -TEST_HEADER - id = $Id$ - summary = low-memory reservoir tests with commit limit, part I - language = c - harness = 2.1 - link = testlib.o rankfmt.o -OUTPUT_SPEC - lim0 = 0 - avail0 = 0 - lim1 > 5000000 - lim1 < 6000000 - deficit1 = 0 - lim2 > 1045 - lim2 < 32768 - deficit2 = 0 - deficit3 > 8000000 - spill3 <= 0 - spill4 <= 0 - grow4 > 500000 - allocfail < 20 - failres = COMMIT_LIMIT - spill5 <= 0 - grow5 = 0 - avail5 > 1500000 - allocfail2 > 5000 - failres2 = COMMIT_LIMIT - shrink6 > 1000000 - spill6 <= 0 - completed = yes -END_HEADER -*/ - -#include "testlib.h" -#include "mpscamc.h" -#include "mpsavm.h" -#include "rankfmt.h" - - -#define ARENA_SIZE ((size_t) 1024*1024*30) - -#define genCOUNT (3) - -static mps_gen_param_s testChain[genCOUNT] = { - { 6000, 0.90 }, { 8000, 0.65 }, { 16000, 0.50 } }; - - -void *stackpointer; - - -static void test(void) -{ - mps_arena_t arena; - mps_pool_t poolamc; - mps_thr_t thread; - mps_root_t root; - - mps_fmt_t format; - mps_chain_t chain; - mps_ap_t apamc; - - mycell *p, *q; - int i; - mps_res_t res; - size_t lim0, avail0, lim1, avail1, commit1, lim2, avail2, commit2; - size_t lim3, avail3, commit3, lim4, avail4, commit4; - size_t lim5, avail5, commit5, lim6, avail6, commit6; - - cdie(mps_arena_create(&arena, mps_arena_class_vm(), ARENA_SIZE), - "create arena"); - - cdie(mps_thread_reg(&thread, arena), "register thread"); - cdie(mps_root_create_reg(&root, arena, mps_rank_ambig(), 0, thread, - mps_stack_scan_ambig, stackpointer, 0), - "create stack root"); - - cdie(mps_fmt_create_A(&format, arena, &fmtA), "create format"); - cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - - die(mmqa_pool_create_chain(&poolamc, arena, mps_class_amc(), format, chain), - "create pool"); - - cdie( - mps_ap_create(&apamc, poolamc, mps_rank_exact()), - "create ap"); - - report("lim0", "%d", lim0 = mps_reservoir_limit(arena)); - report("avail0", "%d", avail0 = mps_reservoir_available(arena)); - mps_reservoir_limit_set(arena, (size_t) 0); - - mps_reservoir_limit_set(arena, (size_t) (5ul*1024*1024)); - report("lim1", "%d", lim1 = mps_reservoir_limit(arena)); - report("avail1", "%d", avail1 = mps_reservoir_available(arena)); - report("commit1", "%d", commit1 = arena_committed_and_used(arena)); - report("deficit1", "%d", lim1-avail1); - - mps_reservoir_limit_set(arena, (size_t) (1045)); - report("lim2", "%d", lim2 = mps_reservoir_limit(arena)); - report("avail2", "%d", avail2 = mps_reservoir_available(arena)); - report("commit2", "%d", commit2 = arena_committed_and_used(arena)); - report("deficit2", "%d", lim2-avail2); - - /* set commit limit to whatever is currently committed plus 1 MB */ - - mps_arena_commit_limit_set(arena, arena_committed_and_used(arena)+1024*1024); - mps_reservoir_limit_set(arena, (size_t) (10ul*1024*1024)); - report("lim3", "%d", lim3 = mps_reservoir_limit(arena)); - report("avail3", "%d", avail3 = mps_reservoir_available(arena)); - report("commit3", "%d", commit3 = arena_committed_and_used(arena)); - report("deficit3", "%d", lim3-avail3); - report("spill3", "%d", commit3-mps_arena_commit_limit(arena)); - - /* now raise it by 1/2 MB -- reservoir should grow */ - - mps_arena_commit_limit_set(arena, arena_committed_and_used(arena)+512*1024); - report("lim4", "%d", lim4 = mps_reservoir_limit(arena)); - report("avail4", "%d", avail4 = mps_reservoir_available(arena)); - report("commit4", "%d", commit4 = arena_committed_and_used(arena)); - report("grow4", "%d", avail4-avail3); - report("spill4", "%d", commit4-mps_arena_commit_limit(arena)); - - /* try some allocation -- more than a small amount should fail */ - - i = -1; - p = NULL; - res = MPS_RES_OK; - while (res == MPS_RES_OK) { - res = allocrone(&q, apamc, 10, mps_rank_exact()); - if (res == MPS_RES_OK) { - setref(q, 0, p); - p = q; - } - i++; - } - report("allocfail", "%d", i); - report_res("failres", res); - - /* available shouldn't have changed since before allocation */ - - report("lim5", "%d", lim5 = mps_reservoir_limit(arena)); - report("avail5", "%d", avail5 = mps_reservoir_available(arena)); - report("commit5", "%d", commit5 = arena_committed_and_used(arena)); - report("grow5", "%d", avail5-avail4); - report("spill5", "%d", commit5-mps_arena_commit_limit(arena)); - - /* try some allocation from reservoir -- not much should fail */ - - i = -1; - res = MPS_RES_OK; - while (res == MPS_RES_OK) { - res = reservoir_allocrone(&q, apamc, 10, mps_rank_exact()); - if (res == MPS_RES_OK) { - setref(q, 0, p); - p = q; - } - i++; - } - report("allocfail2", "%d", i); - report_res("failres2", res); - - /* available should have changed now */ - - report("lim6", "%d", lim6 = mps_reservoir_limit(arena)); - report("avail6", "%d", avail6 = mps_reservoir_available(arena)); - report("commit6", "%d", commit6 = arena_committed_and_used(arena)); - report("spill6", "%d", commit6-mps_arena_commit_limit(arena)); - report("shrink6", "%d", avail5-avail6); - - mps_arena_park(arena); - mps_root_destroy(root); - mps_ap_destroy(apamc); - mps_pool_destroy(poolamc); - mps_chain_destroy(chain); - mps_fmt_destroy(format); - mps_thread_dereg(thread); - mps_arena_destroy(arena); - comment("Destroyed arena."); -} - - -int main(void) -{ - void *m; - stackpointer=&m; /* hack to get stack pointer */ - - easy_tramp(test); - report("completed", "yes"); - return 0; -} diff --git a/mps/test/function/133.c b/mps/test/function/133.c deleted file mode 100644 index 1f717b11660..00000000000 --- a/mps/test/function/133.c +++ /dev/null @@ -1,151 +0,0 @@ -/* -TEST_HEADER - id = $Id$ - summary = low-memory reservoir tests with commit limit, part II - language = c - link = testlib.o rankfmt.o -OUTPUT_SPEC - allocfail3 > 3000 - failres3 = COMMIT_LIMIT - spill8 <= 0 - spill9 <= 0 - grow9 > 1000000 -END_HEADER -*/ - -#include "testlib.h" -#include "mpscamc.h" -#include "mpsavm.h" -#include "rankfmt.h" - -#define ARENA_SIZE ((size_t) 1024*1024*30) - -#define genCOUNT (3) - -static mps_gen_param_s testChain[genCOUNT] = { - { 6000, 0.90 }, { 8000, 0.65 }, { 16000, 0.50 } }; - -void *stackpointer; - -mps_arena_t arena; -mps_pool_t poolamc; -mps_pool_t poolmv; -mps_thr_t thread; -mps_root_t root; - - mps_chain_t chain; -mps_fmt_t format; -mps_ap_t apamc; - -mps_root_t root; - -static void test(void) { - - mycell *p, *q; - int i; - mps_res_t res; - size_t lim7, avail7, commit7, lim8, avail8, commit8; - size_t lim9, avail9, commit9; - - cdie(mps_arena_create(&arena, mps_arena_class_vm(), ARENA_SIZE), - "create arena"); - - cdie(mps_thread_reg(&thread, arena), "register thread"); - - cdie(mps_root_create_reg(&root, arena, mps_rank_ambig(), 0, thread, - mps_stack_scan_ambig, stackpointer, 0), "create stack root"); - - cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); - - cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - - cdie( - mps_pool_create(&poolamc, arena, mps_class_amc(), format, chain), - "create pool"); - - cdie( - mps_ap_create(&apamc, poolamc, mps_rank_exact()), - "create ap"); - - mps_arena_commit_limit_set(arena, mps_arena_committed(arena)+1024*1024); - - mps_reservoir_limit_set(arena, 0); - report("lim7", "%d", lim7 = mps_reservoir_limit(arena)); - report("avail7", "%d", avail7 = mps_reservoir_available(arena)); - report("commit7", "%d", commit7 = mps_arena_committed(arena)); - -/* available should be zero, but should be able to allocate with - reservoir permit, until commit_limit is reached -*/ - - i = -1; - p = NULL; - res = MPS_RES_OK; - while (res == MPS_RES_OK) { - res = reservoir_allocrone(&q, apamc, 10, mps_rank_exact()); - if (res == MPS_RES_OK) { - setref(q, 0, p); - p = q; - } - i++; - } - report("allocfail3", "%d", i); - report_res("failres3", res); - -/* should be none left to make available */ - - mps_reservoir_limit_set(arena, 10ul*1024*1024); - report("lim8", "%d", lim8 = mps_reservoir_limit(arena)); - report("avail8", "%d", avail8 = mps_reservoir_available(arena)); - report("commit8", "%d", commit8 = mps_arena_committed(arena)); - report("spill8", "%d", commit8-mps_arena_commit_limit(arena)); - -/* throw away objects and collect world */ - - p = NULL; - q = NULL; - mps_root_destroy(root); - mps_arena_collect(arena); - -/* available should have gone up now */ - - report("lim9", "%d", lim9 = mps_reservoir_limit(arena)); - report("avail9", "%d", avail9 = mps_reservoir_available(arena)); - report("commit9", "%d", commit9 = mps_arena_committed(arena)); - report("grow9", "%d", avail9-avail8); - report("spill9", "%d", commit9-mps_arena_commit_limit(arena)); - -/* destroy everything remaining -*/ - - mps_arena_park(arena); - mps_ap_destroy(apamc); - comment("Destroyed ap."); - - mps_pool_destroy(poolamc); - comment("Destroyed pool."); - - mps_fmt_destroy(format); - comment("Destroyed format."); - - mps_chain_destroy(chain); - comment("Destroyed chain."); - - mps_thread_dereg(thread); - comment("Deregistered thread."); - - mps_arena_destroy(arena); - comment("Destroyed arena."); -} - -int main(void) -{ - void *m; - stackpointer=&m; /* hack to get stack pointer */ - - easy_tramp(test); - report("result", "pass"); - return 0; -} diff --git a/mps/test/function/149.c b/mps/test/function/149.c deleted file mode 100644 index a26f510ebdc..00000000000 --- a/mps/test/function/149.c +++ /dev/null @@ -1,199 +0,0 @@ -/* -TEST_HEADER - id = $Id$ - summary = SNC low-memory reservoir tests with commit limit - language = c - harness = 2.1 - link = testlib.o rankfmt.o -OUTPUT_SPEC - lim0 = 0 - avail0 = 0 - lim1 > 5000000 - lim1 < 6000000 - defecit1 = 0 - lim2 > 1045 - lim2 < 32768 - defecit2 = 0 - defecit3 > 8000000 - spill3 <= 0 - spill4 <= 0 - grow4 > 500000 - allocfail < 20 - failres = COMMIT_LIMIT - spill5 <= 0 - grow5 = 0 - avail5 > 1500000 - allocfail2 > 5000 - failres2 = COMMIT_LIMIT - shrink6 > 1000000 - spill6 <= 0 - completed = yes -END_HEADER -*/ - -#include "testlib.h" -#include "mpscsnc.h" -#include "mpsavm.h" -#include "rankfmt.h" - -#define ARENA_SIZE ((size_t) 1024*1024*30) - -void *stackpointer; - -mps_arena_t arena; -mps_pool_t poolsnc; -mps_pool_t poolmv; -mps_thr_t thread; -mps_root_t root; - -mps_fmt_t format; -mps_ap_t apsnc; - -mps_root_t root; - -static void test(void) { - - mycell *p, *q; - int i; - mps_res_t res; - size_t lim0, avail0, lim1, avail1, commit1, lim2, avail2, commit2; - size_t lim3, avail3, commit3, lim4, avail4, commit4; - size_t lim5, avail5, commit5, lim6, avail6, commit6; - - cdie(mps_arena_create(&arena, mps_arena_class_vm(), ARENA_SIZE), - "create arena"); - - cdie(mps_thread_reg(&thread, arena), "register thread"); - - cdie(mps_root_create_reg(&root, arena, mps_rank_ambig(), 0, thread, - mps_stack_scan_ambig, stackpointer, 0), "create stack root"); - - cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); - - cdie( - mps_pool_create(&poolsnc, arena, mps_class_snc(), format), - "create pool"); - - cdie( - mps_ap_create(&apsnc, poolsnc, mps_rank_exact()), - "create ap"); - - report("lim0", "%d", lim0 = mps_reservoir_limit(arena)); - report("avail0", "%d", avail0 = mps_reservoir_available(arena)); - mps_reservoir_limit_set(arena, (size_t) 0); - - mps_reservoir_limit_set(arena, (size_t) (5ul*1024*1024)); - report("lim1", "%d", lim1 = mps_reservoir_limit(arena)); - report("avail1", "%d", avail1 = mps_reservoir_available(arena)); - report("commit1", "%d", commit1 = arena_committed_and_used(arena)); - report("defecit1", "%d", lim1-avail1); - - mps_reservoir_limit_set(arena, (size_t) (1045)); - report("lim2", "%d", lim2 = mps_reservoir_limit(arena)); - report("avail2", "%d", avail2 = mps_reservoir_available(arena)); - report("commit2", "%d", commit2 = arena_committed_and_used(arena)); - report("defecit2", "%d", lim2-avail2); - -/* set commit limit to whatever is currently committed plus 1 MB -*/ - - die(mps_arena_commit_limit_set(arena, arena_committed_and_used(arena)+1024*1024), "commit limit set"); - mps_reservoir_limit_set(arena, (size_t) (10ul*1024*1024)); - report("lim3", "%d", lim3 = mps_reservoir_limit(arena)); - report("avail3", "%d", avail3 = mps_reservoir_available(arena)); - report("commit3", "%d", commit3 = arena_committed_and_used(arena)); - report("defecit3", "%d", lim3-avail3); - report("spill3", "%d", commit3-mps_arena_commit_limit(arena)); - -/* now raise it by 1/2 MB -- reservoir should grow -*/ - - die(mps_arena_commit_limit_set(arena, arena_committed_and_used(arena)+512*1024), "commit limit set"); - report("lim4", "%d", lim4 = mps_reservoir_limit(arena)); - report("avail4", "%d", avail4 = mps_reservoir_available(arena)); - report("commit4", "%d", commit4 = arena_committed_and_used(arena)); - report("grow4", "%d", avail4-avail3); - report("spill4", "%d", commit4-mps_arena_commit_limit(arena)); - -/* try some allocation -- more than a small amount should fail -*/ - - i = -1; - p = NULL; - res = MPS_RES_OK; - while (res == MPS_RES_OK) { - res = allocrone(&q, apsnc, 10, mps_rank_exact()); - if (res == MPS_RES_OK) { - setref(q, 0, p); - p = q; - } - i++; - } - report("allocfail", "%d", i); - report_res("failres", res); - -/* available shouldn't have changed since before allocation -*/ - - report("lim5", "%d", lim5 = mps_reservoir_limit(arena)); - report("avail5", "%d", avail5 = mps_reservoir_available(arena)); - report("commit5", "%d", commit5 = arena_committed_and_used(arena)); - report("grow5", "%d", avail5-avail4); - report("spill5", "%d", commit5-mps_arena_commit_limit(arena)); - -/* try some allocation from reservoir -- not much should fail -*/ - - i = -1; - res = MPS_RES_OK; - while (res == MPS_RES_OK) { - res = reservoir_allocrone(&q, apsnc, 10, mps_rank_exact()); - if (res == MPS_RES_OK) { - setref(q, 0, p); - p = q; - } - i++; - } - report("allocfail2", "%d", i); - report_res("failres2", res); - -/* available should have changed now -*/ - - report("lim6", "%d", lim6 = mps_reservoir_limit(arena)); - report("avail6", "%d", avail6 = mps_reservoir_available(arena)); - report("commit6", "%d", commit6 = arena_committed_and_used(arena)); - report("spill6", "%d", commit6-mps_arena_commit_limit(arena)); - report("shrink6", "%d", avail5-avail6); - - mps_arena_park(arena); - mps_root_destroy(root); - comment("Destroyed root."); - - mps_ap_destroy(apsnc); - comment("Destroyed ap."); - - mps_pool_destroy(poolsnc); - comment("Destroyed pool."); - - mps_fmt_destroy(format); - comment("Destroyed format."); - - mps_thread_dereg(thread); - comment("Deregistered thread."); - - mps_arena_destroy(arena); - comment("Destroyed arena."); -} - -int main(void) -{ - void *m; - stackpointer=&m; /* hack to get stack pointer */ - - easy_tramp(test); - report("completed", "yes"); - return 0; -} diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index eae2836a8ce..9a742ebfbc1 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -121,8 +121,7 @@ function/128.c function/129.c % function/130.c -- job003789 % function/131.c -- job003789 -% function/132.c -- job003869 -function/133.c +% 132-133 -- no such test function/134.c function/135.c function/136.c @@ -135,7 +134,7 @@ function/144.c % 145-146 -- no such test function/147.c % function/148.c -- failed on inc4: wanted = 1, was 0 @@@@ -function/149.c +% 149 -- no such test function/150.c function/151.c function/152.c From a4a3e1196a6874bd4e7d581e73a54b57b3951740 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 13 Mar 2016 22:51:36 +0000 Subject: [PATCH 255/337] Add links to job003985. Copied from Perforce Change: 190019 ServerID: perforce.ravenbrook.com --- mps/design/seg.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mps/design/seg.txt b/mps/design/seg.txt index c8cad89137b..19f88064ab7 100644 --- a/mps/design/seg.txt +++ b/mps/design/seg.txt @@ -243,7 +243,9 @@ and initializing ``segHi`` so that on exit ``seg`` is a segment with region ``[base,mid)`` and ``segHi`` is a segment with region ``[mid,limit)``. Usually a method would only directly modify the fields defined for the segment subclass. ``withReservoirPermit`` is -ignored (see job003985). +ignored (see job003985_). + +.. _job003985: http://www.ravenbrook.com/project/mps/issue/job003985/ _`.method.split.next`: A split method should always call the next method, either before or after any class-specific code (see @@ -261,7 +263,7 @@ destructively modifying ``seg`` and finishing ``segHi`` so that on exit ``seg`` is a segment with region ``[base,limit)`` and ``segHi`` is garbage. Usually a method would only modify the fields defined for the segment subclass. ``withReservoirPermit`` is ignored (see -job003985). +job003985_). _`.method.merge.next`: A merge method should always call the next method, either before or after any class-specific code (see From c8658073ea4f12d6cbb311f02447128db05c0403 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 14 Mar 2016 11:51:35 +0000 Subject: [PATCH 256/337] Don't run mmqa on every travis build: it has intermittent failures. Copied from Perforce Change: 190027 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/Makefile.in b/mps/Makefile.in index 32fd3406530..1a7ff142811 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -71,7 +71,7 @@ make-install-dirs: install: @INSTALL_TARGET@ test-make-build: - $(MAKE) $(TARGET_OPTS) testci testmmqa + $(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 testpollnone From e034e7aeea4c8f0c0bfc249d430de3eb814e12fd Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 14 Mar 2016 20:10:14 +0000 Subject: [PATCH 257/337] Address points made by rb in review Copied from Perforce Change: 190031 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 19 ++++++++++--------- mps/code/eventdef.h | 2 +- mps/code/global.c | 4 ++-- mps/code/mpm.h | 4 ++-- mps/code/mpmst.h | 2 +- mps/code/policy.c | 3 +++ mps/code/trace.c | 33 ++++++++++++++++++--------------- mps/code/traceanc.c | 2 +- mps/design/type.txt | 6 ++++-- 9 files changed, 42 insertions(+), 33 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 17634daecbd..dc7ae37b15c 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -1320,15 +1320,6 @@ Size ArenaAvail(Arena arena) /* ArenaCollectable -- return estimate of collectable memory in arena */ Size ArenaCollectable(Arena arena) -{ - /* Conservative estimate -- see job003929. */ - return ArenaScannable(arena); -} - - -/* ArenaScannable -- return estimate of scannable memory in arena */ - -Size ArenaScannable(Arena arena) { /* Conservative estimate -- see job003929. */ Size committed = ArenaCommitted(arena); @@ -1338,6 +1329,16 @@ Size ArenaScannable(Arena arena) } +/* ArenaAccumulateTime -- accumulate time spent tracing */ + +void ArenaAccumulateTime(Arena arena, Clock start, Clock end) +{ + AVERT(Arena, arena); + AVER(start <= end); + arena->tracedTime += (end - start) / (double) ClocksPerSec(); +} + + /* ArenaExtend -- Add a new chunk in the arena */ Res ArenaExtend(Arena arena, Addr base, Size size) diff --git a/mps/code/eventdef.h b/mps/code/eventdef.h index cb7b590274c..312f257ee0f 100644 --- a/mps/code/eventdef.h +++ b/mps/code/eventdef.h @@ -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, quantumWork) /* work constituting a quantum */ + PARAM(X, 7, W, quantumWork) /* tracing work to be done in each poll */ #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 fae5b0bb2dd..39e83714f82 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -739,7 +739,7 @@ void (ArenaPoll)(Globals globals) /* Don't count time spent checking for work, if there was no work to do. */ if (workWasDone) { - ArenaAccumulateTime(arena, start); + ArenaAccumulateTime(arena, start, ClockNow()); } AVER(!PolicyPoll(arena)); @@ -801,7 +801,7 @@ Bool ArenaStep(Globals globals, double interval, double multiplier) } while (now < intervalEnd); if (workWasDone) { - ArenaAccumulateTime(arena, start); + ArenaAccumulateTime(arena, start, now); } return workWasDone; diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 2cd17c27135..6cbc676ab00 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -397,6 +397,7 @@ extern Res TraceCreate(Trace *traceReturn, Arena arena, int why); extern void TraceDestroyInit(Trace trace); extern void TraceDestroyFinished(Trace trace); +extern Bool TraceIsEmpty(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); @@ -537,7 +538,6 @@ 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); @@ -572,6 +572,7 @@ 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 ArenaAccumulateTime(Arena arena, Clock start, Clock now); extern void ArenaSetEmergency(Arena arena, Bool emergency); extern Bool ArenaEmergency(Arena arean); @@ -628,7 +629,6 @@ extern Res ArenaNoGrow(Arena arena, LocusPref pref, Size size); extern Size ArenaAvail(Arena arena); extern Size ArenaCollectable(Arena arena); -extern Size ArenaScannable(Arena arena); extern Res ArenaExtend(Arena, Addr base, Size size); diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index b7267e2cba3..4e848f5da57 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 */ - Work quantumWork; /* collection work constituting a quantum */ + Work quantumWork; /* tracing work to be done in each poll */ 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 */ diff --git a/mps/code/policy.c b/mps/code/policy.c index 82709f7376f..a9bc710be1b 100644 --- a/mps/code/policy.c +++ b/mps/code/policy.c @@ -325,6 +325,8 @@ Bool PolicyStartTrace(Trace *traceReturn, Arena arena) res = policyCondemnChain(&mortality, firstChain, trace); if (res != ResOK) /* should try some other trace, really @@@@ */ goto failCondemn; + if (TraceIsEmpty(trace)) + goto nothingCondemned; trace->chain = firstChain; ChainStartGC(firstChain, trace); res = TraceStart(trace, mortality, trace->condemned * TraceWorkFactor); @@ -336,6 +338,7 @@ Bool PolicyStartTrace(Trace *traceReturn, Arena arena) } /* (dynamicDeferral > 0.0) */ return FALSE; +nothingCondemned: failCondemn: TraceDestroyInit(trace); failStart: diff --git a/mps/code/trace.c b/mps/code/trace.c index 6973d8ce63d..6d9cb0f0f98 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -339,6 +339,15 @@ static ZoneSet traceSetWhiteUnion(TraceSet ts, Arena arena) } +/* TraceIsEmpty -- return TRUE if trace has no condemned segments */ + +Bool TraceIsEmpty(Trace trace) +{ + AVERT(Trace, trace); + return trace->condemned == 0; +} + + /* TraceAddWhite -- add a segment to the white set of a trace */ Res TraceAddWhite(Trace trace, Seg seg) @@ -391,7 +400,6 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet) Seg seg; Arena arena; Res res; - Bool haveWhiteSegs = FALSE; AVERT(Trace, trace); AVER(condemnedSet != ZoneSetEMPTY); @@ -418,14 +426,10 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet) res = TraceAddWhite(trace, seg); if(res != ResOK) goto failBegin; - haveWhiteSegs = TRUE; } } 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 */ @@ -434,7 +438,7 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet) return ResOK; failBegin: - AVER(!haveWhiteSegs); /* See .whiten.fail. */ + AVER(TraceIsEmpty(trace)); /* See .whiten.fail. */ return res; } @@ -697,7 +701,7 @@ 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->quantumWork = (Work)0; /* no work done yet */ + trace->quantumWork = (Work)0; /* computed in TraceStart */ STATISTIC(trace->greySegCount = (Count)0); STATISTIC(trace->greySegMax = (Count)0); STATISTIC(trace->rootScanCount = (Count)0); @@ -1482,7 +1486,6 @@ static Res traceCondemnAll(Trace trace) Res res; Arena arena; Ring poolNode, nextPoolNode, chainNode, nextChainNode; - Bool haveWhiteSegs = FALSE; arena = trace->arena; AVERT(Arena, arena); @@ -1501,12 +1504,11 @@ static Res traceCondemnAll(Trace trace) res = TraceAddWhite(trace, seg); if (res != ResOK) goto failBegin; - haveWhiteSegs = TRUE; } } } - if (!haveWhiteSegs) + if (TraceIsEmpty(trace)) return ResFAIL; /* Notify all the chains. */ @@ -1525,7 +1527,7 @@ static Res traceCondemnAll(Trace trace) * pool class that fails to whiten a segment, then this assertion * will be triggered. In that case, we'll have to recover here by * blackening the segments again. */ - AVER(!haveWhiteSegs); + AVER(TraceIsEmpty(trace)); return res; } @@ -1645,8 +1647,8 @@ 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; - /* One quantum of work equals scanning work divided by number of - * polls, plus one to ensure it's not zero. */ + /* One quantum of work equals total tracing work divided by number + * of polls, plus one to ensure it's not zero. */ trace->quantumWork = (trace->foundation + sSurvivors) / (unsigned long)nPolls + 1; } @@ -1671,9 +1673,10 @@ Res TraceStart(Trace trace, double mortality, double finishingTime) } -/* traceWork -- a measure of the work done for this trace +/* traceWork -- a measure of the work done for this trace. * - * .work: Segment and root scanning work is the measure. */ + * See design.mps.type.work. + */ #define traceWork(trace) ((Work)((trace)->segScanSize + (trace)->rootScanSize)) diff --git a/mps/code/traceanc.c b/mps/code/traceanc.c index e60f8ffcdb3..4730c7a0f54 100644 --- a/mps/code/traceanc.c +++ b/mps/code/traceanc.c @@ -590,7 +590,7 @@ void ArenaPark(Globals globals) TRACE_SET_ITER_END(ti, trace, arena->busyTraces, arena); } - ArenaAccumulateTime(arena, start); + ArenaAccumulateTime(arena, start, ClockNow()); /* All traces have finished so there must not be an emergency. */ AVER(!ArenaEmergency(arena)); diff --git a/mps/design/type.txt b/mps/design/type.txt index dc3c3b8cf99..5f546e1e32e 100644 --- a/mps/design/type.txt +++ b/mps/design/type.txt @@ -669,8 +669,10 @@ _`.word.ops`: ``WordIsAligned()``, ``WordAlignUp()``, _`.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. +_`.work.impl`: Work is implemented as a count of the bytes scanned by +the collector in segments and roots. This is a very crude measure, +because it depends on the scanning functions supplied by the mutator, +which we know very little about. ``typedef Word ZoneSet`` From 03d43d8889388cc2e83ff3f6d3d3dcff94f9d0f2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 14 Mar 2016 23:03:27 +0000 Subject: [PATCH 258/337] Documentation and release notes for new platforms fri3ll and fri6ll. Release notes for job003898, job003934, and job003938. Copied from Perforce Change: 190036 ServerID: perforce.ravenbrook.com --- mps/manual/build.txt | 8 +++++--- mps/manual/source/release.rst | 23 +++++++++++++++++++++++ mps/manual/source/topic/platform.rst | 16 ++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/mps/manual/build.txt b/mps/manual/build.txt index 7b8e17c51b9..b462f013ea9 100644 --- a/mps/manual/build.txt +++ b/mps/manual/build.txt @@ -137,6 +137,8 @@ Platform OS Architecture Compiler Makefile ========== ========= ============= ============ ================= ``fri3gc`` FreeBSD IA-32 GCC ``fri3gc.gmk`` ``fri6gc`` FreeBSD x86_64 GCC ``fri6gc.gmk`` +``fri3ll`` FreeBSD IA-32 Clang ``fri3ll.gmk`` +``fri6ll`` FreeBSD x86_64 Clang ``fri6ll.gmk`` ``lii3gc`` Linux IA-32 GCC ``lii3gc.gmk`` ``lii6gc`` Linux x86_64 GCC ``lii6gc.gmk`` ``lii6ll`` Linux x86_64 Clang ``lii6ll.gmk`` @@ -175,9 +177,9 @@ To build a restricted set of targets for just one variety, run:: make -f 'VARIETY=' For example, to build just the "cool" variety of the ``amcss`` test on -FreeBSD:: +64-bit Linux with Clang:: - gmake -f fri3gc.gmk VARIETY=cool amcss + gmake -f lii6ll.gmk VARIETY=cool amcss On Windows platforms you need to run the "Visual Studio Command Prompt" from the Start menu. Then run one of these commands:: @@ -199,7 +201,7 @@ On Mac OS X, you can build from the command line with:: xcodebuild On most platforms, the output of the build goes to a directory named -after the platform (e.g. ``fri3gc``) so that you can share the source +after the platform (e.g. ``lii6ll``) so that you can share the source tree across platforms. On Mac OS X the output goes in a directory called ``xc``. Building generates ``mps.a`` or ``mps.lib`` or equivalent, a library of object code which you can link with your diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index f95aaba331e..21e426f13cc 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -12,6 +12,9 @@ Release 1.115.0 New features ............ +#. New supported platforms ``fri3ll`` (FreeBSD, IA-32, Clang/LLVM) + and ``fri6ll`` (FreeBSD, x86-64, Clang/LLVM). + #. 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 @@ -105,6 +108,26 @@ Other changes .. _job003866: https://www.ravenbrook.com/project/mps/issue/job003866/ +#. The MPS can now make use of :term:`spare committed memory` even if + it is :term:`mapped` at an unhelpful address, by unmapping it and + remapping at a better address. See job003898_. + + .. _job003898: https://www.ravenbrook.com/project/mps/issue/job003898/ + +#. :c:func:`mps_arena_step` now always considers starting a new + :term:`garbage collection` if the remaining idle time is long + enough to complete it. (Previously, if there was already a + collection in progress when :c:func:`mps_arena_step` was called, it + would finish the collection but not consider starting a new one.) + See job003934_. + + .. _job003934: https://www.ravenbrook.com/project/mps/issue/job003934/ + +#. The MPS no longer carries out :term:`garbage collections` when there + is no collection work to be done. See job003938_. + + .. _job003938: https://www.ravenbrook.com/project/mps/issue/job003938/ + .. _release-notes-1.114: diff --git a/mps/manual/source/topic/platform.rst b/mps/manual/source/topic/platform.rst index e74aa34cde2..15873d27af4 100644 --- a/mps/manual/source/topic/platform.rst +++ b/mps/manual/source/topic/platform.rst @@ -149,6 +149,20 @@ Platform interface x86-64 processor architecture, and the GCC compiler. +.. c:macro:: MPS_PF_FRI3GC + + A :term:`C` preprocessor macro that indicates, if defined, that + the :term:`platform` consists of the FreeBSD operating system, the + IA-32 processor architecture, and the Clang/LLVM compiler. + + +.. c:macro:: MPS_PF_FRI6GC + + A :term:`C` preprocessor macro that indicates, if defined, that + the :term:`platform` consists of the FreeBSD operating system, the + x86-64 processor architecture, and the Clang/LLVM compiler. + + .. c:macro:: MPS_PF_LII3GC A :term:`C` preprocessor macro that indicates, if defined, that @@ -328,8 +342,10 @@ the Memory Pool System, with their current status. Platform Status ========== ======================= ``fri3gc`` Supported +``fri3ll`` Supported ``fri4gc`` Corrected to ``fri3gc`` ``fri6gc`` Supported +``fri6ll`` Supported ``i5m2cc`` *Not supported* ``iam4cc`` *Not supported* ``lii3eg`` *Not supported* From f9e7db4a87a9f521e9e4c78ac2d330d4d2a15e88 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 15 Mar 2016 04:54:19 +0000 Subject: [PATCH 259/337] Removing reservoir-related events. Copied from Perforce Change: 190041 ServerID: perforce.ravenbrook.com --- mps/code/eventdef.h | 6 +----- mps/code/eventrep.c | 5 ----- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/mps/code/eventdef.h b/mps/code/eventdef.h index 9ef997213ee..0586d432680 100644 --- a/mps/code/eventdef.h +++ b/mps/code/eventdef.h @@ -160,7 +160,7 @@ /* PoolPush/Pop go under Object, because they're user ops. */ \ /* EVENT(X, PoolPush , 0x0060, TRUE, Object) */ \ /* EVENT(X, PoolPop , 0x0061, TRUE, Object) */ \ - EVENT(X, ReservoirLimitSet , 0x0062, TRUE, Arena) \ + /* EVENT(X, ReservoirLimitSet , 0x0062, TRUE, Arena) */ \ EVENT(X, CommitLimitSet , 0x0063, TRUE, Arena) \ EVENT(X, SpareCommitLimitSet, 0x0064, TRUE, Arena) \ EVENT(X, ArenaAlloc , 0x0065, TRUE, Arena) \ @@ -551,10 +551,6 @@ PARAM(X, 2, B, isMutator) \ PARAM(X, 3, U, rank) -#define EVENT_ReservoirLimitSet_PARAMS(PARAM, X) \ - PARAM(X, 0, P, arena) \ - PARAM(X, 1, W, size) - #define EVENT_CommitLimitSet_PARAMS(PARAM, X) \ PARAM(X, 0, P, arena) \ PARAM(X, 1, W, limit) \ diff --git a/mps/code/eventrep.c b/mps/code/eventrep.c index e7f303ca47d..6098e52c5bb 100644 --- a/mps/code/eventrep.c +++ b/mps/code/eventrep.c @@ -560,11 +560,6 @@ void EventReplay(Event event, Word etime) (void)mps_arena_spare_commit_limit_set((mps_arena_t)entry, (size_t)event->pw.w1); } break; - case EventReservoirLimitSet: { /* arena, limit */ - found = TableLookup(&entry, arenaTable, (TableKey)event->pw.p0); - verify(found); - mps_reservoir_limit_set((mps_arena_t)entry, (size_t)event->pw.w1); - } break; case EventVMMap: case EventVMUnmap: case EventVMInit: case EventVMFinish: case EventArenaWriteFaults: From a830a7852f05f2a792223455817838fb883c360e Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 15 Mar 2016 05:04:03 +0000 Subject: [PATCH 260/337] Removing more references to the reservoir from documentation. Copied from Perforce Change: 190042 ServerID: perforce.ravenbrook.com --- mps/design/buffer.txt | 4 ++-- mps/design/poolamc.txt | 2 +- mps/design/seg.txt | 4 ++-- mps/design/type.txt | 2 +- mps/manual/source/extensions/mps/designs.py | 2 +- mps/manual/source/topic/cache.rst | 6 ++---- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/mps/design/buffer.txt b/mps/design/buffer.txt index ae55fa34204..04b8779e2ca 100644 --- a/mps/design/buffer.txt +++ b/mps/design/buffer.txt @@ -623,7 +623,7 @@ design.mps.thread-safety_). Returns the pool to which a buffer is attached. -``Res BufferReserve(Addr *pReturn, Buffer buffer, Size size, Bool withReservoirPermit)`` +``Res BufferReserve(Addr *pReturn, Buffer buffer, Size size)`` _`.method.reserve`: Reserves memory from an allocation buffer. @@ -638,7 +638,7 @@ pool to which the buffer belongs) and then passed to the applied twice to a buffer without a ``BufferCommit()`` in-between. In other words, Reserve/Commit pairs do not nest. -``Res BufferFill(Addr *pReturn, Buffer buffer, Size size, Bool withReservoirPermit)`` +``Res BufferFill(Addr *pReturn, Buffer buffer, Size size)`` _`.method.fill`: Refills an empty buffer. If there is not enough space in a buffer to allocate in-line, ``BufferFill()`` must be called to diff --git a/mps/design/poolamc.txt b/mps/design/poolamc.txt index fca51e38da8..f00bc4adbae 100644 --- a/mps/design/poolamc.txt +++ b/mps/design/poolamc.txt @@ -729,7 +729,7 @@ _`.flush.cover`: The buffer needs covering whether it was being used for forwarding or not. See `.flush.expose`_. -``Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn, Pool pool, Buffer buffer, Size size, Bool withReservoirPermit)`` +``Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn, Pool pool, Buffer buffer, Size size)`` _`.fill`: Reserve was called on an allocation buffer which was reset, or there wasn't enough room left in the buffer. Allocate a group for diff --git a/mps/design/seg.txt b/mps/design/seg.txt index 19f88064ab7..fc91d54e6b5 100644 --- a/mps/design/seg.txt +++ b/mps/design/seg.txt @@ -161,7 +161,7 @@ _`.split-and-merge`: There is support for splitting and merging segments, to give pools the flexibility to rearrange their tracts among segments as they see fit. -``Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at, Bool withReservoirPermit, ...)`` +``Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at)`` _`.split`: If successful, segment ``seg`` is split at address ``at``, yielding two segments which are returned in segLoReturn and @@ -190,7 +190,7 @@ _`.split.state`: Except as noted above, the segments returned have the same properties as ``seg``. That is, their colour, summary, rankset, nailedness etc. are set to the values of ``seg``. -``Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi, Bool withReservoirPermit, ...)`` +``Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi)`` _`.merge`: If successful, segments ``segLo`` and ``segHi`` are merged together, yielding a segment which is returned in mergedSegReturn. diff --git a/mps/design/type.txt b/mps/design/type.txt index 25943f41a4b..5912fa93223 100644 --- a/mps/design/type.txt +++ b/mps/design/type.txt @@ -681,7 +681,7 @@ pointers to structures. For example, ``Ring`` is a pointer to a ``Buffer``, ``Chain``, ``Chunk``, ``Format``, ``Globals``, ``Land``, ``LD``, ``Lock``, ``LocusPref``, ``MutatorFaultContext``, ``PoolClass``, ``Page``, ``Pool``, ``PoolDebugMixin``, ``Range``, -``Reservoir``, ``Ring``, ``Root``, ``ScanState``, ``Seg``, ``SegBuf``, +``Ring``, ``Root``, ``ScanState``, ``Seg``, ``SegBuf``, ``StackContext``, ``Thread``, ``Trace``, ``VM``. ``typedef void *Pointer`` diff --git a/mps/manual/source/extensions/mps/designs.py b/mps/manual/source/extensions/mps/designs.py index ff991612fc5..aad0326c553 100644 --- a/mps/manual/source/extensions/mps/designs.py +++ b/mps/manual/source/extensions/mps/designs.py @@ -24,7 +24,7 @@ Fun GenDesc Globals Index Land LD Lock LocusPref LocusPrefKind Message MessageType MutatorFaultContext Page Pointer Pool PoolGen PThreadext Range Rank RankSet ReadonlyAddr Ref RefSet Res - Reservoir Ring Root RootMode RootVar ScanState Seg SegBuf Serial + Ring Root RootMode RootVar ScanState Seg SegBuf Serial Shift Sig Size Space SplayNode SplayTree StackContext Thread Trace TraceId TraceSet TraceStartWhy TraceState ULongest VM Word ZoneSet diff --git a/mps/manual/source/topic/cache.rst b/mps/manual/source/topic/cache.rst index f95b0a7a164..d4446d7a97b 100644 --- a/mps/manual/source/topic/cache.rst +++ b/mps/manual/source/topic/cache.rst @@ -269,7 +269,7 @@ Allocation interface have to be one of the :term:`size classes` of the cache; nor does it have to be aligned. - ``has_reservoir_permit`` should be false. + ``has_reservoir_permit`` is obsolete. Pass false. Returns :c:macro:`MPS_RES_OK` if successful: in this case the address of the allocated block is ``*p_o``. The allocated block @@ -320,9 +320,7 @@ Allocation interface .. note:: :c:func:`MPS_SAC_ALLOC_FAST` may evaluate its arguments - multiple times, except for ``has_reservoir_permit``, which it - evaluates at most once, and only if it decides to access the - pool. + multiple times. .. c:function:: void mps_sac_free(mps_sac_t sac, mps_addr_t p, size_t size) From effbe427e2c17aaf19b4e79434d9b49930e38eaf Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 15 Mar 2016 05:04:38 +0000 Subject: [PATCH 261/337] Removing obsolete comment about the reservoir. Copied from Perforce Change: 190043 ServerID: perforce.ravenbrook.com --- mps/code/mpsi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 8e73a908395..5bebe0a55b0 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -740,8 +740,6 @@ mps_res_t mps_alloc(mps_addr_t *p_o, mps_pool_t pool, size_t size) /* . */ /* Rest ignored, see .varargs. */ - /* @@@@ There is currently no requirement for reservoirs to work */ - /* with unbuffered allocation. */ res = PoolAlloc(&p, pool, size); ArenaLeave(arena); From 980649475e0d4c9b5e8bb36880b82f20caf80f11 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 15 Mar 2016 05:18:53 +0000 Subject: [PATCH 262/337] Removing references to the reservoir from segment design. Copied from Perforce Change: 190044 ServerID: perforce.ravenbrook.com --- mps/design/seg.txt | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/mps/design/seg.txt b/mps/design/seg.txt index fc91d54e6b5..1a25926ffd5 100644 --- a/mps/design/seg.txt +++ b/mps/design/seg.txt @@ -232,7 +232,7 @@ Extensibility Splitting and merging ..................... -``typedef Res (*SegSplitMethod)(Seg seg, Seg segHi, Addr base, Addr mid, Addr limit, Bool withReservoirPermit)`` +``typedef Res (*SegSplitMethod)(Seg seg, Seg segHi, Addr base, Addr mid, Addr limit)`` _`.method.split`: Segment subclasses may extend the support for segment splitting by defining their own "split" method. On entry, @@ -242,10 +242,7 @@ split. The method is responsible for destructively modifying ``seg`` and initializing ``segHi`` so that on exit ``seg`` is a segment with region ``[base,mid)`` and ``segHi`` is a segment with region ``[mid,limit)``. Usually a method would only directly modify the -fields defined for the segment subclass. ``withReservoirPermit`` is -ignored (see job003985_). - -.. _job003985: http://www.ravenbrook.com/project/mps/issue/job003985/ +fields defined for the segment subclass. _`.method.split.next`: A split method should always call the next method, either before or after any class-specific code (see @@ -253,7 +250,7 @@ design.mps.protocol.overview.next-method_). .. _design.mps.protocol.overview.next-method: protocol#overview.next-method -``typedef Res (*SegMergeMethod)(Seg seg, Seg segHi, Addr base, Addr mid, Addr limit, Bool withReservoirPermit)`` +``typedef Res (*SegMergeMethod)(Seg seg, Seg segHi, Addr base, Addr mid, Addr limit)`` _`.method.merge`: Segment subclasses may extend the support for segment merging by defining their own ``merge`` method. On entry, @@ -262,8 +259,7 @@ segment with region ``[mid,limit)``, The method is responsible for destructively modifying ``seg`` and finishing ``segHi`` so that on exit ``seg`` is a segment with region ``[base,limit)`` and ``segHi`` is garbage. Usually a method would only modify the fields defined for -the segment subclass. ``withReservoirPermit`` is ignored (see -job003985_). +the segment subclass. _`.method.merge.next`: A merge method should always call the next method, either before or after any class-specific code (see From 88a8485224ce27bcc2a80f4a48d2b8e2c5a6b710 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 15 Mar 2016 05:59:11 +0000 Subject: [PATCH 263/337] Improving recommendations for arena pause time. Copied from Perforce Change: 190046 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/arena.rst | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index 44e14c801c4..2d6b99ca0db 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -454,12 +454,24 @@ Arena properties ``pause_time`` is the new maximum pause time, in seconds. It must be non-negative. + The MPS makes more efficient use of processor time when it is + allowed longer pauses, up to the maximum time it takes to collect + the entire arena (see :c:func:`mps_arena_collect`). + + When the pause time is short, the MPS needs to take more slices of + time in order to make :term:`garbage collection` progress, and + make more use of :term:`barriers (1)` to support + :term:`incremental collection`. This increases time overheads, + and especially operating system overheads. + The pause time may be set to zero, in which case the MPS returns - as soon as it can do so. The consequence is that the MPS will need - to take more slices of time in order to make :term:`garbage - collection` progress. This value is suitable for interactive - applications where latency needs to be minimized, but where there - is plenty of CPU time available. + as soon as it can, without regard for overall efficiency. This + value is suitable for applications that require high + responsiveness, but where overall run time is unimportant. + + For interactive applications, set this to the maximum pause that a + human being might notice. The default setting of 100ms is + intended for this. The pause time may be set to infinity, in which case the MPS completes all outstanding :term:`garbage collection` work before @@ -486,6 +498,8 @@ Arena properties real-time guarantees (for example, the process may have to wait for :term:`memory (2)` to be :term:`paged in`). + In other words, the MPS is a “soft” real-time system. + .. c:function:: size_t mps_arena_reserved(mps_arena_t arena) From 069dbc4e97a162d080469d3b2fa5b1d17cb21c6c Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 15 Mar 2016 06:04:42 +0000 Subject: [PATCH 264/337] Justifying the default pause time. Copied from Perforce Change: 190049 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mps/code/config.h b/mps/code/config.h index adee968a8f6..734ab21a876 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -412,7 +412,9 @@ #define ARENA_DEFAULT_SPARE_COMMIT_LIMIT ((Size)10uL*1024uL*1024uL) /* ARENA_DEFAULT_PAUSE_TIME is the maximum time (in seconds) that - * operations within the arena may pause the mutator for. */ + * operations within the arena may pause the mutator for. The default + * is set for typical human interaction. See mps_arena_pause_time_set + * in the manual. */ #define ARENA_DEFAULT_PAUSE_TIME (0.1) From 78aa13019dc856f45d1efbe89ba12491fc4e31de Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 15 Mar 2016 06:25:53 +0000 Subject: [PATCH 265/337] Don't return to the mutator if there's an emergency. Clarifying "more time" and what we do if there's isn't. Copied from Perforce Change: 190050 ServerID: perforce.ravenbrook.com --- mps/code/policy.c | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/mps/code/policy.c b/mps/code/policy.c index d0d0a72dfde..b82954bbbe4 100644 --- a/mps/code/policy.c +++ b/mps/code/policy.c @@ -369,31 +369,38 @@ Bool PolicyPoll(Arena arena) Bool PolicyPollAgain(Arena arena, Clock start, Bool moreWork, Work tracedWork) { + Bool moreTime; + Globals globals; + double nextPollThreshold; + AVERT(Arena, arena); UNUSED(tracedWork); - /* Is there more work to do and more time to do it in? */ - if ((moreWork || ArenaEmergency(arena)) - && (ClockNow() - start) < ArenaPauseTime(arena) * ClocksPerSec()) - { + if (ArenaEmergency(arena)) return TRUE; + + /* Is there more work to do and more time to do it in? */ + moreTime = (ClockNow() - start) < ArenaPauseTime(arena) * ClocksPerSec(); + if (moreWork && moreTime) + return TRUE; + + /* We're not going to do more work now, so calculate when to come back. */ + + globals = ArenaGlobals(arena); + + if (moreWork) { + /* We did one quantum of work; consume one unit of 'time'. */ + nextPollThreshold = globals->pollThreshold + ArenaPollALLOCTIME; } else { - Globals globals = ArenaGlobals(arena); - double nextPollThreshold; - - if (moreWork) { - /* We did one quantum of work; consume one unit of 'time'. */ - nextPollThreshold = globals->pollThreshold + ArenaPollALLOCTIME; - } else { - /* No more work to do. Sleep until NOW + a bit. */ - nextPollThreshold = globals->fillMutatorSize + ArenaPollALLOCTIME; - } - - /* Advance pollThreshold; check: enough precision? */ - AVER(nextPollThreshold > globals->pollThreshold); - globals->pollThreshold = nextPollThreshold; - return FALSE; + /* No more work to do. Sleep until NOW + a bit. */ + nextPollThreshold = globals->fillMutatorSize + ArenaPollALLOCTIME; } + + /* Advance pollThreshold; check: enough precision? */ + AVER(nextPollThreshold > globals->pollThreshold); + globals->pollThreshold = nextPollThreshold; + + return FALSE; } From 684126cebf34c599179be094b72bbbf4904a71d8 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 15 Mar 2016 13:02:40 +0000 Subject: [PATCH 266/337] Updates from review by dl . Copied from Perforce Change: 190105 ServerID: perforce.ravenbrook.com --- mps/code/eventdef.h | 2 +- mps/code/mps.h | 2 ++ mps/code/mpsi.c | 2 +- mps/manual/source/topic/telemetry.rst | 16 ++++++++-------- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/mps/code/eventdef.h b/mps/code/eventdef.h index 0586d432680..5219bd2296a 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) diff --git a/mps/code/mps.h b/mps/code/mps.h index ccb1173fb42..644868d6238 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -527,6 +527,8 @@ extern mps_res_t (mps_reserve)(mps_addr_t *, mps_ap_t, size_t); extern mps_bool_t (mps_commit)(mps_ap_t, mps_addr_t, size_t); extern mps_res_t mps_ap_fill(mps_addr_t *, mps_ap_t, size_t); + +/* mps_ap_fill_with_reservoir_permit is deprecated */ extern mps_res_t mps_ap_fill_with_reservoir_permit(mps_addr_t *, mps_ap_t, size_t); diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 5bebe0a55b0..a8a47447cbb 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1156,7 +1156,7 @@ mps_res_t mps_sac_fill(mps_addr_t *p_o, mps_sac_t mps_sac, size_t size, AVER(p_o != NULL); AVER(TESTT(SAC, sac)); arena = SACArena(sac); - UNUSED(has_reservoir_permit); /* FIXME */ + UNUSED(has_reservoir_permit); /* deprecated */ ArenaEnter(arena); diff --git a/mps/manual/source/topic/telemetry.rst b/mps/manual/source/topic/telemetry.rst index 0f107985c20..2c9136ce7da 100644 --- a/mps/manual/source/topic/telemetry.rst +++ b/mps/manual/source/topic/telemetry.rst @@ -306,14 +306,14 @@ takes the following options: For example, here's the result of passing the output shown above through :program:`mpseventtxt`:: - 000AE03973336E3C 002B VMCreate vm:00000001003FC000 base:00000001003FD000 limit:00000001003FE000 - 000AE0397333BC6D 002D VMMap vm:00000001003FC000 base:00000001003FD000 limit:00000001003FE000 - 000AE0397334DF9F 001A Intern stringId:0000000000000002 string:"Reservoir" - 000AE0397334E0A0 001B Label address:00000001078C85B8["Reservoir"] stringId:0000000000000002 - 000AE03973352375 0015 PoolInit pool:00000001003FD328 arena:00000001003FD000 poolClass:00000001078C85B8["Reservoir"] - 000AE039733592F9 002B VMCreate vm:00000001003FE000 base:00000001003FF000 limit:000000010992F000 - 000AE0397335C8B5 002D VMMap vm:00000001003FE000 base:00000001003FF000 limit:0000000107930000 - 000AE03973361D5A 0005 ArenaCreateVM arena:00000001003FD000 userSize:0000000002000000 chunkSize:0000000002000000 + 000021C9DB3812C7 0075 EventClockSync clock:0000000000001EE3 + 000021C9DB39E2FB 002B VMInit vm:00007FFF5429C4B8 base:000000010BA4A000 limit:000000010BA4B000 + 000021C9DB3A5630 002D VMMap vm:00007FFF5429C4B8 base:000000010BA4A000 limit:000000010BA4B000 + 000021C9DB3E6BAA 001A Intern stringId:0000000000000002 string:"MFS" + 000021C9DB3E6E17 001B Label address:000000010BA0C5D8["MFS"] stringId:0000000000000002 + 000021C9DB3EB6F8 0044 PoolInitMFS pool:000000010BA4A360 arena:000000010BA4A000 extendBy:0000000000001000 extendSelf:False unitSize:0000000000000030 + 000021C9DB3EFE3B 002B VMInit vm:00007FFF5429C3D0 base:000000010BC84000 limit:000000010CC24000 + 000021C9DB3F33F3 002D VMMap vm:00007FFF5429C3D0 base:000000010BC84000 limit:000000010BC85000 .. index:: From 662a1b1b9bb8ac726407881af6325a772cdaaaa7 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 17 Mar 2016 13:37:40 +0000 Subject: [PATCH 267/337] Allocate the shield cache. also improve commentary quite a bit. Copied from Perforce Change: 190147 ServerID: perforce.ravenbrook.com --- mps/code/global.c | 22 ++++++-- mps/code/mpmst.h | 3 +- mps/code/shield.c | 138 +++++++++++++++++++++++++++++----------------- 3 files changed, 107 insertions(+), 56 deletions(-) diff --git a/mps/code/global.c b/mps/code/global.c index 354adb54a9a..aa9847451a0 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -156,8 +156,9 @@ Bool GlobalsCheck(Globals arenaGlobals) CHECKD_NOSIG(Ring, &arena->deadRing); CHECKL(BoolCheck(arena->insideShield)); - CHECKL(arena->shCacheLimit <= ShieldCacheSIZE); - CHECKL(arena->shCacheI < arena->shCacheLimit); + CHECKL(arena->shCache == NULL || arena->shCacheLength > 0); + CHECKL(arena->shCacheLimit <= arena->shCacheLength); + CHECKL(arena->shCacheI <= arena->shCacheLimit); CHECKL(BoolCheck(arena->suspended)); depth = 0; @@ -293,12 +294,12 @@ Res GlobalsInit(Globals arenaGlobals) arena->tracedTime = 0.0; arena->lastWorldCollect = ClockNow(); arena->insideShield = FALSE; /* */ + arena->shCache = NULL; + arena->shCacheLength = 0; arena->shCacheI = (Size)0; - arena->shCacheLimit = (Size)1; + arena->shCacheLimit = (Size)0; arena->shDepth = (Size)0; arena->suspended = FALSE; - for(i = 0; i < ShieldCacheSIZE; i++) - arena->shCache[i] = NULL; for (ti = 0; ti < TraceLIMIT; ++ti) { /* */ @@ -435,6 +436,16 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) ArenaPark(arenaGlobals); arena = GlobalsArena(arenaGlobals); + + /* Delete the shield cache, if it exists. */ + if (arena->shCacheLength != 0) { + AVER(arena->shCache != NULL); + ControlFree(arena, arena->shCache, + arena->shCacheLength * sizeof arena->shCache[0]); + arena->shCache = NULL; + arena->shCacheLength = 0; + } + arenaDenounce(arena); defaultChain = arenaGlobals->defaultChain; @@ -1019,6 +1030,7 @@ Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth) "suspended $S\n", WriteFYesNo(arena->suspended), "shDepth $U\n", (WriteFU)arena->shDepth, "shCacheI $U\n", (WriteFU)arena->shCacheI, + "shCacheLength $U\n", (WriteFU)arena->shCacheLength, /* @@@@ should SegDescribe the cached segs? */ NULL); if (res != ResOK) diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 8b76dec162a..dd613f816af 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -760,7 +760,8 @@ typedef struct mps_arena_s { /* shield fields () */ Bool insideShield; /* TRUE if and only if inside shield */ - Seg shCache[ShieldCacheSIZE]; /* Cache of unsynced segs */ + Seg *shCache; /* Cache of unsynced segs */ + Count shCacheLength; Size shCacheI; /* index into cache */ Size shCacheLimit; /* High water mark for cache usage */ Size shDepth; /* sum of depths of all segs */ diff --git a/mps/code/shield.c b/mps/code/shield.c index bd141bdb489..0ad3c0fb979 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -135,8 +135,6 @@ static void shieldFlushEntry(Arena arena, Size i) AVER(i < arena->shCacheLimit); seg = arena->shCache[i]; - if (seg == NULL) - return; AVERT(Seg, seg); AVER(arena->shDepth > 0); @@ -147,28 +145,18 @@ static void shieldFlushEntry(Arena arena, Size i) if (SegDepth(seg) == 0) shieldSync(arena, seg); - arena->shCache[i] = NULL; + arena->shCache[i] = NULL; /* just to make sure it gets overwritten */ } -/* We sort NULLs to the end, and otherwise sort by base address */ static int shieldCacheEntryCompare(const void *a, const void *b) { Seg segA = *(SegStruct * const *)a, segB = *(SegStruct * const *)b; Addr baseA, baseB; - if (segA != NULL) - AVERT(Seg, segA); - if (segB != NULL) - AVERT(Seg, segB); + + AVERT(Seg, segA); /* FIXME: Might be critical? */ + AVERT(Seg, segB); - if (segA == NULL) { - if (segB == NULL) return 0; - else return 1; - } - if (segB == NULL) { - AVER(segA != NULL); - return -1; - } baseA = SegBase(segA); baseB = SegBase(segB); if (baseA < baseB) @@ -180,6 +168,14 @@ static int shieldCacheEntryCompare(const void *a, const void *b) } +static void shieldCacheReset(Arena arena) +{ + AVER(arena->shDepth == 0); + arena->shCacheI = 0; + arena->shCacheLimit = 0; +} + + /* shieldFlushEntries -- flush cache coalescing protects * * base, limit and mode represent outstanding protection to be done. @@ -191,12 +187,21 @@ static void shieldFlushEntries(Arena arena) AccessSet mode = 0; Seg seg; Size i; - qsort(arena->shCache, arena->shCacheLimit, sizeof(arena->shCache[0]), + if (arena->shDepth == 0) + return; + AVER(arena->shCache != NULL); + AVER(arena->shCacheLength > 0); + + /* FIXME: This needs to go through the plinth. */ + /* FIXME: We probably can't use libc's qsort because we can't bound + its use of stack space. */ + qsort(arena->shCache, arena->shCacheLimit, sizeof arena->shCache[0], shieldCacheEntryCompare); - seg = arena->shCache[0]; + + seg = arena->shCache[0]; /* lowest address segment */ if (seg) { AVERT(Seg, seg); - arena->shCache[0] = NULL; + arena->shCache[0] = NULL; /* just to make sure it isn't reused */ AVER(arena->shDepth > 0); AVER(SegDepth(seg) > 0); @@ -214,11 +219,8 @@ static void shieldFlushEntries(Arena arena) if (arena->shDepth == 0) break; seg = arena->shCache[i]; - /* All the NULLs are sorted to the end */ - if (seg == NULL) - break; AVERT(Seg, seg); - arena->shCache[i] = NULL; + arena->shCache[i] = NULL; /* just to make sure it isn't reused */ AVER(arena->shDepth > 0); AVER(SegDepth(seg) > 0); @@ -242,6 +244,7 @@ static void shieldFlushEntries(Arena arena) if (limit != 0) { ProtSet(base, limit, mode); } + shieldCacheReset(arena); } @@ -254,29 +257,68 @@ static void shieldCache(Arena arena, Seg seg) AVERT_CRITICAL(Arena, arena); AVERT_CRITICAL(Seg, seg); - if (SegSM(seg) - == SegPM(seg)) return; - if (SegDepth(seg) > 0) { + if (SegSM(seg) == SegPM(seg)) + return; + if (SegDepth(seg) > 0) { /* already in the cache or exposed? */ + /* This can occur if the mutator isn't suspended, we expose a + segment, then raise the shield on it. In this case, the + mutator isn't allowed to see the segment, but we don't need to + cache it until its covered. */ ShieldSuspend(arena); return; } - if (ShieldCacheSIZE == 0 || !arena->suspended) - shieldSync(arena, seg); - else { - SegSetDepth(seg, SegDepth(seg) + 1); - ++arena->shDepth; - AVER(arena->shDepth > 0); - AVER(SegDepth(seg) > 0); - AVER(arena->shCacheLimit <= ShieldCacheSIZE); - AVER(arena->shCacheI < arena->shCacheLimit); - shieldFlushEntry(arena, arena->shCacheI); - arena->shCache[arena->shCacheI] = seg; - ++arena->shCacheI; - if (arena->shCacheI == ShieldCacheSIZE) - arena->shCacheI = 0; - if (arena->shCacheI == arena->shCacheLimit) - ++arena->shCacheLimit; + + /* Allocate shield cache if necessary. */ + if (arena->shCacheLength == 0) { + void *p; + Res res; + + AVER(arena->shCache == NULL); + + res = ControlAlloc(&p, arena, ShieldCacheSIZE * sizeof arena->shCache[0], FALSE); + if (res != ResOK) { + AVER(res == ResMEMORY); + } else { + arena->shCache = p; + arena->shCacheLength = ShieldCacheSIZE; + } } + + /* Cache unavailable, so synchronize now. Or if the mutator is not + yet suspended and the code raises the shield on a covered + segment, protect it now, because that's probably better than + suspending the mutator. */ + if (arena->shCacheLength == 0 || !arena->suspended) { + shieldSync(arena, seg); + return; + } + + SegSetDepth(seg, SegDepth(seg) + 1); + AVER(SegDepth(seg) > 0); /* overflow */ + ++arena->shDepth; + AVER(arena->shDepth > 0); /* overflow */ + + AVER(arena->shCacheLimit <= arena->shCacheLength); + AVER(arena->shCacheI <= arena->shCacheLimit); + + if (arena->shCacheI >= arena->shCacheLength) + arena->shCacheI = 0; + AVER(arena->shCacheI < arena->shCacheLength); + + AVER(arena->shCacheLength > 0); + + /* If the limit is less than the length, then the cache array has + yet to be filled, and shCacheI is an uninitialized entry. + Otherwise it's the tail end from last time around, and needs to + be flushed. */ + if (arena->shCacheLimit == arena->shCacheLength) + shieldFlushEntry(arena, arena->shCacheI); + + arena->shCache[arena->shCacheI] = seg; + ++arena->shCacheI; + + if (arena->shCacheI >= arena->shCacheLimit) + arena->shCacheLimit = arena->shCacheI; } @@ -316,19 +358,15 @@ void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) void (ShieldEnter)(Arena arena) { - Size i; - AVERT(Arena, arena); AVER(!arena->insideShield); AVER(arena->shDepth == 0); AVER(!arena->suspended); - AVER(arena->shCacheLimit <= ShieldCacheSIZE); - AVER(arena->shCacheI < arena->shCacheLimit); - for (i = 0; i < arena->shCacheLimit; i++) - AVER(arena->shCache[i] == NULL); + AVER(arena->shCacheLimit <= arena->shCacheLength); + AVER(arena->shCacheI <= arena->shCacheLimit); + + shieldCacheReset(arena); - arena->shCacheI = (Size)0; - arena->shCacheLimit = (Size)1; arena->insideShield = TRUE; } From 8df13d0bffe08c9ce41c8acc98304f4164a85444 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 17 Mar 2016 16:55:14 +0000 Subject: [PATCH 268/337] Shield cache that grows. improving commentary. Copied from Perforce Change: 190160 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 4 +- mps/code/shield.c | 107 +++++++++++++++++++++++++++++++++------------- mps/code/trace.c | 1 + 3 files changed, 81 insertions(+), 31 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index 7d5e849e04a..530bf90cb6e 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -483,8 +483,8 @@ /* Shield Configuration -- see */ -#define ShieldCacheSIZE ((size_t)1024) -#define ShieldDepthWIDTH (10) +#define ShieldCacheSIZE 512 +#define ShieldDepthWIDTH 10 /* VM Configuration -- see */ diff --git a/mps/code/shield.c b/mps/code/shield.c index cb3ff034ac9..3c2e29d8f08 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -78,6 +78,43 @@ SRCID(shield, "$Id$"); +/* shieldSegIsSynced -- is a segment synced? + * + * See .def.synced. + */ + +static Bool shieldSegIsSynced(Seg seg) +{ + AVERT_CRITICAL(Seg, seg); + return SegSM(seg) == SegPM(seg); +} + + +/* shieldSync -- synchronize a segment's protection */ + +static void shieldSync(Arena arena, Seg seg) +{ + AVERT(Arena, arena); + AVERT(Seg, seg); + + if (!shieldSegIsSynced(seg)) { + ProtSet(SegBase(seg), SegLimit(seg), SegSM(seg)); + SegSetPM(seg, SegSM(seg)); + /* See .inv.prot.shield. */ + } +} + + +/* ShieldSuspend -- suspend the mutator + * + * From outside impl.c.shield, this is used when we really need to + * lock everything against the mutator -- for example, during flip + * when we must scan all thread registers at once. + * + * It is called from inside impl.c.shield when any segment is not + * synced -- see .inv.unsynced.suspended. + */ + void (ShieldSuspend)(Arena arena) { AVERT(Arena, arena); @@ -90,6 +127,12 @@ void (ShieldSuspend)(Arena arena) } +/* ShieldResume -- declare mutator could be resumed + * + * In practice, we don't resume the mutator until ShieldLeave, but + * this marks the earliest point at which we could resume. + */ + void (ShieldResume)(Arena arena) { AVERT(Arena, arena); @@ -115,19 +158,6 @@ static void protLower(Arena arena, Seg seg, AccessSet mode) } -static void shieldSync(Arena arena, Seg seg) -{ - AVERT(Arena, arena); - AVERT(Seg, seg); - - if (SegPM(seg) != SegSM(seg)) { - ProtSet(SegBase(seg), SegLimit(seg), SegSM(seg)); - SegSetPM(seg, SegSM(seg)); - /* inv.prot.shield */ - } -} - - static void shieldFlushEntry(Arena arena, Size i) { Seg seg; @@ -208,7 +238,7 @@ static void shieldFlushEntries(Arena arena) --arena->shDepth; SegSetDepth(seg, SegDepth(seg) - 1); - if (SegSM(seg) != SegPM(seg)) { + if (!shieldSegIsSynced(seg)) { SegSetPM(seg, SegSM(seg)); base = SegBase(seg); limit = SegLimit(seg); @@ -227,7 +257,7 @@ static void shieldFlushEntries(Arena arena) --arena->shDepth; SegSetDepth(seg, SegDepth(seg) - 1); - if (SegSM(seg) != SegPM(seg)) { + if (!shieldSegIsSynced(seg)) { SegSetPM(seg, SegSM(seg)); if (SegBase(seg) != limit || mode != SegSM(seg)) { if (limit != 0) { @@ -248,17 +278,21 @@ static void shieldFlushEntries(Arena arena) } -/* If the segment is out of sync, either sync it, or ensure - * depth > 0, and the arena is suspended. +/* shieldCache -- consider adding a segment to the cache + * + * If the segment is out of sync, either sync it, or ensure depth > 0, + * and the arena is suspended. */ + static void shieldCache(Arena arena, Seg seg) { /* */ AVERT_CRITICAL(Arena, arena); AVERT_CRITICAL(Seg, seg); - if (SegSM(seg) == SegPM(seg)) + if (shieldSegIsSynced(seg)) return; + if (SegDepth(seg) > 0) { /* already in the cache or exposed? */ /* This can occur if the mutator isn't suspended, we expose a segment, then raise the shield on it. In this case, the @@ -269,18 +303,33 @@ static void shieldCache(Arena arena, Seg seg) } /* Allocate shield cache if necessary. */ - if (arena->shCacheLength == 0) { + /* FIXME: This will try to extend the cache on every attempt, even + if it failed last time. That might be slow. */ + if (arena->shCacheI >= arena->shCacheLength) { void *p; Res res; - - AVER(arena->shCache == NULL); + Count length; - res = ControlAlloc(&p, arena, ShieldCacheSIZE * sizeof arena->shCache[0]); + AVER(arena->shCacheI == arena->shCacheLength); + + if (arena->shCacheLength == 0) + length = ShieldCacheSIZE; + else + length = arena->shCacheLength * 2; + + res = ControlAlloc(&p, arena, length * sizeof arena->shCache[0]); if (res != ResOK) { AVER(res == ResMEMORY); + /* Carry on with the existing cache. */ } else { + if (arena->shCacheLength > 0) { + Size oldSize = arena->shCacheLength * sizeof arena->shCache[0]; + AVER(arena->shCache != NULL); + mps_lib_memcpy(p, arena->shCache, oldSize); + ControlFree(arena, arena->shCache, oldSize); + } arena->shCache = p; - arena->shCacheLength = ShieldCacheSIZE; + arena->shCacheLength = length; } } @@ -294,18 +343,18 @@ static void shieldCache(Arena arena, Seg seg) } SegSetDepth(seg, SegDepth(seg) + 1); - AVER(SegDepth(seg) > 0); /* overflow */ + AVER_CRITICAL(SegDepth(seg) > 0); /* overflow */ ++arena->shDepth; - AVER(arena->shDepth > 0); /* overflow */ + AVER_CRITICAL(arena->shDepth > 0); /* overflow */ - AVER(arena->shCacheLimit <= arena->shCacheLength); - AVER(arena->shCacheI <= arena->shCacheLimit); + AVER_CRITICAL(arena->shCacheLimit <= arena->shCacheLength); + AVER_CRITICAL(arena->shCacheI <= arena->shCacheLimit); if (arena->shCacheI >= arena->shCacheLength) arena->shCacheI = 0; - AVER(arena->shCacheI < arena->shCacheLength); + AVER_CRITICAL(arena->shCacheI < arena->shCacheLength); - AVER(arena->shCacheLength > 0); + AVER_CRITICAL(arena->shCacheLength > 0); /* If the limit is less than the length, then the cache array has yet to be filled, and shCacheI is an uninitialized entry. diff --git a/mps/code/trace.c b/mps/code/trace.c index 6d9cb0f0f98..3c23e552990 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -737,6 +737,7 @@ Res TraceCreate(Trace *traceReturn, Arena arena, int why) /* buffers under our feet. */ /* @@@@ This is a short-term fix for request.dylan.160098_. */ /* .. _request.dylan.160098: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160098 */ + /* FIXME: Where is the corresponding ShieldResume? */ ShieldSuspend(arena); STATISTIC_STAT ({ From 4d889230f96e605d2b903fc14a5dcd839f2ef499 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 17 Mar 2016 18:22:08 +0000 Subject: [PATCH 269/337] Replacing qsort with an iterative implementation. Copied from Perforce Change: 190166 ServerID: perforce.ravenbrook.com --- mps/code/shield.c | 51 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/mps/code/shield.c b/mps/code/shield.c index 3c2e29d8f08..d889ae80240 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -179,9 +179,8 @@ static void shieldFlushEntry(Arena arena, Size i) } -static int shieldCacheEntryCompare(const void *a, const void *b) +static int shieldCacheEntryCompare(Seg segA, Seg segB) { - Seg segA = *(SegStruct * const *)a, segB = *(SegStruct * const *)b; Addr baseA, baseB; AVERT(Seg, segA); /* FIXME: Might be critical? */ @@ -198,6 +197,48 @@ static int shieldCacheEntryCompare(const void *a, const void *b) } +static void quicksort_iterative(Seg array[], Count len) +{ + static Index seed = 0x6A9D03; + Index left, right, stack[64], pos; + Seg pivot, temp; + + left = 0; + pos = 0; + for (;;) { + while (left + 1 < len) { + if (pos >= sizeof stack / sizeof stack[0]) { + pos = 0; + len = stack[pos]; /* stack overflow, reset */ + } + pivot = array[left + seed % (len - left)]; + seed = seed * 69069 + 1; + stack[pos] = len; + ++pos; + right = left; + for (;;) { + while (shieldCacheEntryCompare(array[right], pivot) < 0) + ++right; + do + --len; + while (shieldCacheEntryCompare(pivot, array[len]) < 0); + if (right >= len) + break; + temp = array[right]; + array[right] = array[len]; + array[len] = temp; + } + ++len; + } + if (pos == 0) + break; + left = len; + --pos; + len = stack[pos]; + } +} + + static void shieldCacheReset(Arena arena) { AVER(arena->shDepth == 0); @@ -222,11 +263,7 @@ static void shieldFlushEntries(Arena arena) AVER(arena->shCache != NULL); AVER(arena->shCacheLength > 0); - /* FIXME: This needs to go through the plinth. */ - /* FIXME: We probably can't use libc's qsort because we can't bound - its use of stack space. */ - qsort(arena->shCache, arena->shCacheLimit, sizeof arena->shCache[0], - shieldCacheEntryCompare); + quicksort_iterative(arena->shCache, arena->shCacheLimit); seg = arena->shCache[0]; /* lowest address segment */ if (seg) { From eb8b31f059d240b400328fda215edb394385681f Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 17 Mar 2016 19:26:45 +0000 Subject: [PATCH 270/337] Tidying up quicksort into an mpm utility. Copied from Perforce Change: 190171 ServerID: perforce.ravenbrook.com --- mps/code/mpm.c | 48 +++++++++++++++++++++++++++++++++++ mps/code/mpm.h | 5 ++++ mps/code/shield.c | 64 ++++++++++------------------------------------- 3 files changed, 66 insertions(+), 51 deletions(-) diff --git a/mps/code/mpm.c b/mps/code/mpm.c index aba1ac2f5cb..3b912a54a02 100644 --- a/mps/code/mpm.c +++ b/mps/code/mpm.c @@ -645,6 +645,54 @@ Bool StringEqual(const char *s1, const char *s2) } +/* QuickSort -- non-recursive bounded sort + * + * We can't rely on the standard library's qsort, which might have + * O(n) stack usage. This version does not recurse. + */ + +void QuickSort(void *array[], Count len, + QuickSortCompare compare, void *closure) +{ + static Index seed = 0x6A9D03; + Index left, right, stack[MPS_WORD_WIDTH], pos; + void *pivot, *temp; + + left = 0; + pos = 0; + for (;;) { + while (left + 1 < len) { + if (pos >= sizeof stack / sizeof stack[0]) { + pos = 0; + len = stack[pos]; /* stack overflow, reset */ + } + pivot = array[left + seed % (len - left)]; + seed = seed * 69069 + 1; + stack[pos] = len; + ++pos; + right = left; + for (;;) { + while (compare(array[right], pivot, closure) == CompareLESS) + ++right; + do + --len; + while (compare(pivot, array[len], closure) == CompareLESS); + if (right >= len) + break; + temp = array[right]; + array[right] = array[len]; + array[len] = temp; + } + ++len; + } + if (pos == 0) + break; + left = len; + --pos; + len = stack[pos]; + } +} + /* C. COPYRIGHT AND LICENSE * diff --git a/mps/code/mpm.h b/mps/code/mpm.h index e2b0e57a8a2..01158fb0779 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -171,6 +171,11 @@ extern Res WriteF_firstformat_v(mps_lib_FILE *stream, Count depth, extern size_t StringLength(const char *s); extern Bool StringEqual(const char *s1, const char *s2); +typedef Compare QuickSortCompare(void *left, void *right, + void *closure); +extern void QuickSort(void *array[], Count length, + QuickSortCompare compare, void *closure); + /* Version Determination * diff --git a/mps/code/shield.c b/mps/code/shield.c index d889ae80240..884c13ce0e7 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -73,7 +73,6 @@ */ #include "mpm.h" -#include "stdlib.h" /* For qsort, move */ SRCID(shield, "$Id$"); @@ -179,63 +178,25 @@ static void shieldFlushEntry(Arena arena, Size i) } -static int shieldCacheEntryCompare(Seg segA, Seg segB) +static Compare shieldCacheEntryCompare(void *left, void *right, void *closure) { + Seg segA = left, segB = right; Addr baseA, baseB; - - AVERT(Seg, segA); /* FIXME: Might be critical? */ + + /* Making these CRITICAL had no effect on timings on LII6LL today. + RB 2016-03-17. */ + AVERT(Seg, segA); AVERT(Seg, segB); + UNUSED(closure); baseA = SegBase(segA); baseB = SegBase(segB); if (baseA < baseB) - return -1; + return CompareLESS; if (baseA > baseB) - return 1; + return CompareGREATER; AVER(baseA == baseB); - return 0; -} - - -static void quicksort_iterative(Seg array[], Count len) -{ - static Index seed = 0x6A9D03; - Index left, right, stack[64], pos; - Seg pivot, temp; - - left = 0; - pos = 0; - for (;;) { - while (left + 1 < len) { - if (pos >= sizeof stack / sizeof stack[0]) { - pos = 0; - len = stack[pos]; /* stack overflow, reset */ - } - pivot = array[left + seed % (len - left)]; - seed = seed * 69069 + 1; - stack[pos] = len; - ++pos; - right = left; - for (;;) { - while (shieldCacheEntryCompare(array[right], pivot) < 0) - ++right; - do - --len; - while (shieldCacheEntryCompare(pivot, array[len]) < 0); - if (right >= len) - break; - temp = array[right]; - array[right] = array[len]; - array[len] = temp; - } - ++len; - } - if (pos == 0) - break; - left = len; - --pos; - len = stack[pos]; - } + return CompareEQUAL; } @@ -263,7 +224,8 @@ static void shieldFlushEntries(Arena arena) AVER(arena->shCache != NULL); AVER(arena->shCacheLength > 0); - quicksort_iterative(arena->shCache, arena->shCacheLimit); + QuickSort((void *)arena->shCache, arena->shCacheLimit, + shieldCacheEntryCompare, UNUSED_POINTER); seg = arena->shCache[0]; /* lowest address segment */ if (seg) { @@ -356,7 +318,7 @@ static void shieldCache(Arena arena, Seg seg) res = ControlAlloc(&p, arena, length * sizeof arena->shCache[0]); if (res != ResOK) { - AVER(res == ResMEMORY); + AVER(ResIsAllocFailure(res)); /* Carry on with the existing cache. */ } else { if (arena->shCacheLength > 0) { From 91a08048b7c94441aceb413824ebbab1f44c520c Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 17 Mar 2016 20:04:26 +0000 Subject: [PATCH 271/337] Design documentation, commentary, and code tidying. Copied from Perforce Change: 190172 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 4 +- mps/code/shield.c | 112 ++++++++++++++++++++---------------------- mps/design/shield.txt | 49 ++++++++---------- 3 files changed, 75 insertions(+), 90 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index 530bf90cb6e..bfaaa2e6e4b 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -483,8 +483,8 @@ /* Shield Configuration -- see */ -#define ShieldCacheSIZE 512 -#define ShieldDepthWIDTH 10 +#define ShieldCacheLENGTH 512 /* initial length of shield cache */ +#define ShieldDepthWIDTH 4 /* log2(max nested exposes + 1) */ /* VM Configuration -- see */ diff --git a/mps/code/shield.c b/mps/code/shield.c index 884c13ce0e7..8d0678f493a 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -209,70 +209,68 @@ static void shieldCacheReset(Arena arena) /* shieldFlushEntries -- flush cache coalescing protects + * + * Sort the shield cache into address order, then iterate over it + * coalescing protection work, in order to reduce the number of system + * calls to a minimum. This is very important on OS X, where + * protection calls are extremely inefficient, but has no net gain on + * Windows. * * base, limit and mode represent outstanding protection to be done. */ static void shieldFlushEntries(Arena arena) { - Addr base = 0, limit = 0; - AccessSet mode = 0; + Addr base = NULL, limit = NULL; + AccessSet mode; Seg seg; Size i; - if (arena->shDepth == 0) + + if (arena->shDepth == 0) { + AVER(arena->shCacheLimit == 0); return; + } + AVER(arena->shCache != NULL); AVER(arena->shCacheLength > 0); QuickSort((void *)arena->shCache, arena->shCacheLimit, shieldCacheEntryCompare, UNUSED_POINTER); - seg = arena->shCache[0]; /* lowest address segment */ - if (seg) { - AVERT(Seg, seg); - arena->shCache[0] = NULL; /* just to make sure it isn't reused */ - + mode = AccessSetEMPTY; + for (i = 0; i < arena->shCacheLimit; ++i) { AVER(arena->shDepth > 0); - AVER(SegDepth(seg) > 0); - --arena->shDepth; - SegSetDepth(seg, SegDepth(seg) - 1); - if (!shieldSegIsSynced(seg)) { - SegSetPM(seg, SegSM(seg)); - base = SegBase(seg); - limit = SegLimit(seg); - mode = SegSM(seg); - } - } - for (i=1; i < arena->shCacheLimit; ++i) { - if (arena->shDepth == 0) - break; seg = arena->shCache[i]; - AVERT(Seg, seg); - arena->shCache[i] = NULL; /* just to make sure it isn't reused */ + arena->shCache[i] = NULL; /* ensure it can't be reused */ - AVER(arena->shDepth > 0); + AVERT(Seg, seg); AVER(SegDepth(seg) > 0); + --arena->shDepth; SegSetDepth(seg, SegDepth(seg) - 1); if (!shieldSegIsSynced(seg)) { + AVER(SegSM(seg) != AccessSetEMPTY); /* can't match first iter */ SegSetPM(seg, SegSM(seg)); - if (SegBase(seg) != limit || mode != SegSM(seg)) { - if (limit != 0) { + if (SegSM(seg) != mode || SegBase(seg) != limit) { + if (mode != AccessSetEMPTY) { + AVER(base != NULL); + AVER(base < limit); ProtSet(base, limit, mode); } base = SegBase(seg); - limit = SegLimit(seg); mode = SegSM(seg); - } else { - limit = SegLimit(seg); } + limit = SegLimit(seg); } } - if (limit != 0) { + if (mode != AccessSetEMPTY) { + AVER(base != NULL); + AVER(limit != NULL); ProtSet(base, limit, mode); } + shieldCacheReset(arena); } @@ -312,7 +310,7 @@ static void shieldCache(Arena arena, Seg seg) AVER(arena->shCacheI == arena->shCacheLength); if (arena->shCacheLength == 0) - length = ShieldCacheSIZE; + length = ShieldCacheLENGTH; else length = arena->shCacheLength * 2; @@ -359,8 +357,10 @@ static void shieldCache(Arena arena, Seg seg) yet to be filled, and shCacheI is an uninitialized entry. Otherwise it's the tail end from last time around, and needs to be flushed. */ - if (arena->shCacheLimit == arena->shCacheLength) + if (arena->shCacheLimit >= arena->shCacheLength) { + AVER_CRITICAL(arena->shCacheLimit == arena->shCacheLength); shieldFlushEntry(arena, arena->shCacheI); + } arena->shCache[arena->shCacheI] = seg; ++arena->shCacheI; @@ -379,10 +379,12 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode) AVERT(AccessSet, mode); AVER((SegSM(seg) & mode) == AccessSetEMPTY); - SegSetSM(seg, SegSM(seg) | mode); /* inv.prot.shield preserved */ + + SegSetSM(seg, SegSM(seg) | mode); /* .inv.prot.shield preserved */ - /* ensure inv.unsynced.suspended & inv.unsynced.depth */ + /* ensure .inv.unsynced.suspended and .inv.unsynced.depth */ shieldCache(arena, seg); + AVERT(Arena, arena); AVERT(Seg, seg); } @@ -393,10 +395,8 @@ 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 - * Also inv.prot.shield preserved - */ + /* synced(seg) is not changed by the following preserving + inv.unsynced.suspended Also inv.prot.shield preserved */ SegSetSM(seg, SegSM(seg) & ~mode); protLower(arena, seg, mode); AVERT(Arena, arena); @@ -419,28 +419,22 @@ void (ShieldEnter)(Arena arena) } -/* .shield.flush: Flush empties the shield cache. - * This needs to be called before segments are destroyed as there - * may be references to them in the cache. +/* ShieldFlush -- empty the shield cache * - * The memory for the segment may become spare, and not released back to - * the operating system. Since we keep track of protection on segments - * and not grains we have no way of keeping track of the protection - * state of spare grains. We therefore flush the protection to get it - * back into the default state (unprotected). + * .shield.flush: Flush empties the shield cache. This needs to be + * called before segments are destroyed as there may be references to + * them in the cache. + * + * The memory for the segment may become spare, and not released back + * to the operating system. Since we keep track of protection on + * segments and not grains we have no way of keeping track of the + * protection state of spare grains. We therefore flush the protection + * to get it back into the default state (unprotected). */ + void (ShieldFlush)(Arena arena) { - Size i; - - if(1) - shieldFlushEntries(arena); - - for (i = 0; i < arena->shCacheLimit; ++i) { - if (arena->shDepth == 0) - break; - shieldFlushEntry(arena, i); - } + shieldFlushEntries(arena); } @@ -450,11 +444,11 @@ void (ShieldLeave)(Arena arena) AVER(arena->insideShield); ShieldFlush(arena); - /* Cache is empty so inv.outside.depth holds */ + /* Cache is empty so .inv.outside.depth holds */ AVER(arena->shDepth == 0); - /* Ensuring the mutator is running at this point - * guarantees inv.outside.running */ + /* Ensuring the mutator is running at this point guarantees + .inv.outside.running */ if (arena->suspended) { ThreadRingResume(ArenaThreadRing(arena), ArenaDeadRing(arena)); arena->suspended = FALSE; diff --git a/mps/design/shield.txt b/mps/design/shield.txt index 31648245ed1..42589a3c5e7 100644 --- a/mps/design/shield.txt +++ b/mps/design/shield.txt @@ -115,41 +115,27 @@ segment should be unprotected, and the Shield could re-instate hardware protection. However, as a performance-improving hysteresis, the Shield defers -re-protection, maintaining a cache of the last ``ShieldCacheSIZE`` -times a segment no longer had a reason to be collector-accessible. -Presence in the cache counts as a reason: segments in the cache have -``seg->depth`` increased by one. As segments get pushed out of the -cache, or at ``ShieldLeave()``, this artificial reason is -decremented from ``seg->depth``, and (if ``seg->depth`` is now zero) -the deferred reinstatement of hardware protection happens. +re-protection, maintaining a cache reasons that a segment no longer +had a reason to be collector-accessible. Presence in the cache counts +as a reason: segments in the cache have ``seg->depth`` increased by +one. As segments get pushed out of the cache, or at ``ShieldLeave()``, +this artificial reason is decremented from ``seg->depth``, and (if +``seg->depth`` is now zero) the deferred reinstatement of hardware +protection happens. + +This hysteresis allows the MPS to proceed with garbage collection +during a pause without actually setting hardware protection until it +returns to the mutator. If a complete collection cycle occurs during +one pause (a non-incremental collection), no system calls will be +needed for collection barriers. This is particularly important on +operating systems where the protection is expensive and poorly +implemented, such as OS X. So whenever hardware protection is temporarily removed to allow collector access, there is a *nurse* that will ensure this protection is re-established: the nurse is either the balancing ``ShieldCover()`` call in collector code, or an entry in the shield cache. -.. note:: - - 1. Why is there a fixed-size cache? This is not the simple - approach! All we need is a chain of segs that might need their - hardware protection to be sync'd with their shield mode. Head - in the shield, and one pointer in each seg struct. I guess we - try hard to avoid bloating ``SegStruct`` (to maintain residency - in the processor cache). But is 16 the right size? A cache-miss - wastes two kernel calls. - - 2. I don't like the cache code. For example, why does - ``ShieldFlush()`` break out early if ``arena->shDepth`` is 0? - This should never happen until the cache is completely flushed, - that is, we have reached ``shCacheLimit``. Why does - ``ShieldFlush()`` not reset ``shCacheLimit``? Why does - ``flush()`` silently accept ``NULL`` cache entries? - - 3. Why is ``seg->depth`` never checked for overflow? It is only a - 4-bit-wide bit field, currently. - - Richard Kistruck, 2006-12-19. - Initial ideas ------------- @@ -183,8 +169,13 @@ Document History - 2013-05-24 GDR_ Converted to reStructuredText. +- 2016-03-17 RB_ Updated for dynamic cacheing and general code tidying + that has removed complaints. + .. _GDR: http://www.ravenbrook.com/consultants/gdr/ +.. _RB: http://www.ravenbrook.com/consultants/rb/ + Copyright and License --------------------- From 536960d0612e211b8a33581db092dda8227a81df Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 18 Mar 2016 14:50:11 +0000 Subject: [PATCH 272/337] Writing a clearer quicksort with assertions. Copied from Perforce Change: 190181 ServerID: perforce.ravenbrook.com --- mps/code/mpm.c | 112 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 84 insertions(+), 28 deletions(-) diff --git a/mps/code/mpm.c b/mps/code/mpm.c index 3b912a54a02..d2c87d5038d 100644 --- a/mps/code/mpm.c +++ b/mps/code/mpm.c @@ -651,46 +651,102 @@ Bool StringEqual(const char *s1, const char *s2) * O(n) stack usage. This version does not recurse. */ -void QuickSort(void *array[], Count len, +#ifdef QUICKSORT_DEBUG +static Bool quickSorted(void *array[], Count length, + QuickSortCompare compare, void *closure) +{ + Index i; + if (length > 0) { + for (i = 0; i < length - 1; ++i) { + if (compare(array[i], array[i+1], closure) == CompareGREATER) + return FALSE; + } + } + return TRUE; +} +#endif + +void QuickSort(void *array[], Count length, QuickSortCompare compare, void *closure) { static Index seed = 0x6A9D03; - Index left, right, stack[MPS_WORD_WIDTH], pos; + struct { + Index left, right; + } stack[MPS_WORD_WIDTH]; + Index left, right, sp, lo, hi, leftLimit, rightBase; void *pivot, *temp; + sp = 0; left = 0; - pos = 0; + right = length; + for (;;) { - while (left + 1 < len) { - if (pos >= sizeof stack / sizeof stack[0]) { - pos = 0; - len = stack[pos]; /* stack overflow, reset */ - } - pivot = array[left + seed % (len - left)]; + while (right - left > 1) { /* no need to sort */ + /* Pick a random pivot. */ + pivot = array[left + seed % (right - left)]; seed = seed * 69069 + 1; - stack[pos] = len; - ++pos; - right = left; + + /* Hoare partition: scan from lo to hi, dividing it into elements + less than the pivot and elements greater or equal. */ + lo = left; + hi = right; for (;;) { - while (compare(array[right], pivot, closure) == CompareLESS) - ++right; - do - --len; - while (compare(pivot, array[len], closure) == CompareLESS); - if (right >= len) - break; - temp = array[right]; - array[right] = array[len]; - array[len] = temp; + while (compare(array[lo], pivot, closure) == CompareLESS) + ++lo; + do + --hi; + while (compare(pivot, array[hi], closure) == CompareLESS); + if (lo >= hi) + break; + temp = array[hi]; + array[hi] = array[lo]; + array[lo] = temp; + ++lo; /* step over what we just swapped */ + } + + /* If we ended up at a pivot, then it is in its final position + and we must skip it to ensure termination. This handles the case + where the pivot is at the start of the array, and one of the + partitions is the whole array, for example. */ + if (lo == hi) { + AVER_CRITICAL(array[hi] == pivot); /* and it's in place */ + leftLimit = lo; + rightBase = lo + 1; + } else { + AVER_CRITICAL(lo == hi + 1); + leftLimit = lo; + rightBase = lo; + } + + /* Sort the smaller part now, so that we're sure to use at most + log2 length stack levels. Push the larger part on the stack + for later. */ + AVER_CRITICAL(sp < sizeof stack / sizeof stack[0]); + if (leftLimit - left < right - rightBase) { + stack[sp].left = rightBase; + stack[sp].right = right; + ++sp; + right = leftLimit; + } else { + stack[sp].left = left; + stack[sp].right = leftLimit; + ++sp; + left = rightBase; } - ++len; } - if (pos == 0) + + if (sp == 0) break; - left = len; - --pos; - len = stack[pos]; - } + + --sp; + left = stack[sp].left; + right = stack[sp].right; + AVER_CRITICAL(left < right); /* we do the smaller side immediately */ + } + +#ifdef QUICKSORT_DEBUG + AVER(quickSorted(array, length, compare, closure)); +#endif } From bb206eec148afc63ed7e84ac3bf9f951696fefb1 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Fri, 18 Mar 2016 15:37:53 +0000 Subject: [PATCH 273/337] Adding xci3ll.gmk to make it easier to test 32-bit builds on os x. Copied from Perforce Change: 190184 ServerID: perforce.ravenbrook.com --- mps/code/xci3ll.gmk | 72 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 mps/code/xci3ll.gmk diff --git a/mps/code/xci3ll.gmk b/mps/code/xci3ll.gmk new file mode 100644 index 00000000000..a0af3b7079d --- /dev/null +++ b/mps/code/xci3ll.gmk @@ -0,0 +1,72 @@ +# -*- makefile -*- +# +# xci3ll.gmk: BUILD FOR MAC OS X/i386/Clang PLATFORM +# +# $Id$ +# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. +# +# .prefer.xcode: The documented and preferred way to develop the MPS +# for this platform is to use the Xcode project (mps.xcodeproj). This +# makefile provides a way to compile the MPS one source file at a +# time, rather than all at once via mps.c (which can hide errors due +# to missing headers). + +PFM = xci3ll + +MPMPF = \ + lockix.c \ + prmci3xc.c \ + proti3.c \ + protix.c \ + protxc.c \ + span.c \ + ssixi3.c \ + thxc.c \ + vmix.c + +include ll.gmk + +CC = clang -arch i386 + +include comm.gmk + + +# C. COPYRIGHT AND LICENSE +# +# Copyright (C) 2001-2014 Ravenbrook Limited . +# All rights reserved. This is an open source license. Contact +# Ravenbrook for commercial licensing options. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Redistributions in any form must be accompanied by information on how +# to obtain complete source code for this software and any accompanying +# software that uses this software. The source code must either be +# included in the distribution or be available for no more than the cost +# of distribution plus a nominal fee, and must be freely redistributable +# under reasonable conditions. For an executable file, complete source +# code means the source code for all modules it contains. It does not +# include source code for modules or files that typically accompany the +# major components of the operating system on which the executable file +# runs. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From ed69abbd662eb555fbba81d4f738901dd2abb5fa Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 17 Mar 2016 20:06:41 +0000 Subject: [PATCH 274/337] Deferring non-urgent fixmes to todos. Copied from Perforce Change: 190190 ServerID: perforce.ravenbrook.com --- mps/code/shield.c | 2 +- mps/code/trace.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/code/shield.c b/mps/code/shield.c index 8d0678f493a..7fc9294b180 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -300,7 +300,7 @@ static void shieldCache(Arena arena, Seg seg) } /* Allocate shield cache if necessary. */ - /* FIXME: This will try to extend the cache on every attempt, even + /* TODO: This will try to extend the cache on every attempt, even if it failed last time. That might be slow. */ if (arena->shCacheI >= arena->shCacheLength) { void *p; diff --git a/mps/code/trace.c b/mps/code/trace.c index 3c23e552990..1f3db0d3467 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -737,7 +737,7 @@ Res TraceCreate(Trace *traceReturn, Arena arena, int why) /* buffers under our feet. */ /* @@@@ This is a short-term fix for request.dylan.160098_. */ /* .. _request.dylan.160098: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160098 */ - /* FIXME: Where is the corresponding ShieldResume? */ + /* TODO: Where is the corresponding ShieldResume? */ ShieldSuspend(arena); STATISTIC_STAT ({ From 20a34ca17f0cc68c42952c0a2eb767942e39e2d9 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 19 Mar 2016 08:57:27 +0000 Subject: [PATCH 275/337] Importing good random number generator from testlib for use in quicksort and perhaps later in cuckoo hashing. Copied from Perforce Change: 190191 ServerID: perforce.ravenbrook.com --- mps/code/mpm.c | 36 +++++++++++++++++++++++++++++++++--- mps/code/mpm.h | 3 +++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/mps/code/mpm.c b/mps/code/mpm.c index d2c87d5038d..7d944ae57eb 100644 --- a/mps/code/mpm.c +++ b/mps/code/mpm.c @@ -645,6 +645,38 @@ Bool StringEqual(const char *s1, const char *s2) } +/* Random -- a random number generator + * + * TODO: This is a copy of the generator from testlib.c, which has + * extensive notes and verification tests. The notes need to go to a + * design document, and the tests to a test. + */ + +static unsigned RandomSeed = 1; +#define Random_m 2147483647UL +#define Random_a 48271UL +unsigned Random32(void) +{ + AVER(UINT_MAX >= 4294967295U); + /* requires m == 2^31-1, a < 2^16 */ + unsigned bot = Random_a * (RandomSeed & 0x7FFF); + unsigned top = Random_a * (RandomSeed >> 15); + RandomSeed = bot + ((top & 0xFFFF) << 15) + (top >> 16); + if (RandomSeed > Random_m) + RandomSeed -= Random_m; + return RandomSeed; +} + +Word RandomWord(void) +{ + Word word; + Index i; + for (i = 0; i < MPS_WORD_WIDTH; i += 31) + word = (word << 31) | Random32(); + return word; +} + + /* QuickSort -- non-recursive bounded sort * * We can't rely on the standard library's qsort, which might have @@ -669,7 +701,6 @@ static Bool quickSorted(void *array[], Count length, void QuickSort(void *array[], Count length, QuickSortCompare compare, void *closure) { - static Index seed = 0x6A9D03; struct { Index left, right; } stack[MPS_WORD_WIDTH]; @@ -683,8 +714,7 @@ void QuickSort(void *array[], Count length, for (;;) { while (right - left > 1) { /* no need to sort */ /* Pick a random pivot. */ - pivot = array[left + seed % (right - left)]; - seed = seed * 69069 + 1; + pivot = array[left + RandomWord() % (right - left)]; /* Hoare partition: scan from lo to hi, dividing it into elements less than the pivot and elements greater or equal. */ diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 01158fb0779..96f28ffc840 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -171,6 +171,9 @@ extern Res WriteF_firstformat_v(mps_lib_FILE *stream, Count depth, extern size_t StringLength(const char *s); extern Bool StringEqual(const char *s1, const char *s2); +extern unsigned Random32(void); +extern Word RandomWord(void); + typedef Compare QuickSortCompare(void *left, void *right, void *closure); extern void QuickSort(void *array[], Count length, From 9172773f9ca78104a07f5c2f7cec1000f06744c3 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 19 Mar 2016 10:15:10 +0000 Subject: [PATCH 276/337] Updating shield design and actually checking invariants in code. Copied from Perforce Change: 190192 ServerID: perforce.ravenbrook.com --- mps/code/global.c | 38 +++++++++++++----- mps/code/seg.c | 31 +++++++++------ mps/code/shield.c | 86 +++++++--------------------------------- mps/design/shield.txt | 92 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+), 93 deletions(-) diff --git a/mps/code/global.c b/mps/code/global.c index 6cba0902e95..d6522cc30e3 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -108,7 +108,6 @@ Bool GlobalsCheck(Globals arenaGlobals) TraceId ti; Trace trace; Index i; - Size depth; RefSet rs; Rank rank; @@ -161,16 +160,35 @@ Bool GlobalsCheck(Globals arenaGlobals) CHECKL(arena->shCacheI <= arena->shCacheLimit); CHECKL(BoolCheck(arena->suspended)); - depth = 0; - for (i = 0; i < arena->shCacheLimit; ++i) { - Seg seg = arena->shCache[i]; - if (seg != NULL) { - CHECKD(Seg, seg); - depth += SegDepth(seg); - } - } - CHECKL(depth <= arena->shDepth); + /* The mutator is not suspended while outside the shield + (design.mps.shield.inv.outside.running). */ + CHECKL(arena->insideShield || !arena->suspended); + /* If any segment is not synced, the mutator is suspended + (design.mps.shield.inv.unsynced.suspended). */ + CHECKL(arena->shDepth == 0 || arena->suspended); + + /* The total depth is zero while outside the shield + (design.mps.shield.inv.outside.depth). */ + CHECKL(arena->insideShield || arena->shDepth == 0); + + /* This is too expensive to check all the time since we have an + expanding shield cache that often has 16K elements instead of + 16. */ +#ifdef AVER_AND_CHECK_ALL + { + Count depth = 0; + for (i = 0; i < arena->shCacheLimit; ++i) { + Seg seg = arena->shCache[i]; + if (seg != NULL) { + CHECKD(Seg, seg); + depth += SegDepth(seg); + } + } + CHECKL(depth <= arena->shDepth); + } +#endif + CHECKL(TraceSetCheck(arena->busyTraces)); CHECKL(TraceSetCheck(arena->flippedTraces)); CHECKL(TraceSetSuper(arena->busyTraces, arena->flippedTraces)); diff --git a/mps/code/seg.c b/mps/code/seg.c index 04785652e90..6a7e5e40fac 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -1,7 +1,7 @@ /* seg.c: SEGMENTS * * $Id$ - * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * .design: The design for this module is . * @@ -16,14 +16,6 @@ * all current GC features, and providing full backwards compatibility * with "old-style" segments. It may be subclassed by clients of the * module. - * - * TRANSGRESSIONS - * - * .check.shield: The "pm", "sm", and "depth" fields are not checked by - * SegCheck, because I haven't spent time working out the invariants. - * We should certainly work them out, by studying , and - * assert things about shielding, protection, shield cache consistency, - * etc. richard 1997-04-03 */ #include "tract.h" @@ -223,6 +215,8 @@ static void SegFinish(Seg seg) seg->rankSet = RankSetEMPTY; /* See */ + /* FIXME: We can probably avoid doing this for segments not in the + cache by checking their depth. Zero depth => not in cache. */ ShieldFlush(PoolArena(SegPool(seg))); limit = SegLimit(seg); @@ -711,7 +705,22 @@ Bool SegCheck(Seg seg) CHECKD_NOSIG(Ring, &seg->poolRing); - /* "pm", "sm", and "depth" not checked. See .check.shield. */ + /* The protection mode is never more than the shield mode + (design.mps.shield.inv.prot.shield). */ + CHECKL(BS_DIFF(seg->pm, seg->sm) == 0); + + /* An exposed segment is not protected + (design.mps.shield.inv.expose.prot). FIXME: Discovered to be + FALSE when raising the read barrier on a write-protected + segment. RB 2016-03-19 */ + /* CHECKL(seg->depth == 0 || seg->pm == 0); */ + /* FIXME: Wouldn't it be better to have a flag for "in cache" so + that depth > 0 => exposed? */ + + /* All unsynced segments have positive depth + (design.mps.shield.inv.unsynced.depth). */ + CHECKL(seg->sm == seg->pm || seg->depth > 0); + CHECKL(RankSetCheck(seg->rankSet)); if (seg->rankSet == RankSetEMPTY) { /* : If there are no refs */ @@ -1674,7 +1683,7 @@ void SegClassMixInNoSplitMerge(SegClass class) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2015 Ravenbrook Limited . + * Copyright (C) 2001-2016 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 7fc9294b180..311984e9a21 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -5,71 +5,8 @@ * * See: idea.shield, design.mps.shield. * - * This implementation of the shield avoids suspending threads for - * as long as possible. When threads are suspended, it maintains a - * cache of covered segments where the desired and actual protection - * do not match. This cache is flushed on leaving the shield. - * - * - * Definitions - * - * .def.synced: a seg is synced if the prot and shield modes are the - * same, and unsynced otherwise. - * .def.depth: the depth of a segment is defined as - * depth == #exposes - #covers + #(in cache), where - * #exposes = the total number of times the seg has been exposed - * #covers = the total number of times the seg has been covered - * #(in cache) = the number of times the seg appears in the cache - * The cache is initially empty and Cover should not be called - * without a matching Expose, so this figure should always be - * non-negative. - * .def.total.depth: The total depth is the sum of the depth over - * all segments - * .def.outside: being outside the shield is being between calls - * to leave and enter, and similarly .def.inside: being inside the - * shield is being between calls to enter and leave. - * .def.suspended: suspended is true iff the mutator is suspended. - * .def.shielded: a segment is shielded if the shield mode is non-zero. - * - * - * Properties - * - * .prop.outside.running: The mutator may not be suspended while - * outside the shield. - * .prop.mutator.access: An attempt by the mutator to access - * shielded memory must cause an ArenaAccess. - * .prop.inside.access: Inside the shield it must be possible to access - * all unshielded segments and all exposed segments. - * - * - * Invariants - * - * These invariants are maintained by the code. - * - * .inv.outside.running: The mutator is not suspended while outside the - * shield. - * .inv.unsynced.suspended: If any segment is not synced, - * the mutator is suspended. - * .inv.unsynced.depth: All unsynced segments have positive depth. - * .inv.outside.depth: The total depth is zero while outside the shield. - * .inv.prot.shield: The prot mode is never more than the shield mode. - * .inv.expose.prot: An exposed seg is not protected. - * - * Hints at proofs of properties from invariants - * - * inv.outside.running directly ensures prop.outside running. - * - * As the depth of a segment cannot be negative - * total depth == 0 => for all segments, depth == 0 - * => all segs are synced (by .inv.unsynced.depth) - * - * If the mutator is running then all segs must be synced - * (.inv.unsynced.suspend). Which means that the hardware protection - * (prot mode) must reflect the software protection (shield mode). - * Hence all shielded memory will be hardware protected while the - * mutator is running. This ensures .prop.mutator.access. - * - * inv.prot.shield and inv.expose.prot ensure prop.inside.access. + * IMPORTANT: This code is subtle and critical. Ensure you have read + * and understood design.mps.shield before you touch it. */ #include "mpm.h" @@ -79,27 +16,29 @@ SRCID(shield, "$Id$"); /* shieldSegIsSynced -- is a segment synced? * - * See .def.synced. + * See design.mps.shield.def.synced. */ static Bool shieldSegIsSynced(Seg seg) { - AVERT_CRITICAL(Seg, seg); + AVER_CRITICAL(TESTT(Seg, seg)); return SegSM(seg) == SegPM(seg); } -/* shieldSync -- synchronize a segment's protection */ +/* shieldSync -- synchronize a segment's protection + * + * See design.mps.shield.inv.prot.shield. + */ static void shieldSync(Arena arena, Seg seg) { AVERT(Arena, arena); - AVERT(Seg, seg); + AVER_CRITICAL(TESTT(Seg, seg)); if (!shieldSegIsSynced(seg)) { ProtSet(SegBase(seg), SegLimit(seg), SegSM(seg)); SegSetPM(seg, SegSM(seg)); - /* See .inv.prot.shield. */ } } @@ -147,7 +86,7 @@ static void protLower(Arena arena, Seg seg, AccessSet mode) /* */ AVERT_CRITICAL(Arena, arena); UNUSED(arena); - AVERT_CRITICAL(Seg, seg); + AVER_CRITICAL(TESTT(Seg, seg)); AVERT_CRITICAL(AccessSet, mode); if (SegPM(seg) & mode) { @@ -285,7 +224,8 @@ static void shieldCache(Arena arena, Seg seg) { /* */ AVERT_CRITICAL(Arena, arena); - AVERT_CRITICAL(Seg, seg); + /* Can't fully check seg while we're enforcing its invariants. */ + AVER_CRITICAL(TESTT(Seg, seg)); if (shieldSegIsSynced(seg)) return; @@ -376,6 +316,8 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode) /* this point (this function is called to enforce them) so we */ /* can't check seg. Nor can we check arena as that checks the */ /* segs in the cache. */ + AVER(TESTT(Arena, arena)); + AVER(TESTT(Seg, seg)); AVERT(AccessSet, mode); AVER((SegSM(seg) & mode) == AccessSetEMPTY); diff --git a/mps/design/shield.txt b/mps/design/shield.txt index 42589a3c5e7..09e57d43e18 100644 --- a/mps/design/shield.txt +++ b/mps/design/shield.txt @@ -137,6 +137,98 @@ is re-established: the nurse is either the balancing ``ShieldCover()`` call in collector code, or an entry in the shield cache. +Implementation +-------------- + +.impl.delay: The implementation of the shield avoids suspending +threads for as long as possible. When threads are suspended, it +maintains a cache of covered segments where the desired and actual +protection do not match. This cache is flushed on leaving the shield. + + +Definitions +........... + +.def.synced: A seg is synced if the prot and shield modes are the +same, and unsynced otherwise. + +.def.depth: The depth of a segment is defined as: + + | depth ≔ #exposes − #covers + #(in cache), where + | #exposes = the total number of times the seg has been exposed + | #covers = the total number of times the seg has been covered + | #(in cache) = the number of times the seg appears in the cache + +The cache is initially empty and Cover should not be called without a +matching Expose, so this figure should always be non-negative. + +.def.total.depth: The total depth is the sum of the depth over +all segments. + +.def.outside: Being outside the shield is being between calls to leave +and enter, and similarly .def.inside: being inside the shield is being +between calls to enter and leave. + +.def.suspended: Suspended is true iff the mutator is suspended. + +.def.shielded: A segment is shielded if the shield mode is non-zero. + + +Properties +.......... + +.prop.outside.running: The mutator may not be suspended while outside +the shield. + +.prop.mutator.access: An attempt by the mutator to access shielded +memory must cause an ArenaAccess. + +.prop.inside.access: Inside the shield it must be possible to access +all unshielded segments and all exposed segments. + + +Invariants +.......... + +.inv.outside.running: The mutator is not suspended while outside the +shield. + +.inv.unsynced.suspended: If any segment is not synced, the mutator is +suspended. + +.inv.unsynced.depth: All unsynced segments have positive depth. + +.inv.outside.depth: The total depth is zero while outside the shield. + +.inv.prot.shield: The prot mode is never more than the shield mode. + +.inv.expose.prot: An exposed seg is not protected. + + +Proof Hints +........... + +Hints at proofs of properties from invariants. + +.proof.outside: .inv.outside.running directly ensures .prop.outside +running. + +.proof.sync: As the depth of a segment cannot be negative + + | total depth = 0 + | ⇒ for all segments, depth = 0 + | ⇒ all segs are synced (by .inv.unsynced.depth) + +.proof.access: If the mutator is running then all segs must be synced +(.inv.unsynced.suspend). Which means that the hardware protection +(.prot mode) must reflect the software protection (shield mode). +Hence all shielded memory will be hardware protected while the mutator +is running. This ensures .prop.mutator.access. + +.proof.inside: .inv.prot.shield and .inv.expose.prot ensure +.prop.inside.access. + + Initial ideas ------------- From 2c69ff0ce55e6ae17832c6e610c7c1873907618f Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 19 Mar 2016 10:19:14 +0000 Subject: [PATCH 277/337] Avoid shield flush when finishing a segment that isn't in the cache. Copied from Perforce Change: 190193 ServerID: perforce.ravenbrook.com --- mps/code/seg.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mps/code/seg.c b/mps/code/seg.c index 6a7e5e40fac..2a76f46685d 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -205,6 +205,11 @@ static void SegFinish(Seg seg) AVERT(SegClass, class); arena = PoolArena(SegPool(seg)); + + /* TODO: It would be good to avoid deprotecting segments eagerly + when we free them, especially if they're going to be + unmapped. This would require tracking of protection independent + of the existence of a SegStruct. */ if (seg->sm != AccessSetEMPTY) { ShieldLower(arena, seg, seg->sm); } @@ -215,9 +220,8 @@ static void SegFinish(Seg seg) seg->rankSet = RankSetEMPTY; /* See */ - /* FIXME: We can probably avoid doing this for segments not in the - cache by checking their depth. Zero depth => not in cache. */ - ShieldFlush(PoolArena(SegPool(seg))); + if (seg->depth > 0) + ShieldFlush(PoolArena(SegPool(seg))); limit = SegLimit(seg); From ff69c9af041da2feee2a77b841e94bce96f02be9 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 19 Mar 2016 13:42:09 +0000 Subject: [PATCH 278/337] Separating flag for segment in shield cache from depth, clarifying code and optimising segfree somewhat. Copied from Perforce Change: 190194 ServerID: perforce.ravenbrook.com --- mps/code/check.h | 11 +++- mps/code/global.c | 8 ++- mps/code/mpmst.h | 3 +- mps/code/seg.c | 17 +++---- mps/code/shield.c | 115 ++++++++++++++++++++++++------------------ mps/design/shield.txt | 47 ++++++++++------- 6 files changed, 116 insertions(+), 85 deletions(-) diff --git a/mps/code/check.h b/mps/code/check.h index a2450bebd9a..2a08160040e 100644 --- a/mps/code/check.h +++ b/mps/code/check.h @@ -39,6 +39,15 @@ #include "mpslib.h" +/* FIXME: to config.h? */ + +#if defined(MPS_BUILD_LL) || defined(MPS_BUILD_GC) +#define UNEXPECTED(expr) __builtin_expect((expr) != 0, TRUE) +#else +#define UNEXPECTED(expr) (expr) +#endif + + /* ASSERT -- basic assertion * * The ASSERT macro is equivalent to the ISO C assert() except that it is @@ -51,7 +60,7 @@ #define ASSERT(cond, condstring) \ BEGIN \ - if (cond) NOOP; else \ + if (UNEXPECTED(cond)) NOOP; else \ mps_lib_assert_fail(MPS_FILE, __LINE__, (condstring)); \ END diff --git a/mps/code/global.c b/mps/code/global.c index d6522cc30e3..ce8885daf04 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -175,15 +175,13 @@ Bool GlobalsCheck(Globals arenaGlobals) /* This is too expensive to check all the time since we have an expanding shield cache that often has 16K elements instead of 16. */ -#ifdef AVER_AND_CHECK_ALL +#if defined(AVER_AND_CHECK_ALL) { Count depth = 0; for (i = 0; i < arena->shCacheLimit; ++i) { Seg seg = arena->shCache[i]; - if (seg != NULL) { - CHECKD(Seg, seg); - depth += SegDepth(seg); - } + CHECKD(Seg, seg); + depth += SegDepth(seg); } CHECKL(depth <= arena->shDepth); } diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index ed28ce66214..1ee48063c8d 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -253,7 +253,8 @@ typedef struct SegStruct { /* segment structure */ Tract firstTract; /* first tract of segment */ RingStruct poolRing; /* link in list of segs in pool */ Addr limit; /* limit of segment */ - unsigned depth : ShieldDepthWIDTH; /* see */ + unsigned depth : ShieldDepthWIDTH; /* see design.mps.shield.def.depth */ + BOOLFIELD(cached); /* in shield cache? */ AccessSet pm : AccessLIMIT; /* protection mode, */ AccessSet sm : AccessLIMIT; /* shield mode, */ TraceSet grey : TraceLIMIT; /* traces for which seg is grey */ diff --git a/mps/code/seg.c b/mps/code/seg.c index 2a76f46685d..8f3fe37dcd7 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -150,6 +150,7 @@ static Res SegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) seg->pm = AccessSetEMPTY; seg->sm = AccessSetEMPTY; seg->depth = 0; + seg->cached = FALSE; seg->firstTract = NULL; seg->sig = SegSig; /* set sig now so tract checks will see it */ @@ -220,8 +221,10 @@ static void SegFinish(Seg seg) seg->rankSet = RankSetEMPTY; /* See */ - if (seg->depth > 0) + AVER(seg->depth == 0); + if (seg->cached) ShieldFlush(PoolArena(SegPool(seg))); + AVER(seg->cached == FALSE); limit = SegLimit(seg); @@ -713,17 +716,9 @@ Bool SegCheck(Seg seg) (design.mps.shield.inv.prot.shield). */ CHECKL(BS_DIFF(seg->pm, seg->sm) == 0); - /* An exposed segment is not protected - (design.mps.shield.inv.expose.prot). FIXME: Discovered to be - FALSE when raising the read barrier on a write-protected - segment. RB 2016-03-19 */ - /* CHECKL(seg->depth == 0 || seg->pm == 0); */ - /* FIXME: Wouldn't it be better to have a flag for "in cache" so - that depth > 0 => exposed? */ - - /* All unsynced segments have positive depth + /* All unsynced segments have positive depth or are in the cache (design.mps.shield.inv.unsynced.depth). */ - CHECKL(seg->sm == seg->pm || seg->depth > 0); + CHECKL(seg->sm == seg->pm || seg->depth > 0 || seg->cached); CHECKL(RankSetCheck(seg->rankSet)); if (seg->rankSet == RankSetEMPTY) { diff --git a/mps/code/shield.c b/mps/code/shield.c index 311984e9a21..af1ad934d67 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -25,6 +25,12 @@ static Bool shieldSegIsSynced(Seg seg) return SegSM(seg) == SegPM(seg); } +static Bool SegIsExposed(Seg seg) +{ + AVER_CRITICAL(TESTT(Seg, seg)); + return seg->depth > 0; +} + /* shieldSync -- synchronize a segment's protection * @@ -77,6 +83,7 @@ void (ShieldResume)(Arena arena) AVER(arena->insideShield); AVER(arena->suspended); /* It is only correct to actually resume the mutator here if shDepth is 0 */ + /* TODO: Consider actually doing that. */ } @@ -89,34 +96,35 @@ static void protLower(Arena arena, Seg seg, AccessSet mode) AVER_CRITICAL(TESTT(Seg, seg)); AVERT_CRITICAL(AccessSet, mode); - if (SegPM(seg) & mode) { - SegSetPM(seg, SegPM(seg) & ~mode); + if (BS_INTER(SegPM(seg), mode) != 0) { + SegSetPM(seg, BS_DIFF(SegPM(seg), mode)); ProtSet(SegBase(seg), SegLimit(seg), SegPM(seg)); } } -static void shieldFlushEntry(Arena arena, Size i) +/* shieldFlushEntry -- flush a single entry from the cache */ + +static void shieldFlushEntry(Arena arena, Index i) { Seg seg; - AVERT(Arena, arena); - AVER(i < arena->shCacheLimit); + AVERT(Arena, arena); seg = arena->shCache[i]; AVERT(Seg, seg); - AVER(arena->shDepth > 0); - AVER(SegDepth(seg) > 0); - --arena->shDepth; - SegSetDepth(seg, SegDepth(seg) - 1); + AVER(i < arena->shCacheLimit); + AVER(seg->cached); - if (SegDepth(seg) == 0) + if (!SegIsExposed(seg)) shieldSync(arena, seg); - arena->shCache[i] = NULL; /* just to make sure it gets overwritten */ + arena->shCache[i] = NULL; /* just to make sure it can't be reused */ } +/* shieldCacheEntryCompare -- comparison for cache sorting */ + static Compare shieldCacheEntryCompare(void *left, void *right, void *closure) { Seg segA = left, segB = right; @@ -162,32 +170,25 @@ static void shieldFlushEntries(Arena arena) { Addr base = NULL, limit = NULL; AccessSet mode; - Seg seg; - Size i; + Index i; - if (arena->shDepth == 0) { - AVER(arena->shCacheLimit == 0); + if (arena->shCacheLength == 0) { + AVER(arena->shCache == NULL); return; } - AVER(arena->shCache != NULL); - AVER(arena->shCacheLength > 0); - QuickSort((void *)arena->shCache, arena->shCacheLimit, shieldCacheEntryCompare, UNUSED_POINTER); mode = AccessSetEMPTY; for (i = 0; i < arena->shCacheLimit; ++i) { - AVER(arena->shDepth > 0); - - seg = arena->shCache[i]; - arena->shCache[i] = NULL; /* ensure it can't be reused */ + Seg seg = arena->shCache[i]; AVERT(Seg, seg); - AVER(SegDepth(seg) > 0); - --arena->shDepth; - SegSetDepth(seg, SegDepth(seg) - 1); + AVER(seg->cached); + seg->cached = FALSE; + arena->shCache[i] = NULL; /* ensure it can't be reused */ if (!shieldSegIsSynced(seg)) { AVER(SegSM(seg) != AccessSetEMPTY); /* can't match first iter */ @@ -216,8 +217,8 @@ static void shieldFlushEntries(Arena arena) /* shieldCache -- consider adding a segment to the cache * - * If the segment is out of sync, either sync it, or ensure depth > 0, - * and the arena is suspended. + * If the segment is out of sync, either sync it, or ensure it is + * cached and the arena is suspended. */ static void shieldCache(Arena arena, Seg seg) @@ -227,10 +228,10 @@ static void shieldCache(Arena arena, Seg seg) /* Can't fully check seg while we're enforcing its invariants. */ AVER_CRITICAL(TESTT(Seg, seg)); - if (shieldSegIsSynced(seg)) + if (shieldSegIsSynced(seg) || seg->cached) return; - - if (SegDepth(seg) > 0) { /* already in the cache or exposed? */ + + if (SegIsExposed(seg)) { /* This can occur if the mutator isn't suspended, we expose a segment, then raise the shield on it. In this case, the mutator isn't allowed to see the segment, but we don't need to @@ -279,11 +280,6 @@ static void shieldCache(Arena arena, Seg seg) return; } - SegSetDepth(seg, SegDepth(seg) + 1); - AVER_CRITICAL(SegDepth(seg) > 0); /* overflow */ - ++arena->shDepth; - AVER_CRITICAL(arena->shDepth > 0); /* overflow */ - AVER_CRITICAL(arena->shCacheLimit <= arena->shCacheLength); AVER_CRITICAL(arena->shCacheI <= arena->shCacheLimit); @@ -304,13 +300,14 @@ static void shieldCache(Arena arena, Seg seg) arena->shCache[arena->shCacheI] = seg; ++arena->shCacheI; + seg->cached = TRUE; if (arena->shCacheI >= arena->shCacheLimit) arena->shCacheLimit = arena->shCacheI; } -void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode) +void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode) { /* .seg.broken: Seg's shield invariants may not be true at */ /* this point (this function is called to enforce them) so we */ @@ -327,6 +324,7 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode) /* ensure .inv.unsynced.suspended and .inv.unsynced.depth */ shieldCache(arena, seg); + /* Check cache and segment consistency. */ AVERT(Arena, arena); AVERT(Seg, seg); } @@ -334,13 +332,17 @@ 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(Arena, arena); + AVER(TESTT(Seg, seg)); AVERT(AccessSet, mode); - AVER((SegSM(seg) & mode) == mode); + AVER(BS_INTER(SegSM(seg), mode) == mode); + /* synced(seg) is not changed by the following preserving inv.unsynced.suspended Also inv.prot.shield preserved */ - SegSetSM(seg, SegSM(seg) & ~mode); + SegSetSM(seg, BS_DIFF(SegSM(seg), mode)); protLower(arena, seg, mode); + + /* Check cache and segment consistency. */ AVERT(Arena, arena); AVERT(Seg, seg); } @@ -352,8 +354,6 @@ void (ShieldEnter)(Arena arena) AVER(!arena->insideShield); AVER(arena->shDepth == 0); AVER(!arena->suspended); - AVER(arena->shCacheLimit <= arena->shCacheLength); - AVER(arena->shCacheI <= arena->shCacheLimit); shieldCacheReset(arena); @@ -386,6 +386,7 @@ void (ShieldLeave)(Arena arena) AVER(arena->insideShield); ShieldFlush(arena); + /* Cache is empty so .inv.outside.depth holds */ AVER(arena->shDepth == 0); @@ -396,6 +397,20 @@ void (ShieldLeave)(Arena arena) arena->suspended = FALSE; } arena->insideShield = FALSE; + +#ifdef SHIELD_DEBUG + { + Seg seg; + if (SegFirst(&seg, arena)) + do { + AVER(!seg->cached); + AVER(shieldSegIsSynced(seg)); + /* You can directly set protections here to see if it makes a + difference. */ + ProtSet(SegBase(seg), SegLimit(seg), SegPM(seg)); + } while(SegNext(&seg, arena, seg)); + } +#endif } @@ -434,31 +449,33 @@ void (ShieldExpose)(Arena arena, Seg seg) AVER_CRITICAL(arena->insideShield); SegSetDepth(seg, SegDepth(seg) + 1); + AVER_CRITICAL(SegDepth(seg) > 0); /* overflow */ ++arena->shDepth; - /* */ - AVER_CRITICAL(arena->shDepth > 0); - AVER_CRITICAL(SegDepth(seg) > 0); - if (SegPM(seg) & mode) + AVER_CRITICAL(arena->shDepth > 0); /* overflow */ + + if (BS_INTER(SegPM(seg), mode)) ShieldSuspend(arena); - /* This ensures inv.expose.prot */ + /* Ensure design.mps.shield.inv.expose.prot. */ protLower(arena, seg, mode); } +/* ShieldCover -- declare MPS no longer needs access to seg */ + void (ShieldCover)(Arena arena, Seg seg) { /* */ AVERT_CRITICAL(Arena, arena); AVERT_CRITICAL(Seg, seg); AVER_CRITICAL(SegPM(seg) == AccessSetEMPTY); - - AVER_CRITICAL(arena->shDepth > 0); + AVER_CRITICAL(SegDepth(seg) > 0); SegSetDepth(seg, SegDepth(seg) - 1); + AVER_CRITICAL(arena->shDepth > 0); --arena->shDepth; - /* ensure inv.unsynced.depth */ + /* Ensure design.mps.shield.inv.unsynced.depth. */ shieldCache(arena, seg); } diff --git a/mps/design/shield.txt b/mps/design/shield.txt index 09e57d43e18..c3369750789 100644 --- a/mps/design/shield.txt +++ b/mps/design/shield.txt @@ -115,13 +115,9 @@ segment should be unprotected, and the Shield could re-instate hardware protection. However, as a performance-improving hysteresis, the Shield defers -re-protection, maintaining a cache reasons that a segment no longer -had a reason to be collector-accessible. Presence in the cache counts -as a reason: segments in the cache have ``seg->depth`` increased by -one. As segments get pushed out of the cache, or at ``ShieldLeave()``, -this artificial reason is decremented from ``seg->depth``, and (if -``seg->depth`` is now zero) the deferred reinstatement of hardware -protection happens. +re-protection, maintaining a cache of segments that no longer have a +reason to be collector-accessible. While a segment is in the cache, +it has ``seg->cached`` set to TRUE. This hysteresis allows the MPS to proceed with garbage collection during a pause without actually setting hardware protection until it @@ -154,20 +150,22 @@ same, and unsynced otherwise. .def.depth: The depth of a segment is defined as: - | depth ≔ #exposes − #covers + #(in cache), where + | depth ≔ #exposes − #covers, where | #exposes = the total number of times the seg has been exposed | #covers = the total number of times the seg has been covered - | #(in cache) = the number of times the seg appears in the cache -The cache is initially empty and Cover should not be called without a -matching Expose, so this figure should always be non-negative. +The cache is initially empty and ``ShieldCover`` should not be called +without a matching ``ShieldExpose``, so this figure should always be +non-negative. -.def.total.depth: The total depth is the sum of the depth over -all segments. +.def.total.depth: The total depth is the sum of the depth over all +segments. -.def.outside: Being outside the shield is being between calls to leave -and enter, and similarly .def.inside: being inside the shield is being -between calls to enter and leave. +.def.outside: Being outside the shield is being between calls to +``ShieldLeave`` and ``ShieldEnter``, and similarly .def.inside: being +inside the shield is being between calls to ``ShieldEnter`` and +``ShieldLeave``. [In a multi-threaded MPS this would be per-thread. +RB 2016-03-18] .def.suspended: Suspended is true iff the mutator is suspended. @@ -196,13 +194,15 @@ shield. .inv.unsynced.suspended: If any segment is not synced, the mutator is suspended. -.inv.unsynced.depth: All unsynced segments have positive depth. +.inv.unsynced.depth: All unsynced segments have positive depth or are +in the cache. .inv.outside.depth: The total depth is zero while outside the shield. .inv.prot.shield: The prot mode is never more than the shield mode. -.inv.expose.prot: An exposed seg is not protected. +.inv.expose.prot: An exposed seg is not protected in the mode it was +exposed with. Proof Hints @@ -236,6 +236,17 @@ _`.ideas`: There never was an initial design document, but [RB_1995-11-29]_ and [RB_1995-11-30]_ contain some initial ideas. +Improvement Ideas +----------------- + +.improv.mass-expose: If protection calls have a high overhead it might +be good to pre-emptively unprotect large ranges of memory when we +expose one segment. With the current design this would mean +discovering adjacent shielded segments and adding them to the cache. +The collector should take advantage of this by preferentially scanning +exposed segments during a pause. + + References ---------- From d280ff5c040b10acffec7b2ae0dfc5070bbc9ab0 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 19 Mar 2016 14:11:26 +0000 Subject: [PATCH 279/337] Fixing missing cache flag reset when a single entry is removed in low memory situations. Copied from Perforce Change: 190199 ServerID: perforce.ravenbrook.com --- mps/code/shield.c | 88 ++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 35 deletions(-) diff --git a/mps/code/shield.c b/mps/code/shield.c index af1ad934d67..9aae39ecf84 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -103,23 +103,27 @@ static void protLower(Arena arena, Seg seg, AccessSet mode) } +static Seg shieldDecache(Arena arena, Index i) +{ + Seg seg; + AVER(i < arena->shCacheLimit); + seg = arena->shCache[i]; + AVERT(Seg, seg); + AVER(seg->cached); + arena->shCache[i] = NULL; + seg->cached = FALSE; + return seg; +} + + /* shieldFlushEntry -- flush a single entry from the cache */ static void shieldFlushEntry(Arena arena, Index i) { - Seg seg; - - AVERT(Arena, arena); - seg = arena->shCache[i]; - AVERT(Seg, seg); - - AVER(i < arena->shCacheLimit); - AVER(seg->cached); + Seg seg = shieldDecache(arena, i); if (!SegIsExposed(seg)) shieldSync(arena, seg); - - arena->shCache[i] = NULL; /* just to make sure it can't be reused */ } @@ -182,14 +186,7 @@ static void shieldFlushEntries(Arena arena) mode = AccessSetEMPTY; for (i = 0; i < arena->shCacheLimit; ++i) { - Seg seg = arena->shCache[i]; - - AVERT(Seg, seg); - - AVER(seg->cached); - seg->cached = FALSE; - arena->shCache[i] = NULL; /* ensure it can't be reused */ - + Seg seg = shieldDecache(arena, i); if (!shieldSegIsSynced(seg)) { AVER(SegSM(seg) != AccessSetEMPTY); /* can't match first iter */ SegSetPM(seg, SegSM(seg)); @@ -361,6 +358,34 @@ void (ShieldEnter)(Arena arena) } +#if defined(SHIELD_DEBUG) +static void shieldDebugCheck(Arena arena) +{ + Seg seg; + Count cached = 0; + + AVERT(Arena, arena); + AVER(arena->insideShield || arena->shCacheLimit == 0); + + if (SegFirst(&seg, arena)) + do { + if (arena->shCacheLimit == 0) { + AVER(!seg->cached); + AVER(shieldSegIsSynced(seg)); + /* You can directly set protections here to see if it makes a + difference. */ + /* ProtSet(SegBase(seg), SegLimit(seg), SegPM(seg)); */ + } else { + if (seg->cached) + ++cached; + } + } while(SegNext(&seg, arena, seg)); + + AVER(cached == arena->shCacheLimit); +} +#endif + + /* ShieldFlush -- empty the shield cache * * .shield.flush: Flush empties the shield cache. This needs to be @@ -376,7 +401,15 @@ void (ShieldEnter)(Arena arena) void (ShieldFlush)(Arena arena) { +#ifdef SHIELD_DEBUG + shieldDebugCheck(arena); +#endif shieldFlushEntries(arena); + /* Cache is empty so .inv.outside.depth holds */ + AVER(arena->shDepth == 0); +#ifdef SHIELD_DEBUG + shieldDebugCheck(arena); +#endif } @@ -387,33 +420,18 @@ void (ShieldLeave)(Arena arena) ShieldFlush(arena); - /* Cache is empty so .inv.outside.depth holds */ - AVER(arena->shDepth == 0); - /* Ensuring the mutator is running at this point guarantees .inv.outside.running */ if (arena->suspended) { ThreadRingResume(ArenaThreadRing(arena), ArenaDeadRing(arena)); arena->suspended = FALSE; } - arena->insideShield = FALSE; -#ifdef SHIELD_DEBUG - { - Seg seg; - if (SegFirst(&seg, arena)) - do { - AVER(!seg->cached); - AVER(shieldSegIsSynced(seg)); - /* You can directly set protections here to see if it makes a - difference. */ - ProtSet(SegBase(seg), SegLimit(seg), SegPM(seg)); - } while(SegNext(&seg, arena, seg)); - } -#endif + arena->insideShield = FALSE; } + /* ShieldExpose -- allow the MPS access to a segment while denying the mutator * * The MPS currently does not collect concurrently, however the only thing From ca6aa07632ab89a7208e9e3c8c9e962abee51953 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 19 Mar 2016 14:47:54 +0000 Subject: [PATCH 280/337] Tidying up, especially special assertions. Copied from Perforce Change: 190204 ServerID: perforce.ravenbrook.com --- mps/code/shield.c | 124 ++++++++++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 47 deletions(-) diff --git a/mps/code/shield.c b/mps/code/shield.c index 9aae39ecf84..88959cfecfe 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -1,7 +1,7 @@ /* shield.c: SHIELD IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * See: idea.shield, design.mps.shield. * @@ -14,20 +14,39 @@ SRCID(shield, "$Id$"); -/* shieldSegIsSynced -- is a segment synced? +/* SHIELD_AVER -- transgressive argument checking + * + * .trans.check: A number of shield functions cannot do normal + * argument checking with AVERT because (for example) SegCheck checks + * the shield invariants, and it is these functions that are enforcing + * them. Instead, we AVER(TESTT(Seg, seg)) to check the type + * signature but not the contents. + */ + +#define SHIELD_AVERT(type, exp) AVER(TESTT(type, exp)) +#define SHIELD_AVERT_CRITICAL(type, exp) AVER_CRITICAL(TESTT(type, exp)) + + +/* SegIsSynced -- is a segment synced? * * See design.mps.shield.def.synced. */ -static Bool shieldSegIsSynced(Seg seg) +static Bool SegIsSynced(Seg seg) { - AVER_CRITICAL(TESTT(Seg, seg)); + SHIELD_AVERT_CRITICAL(Seg, seg); return SegSM(seg) == SegPM(seg); } + +/* SegIsExposed -- is a segment exposed? + * + * See design.mps.shield.def.exposed. + */ + static Bool SegIsExposed(Seg seg) { - AVER_CRITICAL(TESTT(Seg, seg)); + SHIELD_AVERT_CRITICAL(Seg, seg); return seg->depth > 0; } @@ -40,9 +59,9 @@ static Bool SegIsExposed(Seg seg) static void shieldSync(Arena arena, Seg seg) { AVERT(Arena, arena); - AVER_CRITICAL(TESTT(Seg, seg)); + SHIELD_AVERT_CRITICAL(Seg, seg); - if (!shieldSegIsSynced(seg)) { + if (!SegIsSynced(seg)) { ProtSet(SegBase(seg), SegLimit(seg), SegSM(seg)); SegSetPM(seg, SegSM(seg)); } @@ -87,22 +106,28 @@ void (ShieldResume)(Arena arena) } -/* This ensures actual prot mode does not include mode */ -static void protLower(Arena arena, Seg seg, AccessSet mode) +/* shieldProtLower -- reduce protection on a segment + * + * This ensures actual prot mode does not include mode. + */ + +static void shieldProtLower(Arena arena, Seg seg, AccessSet mode) { /* */ AVERT_CRITICAL(Arena, arena); UNUSED(arena); - AVER_CRITICAL(TESTT(Seg, seg)); + SHIELD_AVERT_CRITICAL(Seg, seg); AVERT_CRITICAL(AccessSet, mode); - if (BS_INTER(SegPM(seg), mode) != 0) { + if (BS_INTER(SegPM(seg), mode) != AccessSetEMPTY) { SegSetPM(seg, BS_DIFF(SegPM(seg), mode)); ProtSet(SegBase(seg), SegLimit(seg), SegPM(seg)); } } +/* shieldDecache -- remove a segment from the shield cache */ + static Seg shieldDecache(Arena arena, Index i) { Seg seg; @@ -127,35 +152,39 @@ static void shieldFlushEntry(Arena arena, Index i) } +/* shieldCacheReset -- reset shield cache pointers */ + +static void shieldCacheReset(Arena arena) +{ + AVER(arena->shDepth == 0); /* overkill: implies no segs are cached */ + arena->shCacheI = 0; + arena->shCacheLimit = 0; +} + + /* shieldCacheEntryCompare -- comparison for cache sorting */ +static Compare shieldAddrCompare(Addr left, Addr right) +{ + if (left < right) + return CompareLESS; + else if (left == right) + return CompareEQUAL; + else + return CompareGREATER; +} + static Compare shieldCacheEntryCompare(void *left, void *right, void *closure) { Seg segA = left, segB = right; - Addr baseA, baseB; - /* Making these CRITICAL had no effect on timings on LII6LL today. - RB 2016-03-17. */ - AVERT(Seg, segA); - AVERT(Seg, segB); + /* These checks are not critical in a hot build, but slow down cool + builds quite a bit, so just check the signatures. */ + AVER(TESTT(Seg, segA)); + AVER(TESTT(Seg, segB)); UNUSED(closure); - baseA = SegBase(segA); - baseB = SegBase(segB); - if (baseA < baseB) - return CompareLESS; - if (baseA > baseB) - return CompareGREATER; - AVER(baseA == baseB); - return CompareEQUAL; -} - - -static void shieldCacheReset(Arena arena) -{ - AVER(arena->shDepth == 0); - arena->shCacheI = 0; - arena->shCacheLimit = 0; + return shieldAddrCompare(SegBase(segA), SegBase(segB)); } @@ -187,7 +216,7 @@ static void shieldFlushEntries(Arena arena) mode = AccessSetEMPTY; for (i = 0; i < arena->shCacheLimit; ++i) { Seg seg = shieldDecache(arena, i); - if (!shieldSegIsSynced(seg)) { + if (!SegIsSynced(seg)) { AVER(SegSM(seg) != AccessSetEMPTY); /* can't match first iter */ SegSetPM(seg, SegSM(seg)); if (SegSM(seg) != mode || SegBase(seg) != limit) { @@ -222,10 +251,9 @@ static void shieldCache(Arena arena, Seg seg) { /* */ AVERT_CRITICAL(Arena, arena); - /* Can't fully check seg while we're enforcing its invariants. */ - AVER_CRITICAL(TESTT(Seg, seg)); + SHIELD_AVERT_CRITICAL(Seg, seg); - if (shieldSegIsSynced(seg) || seg->cached) + if (SegIsSynced(seg) || seg->cached) return; if (SegIsExposed(seg)) { @@ -304,14 +332,16 @@ static void shieldCache(Arena arena, Seg seg) } +/* ShieldRaise -- declare segment should be protected from mutator + * + * Does not immediately protect the segment, unless the segment is + * covered and the shield cache is unavailable. + */ + void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode) { - /* .seg.broken: Seg's shield invariants may not be true at */ - /* this point (this function is called to enforce them) so we */ - /* can't check seg. Nor can we check arena as that checks the */ - /* segs in the cache. */ - AVER(TESTT(Arena, arena)); - AVER(TESTT(Seg, seg)); + SHIELD_AVERT(Arena, arena); + SHIELD_AVERT(Seg, seg); AVERT(AccessSet, mode); AVER((SegSM(seg) & mode) == AccessSetEMPTY); @@ -330,14 +360,14 @@ void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode) void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) { AVERT(Arena, arena); - AVER(TESTT(Seg, seg)); + SHIELD_AVERT(Seg, seg); AVERT(AccessSet, mode); AVER(BS_INTER(SegSM(seg), mode) == mode); /* synced(seg) is not changed by the following preserving inv.unsynced.suspended Also inv.prot.shield preserved */ SegSetSM(seg, BS_DIFF(SegSM(seg), mode)); - protLower(arena, seg, mode); + shieldProtLower(arena, seg, mode); /* Check cache and segment consistency. */ AVERT(Arena, arena); @@ -371,7 +401,7 @@ static void shieldDebugCheck(Arena arena) do { if (arena->shCacheLimit == 0) { AVER(!seg->cached); - AVER(shieldSegIsSynced(seg)); + AVER(SegIsSynced(seg)); /* You can directly set protections here to see if it makes a difference. */ /* ProtSet(SegBase(seg), SegLimit(seg), SegPM(seg)); */ @@ -475,7 +505,7 @@ void (ShieldExpose)(Arena arena, Seg seg) ShieldSuspend(arena); /* Ensure design.mps.shield.inv.expose.prot. */ - protLower(arena, seg, mode); + shieldProtLower(arena, seg, mode); } @@ -500,7 +530,7 @@ void (ShieldCover)(Arena arena, Seg seg) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2015 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From ff0b6d1379c3868fe6f34348caf356935b81aaa5 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 19 Mar 2016 15:12:12 +0000 Subject: [PATCH 281/337] More documentation, tidying up, and cross-referencing. Copied from Perforce Change: 190205 ServerID: perforce.ravenbrook.com --- mps/code/shield.c | 72 ++++++++++++++++++++++++------------------- mps/design/shield.txt | 50 ++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 32 deletions(-) diff --git a/mps/code/shield.c b/mps/code/shield.c index 88959cfecfe..be5c3c80e04 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -5,8 +5,9 @@ * * See: idea.shield, design.mps.shield. * - * IMPORTANT: This code is subtle and critical. Ensure you have read - * and understood design.mps.shield before you touch it. + * IMPORTANT: HERE BE DRAGONS! This code is subtle and + * critical. Ensure you have read and understood design.mps.shield + * before you touch it. */ #include "mpm.h" @@ -196,7 +197,9 @@ static Compare shieldCacheEntryCompare(void *left, void *right, void *closure) * protection calls are extremely inefficient, but has no net gain on * Windows. * - * base, limit and mode represent outstanding protection to be done. + * TODO: Could we keep extending the outstanding area over memory + * that's *not* in the cache but has the same protection mode? Might + * require design.mps.shield.improve.noseg. */ static void shieldFlushEntries(Arena arena) @@ -357,6 +360,8 @@ void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode) } +/* ShieldLower -- declare segment may be accessed by mutator */ + void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) { AVERT(Arena, arena); @@ -364,9 +369,13 @@ void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) AVERT(AccessSet, mode); AVER(BS_INTER(SegSM(seg), mode) == mode); - /* synced(seg) is not changed by the following preserving - inv.unsynced.suspended Also inv.prot.shield preserved */ + /* SegIsSynced(seg) is not changed by the following preserving + design.mps.shield.inv.unsynced.suspended and + design.mps.shield.inv.prot.shield. */ SegSetSM(seg, BS_DIFF(SegSM(seg), mode)); + /* TODO: Do we need to promptly call shieldProtLower here? It + loses the opportunity to coalesce the protection call. It would + violate design.mps.shield.prop.inside.access. */ shieldProtLower(arena, seg, mode); /* Check cache and segment consistency. */ @@ -375,6 +384,8 @@ void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) } +/* ShieldEnter -- enter the shield, allowing exposes */ + void (ShieldEnter)(Arena arena) { AVERT(Arena, arena); @@ -388,6 +399,18 @@ void (ShieldEnter)(Arena arena) } +/* shieldDebugCheck -- expensive consistency check + * + * While developing the shield it is very easy to make a consistency + * mistake that causes random corruption of the heap, usually because + * all the attempts to avoid protection and suspension end up failing + * to enforce design.mps.shield.prop.mutator.access. In these cases, + * try enabling SHIELD_DEBUG and extending this code as necessary. + * + * The basic idea is to iterate over *all* segments and check + * consistency with the arena and shield cache. + */ + #if defined(SHIELD_DEBUG) static void shieldDebugCheck(Arena arena) { @@ -419,14 +442,15 @@ static void shieldDebugCheck(Arena arena) /* ShieldFlush -- empty the shield cache * * .shield.flush: Flush empties the shield cache. This needs to be - * called before segments are destroyed as there may be references to - * them in the cache. + * called before segments in the cache are destroyed, as there may be + * references to them in the cache. * * The memory for the segment may become spare, and not released back * to the operating system. Since we keep track of protection on * segments and not grains we have no way of keeping track of the * protection state of spare grains. We therefore flush the protection - * to get it back into the default state (unprotected). + * to get it back into the default state (unprotected). See also + * design.mps.shield.improv.noseg. */ void (ShieldFlush)(Arena arena) @@ -443,10 +467,13 @@ void (ShieldFlush)(Arena arena) } +/* ShieldLeave -- leave the shield, protect segs from mutator */ + void (ShieldLeave)(Arena arena) { AVERT(Arena, arena); AVER(arena->insideShield); + AVER(arena->shDepth == 0); /* no pending covers */ ShieldFlush(arena); @@ -464,29 +491,8 @@ void (ShieldLeave)(Arena arena) /* ShieldExpose -- allow the MPS access to a segment while denying the mutator * - * The MPS currently does not collect concurrently, however the only thing - * that makes it not-concurrent is a critical point in the Shield - * abstraction where the MPS seeks to gain privileged access to memory - * (usually in order to scan it for GC). The critical point is where - * ShieldExpose in shield.c has to call ShieldSuspend to preserve the - * shield invariants. This is the only point in the MPS that prevents - * concurrency, and the rest of the MPS is designed to support it. - * - * The restriction could be removed if either: - * - * * the MPS could use a different set of protections to the mutator - * program - * - * * the mutator program uses a software barrier - * - * The first one is tricky, and the second one just hasn't come up in any - * implementation we've been asked to make yet. Given a VM, it could - * happen, and the MPS would be concurrent. - * - * So, I believe there's nothing fundamentally non-concurrent about the - * MPS design. It's kind of waiting to happen. - * - * (Originally written at .) + * The first expose of a shielded segment suspends the mutator to + * ensure the MPS has exclusive access. */ void (ShieldExpose)(Arena arena, Seg seg) @@ -501,10 +507,12 @@ void (ShieldExpose)(Arena arena, Seg seg) ++arena->shDepth; AVER_CRITICAL(arena->shDepth > 0); /* overflow */ - if (BS_INTER(SegPM(seg), mode)) + if (BS_INTER(SegPM(seg), mode) != AccessSetEMPTY) ShieldSuspend(arena); /* Ensure design.mps.shield.inv.expose.prot. */ + /* TODO: Mass exposure -- see + design.mps.shield.improv.mass-expose. */ shieldProtLower(arena, seg, mode); } diff --git a/mps/design/shield.txt b/mps/design/shield.txt index c3369750789..57c2e309ae0 100644 --- a/mps/design/shield.txt +++ b/mps/design/shield.txt @@ -145,6 +145,9 @@ protection do not match. This cache is flushed on leaving the shield. Definitions ........... +.def.exposed: A seg is exposed if the prot mode is a subset of the +shield mode, and covered otherwise. + .def.synced: A seg is synced if the prot and shield modes are the same, and unsynced otherwise. @@ -239,6 +242,10 @@ _`.ideas`: There never was an initial design document, but Improvement Ideas ----------------- + +Mass exposure +............. + .improv.mass-expose: If protection calls have a high overhead it might be good to pre-emptively unprotect large ranges of memory when we expose one segment. With the current design this would mean @@ -247,6 +254,46 @@ The collector should take advantage of this by preferentially scanning exposed segments during a pause. +Segment independence +.................... + +.improve.noseg: The shield is implemented in terms of segments, using +fields in the segment structure to represent its state. This forces us +to (for example) flush the shield cache when deleting a segment. The +shield could keep track of protection and shielding independently, +possibly allowing greater coalescing and more efficient and flexible +use of system calls (see .improve.mass-expose). + + +Concurrent collection +..................... + +.improv.concurrent: The MPS currently does not collect concurrently, +however the only thing that makes it not-concurrent is a critical +point in the Shield abstraction where the MPS seeks to gain privileged +access to memory (usually in order to scan it for GC). The critical +point is where ShieldExpose in shield.c has to call ShieldSuspend to +preserve the shield invariants. This is the only point in the MPS that +prevents concurrency, and the rest of the MPS is designed to support +it. + +The restriction could be removed if either: + + * the MPS could use a different set of protections to the mutator + program + + * the mutator program uses a software barrier + +The first one is tricky, and the second one just hasn't come up in any +implementation we've been asked to make yet. Given a VM, it could +happen, and the MPS would be concurrent. + +So, I believe there's nothing fundamentally non-concurrent about the +MPS design. It's kind of waiting to happen. + +(Originally written at .) + + References ---------- @@ -275,6 +322,9 @@ Document History - 2016-03-17 RB_ Updated for dynamic cacheing and general code tidying that has removed complaints. +- 2016-03-19 RB_ Updated for separate cache flag on segments, changes + of invariants, cross-references, and ideas for future improvement. + .. _GDR: http://www.ravenbrook.com/consultants/gdr/ .. _RB: http://www.ravenbrook.com/consultants/rb/ From a6f292833547dd2a0452d6ab12428b9837a3348f Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 19 Mar 2016 19:40:00 +0000 Subject: [PATCH 282/337] Removing bogus todo. Copied from Perforce Change: 190212 ServerID: perforce.ravenbrook.com --- mps/code/trace.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mps/code/trace.c b/mps/code/trace.c index cc70e71c809..f86e13f5b5f 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1166,7 +1166,7 @@ static Res traceScanSegRes(TraceSet ts, Rank rank, Arena arena, Seg seg) AVER(RefSetSub(ScanStateUnfixedSummary(ss), SegSummary(seg))); /* Remembered set and write barrier */ - /* Was the scan necessary? Did the segment refer to the white set */ + /* Was the scan necessary? Did the segment refer to the white set? */ if (ZoneSetInter(ScanStateUnfixedSummary(ss), white) == ZoneSetEMPTY) { if (seg->defer > 0) --seg->defer; @@ -1176,9 +1176,6 @@ static Res traceScanSegRes(TraceSet ts, Rank rank, Arena arena, Seg seg) } /* Only apply the write barrier if it is not deferred. */ - /* TODO: This discards information we collected during - scanning. Consider keeping the summary but changing the - invariant on shielding instead. */ if (seg->defer == 0) { /* If we scanned every reference in the segment then we have a complete summary we can set. Otherwise, we just have From fde3757bac081b1c474812c3b4ebde2b99f3a374 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 19 Mar 2016 23:07:53 +0000 Subject: [PATCH 283/337] Tidying up and adding cross references to shiny new design document. Copied from Perforce Change: 190213 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 21 +++---- mps/code/trace.c | 29 ++++++--- mps/design/write-barrier.txt | 114 +++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 24 deletions(-) create mode 100644 mps/design/write-barrier.txt diff --git a/mps/code/config.h b/mps/code/config.h index 3a2165cd1d9..40702f86312 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -667,11 +667,10 @@ { 36 * 1024, 0.45 } /* second gen, after which dynamic */ \ } + /* Write barrier deferral * - * Defer using the write barrier for the remembered set until a number - * of unnecessary scans have been performed on a segment. Avoids - * memory protection costs when scanning might be cheaper. See job003975. + * See design.mps.write-barrier.deferral. * * TODO: These settings were determined by trial and error, but should * be based on measurement of the protection overhead on each @@ -682,17 +681,11 @@ * passed in the mutator rather than the number of scans. */ -/* Number of bits needed to keep the write barrier deferral count */ -#define WB_DEFER_BITS 3 -/* The number of unecessary scans performed, before raising the write - barrier to maintian the remembered set. */ -#define WB_DEFER_INIT 3 -/* The number of unecessary scans performed, before raising the write - barrier to remember the refset summary, after a necessary scan */ -#define WB_DEFER_DELAY WB_DEFER_INIT -/* The number of unecessary scans performed, before raising the write - * barrier to remember the refset summary, after a barrier hit */ -#define WB_DEFER_AFTER_HIT 1 +#define WB_DEFER_BITS 3 /* bitfield width for deferral count */ +#define WB_DEFER_INIT 3 /* boring scans after new segment */ +#define WB_DEFER_DELAY 3 /* boring scans after interesting scan */ +#define WB_DEFER_HIT 1 /* boring scans after barrier hit */ + #endif /* config_h */ diff --git a/mps/code/trace.c b/mps/code/trace.c index f86e13f5b5f..6e48ef5684b 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1165,12 +1165,14 @@ static Res traceScanSegRes(TraceSet ts, Rank rank, Arena arena, Seg seg) */ AVER(RefSetSub(ScanStateUnfixedSummary(ss), SegSummary(seg))); - /* Remembered set and write barrier */ - /* Was the scan necessary? Did the segment refer to the white set? */ + /* Write barrier deferral -- see design.mps.write-barrier.deferral. */ + /* Did the segment refer to the white set? */ if (ZoneSetInter(ScanStateUnfixedSummary(ss), white) == ZoneSetEMPTY) { + /* Boring scan. One step closer to raising the write barrier. */ if (seg->defer > 0) --seg->defer; } else { + /* Interesting scan. Defer raising the write barrier. */ if (seg->defer < WB_DEFER_DELAY) seg->defer = WB_DEFER_DELAY; } @@ -1229,27 +1231,34 @@ static Res traceScanSeg(TraceSet ts, Rank rank, Arena arena, Seg seg) void TraceSegAccess(Arena arena, Seg seg, AccessSet mode) { Res res; + AccessSet shieldHit; + Bool readHit, writeHit; AVERT(Arena, arena); AVERT(Seg, seg); AVERT(AccessSet, mode); + shieldHit = BS_INTER(mode, SegSM(seg)); + readHit = BS_INTER(shieldHit, AccessREAD) != AccessSetEMPTY; + writeHit = BS_INTER(shieldHit, AccessWRITE) != AccessSetEMPTY; + /* If it's a read access, then the segment must be grey for a trace */ /* which is flipped. */ - AVER((mode & SegSM(seg) & AccessREAD) == 0 - || TraceSetInter(SegGrey(seg), arena->flippedTraces) != TraceSetEMPTY); + AVER(!readHit || + TraceSetInter(SegGrey(seg), arena->flippedTraces) != TraceSetEMPTY); /* If it's a write access, then the segment must have a summary that */ /* is smaller than the mutator's summary (which is assumed to be */ /* RefSetUNIV). */ - AVER((mode & SegSM(seg) & AccessWRITE) == 0 || SegSummary(seg) != RefSetUNIV); + AVER(!writeHit || SegSummary(seg) != RefSetUNIV); EVENT3(TraceAccess, arena, seg, mode); - if ((mode & SegSM(seg) & AccessWRITE) != 0) /* write barrier? */ - seg->defer = WB_DEFER_AFTER_HIT; + /* Write barrier deferral -- see design.mps.write-barrier.deferral. */ + if (writeHit) + seg->defer = WB_DEFER_HIT; - if((mode & SegSM(seg) & AccessREAD) != 0) { /* read barrier? */ + if (readHit) { Trace trace; TraceId ti; Rank rank; @@ -1283,11 +1292,11 @@ void TraceSegAccess(Arena arena, Seg seg, AccessSet mode) /* The write barrier handling must come after the read barrier, */ /* because the latter may set the summary and raise the write barrier. */ - if((mode & SegSM(seg) & AccessWRITE) != 0) /* write barrier? */ + if (writeHit) SegSetSummary(seg, RefSetUNIV); /* The segment must now be accessible. */ - AVER((mode & SegSM(seg)) == AccessSetEMPTY); + AVER(BS_INTER(mode, SegSM(seg)) == AccessSetEMPTY); } diff --git a/mps/design/write-barrier.txt b/mps/design/write-barrier.txt new file mode 100644 index 00000000000..2a712ddd99c --- /dev/null +++ b/mps/design/write-barrier.txt @@ -0,0 +1,114 @@ +.. mode: -*- rst -*- + +Write barrier +============= + +:Tag: design.mps.write-barrier +:Author: Richard Brooksby +:Date: 2016-03-18 +:Status: incomplete design +:Revision: $Id$ +:Copyright: See `Copyright and License`_. +:Index terms: pair: write barrier; design + + +Introduction +------------ + +.intro: This document explains the design of the write barrer of the +Memory Pool System (MPS). + +.readership: This document is intended for developers of the MPS. + + +Overview +-------- + +.overview: The MPS uses a combination of hardware memory protection +and BIBOP techniques to maintain an approximate remembered set. The +remembered set keeps track of areas of memory that refer to each +other, so that the MPS can avoid scanning areas that are irrelevant +during a garbage collection. The MPS write barrier is implemented by +a one-word "summary" of the zones referenced by a segment. That +summary can be compared with the "white set" of a trace by a simple +logical AND operation. + +[At this point I was interrupted by a man from Porlock.] + + +Write barrier deferral +---------------------- + +.deferral: The overheads hardware barriers varies widely between +operating systems. On Windows it is very cheap to change memory +protection and to handle protecion faults. On OS X it is very +expensive. The balance between barriers and scanning work is +different. There is no point in spending 1000 CPU units raising a +write barrier to avoid 10 CPU units of scanning cost. + +The MPS balances these costs with write barrier deferral. The write +barrier is not immediately raised when a segment is scanned. Instead, +we store a deferral count with the segment. Each time the segment is +"boring" scanned the count is decremented. A boring scan is one that +found no interesting references (to white objects). The write barrier +is raised only when the count reaches zero. The count is reset after +three events: + +1. segment creation (``WB_DEFER_INIT``) + +2. an interesting scan (``WB_DEFER_DELAY``) + +3. a barrier hit (``WB_DEFER_HIT``) + +See also job003975. + + +Document History +---------------- + +- 2016-03-19 RB_ Created. + +.. _RB: http://www.ravenbrook.com/consultants/rb/ + + +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.** From 2469f09e6e0e66c8082b1e3b257be495db8ec7c6 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 19 Mar 2016 23:31:00 +0000 Subject: [PATCH 284/337] Improving design document with references and separating ideas from current implementation. Copied from Perforce Change: 190214 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 2 +- mps/design/write-barrier.txt | 38 ++++++++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index 40702f86312..b7de3a7a227 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -675,7 +675,7 @@ * TODO: These settings were determined by trial and error, but should * be based on measurement of the protection overhead on each * platform. We know it's extremely different between OS X and - * Windows, for example. + * Windows, for example. See design.mps.write-barrier.improv.by-os. * * TODO: Consider basing the count on the amount of time that has * passed in the mutator rather than the number of scans. diff --git a/mps/design/write-barrier.txt b/mps/design/write-barrier.txt index 2a712ddd99c..affdaa49c5d 100644 --- a/mps/design/write-barrier.txt +++ b/mps/design/write-barrier.txt @@ -39,12 +39,9 @@ logical AND operation. Write barrier deferral ---------------------- -.deferral: The overheads hardware barriers varies widely between -operating systems. On Windows it is very cheap to change memory -protection and to handle protecion faults. On OS X it is very -expensive. The balance between barriers and scanning work is -different. There is no point in spending 1000 CPU units raising a -write barrier to avoid 10 CPU units of scanning cost. +.deferral: Both scanning and the write barrier cost CPU time, and +these must be balanced. There is no point spending 1000 CPU units +raising a write barrier to avoid 10 CPU units of scanning cost. The MPS balances these costs with write barrier deferral. The write barrier is not immediately raised when a segment is scanned. Instead, @@ -60,13 +57,38 @@ three events: 3. a barrier hit (``WB_DEFER_HIT``) -See also job003975. + +Improvements +------------ + +.improv.by-os: The overheads hardware barriers varies widely between +operating systems. On Windows it is very cheap to change memory +protection and to handle protecion faults. On OS X it is very +expensive. The balance between barriers and scanning work is +different. We should measure the relative costs and tune the deferral +for each separately. + +.improv.balance: Hardware costs of write barriers vary by OS, but +scanning costs vary depending on many factors including client code. +The MPS could dynamically measure these costs, perhaps using fast +cycle counters such as RDTSC, and use this to dynamically balance the +write barrier deferral. +References +---------- + +.. [job003975] "Poor performance due to imbalance between protection + and scanning costs"; Richard Brooksby; Ravenbrook + Limited; 2016-03-11; + . + + Document History ---------------- -- 2016-03-19 RB_ Created. +- 2016-03-19 RB_ Created during preparation of + branch/2016-03-13/defer-write-barrier for [job003975]_. .. _RB: http://www.ravenbrook.com/consultants/rb/ From e09dbaab0fb182fd570d6da4238b4108ba2cad27 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 20 Mar 2016 00:32:43 +0000 Subject: [PATCH 285/337] Promoting shield to first class structure. Copied from Perforce Change: 190219 ServerID: perforce.ravenbrook.com --- mps/code/global.c | 60 +--------- mps/code/mpm.h | 4 + mps/code/mpmst.h | 33 ++++-- mps/code/mpmtypes.h | 1 + mps/code/poolmrg.c | 2 +- mps/code/shield.c | 270 +++++++++++++++++++++++++++++++------------- 6 files changed, 226 insertions(+), 144 deletions(-) diff --git a/mps/code/global.c b/mps/code/global.c index ce8885daf04..111404d03f8 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -154,39 +154,8 @@ Bool GlobalsCheck(Globals arenaGlobals) CHECKD_NOSIG(Ring, &arena->threadRing); CHECKD_NOSIG(Ring, &arena->deadRing); - CHECKL(BoolCheck(arena->insideShield)); - CHECKL(arena->shCache == NULL || arena->shCacheLength > 0); - CHECKL(arena->shCacheLimit <= arena->shCacheLength); - CHECKL(arena->shCacheI <= arena->shCacheLimit); - CHECKL(BoolCheck(arena->suspended)); + CHECKD_NOSIG(Shield, &arena->shieldStruct); /* FIXME: Sig */ - /* The mutator is not suspended while outside the shield - (design.mps.shield.inv.outside.running). */ - CHECKL(arena->insideShield || !arena->suspended); - - /* If any segment is not synced, the mutator is suspended - (design.mps.shield.inv.unsynced.suspended). */ - CHECKL(arena->shDepth == 0 || arena->suspended); - - /* The total depth is zero while outside the shield - (design.mps.shield.inv.outside.depth). */ - CHECKL(arena->insideShield || arena->shDepth == 0); - - /* This is too expensive to check all the time since we have an - expanding shield cache that often has 16K elements instead of - 16. */ -#if defined(AVER_AND_CHECK_ALL) - { - Count depth = 0; - for (i = 0; i < arena->shCacheLimit; ++i) { - Seg seg = arena->shCache[i]; - CHECKD(Seg, seg); - depth += SegDepth(seg); - } - CHECKL(depth <= arena->shDepth); - } -#endif - CHECKL(TraceSetCheck(arena->busyTraces)); CHECKL(TraceSetCheck(arena->flippedTraces)); CHECKL(TraceSetSuper(arena->busyTraces, arena->flippedTraces)); @@ -311,13 +280,7 @@ Res GlobalsInit(Globals arenaGlobals) arena->tracedWork = 0.0; arena->tracedTime = 0.0; arena->lastWorldCollect = ClockNow(); - arena->insideShield = FALSE; /* */ - arena->shCache = NULL; - arena->shCacheLength = 0; - arena->shCacheI = (Size)0; - arena->shCacheLimit = (Size)0; - arena->shDepth = (Size)0; - arena->suspended = FALSE; + ShieldInit(&arena->shieldStruct); for (ti = 0; ti < TraceLIMIT; ++ti) { /* */ @@ -455,14 +418,7 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) arena = GlobalsArena(arenaGlobals); - /* Delete the shield cache, if it exists. */ - if (arena->shCacheLength != 0) { - AVER(arena->shCache != NULL); - ControlFree(arena, arena->shCache, - arena->shCacheLength * sizeof arena->shCache[0]); - arena->shCache = NULL; - arena->shCacheLength = 0; - } + ShieldFinish(&arena->shieldStruct, arena); arenaDenounce(arena); @@ -1027,7 +983,6 @@ Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth) "rootSerial $U\n", (WriteFU)arenaGlobals->rootSerial, "formatSerial $U\n", (WriteFU)arena->formatSerial, "threadSerial $U\n", (WriteFU)arena->threadSerial, - arena->insideShield ? "inside" : "outside", " shield\n", "busyTraces $B\n", (WriteFB)arena->busyTraces, "flippedTraces $B\n", (WriteFB)arena->flippedTraces, "epoch $U\n", (WriteFU)arena->epoch, @@ -1046,14 +1001,7 @@ Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth) return res; } - res = WriteF(stream, depth, - "} history\n", - "suspended $S\n", WriteFYesNo(arena->suspended), - "shDepth $U\n", (WriteFU)arena->shDepth, - "shCacheI $U\n", (WriteFU)arena->shCacheI, - "shCacheLength $U\n", (WriteFU)arena->shCacheLength, - /* @@@@ should SegDescribe the cached segs? */ - NULL); + res = ShieldDescribe(&arena->shieldStruct, stream, depth); if (res != ResOK) return res; diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 96f28ffc840..21e9e82182a 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -907,6 +907,10 @@ extern ZoneSet ZoneSetBlacklist(Arena arena); /* Shield Interface -- see */ +extern void ShieldInit(Shield shield); +extern void ShieldFinish(Shield shield, Arena arena); +extern Bool ShieldCheck(Shield shield); +extern Res ShieldDescribe(Shield shield, mps_lib_FILE *stream, Count depth); extern void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode); extern void (ShieldLower)(Arena arena, Seg seg, AccessSet mode); extern void (ShieldEnter)(Arena arena); diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 1ee48063c8d..29ad117bbcd 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -677,9 +677,29 @@ typedef struct FreelistStruct { } FreelistStruct; +/* ShieldStruct -- per-arena part of the shield + * + * See design.mps.shield, impl.c.shield. + */ + +#define ShieldSig ((Sig)0x519581E1) /* SIGnature SHEILd */ + +typedef struct ShieldStruct { + Sig sig; + Bool inside; /* TRUE if and only if inside shield */ + Seg *cache; /* Cache of unsynced segs */ + Count length; /* number of elements in shield cache */ + Index i; /* index into cache */ + Index limit; /* High water mark for cache usage */ + Count depth; /* sum of depths of all segs */ + Bool suspended; /* TRUE iff mutator suspended */ +} ShieldStruct; + + /* ArenaStruct -- generic arena * - * See . */ + * See . + */ #define ArenaSig ((Sig)0x519A6E4A) /* SIGnature ARENA */ @@ -737,16 +757,9 @@ typedef struct mps_arena_s { RingStruct threadRing; /* ring of attached threads */ RingStruct deadRing; /* ring of dead threads */ Serial threadSerial; /* serial of next thread */ - - /* shield fields () */ - Bool insideShield; /* TRUE if and only if inside shield */ - Seg *shCache; /* Cache of unsynced segs */ - Count shCacheLength; - Size shCacheI; /* index into cache */ - Size shCacheLimit; /* High water mark for cache usage */ - Size shDepth; /* sum of depths of all segs */ - Bool suspended; /* TRUE iff mutator suspended */ + ShieldStruct shieldStruct; + /* trace fields () */ TraceSet busyTraces; /* set of running traces */ TraceSet flippedTraces; /* set of running and flipped traces */ diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 2e0837940a2..f001038bc9f 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -112,6 +112,7 @@ typedef struct RangeStruct *Range; /* */ typedef struct LandStruct *Land; /* */ typedef struct LandClassStruct *LandClass; /* */ typedef unsigned FindDelete; /* */ +typedef struct ShieldStruct *Shield; /* design.mps.shield */ /* Arena*Method -- see */ diff --git a/mps/code/poolmrg.c b/mps/code/poolmrg.c index 92b1819fa68..554ec2a7319 100644 --- a/mps/code/poolmrg.c +++ b/mps/code/poolmrg.c @@ -821,7 +821,7 @@ static Res MRGDescribe(Pool pool, mps_lib_FILE *stream, Count depth) if (res != ResOK) return res; RING_FOR(node, &mrg->entryRing, nextNode) { - Bool outsideShield = !arena->insideShield; + Bool outsideShield = !arena->shieldStruct.inside; refPart = MRGRefPartOfLink(linkOfRing(node), arena); if (outsideShield) { ShieldEnter(arena); diff --git a/mps/code/shield.c b/mps/code/shield.c index be5c3c80e04..8ba806a701a 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -15,6 +15,95 @@ SRCID(shield, "$Id$"); +void ShieldInit(Shield shield) +{ + shield->inside = FALSE; + shield->cache = NULL; + shield->length = 0; + shield->i = 0; + shield->limit = 0; + shield->depth = 0; + shield->suspended = FALSE; + shield->sig = ShieldSig; +} + + +void ShieldFinish(Shield shield, Arena arena) +{ + shield->sig = SigInvalid; + /* Delete the shield cache, if it exists. */ + if (shield->length != 0) { + AVER(shield->cache != NULL); + ControlFree(arena, shield->cache, + shield->length * sizeof shield->cache[0]); + shield->cache = NULL; + shield->length = 0; + } +} + + +Bool ShieldCheck(Shield shield) +{ + CHECKS(Shield, shield); + CHECKL(BoolCheck(shield->inside)); + CHECKL(shield->cache == NULL || shield->length > 0); + CHECKL(shield->limit <= shield->length); + CHECKL(shield->i <= shield->limit); + CHECKL(BoolCheck(shield->suspended)); + + /* The mutator is not suspended while outside the shield + (design.mps.shield.inv.outside.running). */ + CHECKL(shield->inside || !shield->suspended); + + /* If any segment is not synced, the mutator is suspended + (design.mps.shield.inv.unsynced.suspended). */ + CHECKL(shield->depth == 0 || shield->suspended); + + /* The total depth is zero while outside the shield + (design.mps.shield.inv.outside.depth). */ + CHECKL(shield->inside || shield->depth == 0); + + /* This is too expensive to check all the time since we have an + expanding shield cache that often has 16K elements instead of + 16. */ +#if defined(AVER_AND_CHECK_ALL) + { + Count depth = 0; + Index i; + for (i = 0; i < shield->limit; ++i) { + Seg seg = shield->cache[i]; + CHECKD(Seg, seg); + depth += SegDepth(seg); + } + CHECKL(depth <= shield->depth); + } +#endif + + return TRUE; +} + + +Res ShieldDescribe(Shield shield, mps_lib_FILE *stream, Count depth) +{ + Res res; + + res = WriteF(stream, depth, + shield->inside ? "inside" : "outside", " shield\n", + "suspended $S\n", WriteFYesNo(shield->suspended), + "shield depth $U\n", (WriteFU)shield->depth, + "shield i $U\n", (WriteFU)shield->i, + "shield length $U\n", (WriteFU)shield->length, + NULL); + if (res != ResOK) + return res; + + return ResOK; +} + + +#define ArenaShield(arena) (&(arena)->shieldStruct) + + /* SHIELD_AVER -- transgressive argument checking * * .trans.check: A number of shield functions cannot do normal @@ -57,9 +146,9 @@ static Bool SegIsExposed(Seg seg) * See design.mps.shield.inv.prot.shield. */ -static void shieldSync(Arena arena, Seg seg) +static void shieldSync(Shield shield, Seg seg) { - AVERT(Arena, arena); + UNUSED(shield); SHIELD_AVERT_CRITICAL(Seg, seg); if (!SegIsSynced(seg)) { @@ -81,12 +170,15 @@ static void shieldSync(Arena arena, Seg seg) void (ShieldSuspend)(Arena arena) { + Shield shield; + AVERT(Arena, arena); - AVER(arena->insideShield); + shield = ArenaShield(arena); + AVER(shield->inside); - if (!arena->suspended) { + if (!shield->suspended) { ThreadRingSuspend(ArenaThreadRing(arena), ArenaDeadRing(arena)); - arena->suspended = TRUE; + shield->suspended = TRUE; } } @@ -99,9 +191,13 @@ void (ShieldSuspend)(Arena arena) void (ShieldResume)(Arena arena) { + Shield shield; + AVERT(Arena, arena); - AVER(arena->insideShield); - AVER(arena->suspended); + shield = ArenaShield(arena); + AVER(shield->inside); + AVER(shield->suspended); + /* It is only correct to actually resume the mutator here if shDepth is 0 */ /* TODO: Consider actually doing that. */ } @@ -112,11 +208,9 @@ void (ShieldResume)(Arena arena) * This ensures actual prot mode does not include mode. */ -static void shieldProtLower(Arena arena, Seg seg, AccessSet mode) +static void shieldProtLower(Seg seg, AccessSet mode) { /* */ - AVERT_CRITICAL(Arena, arena); - UNUSED(arena); SHIELD_AVERT_CRITICAL(Seg, seg); AVERT_CRITICAL(AccessSet, mode); @@ -129,14 +223,14 @@ static void shieldProtLower(Arena arena, Seg seg, AccessSet mode) /* shieldDecache -- remove a segment from the shield cache */ -static Seg shieldDecache(Arena arena, Index i) +static Seg shieldDecache(Shield shield, Index i) { Seg seg; - AVER(i < arena->shCacheLimit); - seg = arena->shCache[i]; + AVER(i < shield->limit); + seg = shield->cache[i]; AVERT(Seg, seg); AVER(seg->cached); - arena->shCache[i] = NULL; + shield->cache[i] = NULL; seg->cached = FALSE; return seg; } @@ -144,22 +238,22 @@ static Seg shieldDecache(Arena arena, Index i) /* shieldFlushEntry -- flush a single entry from the cache */ -static void shieldFlushEntry(Arena arena, Index i) +static void shieldFlushEntry(Shield shield, Index i) { - Seg seg = shieldDecache(arena, i); + Seg seg = shieldDecache(shield, i); if (!SegIsExposed(seg)) - shieldSync(arena, seg); + shieldSync(shield, seg); } /* shieldCacheReset -- reset shield cache pointers */ -static void shieldCacheReset(Arena arena) +static void shieldCacheReset(Shield shield) { - AVER(arena->shDepth == 0); /* overkill: implies no segs are cached */ - arena->shCacheI = 0; - arena->shCacheLimit = 0; + AVER(shield->depth == 0); /* overkill: implies no segs are cached */ + shield->i = 0; + shield->limit = 0; } @@ -202,23 +296,23 @@ static Compare shieldCacheEntryCompare(void *left, void *right, void *closure) * require design.mps.shield.improve.noseg. */ -static void shieldFlushEntries(Arena arena) +static void shieldFlushEntries(Shield shield) { Addr base = NULL, limit = NULL; AccessSet mode; Index i; - if (arena->shCacheLength == 0) { - AVER(arena->shCache == NULL); + if (shield->length == 0) { + AVER(shield->cache == NULL); return; } - QuickSort((void *)arena->shCache, arena->shCacheLimit, + QuickSort((void *)shield->cache, shield->limit, shieldCacheEntryCompare, UNUSED_POINTER); mode = AccessSetEMPTY; - for (i = 0; i < arena->shCacheLimit; ++i) { - Seg seg = shieldDecache(arena, i); + for (i = 0; i < shield->limit; ++i) { + Seg seg = shieldDecache(shield, i); if (!SegIsSynced(seg)) { AVER(SegSM(seg) != AccessSetEMPTY); /* can't match first iter */ SegSetPM(seg, SegSM(seg)); @@ -240,7 +334,7 @@ static void shieldFlushEntries(Arena arena) ProtSet(base, limit, mode); } - shieldCacheReset(arena); + shieldCacheReset(shield); } @@ -252,8 +346,11 @@ static void shieldFlushEntries(Arena arena) static void shieldCache(Arena arena, Seg seg) { + Shield shield; + /* */ AVERT_CRITICAL(Arena, arena); + shield = ArenaShield(arena); SHIELD_AVERT_CRITICAL(Seg, seg); if (SegIsSynced(seg) || seg->cached) @@ -271,31 +368,31 @@ static void shieldCache(Arena arena, Seg seg) /* Allocate shield cache if necessary. */ /* TODO: This will try to extend the cache on every attempt, even if it failed last time. That might be slow. */ - if (arena->shCacheI >= arena->shCacheLength) { + if (shield->i >= shield->length) { void *p; Res res; Count length; - AVER(arena->shCacheI == arena->shCacheLength); + AVER(shield->i == shield->length); - if (arena->shCacheLength == 0) + if (shield->length == 0) length = ShieldCacheLENGTH; else - length = arena->shCacheLength * 2; + length = shield->length * 2; - res = ControlAlloc(&p, arena, length * sizeof arena->shCache[0]); + res = ControlAlloc(&p, arena, length * sizeof shield->cache[0]); if (res != ResOK) { AVER(ResIsAllocFailure(res)); /* Carry on with the existing cache. */ } else { - if (arena->shCacheLength > 0) { - Size oldSize = arena->shCacheLength * sizeof arena->shCache[0]; - AVER(arena->shCache != NULL); - mps_lib_memcpy(p, arena->shCache, oldSize); - ControlFree(arena, arena->shCache, oldSize); + if (shield->length > 0) { + Size oldSize = shield->length * sizeof shield->cache[0]; + AVER(shield->cache != NULL); + mps_lib_memcpy(p, shield->cache, oldSize); + ControlFree(arena, shield->cache, oldSize); } - arena->shCache = p; - arena->shCacheLength = length; + shield->cache = p; + shield->length = length; } } @@ -303,35 +400,35 @@ static void shieldCache(Arena arena, Seg seg) yet suspended and the code raises the shield on a covered segment, protect it now, because that's probably better than suspending the mutator. */ - if (arena->shCacheLength == 0 || !arena->suspended) { - shieldSync(arena, seg); + if (shield->length == 0 || !shield->suspended) { + shieldSync(shield, seg); return; } - AVER_CRITICAL(arena->shCacheLimit <= arena->shCacheLength); - AVER_CRITICAL(arena->shCacheI <= arena->shCacheLimit); + AVER_CRITICAL(shield->limit <= shield->length); + AVER_CRITICAL(shield->i <= shield->limit); - if (arena->shCacheI >= arena->shCacheLength) - arena->shCacheI = 0; - AVER_CRITICAL(arena->shCacheI < arena->shCacheLength); + if (shield->i >= shield->length) + shield->i = 0; + AVER_CRITICAL(shield->i < shield->length); - AVER_CRITICAL(arena->shCacheLength > 0); + AVER_CRITICAL(shield->length > 0); /* If the limit is less than the length, then the cache array has yet to be filled, and shCacheI is an uninitialized entry. Otherwise it's the tail end from last time around, and needs to be flushed. */ - if (arena->shCacheLimit >= arena->shCacheLength) { - AVER_CRITICAL(arena->shCacheLimit == arena->shCacheLength); - shieldFlushEntry(arena, arena->shCacheI); + if (shield->limit >= shield->length) { + AVER_CRITICAL(shield->limit == shield->length); + shieldFlushEntry(shield, shield->i); } - arena->shCache[arena->shCacheI] = seg; - ++arena->shCacheI; + shield->cache[shield->i] = seg; + ++shield->i; seg->cached = TRUE; - if (arena->shCacheI >= arena->shCacheLimit) - arena->shCacheLimit = arena->shCacheI; + if (shield->i >= shield->limit) + shield->limit = shield->i; } @@ -343,6 +440,7 @@ static void shieldCache(Arena arena, Seg seg) void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode) { + SHIELD_AVERT(Arena, arena); SHIELD_AVERT(Seg, seg); @@ -376,7 +474,7 @@ void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) /* TODO: Do we need to promptly call shieldProtLower here? It loses the opportunity to coalesce the protection call. It would violate design.mps.shield.prop.inside.access. */ - shieldProtLower(arena, seg, mode); + shieldProtLower(seg, mode); /* Check cache and segment consistency. */ AVERT(Arena, arena); @@ -388,14 +486,17 @@ void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) void (ShieldEnter)(Arena arena) { + Shield shield; + AVERT(Arena, arena); - AVER(!arena->insideShield); - AVER(arena->shDepth == 0); - AVER(!arena->suspended); + shield = ArenaShield(arena); + AVER(!shield->inside); + AVER(shield->depth == 0); + AVER(!shield->suspended); - shieldCacheReset(arena); + shieldCacheReset(shield); - arena->insideShield = TRUE; + shield->inside = TRUE; } @@ -414,15 +515,17 @@ void (ShieldEnter)(Arena arena) #if defined(SHIELD_DEBUG) static void shieldDebugCheck(Arena arena) { + Shield shield; Seg seg; Count cached = 0; AVERT(Arena, arena); - AVER(arena->insideShield || arena->shCacheLimit == 0); + shield = ShieldArena(arena); + AVER(shield->inside || shield->limit == 0); if (SegFirst(&seg, arena)) do { - if (arena->shCacheLimit == 0) { + if (shield->limit == 0) { AVER(!seg->cached); AVER(SegIsSynced(seg)); /* You can directly set protections here to see if it makes a @@ -434,7 +537,7 @@ static void shieldDebugCheck(Arena arena) } } while(SegNext(&seg, arena, seg)); - AVER(cached == arena->shCacheLimit); + AVER(cached == shield->limit); } #endif @@ -455,12 +558,16 @@ static void shieldDebugCheck(Arena arena) void (ShieldFlush)(Arena arena) { + Shield shield; + + AVERT(Arena, arena); + shield = ArenaShield(arena); #ifdef SHIELD_DEBUG shieldDebugCheck(arena); #endif - shieldFlushEntries(arena); + shieldFlushEntries(shield); /* Cache is empty so .inv.outside.depth holds */ - AVER(arena->shDepth == 0); + AVER(shield->depth == 0); #ifdef SHIELD_DEBUG shieldDebugCheck(arena); #endif @@ -471,20 +578,23 @@ void (ShieldFlush)(Arena arena) void (ShieldLeave)(Arena arena) { + Shield shield; + AVERT(Arena, arena); - AVER(arena->insideShield); - AVER(arena->shDepth == 0); /* no pending covers */ + shield = ArenaShield(arena); + AVER(shield->inside); + AVER(shield->depth == 0); /* no pending covers */ ShieldFlush(arena); /* Ensuring the mutator is running at this point guarantees .inv.outside.running */ - if (arena->suspended) { + if (shield->suspended) { ThreadRingResume(ArenaThreadRing(arena), ArenaDeadRing(arena)); - arena->suspended = FALSE; + shield->suspended = FALSE; } - arena->insideShield = FALSE; + shield->inside = FALSE; } @@ -497,15 +607,18 @@ void (ShieldLeave)(Arena arena) void (ShieldExpose)(Arena arena, Seg seg) { + Shield shield; AccessSet mode = AccessREAD | AccessWRITE; + /* */ AVERT_CRITICAL(Arena, arena); - AVER_CRITICAL(arena->insideShield); + shield = ArenaShield(arena); + AVER_CRITICAL(shield->inside); SegSetDepth(seg, SegDepth(seg) + 1); AVER_CRITICAL(SegDepth(seg) > 0); /* overflow */ - ++arena->shDepth; - AVER_CRITICAL(arena->shDepth > 0); /* overflow */ + ++shield->depth; + AVER_CRITICAL(shield->depth > 0); /* overflow */ if (BS_INTER(SegPM(seg), mode) != AccessSetEMPTY) ShieldSuspend(arena); @@ -513,7 +626,7 @@ void (ShieldExpose)(Arena arena, Seg seg) /* Ensure design.mps.shield.inv.expose.prot. */ /* TODO: Mass exposure -- see design.mps.shield.improv.mass-expose. */ - shieldProtLower(arena, seg, mode); + shieldProtLower(seg, mode); } @@ -521,15 +634,18 @@ void (ShieldExpose)(Arena arena, Seg seg) void (ShieldCover)(Arena arena, Seg seg) { + Shield shield; + /* */ AVERT_CRITICAL(Arena, arena); + shield = ArenaShield(arena); AVERT_CRITICAL(Seg, seg); AVER_CRITICAL(SegPM(seg) == AccessSetEMPTY); AVER_CRITICAL(SegDepth(seg) > 0); SegSetDepth(seg, SegDepth(seg) - 1); - AVER_CRITICAL(arena->shDepth > 0); - --arena->shDepth; + AVER_CRITICAL(shield->depth > 0); + --shield->depth; /* Ensure design.mps.shield.inv.unsynced.depth. */ shieldCache(arena, seg); From b97bd74013a16508d14d8ea251a0970e431f630a Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 20 Mar 2016 00:46:59 +0000 Subject: [PATCH 286/337] Renaming shield cache to shield queue. Copied from Perforce Change: 190220 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 2 +- mps/code/mpmst.h | 14 ++-- mps/code/seg.c | 10 +-- mps/code/shield.c | 162 +++++++++++++++++++++--------------------- mps/design/shield.txt | 24 +++---- 5 files changed, 106 insertions(+), 106 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index bfaaa2e6e4b..e9cb47ee27d 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -483,7 +483,7 @@ /* Shield Configuration -- see */ -#define ShieldCacheLENGTH 512 /* initial length of shield cache */ +#define ShieldQueueLENGTH 512 /* initial length of shield queue */ #define ShieldDepthWIDTH 4 /* log2(max nested exposes + 1) */ diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 29ad117bbcd..64ddd12b202 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -254,7 +254,7 @@ typedef struct SegStruct { /* segment structure */ RingStruct poolRing; /* link in list of segs in pool */ Addr limit; /* limit of segment */ unsigned depth : ShieldDepthWIDTH; /* see design.mps.shield.def.depth */ - BOOLFIELD(cached); /* in shield cache? */ + BOOLFIELD(queued); /* in shield queue? */ AccessSet pm : AccessLIMIT; /* protection mode, */ AccessSet sm : AccessLIMIT; /* shield mode, */ TraceSet grey : TraceLIMIT; /* traces for which seg is grey */ @@ -686,13 +686,13 @@ typedef struct FreelistStruct { typedef struct ShieldStruct { Sig sig; - Bool inside; /* TRUE if and only if inside shield */ - Seg *cache; /* Cache of unsynced segs */ - Count length; /* number of elements in shield cache */ - Index i; /* index into cache */ - Index limit; /* High water mark for cache usage */ + Bool inside; /* design.mps.shield.def.inside */ + Seg *queue; /* queue of unsynced segs */ + Count length; /* number of elements in shield queue */ + Index next; /* next free element in shield queue */ + Index limit; /* high water mark for cache usage */ Count depth; /* sum of depths of all segs */ - Bool suspended; /* TRUE iff mutator suspended */ + Bool suspended; /* mutator suspended? */ } ShieldStruct; diff --git a/mps/code/seg.c b/mps/code/seg.c index 8f3fe37dcd7..71fee6a4a1e 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -150,7 +150,7 @@ static Res SegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) seg->pm = AccessSetEMPTY; seg->sm = AccessSetEMPTY; seg->depth = 0; - seg->cached = FALSE; + seg->queued = FALSE; seg->firstTract = NULL; seg->sig = SegSig; /* set sig now so tract checks will see it */ @@ -222,9 +222,9 @@ static void SegFinish(Seg seg) /* See */ AVER(seg->depth == 0); - if (seg->cached) + if (seg->queued) ShieldFlush(PoolArena(SegPool(seg))); - AVER(seg->cached == FALSE); + AVER(seg->queued == FALSE); limit = SegLimit(seg); @@ -716,9 +716,9 @@ Bool SegCheck(Seg seg) (design.mps.shield.inv.prot.shield). */ CHECKL(BS_DIFF(seg->pm, seg->sm) == 0); - /* All unsynced segments have positive depth or are in the cache + /* All unsynced segments have positive depth or are in the queue (design.mps.shield.inv.unsynced.depth). */ - CHECKL(seg->sm == seg->pm || seg->depth > 0 || seg->cached); + CHECKL(seg->sm == seg->pm || seg->depth > 0 || seg->queued); CHECKL(RankSetCheck(seg->rankSet)); if (seg->rankSet == RankSetEMPTY) { diff --git a/mps/code/shield.c b/mps/code/shield.c index 8ba806a701a..ecabcf96dc3 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -18,9 +18,9 @@ SRCID(shield, "$Id$"); void ShieldInit(Shield shield) { shield->inside = FALSE; - shield->cache = NULL; + shield->queue = NULL; shield->length = 0; - shield->i = 0; + shield->next = 0; shield->limit = 0; shield->depth = 0; shield->suspended = FALSE; @@ -31,12 +31,12 @@ void ShieldInit(Shield shield) void ShieldFinish(Shield shield, Arena arena) { shield->sig = SigInvalid; - /* Delete the shield cache, if it exists. */ + /* Delete the shield queue, if it exists. */ if (shield->length != 0) { - AVER(shield->cache != NULL); - ControlFree(arena, shield->cache, - shield->length * sizeof shield->cache[0]); - shield->cache = NULL; + AVER(shield->queue != NULL); + ControlFree(arena, shield->queue, + shield->length * sizeof shield->queue[0]); + shield->queue = NULL; shield->length = 0; } } @@ -46,9 +46,9 @@ Bool ShieldCheck(Shield shield) { CHECKS(Shield, shield); CHECKL(BoolCheck(shield->inside)); - CHECKL(shield->cache == NULL || shield->length > 0); + CHECKL(shield->queue == NULL || shield->length > 0); CHECKL(shield->limit <= shield->length); - CHECKL(shield->i <= shield->limit); + CHECKL(shield->next <= shield->limit); CHECKL(BoolCheck(shield->suspended)); /* The mutator is not suspended while outside the shield @@ -64,14 +64,14 @@ Bool ShieldCheck(Shield shield) CHECKL(shield->inside || shield->depth == 0); /* This is too expensive to check all the time since we have an - expanding shield cache that often has 16K elements instead of + expanding shield queue that often has 16K elements instead of 16. */ #if defined(AVER_AND_CHECK_ALL) { Count depth = 0; Index i; for (i = 0; i < shield->limit; ++i) { - Seg seg = shield->cache[i]; + Seg seg = shield->queue[i]; CHECKD(Seg, seg); depth += SegDepth(seg); } @@ -91,7 +91,7 @@ Res ShieldDescribe(Shield shield, mps_lib_FILE *stream, Count depth) shield->inside ? "inside" : "outside", " shield\n", "suspended $S\n", WriteFYesNo(shield->suspended), "shield depth $U\n", (WriteFU)shield->depth, - "shield i $U\n", (WriteFU)shield->i, + "shield next $U\n", (WriteFU)shield->next, "shield length $U\n", (WriteFU)shield->length, NULL); if (res != ResOK) @@ -221,43 +221,43 @@ static void shieldProtLower(Seg seg, AccessSet mode) } -/* shieldDecache -- remove a segment from the shield cache */ +/* shieldDequeue -- remove a segment from the shield queue */ -static Seg shieldDecache(Shield shield, Index i) +static Seg shieldDequeue(Shield shield, Index i) { Seg seg; AVER(i < shield->limit); - seg = shield->cache[i]; + seg = shield->queue[i]; AVERT(Seg, seg); - AVER(seg->cached); - shield->cache[i] = NULL; - seg->cached = FALSE; + AVER(seg->queued); + shield->queue[i] = NULL; + seg->queued = FALSE; return seg; } -/* shieldFlushEntry -- flush a single entry from the cache */ +/* shieldFlushEntry -- flush a single entry from the queue */ static void shieldFlushEntry(Shield shield, Index i) { - Seg seg = shieldDecache(shield, i); + Seg seg = shieldDequeue(shield, i); if (!SegIsExposed(seg)) shieldSync(shield, seg); } -/* shieldCacheReset -- reset shield cache pointers */ +/* shieldQueueReset -- reset shield queue pointers */ -static void shieldCacheReset(Shield shield) +static void shieldQueueReset(Shield shield) { - AVER(shield->depth == 0); /* overkill: implies no segs are cached */ - shield->i = 0; + AVER(shield->depth == 0); /* overkill: implies no segs are queued */ + shield->next = 0; shield->limit = 0; } -/* shieldCacheEntryCompare -- comparison for cache sorting */ +/* shieldQueueEntryCompare -- comparison for queue sorting */ static Compare shieldAddrCompare(Addr left, Addr right) { @@ -269,7 +269,7 @@ static Compare shieldAddrCompare(Addr left, Addr right) return CompareGREATER; } -static Compare shieldCacheEntryCompare(void *left, void *right, void *closure) +static Compare shieldQueueEntryCompare(void *left, void *right, void *closure) { Seg segA = left, segB = right; @@ -283,16 +283,16 @@ static Compare shieldCacheEntryCompare(void *left, void *right, void *closure) } -/* shieldFlushEntries -- flush cache coalescing protects +/* shieldFlushEntries -- flush queue coalescing protects * - * Sort the shield cache into address order, then iterate over it + * Sort the shield queue into address order, then iterate over it * coalescing protection work, in order to reduce the number of system * calls to a minimum. This is very important on OS X, where * protection calls are extremely inefficient, but has no net gain on * Windows. * * TODO: Could we keep extending the outstanding area over memory - * that's *not* in the cache but has the same protection mode? Might + * that's *not* in the queue but has the same protection mode? Might * require design.mps.shield.improve.noseg. */ @@ -303,16 +303,16 @@ static void shieldFlushEntries(Shield shield) Index i; if (shield->length == 0) { - AVER(shield->cache == NULL); + AVER(shield->queue == NULL); return; } - QuickSort((void *)shield->cache, shield->limit, - shieldCacheEntryCompare, UNUSED_POINTER); + QuickSort((void *)shield->queue, shield->limit, + shieldQueueEntryCompare, UNUSED_POINTER); mode = AccessSetEMPTY; for (i = 0; i < shield->limit; ++i) { - Seg seg = shieldDecache(shield, i); + Seg seg = shieldDequeue(shield, i); if (!SegIsSynced(seg)) { AVER(SegSM(seg) != AccessSetEMPTY); /* can't match first iter */ SegSetPM(seg, SegSM(seg)); @@ -334,17 +334,17 @@ static void shieldFlushEntries(Shield shield) ProtSet(base, limit, mode); } - shieldCacheReset(shield); + shieldQueueReset(shield); } -/* shieldCache -- consider adding a segment to the cache +/* shieldQueue -- consider adding a segment to the queue * * If the segment is out of sync, either sync it, or ensure it is - * cached and the arena is suspended. + * queued and the arena is suspended. */ -static void shieldCache(Arena arena, Seg seg) +static void shieldQueue(Arena arena, Seg seg) { Shield shield; @@ -353,50 +353,50 @@ static void shieldCache(Arena arena, Seg seg) shield = ArenaShield(arena); SHIELD_AVERT_CRITICAL(Seg, seg); - if (SegIsSynced(seg) || seg->cached) + if (SegIsSynced(seg) || seg->queued) return; if (SegIsExposed(seg)) { /* This can occur if the mutator isn't suspended, we expose a segment, then raise the shield on it. In this case, the mutator isn't allowed to see the segment, but we don't need to - cache it until its covered. */ + queue it until its covered. */ ShieldSuspend(arena); return; } - /* Allocate shield cache if necessary. */ - /* TODO: This will try to extend the cache on every attempt, even + /* Allocate shield queue if necessary. */ + /* TODO: This will try to extend the queue on every attempt, even if it failed last time. That might be slow. */ - if (shield->i >= shield->length) { + if (shield->next >= shield->length) { void *p; Res res; Count length; - AVER(shield->i == shield->length); + AVER(shield->next == shield->length); if (shield->length == 0) - length = ShieldCacheLENGTH; + length = ShieldQueueLENGTH; else length = shield->length * 2; - res = ControlAlloc(&p, arena, length * sizeof shield->cache[0]); + res = ControlAlloc(&p, arena, length * sizeof shield->queue[0]); if (res != ResOK) { AVER(ResIsAllocFailure(res)); - /* Carry on with the existing cache. */ + /* Carry on with the existing queue. */ } else { if (shield->length > 0) { - Size oldSize = shield->length * sizeof shield->cache[0]; - AVER(shield->cache != NULL); - mps_lib_memcpy(p, shield->cache, oldSize); - ControlFree(arena, shield->cache, oldSize); + Size oldSize = shield->length * sizeof shield->queue[0]; + AVER(shield->queue != NULL); + mps_lib_memcpy(p, shield->queue, oldSize); + ControlFree(arena, shield->queue, oldSize); } - shield->cache = p; + shield->queue = p; shield->length = length; } } - /* Cache unavailable, so synchronize now. Or if the mutator is not + /* Queue unavailable, so synchronize now. Or if the mutator is not yet suspended and the code raises the shield on a covered segment, protect it now, because that's probably better than suspending the mutator. */ @@ -406,36 +406,36 @@ static void shieldCache(Arena arena, Seg seg) } AVER_CRITICAL(shield->limit <= shield->length); - AVER_CRITICAL(shield->i <= shield->limit); + AVER_CRITICAL(shield->next <= shield->limit); - if (shield->i >= shield->length) - shield->i = 0; - AVER_CRITICAL(shield->i < shield->length); + if (shield->next >= shield->length) + shield->next = 0; + AVER_CRITICAL(shield->next < shield->length); AVER_CRITICAL(shield->length > 0); - /* If the limit is less than the length, then the cache array has - yet to be filled, and shCacheI is an uninitialized entry. + /* If the limit is less than the length, then the queue array has + yet to be filled, and next is an uninitialized entry. Otherwise it's the tail end from last time around, and needs to be flushed. */ if (shield->limit >= shield->length) { AVER_CRITICAL(shield->limit == shield->length); - shieldFlushEntry(shield, shield->i); + shieldFlushEntry(shield, shield->next); } - shield->cache[shield->i] = seg; - ++shield->i; - seg->cached = TRUE; + shield->queue[shield->next] = seg; + ++shield->next; + seg->queued = TRUE; - if (shield->i >= shield->limit) - shield->limit = shield->i; + if (shield->next >= shield->limit) + shield->limit = shield->next; } /* ShieldRaise -- declare segment should be protected from mutator * * Does not immediately protect the segment, unless the segment is - * covered and the shield cache is unavailable. + * covered and the shield queue is unavailable. */ void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode) @@ -450,9 +450,9 @@ void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode) SegSetSM(seg, SegSM(seg) | mode); /* .inv.prot.shield preserved */ /* ensure .inv.unsynced.suspended and .inv.unsynced.depth */ - shieldCache(arena, seg); + shieldQueue(arena, seg); - /* Check cache and segment consistency. */ + /* Check queue and segment consistency. */ AVERT(Arena, arena); AVERT(Seg, seg); } @@ -476,7 +476,7 @@ void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) violate design.mps.shield.prop.inside.access. */ shieldProtLower(seg, mode); - /* Check cache and segment consistency. */ + /* Check queue and segment consistency. */ AVERT(Arena, arena); AVERT(Seg, seg); } @@ -494,7 +494,7 @@ void (ShieldEnter)(Arena arena) AVER(shield->depth == 0); AVER(!shield->suspended); - shieldCacheReset(shield); + shieldQueueReset(shield); shield->inside = TRUE; } @@ -509,7 +509,7 @@ void (ShieldEnter)(Arena arena) * try enabling SHIELD_DEBUG and extending this code as necessary. * * The basic idea is to iterate over *all* segments and check - * consistency with the arena and shield cache. + * consistency with the arena and shield queue. */ #if defined(SHIELD_DEBUG) @@ -517,7 +517,7 @@ static void shieldDebugCheck(Arena arena) { Shield shield; Seg seg; - Count cached = 0; + Count queued = 0; AVERT(Arena, arena); shield = ShieldArena(arena); @@ -526,27 +526,27 @@ static void shieldDebugCheck(Arena arena) if (SegFirst(&seg, arena)) do { if (shield->limit == 0) { - AVER(!seg->cached); + AVER(!seg->queued); AVER(SegIsSynced(seg)); /* You can directly set protections here to see if it makes a difference. */ /* ProtSet(SegBase(seg), SegLimit(seg), SegPM(seg)); */ } else { - if (seg->cached) - ++cached; + if (seg->queued) + ++queued; } } while(SegNext(&seg, arena, seg)); - AVER(cached == shield->limit); + AVER(queued == shield->limit); } #endif -/* ShieldFlush -- empty the shield cache +/* ShieldFlush -- empty the shield queue * - * .shield.flush: Flush empties the shield cache. This needs to be - * called before segments in the cache are destroyed, as there may be - * references to them in the cache. + * .shield.flush: Flush empties the shield queue. This needs to be + * called before segments in the queue are destroyed, as there may be + * references to them in the queue. * * The memory for the segment may become spare, and not released back * to the operating system. Since we keep track of protection on @@ -566,7 +566,7 @@ void (ShieldFlush)(Arena arena) shieldDebugCheck(arena); #endif shieldFlushEntries(shield); - /* Cache is empty so .inv.outside.depth holds */ + /* Queue is empty so .inv.outside.depth holds */ AVER(shield->depth == 0); #ifdef SHIELD_DEBUG shieldDebugCheck(arena); @@ -648,7 +648,7 @@ void (ShieldCover)(Arena arena, Seg seg) --shield->depth; /* Ensure design.mps.shield.inv.unsynced.depth. */ - shieldCache(arena, seg); + shieldQueue(arena, seg); } diff --git a/mps/design/shield.txt b/mps/design/shield.txt index 57c2e309ae0..03a3c2a1c31 100644 --- a/mps/design/shield.txt +++ b/mps/design/shield.txt @@ -115,9 +115,9 @@ segment should be unprotected, and the Shield could re-instate hardware protection. However, as a performance-improving hysteresis, the Shield defers -re-protection, maintaining a cache of segments that no longer have a -reason to be collector-accessible. While a segment is in the cache, -it has ``seg->cached`` set to TRUE. +re-protection, maintaining a queue of segments that no longer have a +reason to be collector-accessible. While a segment is in the queue, +it has ``seg->queued`` set to TRUE. This hysteresis allows the MPS to proceed with garbage collection during a pause without actually setting hardware protection until it @@ -130,7 +130,7 @@ implemented, such as OS X. So whenever hardware protection is temporarily removed to allow collector access, there is a *nurse* that will ensure this protection is re-established: the nurse is either the balancing ``ShieldCover()`` -call in collector code, or an entry in the shield cache. +call in collector code, or an entry in the shield queue. Implementation @@ -138,8 +138,8 @@ Implementation .impl.delay: The implementation of the shield avoids suspending threads for as long as possible. When threads are suspended, it -maintains a cache of covered segments where the desired and actual -protection do not match. This cache is flushed on leaving the shield. +maintains a queue of covered segments where the desired and actual +protection do not match. This queue is flushed on leaving the shield. Definitions @@ -157,7 +157,7 @@ same, and unsynced otherwise. | #exposes = the total number of times the seg has been exposed | #covers = the total number of times the seg has been covered -The cache is initially empty and ``ShieldCover`` should not be called +The queue is initially empty and ``ShieldCover`` should not be called without a matching ``ShieldExpose``, so this figure should always be non-negative. @@ -198,7 +198,7 @@ shield. suspended. .inv.unsynced.depth: All unsynced segments have positive depth or are -in the cache. +in the queue. .inv.outside.depth: The total depth is zero while outside the shield. @@ -249,7 +249,7 @@ Mass exposure .improv.mass-expose: If protection calls have a high overhead it might be good to pre-emptively unprotect large ranges of memory when we expose one segment. With the current design this would mean -discovering adjacent shielded segments and adding them to the cache. +discovering adjacent shielded segments and adding them to the queue. The collector should take advantage of this by preferentially scanning exposed segments during a pause. @@ -259,7 +259,7 @@ Segment independence .improve.noseg: The shield is implemented in terms of segments, using fields in the segment structure to represent its state. This forces us -to (for example) flush the shield cache when deleting a segment. The +to (for example) flush the shield queue when deleting a segment. The shield could keep track of protection and shielding independently, possibly allowing greater coalescing and more efficient and flexible use of system calls (see .improve.mass-expose). @@ -319,10 +319,10 @@ Document History - 2013-05-24 GDR_ Converted to reStructuredText. -- 2016-03-17 RB_ Updated for dynamic cacheing and general code tidying +- 2016-03-17 RB_ Updated for dynamic queueing and general code tidying that has removed complaints. -- 2016-03-19 RB_ Updated for separate cache flag on segments, changes +- 2016-03-19 RB_ Updated for separate queued flag on segments, changes of invariants, cross-references, and ideas for future improvement. .. _GDR: http://www.ravenbrook.com/consultants/gdr/ From a03174304da3a889e6a01012887e2879b623a96a Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 20 Mar 2016 01:01:54 +0000 Subject: [PATCH 287/337] Tearing down shield correctly. Copied from Perforce Change: 190225 ServerID: perforce.ravenbrook.com --- mps/code/global.c | 11 ++++++----- mps/code/mpm.h | 4 +++- mps/code/poolmrg.c | 2 +- mps/code/shield.c | 15 +++++++++------ 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/mps/code/global.c b/mps/code/global.c index 111404d03f8..d1665254a60 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -154,7 +154,7 @@ Bool GlobalsCheck(Globals arenaGlobals) CHECKD_NOSIG(Ring, &arena->threadRing); CHECKD_NOSIG(Ring, &arena->deadRing); - CHECKD_NOSIG(Shield, &arena->shieldStruct); /* FIXME: Sig */ + CHECKD(Shield, ArenaShield(arena)); CHECKL(TraceSetCheck(arena->busyTraces)); CHECKL(TraceSetCheck(arena->flippedTraces)); @@ -280,7 +280,7 @@ Res GlobalsInit(Globals arenaGlobals) arena->tracedWork = 0.0; arena->tracedTime = 0.0; arena->lastWorldCollect = ClockNow(); - ShieldInit(&arena->shieldStruct); + ShieldInit(ArenaShield(arena)); for (ti = 0; ti < TraceLIMIT; ++ti) { /* */ @@ -385,6 +385,7 @@ void GlobalsFinish(Globals arenaGlobals) arenaGlobals->sig = SigInvalid; + ShieldFinish(ArenaShield(arena)); RingFinish(&arena->formatRing); RingFinish(&arena->chainRing); RingFinish(&arena->messageRing); @@ -418,8 +419,6 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) arena = GlobalsArena(arenaGlobals); - ShieldFinish(&arena->shieldStruct, arena); - arenaDenounce(arena); defaultChain = arenaGlobals->defaultChain; @@ -471,6 +470,8 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) PoolDestroy(pool); } + ShieldDestroyQueue(ArenaShield(arena), arena); + /* Check that the tear-down is complete: that the client has * destroyed all data structures associated with the arena. We do * this here rather than in GlobalsFinish because by the time that @@ -1001,7 +1002,7 @@ Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth) return res; } - res = ShieldDescribe(&arena->shieldStruct, stream, depth); + res = ShieldDescribe(ArenaShield(arena), stream, depth); if (res != ResOK) return res; diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 21e9e82182a..ff64ccba362 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -534,6 +534,7 @@ extern Ring GlobalsRememberedSummaryRing(Globals); #define ArenaGreyRing(arena, rank) (&(arena)->greyRing[rank]) #define ArenaPoolRing(arena) (&ArenaGlobals(arena)->poolRing) #define ArenaChunkTree(arena) RVALUE((arena)->chunkTree) +#define ArenaShield(arena) (&(arena)->shieldStruct) extern Bool ArenaGrainSizeCheck(Size size); #define AddrArenaGrainUp(addr, arena) AddrAlignUp(addr, ArenaGrainSize(arena)) @@ -908,9 +909,10 @@ extern ZoneSet ZoneSetBlacklist(Arena arena); /* Shield Interface -- see */ extern void ShieldInit(Shield shield); -extern void ShieldFinish(Shield shield, Arena arena); +extern void ShieldFinish(Shield shield); extern Bool ShieldCheck(Shield shield); extern Res ShieldDescribe(Shield shield, mps_lib_FILE *stream, Count depth); +extern void ShieldDestroyQueue(Shield shield, Arena arena); extern void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode); extern void (ShieldLower)(Arena arena, Seg seg, AccessSet mode); extern void (ShieldEnter)(Arena arena); diff --git a/mps/code/poolmrg.c b/mps/code/poolmrg.c index 554ec2a7319..cc1cab67975 100644 --- a/mps/code/poolmrg.c +++ b/mps/code/poolmrg.c @@ -821,7 +821,7 @@ static Res MRGDescribe(Pool pool, mps_lib_FILE *stream, Count depth) if (res != ResOK) return res; RING_FOR(node, &mrg->entryRing, nextNode) { - Bool outsideShield = !arena->shieldStruct.inside; + Bool outsideShield = !ArenaShield(arena)->inside; refPart = MRGRefPartOfLink(linkOfRing(node), arena); if (outsideShield) { ShieldEnter(arena); diff --git a/mps/code/shield.c b/mps/code/shield.c index ecabcf96dc3..3e957966a05 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -28,10 +28,10 @@ void ShieldInit(Shield shield) } -void ShieldFinish(Shield shield, Arena arena) +void ShieldDestroyQueue(Shield shield, Arena arena) { - shield->sig = SigInvalid; - /* Delete the shield queue, if it exists. */ + AVER(shield->limit == 0); + if (shield->length != 0) { AVER(shield->queue != NULL); ControlFree(arena, shield->queue, @@ -42,6 +42,12 @@ void ShieldFinish(Shield shield, Arena arena) } +void ShieldFinish(Shield shield) +{ + shield->sig = SigInvalid; +} + + Bool ShieldCheck(Shield shield) { CHECKS(Shield, shield); @@ -101,9 +107,6 @@ Res ShieldDescribe(Shield shield, mps_lib_FILE *stream, Count depth) } -#define ArenaShield(arena) (&(arena)->shieldStruct) - - /* SHIELD_AVER -- transgressive argument checking * * .trans.check: A number of shield functions cannot do normal From 5e62e27402972030af884bf37a5b68b1c552a782 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 20 Mar 2016 01:22:15 +0000 Subject: [PATCH 288/337] Fixing splitting and merging for queued segments. Copied from Perforce Change: 190228 ServerID: perforce.ravenbrook.com --- mps/code/seg.c | 14 ++++++++++---- mps/code/shield.c | 7 ++++--- mps/design/seg.txt | 8 ++++---- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/mps/code/seg.c b/mps/code/seg.c index 71fee6a4a1e..64fb86c2d28 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -573,7 +573,8 @@ Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi) AVER(SegBase(segHi) == SegLimit(segLo)); arena = PoolArena(SegPool(segLo)); - ShieldFlush(arena); /* see */ + if (segLo->queued || segHi->queued) + ShieldFlush(arena); /* see */ /* Invoke class-specific methods to do the merge */ res = class->merge(segLo, segHi, base, mid, limit); @@ -625,7 +626,9 @@ Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at) * the split point. */ AVER(SegBuffer(seg) == NULL || BufferLimit(SegBuffer(seg)) <= at); - ShieldFlush(arena); /* see */ + if (seg->queued) + ShieldFlush(arena); /* see */ + AVER(SegSM(seg) == SegPM(seg)); /* Allocate the new segment object from the control pool */ res = ControlAlloc(&p, arena, class->size); @@ -899,9 +902,11 @@ static Res segTrivMerge(Seg seg, Seg segHi, AVER(seg->pm == segHi->pm); AVER(seg->sm == segHi->sm); AVER(seg->depth == segHi->depth); + AVER(seg->queued == segHi->queued); /* Neither segment may be exposed, or in the shield cache */ /* See & */ AVER(seg->depth == 0); + AVER(!seg->queued); /* no need to update fields which match. See .similar */ @@ -938,7 +943,6 @@ static Res segNoSplit(Seg seg, Seg segHi, AVER(SegLimit(seg) == limit); NOTREACHED; return ResFAIL; - } @@ -964,9 +968,10 @@ static Res segTrivSplit(Seg seg, Seg segHi, AVER(SegBase(seg) == base); AVER(SegLimit(seg) == limit); - /* Segment may not be exposed, or in the shield cache */ + /* Segment may not be exposed, or in the shield queue */ /* See & */ AVER(seg->depth == 0); + AVER(!seg->queued); /* Full initialization for segHi. Just modify seg. */ seg->limit = mid; @@ -978,6 +983,7 @@ static Res segTrivSplit(Seg seg, Seg segHi, segHi->pm = seg->pm; segHi->sm = seg->sm; segHi->depth = seg->depth; + segHi->queued = seg->queued; segHi->firstTract = NULL; segHi->class = seg->class; segHi->sig = SegSig; diff --git a/mps/code/shield.c b/mps/code/shield.c index 3e957966a05..f7cc4aef672 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -30,7 +30,7 @@ void ShieldInit(Shield shield) void ShieldDestroyQueue(Shield shield, Arena arena) { - AVER(shield->limit == 0); + AVER(shield->limit == 0); /* queue must be empty */ if (shield->length != 0) { AVER(shield->queue != NULL); @@ -81,7 +81,7 @@ Bool ShieldCheck(Shield shield) CHECKD(Seg, seg); depth += SegDepth(seg); } - CHECKL(depth <= shield->depth); + CHECKL(depth == shield->depth); } #endif @@ -201,7 +201,8 @@ void (ShieldResume)(Arena arena) AVER(shield->inside); AVER(shield->suspended); - /* It is only correct to actually resume the mutator here if shDepth is 0 */ + /* It is only correct to actually resume the mutator here if + shield->depth is 0 and the queue is empty. */ /* TODO: Consider actually doing that. */ } diff --git a/mps/design/seg.txt b/mps/design/seg.txt index 1a25926ffd5..dc9e8b96083 100644 --- a/mps/design/seg.txt +++ b/mps/design/seg.txt @@ -268,14 +268,14 @@ design.mps.protocol.overview.next-method_). .. _design.mps.protocol.overview.next-method: protocol#overview.next-method _`.split-merge.shield`: Split and merge methods may assume that the -segments they are manipulating are not in the shield cache. +segments they are manipulating are not in the shield queue. -_`.split-merge.shield.flush`: The shield cache is flushed before any +_`.split-merge.shield.flush`: The shield queue is flushed before any split or merge methods are invoked. _`.split-merge.shield.re-flush`: If a split or merge method performs -an operation on a segment which might cause the segment to be cached, -the method must flush the shield cache before returning or calling +an operation on a segment which might cause the segment to be queued, +the method must flush the shield queue before returning or calling another split or merge method. _`.split-merge.fail`: Split and merge methods might fail, in which From cc0b4af900c847e91a8b8c5e77d084335faf6417 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 20 Mar 2016 12:43:13 +0000 Subject: [PATCH 289/337] Reinstate -ansi flag on strict clang builds, which somehow got lost. Copied from Perforce Change: 190233 ServerID: perforce.ravenbrook.com --- mps/code/ll.gmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/ll.gmk b/mps/code/ll.gmk index 787380fb3ed..1bdbef3afcb 100644 --- a/mps/code/ll.gmk +++ b/mps/code/ll.gmk @@ -32,7 +32,7 @@ CFLAGSCOMPILER := \ -Wstrict-prototypes \ -Wunreachable-code \ -Wwrite-strings -CFLAGSCOMPILERSTRICT := +CFLAGSCOMPILERSTRICT := -ansi # A different set of compiler flags for less strict compilation, for # instance when we need to #include a third-party header file that From 394b28a73b6eb68021449d0d625caef63c9462ec Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 20 Mar 2016 12:46:50 +0000 Subject: [PATCH 290/337] Fixing compiler warnings. Copied from Perforce Change: 190237 ServerID: perforce.ravenbrook.com --- mps/code/mpm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/code/mpm.c b/mps/code/mpm.c index 7d944ae57eb..f2ea2acb27a 100644 --- a/mps/code/mpm.c +++ b/mps/code/mpm.c @@ -657,10 +657,10 @@ static unsigned RandomSeed = 1; #define Random_a 48271UL unsigned Random32(void) { - AVER(UINT_MAX >= 4294967295U); /* requires m == 2^31-1, a < 2^16 */ unsigned bot = Random_a * (RandomSeed & 0x7FFF); unsigned top = Random_a * (RandomSeed >> 15); + AVER(UINT_MAX >= 4294967295U); RandomSeed = bot + ((top & 0xFFFF) << 15) + (top >> 16); if (RandomSeed > Random_m) RandomSeed -= Random_m; @@ -669,7 +669,7 @@ unsigned Random32(void) Word RandomWord(void) { - Word word; + Word word = 0; Index i; for (i = 0; i < MPS_WORD_WIDTH; i += 31) word = (word << 31) | Random32(); From f15f64c347a0adf04306f518a54709191461c72a Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 19 Mar 2016 19:43:01 +0000 Subject: [PATCH 291/337] Clarifying that padding object sizes won't match pool object sizes. Copied from Perforce Change: 190242 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/format.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mps/manual/source/topic/format.rst b/mps/manual/source/topic/format.rst index 7db5c8a1178..ec1f707aea3 100644 --- a/mps/manual/source/topic/format.rst +++ b/mps/manual/source/topic/format.rst @@ -368,6 +368,12 @@ Format methods object format has a non-zero :c:macro:`MPS_KEY_FMT_HEADER_SIZE`. + .. note:: + + The MPS will ask for padding objects of any size aligned to + the pool alignment, no matter what size objects the pool + holds. For example, a pool holding only two-word objects may + still be asked to create padding objects 2048 bytes long. .. c:type:: mps_res_t (*mps_fmt_scan_t)(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) From e8c2a85e825bf5e19cdc65a202cffc2e589eaf59 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 20 Mar 2016 15:57:52 +0000 Subject: [PATCH 292/337] Consistent use of -std=c89 for gcc and clang on all platforms. Copied from Perforce Change: 190243 ServerID: perforce.ravenbrook.com --- mps/code/gc.gmk | 2 +- mps/code/ll.gmk | 3 +-- mps/code/mps.xcodeproj/project.pbxproj | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/mps/code/gc.gmk b/mps/code/gc.gmk index 76716dc0785..f43e455dcd8 100644 --- a/mps/code/gc.gmk +++ b/mps/code/gc.gmk @@ -27,7 +27,7 @@ CFLAGSCOMPILER := \ -Wstrict-prototypes \ -Wswitch-default \ -Wwrite-strings -CFLAGSCOMPILERSTRICT := -ansi -pedantic +CFLAGSCOMPILERSTRICT := -std=c89 -pedantic # A different set of compiler flags for less strict compilation, for # instance when we need to #include a third-party header file that diff --git a/mps/code/ll.gmk b/mps/code/ll.gmk index 1bdbef3afcb..db30cde45f0 100644 --- a/mps/code/ll.gmk +++ b/mps/code/ll.gmk @@ -13,7 +13,6 @@ CC = clang CFLAGSDEBUG = -O0 -g3 CFLAGSOPT = -O2 -g3 CFLAGSCOMPILER := \ - -pedantic \ -Waggregate-return \ -Wall \ -Wcast-qual \ @@ -32,7 +31,7 @@ CFLAGSCOMPILER := \ -Wstrict-prototypes \ -Wunreachable-code \ -Wwrite-strings -CFLAGSCOMPILERSTRICT := -ansi +CFLAGSCOMPILERSTRICT := -std=c89 -pedantic # A different set of compiler flags for less strict compilation, for # instance when we need to #include a third-party header file that diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index 9cfea1da0d3..9af36ed62a8 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -5311,7 +5311,7 @@ SDKROOT = macosx; SYMROOT = xc; WARNING_CFLAGS = ( - "-pedantic\n-Waggregate-return\n-Wall\n-Wcast-qual\n-Wconversion\n-Wduplicate-enum\n-Wextra\n-Winline\n-Wmissing-prototypes\n-Wmissing-variable-declarations\n-Wnested-externs\n-Wno-extended-offsetof\n-Wpointer-arith\n-Wshadow\n-Wstrict-aliasing=2\n-Wstrict-prototypes\n-Wunreachable-code\n-Wwrite-strings\n", + "-std=c89\n-pedantic\n-Waggregate-return\n-Wall\n-Wcast-qual\n-Wconversion\n-Wduplicate-enum\n-Wextra\n-Winline\n-Wmissing-prototypes\n-Wmissing-variable-declarations\n-Wnested-externs\n-Wno-extended-offsetof\n-Wpointer-arith\n-Wshadow\n-Wstrict-aliasing=2\n-Wstrict-prototypes\n-Wunreachable-code\n-Wwrite-strings\n", ); }; name = RASH; @@ -5734,7 +5734,7 @@ SDKROOT = macosx; SYMROOT = xc; WARNING_CFLAGS = ( - "-pedantic\n-Waggregate-return\n-Wall\n-Wcast-qual\n-Wconversion\n-Wduplicate-enum\n-Wextra\n-Winline\n-Wmissing-prototypes\n-Wmissing-variable-declarations\n-Wnested-externs\n-Wno-extended-offsetof\n-Wpointer-arith\n-Wshadow\n-Wstrict-aliasing=2\n-Wstrict-prototypes\n-Wunreachable-code\n-Wwrite-strings\n", + "-std=c89\n-pedantic\n-Waggregate-return\n-Wall\n-Wcast-qual\n-Wconversion\n-Wduplicate-enum\n-Wextra\n-Winline\n-Wmissing-prototypes\n-Wmissing-variable-declarations\n-Wnested-externs\n-Wno-extended-offsetof\n-Wpointer-arith\n-Wshadow\n-Wstrict-aliasing=2\n-Wstrict-prototypes\n-Wunreachable-code\n-Wwrite-strings\n", ); }; name = Debug; @@ -5775,7 +5775,7 @@ SDKROOT = macosx; SYMROOT = xc; WARNING_CFLAGS = ( - "-pedantic\n-Waggregate-return\n-Wall\n-Wcast-qual\n-Wconversion\n-Wduplicate-enum\n-Wextra\n-Winline\n-Wmissing-prototypes\n-Wmissing-variable-declarations\n-Wnested-externs\n-Wno-extended-offsetof\n-Wpointer-arith\n-Wshadow\n-Wstrict-aliasing=2\n-Wstrict-prototypes\n-Wunreachable-code\n-Wwrite-strings\n", + "-std=c89\n-pedantic\n-Waggregate-return\n-Wall\n-Wcast-qual\n-Wconversion\n-Wduplicate-enum\n-Wextra\n-Winline\n-Wmissing-prototypes\n-Wmissing-variable-declarations\n-Wnested-externs\n-Wno-extended-offsetof\n-Wpointer-arith\n-Wshadow\n-Wstrict-aliasing=2\n-Wstrict-prototypes\n-Wunreachable-code\n-Wwrite-strings\n", ); }; name = Release; From 7ec5dac2bb43a9f29c213f7f00a233d943941f86 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 21 Mar 2016 10:06:23 +0000 Subject: [PATCH 293/337] Fixing language standard to c89 for the mps, except mpseventsql which uses c99 extensions such as strtoull. Copied from Perforce Change: 190254 ServerID: perforce.ravenbrook.com --- mps/code/mps.xcodeproj/project.pbxproj | 63 +++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index 9af36ed62a8..c71c9d86684 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -5284,7 +5284,7 @@ CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_C_LANGUAGE_STANDARD = ansi; + GCC_C_LANGUAGE_STANDARD = c89; GCC_OPTIMIZATION_LEVEL = s; GCC_PREPROCESSOR_DEFINITIONS = CONFIG_VAR_RASH; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; @@ -5311,7 +5311,24 @@ SDKROOT = macosx; SYMROOT = xc; WARNING_CFLAGS = ( - "-std=c89\n-pedantic\n-Waggregate-return\n-Wall\n-Wcast-qual\n-Wconversion\n-Wduplicate-enum\n-Wextra\n-Winline\n-Wmissing-prototypes\n-Wmissing-variable-declarations\n-Wnested-externs\n-Wno-extended-offsetof\n-Wpointer-arith\n-Wshadow\n-Wstrict-aliasing=2\n-Wstrict-prototypes\n-Wunreachable-code\n-Wwrite-strings\n", + "-pedantic", + "-Waggregate-return", + "-Wall", + "-Wcast-qual", + "-Wconversion", + "-Wduplicate-enum", + "-Wextra", + "-Winline", + "-Wmissing-prototypes", + "-Wmissing-variable-declarations", + "-Wnested-externs", + "-Wno-extended-offsetof", + "-Wpointer-arith", + "-Wshadow", + "-Wstrict-aliasing=2", + "-Wstrict-prototypes", + "-Wunreachable-code", + "-Wwrite-strings", ); }; name = RASH; @@ -5706,7 +5723,7 @@ CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - GCC_C_LANGUAGE_STANDARD = ansi; + GCC_C_LANGUAGE_STANDARD = c89; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = CONFIG_VAR_COOL; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; @@ -5734,7 +5751,24 @@ SDKROOT = macosx; SYMROOT = xc; WARNING_CFLAGS = ( - "-std=c89\n-pedantic\n-Waggregate-return\n-Wall\n-Wcast-qual\n-Wconversion\n-Wduplicate-enum\n-Wextra\n-Winline\n-Wmissing-prototypes\n-Wmissing-variable-declarations\n-Wnested-externs\n-Wno-extended-offsetof\n-Wpointer-arith\n-Wshadow\n-Wstrict-aliasing=2\n-Wstrict-prototypes\n-Wunreachable-code\n-Wwrite-strings\n", + "-pedantic", + "-Waggregate-return", + "-Wall", + "-Wcast-qual", + "-Wconversion", + "-Wduplicate-enum", + "-Wextra", + "-Winline", + "-Wmissing-prototypes", + "-Wmissing-variable-declarations", + "-Wnested-externs", + "-Wno-extended-offsetof", + "-Wpointer-arith", + "-Wshadow", + "-Wstrict-aliasing=2", + "-Wstrict-prototypes", + "-Wunreachable-code", + "-Wwrite-strings", ); }; name = Debug; @@ -5748,7 +5782,7 @@ CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_C_LANGUAGE_STANDARD = ansi; + GCC_C_LANGUAGE_STANDARD = c89; GCC_OPTIMIZATION_LEVEL = s; GCC_PREPROCESSOR_DEFINITIONS = CONFIG_VAR_HOT; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; @@ -5775,7 +5809,24 @@ SDKROOT = macosx; SYMROOT = xc; WARNING_CFLAGS = ( - "-std=c89\n-pedantic\n-Waggregate-return\n-Wall\n-Wcast-qual\n-Wconversion\n-Wduplicate-enum\n-Wextra\n-Winline\n-Wmissing-prototypes\n-Wmissing-variable-declarations\n-Wnested-externs\n-Wno-extended-offsetof\n-Wpointer-arith\n-Wshadow\n-Wstrict-aliasing=2\n-Wstrict-prototypes\n-Wunreachable-code\n-Wwrite-strings\n", + "-pedantic", + "-Waggregate-return", + "-Wall", + "-Wcast-qual", + "-Wconversion", + "-Wduplicate-enum", + "-Wextra", + "-Winline", + "-Wmissing-prototypes", + "-Wmissing-variable-declarations", + "-Wnested-externs", + "-Wno-extended-offsetof", + "-Wpointer-arith", + "-Wshadow", + "-Wstrict-aliasing=2", + "-Wstrict-prototypes", + "-Wunreachable-code", + "-Wwrite-strings", ); }; name = Release; From 460f12cd75e299480f5692ac6052b80486568a63 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 21 Mar 2016 10:42:21 +0000 Subject: [PATCH 294/337] Backing out accidental change to check.h. Copied from Perforce Change: 190263 ServerID: perforce.ravenbrook.com --- mps/code/check.h | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/mps/code/check.h b/mps/code/check.h index 2a08160040e..a2450bebd9a 100644 --- a/mps/code/check.h +++ b/mps/code/check.h @@ -39,15 +39,6 @@ #include "mpslib.h" -/* FIXME: to config.h? */ - -#if defined(MPS_BUILD_LL) || defined(MPS_BUILD_GC) -#define UNEXPECTED(expr) __builtin_expect((expr) != 0, TRUE) -#else -#define UNEXPECTED(expr) (expr) -#endif - - /* ASSERT -- basic assertion * * The ASSERT macro is equivalent to the ISO C assert() except that it is @@ -60,7 +51,7 @@ #define ASSERT(cond, condstring) \ BEGIN \ - if (UNEXPECTED(cond)) NOOP; else \ + if (cond) NOOP; else \ mps_lib_assert_fail(MPS_FILE, __LINE__, (condstring)); \ END From 7a7913786c655b45c5e569715300cc33fa7dc1aa Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 22 Mar 2016 16:32:10 +0000 Subject: [PATCH 295/337] Responding to review by gdr . Copied from Perforce Change: 190307 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 2 +- mps/code/seg.c | 28 ++++++++++++++-------------- mps/design/index.txt | 3 +++ mps/design/scan.txt | 4 ++-- mps/design/write-barrier.txt | 6 +++--- mps/manual/source/design/index.rst | 1 + 6 files changed, 24 insertions(+), 20 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index b7de3a7a227..a18f812c606 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -681,7 +681,7 @@ * passed in the mutator rather than the number of scans. */ -#define WB_DEFER_BITS 3 /* bitfield width for deferral count */ +#define WB_DEFER_BITS 2 /* bitfield width for deferral count */ #define WB_DEFER_INIT 3 /* boring scans after new segment */ #define WB_DEFER_DELAY 3 /* boring scans after interesting scan */ #define WB_DEFER_HIT 1 /* boring scans after barrier hit */ diff --git a/mps/code/seg.c b/mps/code/seg.c index 7b11e8a8cf6..137388cc9fe 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -731,7 +731,7 @@ Bool SegCheck(Seg seg) /* write shielded. */ /* CHECKL(seg->_summary == RefSetUNIV || (seg->_sm & AccessWRITE)); */ /* @@@@ What can be checked about the read barrier? */ - /* FIXME: Need gcSegCheck? CHECKL(seg->defer == 0 || seg->summary == RefSetUNIV); */ + /* TODO: Need gcSegCheck? What does RankSet imply about being a gcSeg? */ } return TRUE; } @@ -1313,6 +1313,16 @@ static void gcSegSetRankSet(Seg seg, RankSet rankSet) } +static void gcSegSyncWriteBarrier(Seg seg, Arena arena) +{ + /* Can't check seg -- this function enforces invariants tested by SegCheck. */ + if (SegSummary(seg) == RefSetUNIV) + ShieldLower(arena, seg, AccessWRITE); + else + ShieldRaise(arena, seg, AccessWRITE); +} + + /* gcSegSetSummary -- GCSeg method to change the summary on a segment * * In fact, we only need to raise the write barrier if the @@ -1337,12 +1347,7 @@ static void gcSegSetSummary(Seg seg, RefSet summary) AVER(seg->rankSet != RankSetEMPTY); - /* Note: !RefSetSuper is a test for a strict subset */ - /* FIXME: Duplicate code with gcSegSetRankSummary. */ - if (!RefSetSuper(summary, RefSetUNIV)) - ShieldRaise(arena, seg, AccessWRITE); - else - ShieldLower(arena, seg, AccessWRITE); + gcSegSyncWriteBarrier(seg, arena); } @@ -1369,13 +1374,8 @@ static void gcSegSetRankSummary(Seg seg, RankSet rankSet, RefSet summary) seg->rankSet = BS_BITFIELD(Rank, rankSet); gcseg->summary = summary; - if (rankSet != RankSetEMPTY) { - /* FIXME: Duplicate code with gcSegSetSummary. */ - if (!RefSetSuper(summary, RefSetUNIV)) - ShieldRaise(arena, seg, AccessWRITE); - else - ShieldLower(arena, seg, AccessWRITE); - } + if (rankSet != RankSetEMPTY) + gcSegSyncWriteBarrier(seg, arena); } diff --git a/mps/design/index.txt b/mps/design/index.txt index cde852448bb..7c889f1ee30 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -115,6 +115,7 @@ version_ Software versions vm_ Virtual mapping vmo1_ VM Module on DEC Unix vmso_ VM Design for Solaris +write-barrier_ Write Barrier writef_ The WriteF function ====================== ================================================ @@ -194,6 +195,7 @@ writef_ The WriteF function .. _vm: vm .. _vmo1: vmo1 .. _vmso: vmso +.. _write-barrier: write-barrier .. _writef: writef @@ -227,6 +229,7 @@ Document History - 2013-06-07 RB_ Converting to reST_. Linking to [RB_2002-06-18]_. - 2014-01-29 RB_ The arena no longer manages generation zonesets. - 2014-01-17 GDR_ Add abq, nailboard, range. +- 2016-03-22 RB_ Add write-barier. .. _RB: http://www.ravenbrook.com/consultants/rb .. _NB: http://www.ravenbrook.com/consultants/nb diff --git a/mps/design/scan.txt b/mps/design/scan.txt index 2b4c992d185..ef302553384 100644 --- a/mps/design/scan.txt +++ b/mps/design/scan.txt @@ -24,7 +24,7 @@ _`.summary.subset`: The summary of reference seens by scan There are two reasons that it is not an equality relation: -#. If the segment has had objects forwarded onto it then its summary +1. If the segment has had objects forwarded onto it then its summary will get unioned with the summary of the segment that the object was forwarded from. This may increase the summary. The forwarded object of course may have a smaller summary (if such a thing were @@ -32,7 +32,7 @@ There are two reasons that it is not an equality relation: reduce the summary. (The forwarding process may erroneously introduce zones into the destination's summary). -#. A write barrier hit will set the summary to ``RefSetUNIV``. +2. A write barrier hit will set the summary to ``RefSetUNIV``. The reason that ``ss.unfixedSummary`` is always a subset of the previous summary is due to an "optimization" which has not been made diff --git a/mps/design/write-barrier.txt b/mps/design/write-barrier.txt index f2bd86c7e7d..3b54c882964 100644 --- a/mps/design/write-barrier.txt +++ b/mps/design/write-barrier.txt @@ -138,9 +138,9 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact -Ravenbrook for commercial licensing options. +Copyright © 2016 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 diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 1cea6c4861b..2513cc5e6ad 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -37,4 +37,5 @@ Design thread-manager type vm + write-barrier writef From cf0ac842bc7373223725c4aa9562d65e9f341824 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 23 Mar 2016 08:20:29 +0000 Subject: [PATCH 296/337] Reorganising shield design and updating. Renaming ShieldSuspend to ShieldHold and ShieldResume to ShieldRelease to reduce confusion. Copied from Perforce Change: 190320 ServerID: perforce.ravenbrook.com --- mps/code/mpm.h | 8 +- mps/code/shield.c | 12 +-- mps/code/trace.c | 10 +-- mps/design/shield.txt | 184 ++++++++++++++++++++++++------------------ 4 files changed, 121 insertions(+), 93 deletions(-) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index ff64ccba362..5b03ee449e0 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -919,8 +919,8 @@ extern void (ShieldEnter)(Arena arena); extern void (ShieldLeave)(Arena arena); extern void (ShieldExpose)(Arena arena, Seg seg); extern void (ShieldCover)(Arena arena, Seg seg); -extern void (ShieldSuspend)(Arena arena); -extern void (ShieldResume)(Arena arena); +extern void (ShieldHold)(Arena arena); +extern void (ShieldRelease)(Arena arena); extern void (ShieldFlush)(Arena arena); #if defined(SHIELD) @@ -936,8 +936,8 @@ extern void (ShieldFlush)(Arena arena); BEGIN UNUSED(arena); UNUSED(seg); END #define ShieldCover(arena, seg) \ BEGIN UNUSED(arena); UNUSED(seg); END -#define ShieldSuspend(arena) BEGIN UNUSED(arena); END -#define ShieldResume(arena) BEGIN UNUSED(arena); END +#define ShieldHold(arena) BEGIN UNUSED(arena); END +#define ShieldRelease(arena) BEGIN UNUSED(arena); END #define ShieldFlush(arena) BEGIN UNUSED(arena); END #else #error "No shield configuration." diff --git a/mps/code/shield.c b/mps/code/shield.c index 7eabf5f8986..164b7412819 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -161,7 +161,7 @@ static void shieldSync(Shield shield, Seg seg) } -/* ShieldSuspend -- suspend the mutator +/* ShieldHold -- suspend mutator access to the unprotectable * * From outside impl.c.shield, this is used when we really need to * lock everything against the mutator -- for example, during flip @@ -171,7 +171,7 @@ static void shieldSync(Shield shield, Seg seg) * synced -- see .inv.unsynced.suspended. */ -void (ShieldSuspend)(Arena arena) +void (ShieldHold)(Arena arena) { Shield shield; @@ -186,13 +186,13 @@ void (ShieldSuspend)(Arena arena) } -/* ShieldResume -- declare mutator could be resumed +/* ShieldRelease -- declare mutator could be resumed * * In practice, we don't resume the mutator until ShieldLeave, but * this marks the earliest point at which we could resume. */ -void (ShieldResume)(Arena arena) +void (ShieldRelease)(Arena arena) { Shield shield; @@ -365,7 +365,7 @@ static void shieldQueue(Arena arena, Seg seg) segment, then raise the shield on it. In this case, the mutator isn't allowed to see the segment, but we don't need to queue it until its covered. */ - ShieldSuspend(arena); + ShieldHold(arena); return; } @@ -625,7 +625,7 @@ void (ShieldExpose)(Arena arena, Seg seg) AVER_CRITICAL(shield->depth > 0); /* overflow */ if (BS_INTER(SegPM(seg), mode) != AccessSetEMPTY) - ShieldSuspend(arena); + ShieldHold(arena); /* Ensure design.mps.shield.inv.expose.prot. */ /* TODO: Mass exposure -- see diff --git a/mps/code/trace.c b/mps/code/trace.c index 1f3db0d3467..e81ab41c869 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -573,7 +573,7 @@ static Res traceFlip(Trace trace) arena = trace->arena; rfc.arena = arena; - ShieldSuspend(arena); + ShieldHold(arena); AVER(trace->state == TraceUNFLIPPED); AVER(!TraceSetIsMember(arena->flippedTraces, trace)); @@ -634,11 +634,11 @@ static Res traceFlip(Trace trace) EVENT2(TraceFlipEnd, trace, arena); - ShieldResume(arena); + ShieldRelease(arena); return ResOK; failRootFlip: - ShieldResume(arena); + ShieldRelease(arena); return res; } @@ -737,8 +737,8 @@ Res TraceCreate(Trace *traceReturn, Arena arena, int why) /* buffers under our feet. */ /* @@@@ This is a short-term fix for request.dylan.160098_. */ /* .. _request.dylan.160098: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160098 */ - /* TODO: Where is the corresponding ShieldResume? */ - ShieldSuspend(arena); + /* TODO: Where is the corresponding ShieldRelease? */ + ShieldHold(arena); STATISTIC_STAT ({ /* Iterate over all chains, all GenDescs within a chain, and all diff --git a/mps/design/shield.txt b/mps/design/shield.txt index 03a3c2a1c31..52011a28ca0 100644 --- a/mps/design/shield.txt +++ b/mps/design/shield.txt @@ -9,7 +9,7 @@ Shield :Status: incomplete guide :Revision: $Id$ :Copyright: See `Copyright and License`_. -:Index terms: pair: shield; design +:Index terms: pair: shield; design Introduction @@ -25,8 +25,10 @@ _`.readership`: Any MPS developer. Not confidential. Overview -------- -_`.over`: For incremental collection, we need *separate control* of -collector access and mutator (client) access to memory. The collector +_`.overview`: The MPS implements incremental garbage collection using +memory barriers implemented by a combination of hardware memory +protection and thread control. The MPS needs *separate control* of +collector access and mutator (client) access to memory: the collector must be able to incrementally scan objects, without the mutator being able to see them yet. @@ -38,99 +40,123 @@ limitation, and give the rest of the MPS the illusion that we can control collector and mutator access separately. -Control of mutator access -------------------------- +Interface +--------- -The MPS uses ``ShieldRaise()`` and ``ShieldLower()`` to forbid or -permit the mutator access to object memory (that is, memory allocated -by MPS). + +Mutator access +.............. + +The shield provides ``ShieldRaise`` and ``ShieldLower`` to forbid or +permit the mutator access to object memory segments. Between these +two, a segment is said to have the shield "raised". ``void ShieldRaise(Arena arena, Seg seg, AccessSet mode)`` - Prevent the mutator accessing the memory in the specified mode - (``AccessREAD``, ``AccessWRITE``, or both). + Prevent the mutator accessing the memory segment in the specified + mode (``AccessREAD``, ``AccessWRITE``, or both). ``void ShieldLower(Arena arena, Seg seg, AccessSet mode)`` - Allow the mutator to access the memory in the specified mode - (``AccessREAD``, ``AccessWRITE``, or both). + Allow the mutator to access the memory segment in the specified + mode (``AccessREAD``, ``AccessWRITE``, or both). -If the mutator attempts an access that hits a shield, the MPS gets a -barrier hit (in the form of a fault, interrupt, exception), quickly -does some necessary work, and then makes the access succeed. +If the mutator attempts an access that hits the shield, the MPS gets +an OS-specific hardware protection fault which reaches +``ArenaAccess``, does whatever work is necessary, then lowers the +shield and returns to the mutator. -Some objects (for example registers) cannot be hardware protected: the -only way to prevent mutator access to them is to halt all mutator -threads. The MPS uses ``ShieldSuspend()`` and ``ShieldResume()`` to do -this. - -``void ShieldSuspend(Arena arena)`` - - Stop all registered mutator threads. - -``void ShieldResume(Arena arena)`` - - Resume all registered mutator threads. +``ShieldRaise`` and ``ShieldLower` do *not* nest. -Control of collector access ---------------------------- +Entering the shield +................... -When the collector wants to access object memory (that is, memory -allocated by MPS), it must first call ``ShieldEnter()``, then wrap any -accesses with a ``ShieldExpose()`` and ``ShieldCover()`` pair, and -finally call ``ShieldLeave()``. +The MPS can only gain exclusive access from "inside" the shield. To +enter the shield, the MPS must call ``ShieldEnter``, and to leave it, +the MPS must call ``ShieldLeave``. -``ShieldEnter()`` and ``ShieldLeave()`` are called by ``ArenaEnter()`` -and ``ArenaLeave()`` (approximately) -- so the shield is always -entered when we are within MPS code (approximately). +``ShieldEnter`` and ``ShieldLeave`` are called by ``ArenaEnter`` and +``ArenaLeave`` so almost all of the MPS is is "inside" the shield. -``ShieldExpose()`` might for example be called around: -- format-scan (when scanning); -- format-skip (when marking grains in a non-moving fix); -- format-isMoved and ``AddrCopy()`` (during a copying fix); -- format-pad (during reclaim). +Collector access to aegments +---------------------------- -Note that there is no need to call ``ShieldExpose()`` when accessing -pool management memory such as bit tables. This is not object -memory, is never (legally) accessed by the mutator, and so is never -shielded. +When the MPS wants to access object memory segments from inside the +shield, it must wrap any accesses with a ``ShieldExpose`` and +``ShieldCover`` pair. Between calls to ``ShieldExpose`` and +``ShieldCover``, a segment is said to be "exposed". -On common operating systems, the only way to allow collector access is -to allow access from the whole process, including the mutator. So if -the Shield is asked to allow collector access but deny mutator access, -it will halt all mutator threads to prevent any mutator access. The -Shield performs suspension and restart; normal collector code does not -need to worry about it. +A segment might for example be exposed during: -Collector code can make multiple sequential, overlapping, or nested -calls to ``ShieldExpose()`` on the same segment, as long as each is -balanced by a corresponding ``ShieldCover()`` before ``ShieldLeave()`` -is called). A usage count is maintained on each segment in -``seg->depth``: a positive "depth" means a positive number of -outstanding *reasons* why the segment must be exposed to the collector. -When the usage count reaches zero, there is no longer any reason the -segment should be unprotected, and the Shield could re-instate -hardware protection. + - format-scan (when scanning); + - format-skip (when marking grains in a non-moving fix); + - format-isMoved and ``AddrCopy`` (during a copying fix); + - format-pad (during reclaim). -However, as a performance-improving hysteresis, the Shield defers -re-protection, maintaining a queue of segments that no longer have a -reason to be collector-accessible. While a segment is in the queue, -it has ``seg->queued`` set to TRUE. +Note that there is no need to call ``ShieldExpose`` when accessing +pool management memory such as bit tables. This is not object memory, +is never (legally) accessed by the mutator, and so is never shielded. + +Similarly, a pool class that never raises the shield on its segments +need never expose them to gain access. + + +Collector access to the unprotectable +..................................... + +Then the MPS wants to access an unprotectable object from inside the +shield, it must wrap any accesses with a ``ShieldHold`` and +``ShieldRelease`` pair. This allows access to objects which cannot be +shielded by ``ShieldRaise``, such as: + + - the stack and registers of mutator threads, + - lockless allocation point structures, + - areas of memory that can't be protected by operating system calls, + - unprotectable roots. + +``void ShieldHold(Arena arena)`` + + Get exclusive access to the unprotectable. + +``void ShieldRelease(Arena arena)`` + + Declare that exclusive access is no longer needed. + + +Mechanism +--------- + +On common operating systems, the only way to allow the MPS access is +to allow access from the whole process, including the mutator. So +``ShieldExpose`` will suspend all mutator threads to prevent any mutator +access, and so will ``ShieldRaise`` on an unexposed segment. The +shield handles suspending and resuming threads, and the the rest of +the MPS does not need to worry about it. + +The MPS can make multiple sequential, overlapping, or nested calls to +``ShieldExpose`` on the same segment, as long as each is balanced by a +corresponding ``ShieldCover`` before ``ShieldLeave`` is called. A +usage count is maintained on each segment in ``seg->depth``. When the +usage count reaches zero, there is no longer any reason the segment +should be unprotected, and the shield may reinstate hardware +protection at any time. + +.impl.delay: However, as a performance-improving hysteresis, the +shield defers re-protection, maintaining a queue of segments that +require attention before mutator threads are resumed. While a segment +is in the queue, it has ``seg->queued`` set to TRUE. This hysteresis allows the MPS to proceed with garbage collection during a pause without actually setting hardware protection until it -returns to the mutator. If a complete collection cycle occurs during -one pause (a non-incremental collection), no system calls will be -needed for collection barriers. This is particularly important on -operating systems where the protection is expensive and poorly -implemented, such as OS X. +returns to the mutator. This is particularly important on operating +systems where the protection is expensive and poorly implemented, such +as OS X. -So whenever hardware protection is temporarily removed to allow -collector access, there is a *nurse* that will ensure this protection -is re-established: the nurse is either the balancing ``ShieldCover()`` -call in collector code, or an entry in the shield queue. +The queue also ensures that no memory protection system calls will be +neededIf a complete collection cycle occurs during one pause, allowing +the MPS to operate in a non-incremental mode. Implementation @@ -170,9 +196,11 @@ inside the shield is being between calls to ``ShieldEnter`` and ``ShieldLeave``. [In a multi-threaded MPS this would be per-thread. RB 2016-03-18] -.def.suspended: Suspended is true iff the mutator is suspended. +.def.suspended: Suspended is true iff the mutator is +suspended. [Between calls to ThreadSuspend and ThreadResume?] -.def.shielded: A segment is shielded if the shield mode is non-zero. +.def.shielded: A segment is shielded if the shield mode is +non-zero. [As set by ShieldRaise.] Properties @@ -182,9 +210,9 @@ Properties the shield. .prop.mutator.access: An attempt by the mutator to access shielded -memory must cause an ArenaAccess. +memory be pre-empted by a call to ``ArenaAccess``. -.prop.inside.access: Inside the shield it must be possible to access +.prop.inside.access: Inside the shield the MPS must be able to access all unshielded segments and all exposed segments. @@ -272,7 +300,7 @@ Concurrent collection however the only thing that makes it not-concurrent is a critical point in the Shield abstraction where the MPS seeks to gain privileged access to memory (usually in order to scan it for GC). The critical -point is where ShieldExpose in shield.c has to call ShieldSuspend to +point is where ShieldExpose in shield.c has to call ShieldHold to preserve the shield invariants. This is the only point in the MPS that prevents concurrency, and the rest of the MPS is designed to support it. From 5bc87114eacbd4e21e387a3a1712f58cf9e706c3 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 23 Mar 2016 11:59:57 +0000 Subject: [PATCH 297/337] Counting shield holds and releases, to ensure they are nested correctly. Counting the number of unsynced segments in order to check consistency. Moving the extra shield hold for request.dylan.160098 around actual whitening, and adding a matching shield release. Copied from Perforce Change: 190321 ServerID: perforce.ravenbrook.com --- mps/code/mpmst.h | 2 + mps/code/shield.c | 161 +++++++++++++++++++++++++++++++++++++--------- mps/code/trace.c | 19 +++--- 3 files changed, 142 insertions(+), 40 deletions(-) diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 64ddd12b202..ea8d8bd00bd 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -692,6 +692,8 @@ typedef struct ShieldStruct { Index next; /* next free element in shield queue */ Index limit; /* high water mark for cache usage */ Count depth; /* sum of depths of all segs */ + Count unsynced; /* number of unsynced segments */ + Count holds; /* number of holds */ Bool suspended; /* mutator suspended? */ } ShieldStruct; diff --git a/mps/code/shield.c b/mps/code/shield.c index 164b7412819..307c8d89606 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -23,6 +23,8 @@ void ShieldInit(Shield shield) shield->next = 0; shield->limit = 0; shield->depth = 0; + shield->unsynced = 0; + shield->holds = 0; shield->suspended = FALSE; shield->sig = ShieldSig; } @@ -44,10 +46,15 @@ void ShieldDestroyQueue(Shield shield, Arena arena) void ShieldFinish(Shield shield) { + AVER(shield->depth == 0); + AVER(shield->unsynced == 0); + AVER(shield->holds == 0); shield->sig = SigInvalid; } +static Bool SegIsSynced(Seg seg); + Bool ShieldCheck(Shield shield) { CHECKS(Shield, shield); @@ -63,25 +70,42 @@ Bool ShieldCheck(Shield shield) /* If any segment is not synced, the mutator is suspended (design.mps.shield.inv.unsynced.suspended). */ + CHECKL(shield->unsynced == 0 || shield->suspended); + + /* If any segment is exposed, the mutator is suspended. */ CHECKL(shield->depth == 0 || shield->suspended); /* The total depth is zero while outside the shield (design.mps.shield.inv.outside.depth). */ CHECKL(shield->inside || shield->depth == 0); + /* There are no unsynced segments when we're outside the shield. */ + CHECKL(shield->inside || shield->unsynced == 0); + + /* Every unsynced segment should be on the queue, because we have to + remember to sync it before we return to the mutator. */ + CHECKL(shield->limit >= shield->unsynced); + + /* The mutator is suspeneded if there are any holds. */ + CHECKL(shield->holds == 0 || shield->suspended); + /* This is too expensive to check all the time since we have an expanding shield queue that often has 16K elements instead of 16. */ #if defined(AVER_AND_CHECK_ALL) { Count depth = 0; + Count unsynced = 0; Index i; for (i = 0; i < shield->limit; ++i) { Seg seg = shield->queue[i]; CHECKD(Seg, seg); depth += SegDepth(seg); + if (!SegIsSynced(seg)) + ++unsynced; } CHECKL(depth == shield->depth); + CHECKL(unsynced == shield->unsynced); } #endif @@ -94,11 +118,15 @@ Res ShieldDescribe(Shield shield, mps_lib_FILE *stream, Count depth) Res res; res = WriteF(stream, depth, - shield->inside ? "inside" : "outside", " shield\n", - "suspended $S\n", WriteFYesNo(shield->suspended), - "shield depth $U\n", (WriteFU)shield->depth, - "shield next $U\n", (WriteFU)shield->next, - "shield length $U\n", (WriteFU)shield->length, + "Shield $P {\n", (WriteFP)shield, + " ", shield->inside ? "inside" : "outside", " shield\n", + " suspended $S\n", WriteFYesNo(shield->suspended), + " depth $U\n", (WriteFU)shield->depth, + " next $U\n", (WriteFU)shield->next, + " length $U\n", (WriteFU)shield->length, + " unsynced $U\n", (WriteFU)shield->unsynced, + " holds $U\n", (WriteFU)shield->holds, + "} Shield $P\n", (WriteFP)shield, NULL); if (res != ResOK) return res; @@ -132,6 +160,44 @@ static Bool SegIsSynced(Seg seg) } +/* shieldSetSM -- set shield mode, maintaining sync count */ + +static void shieldSetSM(Shield shield, Seg seg, AccessSet mode) +{ + if (SegSM(seg) != mode) { + if (SegIsSynced(seg)) { + SegSetSM(seg, mode); + ++shield->unsynced; + } else { + SegSetSM(seg, mode); + if (SegIsSynced(seg)) { + AVER(shield->unsynced > 0); + --shield->unsynced; + } + } + } +} + + +/* shieldSetPM -- set protection mode, maintaining sync count */ + +static void shieldSetPM(Shield shield, Seg seg, AccessSet mode) +{ + if (SegPM(seg) != mode) { + if (SegIsSynced(seg)) { + SegSetPM(seg, mode); + ++shield->unsynced; + } else { + SegSetPM(seg, mode); + if (SegIsSynced(seg)) { + AVER(shield->unsynced > 0); + --shield->unsynced; + } + } + } +} + + /* SegIsExposed -- is a segment exposed? * * See design.mps.shield.def.exposed. @@ -151,27 +217,23 @@ static Bool SegIsExposed(Seg seg) static void shieldSync(Shield shield, Seg seg) { - UNUSED(shield); SHIELD_AVERT_CRITICAL(Seg, seg); if (!SegIsSynced(seg)) { ProtSet(SegBase(seg), SegLimit(seg), SegSM(seg)); - SegSetPM(seg, SegSM(seg)); + shieldSetPM(shield, seg, SegSM(seg)); } } -/* ShieldHold -- suspend mutator access to the unprotectable +/* shieldSUspend -- suspend the mutator * - * From outside impl.c.shield, this is used when we really need to - * lock everything against the mutator -- for example, during flip - * when we must scan all thread registers at once. - * - * It is called from inside impl.c.shield when any segment is not - * synced -- see .inv.unsynced.suspended. + * Called from inside impl.c.shield when any segment is not synced, in + * order to provide exclusive access to the segment by the MPS. See + * .inv.unsynced.suspended. */ -void (ShieldHold)(Arena arena) +static void shieldSuspend(Arena arena) { Shield shield; @@ -186,6 +248,21 @@ void (ShieldHold)(Arena arena) } +/* ShieldHold -- suspend mutator access to the unprotectable + * + * From outside impl.c.shield, this is used when we really need to + * lock everything against the mutator -- for example, during flip + * when we must scan all thread registers at once. + */ + +void (ShieldHold)(Arena arena) +{ + AVERT(Arena, arena); + shieldSuspend(arena); + ++ArenaShield(arena)->holds; +} + + /* ShieldRelease -- declare mutator could be resumed * * In practice, we don't resume the mutator until ShieldLeave, but @@ -201,8 +278,12 @@ void (ShieldRelease)(Arena arena) AVER(shield->inside); AVER(shield->suspended); + AVER(shield->holds > 0); + --shield->holds; + /* It is only correct to actually resume the mutator here if - shield->depth is 0 and the queue is empty. */ + shield->depth is 0, shield->unsycned is 0, and the queue is + empty. */ /* TODO: Consider actually doing that. */ } @@ -212,14 +293,14 @@ void (ShieldRelease)(Arena arena) * This ensures actual prot mode does not include mode. */ -static void shieldProtLower(Seg seg, AccessSet mode) +static void shieldProtLower(Shield shield, Seg seg, AccessSet mode) { /* */ SHIELD_AVERT_CRITICAL(Seg, seg); AVERT_CRITICAL(AccessSet, mode); if (BS_INTER(SegPM(seg), mode) != AccessSetEMPTY) { - SegSetPM(seg, BS_DIFF(SegPM(seg), mode)); + shieldSetPM(shield, seg, BS_DIFF(SegPM(seg), mode)); ProtSet(SegBase(seg), SegLimit(seg), SegPM(seg)); } } @@ -240,7 +321,14 @@ static Seg shieldDequeue(Shield shield, Index i) } -/* shieldFlushEntry -- flush a single entry from the queue */ +/* shieldFlushEntry -- flush a single entry from the queue + * + * If the segment is exposed we can simply dequeue it, because later + * there will be a call to ShieldCover that will put it back on the + * queue. If the segment is not exposed, we can sync its protection. + * (And if it does not have the shield raised any more, that will do + * nothing.) + */ static void shieldFlushEntry(Shield shield, Index i) { @@ -256,6 +344,7 @@ static void shieldFlushEntry(Shield shield, Index i) static void shieldQueueReset(Shield shield) { AVER(shield->depth == 0); /* overkill: implies no segs are queued */ + AVER(shield->unsynced == 0); shield->next = 0; shield->limit = 0; } @@ -319,7 +408,7 @@ static void shieldFlushEntries(Shield shield) Seg seg = shieldDequeue(shield, i); if (!SegIsSynced(seg)) { AVER(SegSM(seg) != AccessSetEMPTY); /* can't match first iter */ - SegSetPM(seg, SegSM(seg)); + shieldSetPM(shield, seg, SegSM(seg)); if (SegSM(seg) != mode || SegBase(seg) != limit) { if (mode != AccessSetEMPTY) { AVER(base != NULL); @@ -365,7 +454,7 @@ static void shieldQueue(Arena arena, Seg seg) segment, then raise the shield on it. In this case, the mutator isn't allowed to see the segment, but we don't need to queue it until its covered. */ - ShieldHold(arena); + shieldSuspend(arena); return; } @@ -444,16 +533,18 @@ static void shieldQueue(Arena arena, Seg seg) void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode) { - SHIELD_AVERT(Arena, arena); SHIELD_AVERT(Seg, seg); - AVERT(AccessSet, mode); - AVER((SegSM(seg) & mode) == AccessSetEMPTY); - - SegSetSM(seg, SegSM(seg) | mode); /* .inv.prot.shield preserved */ - /* ensure .inv.unsynced.suspended and .inv.unsynced.depth */ + /* ShieldRaise does not nest. */ + AVER(BS_INTER(SegSM(seg), mode) == AccessSetEMPTY); + + /* design.mps.shield.inv.prot.shield preserved */ + shieldSetSM(ArenaShield(arena), seg, BS_UNION(SegSM(seg), mode)); + + /* Ensure design.mps.shield.inv.unsynced.suspended and + design.mps.shield.inv.unsynced.depth */ shieldQueue(arena, seg); /* Check queue and segment consistency. */ @@ -466,19 +557,22 @@ void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode) void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) { + Shield shield; + AVERT(Arena, arena); + shield = ArenaShield(arena); SHIELD_AVERT(Seg, seg); AVERT(AccessSet, mode); AVER(BS_INTER(SegSM(seg), mode) == mode); - + /* SegIsSynced(seg) is not changed by the following preserving design.mps.shield.inv.unsynced.suspended and design.mps.shield.inv.prot.shield. */ - SegSetSM(seg, BS_DIFF(SegSM(seg), mode)); + shieldSetSM(shield, seg, BS_DIFF(SegSM(seg), mode)); /* TODO: Do we need to promptly call shieldProtLower here? It loses the opportunity to coalesce the protection call. It would violate design.mps.shield.prop.inside.access. */ - shieldProtLower(seg, mode); + shieldProtLower(shield, seg, mode); /* Check queue and segment consistency. */ AVERT(Arena, arena); @@ -588,9 +682,12 @@ void (ShieldLeave)(Arena arena) shield = ArenaShield(arena); AVER(shield->inside); AVER(shield->depth == 0); /* no pending covers */ + AVER(shield->holds == 0); ShieldFlush(arena); + AVER(shield->unsynced == 0); /* everything back in sync */ + /* Ensuring the mutator is running at this point guarantees .inv.outside.running */ if (shield->suspended) { @@ -625,12 +722,12 @@ void (ShieldExpose)(Arena arena, Seg seg) AVER_CRITICAL(shield->depth > 0); /* overflow */ if (BS_INTER(SegPM(seg), mode) != AccessSetEMPTY) - ShieldHold(arena); + shieldSuspend(arena); /* Ensure design.mps.shield.inv.expose.prot. */ /* TODO: Mass exposure -- see design.mps.shield.improv.mass-expose. */ - shieldProtLower(seg, mode); + shieldProtLower(shield, seg, mode); } diff --git a/mps/code/trace.c b/mps/code/trace.c index e81ab41c869..148db0166bf 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -732,14 +732,6 @@ Res TraceCreate(Trace *traceReturn, Arena arena, int why) EVENT3(TraceCreate, trace, arena, (EventFU)why); - /* We suspend the mutator threads so that the PoolWhiten methods */ - /* can calculate white sets without the mutator allocating in */ - /* buffers under our feet. */ - /* @@@@ This is a short-term fix for request.dylan.160098_. */ - /* .. _request.dylan.160098: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160098 */ - /* TODO: Where is the corresponding ShieldRelease? */ - ShieldHold(arena); - STATISTIC_STAT ({ /* Iterate over all chains, all GenDescs within a chain, and all * PoolGens within a GenDesc. */ @@ -1491,6 +1483,14 @@ static Res traceCondemnAll(Trace trace) arena = trace->arena; AVERT(Arena, arena); + /* We suspend the mutator threads so that the PoolWhiten methods */ + /* can calculate white sets without the mutator allocating in */ + /* buffers under our feet. */ + /* @@@@ This is a short-term fix for request.dylan.160098_. */ + /* .. _request.dylan.160098: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160098 */ + /* TODO: Where is the corresponding ShieldRelease? */ + ShieldHold(arena); + /* Condemn all segments in pools with the GC attribute. */ RING_FOR(poolNode, &ArenaGlobals(arena)->poolRing, nextPoolNode) { Pool pool = RING_ELT(Pool, arenaRing, poolNode); @@ -1509,6 +1509,8 @@ static Res traceCondemnAll(Trace trace) } } + ShieldRelease(arena); + if (TraceIsEmpty(trace)) return ResFAIL; @@ -1529,6 +1531,7 @@ static Res traceCondemnAll(Trace trace) * will be triggered. In that case, we'll have to recover here by * blackening the segments again. */ AVER(TraceIsEmpty(trace)); + ShieldRelease(arena); return res; } From c69b78c3dbc3e21e62cd92a0a5ae254046e2e9ae Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 23 Mar 2016 12:55:07 +0000 Subject: [PATCH 298/337] Clarifying definition of "exposed". Copied from Perforce Change: 190326 ServerID: perforce.ravenbrook.com --- mps/design/shield.txt | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/mps/design/shield.txt b/mps/design/shield.txt index 52011a28ca0..72068789c28 100644 --- a/mps/design/shield.txt +++ b/mps/design/shield.txt @@ -49,7 +49,7 @@ Mutator access The shield provides ``ShieldRaise`` and ``ShieldLower`` to forbid or permit the mutator access to object memory segments. Between these -two, a segment is said to have the shield "raised". +two, a segment is said to have the shield "raised" (.def.raised). ``void ShieldRaise(Arena arena, Seg seg, AccessSet mode)`` @@ -66,15 +66,15 @@ an OS-specific hardware protection fault which reaches ``ArenaAccess``, does whatever work is necessary, then lowers the shield and returns to the mutator. -``ShieldRaise`` and ``ShieldLower` do *not* nest. +``ShieldRaise`` and ``ShieldLower`` do *not* nest. Entering the shield ................... -The MPS can only gain exclusive access from "inside" the shield. To -enter the shield, the MPS must call ``ShieldEnter``, and to leave it, -the MPS must call ``ShieldLeave``. +The MPS can only gain exclusive access from "inside" the shield +(.def.inside). To enter the shield, the MPS must call +``ShieldEnter``, and to leave it, the MPS must call ``ShieldLeave``. ``ShieldEnter`` and ``ShieldLeave`` are called by ``ArenaEnter`` and ``ArenaLeave`` so almost all of the MPS is is "inside" the shield. @@ -85,8 +85,10 @@ Collector access to aegments When the MPS wants to access object memory segments from inside the shield, it must wrap any accesses with a ``ShieldExpose`` and -``ShieldCover`` pair. Between calls to ``ShieldExpose`` and -``ShieldCover``, a segment is said to be "exposed". +``ShieldCover`` pair. These calls nest. After a call to +``ShieldExpose`` a segment is said to be "exposed" until the last +nested call to ``ShieldCover``. The shield arranges that the MPS can +access the memory while it is exposed. A segment might for example be exposed during: @@ -164,15 +166,19 @@ Implementation .impl.delay: The implementation of the shield avoids suspending threads for as long as possible. When threads are suspended, it -maintains a queue of covered segments where the desired and actual -protection do not match. This queue is flushed on leaving the shield. +maintains a queue of segments where the desired and actual protection +do not match. This queue is flushed on leaving the shield. Definitions ........... -.def.exposed: A seg is exposed if the prot mode is a subset of the -shield mode, and covered otherwise. +.def.raised: A segment has the shield "raised" for an access mode +after a call to ``ShieldRaise`` and before a call to ``ShieldLower`` +with that mode. + +.def.exposed: A segment is "exposed" after a call to ``ShieldExpose`` +and before a call to ``ShieldLower``. .def.synced: A seg is synced if the prot and shield modes are the same, and unsynced otherwise. @@ -180,8 +186,8 @@ same, and unsynced otherwise. .def.depth: The depth of a segment is defined as: | depth ≔ #exposes − #covers, where - | #exposes = the total number of times the seg has been exposed - | #covers = the total number of times the seg has been covered + | #exposes = the number of calls to ``ShieldExpose`` on the seg + | #covers = the number of calls to ``ShieldCover`` on the seg The queue is initially empty and ``ShieldCover`` should not be called without a matching ``ShieldExpose``, so this figure should always be @@ -232,6 +238,8 @@ in the queue. .inv.prot.shield: The prot mode is never more than the shield mode. +.inv.expose.depth: An exposed seg's depth is greater than zero. + .inv.expose.prot: An exposed seg is not protected in the mode it was exposed with. From f8a79ec8e44f3e4535536e72ab449e65ed3a6e8c Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 23 Mar 2016 13:11:19 +0000 Subject: [PATCH 299/337] Added discussion of when it might be good to resume the mutator early in design.mps.shield.improv.resume. Copied from Perforce Change: 190329 ServerID: perforce.ravenbrook.com --- mps/code/seg.c | 4 +++- mps/code/shield.c | 8 ++++---- mps/design/shield.txt | 18 +++++++++++++++--- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/mps/code/seg.c b/mps/code/seg.c index 64fb86c2d28..e7c43c31ddf 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -714,11 +714,13 @@ Bool SegCheck(Seg seg) /* CHECKL(RingNext(&seg->poolRing) != &seg->poolRing); */ CHECKD_NOSIG(Ring, &seg->poolRing); + + /* Shield invariants -- see design.mps.shield. */ /* The protection mode is never more than the shield mode (design.mps.shield.inv.prot.shield). */ CHECKL(BS_DIFF(seg->pm, seg->sm) == 0); - + /* All unsynced segments have positive depth or are in the queue (design.mps.shield.inv.unsynced.depth). */ CHECKL(seg->sm == seg->pm || seg->depth > 0 || seg->queued); diff --git a/mps/code/shield.c b/mps/code/shield.c index 307c8d89606..5245d2a9177 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -284,7 +284,8 @@ void (ShieldRelease)(Arena arena) /* It is only correct to actually resume the mutator here if shield->depth is 0, shield->unsycned is 0, and the queue is empty. */ - /* TODO: Consider actually doing that. */ + /* See design.mps.shield.improv.resume for a discussion of when it + might be a good idea to resume the mutator early. */ } @@ -618,7 +619,7 @@ static void shieldDebugCheck(Arena arena) Count queued = 0; AVERT(Arena, arena); - shield = ShieldArena(arena); + shield = ArenaShield(arena); AVER(shield->inside || shield->limit == 0); if (SegFirst(&seg, arena)) @@ -664,8 +665,7 @@ void (ShieldFlush)(Arena arena) shieldDebugCheck(arena); #endif shieldFlushEntries(shield); - /* Queue is empty so .inv.outside.depth holds */ - AVER(shield->depth == 0); + AVER(shield->unsynced == 0); /* everything back in sync */ #ifdef SHIELD_DEBUG shieldDebugCheck(arena); #endif diff --git a/mps/design/shield.txt b/mps/design/shield.txt index 72068789c28..a93736f8a16 100644 --- a/mps/design/shield.txt +++ b/mps/design/shield.txt @@ -189,9 +189,8 @@ same, and unsynced otherwise. | #exposes = the number of calls to ``ShieldExpose`` on the seg | #covers = the number of calls to ``ShieldCover`` on the seg -The queue is initially empty and ``ShieldCover`` should not be called -without a matching ``ShieldExpose``, so this figure should always be -non-negative. +``ShieldCover`` should not be called without a matching +``ShieldExpose``, so this figure should always be non-negative. .def.total.depth: The total depth is the sum of the depth over all segments. @@ -330,6 +329,19 @@ MPS design. It's kind of waiting to happen. (Originally written at .) +Early Resume +............ + +.improv.resume: There is a tradeoff between delaying flushing the +shield queue (preventing unnecessary protection and allowing us to +coalesce) and resuming mutator threads. We could resume threads +earlier under some circumstances, such as before reclaim (which does +not need to interact with the mutator). Basically, it might be worth +resuming the mutator early in a pause if we know that we're unlikely +to suspend it again (no more calls to ``ShieldRaise`` or +``ShieldExpose`` on shielded segments). + + References ---------- From 4204f99d6705148a2ce1a2cfcff3374df59eb934 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 23 Mar 2016 13:47:55 +0000 Subject: [PATCH 300/337] Moving quicksort's workspace off the stack to limit mps stack usage. Copied from Perforce Change: 190332 ServerID: perforce.ravenbrook.com --- mps/code/mpm.c | 31 ++++++++++++++++++------------- mps/code/mpm.h | 3 ++- mps/code/mpmst.h | 15 +++++++++++++++ mps/code/shield.c | 3 ++- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/mps/code/mpm.c b/mps/code/mpm.c index f2ea2acb27a..56b5c3973c8 100644 --- a/mps/code/mpm.c +++ b/mps/code/mpm.c @@ -9,6 +9,7 @@ * .sources: */ #include "check.h" +#include "misc.h" #include "mpm.h" #include "vm.h" @@ -699,20 +700,24 @@ static Bool quickSorted(void *array[], Count length, #endif void QuickSort(void *array[], Count length, - QuickSortCompare compare, void *closure) + QuickSortCompare compare, void *closure, + SortStruct *sortStruct) { - struct { - Index left, right; - } stack[MPS_WORD_WIDTH]; Index left, right, sp, lo, hi, leftLimit, rightBase; void *pivot, *temp; + AVER(array != NULL); + /* can't check length */ + AVER(FUNCHECK(compare)); + /* can't check closure */ + AVER(sortStruct != NULL); + sp = 0; left = 0; right = length; for (;;) { - while (right - left > 1) { /* no need to sort */ + while (right - left > 1) { /* only need to sort if two or more */ /* Pick a random pivot. */ pivot = array[left + RandomWord() % (right - left)]; @@ -751,15 +756,15 @@ void QuickSort(void *array[], Count length, /* Sort the smaller part now, so that we're sure to use at most log2 length stack levels. Push the larger part on the stack for later. */ - AVER_CRITICAL(sp < sizeof stack / sizeof stack[0]); + AVER_CRITICAL(sp < sizeof sortStruct->stack / sizeof sortStruct->stack[0]); if (leftLimit - left < right - rightBase) { - stack[sp].left = rightBase; - stack[sp].right = right; + sortStruct->stack[sp].left = rightBase; + sortStruct->stack[sp].right = right; ++sp; right = leftLimit; } else { - stack[sp].left = left; - stack[sp].right = leftLimit; + sortStruct->stack[sp].left = left; + sortStruct->stack[sp].right = leftLimit; ++sp; left = rightBase; } @@ -769,9 +774,9 @@ void QuickSort(void *array[], Count length, break; --sp; - left = stack[sp].left; - right = stack[sp].right; - AVER_CRITICAL(left < right); /* we do the smaller side immediately */ + left = sortStruct->stack[sp].left; + right = sortStruct->stack[sp].right; + AVER_CRITICAL(left < right); /* we did the smaller side earlier */ } #ifdef QUICKSORT_DEBUG diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 5b03ee449e0..9c5de02fb74 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -177,7 +177,8 @@ extern Word RandomWord(void); typedef Compare QuickSortCompare(void *left, void *right, void *closure); extern void QuickSort(void *array[], Count length, - QuickSortCompare compare, void *closure); + QuickSortCompare compare, void *closure, + SortStruct *sortStruct); /* Version Determination diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index ea8d8bd00bd..b7e338c1319 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -677,6 +677,20 @@ typedef struct FreelistStruct { } FreelistStruct; +/* SortStruct -- extra memory required by sorting + * + * See QuickSort in mpm.c. This exists so that the caller can make + * the choice about where to allocate the memory, since the MPS has to + * operate in tight stack constraints -- see design.mps.sp. + */ + +typedef struct SortStruct { + struct { + Index left, right; + } stack[MPS_WORD_WIDTH]; +} SortStruct; + + /* ShieldStruct -- per-arena part of the shield * * See design.mps.shield, impl.c.shield. @@ -695,6 +709,7 @@ typedef struct ShieldStruct { Count unsynced; /* number of unsynced segments */ Count holds; /* number of holds */ Bool suspended; /* mutator suspended? */ + SortStruct sortStruct; /* workspace for queue sort */ } ShieldStruct; diff --git a/mps/code/shield.c b/mps/code/shield.c index 5245d2a9177..0a00ae8f740 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -402,7 +402,8 @@ static void shieldFlushEntries(Shield shield) } QuickSort((void *)shield->queue, shield->limit, - shieldQueueEntryCompare, UNUSED_POINTER); + shieldQueueEntryCompare, UNUSED_POINTER, + &shield->sortStruct); mode = AccessSetEMPTY; for (i = 0; i < shield->limit; ++i) { From c1c7c0cca336335f65ac6d204f054231976dc11f Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 23 Mar 2016 13:54:22 +0000 Subject: [PATCH 301/337] Bracketing out unused stringequal and tidying up stringlength. Copied from Perforce Change: 190333 ServerID: perforce.ravenbrook.com --- mps/code/mpm.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/mps/code/mpm.c b/mps/code/mpm.c index 882a46b7092..a31ab2b5388 100644 --- a/mps/code/mpm.c +++ b/mps/code/mpm.c @@ -619,16 +619,19 @@ Res WriteF_firstformat_v(mps_lib_FILE *stream, Count depth, size_t StringLength(const char *s) { - size_t i; + size_t i = 0; AVER(s != NULL); - for(i = 0; s[i] != '\0'; i++) - NOOP; - return(i); + while (s[i] != '\0') + ++i; + + return i; } +#if 0 /* This code is currently not in use in the MPS */ + /* StringEqual -- slow substitute for (strcmp == 0) */ Bool StringEqual(const char *s1, const char *s2) @@ -649,6 +652,8 @@ Bool StringEqual(const char *s1, const char *s2) return TRUE; } +#endif /* not currently in use */ + /* C. COPYRIGHT AND LICENSE From 0f3a469fa760790586ac19e526ea7648d67ed895 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 23 Mar 2016 14:23:14 +0000 Subject: [PATCH 302/337] Responding to review by gdr . Copied from Perforce Change: 190336 ServerID: perforce.ravenbrook.com --- mps/code/mpmst.h | 2 +- mps/code/seg.c | 3 ++- mps/code/shield.c | 6 ++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index b7e338c1319..99c63458825 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -699,7 +699,7 @@ typedef struct SortStruct { #define ShieldSig ((Sig)0x519581E1) /* SIGnature SHEILd */ typedef struct ShieldStruct { - Sig sig; + Sig sig; /* design.mps.sig */ Bool inside; /* design.mps.shield.def.inside */ Seg *queue; /* queue of unsynced segs */ Count length; /* number of elements in shield queue */ diff --git a/mps/code/seg.c b/mps/code/seg.c index e7c43c31ddf..bd0abeb018b 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -224,7 +224,7 @@ static void SegFinish(Seg seg) AVER(seg->depth == 0); if (seg->queued) ShieldFlush(PoolArena(SegPool(seg))); - AVER(seg->queued == FALSE); + AVER(!seg->queued); limit = SegLimit(seg); @@ -686,6 +686,7 @@ Bool SegCheck(Seg seg) CHECKL(AddrIsArenaGrain(TractBase(seg->firstTract), arena)); CHECKL(AddrIsArenaGrain(seg->limit, arena)); CHECKL(seg->limit > TractBase(seg->firstTract)); + CHECKL(BoolCheck(seg->queued)); /* Each tract of the segment must agree about white traces. Note * that even if the CHECKs are compiled away there is still a diff --git a/mps/code/shield.c b/mps/code/shield.c index 0a00ae8f740..61976403a5c 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -46,6 +46,12 @@ void ShieldDestroyQueue(Shield shield, Arena arena) void ShieldFinish(Shield shield) { + /* The queue should already have been destroyed by + GlobalsPrepareToDestroy calling ShieldDestroyQueue. */ + AVER(shield->length == 0); + AVER(shield->limit == 0); + AVER(shield->queue == NULL); + AVER(shield->depth == 0); AVER(shield->unsynced == 0); AVER(shield->holds == 0); From 20f558f64abc49bbdf4b13cc29b8f04b5a6ab60d Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 23 Mar 2016 14:37:54 +0000 Subject: [PATCH 303/337] Improving commentary in response to nb . Copied from Perforce Change: 190339 ServerID: perforce.ravenbrook.com --- mps/code/mpm.c | 16 +++++++++------- mps/code/shield.c | 10 ++++++---- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/mps/code/mpm.c b/mps/code/mpm.c index 56b5c3973c8..1781b6959a4 100644 --- a/mps/code/mpm.c +++ b/mps/code/mpm.c @@ -721,8 +721,9 @@ void QuickSort(void *array[], Count length, /* Pick a random pivot. */ pivot = array[left + RandomWord() % (right - left)]; - /* Hoare partition: scan from lo to hi, dividing it into elements - less than the pivot and elements greater or equal. */ + /* Hoare partition: scan from left to right, dividing it into + elements less than the pivot and elements greater or + equal. */ lo = left; hi = right; for (;;) { @@ -739,10 +740,11 @@ void QuickSort(void *array[], Count length, ++lo; /* step over what we just swapped */ } - /* If we ended up at a pivot, then it is in its final position - and we must skip it to ensure termination. This handles the case - where the pivot is at the start of the array, and one of the - partitions is the whole array, for example. */ + /* After partition, if we ended up at a pivot, then it is in its + final position and we must skip it to ensure termination. + This handles the case where the pivot is at the start of the + array, and one of the partitions is the whole array, for + example. */ if (lo == hi) { AVER_CRITICAL(array[hi] == pivot); /* and it's in place */ leftLimit = lo; @@ -776,7 +778,7 @@ void QuickSort(void *array[], Count length, --sp; left = sortStruct->stack[sp].left; right = sortStruct->stack[sp].right; - AVER_CRITICAL(left < right); /* we did the smaller side earlier */ + AVER_CRITICAL(left < right); /* we will have done a zero-length part first */ } #ifdef QUICKSORT_DEBUG diff --git a/mps/code/shield.c b/mps/code/shield.c index 61976403a5c..6ec445e2215 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -398,7 +398,7 @@ static Compare shieldQueueEntryCompare(void *left, void *right, void *closure) static void shieldFlushEntries(Shield shield) { - Addr base = NULL, limit = NULL; + Addr base = NULL, limit; AccessSet mode; Index i; @@ -412,10 +412,10 @@ static void shieldFlushEntries(Shield shield) &shield->sortStruct); mode = AccessSetEMPTY; + limit = NULL; for (i = 0; i < shield->limit; ++i) { Seg seg = shieldDequeue(shield, i); if (!SegIsSynced(seg)) { - AVER(SegSM(seg) != AccessSetEMPTY); /* can't match first iter */ shieldSetPM(shield, seg, SegSM(seg)); if (SegSM(seg) != mode || SegBase(seg) != limit) { if (mode != AccessSetEMPTY) { @@ -651,8 +651,10 @@ static void shieldDebugCheck(Arena arena) /* ShieldFlush -- empty the shield queue * * .shield.flush: Flush empties the shield queue. This needs to be - * called before segments in the queue are destroyed, as there may be - * references to them in the queue. + * called before queued segments are destroyed, to remove them from + * the queue. We flush the whole queue because finding the entry is + * O(n) and we're very likely reclaiming and destroying loads of + * segments. See also design.mps.shield.improv.resume. * * The memory for the segment may become spare, and not released back * to the operating system. Since we keep track of protection on From d161c0e4eed57078be4c934847062c442d833c3a Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 23 Mar 2016 15:48:58 +0000 Subject: [PATCH 304/337] Forgot shieldhold/shieldrelease in tracecondemnzones. caught by hot builds of amcssth. Copied from Perforce Change: 190344 ServerID: perforce.ravenbrook.com --- mps/code/trace.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/mps/code/trace.c b/mps/code/trace.c index 148db0166bf..894d1715d49 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -408,6 +408,8 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet) arena = trace->arena; + ShieldHold(arena); /* .whiten.hold */ + if(SegFirst(&seg, arena)) { do { /* Segment should be black now. */ @@ -430,6 +432,8 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet) } while (SegNext(&seg, arena, seg)); } + ShieldRelease(arena); + EVENT3(TraceCondemnZones, trace, condemnedSet, trace->white); /* The trace's white set must be a subset of the condemned set */ @@ -438,6 +442,7 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet) return ResOK; failBegin: + ShieldRelease(arena); AVER(TraceIsEmpty(trace)); /* See .whiten.fail. */ return res; } @@ -1483,12 +1488,12 @@ static Res traceCondemnAll(Trace trace) arena = trace->arena; AVERT(Arena, arena); - /* We suspend the mutator threads so that the PoolWhiten methods */ - /* can calculate white sets without the mutator allocating in */ - /* buffers under our feet. */ - /* @@@@ This is a short-term fix for request.dylan.160098_. */ - /* .. _request.dylan.160098: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160098 */ - /* TODO: Where is the corresponding ShieldRelease? */ + /* .whiten.hold: We suspend the mutator threads so that the + PoolWhiten methods can calculate white sets without the mutator + allocating in buffers under our feet. See request.dylan.160098 + . */ + /* TODO: Consider how to avoid this suspend in order to implement + incremental condemn. */ ShieldHold(arena); /* Condemn all segments in pools with the GC attribute. */ From 33b28efbdbd5f40266b37ac904ea25a75c62777e Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 23 Mar 2016 17:31:59 +0000 Subject: [PATCH 305/337] Responding to review by nb . Copied from Perforce Change: 190349 ServerID: perforce.ravenbrook.com --- mps/code/seg.c | 3 ++- mps/code/shield.c | 6 +++--- mps/design/shield.txt | 25 +++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/mps/code/seg.c b/mps/code/seg.c index bd0abeb018b..d83443fad06 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -686,7 +686,8 @@ Bool SegCheck(Seg seg) CHECKL(AddrIsArenaGrain(TractBase(seg->firstTract), arena)); CHECKL(AddrIsArenaGrain(seg->limit, arena)); CHECKL(seg->limit > TractBase(seg->firstTract)); - CHECKL(BoolCheck(seg->queued)); + /* Can't BoolCheck seg->queued because compilers warn about that on + single-bit fields. */ /* Each tract of the segment must agree about white traces. Note * that even if the CHECKs are compiled away there is still a diff --git a/mps/code/shield.c b/mps/code/shield.c index 6ec445e2215..d27c2611288 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -466,9 +466,7 @@ static void shieldQueue(Arena arena, Seg seg) return; } - /* Allocate shield queue if necessary. */ - /* TODO: This will try to extend the queue on every attempt, even - if it failed last time. That might be slow. */ + /* Allocate or extend the shield queue if necessary. */ if (shield->next >= shield->length) { void *p; Res res; @@ -509,6 +507,8 @@ static void shieldQueue(Arena arena, Seg seg) AVER_CRITICAL(shield->limit <= shield->length); AVER_CRITICAL(shield->next <= shield->limit); + /* If we failed to extend the shield queue array, degrade to an LRU + circular buffer. */ if (shield->next >= shield->length) shield->next = 0; AVER_CRITICAL(shield->next < shield->length); diff --git a/mps/design/shield.txt b/mps/design/shield.txt index a93736f8a16..13743d3496b 100644 --- a/mps/design/shield.txt +++ b/mps/design/shield.txt @@ -342,6 +342,31 @@ to suspend it again (no more calls to ``ShieldRaise`` or ``ShieldExpose`` on shielded segments). +Expose modes +............ + +.improv.expose-modes: Would it be a good idea for ShieldExpose() to +take an AccessSet? It might be good if we didn't have to raise a write +barrier unless we want to write. When scanning (for instance), we may +not need to write, so when scanning a segment behind a write barrier +we shouldn't have to call mprotect(). That's a bit speculative: how +often do we scan a segment and not write to it. Alternatively, and +more speculatively, we could keep the write barrier up, handle the +(possibly nested) trap and *then* expose the shield. I'm just +scraping around for ways to reduce calls to mprotect(). + +Theoretically we can do this, but: + + 1. We're mostly a moving collector so we'll almost always want to + write to segments we scan. That could change if we do more + non-moving collection. + + 2. The main cost of protection is changing it at all, not whether we + change just read or write. On OS X, the main cost seems to be the + TLB flush, which affects wall-clock time of everything on the + processor! + + References ---------- From 97e64d3666d11dce008c53faad6a43540175d283 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 23 Mar 2016 17:35:25 +0000 Subject: [PATCH 306/337] Design document formatting fix. Copied from Perforce Change: 190350 ServerID: perforce.ravenbrook.com --- mps/design/shield.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/design/shield.txt b/mps/design/shield.txt index 13743d3496b..eab5410be43 100644 --- a/mps/design/shield.txt +++ b/mps/design/shield.txt @@ -80,8 +80,8 @@ The MPS can only gain exclusive access from "inside" the shield ``ArenaLeave`` so almost all of the MPS is is "inside" the shield. -Collector access to aegments ----------------------------- +Collector access to segments +............................ When the MPS wants to access object memory segments from inside the shield, it must wrap any accesses with a ``ShieldExpose`` and From b635b8e701b7a0d52a4fbd0b458e5f1e97604884 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 23 Mar 2016 17:54:43 +0000 Subject: [PATCH 307/337] Improving markup of cross-references. Copied from Perforce Change: 190351 ServerID: perforce.ravenbrook.com --- mps/design/shield.txt | 78 +++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/mps/design/shield.txt b/mps/design/shield.txt index eab5410be43..b10bf6771bd 100644 --- a/mps/design/shield.txt +++ b/mps/design/shield.txt @@ -49,7 +49,7 @@ Mutator access The shield provides ``ShieldRaise`` and ``ShieldLower`` to forbid or permit the mutator access to object memory segments. Between these -two, a segment is said to have the shield "raised" (.def.raised). +two, a segment is said to have the shield "raised" (`.def.raised`_). ``void ShieldRaise(Arena arena, Seg seg, AccessSet mode)`` @@ -73,7 +73,7 @@ Entering the shield ................... The MPS can only gain exclusive access from "inside" the shield -(.def.inside). To enter the shield, the MPS must call +(`.def.inside`_). To enter the shield, the MPS must call ``ShieldEnter``, and to leave it, the MPS must call ``ShieldLeave``. ``ShieldEnter`` and ``ShieldLeave`` are called by ``ArenaEnter`` and @@ -145,10 +145,10 @@ usage count reaches zero, there is no longer any reason the segment should be unprotected, and the shield may reinstate hardware protection at any time. -.impl.delay: However, as a performance-improving hysteresis, the -shield defers re-protection, maintaining a queue of segments that -require attention before mutator threads are resumed. While a segment -is in the queue, it has ``seg->queued`` set to TRUE. +However, as a performance-improving hysteresis, the shield defers +re-protection, maintaining a queue of segments that require attention +before mutator threads are resumed (`.impl.delay`_). While a segment is +in the queue, it has ``seg->queued`` set to TRUE. This hysteresis allows the MPS to proceed with garbage collection during a pause without actually setting hardware protection until it @@ -157,14 +157,14 @@ systems where the protection is expensive and poorly implemented, such as OS X. The queue also ensures that no memory protection system calls will be -neededIf a complete collection cycle occurs during one pause, allowing -the MPS to operate in a non-incremental mode. +needed if a complete collection cycle occurs during one pause, +allowing the MPS to operate in a non-incremental mode. Implementation -------------- -.impl.delay: The implementation of the shield avoids suspending +_`.impl.delay`: The implementation of the shield avoids suspending threads for as long as possible. When threads are suspended, it maintains a queue of segments where the desired and actual protection do not match. This queue is flushed on leaving the shield. @@ -173,17 +173,17 @@ do not match. This queue is flushed on leaving the shield. Definitions ........... -.def.raised: A segment has the shield "raised" for an access mode +_`.def.raised`: A segment has the shield "raised" for an access mode after a call to ``ShieldRaise`` and before a call to ``ShieldLower`` with that mode. -.def.exposed: A segment is "exposed" after a call to ``ShieldExpose`` +_`.def.exposed`: A segment is "exposed" after a call to ``ShieldExpose`` and before a call to ``ShieldLower``. -.def.synced: A seg is synced if the prot and shield modes are the +_`.def.synced`: A seg is synced if the prot and shield modes are the same, and unsynced otherwise. -.def.depth: The depth of a segment is defined as: +_`.def.depth`: The depth of a segment is defined as: | depth ≔ #exposes − #covers, where | #exposes = the number of calls to ``ShieldExpose`` on the seg @@ -192,54 +192,54 @@ same, and unsynced otherwise. ``ShieldCover`` should not be called without a matching ``ShieldExpose``, so this figure should always be non-negative. -.def.total.depth: The total depth is the sum of the depth over all +_`.def.total.depth`: The total depth is the sum of the depth over all segments. -.def.outside: Being outside the shield is being between calls to -``ShieldLeave`` and ``ShieldEnter``, and similarly .def.inside: being +_`.def.outside`: Being outside the shield is being between calls to +``ShieldLeave`` and ``ShieldEnter``, and similarly _`.def.inside`: being inside the shield is being between calls to ``ShieldEnter`` and ``ShieldLeave``. [In a multi-threaded MPS this would be per-thread. RB 2016-03-18] -.def.suspended: Suspended is true iff the mutator is +_`.def.suspended`: Suspended is true iff the mutator is suspended. [Between calls to ThreadSuspend and ThreadResume?] -.def.shielded: A segment is shielded if the shield mode is +_`.def.shielded`: A segment is shielded if the shield mode is non-zero. [As set by ShieldRaise.] Properties .......... -.prop.outside.running: The mutator may not be suspended while outside +_`.prop.outside.running`: The mutator may not be suspended while outside the shield. -.prop.mutator.access: An attempt by the mutator to access shielded +_`.prop.mutator.access`: An attempt by the mutator to access shielded memory be pre-empted by a call to ``ArenaAccess``. -.prop.inside.access: Inside the shield the MPS must be able to access +_`.prop.inside.access`: Inside the shield the MPS must be able to access all unshielded segments and all exposed segments. Invariants .......... -.inv.outside.running: The mutator is not suspended while outside the +_`.inv.outside.running`: The mutator is not suspended while outside the shield. -.inv.unsynced.suspended: If any segment is not synced, the mutator is +_`.inv.unsynced.suspended`: If any segment is not synced, the mutator is suspended. -.inv.unsynced.depth: All unsynced segments have positive depth or are +_`.inv.unsynced.depth`: All unsynced segments have positive depth or are in the queue. -.inv.outside.depth: The total depth is zero while outside the shield. +_`.inv.outside.depth`: The total depth is zero while outside the shield. -.inv.prot.shield: The prot mode is never more than the shield mode. +_`.inv.prot.shield`: The prot mode is never more than the shield mode. -.inv.expose.depth: An exposed seg's depth is greater than zero. +_`.inv.expose.depth`: An exposed seg's depth is greater than zero. -.inv.expose.prot: An exposed seg is not protected in the mode it was +_`.inv.expose.prot`: An exposed seg is not protected in the mode it was exposed with. @@ -248,22 +248,22 @@ Proof Hints Hints at proofs of properties from invariants. -.proof.outside: .inv.outside.running directly ensures .prop.outside +_`.proof.outside`: .inv.outside.running directly ensures .prop.outside running. -.proof.sync: As the depth of a segment cannot be negative +_`.proof.sync`: As the depth of a segment cannot be negative | total depth = 0 | ⇒ for all segments, depth = 0 | ⇒ all segs are synced (by .inv.unsynced.depth) -.proof.access: If the mutator is running then all segs must be synced +_`.proof.access`: If the mutator is running then all segs must be synced (.inv.unsynced.suspend). Which means that the hardware protection (.prot mode) must reflect the software protection (shield mode). Hence all shielded memory will be hardware protected while the mutator is running. This ensures .prop.mutator.access. -.proof.inside: .inv.prot.shield and .inv.expose.prot ensure +_`.proof.inside`: .inv.prot.shield and .inv.expose.prot ensure .prop.inside.access. @@ -281,7 +281,7 @@ Improvement Ideas Mass exposure ............. -.improv.mass-expose: If protection calls have a high overhead it might +_`.improv.mass-expose`: If protection calls have a high overhead it might be good to pre-emptively unprotect large ranges of memory when we expose one segment. With the current design this would mean discovering adjacent shielded segments and adding them to the queue. @@ -292,7 +292,7 @@ exposed segments during a pause. Segment independence .................... -.improve.noseg: The shield is implemented in terms of segments, using +_`.improve.noseg`: The shield is implemented in terms of segments, using fields in the segment structure to represent its state. This forces us to (for example) flush the shield queue when deleting a segment. The shield could keep track of protection and shielding independently, @@ -303,7 +303,7 @@ use of system calls (see .improve.mass-expose). Concurrent collection ..................... -.improv.concurrent: The MPS currently does not collect concurrently, +_`.improv.concurrent`: The MPS currently does not collect concurrently, however the only thing that makes it not-concurrent is a critical point in the Shield abstraction where the MPS seeks to gain privileged access to memory (usually in order to scan it for GC). The critical @@ -332,7 +332,7 @@ MPS design. It's kind of waiting to happen. Early Resume ............ -.improv.resume: There is a tradeoff between delaying flushing the +_`.improv.resume`: There is a tradeoff between delaying flushing the shield queue (preventing unnecessary protection and allowing us to coalesce) and resuming mutator threads. We could resume threads earlier under some circumstances, such as before reclaim (which does @@ -345,7 +345,7 @@ to suspend it again (no more calls to ``ShieldRaise`` or Expose modes ............ -.improv.expose-modes: Would it be a good idea for ShieldExpose() to +_`.improv.expose-modes`: Would it be a good idea for ShieldExpose() to take an AccessSet? It might be good if we didn't have to raise a write barrier unless we want to write. When scanning (for instance), we may not need to write, so when scanning a segment behind a write barrier @@ -406,8 +406,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +Copyright © 2013-2016 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 From f3b84793229b97197823a894693e426b67b599ee Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 23 Mar 2016 17:55:22 +0000 Subject: [PATCH 308/337] Improving commentary: the mutator is suspended, not the arena. Copied from Perforce Change: 190352 ServerID: perforce.ravenbrook.com --- mps/code/shield.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/shield.c b/mps/code/shield.c index d27c2611288..71ee4ec0950 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -442,7 +442,7 @@ static void shieldFlushEntries(Shield shield) /* shieldQueue -- consider adding a segment to the queue * * If the segment is out of sync, either sync it, or ensure it is - * queued and the arena is suspended. + * queued and the mutator is suspended. */ static void shieldQueue(Arena arena, Seg seg) From eb1d39c425514b18a4e5b0e4559eb75cc6342bdc Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 23 Mar 2016 19:03:00 +0000 Subject: [PATCH 309/337] Improving shieldflushentries to allow for delayed protection changes on shieldlower. Copied from Perforce Change: 190363 ServerID: perforce.ravenbrook.com --- mps/code/shield.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/mps/code/shield.c b/mps/code/shield.c index 71ee4ec0950..43eb3e284c5 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -226,8 +226,8 @@ static void shieldSync(Shield shield, Seg seg) SHIELD_AVERT_CRITICAL(Seg, seg); if (!SegIsSynced(seg)) { - ProtSet(SegBase(seg), SegLimit(seg), SegSM(seg)); shieldSetPM(shield, seg, SegSM(seg)); + ProtSet(SegBase(seg), SegLimit(seg), SegPM(seg)); } } @@ -418,8 +418,7 @@ static void shieldFlushEntries(Shield shield) if (!SegIsSynced(seg)) { shieldSetPM(shield, seg, SegSM(seg)); if (SegSM(seg) != mode || SegBase(seg) != limit) { - if (mode != AccessSetEMPTY) { - AVER(base != NULL); + if (base != NULL) { AVER(base < limit); ProtSet(base, limit, mode); } @@ -429,9 +428,8 @@ static void shieldFlushEntries(Shield shield) limit = SegLimit(seg); } } - if (mode != AccessSetEMPTY) { - AVER(base != NULL); - AVER(limit != NULL); + if (base != NULL) { + AVER(base < limit); ProtSet(base, limit, mode); } @@ -580,6 +578,7 @@ void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) /* TODO: Do we need to promptly call shieldProtLower here? It loses the opportunity to coalesce the protection call. It would violate design.mps.shield.prop.inside.access. */ + /* shieldQueue(arena, seg); */ shieldProtLower(shield, seg, mode); /* Check queue and segment consistency. */ From 06d330a2cb2b472b98865900dbf5b5d1f0a6e79f Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 24 Mar 2016 03:25:28 +0000 Subject: [PATCH 310/337] Adding release note about write barrier deferral. Copied from Perforce Change: 190358 ServerID: perforce.ravenbrook.com --- mps/manual/source/release.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 1a70fd0b0b2..6816fc16087 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -141,6 +141,14 @@ Other changes .. _job003938: https://www.ravenbrook.com/project/mps/issue/job003938/ +#. The MPS is less aggressive in its use of hardware memory protection + to maintain :term:`write barrier` to speed up future collections. + This is particularly important for OS X, where memory protection is + poorly implemented. See job003371_ and job003975_. + + .. _job003371: http://www.ravenbrook.com/project/mps/issue/job003371/ + .. _job003975: http://www.ravenbrook.com/project/mps/issue/job003975/ + .. _release-notes-1.114: From fb816556409120eac517927adc34227e9562d8ff Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 24 Mar 2016 03:35:58 +0000 Subject: [PATCH 311/337] Writing release note about shield coalescing. Copied from Perforce Change: 190364 ServerID: perforce.ravenbrook.com --- mps/manual/source/release.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 1a70fd0b0b2..e976a4a4ea2 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -141,6 +141,14 @@ Other changes .. _job003938: https://www.ravenbrook.com/project/mps/issue/job003938/ +#. The MPS coalesces memory protection, reducing the number of system + calls. This drastically improves real run time on operating systems + where memory protection is poorly implemented, such as OS X, but + also has a significant effect on Linux. See job003371_ and + job003975_. + + .. _job003371: http://www.ravenbrook.com/project/mps/issue/job003371/ + .. _job003975: http://www.ravenbrook.com/project/mps/issue/job003975/ .. _release-notes-1.114: From 4f3a29c419bb8c8c48f6a6b1973a83dafcac5679 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 24 Mar 2016 10:29:54 +0000 Subject: [PATCH 312/337] Miscellaneous corrections to shield design. Promoting shield design from "old" to "current" in the manual. Copied from Perforce Change: 190369 ServerID: perforce.ravenbrook.com --- mps/design/shield.txt | 32 +++++++++++++----------------- mps/manual/source/design/index.rst | 3 ++- mps/manual/source/design/old.rst | 1 - 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/mps/design/shield.txt b/mps/design/shield.txt index b10bf6771bd..9b56c96a466 100644 --- a/mps/design/shield.txt +++ b/mps/design/shield.txt @@ -108,7 +108,7 @@ need never expose them to gain access. Collector access to the unprotectable ..................................... -Then the MPS wants to access an unprotectable object from inside the +When the MPS wants to access an unprotectable object from inside the shield, it must wrap any accesses with a ``ShieldHold`` and ``ShieldRelease`` pair. This allows access to objects which cannot be shielded by ``ShieldRaise``, such as: @@ -134,7 +134,7 @@ On common operating systems, the only way to allow the MPS access is to allow access from the whole process, including the mutator. So ``ShieldExpose`` will suspend all mutator threads to prevent any mutator access, and so will ``ShieldRaise`` on an unexposed segment. The -shield handles suspending and resuming threads, and the the rest of +shield handles suspending and resuming threads, and so the rest of the MPS does not need to worry about it. The MPS can make multiple sequential, overlapping, or nested calls to @@ -148,7 +148,7 @@ protection at any time. However, as a performance-improving hysteresis, the shield defers re-protection, maintaining a queue of segments that require attention before mutator threads are resumed (`.impl.delay`_). While a segment is -in the queue, it has ``seg->queued`` set to TRUE. +in the queue, it has ``seg->queued`` set true. This hysteresis allows the MPS to proceed with garbage collection during a pause without actually setting hardware protection until it @@ -157,8 +157,8 @@ systems where the protection is expensive and poorly implemented, such as OS X. The queue also ensures that no memory protection system calls will be -needed if a complete collection cycle occurs during one pause, -allowing the MPS to operate in a non-incremental mode. +needed for incremental garbage collection if a complete collection +cycle occurs during one pause. Implementation @@ -201,9 +201,6 @@ inside the shield is being between calls to ``ShieldEnter`` and ``ShieldLeave``. [In a multi-threaded MPS this would be per-thread. RB 2016-03-18] -_`.def.suspended`: Suspended is true iff the mutator is -suspended. [Between calls to ThreadSuspend and ThreadResume?] - _`.def.shielded`: A segment is shielded if the shield mode is non-zero. [As set by ShieldRaise.] @@ -248,8 +245,8 @@ Proof Hints Hints at proofs of properties from invariants. -_`.proof.outside`: .inv.outside.running directly ensures .prop.outside -running. +_`.proof.outside`: `.inv.outside.running`_ directly ensures +`.prop.outside.running`_. _`.proof.sync`: As the depth of a segment cannot be negative @@ -257,14 +254,13 @@ _`.proof.sync`: As the depth of a segment cannot be negative | ⇒ for all segments, depth = 0 | ⇒ all segs are synced (by .inv.unsynced.depth) -_`.proof.access`: If the mutator is running then all segs must be synced -(.inv.unsynced.suspend). Which means that the hardware protection -(.prot mode) must reflect the software protection (shield mode). -Hence all shielded memory will be hardware protected while the mutator -is running. This ensures .prop.mutator.access. - -_`.proof.inside`: .inv.prot.shield and .inv.expose.prot ensure -.prop.inside.access. +_`.proof.access`: If the mutator is running then all segs must be +synced (`.inv.unsynced.suspend`_). Which means that the hardware +protection (protection mode) must reflect the software protection +(shield mode). Hence all shielded memory will be hardware protected +while the mutator is running. This ensures `.prop.mutator.access`_. +_`.proof.inside`: `.inv.prot.shield`_ and `.inv.expose.prot`_ ensure +`.prop.inside.access`_. Initial ideas diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 1cea6c4861b..1c9d27f94b7 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -29,8 +29,9 @@ Design prot range ring - sp + shield sig + sp splay ss testthr diff --git a/mps/manual/source/design/old.rst b/mps/manual/source/design/old.rst index 69c872c773c..28b115e2335 100644 --- a/mps/manual/source/design/old.rst +++ b/mps/manual/source/design/old.rst @@ -48,7 +48,6 @@ Old design root scan seg - shield sso1al strategy telemetry From 428e8bae9282de5244965f1779e251c9e23a924e Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 24 Mar 2016 11:04:58 +0000 Subject: [PATCH 313/337] Fixing build errors on windows (w3i6mv). tagtest was missing from makefiles. Implicit conversion warning from Clock to double. Copied from Perforce Change: 190372 ServerID: perforce.ravenbrook.com --- mps/code/commpost.nmk | 3 +++ mps/code/commpre.nmk | 1 + mps/code/global.c | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk index 201094905bd..35b26ee19f3 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/commpost.nmk @@ -291,6 +291,9 @@ $(PFM)\$(VARIETY)\segsmss.exe: $(PFM)\$(VARIETY)\segsmss.obj \ $(PFM)\$(VARIETY)\steptest.exe: $(PFM)\$(VARIETY)\steptest.obj \ $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) +$(PFM)\$(VARIETY)\tagtest.exe: $(PFM)\$(VARIETY)\tagtest.obj \ + $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) + $(PFM)\$(VARIETY)\teletest.exe: $(PFM)\$(VARIETY)\teletest.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index d1aa7e49d6e..c428e909fa9 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -95,6 +95,7 @@ TEST_TARGETS=\ sacss.exe \ segsmss.exe \ steptest.exe \ + tagtest.exe \ teletest.exe \ walkt0.exe \ zcoll.exe \ diff --git a/mps/code/global.c b/mps/code/global.c index 120161bbf5c..08497c7cc46 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -776,7 +776,7 @@ Bool ArenaStep(Globals globals, double interval, double multiplier) trace = ArenaTrace(arena, (TraceId)0); } else { /* No traces are running: consider collecting the world. */ - if (PolicyShouldCollectWorld(arena, availableEnd - now, now, + if (PolicyShouldCollectWorld(arena, (double)(availableEnd - now), now, clocks_per_sec)) { Res res; From 6090670a8d417191cc13c289b9c306e830491708 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 24 Mar 2016 12:42:27 +0000 Subject: [PATCH 314/337] Running autoreconf to get freebsd with clang into the configure script. Copied from Perforce Change: 190384 ServerID: perforce.ravenbrook.com --- mps/configure | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/mps/configure b/mps/configure index 2aa767cd2d5..0bdf69b11d3 100755 --- a/mps/configure +++ b/mps/configure @@ -3513,6 +3513,16 @@ $as_echo "FreeBSD x86" >&6; } CPP="$CC -I/usr/local/include -E" PFMCFLAGS="$CFLAGS_GC" ;; + amd64-*-freebsd*/yes | x86_64-*-freebsd*/yes) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: FreeBSD x86_64" >&5 +$as_echo "FreeBSD x86_64" >&6; } + MPS_OS_NAME=fr + MPS_ARCH_NAME=i6 + MPS_BUILD_NAME=ll + # Need /usr/local/include in order to find sqlite3.h + CFLAGS="-I/usr/local/include" + CPP="$CC -I/usr/local/include -E" + PFMCFLAGS="$CFLAGS_GC" amd64-*-freebsd*/no | x86_64-*-freebsd*/no) { $as_echo "$as_me:${as_lineno-$LINENO}: result: FreeBSD x86_64" >&5 $as_echo "FreeBSD x86_64" >&6; } @@ -4789,3 +4799,44 @@ fi echo 1>&2 "CONFIGURE/MAKE IS NOT THE BEST WAY TO BUILD THE MPS -- see " + + +# C. COPYRIGHT AND LICENSE +# +# Copyright (C) 2012-2016 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 1a03f7520fb574a2b0cb35062a4faaca80d5ba68 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 24 Mar 2016 12:44:53 +0000 Subject: [PATCH 315/337] Fixing syntax error in detection of freebsd with clang. Copied from Perforce Change: 190385 ServerID: perforce.ravenbrook.com --- mps/configure | 1 + mps/configure.ac | 1 + 2 files changed, 2 insertions(+) diff --git a/mps/configure b/mps/configure index 0bdf69b11d3..8d938b2d09d 100755 --- a/mps/configure +++ b/mps/configure @@ -3523,6 +3523,7 @@ $as_echo "FreeBSD x86_64" >&6; } CFLAGS="-I/usr/local/include" CPP="$CC -I/usr/local/include -E" PFMCFLAGS="$CFLAGS_GC" + ;; amd64-*-freebsd*/no | x86_64-*-freebsd*/no) { $as_echo "$as_me:${as_lineno-$LINENO}: result: FreeBSD x86_64" >&5 $as_echo "FreeBSD x86_64" >&6; } diff --git a/mps/configure.ac b/mps/configure.ac index c7928ec14bb..436aad238c6 100644 --- a/mps/configure.ac +++ b/mps/configure.ac @@ -107,6 +107,7 @@ case $host/$CLANG in CFLAGS="-I/usr/local/include" CPP="$CC -I/usr/local/include -E" PFMCFLAGS="$CFLAGS_GC" + ;; amd64-*-freebsd*/no | x86_64-*-freebsd*/no) AC_MSG_RESULT([FreeBSD x86_64]) MPS_OS_NAME=fr From cae88818754b7f7350856612cd11b70f4c147964 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 24 Mar 2016 17:49:06 +0000 Subject: [PATCH 316/337] Mentioning freebsd with clang/llvm support in the readme.txt. Copied from Perforce Change: 190389 ServerID: perforce.ravenbrook.com --- mps/readme.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mps/readme.txt b/mps/readme.txt index 2959f6eb7b4..08f0fe40b8a 100644 --- a/mps/readme.txt +++ b/mps/readme.txt @@ -77,7 +77,7 @@ The MPS is currently supported for deployment on: - Linux 2.4 or later, on IA-32 using GCC and on x86-64 using GCC or Clang/LLVM; -- FreeBSD 7 or later, on IA-32 and x86-64, using GCC; +- FreeBSD 7 or later, on IA-32 and x86-64, using GCC or Clang/LLVM; - OS X 10.4 or later, on IA-32 and x86-64, using Clang/LLVM. @@ -132,6 +132,7 @@ Document History brought to you in glorious reStructuredText. 2014-01-13 GDR_ Updated supported platforms. 2014-07-04 GDR_ Link to hotfix for WOW64 bug. +2016-03-24 RB_ Adding support for FreeBSD with Clang/LLVM. ========== ===== ====================================================== .. _GDR: mailto:gdr@ravenbrook.com @@ -143,7 +144,7 @@ Document History Copyright and Licence --------------------- -Copyright (C) 2001-2014 Ravenbrook Limited. All rights reserved. +Copyright (C) 2001-2016 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. From 36beebd4400a4d059fdfee086f136299d9c41cfc Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 24 Mar 2016 21:59:39 +0000 Subject: [PATCH 317/337] Correcting return type of zonesetofrange to a zoneset. Copied from Perforce Change: 190395 ServerID: perforce.ravenbrook.com --- mps/code/ref.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/mps/code/ref.c b/mps/code/ref.c index 3f330315556..c9b2de07aa6 100644 --- a/mps/code/ref.c +++ b/mps/code/ref.c @@ -1,7 +1,7 @@ /* ref.c: REFERENCES * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * .purpose: Implement operations on Ref, RefSet, ZoneSet, and Rank. * @@ -35,7 +35,7 @@ Bool RankSetCheck(RankSet rankSet) /* ZoneSetOfRange -- calculate the zone set of a range of addresses */ -RefSet ZoneSetOfRange(Arena arena, Addr base, Addr limit) +ZoneSet ZoneSetOfRange(Arena arena, Addr base, Addr limit) { Word zbase, zlimit; @@ -292,13 +292,9 @@ ZoneSet ZoneSetBlacklist(Arena arena) } - - - - /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From 08637d7d97d472df4d4f994371851e9eeb8db620 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 27 Mar 2016 11:14:27 +0100 Subject: [PATCH 318/337] Fixing the position of the ravenbrook url in the licences in design documents. Copied from Perforce Change: 190434 ServerID: perforce.ravenbrook.com --- mps/design/abq.txt | 4 ++-- mps/design/alloc-frame.txt | 4 ++-- mps/design/an.txt | 4 ++-- mps/design/arena.txt | 4 ++-- mps/design/arenavm.txt | 4 ++-- mps/design/bt.txt | 4 ++-- mps/design/buffer.txt | 4 ++-- mps/design/check.txt | 4 ++-- mps/design/class-interface.txt | 4 ++-- mps/design/clock.txt | 4 ++-- mps/design/collection.txt | 4 ++-- mps/design/config.txt | 4 ++-- mps/design/diag.txt | 4 ++-- mps/design/exec-env.txt | 4 ++-- mps/design/finalize.txt | 4 ++-- mps/design/fix.txt | 4 ++-- mps/design/freelist.txt | 4 ++-- mps/design/guide.hex.trans.txt | 4 ++-- mps/design/guide.review.txt | 4 ++-- mps/design/index.txt | 4 ++-- mps/design/interface-c.txt | 4 ++-- mps/design/io.txt | 4 ++-- mps/design/keyword-arguments.txt | 4 ++-- mps/design/lib.txt | 4 ++-- mps/design/lock.txt | 4 ++-- mps/design/locus.txt | 4 ++-- mps/design/message-gc.txt | 4 ++-- mps/design/message.txt | 4 ++-- mps/design/nailboard.txt | 4 ++-- mps/design/object-debug.txt | 4 ++-- mps/design/pool.txt | 4 ++-- mps/design/poolamc.txt | 4 ++-- mps/design/poolams.txt | 4 ++-- mps/design/poolawl.txt | 4 ++-- mps/design/poollo.txt | 4 ++-- mps/design/poolmfs.txt | 4 ++-- mps/design/poolmrg.txt | 4 ++-- mps/design/poolmv.txt | 4 ++-- mps/design/poolmvff.txt | 11 ++++++----- mps/design/prmc.txt | 4 ++-- mps/design/prot.txt | 4 ++-- mps/design/protli.txt | 4 ++-- mps/design/protocol.txt | 4 ++-- mps/design/protsu.txt | 4 ++-- mps/design/pthreadext.txt | 4 ++-- mps/design/range.txt | 4 ++-- mps/design/root.txt | 4 ++-- mps/design/sig.txt | 4 ++-- mps/design/sp.txt | 4 ++-- mps/design/splay.txt | 4 ++-- mps/design/ss.txt | 4 ++-- mps/design/sso1al.txt | 4 ++-- mps/design/strategy.txt | 4 ++-- mps/design/telemetry.txt | 4 ++-- mps/design/tests.txt | 4 ++-- mps/design/testthr.txt | 4 ++-- mps/design/thread-manager.txt | 4 ++-- mps/design/thread-safety.txt | 4 ++-- mps/design/trace.txt | 4 ++-- mps/design/type.txt | 4 ++-- mps/design/version-library.txt | 4 ++-- mps/design/version.txt | 4 ++-- mps/design/vm.txt | 4 ++-- mps/design/vmo1.txt | 4 ++-- mps/design/vmso.txt | 4 ++-- mps/design/writef.txt | 4 ++-- 66 files changed, 136 insertions(+), 135 deletions(-) diff --git a/mps/design/abq.txt b/mps/design/abq.txt index cc0cfe0159f..75aaec3d1a2 100644 --- a/mps/design/abq.txt +++ b/mps/design/abq.txt @@ -120,8 +120,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2016 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +Copyright © 2013-2016 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 diff --git a/mps/design/alloc-frame.txt b/mps/design/alloc-frame.txt index b199c2c567f..4dac0fe9fb1 100644 --- a/mps/design/alloc-frame.txt +++ b/mps/design/alloc-frame.txt @@ -473,8 +473,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/an.txt b/mps/design/an.txt index 7d6cc117407..78ecccfeafb 100644 --- a/mps/design/an.txt +++ b/mps/design/an.txt @@ -176,8 +176,8 @@ Document History Copyright and License --------------------- -Copyright © 2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/arena.txt b/mps/design/arena.txt index 1d7f412dd86..7d6fe4c0eb7 100644 --- a/mps/design/arena.txt +++ b/mps/design/arena.txt @@ -616,8 +616,8 @@ Document History Copyright and License --------------------- -Copyright © 2001-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +Copyright © 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 diff --git a/mps/design/arenavm.txt b/mps/design/arenavm.txt index d746f18d883..c43a35bb3d0 100644 --- a/mps/design/arenavm.txt +++ b/mps/design/arenavm.txt @@ -235,8 +235,8 @@ management of page table mapping. Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/bt.txt b/mps/design/bt.txt index bc069efd2a9..4d6a40b8460 100644 --- a/mps/design/bt.txt +++ b/mps/design/bt.txt @@ -751,8 +751,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/buffer.txt b/mps/design/buffer.txt index 04b8779e2ca..a15a63c76f0 100644 --- a/mps/design/buffer.txt +++ b/mps/design/buffer.txt @@ -736,8 +736,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/check.txt b/mps/design/check.txt index 138c2a7fc1d..2cf5bf091c6 100644 --- a/mps/design/check.txt +++ b/mps/design/check.txt @@ -138,8 +138,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/class-interface.txt b/mps/design/class-interface.txt index 65cc8accb2a..00925e51019 100644 --- a/mps/design/class-interface.txt +++ b/mps/design/class-interface.txt @@ -264,8 +264,8 @@ Document history Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/clock.txt b/mps/design/clock.txt index d9b73d43081..3213d6ccff5 100644 --- a/mps/design/clock.txt +++ b/mps/design/clock.txt @@ -93,8 +93,8 @@ Document History Copyright and License --------------------- -Copyright © 2016 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +Copyright © 2016 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 diff --git a/mps/design/collection.txt b/mps/design/collection.txt index ebf0c05df9f..9adea762c5e 100644 --- a/mps/design/collection.txt +++ b/mps/design/collection.txt @@ -419,8 +419,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/config.txt b/mps/design/config.txt index 9d49a5889ce..544b9a61ed1 100644 --- a/mps/design/config.txt +++ b/mps/design/config.txt @@ -610,8 +610,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2016 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +Copyright © 2013-2016 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 diff --git a/mps/design/diag.txt b/mps/design/diag.txt index f8e86e2bdda..15384db203b 100644 --- a/mps/design/diag.txt +++ b/mps/design/diag.txt @@ -193,8 +193,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/exec-env.txt b/mps/design/exec-env.txt index 29576212b4a..71d7287f057 100644 --- a/mps/design/exec-env.txt +++ b/mps/design/exec-env.txt @@ -149,8 +149,8 @@ Document History Copyright and License --------------------- -Copyright © 1996-2016 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +Copyright © 1996-2016 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 diff --git a/mps/design/finalize.txt b/mps/design/finalize.txt index e3668716df7..b8e47021a0a 100644 --- a/mps/design/finalize.txt +++ b/mps/design/finalize.txt @@ -139,8 +139,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/fix.txt b/mps/design/fix.txt index dce6b561c84..7bd8b3a9b89 100644 --- a/mps/design/fix.txt +++ b/mps/design/fix.txt @@ -73,8 +73,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/freelist.txt b/mps/design/freelist.txt index c89181505c1..c86ae9a9f14 100644 --- a/mps/design/freelist.txt +++ b/mps/design/freelist.txt @@ -172,8 +172,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/guide.hex.trans.txt b/mps/design/guide.hex.trans.txt index 8120f6e53e5..bf20d099096 100644 --- a/mps/design/guide.hex.trans.txt +++ b/mps/design/guide.hex.trans.txt @@ -144,8 +144,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/guide.review.txt b/mps/design/guide.review.txt index 4bed3049842..52d8f4635ea 100644 --- a/mps/design/guide.review.txt +++ b/mps/design/guide.review.txt @@ -56,8 +56,8 @@ Document History Copyright and License --------------------- -Copyright © 2015-2016 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +Copyright © 2015-2016 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 diff --git a/mps/design/index.txt b/mps/design/index.txt index 7c889f1ee30..e486020574d 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -240,8 +240,8 @@ Document History Copyright and License --------------------- -Copyright © 2002-2016 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +Copyright © 2002-2016 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 diff --git a/mps/design/interface-c.txt b/mps/design/interface-c.txt index 1e5424105b7..912b4aa9bdf 100644 --- a/mps/design/interface-c.txt +++ b/mps/design/interface-c.txt @@ -405,8 +405,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/io.txt b/mps/design/io.txt index 27ab9d7802a..0a89d5e6d41 100644 --- a/mps/design/io.txt +++ b/mps/design/io.txt @@ -431,8 +431,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2015 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +Copyright © 2013-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 diff --git a/mps/design/keyword-arguments.txt b/mps/design/keyword-arguments.txt index af6db232a5a..5a7f1d1f1a5 100644 --- a/mps/design/keyword-arguments.txt +++ b/mps/design/keyword-arguments.txt @@ -163,8 +163,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/lib.txt b/mps/design/lib.txt index 1dd7efe6964..1da7f673c49 100644 --- a/mps/design/lib.txt +++ b/mps/design/lib.txt @@ -95,8 +95,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2015 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +Copyright © 2013-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 diff --git a/mps/design/lock.txt b/mps/design/lock.txt index 069474ae428..ed1bbcd14a7 100644 --- a/mps/design/lock.txt +++ b/mps/design/lock.txt @@ -287,8 +287,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/locus.txt b/mps/design/locus.txt index 4777857c9d7..ebee711f481 100644 --- a/mps/design/locus.txt +++ b/mps/design/locus.txt @@ -700,8 +700,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/message-gc.txt b/mps/design/message-gc.txt index f69a3d2c3f0..94de3049552 100644 --- a/mps/design/message-gc.txt +++ b/mps/design/message-gc.txt @@ -317,8 +317,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/message.txt b/mps/design/message.txt index 807f9cc6cdd..1c5d4210914 100644 --- a/mps/design/message.txt +++ b/mps/design/message.txt @@ -407,8 +407,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/nailboard.txt b/mps/design/nailboard.txt index 2f88b5b57b7..cce46ac34d0 100644 --- a/mps/design/nailboard.txt +++ b/mps/design/nailboard.txt @@ -214,8 +214,8 @@ Document History Copyright and License --------------------- -Copyright © 2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/object-debug.txt b/mps/design/object-debug.txt index 627f8352c3a..a803b16eb1d 100644 --- a/mps/design/object-debug.txt +++ b/mps/design/object-debug.txt @@ -427,8 +427,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/pool.txt b/mps/design/pool.txt index 2ad6d6e64d7..e54f55b60b0 100644 --- a/mps/design/pool.txt +++ b/mps/design/pool.txt @@ -78,8 +78,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/poolamc.txt b/mps/design/poolamc.txt index f00bc4adbae..cd1612e982d 100644 --- a/mps/design/poolamc.txt +++ b/mps/design/poolamc.txt @@ -813,8 +813,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/poolams.txt b/mps/design/poolams.txt index ef59e46724a..30a4efc10e7 100644 --- a/mps/design/poolams.txt +++ b/mps/design/poolams.txt @@ -497,8 +497,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/poolawl.txt b/mps/design/poolawl.txt index 609d236320e..88d038b80b0 100644 --- a/mps/design/poolawl.txt +++ b/mps/design/poolawl.txt @@ -565,8 +565,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/poollo.txt b/mps/design/poollo.txt index ebb402c316b..aae70799452 100644 --- a/mps/design/poollo.txt +++ b/mps/design/poollo.txt @@ -265,8 +265,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/poolmfs.txt b/mps/design/poolmfs.txt index 31fe8c24cd9..4ed24263308 100644 --- a/mps/design/poolmfs.txt +++ b/mps/design/poolmfs.txt @@ -44,8 +44,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/poolmrg.txt b/mps/design/poolmrg.txt index 148e016fae7..9c8de7e092e 100644 --- a/mps/design/poolmrg.txt +++ b/mps/design/poolmrg.txt @@ -685,8 +685,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/poolmv.txt b/mps/design/poolmv.txt index 1b25c441a27..ca51cc59c6c 100644 --- a/mps/design/poolmv.txt +++ b/mps/design/poolmv.txt @@ -47,8 +47,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2016 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +Copyright © 2013-2016 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 diff --git a/mps/design/poolmvff.txt b/mps/design/poolmvff.txt index d29efc6ba89..6eb2004ea01 100644 --- a/mps/design/poolmvff.txt +++ b/mps/design/poolmvff.txt @@ -22,9 +22,10 @@ pool class. This pool implements a first (or last) fit policy for variable-sized manually-managed objects, with control over first/last, segment preference high/low, and slot fit low/high. -The pool was created in a response to a belief that the ScriptWorks -EPDL/EPDR's first fit policy is beneficial for some classes of client -behaviour, but the performance of a linear free list was unacceptable. +_`.background`: The pool was created in a response to a belief that +the ScriptWorks EPDL/EPDR's first fit policy is beneficial for some +classes of client behaviour, but the performance of a linear free list +was unacceptable. Overview @@ -115,8 +116,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/prmc.txt b/mps/design/prmc.txt index c7aaad52d57..e633729798f 100644 --- a/mps/design/prmc.txt +++ b/mps/design/prmc.txt @@ -271,8 +271,8 @@ Document History Copyright and License --------------------- -Copyright © 2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/prot.txt b/mps/design/prot.txt index fb06b78b328..0cdd8d38fcd 100644 --- a/mps/design/prot.txt +++ b/mps/design/prot.txt @@ -165,8 +165,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/protli.txt b/mps/design/protli.txt index 8d4a2f7b395..d07ee96065e 100644 --- a/mps/design/protli.txt +++ b/mps/design/protli.txt @@ -217,8 +217,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/protocol.txt b/mps/design/protocol.txt index 4dca17bcf97..38f29062913 100644 --- a/mps/design/protocol.txt +++ b/mps/design/protocol.txt @@ -540,8 +540,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/protsu.txt b/mps/design/protsu.txt index e31edf3fe73..22d9dca5224 100644 --- a/mps/design/protsu.txt +++ b/mps/design/protsu.txt @@ -131,8 +131,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/pthreadext.txt b/mps/design/pthreadext.txt index 18b7b2d9d9f..b2d886b75a5 100644 --- a/mps/design/pthreadext.txt +++ b/mps/design/pthreadext.txt @@ -368,8 +368,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/range.txt b/mps/design/range.txt index 9e6d4ce34a4..ee1e734ea40 100644 --- a/mps/design/range.txt +++ b/mps/design/range.txt @@ -124,8 +124,8 @@ Document history Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/root.txt b/mps/design/root.txt index dd20868f3ed..11eb65565a6 100644 --- a/mps/design/root.txt +++ b/mps/design/root.txt @@ -97,8 +97,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/sig.txt b/mps/design/sig.txt index 23f55a881a1..98ab1f489e0 100644 --- a/mps/design/sig.txt +++ b/mps/design/sig.txt @@ -177,8 +177,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2016 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +Copyright © 2013-2016 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 diff --git a/mps/design/sp.txt b/mps/design/sp.txt index 47dab436b4e..30c8fa62f35 100644 --- a/mps/design/sp.txt +++ b/mps/design/sp.txt @@ -186,8 +186,8 @@ Document History Copyright and License --------------------- -Copyright © 2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/splay.txt b/mps/design/splay.txt index 3a2ed9fd546..c1dfa8bb977 100644 --- a/mps/design/splay.txt +++ b/mps/design/splay.txt @@ -955,8 +955,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/ss.txt b/mps/design/ss.txt index 8ecd6a18153..d81a0c7a4c2 100644 --- a/mps/design/ss.txt +++ b/mps/design/ss.txt @@ -132,8 +132,8 @@ Document History Copyright and License --------------------- -Copyright © 2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/sso1al.txt b/mps/design/sso1al.txt index bcf2905f198..e7f7065675e 100644 --- a/mps/design/sso1al.txt +++ b/mps/design/sso1al.txt @@ -153,8 +153,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/strategy.txt b/mps/design/strategy.txt index 51b32e9e31a..97aa86a4a08 100644 --- a/mps/design/strategy.txt +++ b/mps/design/strategy.txt @@ -557,8 +557,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2016 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +Copyright © 2013-2016 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 diff --git a/mps/design/telemetry.txt b/mps/design/telemetry.txt index c19bbab0056..33ad9a4e38d 100644 --- a/mps/design/telemetry.txt +++ b/mps/design/telemetry.txt @@ -457,8 +457,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/tests.txt b/mps/design/tests.txt index e1e9eb51e83..31cfffb0bf2 100644 --- a/mps/design/tests.txt +++ b/mps/design/tests.txt @@ -76,8 +76,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2016 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +Copyright © 2013-2016 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 diff --git a/mps/design/testthr.txt b/mps/design/testthr.txt index a1bf99bb247..86f545aa194 100644 --- a/mps/design/testthr.txt +++ b/mps/design/testthr.txt @@ -115,8 +115,8 @@ Document History Copyright and License --------------------- -Copyright © 2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/thread-manager.txt b/mps/design/thread-manager.txt index 88f2b2478fa..1d6d585a9d6 100644 --- a/mps/design/thread-manager.txt +++ b/mps/design/thread-manager.txt @@ -335,8 +335,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/thread-safety.txt b/mps/design/thread-safety.txt index 826d008a596..9e3df1de20b 100644 --- a/mps/design/thread-safety.txt +++ b/mps/design/thread-safety.txt @@ -349,8 +349,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/trace.txt b/mps/design/trace.txt index 236a0cae5d9..a2869145155 100644 --- a/mps/design/trace.txt +++ b/mps/design/trace.txt @@ -295,8 +295,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/type.txt b/mps/design/type.txt index 008a54a209c..365de98b1a7 100644 --- a/mps/design/type.txt +++ b/mps/design/type.txt @@ -717,8 +717,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/version-library.txt b/mps/design/version-library.txt index b679c382713..0afb604e690 100644 --- a/mps/design/version-library.txt +++ b/mps/design/version-library.txt @@ -133,8 +133,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/version.txt b/mps/design/version.txt index 798c01ead99..15e661c9513 100644 --- a/mps/design/version.txt +++ b/mps/design/version.txt @@ -61,8 +61,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/vm.txt b/mps/design/vm.txt index fb1be6eb5da..72babab8396 100644 --- a/mps/design/vm.txt +++ b/mps/design/vm.txt @@ -369,8 +369,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/vmo1.txt b/mps/design/vmo1.txt index 33c90858439..2bb33a4f182 100644 --- a/mps/design/vmo1.txt +++ b/mps/design/vmo1.txt @@ -72,8 +72,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/vmso.txt b/mps/design/vmso.txt index a73a0d65cbd..9a06c26950b 100644 --- a/mps/design/vmso.txt +++ b/mps/design/vmso.txt @@ -159,8 +159,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +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 diff --git a/mps/design/writef.txt b/mps/design/writef.txt index 2a0277990e0..71792920102 100644 --- a/mps/design/writef.txt +++ b/mps/design/writef.txt @@ -158,8 +158,8 @@ Document History Copyright and License --------------------- -Copyright © 2013-2015 Ravenbrook Limited. All rights reserved. -. This is an open source license. Contact +Copyright © 2013-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 From bcc567710b6a64fde83aab386c752dc78a510ff0 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 27 Mar 2016 20:48:38 +0100 Subject: [PATCH 319/337] Documenting and checking constraints on mps_key_align on manual pools. Copied from Perforce Change: 190472 ServerID: perforce.ravenbrook.com --- mps/code/apss.c | 26 ++++++++++++++++---------- mps/code/poolmv.c | 5 ++++- mps/code/poolmv2.c | 6 +++--- mps/code/poolmvff.c | 6 +++--- mps/code/testlib.c | 26 +++++++++++++++++++++----- mps/code/testlib.h | 5 +++++ mps/manual/source/pool/mv.rst | 9 +++++---- mps/manual/source/pool/mvff.rst | 11 +++++------ mps/manual/source/pool/mvt.rst | 11 +++++------ mps/manual/source/topic/arena.rst | 6 +++--- 10 files changed, 70 insertions(+), 41 deletions(-) diff --git a/mps/code/apss.c b/mps/code/apss.c index 79a029f86b1..e254323e380 100644 --- a/mps/code/apss.c +++ b/mps/code/apss.c @@ -169,13 +169,14 @@ static mps_pool_debug_option_s fenceOptions = { */ static void test(mps_arena_class_t arena_class, mps_arg_s arena_args[], + size_t arena_grain_size, 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_align_t align = rnd_align(sizeof(void *), arena_grain_size); MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE); @@ -189,14 +190,14 @@ static void test(mps_arena_class_t arena_class, mps_arg_s arena_args[], /* yet (MV Debug works here, because it fakes it through PoolAlloc). */ MPS_ARGS_BEGIN(args) { - mps_align_t align = (mps_align_t)1 << (rnd() % 6); + mps_align_t align = rnd_align(sizeof(void *), arena_grain_size); MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); die(stress(arena, NULL, align, randomSizeAligned, "MV", mps_class_mv(), args), "stress MV"); } MPS_ARGS_END(args); MPS_ARGS_BEGIN(args) { - mps_align_t align = (mps_align_t)1 << (rnd() % 6); + mps_align_t align = rnd_align(sizeof(void *), arena_grain_size); MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options); die(stress(arena, options, align, randomSizeAligned, "MV debug", @@ -204,7 +205,7 @@ static void test(mps_arena_class_t arena_class, mps_arg_s arena_args[], } MPS_ARGS_END(args); MPS_ARGS_BEGIN(args) { - mps_align_t align = sizeof(void *) << (rnd() % 4); + mps_align_t align = rnd_align(sizeof(void *), arena_grain_size); MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); die(stress(arena, NULL, align, randomSizeAligned, "MVT", mps_class_mvt(), args), "stress MVT"); @@ -218,28 +219,33 @@ static void test(mps_arena_class_t arena_class, mps_arg_s arena_args[], int main(int argc, char *argv[]) { + size_t arena_grain_size; + testlib_init(argc, argv); + arena_grain_size = rnd_grain(2 * testArenaSIZE); 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_GRAIN_SIZE, arena_grain_size); MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, testArenaSIZE); - test(mps_arena_class_vm(), args, &fenceOptions); + test(mps_arena_class_vm(), args, arena_grain_size, &fenceOptions); } MPS_ARGS_END(args); + arena_grain_size = rnd_grain(2 * testArenaSIZE); 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)); - test(mps_arena_class_vm(), args, &bothOptions); + MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, arena_grain_size); + test(mps_arena_class_vm(), args, arena_grain_size, &bothOptions); } MPS_ARGS_END(args); + arena_grain_size = rnd_grain(testArenaSIZE); 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)); - test(mps_arena_class_cl(), args, &bothOptions); + MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, arena_grain_size); + test(mps_arena_class_cl(), args, arena_grain_size, &bothOptions); } MPS_ARGS_END(args); printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); diff --git a/mps/code/poolmv.c b/mps/code/poolmv.c index 719cba6d7df..f3ef16f69ee 100644 --- a/mps/code/poolmv.c +++ b/mps/code/poolmv.c @@ -29,6 +29,7 @@ #include "dbgpool.h" #include "poolmv.h" #include "poolmfs.h" +#include "mpscmvff.h" #include "mpm.h" SRCID(poolmv, "$Id$"); @@ -236,7 +237,10 @@ static Res MVInit(Pool pool, ArgList args) if (ArgPick(&arg, args, MPS_KEY_MAX_SIZE)) maxSize = arg.val.size; + arena = PoolArena(pool); + AVERT(Align, align); + AVER(align <= ArenaGrainSize(arena)); AVER(extendBy > 0); AVER(avgSize > 0); AVER(avgSize <= extendBy); @@ -245,7 +249,6 @@ static Res MVInit(Pool pool, ArgList args) pool->alignment = align; mv = PoolMV(pool); - arena = PoolArena(pool); /* At 100% fragmentation we will need one block descriptor for every other */ /* allocated block, or (extendBy/avgSize)/2 descriptors. See note 1. */ diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index dc352d6eb81..fbfb8464e61 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -259,10 +259,10 @@ static Res MVTInit(Pool pool, ArgList args) AVERT(Align, align); /* This restriction on the alignment is necessary because of the use - * of a Freelist to store the free address ranges in low-memory - * situations. See . - */ + of a Freelist to store the free address ranges in low-memory + situations. See . */ AVER(AlignIsAligned(align, FreelistMinimumAlignment)); + AVER(align <= ArenaGrainSize(arena)); AVER(0 < minSize); AVER(minSize <= meanSize); AVER(meanSize <= maxSize); diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 82d5c072ff3..64acc2606ab 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -486,10 +486,10 @@ static Res MVFFInit(Pool pool, ArgList args) AVER(spare <= 1.0); /* .arg.check */ AVERT(Align, align); /* This restriction on the alignment is necessary because of the use - * of a Freelist to store the free address ranges in low-memory - * situations. . - */ + of a Freelist to store the free address ranges in low-memory + situations. . */ AVER(AlignIsAligned(align, FreelistMinimumAlignment)); + AVER(align <= ArenaGrainSize(arena)); AVERT(Bool, slotHigh); AVERT(Bool, arenaHigh); AVERT(Bool, firstFit); diff --git a/mps/code/testlib.c b/mps/code/testlib.c index 401c4059938..af96d3643fb 100644 --- a/mps/code/testlib.c +++ b/mps/code/testlib.c @@ -220,14 +220,30 @@ double rnd_double(void) return rnd() / R_m_float; } +static unsigned sizelog2(size_t size) +{ + return (unsigned)(log((double)size) / log(2.0)); +} + size_t rnd_grain(size_t arena_size) { /* The grain size must be small enough to allow for a complete set - * of zones in the initial chunk. */ - size_t s = (size_t)(log((double)arena_size) / log(2.0)); - size_t shift = MPS_WORD_SHIFT; - Insist(s > shift); - return (size_t)1 << (rnd() % (s - shift)); + of zones in the initial chunk, but bigger than one word. */ + Insist(arena_size >> MPS_WORD_SHIFT >= sizeof(void *)); + return rnd_align(sizeof(void *), (size_t)1 << sizelog2(arena_size >> MPS_WORD_SHIFT)); +} + +size_t rnd_align(size_t min, size_t max) +{ + unsigned log2min = sizelog2(min); + unsigned log2max = sizelog2(max); + Insist(min <= max); + Insist(1uL << log2min == min); + Insist(1uL << log2max == max); + if (log2min < log2max) + return min << (rnd() % (log2max - log2min + 1)); + else + return min; } rnd_state_t rnd_seed(void) diff --git a/mps/code/testlib.h b/mps/code/testlib.h index 0b5b7160165..0492aaf138b 100644 --- a/mps/code/testlib.h +++ b/mps/code/testlib.h @@ -260,6 +260,11 @@ extern double rnd_double(void); extern size_t rnd_grain(size_t arena_size); +/* rnd_align -- random alignment */ + +extern size_t rnd_align(size_t min, size_t max); + + /* randomize -- randomize the generator, or initialize to replay * * randomize(argc, argv) randomizes the rnd generator (using time(3)) diff --git a/mps/manual/source/pool/mv.rst b/mps/manual/source/pool/mv.rst index 27e691ed3af..b8cfb08d2ea 100644 --- a/mps/manual/source/pool/mv.rst +++ b/mps/manual/source/pool/mv.rst @@ -70,10 +70,11 @@ MV interface optional :term:`keyword arguments`: * :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is - :c:macro:`MPS_PF_ALIGN`) is the - :term:`alignment` of addresses for allocation (and freeing) in - the pool. If an unaligned size is passed to :c:func:`mps_alloc` or - :c:func:`mps_free`, it will be rounded up to the pool's alignment. + :c:macro:`MPS_PF_ALIGN`) is the :term:`alignment` of the + addresses allocated (and freed) in the pool. The minimum + alignment supported by pools of this class is 1 (one) + and the maximum is the arena grain size + (see :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE`). * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default 65536) is the :term:`size` of block that the pool will diff --git a/mps/manual/source/pool/mvff.rst b/mps/manual/source/pool/mvff.rst index 04a7d48603d..fd890f17dc9 100644 --- a/mps/manual/source/pool/mvff.rst +++ b/mps/manual/source/pool/mvff.rst @@ -115,12 +115,11 @@ MVFF interface efficient if this is wrong, but nothing will break. * :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is - :c:macro:`MPS_PF_ALIGN`) is the - :term:`alignment` of addresses for allocation (and freeing) in - the pool. If an unaligned size is passed to :c:func:`mps_alloc` - or :c:func:`mps_free`, it will be rounded up to the pool's - alignment. The minimum alignment supported by pools of this - class is ``sizeof(void *)``. + :c:macro:`MPS_PF_ALIGN`) is the :term:`alignment` of the + addresses allocated (and freed) in the pool. The minimum + alignment supported by pools of this class is ``sizeof(void *)`` + and the maximum is the arena grain size + (see :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE`). * :c:macro:`MPS_KEY_SPARE` (type :c:type:`double`, default 0.75) is the maximum proportion of memory that the pool will keep diff --git a/mps/manual/source/pool/mvt.rst b/mps/manual/source/pool/mvt.rst index da2ce024baa..8973823f948 100644 --- a/mps/manual/source/pool/mvt.rst +++ b/mps/manual/source/pool/mvt.rst @@ -115,12 +115,11 @@ MVT interface optional :term:`keyword arguments`: * :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is - :c:macro:`MPS_PF_ALIGN`) is the - :term:`alignment` of addresses for allocation (and freeing) in - the pool. If an unaligned size is passed to :c:func:`mps_alloc` or - :c:func:`mps_free`, it will be rounded up to the pool's alignment. - The minimum alignment supported by pools of this class is - ``sizeof(void *)``. + :c:macro:`MPS_PF_ALIGN`) is the :term:`alignment` of the + addresses allocated (and freed) in the pool. The minimum + alignment supported by pools of this class is ``sizeof(void *)`` + and the maximum is the arena grain size + (see :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE`). * :c:macro:`MPS_KEY_MIN_SIZE` (type :c:type:`size_t`, default is :c:macro:`MPS_PF_ALIGN`) is the diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index 2d6b99ca0db..d538402cba9 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -150,9 +150,9 @@ Client arenas * :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` (type :c:type:`size_t`, default 8192) is the granularity with which the arena will - manage memory internally. It must be a power of 2. Larger - granularity reduces overheads, but increases - :term:`fragmentation` and :term:`retention`. + manage memory internally. It must be a power of 2, and at least + ``sizeof(void *)``. Larger granularity reduces overheads, but + increases :term:`fragmentation` and :term:`retention`. * :c:macro:`MPS_KEY_PAUSE_TIME` (type :c:type:`double`, default 0.1) is the maximum time, in seconds, that operations within the From e67a9934f174bd62c3c4fe01bc0e66ad05d40289 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sun, 27 Mar 2016 21:17:53 +0100 Subject: [PATCH 320/337] Cross-referencing comment about non-working debugging aps to job003995. Copied from Perforce Change: 190477 ServerID: perforce.ravenbrook.com --- mps/code/apss.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mps/code/apss.c b/mps/code/apss.c index e254323e380..7f579e54dda 100644 --- a/mps/code/apss.c +++ b/mps/code/apss.c @@ -186,8 +186,9 @@ static void test(mps_arena_class_t arena_class, mps_arg_s arena_args[], mps_class_mvff(), args), "stress MVFF"); } MPS_ARGS_END(args); - /* IWBN to test MVFFDebug, but the MPS doesn't support debugging APs, */ - /* yet (MV Debug works here, because it fakes it through PoolAlloc). */ + /* IWBN to test MVFFDebug, but the MPS doesn't support debugging + APs, yet (MV Debug works here, because it fakes it through + PoolAlloc). See job003995. */ MPS_ARGS_BEGIN(args) { mps_align_t align = rnd_align(sizeof(void *), arena_grain_size); From 956f09bc2d76d90c51e81c4b61a45cbb29ec0acb Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 31 Mar 2016 09:28:41 +0100 Subject: [PATCH 321/337] Reducing over-ambitious random alignment increases in apss test. Copied from Perforce Change: 190575 ServerID: perforce.ravenbrook.com --- mps/code/apss.c | 11 +++++++---- mps/example/scheme/scheme-advanced.c | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/mps/code/apss.c b/mps/code/apss.c index 7f579e54dda..fbe58f249df 100644 --- a/mps/code/apss.c +++ b/mps/code/apss.c @@ -23,6 +23,7 @@ #define testArenaSIZE ((((size_t)3)<<24) - 4) #define testSetSIZE 200 #define testLOOPS 10 +#define MAX_ALIGN 64 /* TODO: Make this test work up to arena_grain_size? */ /* make -- allocate one object */ @@ -175,8 +176,10 @@ static void test(mps_arena_class_t arena_class, mps_arg_s arena_args[], mps_arena_t arena; die(mps_arena_create_k(&arena, arena_class, arena_args), "mps_arena_create"); + (void)arena_grain_size; /* TODO: test larger alignments up to this */ + MPS_ARGS_BEGIN(args) { - mps_align_t align = rnd_align(sizeof(void *), arena_grain_size); + mps_align_t align = rnd_align(sizeof(void *), MAX_ALIGN); MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE); @@ -191,14 +194,14 @@ static void test(mps_arena_class_t arena_class, mps_arg_s arena_args[], PoolAlloc). See job003995. */ MPS_ARGS_BEGIN(args) { - mps_align_t align = rnd_align(sizeof(void *), arena_grain_size); + mps_align_t align = rnd_align(sizeof(void *), MAX_ALIGN); MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); die(stress(arena, NULL, align, randomSizeAligned, "MV", mps_class_mv(), args), "stress MV"); } MPS_ARGS_END(args); MPS_ARGS_BEGIN(args) { - mps_align_t align = rnd_align(sizeof(void *), arena_grain_size); + mps_align_t align = rnd_align(sizeof(void *), MAX_ALIGN); MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options); die(stress(arena, options, align, randomSizeAligned, "MV debug", @@ -206,7 +209,7 @@ static void test(mps_arena_class_t arena_class, mps_arg_s arena_args[], } MPS_ARGS_END(args); MPS_ARGS_BEGIN(args) { - mps_align_t align = rnd_align(sizeof(void *), arena_grain_size); + mps_align_t align = rnd_align(sizeof(void *), MAX_ALIGN); MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); die(stress(arena, NULL, align, randomSizeAligned, "MVT", mps_class_mvt(), args), "stress MVT"); diff --git a/mps/example/scheme/scheme-advanced.c b/mps/example/scheme/scheme-advanced.c index 707390b2962..8d2d11df943 100644 --- a/mps/example/scheme/scheme-advanced.c +++ b/mps/example/scheme/scheme-advanced.c @@ -4444,7 +4444,7 @@ static mps_gen_param_s obj_gen_params[] = { int main(int argc, char *argv[]) { - size_t arenasize = 32ul * 1024 * 1024; + size_t arenasize = 1024ul * 1024 * 1024; mps_res_t res; mps_chain_t obj_chain; mps_fmt_t obj_fmt, buckets_fmt; From 52dca35af50eb1d8104a802123b2f9cc992036ec Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 31 Mar 2016 12:15:15 +0100 Subject: [PATCH 322/337] Toning down critical wording in the release notes. see . Copied from Perforce Change: 190578 ServerID: perforce.ravenbrook.com --- mps/manual/source/release.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 857daf78583..10fda30689c 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -143,13 +143,13 @@ Other changes #. The MPS is less aggressive in its use of hardware memory protection to maintain :term:`write barrier` to speed up future collections. - This is particularly important for OS X, where memory protection is - poorly implemented. See job003371_ and job003975_. + This is particularly important for OS X, where memory protection + operations are very expensive. See job003371_ and job003975_. #. The MPS coalesces memory protection, reducing the number of system - calls. This drastically improves real run time on operating systems - where memory protection is poorly implemented, such as OS X, but - also has a significant effect on Linux. See job003371_ and + calls. This markedly improves real run time on operating systems + where memory protection operations are very expensive, such as OS + X, but also has a significant effect on Linux. See job003371_ and job003975_. .. _job003371: http://www.ravenbrook.com/project/mps/issue/job003371/ From 27e38efbdaecab003ac7bddfbab8289a6788adae Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 31 Mar 2016 23:41:46 +0100 Subject: [PATCH 323/337] Don't allow pools to whiten segments without condemning objects, so that a condemned size of zero implies no white segments, allowing quick trace destruction. Copied from Perforce Change: 190607 ServerID: perforce.ravenbrook.com --- mps/code/poolams.c | 8 ++++++-- mps/code/poolawl.c | 8 ++++++-- mps/code/trace.c | 25 ++++++++++++++++++++----- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/mps/code/poolams.c b/mps/code/poolams.c index 71701be7bee..af9ae20c407 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -1170,9 +1170,13 @@ static Res AMSWhiten(Pool pool, Trace trace, Seg seg) amsseg->newGrains = uncondemned; amsseg->marksChanged = FALSE; /* */ amsseg->ambiguousFixes = FALSE; - trace->condemned += AMSGrainsSize(ams, amsseg->oldGrains); - SegSetWhite(seg, TraceSetAdd(SegWhite(seg), trace)); + if (amsseg->oldGrains > 0) { + trace->condemned += AMSGrainsSize(ams, amsseg->oldGrains); + SegSetWhite(seg, TraceSetAdd(SegWhite(seg), trace)); + } else { + amsseg->colourTablesInUse = FALSE; + } return ResOK; } diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 42460f97056..eb61281526c 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -791,8 +791,12 @@ static Res AWLWhiten(Pool pool, Trace trace, Seg seg) PoolGenAccountForAge(&awl->pgen, AWLGrainsSize(awl, awlseg->newGrains - uncondemned), FALSE); awlseg->oldGrains += awlseg->newGrains - uncondemned; awlseg->newGrains = uncondemned; - trace->condemned += AWLGrainsSize(awl, awlseg->oldGrains); - SegSetWhite(seg, TraceSetAdd(SegWhite(seg), trace)); + + if (awlseg->oldGrains > 0) { + trace->condemned += AWLGrainsSize(awl, awlseg->oldGrains); + SegSetWhite(seg, TraceSetAdd(SegWhite(seg), trace)); + } + return ResOK; } diff --git a/mps/code/trace.c b/mps/code/trace.c index 10517d89640..17e1061127a 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -339,7 +339,12 @@ static ZoneSet traceSetWhiteUnion(TraceSet ts, Arena arena) } -/* TraceIsEmpty -- return TRUE if trace has no condemned segments */ +/* TraceIsEmpty -- return TRUE if trace has no condemned segments + * + * .empty.size: If the trace has a condemned size of zero, then it has + * no white segments, because we don't allow pools to whiten segments + * with no white objects in. + */ Bool TraceIsEmpty(Trace trace) { @@ -354,6 +359,7 @@ Res TraceAddWhite(Trace trace, Seg seg) { Res res; Pool pool; + Size condemnedBefore; AVERT(Trace, trace); AVERT(Seg, seg); @@ -362,18 +368,25 @@ Res TraceAddWhite(Trace trace, Seg seg) pool = SegPool(seg); AVERT(Pool, pool); + condemnedBefore = trace->condemned; + /* Give the pool the opportunity to turn the segment white. */ /* If it fails, unwind. */ res = PoolWhiten(pool, trace, seg); if(res != ResOK) return res; - /* Add the segment to the approximation of the white set if the */ - /* pool made it white. */ - if(TraceSetIsMember(SegWhite(seg), trace)) { + if (TraceSetIsMember(SegWhite(seg), trace)) { + /* Pools must not condemn empty segments, otherwise we can't tell + when a trace is empty and safe to destroy. See .empty.size. */ + AVER(trace->condemned > condemnedBefore); + + /* Add the segment to the approximation of the white set if the + pool made it white. */ trace->white = ZoneSetUnion(trace->white, ZoneSetOfSeg(trace->arena, seg)); + /* if the pool is a moving GC, then condemned objects may move */ - if(PoolHasAttr(pool, AttrMOVINGGC)) { + if (PoolHasAttr(pool, AttrMOVINGGC)) { trace->mayMove = ZoneSetUnion(trace->mayMove, ZoneSetOfSeg(trace->arena, seg)); } @@ -1532,11 +1545,13 @@ static Res traceCondemnAll(Trace trace) Ring segNode, nextSegNode; RING_FOR(segNode, PoolSegRing(pool), nextSegNode) { Seg seg = SegOfPoolRing(segNode); + AVERT(Seg, seg); res = TraceAddWhite(trace, seg); if (res != ResOK) goto failBegin; + } } } From 372aa0090e7c5ccee0c9ccc82f90860e0fa945c8 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 2 Apr 2016 07:36:54 +0100 Subject: [PATCH 324/337] Undoing accidental submit of change to arena size in scheme-advanced.c. Copied from Perforce Change: 190624 ServerID: perforce.ravenbrook.com --- mps/example/scheme/scheme-advanced.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/example/scheme/scheme-advanced.c b/mps/example/scheme/scheme-advanced.c index 8d2d11df943..707390b2962 100644 --- a/mps/example/scheme/scheme-advanced.c +++ b/mps/example/scheme/scheme-advanced.c @@ -4444,7 +4444,7 @@ static mps_gen_param_s obj_gen_params[] = { int main(int argc, char *argv[]) { - size_t arenasize = 1024ul * 1024 * 1024; + size_t arenasize = 32ul * 1024 * 1024; mps_res_t res; mps_chain_t obj_chain; mps_fmt_t obj_fmt, buckets_fmt; From dc5632de9a358927bbf8b277c8d42d7c14ed7b9f Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 2 Apr 2016 09:18:37 +0100 Subject: [PATCH 325/337] Fixing default behaviour for merging segments with differing summaries and therefore write barriers. Copied from Perforce Change: 190629 ServerID: perforce.ravenbrook.com --- mps/code/seg.c | 22 +++++++++++++++------- mps/design/seg.txt | 10 ++++------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/mps/code/seg.c b/mps/code/seg.c index 22cfd98e7cb..cf71dbd197a 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -1463,6 +1463,21 @@ static Res gcSegMerge(Seg seg, Seg segHi, grey = SegGrey(segHi); /* check greyness */ AVER(SegGrey(seg) == grey); + /* Assume that the write barrier shield is being used to implement + the remembered set only, and so we can merge the shield and + protection modes by unioning the segment summaries. See also + design.mps.seg.merge.inv.similar. */ + summary = RefSetUnion(gcseg->summary, gcsegHi->summary); + SegSetSummary(seg, summary); + SegSetSummary(segHi, summary); + AVER(SegSM(seg) == SegSM(segHi)); + if (SegPM(seg) != SegPM(segHi)) { + /* This shield won't cope with a partially-protected segment, so + flush the shield queue to bring both halves in sync. See also + design.mps.seg.split-merge.shield.re-flush. */ + ShieldFlush(PoolArena(SegPool(seg))); + } + /* Merge the superclass fields via next-method call */ super = SEG_SUPERCLASS(GCSegClass); res = super->merge(seg, segHi, base, mid, limit); @@ -1470,13 +1485,6 @@ static Res gcSegMerge(Seg seg, Seg segHi, goto failSuper; /* Update fields of gcseg. Finish gcsegHi. */ - summary = RefSetUnion(gcseg->summary, gcsegHi->summary); - if (summary != gcseg->summary) { - gcSegSetSummary(seg, summary); - /* */ - ShieldFlush(PoolArena(SegPool(seg))); - } - gcSegSetGreyInternal(segHi, grey, TraceSetEMPTY); gcsegHi->summary = RefSetEMPTY; gcsegHi->sig = SigInvalid; diff --git a/mps/design/seg.txt b/mps/design/seg.txt index dc9e8b96083..4e118bfbb96 100644 --- a/mps/design/seg.txt +++ b/mps/design/seg.txt @@ -213,12 +213,10 @@ before calling ``SegMerge()``: - _`.merge.inv.similar`: ``segLo`` and ``segHi`` must be sufficiently similar. Two segments are sufficiently similar if they have identical values for each of the following fields: ``class``, - ``sm``, ``grey``, ``white``, ``nailed``, ``rankSet``. Justification: - there is no single choice of behaviour for cases where these fields - are not identical. The pool class must make it's own choices about - this if it wishes to permit more flexible merging. If so, it should - be a simple matter for the pool to arrange for the segments to look - sufficiently similar before calling ``SegMerge()``. + ``grey``, ``white``, ``nailed``, ``rankSet``. Justification: There + has yet to be a need to implement default behaviour for these + cases. Pool classes should arrange for these values to be the same + before calling ``SegMerge()``. _`.merge.state`: The merged segment will share the same state as ``segLo`` and ``segHi`` for those fields which are identical (see From ba9d203b1d8ad1e153bd7cde46d79d63782ffc89 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 2 Apr 2016 12:07:46 +0100 Subject: [PATCH 326/337] Don't attempt to merge a non-white segment with a white one. Copied from Perforce Change: 190634 ServerID: perforce.ravenbrook.com --- mps/code/segsmss.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/mps/code/segsmss.c b/mps/code/segsmss.c index 746c253f321..1de5ccf0612 100644 --- a/mps/code/segsmss.c +++ b/mps/code/segsmss.c @@ -508,10 +508,10 @@ static void AMSAllocateRange(AMS ams, Seg seg, Addr base, Addr limit) * Calls next method - but possibly splits or merges the chosen * segment. * - * .merge: A merge is performed when the next method returns - * the entire segment, this segment had previously been split - * from the segment below, and the segment below is appropriately - * similar (i.e. not already attached to a buffer and similarly grey) + * .merge: A merge is performed when the next method returns the + * entire segment, this segment had previously been split from the + * segment below, and the segment below is appropriately similar + * (i.e. not already attached to a buffer and similarly coloured) * * .split: If we're not merging, a split is performed if the next method * returns the entire segment, and yet lower half of the segment would @@ -551,7 +551,9 @@ static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn, if (SegLimit(seg) == limit && SegBase(seg) == base) { if (amstseg->prev != NULL) { Seg segLo = AMSTSeg2Seg(amstseg->prev); - if (SegBuffer(segLo) == NULL && SegGrey(segLo) == SegGrey(seg)) { + if (SegBuffer(segLo) == NULL && + SegGrey(segLo) == SegGrey(seg) && + SegWhite(segLo) == SegWhite(seg)) { /* .merge */ Seg mergedSeg; Res mres; From a53339fed30d5436fd56fe03dde1abc50dae651e Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 2 Apr 2016 15:53:57 +0100 Subject: [PATCH 327/337] Protecting some segment accessor macros with rvalue. Removing duplicate definition of SegPoolRing. Copied from Perforce Change: 190642 ServerID: perforce.ravenbrook.com --- mps/code/mpm.h | 18 +++++++++--------- mps/code/seg.c | 4 ---- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 9c5de02fb74..060daa88d39 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -724,15 +724,15 @@ extern Addr (SegLimit)(Seg seg); /* .bitfield.promote: The bit field accesses need to be cast to the */ /* right type, otherwise they'll be promoted to signed int, see */ /* standard.ansic.6.2.1.1. */ -#define SegRankSet(seg) ((RankSet)(seg)->rankSet) -#define SegPM(seg) ((AccessSet)(seg)->pm) -#define SegSM(seg) ((AccessSet)(seg)->sm) -#define SegDepth(seg) ((unsigned)(seg)->depth) -#define SegGrey(seg) ((TraceSet)(seg)->grey) -#define SegWhite(seg) ((TraceSet)(seg)->white) -#define SegNailed(seg) ((TraceSet)(seg)->nailed) -#define SegPoolRing(seg) (&(seg)->poolRing) -#define SegOfPoolRing(node) (RING_ELT(Seg, poolRing, (node))) +#define SegRankSet(seg) RVALUE((RankSet)(seg)->rankSet) +#define SegPM(seg) RVALUE((AccessSet)(seg)->pm) +#define SegSM(seg) RVALUE((AccessSet)(seg)->sm) +#define SegDepth(seg) RVALUE((unsigned)(seg)->depth) +#define SegGrey(seg) RVALUE((TraceSet)(seg)->grey) +#define SegWhite(seg) RVALUE((TraceSet)(seg)->white) +#define SegNailed(seg) RVALUE((TraceSet)(seg)->nailed) +#define SegPoolRing(seg) RVALUE(&(seg)->poolRing) +#define SegOfPoolRing(node) RING_ELT(Seg, poolRing, (node)) #define SegOfGreyRing(node) (&(RING_ELT(GCSeg, greyRing, (node)) \ ->segStruct)) diff --git a/mps/code/seg.c b/mps/code/seg.c index cf71dbd197a..97b1da659a8 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -28,10 +28,6 @@ SRCID(seg, "$Id$"); #define SegGCSeg(seg) ((GCSeg)(seg)) -/* SegPoolRing -- Pool ring accessor */ - -#define SegPoolRing(seg) (&(seg)->poolRing) - /* forward declarations */ From 19a55b06d86b5236fb0e8c3ddf291eb060812aac Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Sat, 2 Apr 2016 15:54:24 +0100 Subject: [PATCH 328/337] Adding new build directories to .p4ignore. Copied from Perforce Change: 190643 ServerID: perforce.ravenbrook.com --- mps/code/.p4ignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mps/code/.p4ignore b/mps/code/.p4ignore index 7db90ebb062..9f2cb4f2aa8 100644 --- a/mps/code/.p4ignore +++ b/mps/code/.p4ignore @@ -14,6 +14,8 @@ lii6ll w3i3mv w3i6mv xci3gc +xci3ll +xci6gc xci6ll # Visual Studio junk Debug From a2931bfddbd79e3ea33b0fc80108021807c1a1ea Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 4 Apr 2016 19:20:26 +0100 Subject: [PATCH 329/337] Linking .p4ignore to .gitignore to share configuration between perforce and git. Copied from Perforce Change: 190667 ServerID: perforce.ravenbrook.com --- mps/.renamed-gitignore | 1 + mps/code/.renamed-gitignore | 1 + mps/code/w3mv/.renamed-gitignore | 1 + mps/example/scheme/.renamed-gitignore | 1 + mps/manual/.renamed-gitignore | 1 + mps/manual/source/design/.renamed-gitignore | 1 + mps/tool/.renamed-gitignore | 1 + 7 files changed, 7 insertions(+) create mode 120000 mps/.renamed-gitignore create mode 120000 mps/code/.renamed-gitignore create mode 120000 mps/code/w3mv/.renamed-gitignore create mode 120000 mps/example/scheme/.renamed-gitignore create mode 120000 mps/manual/.renamed-gitignore create mode 120000 mps/manual/source/design/.renamed-gitignore create mode 120000 mps/tool/.renamed-gitignore diff --git a/mps/.renamed-gitignore b/mps/.renamed-gitignore new file mode 120000 index 00000000000..c5c99a6a89c --- /dev/null +++ b/mps/.renamed-gitignore @@ -0,0 +1 @@ +.p4ignore \ No newline at end of file diff --git a/mps/code/.renamed-gitignore b/mps/code/.renamed-gitignore new file mode 120000 index 00000000000..c5c99a6a89c --- /dev/null +++ b/mps/code/.renamed-gitignore @@ -0,0 +1 @@ +.p4ignore \ No newline at end of file diff --git a/mps/code/w3mv/.renamed-gitignore b/mps/code/w3mv/.renamed-gitignore new file mode 120000 index 00000000000..c5c99a6a89c --- /dev/null +++ b/mps/code/w3mv/.renamed-gitignore @@ -0,0 +1 @@ +.p4ignore \ No newline at end of file diff --git a/mps/example/scheme/.renamed-gitignore b/mps/example/scheme/.renamed-gitignore new file mode 120000 index 00000000000..c5c99a6a89c --- /dev/null +++ b/mps/example/scheme/.renamed-gitignore @@ -0,0 +1 @@ +.p4ignore \ No newline at end of file diff --git a/mps/manual/.renamed-gitignore b/mps/manual/.renamed-gitignore new file mode 120000 index 00000000000..c5c99a6a89c --- /dev/null +++ b/mps/manual/.renamed-gitignore @@ -0,0 +1 @@ +.p4ignore \ No newline at end of file diff --git a/mps/manual/source/design/.renamed-gitignore b/mps/manual/source/design/.renamed-gitignore new file mode 120000 index 00000000000..c5c99a6a89c --- /dev/null +++ b/mps/manual/source/design/.renamed-gitignore @@ -0,0 +1 @@ +.p4ignore \ No newline at end of file diff --git a/mps/tool/.renamed-gitignore b/mps/tool/.renamed-gitignore new file mode 120000 index 00000000000..c5c99a6a89c --- /dev/null +++ b/mps/tool/.renamed-gitignore @@ -0,0 +1 @@ +.p4ignore \ No newline at end of file From 845e66778d8f21c819b35181824cbd4b3d98cb8c Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 4 Apr 2016 23:28:28 +0100 Subject: [PATCH 330/337] Fixing horrible intialization of segment class by poking before calling seginit. Copied from Perforce Change: 190694 ServerID: perforce.ravenbrook.com --- mps/code/seg.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/mps/code/seg.c b/mps/code/seg.c index 97b1da659a8..49218c0d1a7 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -33,8 +33,8 @@ SRCID(seg, "$Id$"); static void SegFinish(Seg seg); -static Res SegInit(Seg seg, Pool pool, Addr base, Size size, - ArgList args); +static Res SegInit(Seg seg, SegClass class, Pool pool, + Addr base, Size size, ArgList args); /* Generic interface support */ @@ -72,8 +72,7 @@ Res SegAlloc(Seg *segReturn, SegClass class, LocusPref pref, goto failControl; seg = p; - seg->class = class; - res = SegInit(seg, pool, base, size, args); + res = SegInit(seg, class, pool, base, size, args); if (res != ResOK) goto failInit; @@ -121,12 +120,11 @@ void SegFree(Seg seg) /* SegInit -- initialize a segment */ -static Res SegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) +static Res SegInit(Seg seg, SegClass class, Pool pool, Addr base, Size size, ArgList args) { Tract tract; Addr addr, limit; Arena arena; - SegClass class; Res res; AVER(seg != NULL); @@ -134,9 +132,9 @@ static Res SegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) arena = PoolArena(pool); AVER(AddrIsArenaGrain(base, arena)); AVER(SizeIsArenaGrains(size, arena)); - class = seg->class; AVERT(SegClass, class); + seg->class = class; limit = AddrAdd(base, size); seg->limit = limit; seg->rankSet = RankSetEMPTY; From 7fd416c8b0833a698458d3e6a12d4342b22e7224 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 4 Apr 2016 19:55:45 +0100 Subject: [PATCH 331/337] Updating .p4ignore files with miscellaneous entries collected from work with git. Copied from Perforce Change: 190702 ServerID: perforce.ravenbrook.com --- mps/.p4ignore | 13 +++++++++++-- mps/code/.p4ignore | 3 +++ mps/example/scheme/.p4ignore | 5 ++++- mps/manual/.p4ignore | 5 ++++- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/mps/.p4ignore b/mps/.p4ignore index 25cd419ae6d..89c70e46dc5 100644 --- a/mps/.p4ignore +++ b/mps/.p4ignore @@ -8,16 +8,25 @@ # Patch results *.orig *.rej +# Autoconf and Automake output Makefile autom4te.cache config.log config.status +.deps +.dirstamp +bin +lib +# Misc TAGS *.dSYM -code/*/*/*.d *.pyc test/obj test/test/log test/test/obj ....gcda -....gcno \ No newline at end of file +....gcno +\#*# +*~ +.#.* +core diff --git a/mps/code/.p4ignore b/mps/code/.p4ignore index 9f2cb4f2aa8..70e69009357 100644 --- a/mps/code/.p4ignore +++ b/mps/code/.p4ignore @@ -35,6 +35,7 @@ mpsio*.txt *.lib *.exe a.out +core # Xcode junk xc mps.xcodeproj/xcuserdata @@ -55,3 +56,5 @@ tags .DS_Store # Emacs backups *~ +# GNU make dependencies +*/*/*.d diff --git a/mps/example/scheme/.p4ignore b/mps/example/scheme/.p4ignore index bf0e12d6afd..e368d2c9887 100644 --- a/mps/example/scheme/.p4ignore +++ b/mps/example/scheme/.p4ignore @@ -6,4 +6,7 @@ scheme-advanced.dSYM scheme-boehm scheme-boehm.dSYM scheme-malloc -scheme-malloc.dSYM \ No newline at end of file +scheme-malloc.dSYM +a.out +*.o +core diff --git a/mps/manual/.p4ignore b/mps/manual/.p4ignore index 86aa08494ce..f2a531e43c7 100644 --- a/mps/manual/.p4ignore +++ b/mps/manual/.p4ignore @@ -2,4 +2,7 @@ doctrees converted epub html -mmref \ No newline at end of file +mmref +source/design/*.rst +source/design/*.svg +tool From 003e4ee58088c6f5311e0abe6f3e2b88ecc0d9e6 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 5 Apr 2016 11:30:42 +0100 Subject: [PATCH 332/337] Updating copyright date to current year. Copied from Perforce Change: 190707 ServerID: perforce.ravenbrook.com --- mps/code/version.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/version.c b/mps/code/version.c index 9a212dbbb77..b2f7472798e 100644 --- a/mps/code/version.c +++ b/mps/code/version.c @@ -49,7 +49,7 @@ SRCID(version, "$Id$"); extern char MPSCopyrightNotice[]; char MPSCopyrightNotice[] = - "Portions copyright (c) 2010-2014 Ravenbrook Limited and Global Graphics Software."; + "Portions copyright (c) 2010-2016 Ravenbrook Limited and Global Graphics Software."; /* MPSVersion -- return version string From d0939e6f6bd99ac1a674dd7e6ffdbde44203dc76 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 5 Apr 2016 11:32:33 +0100 Subject: [PATCH 333/337] Adding step to update copyright date in version.c. Copied from Perforce Change: 190708 ServerID: perforce.ravenbrook.com --- mps/procedure/version-create.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mps/procedure/version-create.rst b/mps/procedure/version-create.rst index e92e93535d3..8715598435f 100644 --- a/mps/procedure/version-create.rst +++ b/mps/procedure/version-create.rst @@ -82,6 +82,11 @@ evolution. A version has these parts: first release from the version you are about to create. If it is wrong, correct and submit it. +#. Does ``code/version.c`` in the master sources have the correct + copyright dates for the ``MPSCopyrightNotice`` string? It should + include the current year. If it is wrong, correct and submit it. + + 3.2. Automated procedure ~~~~~~~~~~~~~~~~~~~~~~~~ From da9032b4fdc7225624f1c5f1511ba3a6c5d582e0 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 5 Apr 2016 11:36:31 +0100 Subject: [PATCH 334/337] Adding advice about what to put in the version branch description. Copied from Perforce Change: 190709 ServerID: perforce.ravenbrook.com --- mps/procedure/version-create.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mps/procedure/version-create.rst b/mps/procedure/version-create.rst index 8715598435f..593c470cbfb 100644 --- a/mps/procedure/version-create.rst +++ b/mps/procedure/version-create.rst @@ -97,9 +97,13 @@ Run the script ``tool/branch``, passing the options: * ``-p master`` — parent branch * ``-C CHANGELEVEL`` — changelevel at which to make the branch * ``-v`` — request a version branch -* ``-d "DESCRIPTION"`` — description of the branch +* ``-d "DESCRIPTION"`` — description of the branch (see below) * ``-y`` — yes, really create the branch +The branch description will be published in the version index and +should be a short summary of the improvements detailed in the release +notes. + If omitted, the project and parent branch are deduced from the current directory, and the changelevel defaults to the most recent change on the parent branch. A typical invocation looks like this:: From 509215f88272f36c4dfd5e8287291bec40f8eb41 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 5 Apr 2016 11:42:30 +0100 Subject: [PATCH 335/337] Adding step to check the result of the version branch tool before actually making the branch. Copied from Perforce Change: 190710 ServerID: perforce.ravenbrook.com --- mps/procedure/version-create.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mps/procedure/version-create.rst b/mps/procedure/version-create.rst index 593c470cbfb..1d374b382c9 100644 --- a/mps/procedure/version-create.rst +++ b/mps/procedure/version-create.rst @@ -98,7 +98,6 @@ Run the script ``tool/branch``, passing the options: * ``-C CHANGELEVEL`` — changelevel at which to make the branch * ``-v`` — request a version branch * ``-d "DESCRIPTION"`` — description of the branch (see below) -* ``-y`` — yes, really create the branch The branch description will be published in the version index and should be a short summary of the improvements detailed in the release @@ -108,7 +107,11 @@ If omitted, the project and parent branch are deduced from the current directory, and the changelevel defaults to the most recent change on the parent branch. A typical invocation looks like this:: - tool/branch -p master -v -d "Improved interface to generation chains." -y + tool/branch -p master -v -d "Improved interface to generation chains." + +Visually check the output of the script against `3.3. Manual +procedure`_, and when satisfied, repeat the invocation with the ``-y`` +option. 3.3. Manual procedure From 877fa8647caf5857d40a18abbd9dcca190f035a1 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 5 Apr 2016 11:52:42 +0100 Subject: [PATCH 336/337] Adding post-branch checklist steps to ensure the branch appears correctly in various places. Adding document history, updating copyrights, fixing cross-reference. Copied from Perforce Change: 190711 ServerID: perforce.ravenbrook.com --- mps/procedure/version-create.rst | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/mps/procedure/version-create.rst b/mps/procedure/version-create.rst index 1d374b382c9..459c021fa22 100644 --- a/mps/procedure/version-create.rst +++ b/mps/procedure/version-create.rst @@ -3,6 +3,7 @@ Memory Pool System Version Create Procedure :author: Richard Kistruck :organization: Ravenbrook Limited :date: 2008-10-29 +:Revision: $Id$ :confidentiality: public :copyright: See `C. Copyright and License`_ :readership: MPS developers @@ -30,7 +31,7 @@ you what "a version" actually is. You might not need to create a new version. An alternative is to create a further "point release" on the existing version. Refer to -[RB_1999-05-20] when deciding. (Summary: if changing the +[RB_1999-05-20]_ when deciding. (Summary: if changing the specification, make a new version; if improving the product against an unchanged specification, make a point release.) @@ -123,7 +124,6 @@ option. //info.ravenbrook.com/project/mps/version/$VERSION/... //info.ravenbrook.com/project/mps/branch/index.html - //info.ravenbrook.com/infosys/robots/git-fusion/etc/pushes #. Create the version branch specification by running:: @@ -153,21 +153,22 @@ option. #. Update the `table of versions `_. -#. Make a client specification that can be used by the `git-fusion robot `_ to sync the version:: +#. Add the version to the “mps” and “mps-public” repos published by + Git Fusion by editing ``//.git-fusion/repos/mps/p4gf_config`` and + ``//.git-fusion/repos/mps-public/p4gf_config`` with entries similar + to existing version branches. - p4 client -i <`_:: +3.4. Post-branch checklist +~~~~~~~~~~~~~~~~~~~~~~~~~~ - PUSHES=$(p4 have //info.ravenbrook.com/infosys/robots/git-fusion/etc/pushes | cut -d' ' -f3) - p4 edit $PUSHES - printf "mps-version-$VERSION\tgit@github.com:Ravenbrook/mps.git\tversion/$VERSION" >> $PUSHES - p4 submit -d "Arranging for MPS version $VERSION to be pushed to GitHub by Git Fusion" $PUSHES +Ensure that the branch appears correctly at: + +#. the internal index at https://info.ravenbrook.com/project/mps/version + +#. the external index at http://www.ravenbrook.com/project/mps/version + +#. the GitHub mirror at https://github.com/Ravenbrook/mps/branches A. References @@ -191,6 +192,7 @@ B. Document History 2014-01-14 GDR_ Step for adding to Git Fusion. 2014-03-19 GDR_ Describe automated procedure. 2016-01-28 RB_ Git repository renamed from mps-temporary to mps. +2016-04-05 RB_ Bringing up to date in preparation for version 1.115. ========== ===== ======================================================== .. _GDR: mailto:gdr@ravenbrook.com @@ -200,7 +202,7 @@ B. Document History C. Copyright and License ------------------------ -Copyright © 2002-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2002-2016 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. From aeb1eed7924680d9be28c7812b83a6f2e64551f1 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 5 Apr 2016 12:01:38 +0100 Subject: [PATCH 337/337] Simplifying manual procedure using "p4 populate". Copied from Perforce Change: 190714 ServerID: perforce.ravenbrook.com --- mps/procedure/version-create.rst | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/mps/procedure/version-create.rst b/mps/procedure/version-create.rst index 459c021fa22..80d7e229a81 100644 --- a/mps/procedure/version-create.rst +++ b/mps/procedure/version-create.rst @@ -118,13 +118,6 @@ option. 3.3. Manual procedure ~~~~~~~~~~~~~~~~~~~~~ -#. Make sure that the sources for the version you are about to create, - for the table of versions, and for the table of Git Fusion pushes, - are mapped in your Perforce client:: - - //info.ravenbrook.com/project/mps/version/$VERSION/... - //info.ravenbrook.com/project/mps/branch/index.html - #. Create the version branch specification by running:: VERSION=A.BBB @@ -135,21 +128,15 @@ option. View: //info.ravenbrook.com/project/mps/master/... //info.ravenbrook.com/project/$BRANCH/... END -#. Make sure you have no unsubmitted files:: +#. Create the branch itself by running:: - $ p4 opened - File(s) not opened on this client. - - and then:: - - p4 integrate -b $BRANCH - p4 submit -d "Branching master sources for version $VERSION." + p4 populate -b $BRANCH -d "Branching master sources for version $VERSION." #. Determine the origin of the new version:: p4 changes -m 5 //info.ravenbrook.com/project/mps/master/... - Note the latest change that was in before the integrate. + Note the latest change that was in before the populate. #. Update the `table of versions `_.