From 91ed6eb0d9c82582566c82e68710f11248063cb3 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 24 Feb 2014 23:04:31 +0000 Subject: [PATCH 001/266] Instead of aggressively returning every page it can, mvff takes a parameter for the proportion of spare space to hold in its free lists before attempting to return space to the arena. Copied from Perforce Change: 184498 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 1 + mps/code/mps.h | 3 ++ mps/code/pool.c | 1 + mps/code/poolmvff.c | 126 +++++++++++++++++++++++++++++--------------- 4 files changed, 88 insertions(+), 43 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index 4ad6ea51f15..da4bf132400 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -277,6 +277,7 @@ #define MVFF_SLOT_HIGH_DEFAULT FALSE #define MVFF_ARENA_HIGH_DEFAULT FALSE #define MVFF_FIRST_FIT_DEFAULT TRUE +#define MVFF_SPARE_DEFAULT 0.75 /* Pool MVT Configuration -- see */ diff --git a/mps/code/mps.h b/mps/code/mps.h index f8751d01372..7e3e734d336 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -184,6 +184,9 @@ extern const struct mps_key_s _mps_key_max_size; extern const struct mps_key_s _mps_key_align; #define MPS_KEY_ALIGN (&_mps_key_align) #define MPS_KEY_ALIGN_FIELD align +extern const struct mps_key_s _mps_key_spare; +#define MPS_KEY_SPARE (&_mps_key_spare) +#define MPS_KEY_SPARE_FIELD double extern const struct mps_key_s _mps_key_cbs_extend_by; #define MPS_KEY_CBS_EXTEND_BY (&_mps_key_cbs_extend_by) #define MPS_KEY_CBS_EXTEND_BY_FIELD size diff --git a/mps/code/pool.c b/mps/code/pool.c index df6b0fa9032..eaf751b25d8 100644 --- a/mps/code/pool.c +++ b/mps/code/pool.c @@ -118,6 +118,7 @@ ARG_DEFINE_KEY(min_size, Size); ARG_DEFINE_KEY(mean_size, Size); ARG_DEFINE_KEY(max_size, Size); ARG_DEFINE_KEY(align, Align); +ARG_DEFINE_KEY(spare, double); /* PoolInit -- initialize a pool diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index d26011856b7..07adb19ad4d 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -49,6 +49,7 @@ typedef struct MVFFStruct { /* MVFF pool outer structure */ Size avgSize; /* client estimate of allocation size */ Size total; /* total bytes in pool */ Size free; /* total free bytes in pool */ + double spare; /* spare space fraction, see MVFFReduce */ MFSStruct cbsBlockPoolStruct; /* stores blocks for CBSs */ CBSStruct totalCBSStruct; /* all memory allocated from the arena */ CBSStruct freeCBSStruct; /* free list */ @@ -156,55 +157,85 @@ static void MVFFDeleteFromFree(MVFF mvff, Range range) /* MVFFReduce -- free segments from given range * - * Given a free range, attempts to find entire tracts within - * it, and returns them to the arena, updating total size counter. + * Consider reducing the total size of the pool by returning memory + * to the arena. * * This is usually called immediately after MVFFAddToFreeList. * It is not combined with MVFFAddToFreeList because the latter * is also called when new segments are added under MVFFAlloc. */ -static void MVFFReduce(MVFF mvff, Range range) +static void MVFFReduce(MVFF mvff) { Arena arena; - RangeStruct alignedRange, oldRange; - Addr base, limit; - Size size; - Res res; - - AVERT(MVFF, mvff); - AVER(RangeBase(range) < RangeLimit(range)); - /* Could profitably AVER that the given range is free, */ - /* but the CBS doesn't provide that facility. */ - - size = RangeSize(range); - - arena = PoolArena(MVFF2Pool(mvff)); - base = AddrAlignUp(RangeBase(range), ArenaAlign(arena)); - limit = AddrAlignDown(RangeLimit(range), ArenaAlign(arena)); - if (base >= limit) { /* no whole tracts */ - return; - } - - RangeInit(&alignedRange, base, limit); - AVER(RangesNest(range, &alignedRange)); - - /* Delete the range from the free list before attempting to delete it - from the total allocated memory, so that we don't have dangling blocks - in the freelist, even for a moment. If we fail to delete from the - totalCBS we add back to the freelist, which can't fail. */ + RangeStruct freeRange; + Size freeLimit, targetFree; + Align align; - MVFFDeleteFromFree(mvff, &alignedRange); + AVERT(MVFF, mvff); + arena = PoolArena(MVFF2Pool(mvff)); + align = ArenaAlign(arena); - res = CBSDelete(&oldRange, MVFFTotalCBS(mvff), &alignedRange); - if (res != ResOK) { - RangeStruct coalesced; - MVFFAddToFree(&coalesced, mvff, &alignedRange); + /* Try to return memory when the amount of free memory exceeds a + threshold fraction of the total memory. */ + + /* NOTE: If this code becomes very hot, then the test of whether there's + a large free block in the CBS could be inlined, since it's a property + stored at the root node. */ + + freeLimit = (Size)(mvff->total * mvff->spare); + if (mvff->free < freeLimit) return; - } - mvff->total -= RangeSize(&alignedRange); - ArenaFree(base, AddrOffset(base, limit), MVFF2Pool(mvff)); + targetFree = freeLimit / 2; + while (mvff->free > targetFree && + CBSFindLargest(&freeRange, &freeRange, MVFFFreeCBS(mvff), + 0, FindDeleteNONE)) { + RangeStruct pageRange, oldRange; + Size size; + Res res; + Addr base, limit; + + base = AddrAlignUp(RangeBase(&freeRange), align); + limit = AddrAlignDown(RangeLimit(&freeRange), align); + + /* Give up if the block is too small to contain a whole page when + aligned, even though it might be masking smaller better aligned + pages that we could return, because CBSFindLargest won't be able + to find those. */ + if (base >= limit) + break; + + size = AddrOffset(base, limit); + + /* Don't return (much) more than we need to. */ + if (size > mvff->free - targetFree) + size = SizeAlignUp(mvff->free - targetFree, align); + + /* Calculate the range of pages we can return to the arena near the + top end of the free memory (because we're first fit). */ + RangeInit(&pageRange, AddrSub(limit, size), limit); + AVER(!RangeIsEmpty(&pageRange)); + AVER(RangesNest(&freeRange, &pageRange)); + AVER(RangeIsAligned(&pageRange, align)); + + /* Delete the range from the free list before attempting to delete it + from the total allocated memory, so that we don't have dangling blocks + in the freelist, even for a moment. If we fail to delete from the + totalCBS we add back to the freelist, which can't fail. */ + + MVFFDeleteFromFree(mvff, &pageRange); + + res = CBSDelete(&oldRange, MVFFTotalCBS(mvff), &pageRange); + if (res != ResOK) { + RangeStruct coalesced; + MVFFAddToFree(&coalesced, mvff, &pageRange); + return; + } + mvff->total -= RangeSize(&pageRange); + + ArenaFree(RangeBase(&pageRange), RangeSize(&pageRange), MVFF2Pool(mvff)); + } } @@ -374,7 +405,7 @@ static void MVFFFree(Pool pool, Addr old, Size size) size = SizeAlignUp(size, PoolAlignment(pool)); RangeInit(&range, old, AddrAdd(old, size)); MVFFAddToFree(&coalescedRange, mvff, &range); - MVFFReduce(mvff, &coalescedRange); + MVFFReduce(mvff); } /* MVFFFindLargest -- call CBSFindLargest and then fall back to @@ -464,7 +495,7 @@ static void MVFFBufferEmpty(Pool pool, Buffer buffer, RangeInit(&range, base, limit); MVFFAddToFree(&coalescedRange, mvff, &range); - MVFFReduce(mvff, &coalescedRange); + MVFFReduce(mvff); } @@ -510,6 +541,7 @@ static Res MVFFInit(Pool pool, ArgList args) Bool slotHigh = MVFF_SLOT_HIGH_DEFAULT; Bool arenaHigh = MVFF_ARENA_HIGH_DEFAULT; Bool firstFit = MVFF_FIRST_FIT_DEFAULT; + double spare = MVFF_SPARE_DEFAULT; MVFF mvff; Arena arena; Res res; @@ -533,6 +565,9 @@ static Res MVFFInit(Pool pool, ArgList args) if (ArgPick(&arg, args, MPS_KEY_ALIGN)) align = arg.val.align; + if (ArgPick(&arg, args, MPS_KEY_SPARE)) + spare = arg.val.d; + if (ArgPick(&arg, args, MPS_KEY_MVFF_SLOT_HIGH)) slotHigh = arg.val.b; @@ -545,6 +580,8 @@ static Res MVFFInit(Pool pool, ArgList args) AVER(extendBy > 0); /* .arg.check */ AVER(avgSize > 0); /* .arg.check */ AVER(avgSize <= extendBy); /* .arg.check */ + AVER(spare >= 0.0); /* .arg.check */ + AVER(spare <= 1.0); /* .arg.check */ AVER(SizeIsAligned(align, MPS_PF_ALIGN)); AVER(BoolCheck(slotHigh)); AVER(BoolCheck(arenaHigh)); @@ -557,6 +594,7 @@ static Res MVFFInit(Pool pool, ArgList args) pool->alignment = align; mvff->slotHigh = slotHigh; mvff->firstFit = firstFit; + mvff->spare = spare; SegPrefInit(MVFFSegPref(mvff)); SegPrefExpress(MVFFSegPref(mvff), arenaHigh ? SegPrefHigh : SegPrefLow, NULL); @@ -794,6 +832,8 @@ static Bool MVFFCheck(MVFF mvff) CHECKL(mvff->extendBy > 0); /* see .arg.check */ CHECKL(mvff->avgSize > 0); /* see .arg.check */ CHECKL(mvff->avgSize <= mvff->extendBy); /* see .arg.check */ + CHECKL(mvff->spare >= 0.0); /* see .arg.check */ + CHECKL(mvff->spare <= 1.0); /* see .arg.check */ CHECKL(mvff->total >= mvff->free); CHECKL(SizeIsAligned(mvff->free, PoolAlignment(MVFF2Pool(mvff)))); CHECKL(SizeIsAligned(mvff->total, ArenaAlign(PoolArena(MVFF2Pool(mvff))))); @@ -801,10 +841,10 @@ static Bool MVFFCheck(MVFF mvff) CHECKD(Freelist, MVFFFreelist(mvff)); CHECKL(BoolCheck(mvff->slotHigh)); CHECKL(BoolCheck(mvff->firstFit)); -#if MVFF_DEBUG - CHECKL(CBSSize(MVFFFreeCBS(mvff)) + - FreelistSize(MVFFFreelist(mvff)) == mvff->free); - CHECKL(CBSSize(MVFFTotalCBS(mvff)) == mvff->total); +#ifdef MVFF_DEBUG /* FIXME: Consider using just "if" */ + CHECKL(mvff->free == CBSSize(MVFFFreeCBS(mvff)) + + FreelistSize(MVFFFreelist(mvff))); + CHECKL(mvff->total == CBSSize(MVFFTotalCBS(mvff))); #endif return TRUE; } From ecedc44dd7aa54a6bb066639d4703cba6bbd23b7 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 24 Feb 2014 23:40:08 +0000 Subject: [PATCH 002/266] Avoid checking every tract in a span on mvspancheck. Copied from Perforce Change: 184499 ServerID: perforce.ravenbrook.com --- mps/code/poolmv.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/mps/code/poolmv.c b/mps/code/poolmv.c index 14cf2c12ce2..b132581969d 100644 --- a/mps/code/poolmv.c +++ b/mps/code/poolmv.c @@ -132,9 +132,7 @@ typedef struct MVSpanStruct { static Bool MVSpanCheck(MVSpan span) { - Addr addr, base, limit; - Arena arena; - Tract tract; + Addr base, limit; CHECKS(MVSpan, span); @@ -170,13 +168,20 @@ static Bool MVSpanCheck(MVSpan span) CHECKL(span->largest == SpanSize(span)+1); } - /* Each tract of the span must refer to the span */ - arena = PoolArena(TractPool(span->tract)); - TRACT_FOR(tract, addr, arena, base, limit) { - CHECKD_NOSIG(Tract, tract); - CHECKL(TractP(tract) == (void *)span); +#ifdef MV_DEBUG + { + Addr addr; + Arena arena; + Tract tract; + /* Each tract of the span must refer to the span */ + arena = PoolArena(TractPool(span->tract)); + TRACT_FOR(tract, addr, arena, base, limit) { + CHECKD_NOSIG(Tract, tract); + CHECKL(TractP(tract) == (void *)span); + } + CHECKL(addr == limit); } - CHECKL(addr == limit); +#endif return TRUE; } From eb2b630b27ffb7916e0de741e2a7cffbee52d1d3 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 18 Mar 2014 14:40:01 +0000 Subject: [PATCH 003/266] Branching master to version/1.113. Copied from Perforce Change: 184858 ServerID: perforce.ravenbrook.com From 94ee4e158b8a9a4e730b5d78e8ea97a4c3c7c446 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 18 Mar 2014 18:11:48 +0000 Subject: [PATCH 004/266] Update release index and bump release number accordingly. Copied from Perforce Change: 184870 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 28f1b3e1ce0..32711dd43a5 100644 --- a/mps/code/version.c +++ b/mps/code/version.c @@ -38,7 +38,7 @@ SRCID(version, "$Id$"); * .release.old: before 2006-02-01 the style was "release.epcore.chub". */ -#define MPS_RELEASE "release/1.113.0" +#define MPS_RELEASE "release/1.113.1" /* MPSCopyrightNotice -- copyright notice for the binary From d13677d177f0a0fcee6fd92f5b62c9258eb310f3 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 20 Mar 2014 13:24:00 +0000 Subject: [PATCH 005/266] In the 1.113.0 release notes, explain the backwards-imcompatible consequences of the generation chain changes. Copied from Perforce Change: 184903 ServerID: perforce.ravenbrook.com --- mps/manual/source/release.rst | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 3e6f650e146..ff3d466705f 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -8,6 +8,45 @@ Release notes Release 1.113.0 --------------- +New features +............ + +#. In previous releases there was an implicit connection between + blocks allocated by blocks allocated by :ref:`pool-awl` and + :ref:`pool-lo` pools, and blocks allocated by other automatically + managed pool classes. + + In particular, blocks allocated by AWL and LO pools were garbage + collected together with blocks allocated by :ref:`pool-ams` pools, + and blocks allocated by :ref:`pool-amc` pools in generation 1 of + their chains. + + This is no longer the case: to arrange for blocks to be collected + together you need to ensure that they are allocated in the *same* + generation chain, using the :c:macro:`MPS_KEY_CHAIN` and + :c:macro:`MPS_KEY_GEN` keyword arguments to + :c:func:`mps_pool_create_k`. + + So if you have code like this:: + + res = mps_pool_create(&my_amc, arena, mps_class_amc(), my_chain); + res = mps_pool_create(&my_awl, arena, mps_class_awl()); + + and you want to retain the connection between these pools, then you + must ensure that they use the same generation chain:: + + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_CHAIN, my_chain); + res = mps_pool_create_k(&my_amc, arena, mps_class_amc(), args); + } MPS_ARGS_END(args); + + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_CHAIN, my_chain); + MPS_ARGS_ADD(args, MPS_KEY_GEN, 1); + res = mps_pool_create_k(&my_awl, arena, mps_class_awl(), args); + } MPS_ARGS_END(args); + + Interface changes ................. From ead24bedd5203edee6e71c109fd0995bfa66c8e7 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 20 Mar 2014 17:34:54 +0000 Subject: [PATCH 006/266] Fix typo. Copied from Perforce Change: 184909 ServerID: perforce.ravenbrook.com --- mps/manual/source/release.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index ff3d466705f..e660c2ff95b 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -12,9 +12,8 @@ New features ............ #. In previous releases there was an implicit connection between - blocks allocated by blocks allocated by :ref:`pool-awl` and - :ref:`pool-lo` pools, and blocks allocated by other automatically - managed pool classes. + blocks allocated by :ref:`pool-awl` and :ref:`pool-lo` pools, and + blocks allocated by other automatically managed pool classes. In particular, blocks allocated by AWL and LO pools were garbage collected together with blocks allocated by :ref:`pool-ams` pools, From 8da10d1ffd416a76a1149cab807089eaede52f78 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 25 Mar 2014 16:01:06 +0000 Subject: [PATCH 007/266] Branching master to branch/2014-03-25/ansi. Copied from Perforce Change: 185015 ServerID: perforce.ravenbrook.com From 4bd54353146cdca5e87da16a2d89f6b2f9d1509f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 26 Mar 2014 12:27:35 +0000 Subject: [PATCH 008/266] Fix review comments from dl . Add __attribute__((__format__(printf))) to functions that take a printf-compatible format string (when building using GCC or Clang), so that format string mistakes can be detected statically. Copied from Perforce Change: 185021 ServerID: perforce.ravenbrook.com --- mps/code/mps.c | 14 +++++++++++++- mps/code/mps.xcodeproj/project.pbxproj | 8 ++++++++ mps/code/protan.c | 2 +- mps/code/vman.c | 3 ++- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/mps/code/mps.c b/mps/code/mps.c index ef2484eabdf..b3be2615c5b 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -95,9 +95,21 @@ #include "mpsioan.c" #endif +/* ANSI back end. */ + +#if defined(CONFIG_ANSI) + +#include "lockan.c" /* generic locks */ +#include "than.c" /* generic threads manager */ +#include "vman.c" /* malloc-based pseudo memory mapping */ +#include "protan.c" /* generic memory protection */ +#include "prmcan.c" /* generic protection mutator context */ +#include "span.c" /* generic stack probe */ +#include "ssan.c" /* generic stack scanner */ + /* Mac OS X on 32-bit Intel built with Clang or GCC */ -#if defined(MPS_PF_XCI3LL) || defined(MPS_PF_XCI3GC) +#elif defined(MPS_PF_XCI3LL) || defined(MPS_PF_XCI3GC) #include "lockix.c" /* Posix locks */ #include "thxc.c" /* OS X Mach threading */ diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index d7865d3d4a6..37fb0893447 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -4439,6 +4439,10 @@ 3114A654156E9596001E0AA3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "CONFIG_VAR_COOL=1", + "CONFIG_ANSI=1", + ); PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -4523,6 +4527,10 @@ 3124CAC0156BE3EC00753214 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + CONFIG_VAR_COOL, + CONFIG_ANSI, + ); PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; diff --git a/mps/code/protan.c b/mps/code/protan.c index 51b2edd6df8..b9fb46e7062 100644 --- a/mps/code/protan.c +++ b/mps/code/protan.c @@ -59,7 +59,7 @@ void ProtSync(Arena arena) ShieldLeave(arena); synced = FALSE; } - } while(SegNext(&seg, arena, base)); + } while(SegNext(&seg, arena, seg)); } } while(!synced); } diff --git a/mps/code/vman.c b/mps/code/vman.c index db7795c9f2e..2b4f0c3ecb2 100644 --- a/mps/code/vman.c +++ b/mps/code/vman.c @@ -63,11 +63,12 @@ Res VMParamFromArgs(void *params, size_t paramSize, ArgList args) /* VMCreate -- reserve some virtual address space, and create a VM structure */ -Res VMCreate(VM *vmReturn, Size size) +Res VMCreate(VM *vmReturn, Size size, void *params) { VM vm; AVER(vmReturn != NULL); + AVER(params != NULL); /* Note that because we add VMANPageALIGNMENT rather than */ /* VMANPageALIGNMENT-1 we are not in danger of overflowing */ From d1a51c98c8c7904161f16ed9e8d82e0883c79768 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 26 Mar 2014 16:25:14 +0000 Subject: [PATCH 009/266] Symbols starting config_ must be confined to config.h (see design.mps.config.impl.dep). Copied from Perforce Change: 185027 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 12 ++++++++++++ mps/code/mps.c | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index 4778b4b7552..bf056d2dc0d 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -152,6 +152,18 @@ #endif +/* CONFIG_PF_ANSI -- use the ANSI platform + * + * This symbol tells mps.c to exclude the sources for the + * auto-detected platform, and use the generic ("ANSI") platform + * instead. + */ + +#if defined(CONFIG_PF_ANSI) +#define PLATFORM_ANSI +#endif + + #define MPS_VARIETY_STRING \ MPS_ASSERT_STRING "." MPS_LOG_STRING "." MPS_STATS_STRING diff --git a/mps/code/mps.c b/mps/code/mps.c index b3be2615c5b..4fe83c151ec 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -95,9 +95,9 @@ #include "mpsioan.c" #endif -/* ANSI back end. */ +/* Generic ("ANSI") platform */ -#if defined(CONFIG_ANSI) +#if defined(PLATFORM_ANSI) #include "lockan.c" /* generic locks */ #include "than.c" /* generic threads manager */ From 8f0f336651585717bb74f93968d5c9286e85e302 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 26 Mar 2014 17:09:49 +0000 Subject: [PATCH 010/266] Generic stack scanner implementation. Copied from Perforce Change: 185032 ServerID: perforce.ravenbrook.com --- mps/code/ssan.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/mps/code/ssan.c b/mps/code/ssan.c index 6f632dd1d24..603895dbf49 100644 --- a/mps/code/ssan.c +++ b/mps/code/ssan.c @@ -3,10 +3,16 @@ * $Id$ * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. * - * This module provides zero functionality. It exists to feed the - * linker (prevent linker errors). + * This module makes a best effort to scan the stack and fix the + * registers which may contain roots, using only the features of the + * Standard C library. + * + * .assume.setjmp: The implementation assumes that setjmp stores all + * the registers that need to be scanned in the jmp_buf. */ +#include + #include "mpmtypes.h" #include "misc.h" #include "ss.h" @@ -17,8 +23,17 @@ SRCID(ssan, "$Id$"); Res StackScan(ScanState ss, Addr *stackBot) { - UNUSED(ss); UNUSED(stackBot); - return ResUNIMPL; + jmp_buf jb; + void *stackTop = &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); + + return StackScanInner(ss, stackBot, stackTop, sizeof jb / sizeof(Addr*)); } From 47a6cc51b5eb1f4be21ab95db5ac5084fafb58c2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 26 Mar 2014 21:23:04 +0000 Subject: [PATCH 011/266] Refactor comm.gmk so that cflags is reserved for the user. this means that if you want to build using the ansi platform you can run "make -f xci6ll.gmk cflags=-dconfig_pf_ansi". Don't include the testrun target in the "all" target. Copied from Perforce Change: 185034 ServerID: perforce.ravenbrook.com --- mps/code/comm.gmk | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index ffef57e63fa..bd0346e1679 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -15,8 +15,8 @@ # Assumes the following variables and definitions: # EXTRA_TARGETS a list of extra targets to build # CFLAGSCOMPILER a list of flags for all compilations -# CFLAGSSTRICT a list of flags for almost all compilations -# CFLAGSLAX a list of flags for compilations which can't be as +# CFLAGSCOMPILERSTRICT a list of flags for almost all compilations +# CFLAGSCOMPILERLAX a list of flags for compilations which can't be as # strict (e.g. because they have to include a third- # party header file that isn't -ansi -pedantic). # CFLAGSDEBUG a list of flags for compilations with maximum debug @@ -108,7 +108,7 @@ endif # These flags are included in all compilations. # Avoid using PFMDEFS in platform makefiles, as they prevent the MPS being # built with a simple command like "cc -c mps.c". -CFLAGSCOMMON = $(PFMDEFS) $(CFLAGSCOMPILER) $(CFLAGSCOMPILERSTRICT) +CFLAGSCOMMONSTRICT = $(PFMDEFS) $(CFLAGSCOMPILER) $(CFLAGSCOMPILERSTRICT) CFLAGSCOMMONLAX = $(PFMDEFS) $(CFLAGSCOMPILER) $(CFLAGSCOMPILERLAX) # %%VARIETY: When adding a new variety, define a macro containing the set @@ -119,20 +119,17 @@ CFRASH = -DCONFIG_VAR_RASH -DNDEBUG $(CFLAGSOPT) CFHOT = -DCONFIG_VAR_HOT -DNDEBUG $(CFLAGSOPT) CFCOOL = -DCONFIG_VAR_COOL $(CFLAGSDEBUG) -# Bind CFLAGS to the appropriate set of flags for the variety. -# %%VARIETY: When adding a new variety, add a test for the variety and set -# CFLAGS here. +# Bind CFLAGSVARIETY to the appropriate set of flags for the variety. +# %%VARIETY: When adding a new variety, add a test for the variety and +# set CFLAGSVARIETY here. ifeq ($(VARIETY),rash) -CFLAGS=$(CFLAGSCOMMON) $(CFRASH) -CFLAGSLAX=$(CFLAGSCOMMONLAX) $(CFRASH) +CFLAGSVARIETY=$(CFRASH) else ifeq ($(VARIETY),hot) -CFLAGS=$(CFLAGSCOMMON) $(CFHOT) -CFLAGSLAX=$(CFLAGSCOMMONLAX) $(CFHOT) +CFLAGSVARIETY=$(CFHOT) else ifeq ($(VARIETY),cool) -CFLAGS=$(CFLAGSCOMMON) $(CFCOOL) -CFLAGSLAX=$(CFLAGSCOMMONLAX) $(CFCOOL) +CFLAGSVARIETY=$(CFCOOL) else ifneq ($(VARIETY),) $(error Variety "$(VARIETY)" not recognized: must be rash/hot/cool) @@ -141,7 +138,8 @@ endif endif endif - +CFLAGSSTRICT=$(CFLAGSCOMMONSTRICT) $(CFLAGSVARIETY) $(CFLAGS) +CFLAGSLAX=$(CFLAGSCOMMONLAX) $(CFLAGSVARIETY) $(CFLAGS) ARFLAGS=rc$(ARFLAGSPFM) @@ -273,7 +271,7 @@ TEST_TARGETS=\ UNBUILDABLE_TARGETS=\ replay # depends on the EPVM pool -ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS) testrun +ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS) # == Pseudo-targets == @@ -290,7 +288,7 @@ $(PFM)/$(VARIETY)/testrun: $(TEST_TARGETS) # These convenience targets allow one to type "make foo" to build target # foo in selected varieties (or none, for the latter rule). -$(ALL_TARGETS): phony +$(ALL_TARGETS) testrun: phony ifdef VARIETY $(MAKE) -f $(PFM).gmk TARGET=$@ variety else @@ -513,11 +511,11 @@ endif # Object files -define run-cc +define run-cc-strict $(ECHO) "$(PFM): $@" mkdir -p $(PFM) mkdir -p $(PFM)/$(VARIETY) -$(CC) $(CFLAGS) -c -o $@ $< +$(CC) $(CFLAGSSTRICT) -c -o $@ $< endef define run-cc-lax @@ -529,16 +527,16 @@ endef # .rule.c-to-o: $(PFM)/$(VARIETY)/%.o: %.c - $(run-cc) + $(run-cc-strict) $(PFM)/$(VARIETY)/eventsql.o: eventsql.c $(run-cc-lax) $(PFM)/$(VARIETY)/%.o: %.s - $(run-cc) + $(run-cc-strict) $(PFM)/$(VARIETY)/%.o: %.S - $(run-cc) + $(run-cc-strict) # Dependencies # @@ -587,7 +585,7 @@ endif $(PFM)/$(VARIETY)/%.a: $(ECHO) "$(PFM): $@" rm -f $@ - $(CC) $(CFLAGS) -c -o $(PFM)/$(VARIETY)/version.o version.c + $(CC) $(CFLAGSSTRICT) -c -o $(PFM)/$(VARIETY)/version.o version.c $(AR) $(ARFLAGS) $@ $^ $(PFM)/$(VARIETY)/version.o $(RANLIB) $@ @@ -595,11 +593,11 @@ $(PFM)/$(VARIETY)/%.a: $(PFM)/$(VARIETY)/%: $(ECHO) "$(PFM): $@" - $(CC) $(CFLAGS) $(LINKFLAGS) -o $@ $^ $(LIBS) + $(CC) $(CFLAGSSTRICT) $(LINKFLAGS) -o $@ $^ $(LIBS) $(PFM)/$(VARIETY)/mpseventsql: $(ECHO) "$(PFM): $@" - $(CC) $(CFLAGS) $(LINKFLAGS) -o $@ $^ $(LIBS) -lsqlite3 + $(CC) $(CFLAGSLAX) $(LINKFLAGS) -o $@ $^ $(LIBS) -lsqlite3 # Special targets for development From 4da195068c424223b9d8178eb1410a69a35798c9 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 26 Mar 2014 23:19:04 +0000 Subject: [PATCH 012/266] Add and document new configuration options config_thread_single and config_protection_none. Copied from Perforce Change: 185037 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 29 +++++++++++++++++++++++++++-- mps/code/lock.h | 13 ++----------- mps/code/lockix.c | 24 ++++++++++++------------ mps/code/lockli.c | 24 ++++++++++++------------ mps/code/lockw3.c | 24 ++++++++++++------------ mps/design/config.txt | 39 +++++++++++++++++++++++++++++++++++++-- 6 files changed, 102 insertions(+), 51 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index bf056d2dc0d..a1ebc2e688a 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -164,6 +164,33 @@ #endif +/* CONFIG_THREAD_SINGLE -- support single-threaded execution only + * + * This symbol causes the MPS to be built for single-threaded + * execution only, where locks are not needed and so lock operations + * can be defined as no-ops by lock.h. + */ + +#if defined(CONFIG_THREAD_SINGLE) +#define THREAD_SINGLE +#else +#define THREAD_MULTI +#endif + +/* CONFIG_PROTECTION_NONE -- no support for memory protection + * + * This symbol causes the MPS to built for an environment where there + * is no memory protection, and so segment summaries cannot be + * maintained by seg.c. + */ + +#if defined(CONFIG_PROTECTION_NONE) +#define PROTECTION_NONE +#else +#define PROTECTION +#endif + + #define MPS_VARIETY_STRING \ MPS_ASSERT_STRING "." MPS_LOG_STRING "." MPS_STATS_STRING @@ -517,8 +544,6 @@ #define MPS_PROD_STRING "mps" #define MPS_PROD_MPS -#define THREAD_MULTI -#define PROTECTION #define PROD_CHECKLEVEL_INITIAL CheckLevelSHALLOW /* TODO: This should be proportional to the memory usage of the MPS, not diff --git a/mps/code/lock.h b/mps/code/lock.h index 1431bbacd85..5faddfa05b8 100644 --- a/mps/code/lock.h +++ b/mps/code/lock.h @@ -85,9 +85,6 @@ #define LockSig ((Sig)0x51970CC9) /* SIGnature LOCK */ -#if defined(THREAD_MULTI) - - /* LockSize -- Return the size of a LockStruct * * Supports allocation of locks. @@ -198,8 +195,7 @@ extern void LockClaimGlobal(void); extern void LockReleaseGlobal(void); -#elif defined(THREAD_SINGLE) - +#ifdef THREAD_SINGLE #define LockSize() MPS_PF_ALIGN #define LockInit(lock) UNUSED(lock) @@ -214,12 +210,7 @@ extern void LockReleaseGlobal(void); #define LockClaimGlobal() #define LockReleaseGlobal() - -#else - -#error "No threading defined." - -#endif +#endif /* THREAD_SINGLE */ #endif /* lock_h */ diff --git a/mps/code/lockix.c b/mps/code/lockix.c index c32361e8560..2afd294246e 100644 --- a/mps/code/lockix.c +++ b/mps/code/lockix.c @@ -58,7 +58,7 @@ typedef struct LockStruct { /* LockSize -- size of a LockStruct */ -size_t LockSize(void) +size_t (LockSize)(void) { return sizeof(LockStruct); } @@ -66,7 +66,7 @@ size_t LockSize(void) /* LockCheck -- check a lock */ -Bool LockCheck(Lock lock) +Bool (LockCheck)(Lock lock) { CHECKS(Lock, lock); /* While claims can't be very large, I don't dare to put a limit on it. */ @@ -77,7 +77,7 @@ Bool LockCheck(Lock lock) /* LockInit -- initialize a lock */ -void LockInit(Lock lock) +void (LockInit)(Lock lock) { pthread_mutexattr_t attr; int res; @@ -99,7 +99,7 @@ void LockInit(Lock lock) /* LockFinish -- finish a lock */ -void LockFinish(Lock lock) +void (LockFinish)(Lock lock) { int res; @@ -114,7 +114,7 @@ void LockFinish(Lock lock) /* LockClaim -- claim a lock (non-recursive) */ -void LockClaim(Lock lock) +void (LockClaim)(Lock lock) { int res; @@ -133,7 +133,7 @@ void LockClaim(Lock lock) /* LockReleaseMPM -- release a lock (non-recursive) */ -void LockReleaseMPM(Lock lock) +void (LockReleaseMPM)(Lock lock) { int res; @@ -148,7 +148,7 @@ void LockReleaseMPM(Lock lock) /* LockClaimRecursive -- claim a lock (recursive) */ -void LockClaimRecursive(Lock lock) +void (LockClaimRecursive)(Lock lock) { int res; @@ -168,7 +168,7 @@ void LockClaimRecursive(Lock lock) /* LockReleaseRecursive -- release a lock (recursive) */ -void LockReleaseRecursive(Lock lock) +void (LockReleaseRecursive)(Lock lock) { int res; @@ -203,7 +203,7 @@ static void globalLockInit(void) /* LockClaimGlobalRecursive -- claim the global recursive lock */ -void LockClaimGlobalRecursive(void) +void (LockClaimGlobalRecursive)(void) { int res; @@ -216,7 +216,7 @@ void LockClaimGlobalRecursive(void) /* LockReleaseGlobalRecursive -- release the global recursive lock */ -void LockReleaseGlobalRecursive(void) +void (LockReleaseGlobalRecursive)(void) { LockReleaseRecursive(globalRecLock); } @@ -224,7 +224,7 @@ void LockReleaseGlobalRecursive(void) /* LockClaimGlobal -- claim the global non-recursive lock */ -void LockClaimGlobal(void) +void (LockClaimGlobal)(void) { int res; @@ -237,7 +237,7 @@ void LockClaimGlobal(void) /* LockReleaseGlobal -- release the global non-recursive lock */ -void LockReleaseGlobal(void) +void (LockReleaseGlobal)(void) { LockReleaseMPM(globalLock); } diff --git a/mps/code/lockli.c b/mps/code/lockli.c index 06437b5b531..5e63e15d291 100644 --- a/mps/code/lockli.c +++ b/mps/code/lockli.c @@ -72,7 +72,7 @@ typedef struct LockStruct { /* LockSize -- size of a LockStruct */ -size_t LockSize(void) +size_t (LockSize)(void) { return sizeof(LockStruct); } @@ -80,7 +80,7 @@ size_t LockSize(void) /* LockCheck -- check a lock */ -Bool LockCheck(Lock lock) +Bool (LockCheck)(Lock lock) { CHECKS(Lock, lock); /* While claims can't be very large, I don't dare to put a limit on it. */ @@ -91,7 +91,7 @@ Bool LockCheck(Lock lock) /* LockInit -- initialize a lock */ -void LockInit(Lock lock) +void (LockInit)(Lock lock) { pthread_mutexattr_t attr; int res; @@ -113,7 +113,7 @@ void LockInit(Lock lock) /* LockFinish -- finish a lock */ -void LockFinish(Lock lock) +void (LockFinish)(Lock lock) { int res; @@ -128,7 +128,7 @@ void LockFinish(Lock lock) /* LockClaim -- claim a lock (non-recursive) */ -void LockClaim(Lock lock) +void (LockClaim)(Lock lock) { int res; @@ -147,7 +147,7 @@ void LockClaim(Lock lock) /* LockReleaseMPM -- release a lock (non-recursive) */ -void LockReleaseMPM(Lock lock) +void (LockReleaseMPM)(Lock lock) { int res; @@ -162,7 +162,7 @@ void LockReleaseMPM(Lock lock) /* LockClaimRecursive -- claim a lock (recursive) */ -void LockClaimRecursive(Lock lock) +void L(ockClaimRecursive)(Lock lock) { int res; @@ -182,7 +182,7 @@ void LockClaimRecursive(Lock lock) /* LockReleaseRecursive -- release a lock (recursive) */ -void LockReleaseRecursive(Lock lock) +void (LockReleaseRecursive)(Lock lock) { int res; @@ -217,7 +217,7 @@ static void globalLockInit(void) /* LockClaimGlobalRecursive -- claim the global recursive lock */ -void LockClaimGlobalRecursive(void) +void (LockClaimGlobalRecursive)(void) { int res; @@ -230,7 +230,7 @@ void LockClaimGlobalRecursive(void) /* LockReleaseGlobalRecursive -- release the global recursive lock */ -void LockReleaseGlobalRecursive(void) +void (LockReleaseGlobalRecursive)(void) { LockReleaseRecursive(globalRecLock); } @@ -238,7 +238,7 @@ void LockReleaseGlobalRecursive(void) /* LockClaimGlobal -- claim the global non-recursive lock */ -void LockClaimGlobal(void) +void (LockClaimGlobal)(void) { int res; @@ -251,7 +251,7 @@ void LockClaimGlobal(void) /* LockReleaseGlobal -- release the global non-recursive lock */ -void LockReleaseGlobal(void) +void (LockReleaseGlobal)(void) { LockReleaseMPM(globalLock); } diff --git a/mps/code/lockw3.c b/mps/code/lockw3.c index 258b31bff44..2fdc2800032 100644 --- a/mps/code/lockw3.c +++ b/mps/code/lockw3.c @@ -40,18 +40,18 @@ typedef struct LockStruct { } LockStruct; -size_t LockSize(void) +size_t (LockSize)(void) { return sizeof(LockStruct); } -Bool LockCheck(Lock lock) +Bool (LockCheck)(Lock lock) { CHECKS(Lock, lock); return TRUE; } -void LockInit(Lock lock) +void (LockInit)(Lock lock) { AVER(lock != NULL); lock->claims = 0; @@ -60,7 +60,7 @@ void LockInit(Lock lock) AVERT(Lock, lock); } -void LockFinish(Lock lock) +void (LockFinish)(Lock lock) { AVERT(Lock, lock); /* Lock should not be finished while held */ @@ -69,7 +69,7 @@ void LockFinish(Lock lock) lock->sig = SigInvalid; } -void LockClaim(Lock lock) +void (LockClaim)(Lock lock) { AVERT(Lock, lock); EnterCriticalSection(&lock->cs); @@ -79,7 +79,7 @@ void LockClaim(Lock lock) lock->claims = 1; } -void LockReleaseMPM(Lock lock) +void (LockReleaseMPM)(Lock lock) { AVERT(Lock, lock); AVER(lock->claims == 1); /* The lock should only be held once */ @@ -87,7 +87,7 @@ void LockReleaseMPM(Lock lock) LeaveCriticalSection(&lock->cs); } -void LockClaimRecursive(Lock lock) +void (LockClaimRecursive)(Lock lock) { AVERT(Lock, lock); EnterCriticalSection(&lock->cs); @@ -95,7 +95,7 @@ void LockClaimRecursive(Lock lock) AVER(lock->claims > 0); } -void LockReleaseRecursive(Lock lock) +void (LockReleaseRecursive)(Lock lock) { AVERT(Lock, lock); AVER(lock->claims > 0); @@ -129,27 +129,27 @@ static void lockEnsureGlobalLock(void) } } -void LockClaimGlobalRecursive(void) +void (LockClaimGlobalRecursive)(void) { lockEnsureGlobalLock(); AVER(globalLockInit); LockClaimRecursive(globalRecLock); } -void LockReleaseGlobalRecursive(void) +void (LockReleaseGlobalRecursive)(void) { AVER(globalLockInit); LockReleaseRecursive(globalRecLock); } -void LockClaimGlobal(void) +void (LockClaimGlobal)(void) { lockEnsureGlobalLock(); AVER(globalLockInit); LockClaim(globalLock); } -void LockReleaseGlobal(void) +void (LockReleaseGlobal)(void) { AVER(globalLockInit); LockReleaseMPM(globalLock); diff --git a/mps/design/config.txt b/mps/design/config.txt index 03bfec5109a..c7184ab31ee 100644 --- a/mps/design/config.txt +++ b/mps/design/config.txt @@ -97,6 +97,10 @@ as a dimension of configuration since `.req.prod`_ has been retired. _`.def.target`: The *target* is the result of the build. +_`.def.option`: An *option* is a feature of the MPS that is not +selected via the *platform* and *variety*. See `.opt`_. + + Overview -------- @@ -150,7 +154,7 @@ _`.build.cc`: A consequence of this approach is that it should always be possible to build a complete target with a single UNIX command line calling the compiler driver (usually "cc" or "gcc"), for example:: - cc -o main -DCONFIG_VAR_DF foo.c bar.c baz.s -lz + cc -o main -DCONFIG_VAR_COOL foo.c bar.c baz.s -lz _`.build.defs`: The "defs" are the set of preprocessor macros which are to be predefined when compiling the module sources:: @@ -319,12 +323,14 @@ _`.pf.form`: This file consists of sets of directives of the form:: #elif #define MPS_PF_ + #define MPS_PF_STRING "" #define MPS_OS_ #define MPS_ARCH_ #define MPS_BUILD_ #define MPS_T_WORD #define MPS_T_ULONGEST - #define MPS_WORD_SHIFT + #define MPS_WORD_WIDTH + #define MPS_WORD_SHIFT #define MPS_PF_ALIGN _`.pf.detect`: The conjunction of builder predefinitions is a constant @@ -513,6 +519,35 @@ For example, this sort of thing:: This violates `.no-spaghetti`_. +Configuration options +--------------------- + +_`.opt`: Options select features of the MPS that are not selected by the *platform* and the *variety*. + +_`.opt.support`: The features selected by options are not supported or +documented in the public interface. This is to keep the complexity of +the MPS manageable: at present the number of supported configuration +is *platforms* × *varieties* (at time of writing, 9 × 3 = 27). Each +supported option would double (or worse) the number of supported +configurations. + +_`.opt.ansi`: ``CONFIG_PF_ANSI`` tells ``mps.c`` to exclude the +sources for the auto-detected platform, and use the generic ("ANSI") +platform instead. + +_`.opt.thread`: ``CONFIG_THREAD_SINGLE`` causes the MPS to be built +for single-threaded execution only, where locks are not needed and so +lock operations can be defined as no-ops by ``lock.h``. + +_`.opt.prot`: ``CONFIG_PROTECTION_NONE`` causes the MPS to be built +for an environment where there is no memory protection, and so segment summaries cannot be maintained by ``seg.c``. + +_`.opt.prot.thread`: If both ``CONFIG_THREAD_SINGLE`` and +``CONFIG_PROTECTION_NONE`` are defined, then the shield is not needed +and so shield operations can be defined as no-ops by ``mpm.h``. + + + To document ----------- - What about constants in config.h? From 74c04b45f0a1d8f643d6b94c6565bac2385a965a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 27 Mar 2014 11:52:27 +0000 Subject: [PATCH 013/266] Provide three different test targets for different purposes: * testrun = "smoke test", fast enough to run before every commit * testci = continuous integration tests, must be known good * testall = all test cases, for ensuring quality of a release Switch the main "make test" from testrun to testci. Put test cases into "database" so that they can be selected. Copied from Perforce Change: 185039 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 7 +- mps/code/comm.gmk | 14 ++- mps/code/mps.xcodeproj/project.pbxproj | 160 ++++++++++++++++++++++--- mps/tool/testcases.txt | 54 +++++++++ mps/tool/testrun.sh | 71 ++++------- 5 files changed, 234 insertions(+), 72 deletions(-) create mode 100644 mps/tool/testcases.txt diff --git a/mps/Makefile.in b/mps/Makefile.in index 2d558588673..960903ba43a 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -68,11 +68,10 @@ make-install-dirs: install: @INSTALL_TARGET@ test-make-build: @BUILD_TARGET@ - $(MAKE) $(TARGET_OPTS) VARIETY=cool testrun - $(MAKE) $(TARGET_OPTS) VARIETY=hot testrun + $(MAKE) $(TARGET_OPTS) testci test-xcode-build: - $(XCODEBUILD) -config Release -target testrun - $(XCODEBUILD) -config Debug -target testrun + $(XCODEBUILD) -config Release -target testci + $(XCODEBUILD) -config Debug -target testci test: @TEST_TARGET@ diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index bd0346e1679..837b025e974 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -279,16 +279,22 @@ ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS) all: $(ALL_TARGETS) -# Run the automated tests. +# == Automated test suites == +# +# testrun = "smoke test", fast enough to run before every commit +# testci = continuous integration tests, must be known good +# testall = all test cases, for ensuring quality of a release -$(PFM)/$(VARIETY)/testrun: $(TEST_TARGETS) - ../tool/testrun.sh "$(PFM)/$(VARIETY)" +TEST_SUITES=testrun testci testall + +$(addprefix $(PFM)/$(VARIETY)/,$(TEST_SUITES)): $(TEST_TARGETS) + ../tool/testrun.sh "$(PFM)/$(VARIETY)" "$(notdir $@)" # These convenience targets allow one to type "make foo" to build target # foo in selected varieties (or none, for the latter rule). -$(ALL_TARGETS) testrun: phony +$(ALL_TARGETS) $(TEST_SUITES): phony ifdef VARIETY $(MAKE) -f $(PFM).gmk TARGET=$@ variety else diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index adbe341583b..1c9f39ff0f1 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -7,6 +7,30 @@ objects = { /* Begin PBXAggregateTarget section */ + 225F0AFC18E4453A003F2183 /* testci */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 225F0B0018E4453A003F2183 /* Build configuration list for PBXAggregateTarget "testci" */; + buildPhases = ( + 225F0AFF18E4453A003F2183 /* ShellScript */, + ); + dependencies = ( + 225F0AFD18E4453A003F2183 /* PBXTargetDependency */, + ); + name = testci; + productName = testrun; + }; + 225F0B0418E44549003F2183 /* testall */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 225F0B0818E44549003F2183 /* Build configuration list for PBXAggregateTarget "testall" */; + buildPhases = ( + 225F0B0718E44549003F2183 /* ShellScript */, + ); + dependencies = ( + 225F0B0518E44549003F2183 /* PBXTargetDependency */, + ); + name = testall; + productName = testrun; + }; 22CDE8EF16E9E97D00366D0A /* testrun */ = { isa = PBXAggregateTarget; buildConfigurationList = 22CDE8F016E9E97E00366D0A /* Build configuration list for PBXAggregateTarget "testrun" */; @@ -320,6 +344,20 @@ remoteGlobalIDString = 224CC78C175E1821002FF81B; remoteInfo = mvfftest; }; + 225F0AFE18E4453A003F2183 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3104AFF1156D37A0000A585A; + remoteInfo = all; + }; + 225F0B0618E44549003F2183 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3104AFF1156D37A0000A585A; + remoteInfo = all; + }; 2275798816C5422900B662B0 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; @@ -1326,8 +1364,6 @@ 22FACED5188807FF000FDBC1 /* fmtno.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fmtno.h; sourceTree = ""; }; 22FACED6188807FF000FDBC1 /* fmtscheme.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fmtscheme.c; sourceTree = ""; }; 22FACED7188807FF000FDBC1 /* fmtscheme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fmtscheme.h; sourceTree = ""; }; - 22FACED8188807FF000FDBC1 /* locbwcss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = locbwcss.c; sourceTree = ""; }; - 22FACED9188807FF000FDBC1 /* locusss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = locusss.c; sourceTree = ""; }; 22FACEDA1888088A000FDBC1 /* ss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ss.c; sourceTree = ""; }; 22FACEDB188808D5000FDBC1 /* mpscmfs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mpscmfs.h; sourceTree = ""; }; 22FACEDC18880933000FDBC1 /* poolmfs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = poolmfs.h; sourceTree = ""; }; @@ -3248,6 +3284,8 @@ targets = ( 3104AFF1156D37A0000A585A /* all */, 22CDE8EF16E9E97D00366D0A /* testrun */, + 225F0AFC18E4453A003F2183 /* testci */, + 225F0B0418E44549003F2183 /* testall */, 31EEABFA156AAF9D00714D05 /* mps */, 3114A632156E94DB001E0AA3 /* abqtest */, 22FACEE018880983000FDBC1 /* airtest */, @@ -3299,6 +3337,34 @@ /* End PBXProject section */ /* Begin PBXShellScriptBuildPhase section */ + 225F0AFF18E4453A003F2183 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\""; + showEnvVarsInLog = 0; + }; + 225F0B0718E44549003F2183 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\""; + showEnvVarsInLog = 0; + }; 22CDE8F416E9E9D400366D0A /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -3310,7 +3376,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\"\n"; + shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\""; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -3827,6 +3893,16 @@ target = 224CC78C175E1821002FF81B /* fotest */; targetProxy = 224CC79C175E187C002FF81B /* PBXContainerItemProxy */; }; + 225F0AFD18E4453A003F2183 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3104AFF1156D37A0000A585A /* all */; + targetProxy = 225F0AFE18E4453A003F2183 /* PBXContainerItemProxy */; + }; + 225F0B0518E44549003F2183 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3104AFF1156D37A0000A585A /* all */; + targetProxy = 225F0B0618E44549003F2183 /* PBXContainerItemProxy */; + }; 2275798916C5422900B662B0 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 2D604B9B16514B1A003AAF46 /* mpseventtxt */; @@ -4286,6 +4362,48 @@ }; name = Release; }; + 225F0B0118E4453A003F2183 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testrun copy"; + }; + name = Debug; + }; + 225F0B0218E4453A003F2183 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testrun copy"; + }; + name = Release; + }; + 225F0B0318E4453A003F2183 /* RASH */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testrun copy"; + }; + name = RASH; + }; + 225F0B0918E44549003F2183 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testrun copy copy"; + }; + name = Debug; + }; + 225F0B0A18E44549003F2183 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testrun copy copy"; + }; + name = Release; + }; + 225F0B0B18E44549003F2183 /* RASH */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testrun copy copy"; + }; + name = RASH; + }; 2291A5BA175CAB2F001D4920 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4362,8 +4480,6 @@ 22C2ACAC18BE400A006B3677 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_GENERATE_TEST_COVERAGE_FILES = YES; - GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = YES; PRODUCT_NAME = nailboardtest; }; name = Debug; @@ -4371,8 +4487,6 @@ 22C2ACAD18BE400A006B3677 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_GENERATE_TEST_COVERAGE_FILES = NO; - GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO; PRODUCT_NAME = nailboardtest; }; name = Release; @@ -4380,8 +4494,6 @@ 22C2ACAE18BE400A006B3677 /* RASH */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_GENERATE_TEST_COVERAGE_FILES = NO; - GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO; PRODUCT_NAME = nailboardtest; }; name = RASH; @@ -4417,8 +4529,6 @@ 22FACEEA18880983000FDBC1 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_GENERATE_TEST_COVERAGE_FILES = YES; - GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = YES; PRODUCT_NAME = airtest; }; name = Debug; @@ -4426,8 +4536,6 @@ 22FACEEB18880983000FDBC1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_GENERATE_TEST_COVERAGE_FILES = NO; - GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO; PRODUCT_NAME = airtest; }; name = Release; @@ -4435,8 +4543,6 @@ 22FACEEC18880983000FDBC1 /* WE */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_GENERATE_TEST_COVERAGE_FILES = NO; - GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO; PRODUCT_NAME = airtest; }; name = WE; @@ -4686,10 +4792,6 @@ 3114A654156E9596001E0AA3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = ( - "CONFIG_VAR_COOL=1", - "CONFIG_ANSI=1", - ); PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -5500,6 +5602,26 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 225F0B0018E4453A003F2183 /* Build configuration list for PBXAggregateTarget "testci" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 225F0B0118E4453A003F2183 /* Debug */, + 225F0B0218E4453A003F2183 /* Release */, + 225F0B0318E4453A003F2183 /* RASH */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 225F0B0818E44549003F2183 /* Build configuration list for PBXAggregateTarget "testall" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 225F0B0918E44549003F2183 /* Debug */, + 225F0B0A18E44549003F2183 /* Release */, + 225F0B0B18E44549003F2183 /* RASH */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 2291A5B9175CAB2F001D4920 /* Build configuration list for PBXNativeTarget "awlutth" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/mps/tool/testcases.txt b/mps/tool/testcases.txt new file mode 100644 index 00000000000..96d3a4d2cff --- /dev/null +++ b/mps/tool/testcases.txt @@ -0,0 +1,54 @@ +============= ================ ========================================== +Test case Flags Notes +============= ================ ========================================== +abqtest +airtest +amcss +amcsshe +amcssth =B =X job003561, job003703 +amsss +amssshe +apss +arenacv +awlut +awluthe +awlutth =X +btcv +bttest =N interactive +djbench =N benchmark +exposet0 +expt825 +fbmtest +finalcv +finaltest +fotest +gcbench =N benchmark +locbwcss +lockcov +lockutw3 =W +locusss +locv +messtest +mpmss +mpsicv +mv2test +nailboardtest +poolncv +qs +sacss +segsmss +steptest +teletest =N interactive +walkt0 +zcoll =B =L +zmess +============= ================ ========================================== + +Key to flags +............ + + B -- known Bad + L -- Long runtime + N -- Not an automated test case + W -- Windows-only + X -- Unix-only diff --git a/mps/tool/testrun.sh b/mps/tool/testrun.sh index 9cecd1c6fd5..2785929db8f 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -12,57 +12,38 @@ # # Usage:: # -# testrun.sh DIR [CASE1 CASE2 ...] - -ALL_TEST_CASES=" - abqtest - amcss - amcsshe - amcssth - amsss - amssshe - apss - arenacv - awlut - awluthe - awlutth - btcv - exposet0 - expt825 - fbmtest - finalcv - finaltest - fotest - locbwcss - lockcov - locusss - locv - messtest - mpmss - mpsicv - mv2test - poolncv - qs - sacss - segsmss - steptest - walkt0 - zmess -" -# bttest -- interactive, so cannot be run unattended -# djbench -- benchmark, not test case -# gcbench -- benchmark, not test case -# teletest -- interactive, so cannot be run unattended -# zcoll -- takes too long to be useful as a regularly run smoke test +# testrun.sh DIR ( SUITE | CASE1 CASE2 [...] ) # Make a temporary output directory for the test logs. LOGDIR=$(mktemp -d /tmp/mps.log.XXXXXX) -TEST_DIR=$1 echo "MPS test suite" echo "Logging test output to $LOGDIR" -echo "Test directory: $TEST_DIR" + +# First argument is the directory containing the test cases. +TEST_DIR=$1 shift -TEST_CASES=${*:-${ALL_TEST_CASES}} +echo "Test directory: $TEST_DIR" + +# Determine which tests to run. +TEST_CASE_DB=$(dirname -- "$0")/testcases.txt +if [ $# == 1 ]; then + TEST_SUITE=$1 + echo "Test suite: $TEST_SUITE" + case $TEST_SUITE in + testrun) EXCLUDE="=[LNW]" ;; + testci) EXCLUDE="=[BNW]" ;; + testall) EXCLUDE="=[NW]" ;; + *) + 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 SEPARATOR="----------------------------------------" TEST_COUNT=0 From d5571ac9cf693d25dfc7f7bce068c16261174842 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 27 Mar 2014 12:22:19 +0000 Subject: [PATCH 014/266] Fix typo. Copied from Perforce Change: 185042 ServerID: perforce.ravenbrook.com --- mps/code/lockli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/lockli.c b/mps/code/lockli.c index 5e63e15d291..89e8f4f0653 100644 --- a/mps/code/lockli.c +++ b/mps/code/lockli.c @@ -162,7 +162,7 @@ void (LockReleaseMPM)(Lock lock) /* LockClaimRecursive -- claim a lock (recursive) */ -void L(ockClaimRecursive)(Lock lock) +void (LockClaimRecursive)(Lock lock) { int res; From 849318cc45c25bf7e73672ee038681d45ebcf024 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 27 Mar 2014 14:01:16 +0000 Subject: [PATCH 015/266] Share test case database between windows and unix. Add testci and testall targets on Windows. Copied from Perforce Change: 185047 ServerID: perforce.ravenbrook.com --- mps/code/commpost.nmk | 10 +++--- mps/tool/testrun.bat | 71 ++++++++++++++++--------------------------- mps/tool/testrun.sh | 8 ++--- 3 files changed, 35 insertions(+), 54 deletions(-) diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk index f049123a276..46203a321a3 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/commpost.nmk @@ -53,15 +53,15 @@ variety: $(PFM)\$(VARIETY)\$(TARGET) !ENDIF !ENDIF -# testrun +# testrun testci testall # Runs automated test cases. -testrun: $(TEST_TARGETS) +testrun testci testall: $(TEST_TARGETS) !IFDEF VARIETY - ..\tool\testrun.bat $(PFM) $(VARIETY) + ..\tool\testrun.bat $(PFM) $(VARIETY) $@ !ELSE - $(MAKE) /nologo /f $(PFM).nmk VARIETY=hot testrun - $(MAKE) /nologo /f $(PFM).nmk VARIETY=cool testrun + $(MAKE) /nologo /f $(PFM).nmk VARIETY=hot $@ + $(MAKE) /nologo /f $(PFM).nmk VARIETY=cool $@ !ENDIF diff --git a/mps/tool/testrun.bat b/mps/tool/testrun.bat index 696aaac0fd9..06f947a25e3 100755 --- a/mps/tool/testrun.bat +++ b/mps/tool/testrun.bat @@ -14,56 +14,28 @@ @echo off -@rem First two arguments are platform and variety. +@rem Find test case database in same directory as this script. +for %%F in ("%0") do set TEST_CASE_DB=%%~dpF%testcases.txt + set PFM=%1 shift set VARIETY=%1 shift +set TESTSUITE=%1 @rem Make a temporary output directory for the test logs. set LOGDIR=%TMP%\mps-%PFM%-%VARIETY%-log +echo MPS test suite echo Logging test output to %LOGDIR% +echo Test directory: %PFM%\%VARIETY% rmdir /q /s %LOGDIR% mkdir %LOGDIR% @rem Determine which tests to run. - - -set ALL_TEST_CASES=^ - abqtest.exe ^ - airtest.exe ^ - amcss.exe ^ - amcsshe.exe ^ - amsss.exe ^ - amssshe.exe ^ - apss.exe ^ - arenacv.exe ^ - awlut.exe ^ - awluthe.exe ^ - btcv.exe ^ - exposet0.exe ^ - expt825.exe ^ - fbmtest.exe ^ - finalcv.exe ^ - finaltest.exe ^ - fotest.exe ^ - locbwcss.exe ^ - lockcov.exe ^ - lockutw3.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 ^ - walkt0.exe ^ - zmess.exe +set EXCLUDE= +if "%TESTSUITE%"=="testrun" set EXCLUDE=LNX +if "%TESTSUITE%"=="testci" set EXCLUDE=BNX +if "%TESTSUITE%"=="testall" set EXCLUDE=NX @rem Ensure that test cases don't pop up dialog box on abort() set MPS_TESTLIB_NOABORT=true @@ -72,18 +44,28 @@ set PASS_COUNT=0 set FAIL_COUNT=0 set SEPARATOR=---------------------------------------- -if "%1"=="" call :run_tests %ALL_TEST_CASES% +if "%EXCLUDE%"=="" goto :args +for /f "tokens=1" %%T IN ('type %TEST_CASE_DB% ^|^ + findstr /b /r [abcdefghijklmnopqrstuvwxyz] ^|^ + findstr /v /r =[%EXCLUDE%]') do call :run_test %%T +goto :done +:args +if "%1"=="" goto :done +call :run_test %1 +shift +goto :args + +:done if "%FAIL_COUNT%"=="0" ( echo Tests: %TEST_COUNT%. All tests pass. - exit 0 + exit /b 0 ) else ( echo Tests: %TEST_COUNT%. Passes: %PASS_COUNT%. Failures: %FAIL_COUNT%. - exit 1 + exit /b 1 ) -:run_tests -if "%1"=="" exit /b +:run_test set /a TEST_COUNT=%TEST_COUNT%+1 echo Running %1 %PFM%\%VARIETY%\%1 > %LOGDIR%\%1 @@ -95,8 +77,7 @@ if "%errorlevel%"=="0" ( echo %SEPARATOR%%SEPARATOR% set /a FAIL_COUNT=%FAIL_COUNT%+1 ) -shift -goto run_tests +exit /b @rem C. COPYRIGHT AND LICENSE diff --git a/mps/tool/testrun.sh b/mps/tool/testrun.sh index 2785929db8f..303168cad63 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -30,15 +30,15 @@ if [ $# == 1 ]; then TEST_SUITE=$1 echo "Test suite: $TEST_SUITE" case $TEST_SUITE in - testrun) EXCLUDE="=[LNW]" ;; - testci) EXCLUDE="=[BNW]" ;; - testall) EXCLUDE="=[NW]" ;; + testrun) EXCLUDE="LNW" ;; + testci) EXCLUDE="BNW" ;; + testall) EXCLUDE="NW" ;; *) echo "Test suite $TEST_SUITE not recognized." exit 1 ;; esac TEST_CASES=$(<"$TEST_CASE_DB" grep -e '^[a-z]' | - grep -v -e "$EXCLUDE" | + grep -v -e "=[$EXCLUDE]" | cut -d' ' -f1) else echo "$# test cases from the command line" From 1597e8be5ae3918316b8f531bd105a8d326d02c5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 27 Mar 2014 14:19:01 +0000 Subject: [PATCH 016/266] Don't depend on test accepting == (not portable to /bin/sh). Copied from Perforce Change: 185048 ServerID: perforce.ravenbrook.com --- mps/tool/testrun.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/tool/testrun.sh b/mps/tool/testrun.sh index 303168cad63..35197dd879c 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -26,7 +26,7 @@ echo "Test directory: $TEST_DIR" # Determine which tests to run. TEST_CASE_DB=$(dirname -- "$0")/testcases.txt -if [ $# == 1 ]; then +if [ $# -eq 1 ]; then TEST_SUITE=$1 echo "Test suite: $TEST_SUITE" case $TEST_SUITE in From 693e3a462211ec174043aadfa8c9f4a9cd0f1326 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 27 Mar 2014 15:19:42 +0000 Subject: [PATCH 017/266] Test case database now notes which test cases use threads. New test suite "testansi" consists of test cases that run on the generic ("ANSI") platform. New target "ansi" builds the MPS with the CONFIG_PF_ANSI CONFIG_THREAD_SINGLE and CONFIG_PROTECTION_NONE settings. Build and test the "ansi" target as part of "make test" for the benefit of the buildbots (just Linux and FreeBSD for the moment). Copied from Perforce Change: 185050 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 7 ++- mps/code/comm.gmk | 3 +- mps/code/commpost.nmk | 4 +- mps/code/mps.xcodeproj/project.pbxproj | 70 ++++++++++++++++++++++++++ mps/tool/testcases.txt | 9 ++-- mps/tool/testrun.bat | 7 +-- mps/tool/testrun.sh | 7 +-- 7 files changed, 92 insertions(+), 15 deletions(-) diff --git a/mps/Makefile.in b/mps/Makefile.in index 960903ba43a..e77813f19d5 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -67,11 +67,14 @@ make-install-dirs: install: @INSTALL_TARGET@ -test-make-build: @BUILD_TARGET@ +test-make-build: + $(MAKE) clean + $(MAKE) $(TARGET_OPTS) VARIETY=hot CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE -DCONFIG_PROTECTION_NONE" testansi + $(MAKE) clean $(MAKE) $(TARGET_OPTS) testci test-xcode-build: - $(XCODEBUILD) -config Release -target testci $(XCODEBUILD) -config Debug -target testci + $(XCODEBUILD) -config Release -target testci test: @TEST_TARGET@ diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index 837b025e974..64ce520b560 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -284,8 +284,9 @@ all: $(ALL_TARGETS) # testrun = "smoke test", fast enough to run before every commit # 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 -TEST_SUITES=testrun testci testall +TEST_SUITES=testrun testci testall testansi $(addprefix $(PFM)/$(VARIETY)/,$(TEST_SUITES)): $(TEST_TARGETS) ../tool/testrun.sh "$(PFM)/$(VARIETY)" "$(notdir $@)" diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk index 46203a321a3..6c9966efe03 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/commpost.nmk @@ -53,10 +53,10 @@ variety: $(PFM)\$(VARIETY)\$(TARGET) !ENDIF !ENDIF -# testrun testci testall +# testrun testci testall testansi # Runs automated test cases. -testrun testci testall: $(TEST_TARGETS) +testrun testci testall testansi: $(TEST_TARGETS) !IFDEF VARIETY ..\tool\testrun.bat $(PFM) $(VARIETY) $@ !ELSE diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index 1c9f39ff0f1..cd178d5f855 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -31,6 +31,18 @@ name = testall; productName = testrun; }; + 2291B6E318E4754D0004B79C /* testansi */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 2291B6E718E4754D0004B79C /* Build configuration list for PBXAggregateTarget "testansi" */; + buildPhases = ( + 2291B6E618E4754D0004B79C /* ShellScript */, + ); + dependencies = ( + 2291B6E418E4754D0004B79C /* PBXTargetDependency */, + ); + name = testansi; + productName = testrun; + }; 22CDE8EF16E9E97D00366D0A /* testrun */ = { isa = PBXAggregateTarget; buildConfigurationList = 22CDE8F016E9E97E00366D0A /* Build configuration list for PBXAggregateTarget "testrun" */; @@ -407,6 +419,13 @@ remoteGlobalIDString = 2291A5C1175CAFCA001D4920; remoteInfo = expt825; }; + 2291B6E518E4754D0004B79C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3104AFF1156D37A0000A585A; + remoteInfo = all; + }; 22B2BC3818B643AD00C33E63 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; @@ -3286,6 +3305,7 @@ 22CDE8EF16E9E97D00366D0A /* testrun */, 225F0AFC18E4453A003F2183 /* testci */, 225F0B0418E44549003F2183 /* testall */, + 2291B6E318E4754D0004B79C /* testansi */, 31EEABFA156AAF9D00714D05 /* mps */, 3114A632156E94DB001E0AA3 /* abqtest */, 22FACEE018880983000FDBC1 /* airtest */, @@ -3365,6 +3385,20 @@ shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\""; showEnvVarsInLog = 0; }; + 2291B6E618E4754D0004B79C /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\""; + showEnvVarsInLog = 0; + }; 22CDE8F416E9E9D400366D0A /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -3938,6 +3972,11 @@ target = 2291A5C1175CAFCA001D4920 /* expt825 */; targetProxy = 2291A5E7175CB20E001D4920 /* PBXContainerItemProxy */; }; + 2291B6E418E4754D0004B79C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3104AFF1156D37A0000A585A /* all */; + targetProxy = 2291B6E518E4754D0004B79C /* PBXContainerItemProxy */; + }; 22B2BC3918B643AD00C33E63 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 31FCAE0917692403008C034C /* scheme */; @@ -4446,6 +4485,27 @@ }; name = Release; }; + 2291B6E818E4754D0004B79C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testall copy"; + }; + name = Debug; + }; + 2291B6E918E4754D0004B79C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testall copy"; + }; + name = Release; + }; + 2291B6EA18E4754D0004B79C /* RASH */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testall copy"; + }; + name = RASH; + }; 22B2BC3318B6434F00C33E63 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5652,6 +5712,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 2291B6E718E4754D0004B79C /* Build configuration list for PBXAggregateTarget "testansi" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2291B6E818E4754D0004B79C /* Debug */, + 2291B6E918E4754D0004B79C /* Release */, + 2291B6EA18E4754D0004B79C /* RASH */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 22B2BC3218B6434F00C33E63 /* Build configuration list for PBXNativeTarget "scheme-advanced" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/mps/tool/testcases.txt b/mps/tool/testcases.txt index 96d3a4d2cff..c60e79d8ccd 100644 --- a/mps/tool/testcases.txt +++ b/mps/tool/testcases.txt @@ -5,14 +5,14 @@ abqtest airtest amcss amcsshe -amcssth =B =X job003561, job003703 +amcssth =B =T =X job003561, job003703 amsss amssshe apss arenacv awlut awluthe -awlutth =X +awlutth =T =X btcv bttest =N interactive djbench =N benchmark @@ -25,7 +25,7 @@ fotest gcbench =N benchmark locbwcss lockcov -lockutw3 =W +lockutw3 =T =W locusss locv messtest @@ -40,7 +40,7 @@ segsmss steptest teletest =N interactive walkt0 -zcoll =B =L +zcoll =B =L job003658 zmess ============= ================ ========================================== @@ -50,5 +50,6 @@ Key to flags B -- known Bad L -- Long runtime N -- Not an automated test case + T -- multi-Threaded W -- Windows-only X -- Unix-only diff --git a/mps/tool/testrun.bat b/mps/tool/testrun.bat index 06f947a25e3..6b683762136 100755 --- a/mps/tool/testrun.bat +++ b/mps/tool/testrun.bat @@ -33,9 +33,10 @@ 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%"=="testrun" set EXCLUDE=LNX +if "%TESTSUITE%"=="testci" set EXCLUDE=BNX +if "%TESTSUITE%"=="testall" set EXCLUDE=NX +if "%TESTSUITE%"=="testansi" set EXCLUDE=LNTX @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 35197dd879c..f5d54699cae 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -30,9 +30,10 @@ 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" ;; + testrun) EXCLUDE="LNW" ;; + testci) EXCLUDE="BNW" ;; + testall) EXCLUDE="NW" ;; + testansi) EXCLUDE="LNTW" ;; *) echo "Test suite $TEST_SUITE not recognized." exit 1 ;; From ada625ef8bb586ae20ff35ad4f61c24d58e026c9 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 27 Mar 2014 15:38:39 +0000 Subject: [PATCH 018/266] Reduce busyness of the diff by restoring the order. Copied from Perforce Change: 185052 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 e77813f19d5..448a0219681 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -74,7 +74,7 @@ test-make-build: $(MAKE) $(TARGET_OPTS) testci test-xcode-build: - $(XCODEBUILD) -config Debug -target testci $(XCODEBUILD) -config Release -target testci + $(XCODEBUILD) -config Debug -target testci test: @TEST_TARGET@ From 5770143183d07c91ffddd9a87814ec1a3abd05a5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 27 Mar 2014 15:57:34 +0000 Subject: [PATCH 019/266] Remove comment from rb "the thread_single and protection_none build configs aren't regularly tested, though they might well be useful for embedded custom targets. should test them." -- this configuration is now tested by "make test" on the linux and freebsd platforms. Copied from Perforce Change: 185054 ServerID: perforce.ravenbrook.com --- mps/code/global.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mps/code/global.c b/mps/code/global.c index 0bf481cb136..2dfda251f91 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -509,10 +509,6 @@ Ring GlobalsRememberedSummaryRing(Globals global) /* ArenaEnter -- enter the state where you can look at the arena */ -/* TODO: The THREAD_SINGLE and PROTECTION_NONE build configs aren't regularly - tested, though they might well be useful for embedded custom targets. - Should test them. RB 2012-09-03 */ - #if defined(THREAD_SINGLE) && defined(PROTECTION_NONE) void (ArenaEnter)(Arena arena) { From 057dd6a22b4d99d0db3667b6dcd55940cbc82776 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 27 Mar 2014 17:47:15 +0000 Subject: [PATCH 020/266] Variable "base" no longer needed for passing to segnext, so remove it. Copied from Perforce Change: 185056 ServerID: perforce.ravenbrook.com --- mps/code/protan.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/mps/code/protan.c b/mps/code/protan.c index b9fb46e7062..86afa645e63 100644 --- a/mps/code/protan.c +++ b/mps/code/protan.c @@ -50,9 +50,7 @@ void ProtSync(Arena arena) synced = TRUE; if (SegFirst(&seg, arena)) { - Addr base; do { - base = SegBase(seg); if (SegPM(seg) != AccessSetEMPTY) { /* */ ShieldEnter(arena); TraceSegAccess(arena, seg, SegPM(seg)); From 67a99958636f13ab5fd787ad77e8aa42858fe328 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 27 Mar 2014 20:41:31 +0000 Subject: [PATCH 021/266] Mark amsss and amssshe as bad because of job001549. Copied from Perforce Change: 185061 ServerID: perforce.ravenbrook.com --- mps/tool/testcases.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/tool/testcases.txt b/mps/tool/testcases.txt index 147ea76d3f9..29ed3667809 100644 --- a/mps/tool/testcases.txt +++ b/mps/tool/testcases.txt @@ -6,8 +6,8 @@ airtest amcss amcsshe amcssth =B =T =X job003561, job003703 -amsss -amssshe +amsss =B job001549 +amssshe =B job001549 apss arenacv awlut From 6103d4aeb37960d16269ad05a2946de1d0496164 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 27 Mar 2014 20:42:12 +0000 Subject: [PATCH 022/266] Zcoll no longer bad. Copied from Perforce Change: 185062 ServerID: perforce.ravenbrook.com --- mps/tool/testcases.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/tool/testcases.txt b/mps/tool/testcases.txt index 29ed3667809..4d724705d63 100644 --- a/mps/tool/testcases.txt +++ b/mps/tool/testcases.txt @@ -40,7 +40,7 @@ segsmss steptest teletest =N interactive walkt0 -zcoll =L job003658 +zcoll =L zmess ============= ================ ========================================== From a2b3bf997e451862071ffe668b6882930cf7288b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 30 Mar 2014 18:10:33 +0100 Subject: [PATCH 023/266] Branching master to branch/2014-03-30/addrset. Copied from Perforce Change: 185093 ServerID: perforce.ravenbrook.com From 22fa48f5966255f33a6c517be45dd6a57cf7ebe1 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 31 Mar 2014 20:50:42 +0100 Subject: [PATCH 024/266] Uniquify the test log files so that you can run the same test case multiple times and still capture the output from each run. Copied from Perforce Change: 185114 ServerID: perforce.ravenbrook.com --- mps/tool/testrun.bat | 5 +++-- mps/tool/testrun.sh | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mps/tool/testrun.bat b/mps/tool/testrun.bat index 6b683762136..5496ef5afea 100755 --- a/mps/tool/testrun.bat +++ b/mps/tool/testrun.bat @@ -68,13 +68,14 @@ if "%FAIL_COUNT%"=="0" ( :run_test set /a TEST_COUNT=%TEST_COUNT%+1 +set LOGTEST=%LOGDIR%\%TEST_COUNT%-%1 echo Running %1 -%PFM%\%VARIETY%\%1 > %LOGDIR%\%1 +%PFM%\%VARIETY%\%1 > %LOGTEST% if "%errorlevel%"=="0" ( set /a PASS_COUNT=%PASS_COUNT%+1 ) else ( echo %SEPARATOR%%SEPARATOR% - type %LOGDIR%\%1 + type %LOGTEST% echo %SEPARATOR%%SEPARATOR% set /a FAIL_COUNT=%FAIL_COUNT%+1 ) diff --git a/mps/tool/testrun.sh b/mps/tool/testrun.sh index f5d54699cae..87559faf1d4 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -52,7 +52,7 @@ PASS_COUNT=0 FAIL_COUNT=0 for TESTCASE in $TEST_CASES; do TEST="$(basename -- "$TESTCASE")" - LOGTEST="$LOGDIR/$TEST" + LOGTEST="$LOGDIR/$TEST_COUNT-$TEST" echo "Running $TEST" TEST_COUNT=$(expr $TEST_COUNT + 1) if "$TEST_DIR/$TESTCASE" > "$LOGTEST" 2>&1; then From 042f9c5f14cc0fab6d4886e2d69e066e18e9f022 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 1 Apr 2014 19:51:55 +0100 Subject: [PATCH 025/266] First pass at implementation of lands (collections of address ranges). 100% boilerplate! Copied from Perforce Change: 185131 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 135 ++++++++--------- mps/code/cbs.c | 329 ++++++++++++++++++++++++----------------- mps/code/cbs.h | 36 +---- mps/code/eventdef.h | 6 +- mps/code/fbmtest.c | 31 ++-- mps/code/fotest.c | 8 +- mps/code/freelist.c | 15 +- mps/code/freelist.h | 3 +- mps/code/land.c | 348 ++++++++++++++++++++++++++++++++++++++++++++ mps/code/locus.c | 1 + mps/code/mpm.h | 28 +++- mps/code/mpmst.h | 54 ++++++- mps/code/mpmtypes.h | 21 ++- mps/code/mps.c | 1 + mps/code/poolmv2.c | 44 +++--- mps/code/poolmvff.c | 32 ++-- mps/code/range.h | 2 - mps/code/tract.c | 22 +-- 18 files changed, 800 insertions(+), 316 deletions(-) create mode 100644 mps/code/land.c diff --git a/mps/code/arena.c b/mps/code/arena.c index d5833c65441..b63ef84748a 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -19,7 +19,7 @@ SRCID(arena, "$Id$"); #define ArenaControlPool(arena) MV2Pool(&(arena)->controlPoolStruct) #define ArenaCBSBlockPool(arena) (&(arena)->freeCBSBlockPoolStruct.poolStruct) -#define ArenaFreeCBS(arena) (&(arena)->freeCBSStruct) +#define ArenaFreeLand(arena) ((Land)&(arena)->freeLandStruct) /* Forward declarations */ @@ -153,9 +153,9 @@ Bool ArenaCheck(Arena arena) CHECKL(LocusCheck(arena)); - CHECKL(BoolCheck(arena->hasFreeCBS)); - if (arena->hasFreeCBS) - CHECKL(CBSCheck(ArenaFreeCBS(arena))); + CHECKL(BoolCheck(arena->hasFreeLand)); + if (arena->hasFreeLand) + CHECKL(LandCheck(ArenaFreeLand(arena))); return TRUE; } @@ -198,7 +198,7 @@ Res ArenaInit(Arena arena, ArenaClass class, Align alignment, ArgList args) arena->poolReady = FALSE; /* */ arena->lastTract = NULL; arena->lastTractBase = NULL; - arena->hasFreeCBS = FALSE; + arena->hasFreeLand = FALSE; arena->freeZones = ZoneSetUNIV; arena->zoned = zoned; @@ -214,11 +214,12 @@ Res ArenaInit(Arena arena, ArenaClass class, Align alignment, ArgList args) goto failGlobalsInit; 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 CBS is used. */ + handled where the Land is used. */ MPS_ARGS_BEGIN(piArgs) { MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSBlockStruct)); @@ -231,18 +232,19 @@ Res ArenaInit(Arena arena, ArenaClass class, Align alignment, ArgList args) if (res != ResOK) goto failMFSInit; - /* Initialise the freeCBS. */ - MPS_ARGS_BEGIN(cbsiArgs) { - MPS_ARGS_ADD(cbsiArgs, CBSBlockPool, ArenaCBSBlockPool(arena)); - MPS_ARGS_DONE(cbsiArgs); - res = CBSInit(ArenaFreeCBS(arena), arena, arena, alignment, - /* fastFind */ TRUE, arena->zoned, cbsiArgs); - } MPS_ARGS_END(cbsiArgs); + /* Initialise the freeLand. */ + MPS_ARGS_BEGIN(landiArgs) { + MPS_ARGS_ADD(landiArgs, CBSBlockPool, ArenaCBSBlockPool(arena)); + MPS_ARGS_ADD(landiArgs, CBSFastFind, TRUE); + MPS_ARGS_ADD(landiArgs, CBSZoned, arena->zoned); + MPS_ARGS_DONE(landiArgs); + res = LandInit(ArenaFreeLand(arena), CBSLandClassGet(), arena, alignment, arena, landiArgs); + } MPS_ARGS_END(landiArgs); AVER(res == ResOK); /* no allocation, no failure expected */ if (res != ResOK) - goto failCBSInit; - /* Note that although freeCBS is initialised, it doesn't have any memory - for its blocks, so hasFreeCBS remains FALSE until later. */ + 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); @@ -253,8 +255,8 @@ Res ArenaInit(Arena arena, ArenaClass class, Align alignment, ArgList args) return ResOK; failReservoirInit: - CBSFinish(ArenaFreeCBS(arena)); -failCBSInit: + LandFinish(ArenaFreeLand(arena)); +failLandInit: PoolFinish(ArenaCBSBlockPool(arena)); failMFSInit: GlobalsFinish(ArenaGlobals(arena)); @@ -304,15 +306,15 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args) goto failStripeSize; } - /* With the primary chunk initialised we can add page memory to the freeCBS + /* With the primary chunk initialised we can add page memory to the freeLand that describes the free address space in the primary chunk. */ - arena->hasFreeCBS = TRUE; - res = ArenaFreeCBSInsert(arena, + arena->hasFreeLand = TRUE; + res = ArenaFreeLandInsert(arena, PageIndexBase(arena->primary, arena->primary->allocBase), arena->primary->limit); if (res != ResOK) - goto failPrimaryCBS; + goto failPrimaryLand; res = ControlInit(arena); if (res != ResOK) @@ -329,7 +331,7 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args) failGlobalsCompleteCreate: ControlFinish(arena); failControlInit: -failPrimaryCBS: +failPrimaryLand: failStripeSize: (*class->finish)(arena); failInit: @@ -378,11 +380,11 @@ void ArenaDestroy(Arena arena) arena->poolReady = FALSE; ControlFinish(arena); - /* We must tear down the freeCBS before the chunks, because pages + /* We must tear down the freeLand before the chunks, because pages containing CBS blocks might be allocated in those chunks. */ - AVER(arena->hasFreeCBS); - arena->hasFreeCBS = FALSE; - CBSFinish(ArenaFreeCBS(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 ZonedCBS. */ @@ -601,9 +603,10 @@ Res ControlDescribe(Arena arena, mps_lib_FILE *stream) /* arenaAllocPage -- allocate one page from the arena * - * This is a primitive allocator used to allocate pages for the arena CBS. - * It is called rarely and can use a simple search. It may not use the - * CBS or any pool, because it is used as part of the bootstrap. + * 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. */ static Res arenaAllocPageInChunk(Addr *baseReturn, Chunk chunk, Pool pool) @@ -685,7 +688,7 @@ static Res arenaExtendCBSBlockPool(Range pageRangeReturn, Arena arena) return ResOK; } -/* arenaExcludePage -- exclude CBS block pool's page from CBSs +/* arenaExcludePage -- exclude CBS block pool's page from Land * * Exclude the page we specially allocated for the CBS block pool * so that it doesn't get reallocated. @@ -696,20 +699,20 @@ static void arenaExcludePage(Arena arena, Range pageRange) RangeStruct oldRange; Res res; - res = CBSDelete(&oldRange, ArenaFreeCBS(arena), pageRange); - AVER(res == ResOK); /* we just gave memory to the CBSs */ + res = LandDelete(&oldRange, ArenaFreeLand(arena), pageRange); + AVER(res == ResOK); /* we just gave memory to the Land */ } -/* arenaCBSInsert -- add a block to an arena CBS, extending pool if necessary +/* arenaLandInsert -- add a block to an arena Land, extending pool if necessary * - * The arena's CBSs can't get memory in the usual way because they are used + * The arena's Land can't get memory in the usual way because they are used * in the basic allocator, so we allocate pages specially. * * Only fails if it can't get a page for the block pool. */ -static Res arenaCBSInsert(Range rangeReturn, Arena arena, Range range) +static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range) { Res res; @@ -717,17 +720,17 @@ static Res arenaCBSInsert(Range rangeReturn, Arena arena, Range range) AVERT(Arena, arena); AVERT(Range, range); - res = CBSInsert(rangeReturn, ArenaFreeCBS(arena), range); + res = LandInsert(rangeReturn, ArenaFreeLand(arena), range); - if (res == ResLIMIT) { /* freeCBS MFS pool ran out of blocks */ + if (res == ResLIMIT) { /* freeLand MFS pool ran out of blocks */ RangeStruct pageRange; res = arenaExtendCBSBlockPool(&pageRange, arena); if (res != ResOK) return res; /* .insert.exclude: Must insert before exclude so that we can bootstrap when the zoned CBS is empty. */ - res = CBSInsert(rangeReturn, ArenaFreeCBS(arena), range); - AVER(res == ResOK); /* we just gave memory to the CBSs */ + res = LandInsert(rangeReturn, ArenaFreeLand(arena), range); + AVER(res == ResOK); /* we just gave memory to the Land */ arenaExcludePage(arena, &pageRange); } @@ -735,16 +738,16 @@ static Res arenaCBSInsert(Range rangeReturn, Arena arena, Range range) } -/* ArenaFreeCBSInsert -- add a block to arena CBS, maybe stealing memory +/* ArenaFreeLandInsert -- add a block to arena Land, maybe stealing memory * - * See arenaCBSInsert. This function may only be applied to mapped pages - * and may steal them to store CBS nodes if it's unable to allocate + * 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 nodes. * * IMPORTANT: May update rangeIO. */ -static void arenaCBSInsertSteal(Range rangeReturn, Arena arena, Range rangeIO) +static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO) { Res res; @@ -752,7 +755,7 @@ static void arenaCBSInsertSteal(Range rangeReturn, Arena arena, Range rangeIO) AVERT(Arena, arena); AVERT(Range, rangeIO); - res = arenaCBSInsert(rangeReturn, arena, rangeIO); + res = arenaLandInsert(rangeReturn, arena, rangeIO); if (res != ResOK) { Addr pageBase; @@ -773,22 +776,22 @@ static void arenaCBSInsertSteal(Range rangeReturn, Arena arena, Range rangeIO) MFSExtend(ArenaCBSBlockPool(arena), pageBase, ArenaAlign(arena)); /* Try again. */ - res = CBSInsert(rangeReturn, ArenaFreeCBS(arena), rangeIO); - AVER(res == ResOK); /* we just gave memory to the CBS */ + res = LandInsert(rangeReturn, ArenaFreeLand(arena), rangeIO); + AVER(res == ResOK); /* we just gave memory to the Land */ } - AVER(res == ResOK); /* not expecting other kinds of error from the CBS */ + AVER(res == ResOK); /* not expecting other kinds of error from the Land */ } -/* ArenaFreeCBSInsert -- add block to free CBS, extending pool if necessary +/* ArenaFreeLandInsert -- add block to free Land, extending pool if necessary * * The inserted block of address space may not abut any existing block. * This restriction ensures that we don't coalesce chunks and allocate * object across the boundary, preventing chunk deletion. */ -Res ArenaFreeCBSInsert(Arena arena, Addr base, Addr limit) +Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit) { RangeStruct range, oldRange; Res res; @@ -796,7 +799,7 @@ Res ArenaFreeCBSInsert(Arena arena, Addr base, Addr limit) AVERT(Arena, arena); RangeInit(&range, base, limit); - res = arenaCBSInsert(&oldRange, arena, &range); + res = arenaLandInsert(&oldRange, arena, &range); if (res != ResOK) return res; @@ -809,7 +812,7 @@ Res ArenaFreeCBSInsert(Arena arena, Addr base, Addr limit) } -/* ArenaFreeCBSDelete -- remove a block from free CBS, extending pool if necessary +/* ArenaFreeLandDelete -- remove a block from free Land, extending pool if necessary * * This is called from ChunkFinish in order to remove address space from * the arena. @@ -820,13 +823,13 @@ Res ArenaFreeCBSInsert(Arena arena, Addr base, Addr limit) * so we can't test that path. */ -void ArenaFreeCBSDelete(Arena arena, Addr base, Addr limit) +void ArenaFreeLandDelete(Arena arena, Addr base, Addr limit) { RangeStruct range, oldRange; Res res; RangeInit(&range, base, limit); - res = CBSDelete(&oldRange, ArenaFreeCBS(arena), &range); + res = LandDelete(&oldRange, ArenaFreeLand(arena), &range); /* Shouldn't be any other kind of failure because we were only deleting a non-coalesced block. See .chunk.no-coalesce and @@ -835,7 +838,7 @@ void ArenaFreeCBSDelete(Arena arena, Addr base, Addr limit) } -static Res arenaAllocFromCBS(Tract *tractReturn, ZoneSet zones, Bool high, +static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high, Size size, Pool pool) { Arena arena; @@ -858,7 +861,7 @@ static Res arenaAllocFromCBS(Tract *tractReturn, ZoneSet zones, Bool high, /* Step 1. Find a range of address space. */ - res = CBSFindInZones(&range, &oldRange, ArenaFreeCBS(arena), + res = LandFindInZones(&range, &oldRange, ArenaFreeLand(arena), size, zones, high); if (res == ResLIMIT) { /* found block, but couldn't store info */ @@ -867,7 +870,7 @@ static Res arenaAllocFromCBS(Tract *tractReturn, ZoneSet zones, Bool high, if (res != ResOK) /* disastrously short on memory */ return res; arenaExcludePage(arena, &pageRange); - res = CBSFindInZones(&range, &oldRange, ArenaFreeCBS(arena), + res = LandFindInZones(&range, &oldRange, ArenaFreeLand(arena), size, zones, high); AVER(res != ResLIMIT); } @@ -901,7 +904,7 @@ static Res arenaAllocFromCBS(Tract *tractReturn, ZoneSet zones, Bool high, failMark: { - Res insertRes = arenaCBSInsert(&oldRange, arena, &range); + Res insertRes = arenaLandInsert(&oldRange, arena, &range); AVER(insertRes == ResOK); /* We only just deleted it. */ /* If the insert does fail, we lose some address space permanently. */ } @@ -942,10 +945,10 @@ static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, SegPref pref, } } - /* Plan A: allocate from the free CBS 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 = arenaAllocFromCBS(&tract, zones, pref->high, size, pool); + res = arenaAllocFromLand(&tract, zones, pref->high, size, pool); if (res == ResOK) goto found; } @@ -957,7 +960,7 @@ static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, SegPref pref, See also job003384. */ moreZones = ZoneSetUnion(pref->zones, ZoneSetDiff(arena->freeZones, pref->avoid)); if (moreZones != zones) { - res = arenaAllocFromCBS(&tract, moreZones, pref->high, size, pool); + res = arenaAllocFromLand(&tract, moreZones, pref->high, size, pool); if (res == ResOK) goto found; } @@ -968,13 +971,13 @@ static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, SegPref pref, if (res != ResOK) return res; if (zones != ZoneSetEMPTY) { - res = arenaAllocFromCBS(&tract, zones, pref->high, size, pool); + 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 = arenaAllocFromCBS(&tract, moreZones, pref->high, size, pool); + res = arenaAllocFromLand(&tract, moreZones, pref->high, size, pool); if (res == ResOK) goto found; } @@ -986,7 +989,7 @@ static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, SegPref pref, /* TODO: log an event for this */ evenMoreZones = ZoneSetDiff(ZoneSetUNIV, pref->avoid); if (evenMoreZones != moreZones) { - res = arenaAllocFromCBS(&tract, evenMoreZones, pref->high, size, pool); + res = arenaAllocFromLand(&tract, evenMoreZones, pref->high, size, pool); if (res == ResOK) goto found; } @@ -995,7 +998,7 @@ static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, SegPref pref, common ambiguous bit patterns pin them down, causing the zone check to give even more false positives permanently, and possibly retaining garbage indefinitely. */ - res = arenaAllocFromCBS(&tract, ZoneSetUNIV, pref->high, size, pool); + res = arenaAllocFromLand(&tract, ZoneSetUNIV, pref->high, size, pool); if (res == ResOK) goto found; @@ -1113,7 +1116,7 @@ void ArenaFree(Addr base, Size size, Pool pool) RangeInit(&range, base, limit); - arenaCBSInsertSteal(&oldRange, arena, &range); /* may update range */ + arenaLandInsertSteal(&oldRange, arena, &range); /* may update range */ (*arena->class->free)(RangeBase(&range), RangeSize(&range), pool); diff --git a/mps/code/cbs.c b/mps/code/cbs.c index c57c322d267..bf02c9d7737 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -26,6 +26,7 @@ SRCID(cbs, "$Id$"); #define CBSBlockSize(block) AddrOffset((block)->base, (block)->limit) +#define cbsOfLand(land) ((CBS)(land)) #define cbsSplay(cbs) (&((cbs)->splayTreeStruct)) #define cbsOfSplay(_splay) PARENT(CBSStruct, splayTreeStruct, _splay) #define cbsBlockTree(block) (&((block)->treeStruct)) @@ -65,16 +66,14 @@ Bool CBSCheck(CBS cbs) { /* See .enter-leave.simple. */ CHECKS(CBS, cbs); - CHECKL(cbs != NULL); + CHECKL(LandCheck(&cbs->landStruct)); CHECKD(SplayTree, cbsSplay(cbs)); /* nothing to check about treeSize */ CHECKD(Pool, cbs->blockPool); - CHECKU(Arena, cbs->arena); CHECKL(BoolCheck(cbs->fastFind)); CHECKL(BoolCheck(cbs->inCBS)); CHECKL(BoolCheck(cbs->ownPool)); CHECKL(BoolCheck(cbs->zoned)); - /* No MeterCheck */ return TRUE; } @@ -212,7 +211,7 @@ static void cbsUpdateZonedNode(SplayTree splay, Tree tree) cbsUpdateNode(splay, tree); block = cbsBlockOfTree(tree); - arena = cbsOfSplay(splay)->arena; + arena = cbsOfSplay(splay)->landStruct.arena; zones = ZoneSetOfRange(arena, CBSBlockBase(block), CBSBlockLimit(block)); if (TreeHasLeft(tree)) @@ -225,29 +224,34 @@ static void cbsUpdateZonedNode(SplayTree splay, Tree tree) } -/* CBSInit -- Initialise a CBS structure +/* cbsInit -- Initialise a CBS structure * * See . */ ARG_DEFINE_KEY(cbs_extend_by, Size); ARG_DEFINE_KEY(cbs_block_pool, Pool); +ARG_DEFINE_KEY(cbs_fast_find, Bool); +ARG_DEFINE_KEY(cbs_zoned, Bool); -Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment, - Bool fastFind, Bool zoned, ArgList args) +static Res cbsInit(Land land, ArgList args) { + CBS cbs; + LandClass super; Size extendBy = CBS_EXTEND_BY_DEFAULT; Bool extendSelf = TRUE; + Bool fastFind = FALSE; + Bool zoned = FALSE; ArgStruct arg; Res res; Pool blockPool = NULL; SplayUpdateNodeMethod update; - AVERT(Arena, arena); - AVER(cbs != NULL); - AVER(AlignCheck(alignment)); - AVER(BoolCheck(fastFind)); - AVER(BoolCheck(zoned)); + AVERT(Land, land); + super = LAND_SUPERCLASS(CBSLandClass); + res = (*super->init)(land, args); + if (res != ResOK) + return res; if (ArgPick(&arg, args, CBSBlockPool)) blockPool = arg.val.pool; @@ -255,6 +259,10 @@ Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment, extendBy = arg.val.size; if (ArgPick(&arg, args, MFSExtendSelf)) extendSelf = arg.val.b; + if (ArgPick(&arg, args, CBSFastFind)) + fastFind = arg.val.b; + if (ArgPick(&arg, args, CBSZoned)) + zoned = arg.val.b; update = SplayTrivUpdate; if (fastFind) @@ -264,6 +272,7 @@ Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment, update = cbsUpdateZonedNode; } + cbs = cbsOfLand(land); SplayTreeInit(cbsSplay(cbs), cbsCompare, cbsKey, update); if (blockPool != NULL) { @@ -274,7 +283,7 @@ Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment, MPS_ARGS_ADD(pcArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSBlockStruct)); MPS_ARGS_ADD(pcArgs, MPS_KEY_EXTEND_BY, extendBy); MPS_ARGS_ADD(pcArgs, MFSExtendSelf, extendSelf); - res = PoolCreate(&cbs->blockPool, arena, PoolClassMFS(), pcArgs); + res = PoolCreate(&cbs->blockPool, LandArena(land), PoolClassMFS(), pcArgs); } MPS_ARGS_END(pcArgs); if (res != ResOK) return res; @@ -282,10 +291,8 @@ Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment, } cbs->treeSize = 0; - cbs->arena = arena; cbs->fastFind = fastFind; cbs->zoned = zoned; - cbs->alignment = alignment; cbs->inCBS = TRUE; METER_INIT(cbs->treeSearch, "size of tree", (void *)cbs); @@ -293,7 +300,6 @@ Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment, cbs->sig = CBSSig; AVERT(CBS, cbs); - EVENT2(CBSInit, cbs, owner); cbsLeave(cbs); return ResOK; } @@ -304,8 +310,12 @@ Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment, * See . */ -void CBSFinish(CBS cbs) +static void cbsFinish(Land land) { + CBS cbs; + + AVERT(Land, land); + cbs = cbsOfLand(land); AVERT(CBS, cbs); cbsEnter(cbs); @@ -427,8 +437,9 @@ static void cbsBlockInsert(CBS cbs, CBSBlock block) /* cbsInsertIntoTree -- Insert a range into the tree */ -static Res cbsInsertIntoTree(Range rangeReturn, CBS cbs, Range range) +static Res cbsInsertIntoTree(Range rangeReturn, Land land, Range range) { + CBS cbs; Bool b; Res res; Addr base, limit, newBase, newLimit; @@ -438,10 +449,11 @@ static Res cbsInsertIntoTree(Range rangeReturn, CBS cbs, Range range) Size oldSize; AVER(rangeReturn != NULL); - AVERT(CBS, cbs); + AVERT(Land, land); AVERT(Range, range); - AVER(RangeIsAligned(range, cbs->alignment)); + AVER(RangeIsAligned(range, LandAlignment(land))); + cbs = cbsOfLand(land); base = RangeBase(range); limit = RangeLimit(range); @@ -522,7 +534,7 @@ static Res cbsInsertIntoTree(Range rangeReturn, CBS cbs, Range range) } -/* CBSInsert -- Insert a range into the CBS +/* cbsInsert -- Insert a range into the CBS * * See . * @@ -530,18 +542,21 @@ static Res cbsInsertIntoTree(Range rangeReturn, CBS cbs, Range range) * abut an existing range. */ -Res CBSInsert(Range rangeReturn, CBS cbs, Range range) +static Res cbsInsert(Range rangeReturn, Land land, Range range) { + CBS cbs; Res res; + AVERT(Land, land); + cbs = cbsOfLand(land); AVERT(CBS, cbs); cbsEnter(cbs); AVER(rangeReturn != NULL); AVERT(Range, range); - AVER(RangeIsAligned(range, cbs->alignment)); + AVER(RangeIsAligned(range, LandAlignment(land))); - res = cbsInsertIntoTree(rangeReturn, cbs, range); + res = cbsInsertIntoTree(rangeReturn, land, range); cbsLeave(cbs); return res; @@ -550,18 +565,20 @@ Res CBSInsert(Range rangeReturn, CBS cbs, Range range) /* cbsDeleteFromTree -- delete blocks from the tree */ -static Res cbsDeleteFromTree(Range rangeReturn, CBS cbs, Range range) +static Res cbsDeleteFromTree(Range rangeReturn, Land land, Range range) { + CBS cbs; Res res; CBSBlock cbsBlock; Tree tree; Addr base, limit, oldBase, oldLimit; Size oldSize; + AVERT(Land, land); + cbs = cbsOfLand(land); AVER(rangeReturn != NULL); - AVERT(CBS, cbs); AVERT(Range, range); - AVER(RangeIsAligned(range, cbs->alignment)); + AVER(RangeIsAligned(range, LandAlignment(land))); base = RangeBase(range); limit = RangeLimit(range); @@ -626,7 +643,7 @@ static Res cbsDeleteFromTree(Range rangeReturn, CBS cbs, Range range) } -/* CBSDelete -- Remove a range from a CBS +/* cbsDelete -- Remove a range from a CBS * * See . * @@ -634,18 +651,21 @@ static Res cbsDeleteFromTree(Range rangeReturn, CBS cbs, Range range) * an existing range. */ -Res CBSDelete(Range rangeReturn, CBS cbs, Range range) +static Res cbsDelete(Range rangeReturn, Land land, Range range) { - Res res; + CBS cbs; + Res res; + AVERT(Land, land); + cbs = cbsOfLand(land); AVERT(CBS, cbs); cbsEnter(cbs); AVER(rangeReturn != NULL); AVERT(Range, range); - AVER(RangeIsAligned(range, cbs->alignment)); + AVER(RangeIsAligned(range, LandAlignment(land))); - res = cbsDeleteFromTree(rangeReturn, cbs, range); + res = cbsDeleteFromTree(rangeReturn, land, range); cbsLeave(cbs); return res; @@ -683,7 +703,7 @@ static Res cbsSplayNodeDescribe(Tree tree, mps_lib_FILE *stream) } -/* CBSIterate -- iterate over all blocks in CBS +/* cbsIterate -- iterate over all blocks in CBS * * Applies a visitor to all isolated contiguous ranges in a CBS. * It receives a pointer, ``Size`` closure pair to pass on to the @@ -699,8 +719,8 @@ static Res cbsSplayNodeDescribe(Tree tree, mps_lib_FILE *stream) */ typedef struct CBSIterateClosure { - CBS cbs; - CBSVisitor iterate; + Land land; + LandVisitor iterate; void *closureP; Size closureS; } CBSIterateClosure; @@ -710,24 +730,28 @@ static Bool cbsIterateVisit(Tree tree, void *closureP, Size closureS) CBSIterateClosure *closure = closureP; RangeStruct range; CBSBlock cbsBlock; - CBS cbs = closure->cbs; + Land land = closure->land; + CBS cbs = cbsOfLand(land); UNUSED(closureS); cbsBlock = cbsBlockOfTree(tree); RangeInit(&range, CBSBlockBase(cbsBlock), CBSBlockLimit(cbsBlock)); - if (!closure->iterate(cbs, &range, closure->closureP, closure->closureS)) + if (!closure->iterate(land, &range, closure->closureP, closure->closureS)) return FALSE; METER_ACC(cbs->treeSearch, cbs->treeSize); return TRUE; } -void CBSIterate(CBS cbs, CBSVisitor visitor, - void *closureP, Size closureS) +static void cbsIterate(Land land, LandVisitor visitor, + void *closureP, Size closureS) { + CBS cbs; SplayTree splay; CBSIterateClosure closure; + AVERT(Land, land); + cbs = cbsOfLand(land); AVERT(CBS, cbs); cbsEnter(cbs); AVER(FUNCHECK(visitor)); @@ -737,7 +761,7 @@ void CBSIterate(CBS cbs, CBSVisitor visitor, /* searches and meter it. */ METER_ACC(cbs->treeSearch, cbs->treeSize); - closure.cbs = cbs; + closure.land = land; closure.iterate = visitor; closure.closureP = closureP; closure.closureS = closureS; @@ -766,7 +790,7 @@ Bool FindDeleteCheck(FindDelete findDelete) /* cbsFindDeleteRange -- delete appropriate range of block found */ static void cbsFindDeleteRange(Range rangeReturn, Range oldRangeReturn, - CBS cbs, Range range, Size size, + Land land, Range range, Size size, FindDelete findDelete) { Bool callDelete = TRUE; @@ -774,11 +798,11 @@ static void cbsFindDeleteRange(Range rangeReturn, Range oldRangeReturn, AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); - AVERT(CBS, cbs); + AVERT(Land, land); AVERT(Range, range); - AVER(RangeIsAligned(range, cbs->alignment)); + AVER(RangeIsAligned(range, LandAlignment(land))); AVER(size > 0); - AVER(SizeIsAligned(size, cbs->alignment)); + AVER(SizeIsAligned(size, LandAlignment(land))); AVER(RangeSize(range) >= size); AVERT(FindDelete, findDelete); @@ -812,7 +836,7 @@ static void cbsFindDeleteRange(Range rangeReturn, Range oldRangeReturn, if (callDelete) { Res res; - res = cbsDeleteFromTree(oldRangeReturn, cbs, rangeReturn); + res = cbsDeleteFromTree(oldRangeReturn, land, rangeReturn); /* Can't have run out of memory, because all our callers pass in blocks that were just found in the tree, and we only deleted from one end of the block, so cbsDeleteFromTree did not @@ -824,19 +848,22 @@ static void cbsFindDeleteRange(Range rangeReturn, Range oldRangeReturn, /* CBSFindFirst -- find the first block of at least the given size */ -Bool CBSFindFirst(Range rangeReturn, Range oldRangeReturn, - CBS cbs, Size size, FindDelete findDelete) +static Bool cbsFindFirst(Range rangeReturn, Range oldRangeReturn, + Land land, Size size, FindDelete findDelete) { + CBS cbs; Bool found; Tree tree; + AVERT(Land, land); + cbs = cbsOfLand(land); AVERT(CBS, cbs); cbsEnter(cbs); AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); AVER(size > 0); - AVER(SizeIsAligned(size, cbs->alignment)); + AVER(SizeIsAligned(size, LandAlignment(land))); AVER(cbs->fastFind); AVERT(FindDelete, findDelete); @@ -850,7 +877,7 @@ Bool CBSFindFirst(Range rangeReturn, Range oldRangeReturn, AVER(CBSBlockSize(block) >= size); RangeInit(&range, CBSBlockBase(block), CBSBlockLimit(block)); AVER(RangeSize(&range) >= size); - cbsFindDeleteRange(rangeReturn, oldRangeReturn, cbs, &range, + cbsFindDeleteRange(rangeReturn, oldRangeReturn, land, &range, size, findDelete); } @@ -858,8 +885,10 @@ Bool CBSFindFirst(Range rangeReturn, Range oldRangeReturn, return found; } -/* CBSFindFirstInZones -- find the first block of at least the given size - that lies entirely within a zone set */ +/* cbsFindInZones -- find a block of at least the given size that lies + * entirely within a zone set. (The first such block, if high is + * FALSE, or the last, if high is TRUE.) + */ typedef struct cbsTestNodeInZonesClosureStruct { Size size; @@ -902,90 +931,25 @@ static Bool cbsTestTreeInZones(SplayTree splay, Tree tree, ZoneSetInter(block->zones, closure->zoneSet) != ZoneSetEMPTY; } -Res CBSFindInZones(Range rangeReturn, Range oldRangeReturn, - CBS cbs, Size size, - ZoneSet zoneSet, Bool high) -{ - Tree tree; - cbsTestNodeInZonesClosureStruct closure; - Res res; - CBSFindMethod cbsFind; - SplayFindMethod splayFind; - - AVER(rangeReturn != NULL); - AVER(oldRangeReturn != NULL); - AVERT(CBS, cbs); - /* AVER(ZoneSetCheck(zoneSet)); */ - AVER(BoolCheck(high)); - - cbsFind = high ? CBSFindLast : CBSFindFirst; - splayFind = high ? SplayFindLast : SplayFindFirst; - - if (zoneSet == ZoneSetEMPTY) - return ResFAIL; - if (zoneSet == ZoneSetUNIV) { - FindDelete fd = high ? FindDeleteHIGH : FindDeleteLOW; - if (cbsFind(rangeReturn, oldRangeReturn, cbs, size, fd)) - return ResOK; - else - return ResFAIL; - } - if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(cbs->arena)) - return ResFAIL; - - /* It would be nice if there were a neat way to eliminate all runs of - zones in zoneSet too small for size.*/ - - cbsEnter(cbs); - - closure.arena = cbs->arena; - closure.zoneSet = zoneSet; - closure.size = size; - closure.high = high; - if (splayFind(&tree, cbsSplay(cbs), - cbsTestNodeInZones, - cbsTestTreeInZones, - &closure, sizeof(closure))) { - CBSBlock block = cbsBlockOfTree(tree); - RangeStruct rangeStruct, oldRangeStruct; - - AVER(CBSBlockBase(block) <= closure.base); - AVER(AddrOffset(closure.base, closure.limit) >= size); - AVER(ZoneSetSub(ZoneSetOfRange(cbs->arena, closure.base, closure.limit), zoneSet)); - AVER(closure.limit <= CBSBlockLimit(block)); - - if (!high) - RangeInit(&rangeStruct, closure.base, AddrAdd(closure.base, size)); - else - RangeInit(&rangeStruct, AddrSub(closure.limit, size), closure.limit); - res = cbsDeleteFromTree(&oldRangeStruct, cbs, &rangeStruct); - if (res == ResOK) { /* enough memory to split block */ - RangeCopy(rangeReturn, &rangeStruct); - RangeCopy(oldRangeReturn, &oldRangeStruct); - } - } else - res = ResFAIL; - - cbsLeave(cbs); - return res; -} - - -/* CBSFindLast -- find the last block of at least the given size */ - -Bool CBSFindLast(Range rangeReturn, Range oldRangeReturn, - CBS cbs, Size size, FindDelete findDelete) + +/* cbsFindLast -- find the last block of at least the given size */ + +static Bool cbsFindLast(Range rangeReturn, Range oldRangeReturn, + Land land, Size size, FindDelete findDelete) { + CBS cbs; Bool found; Tree tree; + AVERT(Land, land); + cbs = cbsOfLand(land); AVERT(CBS, cbs); cbsEnter(cbs); AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); AVER(size > 0); - AVER(SizeIsAligned(size, cbs->alignment)); + AVER(SizeIsAligned(size, LandAlignment(land))); AVER(cbs->fastFind); AVERT(FindDelete, findDelete); @@ -999,7 +963,7 @@ Bool CBSFindLast(Range rangeReturn, Range oldRangeReturn, AVER(CBSBlockSize(block) >= size); RangeInit(&range, CBSBlockBase(block), CBSBlockLimit(block)); AVER(RangeSize(&range) >= size); - cbsFindDeleteRange(rangeReturn, oldRangeReturn, cbs, &range, + cbsFindDeleteRange(rangeReturn, oldRangeReturn, land, &range, size, findDelete); } @@ -1008,13 +972,16 @@ Bool CBSFindLast(Range rangeReturn, Range oldRangeReturn, } -/* CBSFindLargest -- find the largest block in the CBS */ +/* cbsFindLargest -- find the largest block in the CBS */ -Bool CBSFindLargest(Range rangeReturn, Range oldRangeReturn, - CBS cbs, Size size, FindDelete findDelete) +static Bool cbsFindLargest(Range rangeReturn, Range oldRangeReturn, + Land land, Size size, FindDelete findDelete) { + CBS cbs; Bool found = FALSE; + AVERT(Land, land); + cbs = cbsOfLand(land); AVERT(CBS, cbs); cbsEnter(cbs); @@ -1039,7 +1006,7 @@ Bool CBSFindLargest(Range rangeReturn, Range oldRangeReturn, AVER(CBSBlockSize(block) >= maxSize); RangeInit(&range, CBSBlockBase(block), CBSBlockLimit(block)); AVER(RangeSize(&range) >= maxSize); - cbsFindDeleteRange(rangeReturn, oldRangeReturn, cbs, &range, + cbsFindDeleteRange(rangeReturn, oldRangeReturn, land, &range, maxSize, findDelete); } } @@ -1049,15 +1016,91 @@ Bool CBSFindLargest(Range rangeReturn, Range oldRangeReturn, } -/* CBSDescribe -- describe a CBS +static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn, + Land land, Size size, + ZoneSet zoneSet, Bool high) +{ + CBS cbs; + Tree tree; + cbsTestNodeInZonesClosureStruct closure; + Res res; + LandFindMethod landFind; + SplayFindMethod splayFind; + + AVER(rangeReturn != NULL); + AVER(oldRangeReturn != NULL); + AVERT(Land, land); + cbs = cbsOfLand(land); + AVERT(CBS, cbs); + /* AVER(ZoneSetCheck(zoneSet)); */ + AVER(BoolCheck(high)); + + landFind = high ? cbsFindLast : cbsFindFirst; + splayFind = high ? SplayFindLast : SplayFindFirst; + + if (zoneSet == ZoneSetEMPTY) + return ResFAIL; + if (zoneSet == ZoneSetUNIV) { + FindDelete fd = high ? FindDeleteHIGH : FindDeleteLOW; + if ((*landFind)(rangeReturn, oldRangeReturn, land, size, fd)) + return ResOK; + else + return ResFAIL; + } + if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(LandArena(land))) + return ResFAIL; + + /* It would be nice if there were a neat way to eliminate all runs of + zones in zoneSet too small for size.*/ + + cbsEnter(cbs); + + closure.arena = LandArena(land); + closure.zoneSet = zoneSet; + closure.size = size; + closure.high = high; + if (splayFind(&tree, cbsSplay(cbs), + cbsTestNodeInZones, + cbsTestTreeInZones, + &closure, sizeof(closure))) { + CBSBlock block = cbsBlockOfTree(tree); + RangeStruct rangeStruct, oldRangeStruct; + + AVER(CBSBlockBase(block) <= closure.base); + AVER(AddrOffset(closure.base, closure.limit) >= size); + AVER(ZoneSetSub(ZoneSetOfRange(LandArena(land), closure.base, closure.limit), zoneSet)); + AVER(closure.limit <= CBSBlockLimit(block)); + + if (!high) + RangeInit(&rangeStruct, closure.base, AddrAdd(closure.base, size)); + else + RangeInit(&rangeStruct, AddrSub(closure.limit, size), closure.limit); + res = cbsDeleteFromTree(&oldRangeStruct, land, &rangeStruct); + if (res == ResOK) { /* enough memory to split block */ + RangeCopy(rangeReturn, &rangeStruct); + RangeCopy(oldRangeReturn, &oldRangeStruct); + } + } else + res = ResFAIL; + + cbsLeave(cbs); + return res; +} + + +/* cbsDescribe -- describe a CBS * * See . */ -Res CBSDescribe(CBS cbs, mps_lib_FILE *stream) +static Res cbsDescribe(Land land, mps_lib_FILE *stream) { + CBS cbs; Res res; + if (!TESTT(Land, land)) + return ResFAIL; + cbs = cbsOfLand(land); if (!TESTT(CBS, cbs)) return ResFAIL; if (stream == NULL) @@ -1065,7 +1108,6 @@ Res CBSDescribe(CBS cbs, mps_lib_FILE *stream) res = WriteF(stream, "CBS $P {\n", (WriteFP)cbs, - " alignment: $U\n", (WriteFU)cbs->alignment, " blockPool: $P\n", (WriteFP)cbsBlockPool(cbs), " fastFind: $U\n", (WriteFU)cbs->fastFind, " inCBS: $U\n", (WriteFU)cbs->inCBS, @@ -1084,6 +1126,27 @@ Res CBSDescribe(CBS cbs, mps_lib_FILE *stream) } +typedef LandClassStruct CBSLandClassStruct; + +DEFINE_CLASS(CBSLandClass, class) +{ + INHERIT_CLASS(class, LandClass); + class->name = "CBS"; + class->size = sizeof(CBSStruct); + class->init = cbsInit; + class->finish = cbsFinish; + class->insert = cbsInsert; + class->delete = cbsDelete; + class->iterate = cbsIterate; + class->findFirst = cbsFindFirst; + class->findLast = cbsFindLast; + class->findLargest = cbsFindLargest; + class->findInZones = cbsFindInZones; + class->describe = cbsDescribe; +} + + + /* C. COPYRIGHT AND LICENSE * * Copyright (C) 2001-2013 Ravenbrook Limited . diff --git a/mps/code/cbs.h b/mps/code/cbs.h index e425bd80cf8..170c41d496b 100644 --- a/mps/code/cbs.h +++ b/mps/code/cbs.h @@ -15,7 +15,6 @@ #include "range.h" #include "splay.h" - /* TODO: There ought to be different levels of CBS block with inheritance so that CBSs without fastFind don't allocate the maxSize and zones fields, and CBSs without zoned don't allocate the zones field. */ @@ -29,40 +28,21 @@ typedef struct CBSBlockStruct { ZoneSet zones; /* union zone set of all ranges in sub-tree */ } CBSBlockStruct; - -typedef struct CBSStruct *CBS; -typedef Bool (*CBSVisitor)(CBS cbs, Range range, - void *closureP, Size closureS); - extern Bool CBSCheck(CBS cbs); +extern CBSLandClass CBSLandClassGet(void); + extern const struct mps_key_s _mps_key_cbs_block_pool; #define CBSBlockPool (&_mps_key_cbs_block_pool) #define CBSBlockPool_FIELD pool +extern const struct mps_key_s _mps_key_cbs_fast_find; +#define CBSFastFind (&_mps_key_cbs_fast_find) +#define CBSFastFind_FIELD b +extern const struct mps_key_s _mps_key_cbs_zoned; +#define CBSZoned (&_mps_key_cbs_zoned) +#define CBSZoned_FIELD b /* TODO: Passing booleans to affect behaviour is ugly and error-prone. */ -extern Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment, - Bool fastFind, Bool zoned, ArgList args); -extern void CBSFinish(CBS cbs); - -extern Res CBSInsert(Range rangeReturn, CBS cbs, Range range); -extern Res CBSDelete(Range rangeReturn, CBS cbs, Range range); -extern void CBSIterate(CBS cbs, CBSVisitor visitor, - void *closureP, Size closureS); - -extern Res CBSDescribe(CBS cbs, mps_lib_FILE *stream); - -typedef Bool (*CBSFindMethod)(Range rangeReturn, Range oldRangeReturn, - CBS cbs, Size size, FindDelete findDelete); -extern Bool CBSFindFirst(Range rangeReturn, Range oldRangeReturn, - CBS cbs, Size size, FindDelete findDelete); -extern Bool CBSFindLast(Range rangeReturn, Range oldRangeReturn, - CBS cbs, Size size, FindDelete findDelete); -extern Bool CBSFindLargest(Range rangeReturn, Range oldRangeReturn, - CBS cbs, Size size, FindDelete findDelete); - -extern Res CBSFindInZones(Range rangeReturn, Range oldRangeReturn, - CBS cbs, Size size, ZoneSet zoneSet, Bool high); #endif /* cbs_h */ diff --git a/mps/code/eventdef.h b/mps/code/eventdef.h index cc3b3d61c21..0ff0a608b58 100644 --- a/mps/code/eventdef.h +++ b/mps/code/eventdef.h @@ -96,7 +96,7 @@ EVENT(X, PoolFinish , 0x0016, TRUE, Pool) \ EVENT(X, PoolAlloc , 0x0017, TRUE, Object) \ EVENT(X, PoolFree , 0x0018, TRUE, Object) \ - EVENT(X, CBSInit , 0x0019, TRUE, Pool) \ + EVENT(X, LandInit , 0x0019, TRUE, Pool) \ EVENT(X, Intern , 0x001a, TRUE, User) \ EVENT(X, Label , 0x001b, TRUE, User) \ EVENT(X, TraceStart , 0x001c, TRUE, Trace) \ @@ -311,8 +311,8 @@ PARAM(X, 1, A, old) \ PARAM(X, 2, W, size) -#define EVENT_CBSInit_PARAMS(PARAM, X) \ - PARAM(X, 0, P, cbs) \ +#define EVENT_LandInit_PARAMS(PARAM, X) \ + PARAM(X, 0, P, land) \ PARAM(X, 1, P, owner) #define EVENT_Intern_PARAMS(PARAM, X) \ diff --git a/mps/code/fbmtest.c b/mps/code/fbmtest.c index f98c49032a9..b4072d929af 100644 --- a/mps/code/fbmtest.c +++ b/mps/code/fbmtest.c @@ -56,7 +56,7 @@ typedef struct FBMStateStruct { BT allocTable; Addr block; union { - CBS cbs; + Land land; Freelist fl; } the; } FBMStateStruct, *FBMState; @@ -83,7 +83,7 @@ static Index (indexOfAddr)(FBMState state, Addr a) static void describe(FBMState state) { switch (state->type) { case FBMTypeCBS: - die(CBSDescribe(state->the.cbs, mps_lib_get_stdout()), "CBSDescribe"); + die(LandDescribe(state->the.land, mps_lib_get_stdout()), "LandDescribe"); break; case FBMTypeFreelist: die(FreelistDescribe(state->the.fl, mps_lib_get_stdout()), "FreelistDescribe"); @@ -125,10 +125,10 @@ static Bool checkCallback(Range range, void *closureP, Size closureS) } -static Bool checkCBSCallback(CBS cbs, Range range, +static Bool checkCBSCallback(Land land, Range range, void *closureP, Size closureS) { - UNUSED(cbs); + UNUSED(land); return checkCallback(range, closureP, closureS); } @@ -151,7 +151,7 @@ static void check(FBMState state) switch (state->type) { case FBMTypeCBS: - CBSIterate(state->the.cbs, checkCBSCallback, (void *)&closure, 0); + LandIterate(state->the.land, checkCBSCallback, (void *)&closure, 0); break; case FBMTypeFreelist: FreelistIterate(state->the.fl, checkFLCallback, (void *)&closure, 0); @@ -305,7 +305,7 @@ static void allocate(FBMState state, Addr base, Addr limit) RangeInit(&range, base, limit); switch (state->type) { case FBMTypeCBS: - res = CBSDelete(&oldRange, state->the.cbs, &range); + res = LandDelete(&oldRange, state->the.land, &range); break; case FBMTypeFreelist: res = FreelistDelete(&oldRange, state->the.fl, &range); @@ -381,7 +381,7 @@ static void deallocate(FBMState state, Addr base, Addr limit) RangeInit(&range, base, limit); switch (state->type) { case FBMTypeCBS: - res = CBSInsert(&freeRange, state->the.cbs, &range); + res = LandInsert(&freeRange, state->the.land, &range); break; case FBMTypeFreelist: res = FreelistInsert(&freeRange, state->the.fl, &range); @@ -459,8 +459,8 @@ static void find(FBMState state, Size size, Bool high, FindDelete findDelete) switch (state->type) { case FBMTypeCBS: - found = (high ? CBSFindLast : CBSFindFirst) - (&foundRange, &oldRange, state->the.cbs, size * state->align, findDelete); + found = (high ? LandFindLast : LandFindFirst) + (&foundRange, &oldRange, state->the.land, size * state->align, findDelete); break; case FBMTypeFreelist: found = (high ? FreelistFindLast : FreelistFindFirst) @@ -558,6 +558,7 @@ extern int main(int argc, char *argv[]) BT allocTable; FreelistStruct flStruct; CBSStruct cbsStruct; + Land land = (Land)&cbsStruct; Align align; testlib_init(argc, argv); @@ -585,16 +586,18 @@ extern int main(int argc, char *argv[]) (char *)dummyBlock + ArraySize); } - die((mps_res_t)CBSInit(&cbsStruct, arena, arena, align, - /* fastFind */ TRUE, /* zoned */ FALSE, mps_args_none), - "failed to initialise CBS"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, CBSFastFind, TRUE); + die((mps_res_t)LandInit(land, CBSLandClassGet(), arena, align, NULL, args), + "failed to initialise CBS"); + } MPS_ARGS_END(args); state.type = FBMTypeCBS; state.align = align; state.block = dummyBlock; state.allocTable = allocTable; - state.the.cbs = &cbsStruct; + state.the.land = land; test(&state, nCBSOperations); - CBSFinish(&cbsStruct); + LandFinish(land); die((mps_res_t)FreelistInit(&flStruct, align), "failed to initialise Freelist"); diff --git a/mps/code/fotest.c b/mps/code/fotest.c index 4025d20a2c6..bef621362d7 100644 --- a/mps/code/fotest.c +++ b/mps/code/fotest.c @@ -38,8 +38,8 @@ /* Accessors for the CBS used to implement a pool. */ -extern CBS _mps_mvff_cbs(mps_pool_t); -extern CBS _mps_mvt_cbs(mps_pool_t); +extern Land _mps_mvff_cbs(mps_pool_t); +extern Land _mps_mvt_cbs(mps_pool_t); /* "OOM" pool class -- dummy alloc/free pool class whose alloc() @@ -180,7 +180,7 @@ int main(int argc, char *argv[]) die(mps_pool_create_k(&pool, arena, mps_class_mvff(), args), "create MVFF"); } MPS_ARGS_END(args); { - CBS cbs = _mps_mvff_cbs(pool); + CBS cbs = (CBS)_mps_mvff_cbs(pool); die(stress(randomSizeAligned, alignment, pool, cbs), "stress MVFF"); } mps_pool_destroy(pool); @@ -199,7 +199,7 @@ int main(int argc, char *argv[]) die(mps_pool_create_k(&pool, arena, mps_class_mvt(), args), "create MVFF"); } MPS_ARGS_END(args); { - CBS cbs = _mps_mvt_cbs(pool); + CBS cbs = (CBS)_mps_mvt_cbs(pool); die(stress(randomSizeAligned, alignment, pool, cbs), "stress MVT"); } mps_pool_destroy(pool); diff --git a/mps/code/freelist.c b/mps/code/freelist.c index 6260451ff59..a299dafb6e6 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -6,7 +6,6 @@ * .sources: . */ -#include "cbs.h" #include "freelist.h" #include "mpm.h" @@ -589,22 +588,22 @@ Res FreelistDescribe(Freelist fl, mps_lib_FILE *stream) /* freelistFlushIterateMethod -- Iterate method for - * FreelistFlushToCBS. Attempst to insert the range into the CBS. + * FreelistFlushToLand. Attempst to insert the range into the Land. */ static Bool freelistFlushIterateMethod(Bool *deleteReturn, Range range, void *closureP, Size closureS) { Res res; RangeStruct newRange; - CBS cbs; + Land land; AVER(deleteReturn != NULL); AVERT(Range, range); AVER(closureP != NULL); UNUSED(closureS); - cbs = closureP; - res = CBSInsert(&newRange, cbs, range); + land = closureP; + res = LandInsert(&newRange, land, range); if (res == ResOK) { *deleteReturn = TRUE; return TRUE; @@ -615,12 +614,12 @@ static Bool freelistFlushIterateMethod(Bool *deleteReturn, Range range, } -void FreelistFlushToCBS(Freelist fl, CBS cbs) +void FreelistFlushToLand(Freelist fl, Land land) { AVERT(Freelist, fl); - AVERT(CBS, cbs); + AVERT(Land, land); - FreelistIterate(fl, freelistFlushIterateMethod, cbs, 0); + FreelistIterate(fl, freelistFlushIterateMethod, land, 0); } diff --git a/mps/code/freelist.h b/mps/code/freelist.h index 1bb9840c8c9..b9aea9bdf6c 100644 --- a/mps/code/freelist.h +++ b/mps/code/freelist.h @@ -9,7 +9,6 @@ #ifndef freelist_h #define freelist_h -#include "cbs.h" #include "mpmtypes.h" #include "range.h" @@ -46,7 +45,7 @@ extern Bool FreelistFindLast(Range rangeReturn, Range oldRangeReturn, extern Bool FreelistFindLargest(Range rangeReturn, Range oldRangeReturn, Freelist fl, Size size, FindDelete findDelete); -extern void FreelistFlushToCBS(Freelist fl, CBS cbs); +extern void FreelistFlushToLand(Freelist fl, Land land); #endif /* freelist.h */ diff --git a/mps/code/land.c b/mps/code/land.c new file mode 100644 index 00000000000..3abd9c41e15 --- /dev/null +++ b/mps/code/land.c @@ -0,0 +1,348 @@ +/* land.c: LAND (COLLECTION OF ADDRESS RANGES) IMPLEMENTATION + * + * $Id: //info.ravenbrook.com/project/mps/branch/2014-03-30/land/code/land.c#1 $ + * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * + * .design: + */ + +#include "mpm.h" + +SRCID(land, "$Id$"); + + +Bool LandCheck(Land land) +{ + CHECKS(Land, land); + CHECKU(Arena, land->arena); + CHECKL(AlignCheck(land->alignment)); + return TRUE; +} + +Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *owner, ArgList args) +{ + Res res; + + AVER(land != NULL); + AVERT(LandClass, class); + AVER(AlignCheck(alignment)); + + land->alignment = alignment; + land->arena = arena; + land->class = class; + land->sig = LandSig; + + AVERT(Land, land); + + res = (*class->init)(land, args); + if (res != ResOK) + goto failInit; + + EVENT2(LandInit, land, owner); + return ResOK; + + failInit: + land->sig = SigInvalid; + return res; +} + +Res LandCreate(Land *landReturn, Arena arena, LandClass class, Align alignment, void *owner, ArgList args) +{ + Res res; + Land land; + void *p; + + AVER(landReturn != NULL); + AVERT(Arena, arena); + AVERT(LandClass, class); + + res = ControlAlloc(&p, arena, class->size, + /* withReservoirPermit */ FALSE); + if (res != ResOK) + goto failAlloc; + land = p; + + res = LandInit(land, class, arena, alignment, owner, args); + if (res != ResOK) + goto failInit; + + *landReturn = land; + return ResOK; + +failInit: + ControlFree(arena, land, class->size); +failAlloc: + return res; +} + +void LandDestroy(Land land) +{ + Arena arena; + LandClass class; + + AVERT(Land, land); + arena = land->arena; + class = land->class; + AVERT(LandClass, class); + LandFinish(land); + ControlFree(arena, land, class->size); +} + +void LandFinish(Land land) +{ + AVERT(Land, land); + (*land->class->finish)(land); +} + +Res LandInsert(Range rangeReturn, Land land, Range range) +{ + AVER(rangeReturn != NULL); + AVERT(Land, land); + AVERT(Range, range); + AVER(RangeIsAligned(range, land->alignment)); + + return (*land->class->insert)(rangeReturn, land, range); +} + +Res LandDelete(Range rangeReturn, Land land, Range range) +{ + AVER(rangeReturn != NULL); + AVERT(Land, land); + AVERT(Range, range); + AVER(RangeIsAligned(range, land->alignment)); + + return (*land->class->delete)(rangeReturn, land, range); +} + +void LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) +{ + AVERT(Land, land); + AVER(FUNCHECK(visitor)); + + (*land->class->iterate)(land, visitor, closureP, closureS); +} + +Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) +{ + AVER(rangeReturn != NULL); + AVER(oldRangeReturn != NULL); + AVERT(Land, land); + AVER(SizeIsAligned(size, land->alignment)); + AVER(FindDeleteCheck(findDelete)); + + return (*land->class->findFirst)(rangeReturn, oldRangeReturn, land, size, + findDelete); +} + +Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) +{ + AVER(rangeReturn != NULL); + AVER(oldRangeReturn != NULL); + AVERT(Land, land); + AVER(SizeIsAligned(size, land->alignment)); + AVER(FindDeleteCheck(findDelete)); + + return (*land->class->findLast)(rangeReturn, oldRangeReturn, land, size, + findDelete); +} + +Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) +{ + AVER(rangeReturn != NULL); + AVER(oldRangeReturn != NULL); + AVERT(Land, land); + AVER(SizeIsAligned(size, land->alignment)); + AVER(FindDeleteCheck(findDelete)); + + return (*land->class->findLargest)(rangeReturn, oldRangeReturn, land, size, + findDelete); +} + +Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high) +{ + AVER(rangeReturn != NULL); + AVER(oldRangeReturn != NULL); + AVERT(Land, land); + AVER(SizeIsAligned(size, land->alignment)); + /* AVER(ZoneSetCheck(zoneSet)); */ + AVER(BoolCheck(high)); + + return (*land->class->findInZones)(rangeReturn, oldRangeReturn, land, size, + zoneSet, high); +} + +Res LandDescribe(Land land, mps_lib_FILE *stream) +{ + Res res; + + if (!TESTT(Land, land)) return ResFAIL; + if (stream == NULL) return ResFAIL; + + res = WriteF(stream, + "Land $P {\n", (WriteFP)land, + " class $P", (WriteFP)land->class, + " (\"$S\")\n", land->class->name, + " arena $P\n", (WriteFP)land->arena, + " align $U\n", (WriteFU)land->alignment, + NULL); + if (res != ResOK) + return res; + + res = (*land->class->describe)(land, stream); + if (res != ResOK) + return res; + + res = WriteF(stream, "} Land $P\n", (WriteFP)land, NULL); + return ResOK; +} + + +Bool LandClassCheck(LandClass class) +{ + CHECKL(ProtocolClassCheck(&class->protocol)); + CHECKL(class->name != NULL); /* Should be <=6 char C identifier */ + CHECKL(class->size >= sizeof(LandStruct)); + CHECKL(FUNCHECK(class->init)); + CHECKL(FUNCHECK(class->finish)); + CHECKL(FUNCHECK(class->insert)); + CHECKL(FUNCHECK(class->delete)); + CHECKL(FUNCHECK(class->findFirst)); + CHECKL(FUNCHECK(class->findLast)); + CHECKL(FUNCHECK(class->findLargest)); + CHECKL(FUNCHECK(class->findInZones)); + CHECKL(FUNCHECK(class->describe)); + CHECKS(LandClass, class); + return TRUE; +} + + +static Res landTrivInit(Land land, ArgList args) +{ + AVERT(Land, land); + AVER(ArgListCheck(args)); + UNUSED(args); + return ResOK; +} + +static void landTrivFinish(Land land) +{ + AVERT(Land, land); + NOOP; +} + +static Res landNoInsert(Range rangeReturn, Land land, Range range) +{ + AVER(rangeReturn != NULL); + AVERT(Land, land); + AVERT(Range, range); + return ResUNIMPL; +} + +static Res landNoDelete(Range rangeReturn, Land land, Range range) +{ + AVER(rangeReturn != NULL); + AVERT(Land, land); + AVERT(Range, range); + return ResUNIMPL; +} + +static void landNoIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) +{ + AVERT(Land, land); + AVER(visitor != NULL); + UNUSED(closureP); + UNUSED(closureS); + NOOP; +} + +static Bool landNoFind(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) +{ + AVER(rangeReturn != NULL); + AVER(oldRangeReturn != NULL); + AVERT(Land, land); + UNUSED(size); + AVER(FindDeleteCheck(findDelete)); + return ResUNIMPL; +} + +static Res landNoFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high) +{ + AVER(rangeReturn != NULL); + AVER(oldRangeReturn != NULL); + AVERT(Land, land); + UNUSED(size); + UNUSED(zoneSet); + AVER(BoolCheck(high)); + return ResUNIMPL; +} + +static Res landTrivDescribe(Land land, mps_lib_FILE *stream) +{ + if (!TESTT(Land, land)) + return ResFAIL; + if (stream == NULL) + return ResFAIL; + /* dispatching function does it all */ + return ResOK; +} + +DEFINE_CLASS(LandClass, class) +{ + INHERIT_CLASS(&class->protocol, ProtocolClass); + class->name = "LAND"; + class->size = sizeof(LandStruct); + class->init = landTrivInit; + class->finish = landTrivFinish; + class->insert = landNoInsert; + class->delete = landNoDelete; + class->iterate = landNoIterate; + class->findFirst = landNoFind; + class->findLast = landNoFind; + class->findLargest = landNoFind; + class->findInZones = landNoFindInZones; + class->describe = landTrivDescribe; + class->sig = LandClassSig; + AVERT(LandClass, class); +} + + +/* 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/locus.c b/mps/code/locus.c index f0ba7415cde..a3d7986deb3 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -480,6 +480,7 @@ void LocusInit(Arena arena) gen->proflow = 0.0; RingInit(&gen->locusRing); gen->sig = GenDescSig; + AVERT(GenDesc, gen); } diff --git a/mps/code/mpm.h b/mps/code/mpm.h index da45d9aedd2..4e65ea83ed4 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -490,8 +490,8 @@ extern void ArenaFinish(Arena arena); extern Res ArenaDescribe(Arena arena, mps_lib_FILE *stream); extern Res ArenaDescribeTracts(Arena arena, mps_lib_FILE *stream); extern Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context); -extern Res ArenaFreeCBSInsert(Arena arena, Addr base, Addr limit); -extern void ArenaFreeCBSDelete(Arena arena, Addr base, Addr limit); +extern Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit); +extern void ArenaFreeLandDelete(Arena arena, Addr base, Addr limit); extern Bool GlobalsCheck(Globals arena); @@ -992,6 +992,30 @@ extern Size VMReserved(VM vm); extern Size VMMapped(VM vm); +/* Land Interface -- see */ + +extern Bool LandCheck(Land land); +#define LandArena(land) ((land)->arena) +#define LandAlignment(land) ((land)->alignment) + +extern Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *owner, ArgList args); +extern Res LandCreate(Land *landReturn, Arena arena, LandClass class, Align alignment, void *owner, ArgList args); +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 void LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS); +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); +extern Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high); +extern Res LandDescribe(Land land, mps_lib_FILE *stream); + +extern Bool LandClassCheck(LandClass class); +extern LandClass LandClassGet(void); +#define LAND_SUPERCLASS(className) ((LandClass)SUPERCLASS(className)) + + /* Stack Probe */ extern void StackProbe(Size depth); diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 85e95a78ec1..8d7a414465b 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -604,7 +604,50 @@ typedef struct GlobalsStruct { } GlobalsStruct; +/* LandClassStruct -- land class structure + * + * See . + */ + +#define LandClassSig ((Sig)0x5197A4DC) /* SIGnature LAND Class */ + +typedef struct LandClassStruct { + ProtocolClassStruct protocol; + const char *name; /* class name string */ + size_t size; /* size of outer structure */ + LandInitMethod init; /* initialize the land */ + LandFinishMethod finish; /* finish the land */ + LandInsertMethod insert; /* insert a range into the land */ + LandDeleteMethod delete; /* delete a range from the land */ + LandIterateMethod iterate; /* iterate over ranges in the land */ + LandFindMethod findFirst; /* find first range of given size */ + LandFindMethod findLast; /* find last range of given size */ + LandFindMethod findLargest; /* find largest range */ + LandFindInZonesMethod findInZones; /* find first range of given size in zone set */ + LandDescribeMethod describe; /* describe the land */ + Sig sig; /* .class.end-sig */ +} LandClassStruct; + + +/* LandStruct -- generic land structure + * + * See , + */ + +#define LandSig ((Sig)0x5197A4D9) /* SIGnature LAND */ + +typedef struct LandStruct { + Sig sig; /* */ + LandClass class; /* land class structure */ + Arena arena; /* owning arena */ + Align alignment; /* alignment of addresses */ +} LandStruct; + + /* CBSStruct -- coalescing block structure + * + * CBS is a subclass of Land that maintains a collection of disjoint + * ranges in a splay tree. * * See . */ @@ -612,18 +655,17 @@ typedef struct GlobalsStruct { #define CBSSig ((Sig)0x519CB599) /* SIGnature CBS */ typedef struct CBSStruct { + LandStruct landStruct; /* superclass fields come first */ SplayTreeStruct splayTreeStruct; STATISTIC_DECL(Count treeSize); - Arena arena; - Pool blockPool; - Align alignment; + Pool blockPool; /* pool that manages blocks */ Bool fastFind; /* maintain and use size property? */ Bool zoned; /* maintain and use zone property? */ Bool inCBS; /* prevent reentrance */ Bool ownPool; /* did we create blockPool? */ /* meters for sizes of search structures at each op */ METER_DECL(treeSearch); - Sig sig; /* sig at end because embeded */ + Sig sig; /* sig at end because embedded */ } CBSStruct; @@ -661,9 +703,9 @@ typedef struct mps_arena_s { Serial chunkSerial; /* next chunk number */ ChunkCacheEntryStruct chunkCache; /* just one entry */ - Bool hasFreeCBS; /* Is freeCBS available? */ + Bool hasFreeLand; /* Is freeLand available? */ MFSStruct freeCBSBlockPoolStruct; - CBSStruct freeCBSStruct; + CBSStruct freeLandStruct; ZoneSet freeZones; /* zones not yet allocated */ Bool zoned; /* use zoned allocation? */ diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 9aac8322b35..8abc43bb111 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -109,7 +109,13 @@ typedef struct AllocPatternStruct *AllocPattern; typedef struct AllocFrameStruct *AllocFrame; /* */ typedef struct ReservoirStruct *Reservoir; /* */ typedef struct StackContextStruct *StackContext; -typedef unsigned FindDelete; /* */ +typedef struct RangeStruct *Range; /* */ +typedef struct LandStruct *Land; /* */ +typedef struct LandClassStruct *LandClass; /* */ +typedef LandClass CBSLandClass; /* */ +typedef struct CBSStruct *CBS; /* */ +typedef LandClass FreelistClass; /* */ +typedef unsigned FindDelete; /* */ /* Arena*Method -- see */ @@ -262,6 +268,19 @@ typedef struct TraceStartMessageStruct *TraceStartMessage; typedef struct TraceMessageStruct *TraceMessage; /* trace end */ +/* Land*Method -- see */ + +typedef Res (*LandInitMethod)(Land land, ArgList args); +typedef void (*LandFinishMethod)(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 void (*LandIterateMethod)(Land land, LandVisitor visitor, void *closureP, Size closureS); +typedef Bool (*LandFindMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete); +typedef Res (*LandFindInZonesMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high); +typedef Res (*LandDescribeMethod)(Land land, mps_lib_FILE *stream); + + /* CONSTANTS */ diff --git a/mps/code/mps.c b/mps/code/mps.c index 0a8f29be9ba..34c7a9b49cd 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -75,6 +75,7 @@ #include "range.c" #include "freelist.c" #include "sa.c" +#include "land.c" /* Additional pool classes */ diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index d9d063dc39e..f3de433a5ef 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -51,7 +51,7 @@ static Res MVTContingencySearch(Addr *baseReturn, Addr *limitReturn, MVT mvt, Size min); static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena); static ABQ MVTABQ(MVT mvt); -static CBS MVTCBS(MVT mvt); +static Land MVTCBS(MVT mvt); static Freelist MVTFreelist(MVT mvt); @@ -168,9 +168,9 @@ static ABQ MVTABQ(MVT mvt) } -static CBS MVTCBS(MVT mvt) +static Land MVTCBS(MVT mvt) { - return &mvt->cbsStruct; + return (Land)(&mvt->cbsStruct); } @@ -269,8 +269,10 @@ static Res MVTInit(Pool pool, ArgList args) if (abqDepth < 3) abqDepth = 3; - res = CBSInit(MVTCBS(mvt), arena, (void *)mvt, align, - /* fastFind */ FALSE, /* zoned */ FALSE, args); + MPS_ARGS_BEGIN(landiArgs) { + MPS_ARGS_ADD(landiArgs, CBSFastFind, TRUE); + res = LandInit(MVTCBS(mvt), CBSLandClassGet(), arena, align, mvt, landiArgs); + } MPS_ARGS_END(landiArgs); if (res != ResOK) goto failCBS; @@ -348,7 +350,7 @@ static Res MVTInit(Pool pool, ArgList args) failFreelist: ABQFinish(arena, MVTABQ(mvt)); failABQ: - CBSFinish(MVTCBS(mvt)); + LandFinish(MVTCBS(mvt)); failCBS: AVER(res != ResOK); return res; @@ -422,7 +424,7 @@ static void MVTFinish(Pool pool) /* Finish the Freelist, ABQ and CBS structures */ FreelistFinish(MVTFreelist(mvt)); ABQFinish(arena, MVTABQ(mvt)); - CBSFinish(MVTCBS(mvt)); + LandFinish(MVTCBS(mvt)); } @@ -808,10 +810,10 @@ static Res MVTInsert(MVT mvt, Addr base, Addr limit) /* Attempt to flush the Freelist to the CBS to give maximum * opportunities for coalescence. */ - FreelistFlushToCBS(MVTFreelist(mvt), MVTCBS(mvt)); + FreelistFlushToLand(MVTFreelist(mvt), MVTCBS(mvt)); RangeInit(&range, base, limit); - res = CBSInsert(&newRange, MVTCBS(mvt), &range); + res = LandInsert(&newRange, MVTCBS(mvt), &range); if (ResIsAllocFailure(res)) { /* CBS ran out of memory for splay nodes: add range to emergency * free list instead. */ @@ -845,7 +847,7 @@ static Res MVTDelete(MVT mvt, Addr base, Addr limit) AVER(base < limit); RangeInit(&range, base, limit); - res = CBSDelete(&rangeOld, MVTCBS(mvt), &range); + res = LandDelete(&rangeOld, MVTCBS(mvt), &range); if (ResIsAllocFailure(res)) { /* CBS ran out of memory for splay nodes, which must mean that * there were fragments on both sides: see @@ -853,7 +855,7 @@ static Res MVTDelete(MVT mvt, Addr base, Addr limit) * deleting the whole of rangeOld (which requires no * allocation) and re-inserting the fragments. */ RangeStruct rangeOld2; - res = CBSDelete(&rangeOld2, MVTCBS(mvt), &rangeOld); + res = LandDelete(&rangeOld2, MVTCBS(mvt), &rangeOld); AVER(res == ResOK); AVER(RangesEqual(&rangeOld2, &rangeOld)); AVER(RangeBase(&rangeOld) != base); @@ -1043,7 +1045,7 @@ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream) NULL); if(res != ResOK) return res; - res = CBSDescribe(MVTCBS(mvt), stream); + res = LandDescribe(MVTCBS(mvt), stream); if(res != ResOK) return res; res = ABQDescribe(MVTABQ(mvt), (ABQDescribeElement)RangeDescribe, stream); @@ -1285,11 +1287,11 @@ static Bool MVTRefillCallback(MVT mvt, Range range) return MVTReserve(mvt, range); } -static Bool MVTCBSRefillCallback(CBS cbs, Range range, +static Bool MVTCBSRefillCallback(Land land, Range range, void *closureP, Size closureS) { MVT mvt; - AVERT(CBS, cbs); + AVERT(Land, land); mvt = closureP; AVERT(MVT, mvt); UNUSED(closureS); @@ -1324,7 +1326,7 @@ static void MVTRefillABQIfEmpty(MVT mvt, Size size) if (mvt->abqOverflow && ABQIsEmpty(MVTABQ(mvt))) { mvt->abqOverflow = FALSE; METER_ACC(mvt->refills, size); - CBSIterate(MVTCBS(mvt), &MVTCBSRefillCallback, mvt, 0); + LandIterate(MVTCBS(mvt), &MVTCBSRefillCallback, mvt, 0); FreelistIterate(MVTFreelist(mvt), &MVTFreelistRefillCallback, mvt, 0); } } @@ -1387,11 +1389,11 @@ static Bool MVTContingencyCallback(MVTContigency cl, Range range) return TRUE; } -static Bool MVTCBSContingencyCallback(CBS cbs, Range range, +static Bool MVTCBSContingencyCallback(Land land, Range range, void *closureP, Size closureS) { MVTContigency cl = closureP; - UNUSED(cbs); + AVERT(Land, land); UNUSED(closureS); return MVTContingencyCallback(cl, range); } @@ -1421,9 +1423,9 @@ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn, cls.steps = 0; cls.hardSteps = 0; - FreelistFlushToCBS(MVTFreelist(mvt), MVTCBS(mvt)); + FreelistFlushToLand(MVTFreelist(mvt), MVTCBS(mvt)); - CBSIterate(MVTCBS(mvt), MVTCBSContingencyCallback, (void *)&cls, 0); + LandIterate(MVTCBS(mvt), MVTCBSContingencyCallback, (void *)&cls, 0); FreelistIterate(MVTFreelist(mvt), MVTFreelistContingencyCallback, (void *)&cls, 0); if (!cls.found) @@ -1472,8 +1474,8 @@ static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena) /* Return the CBS of an MVT pool for the benefit of fotest.c. */ -extern CBS _mps_mvt_cbs(mps_pool_t); -CBS _mps_mvt_cbs(mps_pool_t mps_pool) { +extern Land _mps_mvt_cbs(mps_pool_t); +Land _mps_mvt_cbs(mps_pool_t mps_pool) { Pool pool; MVT mvt; diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index e1d1d094d38..f1679e5acaa 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -58,7 +58,7 @@ typedef struct MVFFStruct { /* MVFF pool outer structure */ #define Pool2MVFF(pool) PARENT(MVFFStruct, poolStruct, pool) #define MVFF2Pool(mvff) (&((mvff)->poolStruct)) -#define CBSOfMVFF(mvff) (&((mvff)->cbsStruct)) +#define CBSOfMVFF(mvff) ((Land)&((mvff)->cbsStruct)) #define MVFFOfCBS(cbs) PARENT(MVFFStruct, cbsStruct, cbs) #define FreelistOfMVFF(mvff) (&((mvff)->flStruct)) #define MVFFOfFreelist(fl) PARENT(MVFFStruct, flStruct, fl) @@ -95,7 +95,7 @@ static Res MVFFAddToFreeList(Addr *baseIO, Addr *limitIO, MVFF mvff) { AVERT(MVFF, mvff); RangeInit(&range, *baseIO, *limitIO); - res = CBSInsert(&newRange, CBSOfMVFF(mvff), &range); + res = LandInsert(&newRange, CBSOfMVFF(mvff), &range); if (ResIsAllocFailure(res)) { /* CBS ran out of memory for splay nodes: add range to emergency * free list instead. */ @@ -150,7 +150,7 @@ static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit) RangeStruct range, oldRange; RangeInit(&range, segBase, segLimit); - res = CBSDelete(&oldRange, CBSOfMVFF(mvff), &range); + res = LandDelete(&oldRange, CBSOfMVFF(mvff), &range); if (res == ResOK) { mvff->free -= RangeSize(&range); } else if (ResIsAllocFailure(res)) { @@ -160,7 +160,7 @@ static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit) * deleting the whole of oldRange (which requires no * allocation) and re-inserting the fragments. */ RangeStruct oldRange2; - res = CBSDelete(&oldRange2, CBSOfMVFF(mvff), &oldRange); + res = LandDelete(&oldRange2, CBSOfMVFF(mvff), &oldRange); AVER(res == ResOK); AVER(RangesEqual(&oldRange2, &oldRange)); mvff->free -= RangeSize(&oldRange); @@ -297,12 +297,12 @@ static Bool MVFFFindFirstFree(Addr *baseReturn, Addr *limitReturn, AVER(size > 0); AVER(SizeIsAligned(size, PoolAlignment(MVFF2Pool(mvff)))); - FreelistFlushToCBS(FreelistOfMVFF(mvff), CBSOfMVFF(mvff)); + FreelistFlushToLand(FreelistOfMVFF(mvff), CBSOfMVFF(mvff)); findDelete = mvff->slotHigh ? FindDeleteHIGH : FindDeleteLOW; foundBlock = - (mvff->firstFit ? CBSFindFirst : CBSFindLast) + (mvff->firstFit ? LandFindFirst : LandFindLast) (&range, &oldRange, CBSOfMVFF(mvff), size, findDelete); if (!foundBlock) { @@ -411,9 +411,9 @@ static Bool MVFFFindLargest(Range range, Range oldRange, MVFF mvff, AVER(size > 0); AVERT(FindDelete, findDelete); - FreelistFlushToCBS(FreelistOfMVFF(mvff), CBSOfMVFF(mvff)); + FreelistFlushToLand(FreelistOfMVFF(mvff), CBSOfMVFF(mvff)); - if (CBSFindLargest(range, oldRange, CBSOfMVFF(mvff), size, findDelete)) + if (LandFindLargest(range, oldRange, CBSOfMVFF(mvff), size, findDelete)) return TRUE; if (FreelistFindLargest(range, oldRange, FreelistOfMVFF(mvff), @@ -602,8 +602,10 @@ static Res MVFFInit(Pool pool, ArgList args) if (res != ResOK) goto failInit; - res = CBSInit(CBSOfMVFF(mvff), arena, (void *)mvff, align, - /* fastFind */ TRUE, /* zoned */ FALSE, args); + MPS_ARGS_BEGIN(landiArgs) { + MPS_ARGS_ADD(landiArgs, CBSFastFind, TRUE); + res = LandInit(CBSOfMVFF(mvff), CBSLandClassGet(), arena, align, mvff, landiArgs); + } MPS_ARGS_END(landiArgs); if (res != ResOK) goto failInit; @@ -646,7 +648,7 @@ static void MVFFFinish(Pool pool) arena = PoolArena(pool); ControlFree(arena, mvff->segPref, sizeof(SegPrefStruct)); - CBSFinish(CBSOfMVFF(mvff)); + LandFinish(CBSOfMVFF(mvff)); FreelistFinish(FreelistOfMVFF(mvff)); mvff->sig = SigInvalid; @@ -691,7 +693,7 @@ static Res MVFFDescribe(Pool pool, mps_lib_FILE *stream) if (res != ResOK) return res; - res = CBSDescribe(CBSOfMVFF(mvff), stream); + res = LandDescribe(CBSOfMVFF(mvff), stream); if (res != ResOK) return res; @@ -802,7 +804,7 @@ static Bool MVFFCheck(MVFF mvff) CHECKL(mvff->total >= mvff->free); CHECKL(SizeIsAligned(mvff->free, PoolAlignment(MVFF2Pool(mvff)))); CHECKL(SizeIsAligned(mvff->total, ArenaAlign(PoolArena(MVFF2Pool(mvff))))); - CHECKD(CBS, CBSOfMVFF(mvff)); + CHECKD(Land, CBSOfMVFF(mvff)); CHECKD(Freelist, FreelistOfMVFF(mvff)); CHECKL(BoolCheck(mvff->slotHigh)); CHECKL(BoolCheck(mvff->firstFit)); @@ -812,8 +814,8 @@ static Bool MVFFCheck(MVFF mvff) /* Return the CBS of an MVFF pool for the benefit of fotest.c. */ -extern CBS _mps_mvff_cbs(mps_pool_t); -CBS _mps_mvff_cbs(mps_pool_t mps_pool) { +extern Land _mps_mvff_cbs(mps_pool_t); +Land _mps_mvff_cbs(mps_pool_t mps_pool) { Pool pool; MVFF mvff; diff --git a/mps/code/range.h b/mps/code/range.h index 4c5b87854da..c996276cca6 100644 --- a/mps/code/range.h +++ b/mps/code/range.h @@ -21,8 +21,6 @@ /* Prototypes */ -typedef struct RangeStruct *Range; - #define RangeBase(range) ((range)->base) #define RangeLimit(range) ((range)->limit) #define RangeSize(range) (AddrOffset(RangeBase(range), RangeLimit(range))) diff --git a/mps/code/tract.c b/mps/code/tract.c index 69ae479cf1a..542206daa69 100644 --- a/mps/code/tract.c +++ b/mps/code/tract.c @@ -210,25 +210,25 @@ Res ChunkInit(Chunk chunk, Arena arena, /* Add the chunk's free address space to the arena's freeCBS, so that we can allocate from it. */ - if (arena->hasFreeCBS) { - res = ArenaFreeCBSInsert(arena, - PageIndexBase(chunk, chunk->allocBase), - chunk->limit); + if (arena->hasFreeLand) { + res = ArenaFreeLandInsert(arena, + PageIndexBase(chunk, chunk->allocBase), + chunk->limit); if (res != ResOK) - goto failCBSInsert; + goto failLandInsert; } chunk->sig = ChunkSig; AVERT(Chunk, chunk); /* As part of the bootstrap, the first created chunk becomes the primary - chunk. This step allows AreaFreeCBSInsert to allocate pages. */ + chunk. This step allows AreaFreeLandInsert to allocate pages. */ if (arena->primary == NULL) arena->primary = chunk; return ResOK; -failCBSInsert: +failLandInsert: (arena->class->chunkFinish)(chunk); /* .no-clean: No clean-ups needed past this point for boot, as we will discard the chunk. */ @@ -248,10 +248,10 @@ void ChunkFinish(Chunk chunk) chunk->sig = SigInvalid; RingRemove(&chunk->chunkRing); - if (ChunkArena(chunk)->hasFreeCBS) - ArenaFreeCBSDelete(ChunkArena(chunk), - PageIndexBase(chunk, chunk->allocBase), - chunk->limit); + if (ChunkArena(chunk)->hasFreeLand) + ArenaFreeLandDelete(ChunkArena(chunk), + PageIndexBase(chunk, chunk->allocBase), + chunk->limit); if (chunk->arena->primary == chunk) chunk->arena->primary = NULL; From e43a554d1c650c1df81327e503e8cbca54fcfab3 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 1 Apr 2014 21:26:07 +0100 Subject: [PATCH 026/266] Add land.c to list of modules, and missing header range.h. Copied from Perforce Change: 185134 ServerID: perforce.ravenbrook.com --- mps/code/comm.gmk | 52 +++++++++++++++++++++++++++++++++++++++----- mps/code/commpre.nmk | 1 + mps/code/land.c | 1 + 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index 7e68f45bfd9..ff915aaa5e3 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -164,12 +164,52 @@ FMTDYTST = fmtdy.c fmtno.c fmtdytst.c FMTHETST = fmthe.c fmtdy.c fmtno.c fmtdytst.c PLINTH = mpsliban.c mpsioan.c EVENTPROC = eventcnv.c table.c -MPMCOMMON = abq.c arena.c arenacl.c arenavm.c arg.c boot.c bt.c \ - buffer.c cbs.c dbgpool.c dbgpooli.c event.c format.c \ - freelist.c global.c ld.c locus.c message.c meter.c mpm.c mpsi.c \ - pool.c poolabs.c poolmfs.c poolmrg.c poolmv.c protocol.c range.c \ - ref.c reserv.c ring.c root.c sa.c sac.c seg.c shield.c splay.c ss.c \ - table.c trace.c traceanc.c tract.c tree.c walk.c +MPMCOMMON = \ + abq.c \ + arena.c \ + arenacl.c \ + arenavm.c \ + arg.c \ + boot.c \ + bt.c \ + buffer.c \ + cbs.c \ + dbgpool.c \ + dbgpooli.c \ + event.c \ + format.c \ + freelist.c \ + global.c \ + land.c \ + ld.c \ + locus.c \ + message.c \ + meter.c \ + mpm.c \ + mpsi.c \ + pool.c \ + poolabs.c \ + poolmfs.c \ + poolmrg.c \ + poolmv.c \ + protocol.c \ + range.c \ + ref.c \ + reserv.c \ + ring.c \ + root.c \ + sa.c \ + sac.c \ + seg.c \ + shield.c \ + splay.c \ + ss.c \ + table.c \ + trace.c \ + traceanc.c \ + tract.c \ + tree.c \ + walk.c MPM = $(MPMCOMMON) $(MPMPF) diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index 8d81ef13ccd..0c8e68a90f9 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -126,6 +126,7 @@ MPMCOMMON=\ \ \ \ + \ \ \ \ diff --git a/mps/code/land.c b/mps/code/land.c index 3abd9c41e15..991739f7b7f 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -7,6 +7,7 @@ */ #include "mpm.h" +#include "range.h" SRCID(land, "$Id$"); From 7c640f78d27588316e2f0190347c887cd75b33a4 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 1 Apr 2014 23:35:23 +0100 Subject: [PATCH 027/266] First draft of land design. Copied from Perforce Change: 185146 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 2 +- mps/design/cbs.txt | 218 +++++---------------- mps/design/index.txt | 1 + mps/design/land.txt | 292 +++++++++++++++++++++++++++++ mps/manual/source/design/index.rst | 1 + 5 files changed, 341 insertions(+), 173 deletions(-) create mode 100644 mps/design/land.txt diff --git a/mps/code/arena.c b/mps/code/arena.c index b63ef84748a..8f0bfcf43ff 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -19,7 +19,7 @@ SRCID(arena, "$Id$"); #define ArenaControlPool(arena) MV2Pool(&(arena)->controlPoolStruct) #define ArenaCBSBlockPool(arena) (&(arena)->freeCBSBlockPoolStruct.poolStruct) -#define ArenaFreeLand(arena) ((Land)&(arena)->freeLandStruct) +#define ArenaFreeLand(arena) (&(arena)->freeLandStruct.landStruct) /* Forward declarations */ diff --git a/mps/design/cbs.txt b/mps/design/cbs.txt index 6531cd02090..051889087d9 100644 --- a/mps/design/cbs.txt +++ b/mps/design/cbs.txt @@ -29,50 +29,24 @@ high level communication with the client about the size of contiguous ranges, and detection of protocol violations. -Definitions ------------ - -_`.def.range`: A (contiguous) *range* of addresses is a semi-open -interval on address space. - -_`.def.isolated`: A contiguous range is *isolated* with respect to -some property it has, if adjacent elements do not have that property. - - Requirements ------------ -_`.req.set`: Must maintain a set of addresses. +In addition to the generic land requirements (see +design.mps.land.req), the CBS must satisfy: _`.req.fast`: Common operations must have a low amortized cost. -_`.req.add`: Must be able to add address ranges to the set. - -_`.req.remove`: Must be able to remove address ranges from the set. - -_`.req.size`: Must report concisely to the client when isolated -contiguous ranges of at least a certain size appear and disappear. - -_`.req.iterate`: Must support the iteration of all isolated -contiguous ranges. This will not be a common operation. - -_`.req.protocol`: Must detect protocol violations. - -_`.req.debug`: Must support debugging of client code. - _`.req.small`: Must have a small space overhead for the storage of typical subsets of address space and not have abysmal overhead for the storage of any subset of address space. -_`.req.align`: Must support an alignment (the alignment of all -addresses specifying ranges) of down to ``sizeof(void *)`` without -losing memory. - Interface --------- -_`.header`: CBS is used through impl.h.cbs. +_`.land`: The interface to CBS is the generic functions for the *land* +abstract data type. See `design.mps.land `_. External types @@ -80,147 +54,51 @@ External types ``typedef struct CBSStruct *CBS`` -_`.type.cbs`: ``CBS`` is the main data structure for manipulating a -CBS. It is intended that a ``CBSStruct`` be embedded in another -structure. No convenience functions are provided for the allocation or -deallocation of the CBS. - -``typedef Bool (*CBSIterateMethod)(CBS cbs, Range range, void *closureP, Size closureS)`` - -_`.type.cbs.iterate.method`: Type ``CBSIterateMethod`` is a callback -function that may be passed to ``CBSIterate()``. It is called for -every isolated contiguous range in address order. The function must -returns a ``Bool`` indicating whether to continue with the iteration. +_`.type.cbs`: A ``CBSStruct`` may be embedded in another structure, or +you can create it using ``LandCreate()``. External functions .................. -``Res CBSInit(Arena arena, CBS cbs, void *owner, Align alignment, Bool fastFind, ArgList args)`` +``LandClass CBSLandClassGet(void)`` -_`.function.cbs.init`: ``CBSInit()`` is the function that initialises -the CBS structure. It performs allocation in the supplied arena. The -parameter ``owner`` is passed to ``MeterInit()``, an ``alignment`` -indicates the alignment of ranges to be maintained. An initialised CBS -contains no ranges. - -``fastFind``, if set, causes the CBS to maintain, for each subtree, -the size of the largest block in that subtree. This must be true if -any of the ``CBSFindFirst()``, ``CBSFindLast()``, or -``CBSFindLargest()`` functions are going to be used on the CBS. - -``CBSInit()`` may take one keyword argument: - -* ``MPS_KEY_CBS_EXTEND_BY`` (type ``Size``; default 4096) is the size - of segment that the CBS will request from the arena in which to - allocate its ``CBSBlock`` structures. - -``void CBSFinish(CBS cbs)`` - -_`.function.cbs.finish`: ``CBSFinish()`` is the function that finishes -the CBS structure and discards any other resources associated with the -CBS. - -``Res CBSInsert(Range rangeReturn, CBS cbs, Range range)`` - -_`.function.cbs.insert`: If any part of ``range`` is already in the -CBS, then leave it unchanged and return ``ResFAIL``. Otherwise, -attempt to insert ``range`` into the CBS. If the insertion succeeds, -then update ``rangeReturn`` to describe the contiguous isolated range -containing the inserted range (this may differ from ``range`` if there -was coalescence on either side) and return ``ResOK``. If the insertion -fails, return a result code indicating allocation failure. - -_`.function.cbs.insert.fail`: Insertion of a valid range (that is, one -that does not overlap with any range in the CBS) can only fail if the -new range is isolated and the allocation of the necessary data -structure to represent it failed. +_`.function.class`: The function ``CBSLandClassGet()`` returns the CBS +class, a subclass of ``LandClass`` suitable for passing to +``LandCreate()`` or ``LandInit()``. -``Res CBSDelete(Range rangeReturn, CBS cbs, Range range)`` +Keyword arguments +................. -_`.function.cbs.delete`: If any part of the range is not in the CBS, -then leave the CBS unchanged and return ``ResFAIL``. Otherwise, update -``rangeReturn`` to describe the contiguous isolated range that -contains ``range`` (this may differ from ``range`` if there are -fragments on either side) and attempt to delete the range from the -CBS. If the deletion succeeds, return ``ResOK``. If the deletion -fails, return a result code indicating allocation failure. +When initializing a CBS, ``LandCreate()`` and ``LandInit()`` take the +following optional keyword arguments: -_`.function.cbs.delete.fail`: Deletion of a valid range (that is, one -that is wholly contained in the CBS) can only fail if there are -fragments on both sides and the allocation of the necessary data -structures to represent them fails. +* ``CBSBlockPool`` (type ``Pool``) is the pool from which the CBS + block descriptors will be allocated. If omitted, a new MFS pool is + created for this purpose. -_`.function.cbs.delete.return`: ``CBSDelete()`` returns the contiguous -isolated range that contains ``range`` even if the deletion fails. -This is so that the caller can try deleting the whole block (which is -guaranteed to succeed) and managing the fragments using a fallback -strategy. +* ``MPS_KEY_CBS_EXTEND_BY`` (type ``Size``; default 4096) is passed as + the ``MPS_KEY_EXTEND_BY`` keyword argument to ``PoolCreate()`` if a + block descriptor pool is created. It specifies the size of segment + that the block descriptor pool will request from the arena. -``void CBSIterate(CBS cbs, CBSIterateMethod iterate, void *closureP, Size closureS)`` +* ``MFSExtendSelf`` (type ``Bool``; default ``TRUE``) is passed to + ``PoolCreate()`` if a block descriptor pool is created. If ``TRUE``, + the block descriptor pool automatically extends itself when out of + space; if ``FALSE``, the pool returns ``ResLIMIT`` in this case. + (This feature is used by the arena to bootstrap its own CBS of free + memory.) -_`.function.cbs.iterate`: ``CBSIterate()`` is the function used to -iterate all isolated contiguous ranges in a CBS. It receives a -pointer, ``Size`` closure pair to pass on to the iterator method, -and an iterator method to invoke on every range in address order. If -the iterator method returns ``FALSE``, then the iteration is -terminated. +* ``CBSFastFind`` (type ``Bool``; default ``FALSE``). If ``TRUE``, + causes the CBS to maintain, for each subtree, the size of the + largest block in that subtree. This enables the ``LandFindFirst()``, + ``LandFindLast()``, and ``LandFindLargest()`` generic functions. -``Res CBSDescribe(CBS cbs, mps_lib_FILE *stream)`` - -_`.function.cbs.describe`: ``CBSDescribe()`` is a function that prints -a textual representation of the CBS to the given stream, indicating -the contiguous ranges in order, as well as the structure of the -underlying splay tree implementation. It is provided for debugging -purposes only. - -``Bool CBSFindFirst(Range rangeReturn, Range oldRangeReturn, CBS cbs, Size size, FindDelete findDelete)`` - -_`.function.cbs.find.first`: Locate the first block (in address order) -within the CBS of at least the specified size, update ``rangeReturn`` -to describe that range, and return ``TRUE``. If there is no such -block, it returns ``FALSE``. - -In addition, optionally delete the top, bottom, or all of the found -range, depending on the ``findDelete`` argument. This saves a separate -call to ``CBSDelete()``, and uses the knowledge of exactly where we -found the range. The value of ``findDelete`` must come from this -enumeration:: - - enum { - FindDeleteNONE, /* don't delete after finding */ - FindDeleteLOW, /* delete size bytes from low end of block */ - FindDeleteHIGH, /* delete size bytes from high end of block */ - FindDeleteENTIRE /* delete entire range */ - }; - -The original contiguous isolated range in which the range was found is -returned via the ``oldRangeReturn`` argument. (If ``findDelete`` is -``FindDeleteNONE`` or ``FindDeleteENTIRE``, then this will be -identical to the range returned via the ``rangeReturn`` argument.) - -``CBSFindFirst()`` requires that ``fastFind`` was true when -``CBSInit()`` was called. - -``Bool CBSFindLast(Range rangeReturn, Range oldRangeReturn, CBS cbs, Size size, FindDelete findDelete)`` - -_`.function.cbs.find.last`: Like ``CBSFindFirst()``, except that it -finds the last block in address order. - -``Bool CBSFindLargest(Range rangeReturn, Range oldRangeReturn, CBS cbs, Size size, FindDelete findDelete)`` - -_`.function.cbs.find.largest`: Locate the largest block within the -CBS, and if that block is at least as big as ``size``, return its -range via the ``rangeReturn`` argument, and return ``TRUE``. If there -are no blocks in the CBS at least as large as ``size``, return -``FALSE``. Pass 0 for ``size`` if you want the largest block -unconditionally. - -Like ``CBSFindFirst()``, optionally delete the range (specifying -``FindDeleteLOW`` or ``FindDeleteHIGH`` has the same effect as -``FindDeleteENTIRE``). This feature requires that ``fastFind`` was -true when ``CBSInit()`` was called. +* ``CBSZoned`` (type ``Bool``; default ``FALSE``). If ``TRUE``, caused + the CBS to maintain, for each subtree, the union of the zone sets of + all ranges in that subtree. This enables the ``LandFindInZones()`` + generic function. Implementation @@ -241,19 +119,19 @@ for comparison is the base of another range. .. _design.mps.splay: splay -_`.impl.splay.fast-find`: ``CBSFindFirst()`` and ``CBSFindLast()`` use +_`.impl.splay.fast-find`: ``cbsFindFirst()`` and ``cbsFindLast()`` use the update/refresh facility of splay trees to store, in each ``CBSBlock``, an accurate summary of the maximum block size in the tree rooted at the corresponding splay node. This allows rapid location of the first or last suitable block, and very rapid failure if there is no suitable block. -_`.impl.find-largest`: ``CBSFindLargest()`` simply finds out the size +_`.impl.find-largest`: ``cbsFindLargest()`` simply finds out the size of the largest block in the CBS from the root of the tree, using ``SplayRoot()``, and does ``SplayFindFirst()`` for a block of that size. This takes time proportional to the logarithm of the size of the free list, so it's about the best you can do without maintaining a -separate priority queue, just to do ``CBSFindLargest()``. +separate priority queue, just to do ``cbsFindLargest()``. Low memory behaviour @@ -261,10 +139,10 @@ Low memory behaviour _`.impl.low-mem`: When the CBS tries to allocate a new ``CBSBlock`` structure for a new isolated range as a result of either -``CBSInsert()`` or ``CBSDelete()``, and there is insufficient memory +``LandInsert()`` or ``LandDelete()``, and there is insufficient memory to allocation the ``CBSBlock`` structure, then the range is not added -to the CBS or deleted from it, and the call to ``CBSInsert()`` or -``CBSDelete()`` returns ``ResMEMORY``. +to the CBS or deleted from it, and the call to ``LandInsert()`` or +``LandDelete()`` returns ``ResMEMORY``. The CBS block @@ -285,15 +163,8 @@ Testing _`.test`: The following testing will be performed on this module: -_`.test.cbstest`: There is a stress test for this module in -impl.c.cbstest. This allocates a large block of memory and then -simulates the allocation and deallocation of ranges within this block -using both a ``CBS`` and a ``BT``. It makes both valid and invalid -requests, and compares the ``CBS`` response to the correct behaviour -as determined by the ``BT``. It also iterates the ranges in the -``CBS``, comparing them to the ``BT``. It also invokes the -``CBSDescribe()`` method, but makes no automatic test of the resulting -output. It does not currently test the callbacks. +_`.test.fbmtest`: A generic test for land implementations. See +design.mps.land.fbmtest. _`.test.pool`: Several pools (currently MVT_ and MVFF_) are implemented on top of a CBS. These pool are subject to testing in development, QA, @@ -359,6 +230,9 @@ Document History talking about the deleted "emergency" free list allocator. Documented ``fastFind`` argument to ``CBSInit()``. +- 2014-04-01 GDR_ Moved generic material to design.mps.land. + Documented new keyword arguments. + .. _RB: http://www.ravenbrook.com/consultants/rb/ .. _GDR: http://www.ravenbrook.com/consultants/gdr/ diff --git a/mps/design/index.txt b/mps/design/index.txt index b47c04bbcc6..251d598a102 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -59,6 +59,7 @@ guide.impl.c.format_ Coding standard: conventions for the general format of C interface-c_ The design of the Memory Pool System interface to C io_ The design of the MPS I/O subsystem keyword-arguments_ The design of the MPS mechanism for passing arguments by keyword. +land_ Lands (collections of address ranges) lib_ The design of the Memory Pool System library interface lock_ The design of the lock module locus_ The design for the locus manager diff --git a/mps/design/land.txt b/mps/design/land.txt new file mode 100644 index 00000000000..fcbdde02ab1 --- /dev/null +++ b/mps/design/land.txt @@ -0,0 +1,292 @@ +.. mode: -*- rst -*- + +Lands +===== + +:Tag: design.mps.land +:Author: Gareth Rees +:Date: 2014-04-01 +:Status: incomplete design +:Revision: $Id$ +:Copyright: See section `Copyright and License`_. + + +Introduction +------------ + +_`.intro`: This is the design of the *land* abstract data type, which +represents a collection of contiguous address ranges. + +_`.readership`: This document is intended for any MPS developer. + +_`.source`: `design.mps.cbs `_, `design.mps.freelist `_. + +_`.overview`: Collections of address ranges are used in several places +in the MPS: the arena stores a set of mapped address ranges; pools +store sets of address ranges which have been acquired from the arena +and sets of address ranges that are available for allocation. The +*land* abstract data type makes it easy to try out different +implementations with different performance characteristics and other +attributes. + +_`.name`: The name is inspired by *rangeland* meaning *group of +ranges* (where *ranges* is used in the sense *grazing areas*). + + +Definitions +----------- + +_`.def.range`: A (contiguous) *range* of addresses is a semi-open +interval on address space. + +_`.def.isolated`: A contiguous range is *isolated* with respect to +some property it has, if adjacent elements do not have that property. + + +Requirements +------------ + +_`.req.set`: Must maintain a set of addresses. + +_`.req.add`: Must be able to add address ranges to the set. + +_`.req.remove`: Must be able to remove address ranges from the set. + +_`.req.size`: Must report concisely to the client when isolated +contiguous ranges of at least a certain size appear and disappear. + +_`.req.iterate`: Must support the iteration of all isolated +contiguous ranges. + +_`.req.protocol`: Must detect protocol violations. + +_`.req.debug`: Must support debugging of client code. + +_`.req.align`: Must support an alignment (the alignment of all +addresses specifying ranges) of down to ``sizeof(void *)`` without +losing memory. + + +Interface +--------- + +Types +..... + +``typedef LandStruct *Land;`` + +_`.type.land`: The type of a generic land instance. + +``typedef Bool (*LandVisitor)(Land land, Range range, void *closureP, Size closureS);`` + +_`.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. + + +Generic functions +................. + +``Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *owner, ArgList args)`` + +_`.function.init`: ``LandInit()`` initializes the land structure for +the given class. The land will perform allocation (if necessary -- not +all land classes need to allocate) in the supplied arena. The +``alignment`` parameter is the alignment of the address ranges that +will be stored and retrieved from the land. The parameter ``owner`` is +output as a parameter to the ``LandInit`` event. The newly initialized +land contains no ranges. + +``Res LandCreate(Land *landReturn, Arena arena, LandClass class, Align alignment, void *owner, ArgList args)`` + +_`.function.create`: ``LandCreate()`` allocates memory for a land +structure of the given class in ``arena``, and then passes all +parameters to ``LandInit()``. + +``void LandDestroy(Land land)`` + +_`.function.destroy`: ``LandDestroy()`` calls ``LandFinish()`` to +finish the land structure, and then frees its memory. + +``void LandFinish(Land land)`` + +_`.function.finish`: ``LandFinish()`` finishes the land structure and +discards any other resources associated with the land. + +``Res LandInsert(Range rangeReturn, Land land, Range range)`` + +_`.function.insert`: If any part of ``range`` is already in the +land, then leave it unchanged and return ``ResFAIL``. Otherwise, +attempt to insert ``range`` into the land. If the insertion succeeds, +then update ``rangeReturn`` to describe the contiguous isolated range +containing the inserted range (this may differ from ``range`` if there +was coalescence on either side) and return ``ResOK``. If the insertion +fails, return a result code indicating allocation failure. + +_`.function.insert.fail`: Insertion of a valid range (that is, one +that does not overlap with any range in the land) can only fail if the +new range is isolated and the allocation of the necessary data +structure to represent it failed. + +``Res LandDelete(Range rangeReturn, Land land, Range range)`` + +_`.function.delete`: If any part of the range is not in the land, +then leave the land unchanged and return ``ResFAIL``. Otherwise, update +``rangeReturn`` to describe the contiguous isolated range that +contains ``range`` (this may differ from ``range`` if there are +fragments on either side) and attempt to delete the range from the +land. If the deletion succeeds, return ``ResOK``. If the deletion +fails, return a result code indicating allocation failure. + +_`.function.delete.fail`: Deletion of a valid range (that is, one +that is wholly contained in the land) can only fail if there are +fragments on both sides and the allocation of the necessary data +structures to represent them fails. + +_`.function.delete.return`: ``LandDelete()`` returns the contiguous +isolated range that contains ``range`` even if the deletion fails. +This is so that the caller can try deleting the whole block (which is +guaranteed to succeed) and managing the fragments using a fallback +strategy. + +``void LandIterate(Land land, LandIterateMethod iterate, void *closureP, Size closureS)`` + +_`.function.iterate`: ``LandIterate()`` is the function used to +iterate all isolated contiguous ranges in a land. It receives a +pointer, ``Size`` closure pair to pass on to the iterator method, +and an iterator method to invoke on every range in address order. If +the iterator method returns ``FALSE``, then the iteration is +terminated. + +``Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)`` + +_`.function.find.first`: Locate the first block (in address order) +within the land of at least the specified size, update ``rangeReturn`` +to describe that range, and return ``TRUE``. If there is no such +block, it returns ``FALSE``. + +In addition, optionally delete the top, bottom, or all of the found +range, depending on the ``findDelete`` argument. This saves a separate +call to ``LandDelete()``, and uses the knowledge of exactly where we +found the range. The value of ``findDelete`` must come from this +enumeration:: + + enum { + FindDeleteNONE, /* don't delete after finding */ + FindDeleteLOW, /* delete size bytes from low end of block */ + FindDeleteHIGH, /* delete size bytes from high end of block */ + FindDeleteENTIRE /* delete entire range */ + }; + +The original contiguous isolated range in which the range was found is +returned via the ``oldRangeReturn`` argument. (If ``findDelete`` is +``FindDeleteNONE`` or ``FindDeleteENTIRE``, then this will be +identical to the range returned via the ``rangeReturn`` argument.) + +``Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)`` + +_`.function.find.last`: Like ``LandFindFirst()``, except that it +finds the last block in address order. + +``Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)`` + +_`.function.find.largest`: Locate the largest block within the +land, and if that block is at least as big as ``size``, return its +range via the ``rangeReturn`` argument, and return ``TRUE``. If there +are no blocks in the land at least as large as ``size``, return +``FALSE``. Pass 0 for ``size`` if you want the largest block +unconditionally. + +Like ``LandFindFirst()``, optionally delete the range (specifying +``FindDeleteLOW`` or ``FindDeleteHIGH`` has the same effect as +``FindDeleteENTIRE``), and return the original contiguous isolated +range in which the range was found via the ``oldRangeReturn`` +argument. + +``Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high)`` + +_`.function.find.zones`: Locate a block at least as big as ``size`` +that lies entirely within the ``zoneSet``, return its range via the +``rangeReturn`` argument, and return ``TRUE``. (The first such block, +if ``high`` is ``FALSE``, or the last, if ``high`` is ``TRUE``.) If +there is no such block, , return ``FALSE``. + +Delete the range as for ``LandFindFirst()`` and ``LastFindLast()`` +(with the effect of ``FindDeleteLOW`` if ``high`` is ``FALSE`` and the +effect of ``FindDeleteHIGH`` if ``high`` is ``TRUE``), and return the +original contiguous isolated range in which the range was found via +the ``oldRangeReturn`` argument. + +``Res LandDescribe(Land land, mps_lib_FILE *stream)`` + +_`.function.describe`: ``LandDescribe()`` is a function that prints +a textual representation of the land to the given stream, indicating +the contiguous ranges in order, as well as the structure of the +underlying splay tree implementation. It is provided for debugging +purposes only. + + +Testing +------- + +_`.test.fbmtest`: There is a stress test for implementations of this +interface in impl.c.fbmtest. This allocates a large block of memory +and then simulates the allocation and deallocation of ranges within +this block using both a ``Land`` and a ``BT``. It makes both valid and +invalid requests, and compares the ``Land`` response to the correct +behaviour as determined by the ``BT``. It iterates the ranges in the +``Land``, comparing them to the ``BT``. It invokes the +``LandDescribe()`` generic function, but makes no automatic test of +the resulting output. + + +Document History +---------------- + +- 2014-04-01 GDR_ Created based on `design.mps.cbs `_. + +.. _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/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 3cf6719ac74..f87cfdadaa2 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -14,6 +14,7 @@ Design guide.hex.trans guide.impl.c.format keyword-arguments + land range ring sig From 10c511ff58c92e149b986b27b5fd1ce2a2a0e53c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 1 Apr 2014 23:39:03 +0100 Subject: [PATCH 028/266] Landiargs -> liargs for terseness and consistency. Copied from Perforce Change: 185147 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 14 +++++++------- mps/code/poolmv2.c | 8 ++++---- mps/code/poolmvff.c | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 8f0bfcf43ff..afdb815f232 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -233,13 +233,13 @@ Res ArenaInit(Arena arena, ArenaClass class, Align alignment, ArgList args) goto failMFSInit; /* Initialise the freeLand. */ - MPS_ARGS_BEGIN(landiArgs) { - MPS_ARGS_ADD(landiArgs, CBSBlockPool, ArenaCBSBlockPool(arena)); - MPS_ARGS_ADD(landiArgs, CBSFastFind, TRUE); - MPS_ARGS_ADD(landiArgs, CBSZoned, arena->zoned); - MPS_ARGS_DONE(landiArgs); - res = LandInit(ArenaFreeLand(arena), CBSLandClassGet(), arena, alignment, arena, landiArgs); - } MPS_ARGS_END(landiArgs); + MPS_ARGS_BEGIN(liArgs) { + MPS_ARGS_ADD(liArgs, CBSBlockPool, ArenaCBSBlockPool(arena)); + MPS_ARGS_ADD(liArgs, CBSFastFind, TRUE); + MPS_ARGS_ADD(liArgs, CBSZoned, arena->zoned); + MPS_ARGS_DONE(liArgs); + res = LandInit(ArenaFreeLand(arena), CBSLandClassGet(), arena, alignment, arena, liArgs); + } MPS_ARGS_END(liArgs); AVER(res == ResOK); /* no allocation, no failure expected */ if (res != ResOK) goto failLandInit; diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index f3de433a5ef..03cd5bc4765 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -269,10 +269,10 @@ static Res MVTInit(Pool pool, ArgList args) if (abqDepth < 3) abqDepth = 3; - MPS_ARGS_BEGIN(landiArgs) { - MPS_ARGS_ADD(landiArgs, CBSFastFind, TRUE); - res = LandInit(MVTCBS(mvt), CBSLandClassGet(), arena, align, mvt, landiArgs); - } MPS_ARGS_END(landiArgs); + MPS_ARGS_BEGIN(liArgs) { + MPS_ARGS_ADD(liArgs, CBSFastFind, TRUE); + res = LandInit(MVTCBS(mvt), CBSLandClassGet(), arena, align, mvt, liArgs); + } MPS_ARGS_END(liArgs); if (res != ResOK) goto failCBS; diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index f1679e5acaa..fa5250c7011 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -602,10 +602,10 @@ static Res MVFFInit(Pool pool, ArgList args) if (res != ResOK) goto failInit; - MPS_ARGS_BEGIN(landiArgs) { - MPS_ARGS_ADD(landiArgs, CBSFastFind, TRUE); - res = LandInit(CBSOfMVFF(mvff), CBSLandClassGet(), arena, align, mvff, landiArgs); - } MPS_ARGS_END(landiArgs); + MPS_ARGS_BEGIN(liArgs) { + MPS_ARGS_ADD(liArgs, CBSFastFind, TRUE); + res = LandInit(CBSOfMVFF(mvff), CBSLandClassGet(), arena, align, mvff, liArgs); + } MPS_ARGS_END(liArgs); if (res != ResOK) goto failInit; From e5bc35b28fa4abc17560603abea9435848120e5b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 2 Apr 2014 12:16:38 +0100 Subject: [PATCH 029/266] Avoid type puns. Copied from Perforce Change: 185151 ServerID: perforce.ravenbrook.com --- mps/code/fbmtest.c | 2 +- mps/code/poolmv2.c | 2 +- mps/code/poolmvff.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mps/code/fbmtest.c b/mps/code/fbmtest.c index b4072d929af..97776deab40 100644 --- a/mps/code/fbmtest.c +++ b/mps/code/fbmtest.c @@ -558,7 +558,7 @@ extern int main(int argc, char *argv[]) BT allocTable; FreelistStruct flStruct; CBSStruct cbsStruct; - Land land = (Land)&cbsStruct; + Land land = &cbsStruct.landStruct; Align align; testlib_init(argc, argv); diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index 03cd5bc4765..05252eaca8f 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -170,7 +170,7 @@ static ABQ MVTABQ(MVT mvt) static Land MVTCBS(MVT mvt) { - return (Land)(&mvt->cbsStruct); + return &mvt->cbsStruct.landStruct; } diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index fa5250c7011..8e0f985b757 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -58,7 +58,7 @@ typedef struct MVFFStruct { /* MVFF pool outer structure */ #define Pool2MVFF(pool) PARENT(MVFFStruct, poolStruct, pool) #define MVFF2Pool(mvff) (&((mvff)->poolStruct)) -#define CBSOfMVFF(mvff) ((Land)&((mvff)->cbsStruct)) +#define CBSOfMVFF(mvff) (&((mvff)->cbsStruct.landStruct)) #define MVFFOfCBS(cbs) PARENT(MVFFStruct, cbsStruct, cbs) #define FreelistOfMVFF(mvff) (&((mvff)->flStruct)) #define MVFFOfFreelist(fl) PARENT(MVFFStruct, flStruct, fl) From 6ef8e57b1fe32be2d9dcaa7d0337fde2ae72ca0e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 2 Apr 2014 14:01:18 +0100 Subject: [PATCH 030/266] Turn freelist into a land class. Copied from Perforce Change: 185155 ServerID: perforce.ravenbrook.com --- mps/code/cbs.c | 12 +- mps/code/comm.gmk | 8 +- mps/code/commpost.nmk | 6 +- mps/code/commpre.nmk | 2 +- mps/code/freelist.c | 167 ++++++++++++---------- mps/code/freelist.h | 36 +---- mps/code/land.c | 122 ++++++++++++++++ mps/code/{fbmtest.c => landtest.c} | 188 ++++++++----------------- mps/code/mpm.h | 1 + mps/code/mpmst.h | 20 ++- mps/code/mpmtypes.h | 8 +- mps/code/mps.xcodeproj/project.pbxproj | 30 ++-- mps/code/poolmv2.c | 104 +++++--------- mps/code/poolmvff.c | 35 +++-- mps/design/cbs.txt | 55 ++++++-- mps/design/freelist.txt | 184 ++++++------------------ mps/design/land.txt | 44 +++--- mps/tool/testrun.bat | 2 +- mps/tool/testrun.sh | 2 +- 19 files changed, 492 insertions(+), 534 deletions(-) rename mps/code/{fbmtest.c => landtest.c} (79%) diff --git a/mps/code/cbs.c b/mps/code/cbs.c index bf02c9d7737..bfd21af7746 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -26,7 +26,7 @@ SRCID(cbs, "$Id$"); #define CBSBlockSize(block) AddrOffset((block)->base, (block)->limit) -#define cbsOfLand(land) ((CBS)(land)) +#define cbsOfLand(land) PARENT(CBSStruct, landStruct, land) #define cbsSplay(cbs) (&((cbs)->splayTreeStruct)) #define cbsOfSplay(_splay) PARENT(CBSStruct, splayTreeStruct, _splay) #define cbsBlockTree(block) (&((block)->treeStruct)) @@ -720,7 +720,7 @@ static Res cbsSplayNodeDescribe(Tree tree, mps_lib_FILE *stream) typedef struct CBSIterateClosure { Land land; - LandVisitor iterate; + LandVisitor visitor; void *closureP; Size closureS; } CBSIterateClosure; @@ -732,12 +732,16 @@ static Bool cbsIterateVisit(Tree tree, void *closureP, Size closureS) CBSBlock cbsBlock; Land land = closure->land; CBS cbs = cbsOfLand(land); + Bool delete = FALSE; + Bool cont = TRUE; UNUSED(closureS); cbsBlock = cbsBlockOfTree(tree); RangeInit(&range, CBSBlockBase(cbsBlock), CBSBlockLimit(cbsBlock)); - if (!closure->iterate(land, &range, closure->closureP, closure->closureS)) + cont = (*closure->visitor)(&delete, land, &range, closure->closureP, closure->closureS); + AVER(!delete); + if (!cont) return FALSE; METER_ACC(cbs->treeSearch, cbs->treeSize); return TRUE; @@ -762,7 +766,7 @@ static void cbsIterate(Land land, LandVisitor visitor, METER_ACC(cbs->treeSearch, cbs->treeSize); closure.land = land; - closure.iterate = visitor; + closure.visitor = visitor; closure.closureP = closureP; closure.closureS = closureS; (void)TreeTraverse(SplayTreeRoot(splay), splay->compare, splay->nodeKey, diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index ff915aaa5e3..beeb542fca9 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -280,11 +280,11 @@ TEST_TARGETS=\ djbench \ exposet0 \ expt825 \ - fbmtest \ finalcv \ finaltest \ fotest \ gcbench \ + landtest \ locbwcss \ lockcov \ locusss \ @@ -452,9 +452,6 @@ $(PFM)/$(VARIETY)/exposet0: $(PFM)/$(VARIETY)/exposet0.o \ $(PFM)/$(VARIETY)/expt825: $(PFM)/$(VARIETY)/expt825.o \ $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a -$(PFM)/$(VARIETY)/fbmtest: $(PFM)/$(VARIETY)/fbmtest.o \ - $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a - $(PFM)/$(VARIETY)/finalcv: $(PFM)/$(VARIETY)/finalcv.o \ $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a @@ -467,6 +464,9 @@ $(PFM)/$(VARIETY)/fotest: $(PFM)/$(VARIETY)/fotest.o \ $(PFM)/$(VARIETY)/gcbench: $(PFM)/$(VARIETY)/gcbench.o \ $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a +$(PFM)/$(VARIETY)/landtest: $(PFM)/$(VARIETY)/landtest.o \ + $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a + $(PFM)/$(VARIETY)/locbwcss: $(PFM)/$(VARIETY)/locbwcss.o \ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk index 2406131db0c..78095f33714 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/commpost.nmk @@ -158,9 +158,6 @@ $(PFM)\$(VARIETY)\exposet0.exe: $(PFM)\$(VARIETY)\exposet0.obj \ $(PFM)\$(VARIETY)\expt825.exe: $(PFM)\$(VARIETY)\expt825.obj \ $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) -$(PFM)\$(VARIETY)\fbmtest.exe: $(PFM)\$(VARIETY)\fbmtest.obj \ - $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) - $(PFM)\$(VARIETY)\finalcv.exe: $(PFM)\$(VARIETY)\finalcv.obj \ $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) @@ -170,6 +167,9 @@ $(PFM)\$(VARIETY)\finaltest.exe: $(PFM)\$(VARIETY)\finaltest.obj \ $(PFM)\$(VARIETY)\fotest.exe: $(PFM)\$(VARIETY)\fotest.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) +$(PFM)\$(VARIETY)\landtest.exe: $(PFM)\$(VARIETY)\landtest.obj \ + $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) + $(PFM)\$(VARIETY)\locbwcss.exe: $(PFM)\$(VARIETY)\locbwcss.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index 0c8e68a90f9..75dbdad446e 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -66,10 +66,10 @@ TEST_TARGETS=\ bttest.exe \ exposet0.exe \ expt825.exe \ - fbmtest.exe \ finalcv.exe \ finaltest.exe \ fotest.exe \ + landtest.exe \ locbwcss.exe \ lockcov.exe \ lockutw3.exe \ diff --git a/mps/code/freelist.c b/mps/code/freelist.c index a299dafb6e6..14091c02558 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -12,10 +12,14 @@ SRCID(freelist, "$Id$"); +#define freelistOfLand(land) PARENT(FreelistStruct, landStruct, land) +#define freelistAlignment(fl) LandAlignment(&fl->landStruct) + + typedef union FreelistBlockUnion { struct { FreelistBlock next; /* tagged with low bit 1 */ - /* limit is (char *)this + fl->alignment */ + /* limit is (char *)this + freelistAlignment(fl) */ } small; struct { FreelistBlock next; @@ -50,7 +54,7 @@ static Addr FreelistBlockLimit(Freelist fl, FreelistBlock block) { AVERT(Freelist, fl); if (FreelistBlockIsSmall(block)) { - return AddrAdd(FreelistBlockBase(block), fl->alignment); + return AddrAdd(FreelistBlockBase(block), freelistAlignment(fl)); } else { return block->large.limit; } @@ -104,7 +108,7 @@ static void FreelistBlockSetLimit(Freelist fl, FreelistBlock block, Addr limit) AVERT(Freelist, fl); AVERT(FreelistBlock, block); - AVER(AddrIsAligned(limit, fl->alignment)); + AVER(AddrIsAligned(limit, freelistAlignment(fl))); AVER(FreelistBlockBase(block) < limit); size = AddrOffset(block, limit); @@ -127,9 +131,9 @@ static FreelistBlock FreelistBlockInit(Freelist fl, Addr base, Addr limit) AVERT(Freelist, fl); AVER(base != NULL); - AVER(AddrIsAligned(base, fl->alignment)); + AVER(AddrIsAligned(base, freelistAlignment(fl))); AVER(base < limit); - AVER(AddrIsAligned(limit, fl->alignment)); + AVER(AddrIsAligned(limit, freelistAlignment(fl))); block = (FreelistBlock)base; block->small.next = FreelistTagSet(NULL); @@ -141,21 +145,34 @@ static FreelistBlock FreelistBlockInit(Freelist fl, Addr base, Addr limit) Bool FreelistCheck(Freelist fl) { + Land land; CHECKS(Freelist, fl); + land = &fl->landStruct; + CHECKL(LandCheck(land)); /* See */ - CHECKL(AlignIsAligned(fl->alignment, freelistMinimumAlignment)); + CHECKL(AlignIsAligned(LandAlignment(land), freelistMinimumAlignment)); CHECKL((fl->list == NULL) == (fl->listSize == 0)); return TRUE; } -Res FreelistInit(Freelist fl, Align alignment) +static Res freelistInit(Land land, ArgList args) { + Freelist fl; + LandClass super; + Res res; + + AVERT(Land, land); + super = LAND_SUPERCLASS(FreelistLandClass); + res = (*super->init)(land, args); + if (res != ResOK) + return res; + /* See */ - if (!AlignIsAligned(alignment, freelistMinimumAlignment)) + if (!AlignIsAligned(LandAlignment(land), freelistMinimumAlignment)) return ResPARAM; - fl->alignment = alignment; + fl = freelistOfLand(land); fl->list = NULL; fl->listSize = 0; @@ -165,8 +182,12 @@ Res FreelistInit(Freelist fl, Align alignment) } -void FreelistFinish(Freelist fl) +static void freelistFinish(Land land) { + Freelist fl; + + AVERT(Land, land); + fl = freelistOfLand(land); AVERT(Freelist, fl); fl->sig = SigInvalid; fl->list = NULL; @@ -200,16 +221,19 @@ static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev, } -Res FreelistInsert(Range rangeReturn, Freelist fl, Range range) +static Res freelistInsert(Range rangeReturn, Land land, Range range) { + Freelist fl; FreelistBlock prev, cur, next, new; Addr base, limit; Bool coalesceLeft, coalesceRight; AVER(rangeReturn != NULL); + AVERT(Land, land); + fl = freelistOfLand(land); AVERT(Freelist, fl); AVERT(Range, range); - AVER(RangeIsAligned(range, fl->alignment)); + AVER(RangeIsAligned(range, freelistAlignment(fl))); base = RangeBase(range); limit = RangeLimit(range); @@ -281,7 +305,7 @@ static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl, AVER(rangeReturn != NULL); AVERT(Freelist, fl); AVERT(Range, range); - AVER(RangeIsAligned(range, fl->alignment)); + AVER(RangeIsAligned(range, freelistAlignment(fl))); AVER(prev == NULL || FreelistBlockNext(prev) == block); AVERT(FreelistBlock, block); AVER(FreelistBlockBase(block) <= RangeBase(range)); @@ -319,12 +343,15 @@ static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl, } -Res FreelistDelete(Range rangeReturn, Freelist fl, Range range) +static Res freelistDelete(Range rangeReturn, Land land, Range range) { + Freelist fl; FreelistBlock prev, cur, next; Addr base, limit; AVER(rangeReturn != NULL); + AVERT(Land, land); + fl = freelistOfLand(land); AVERT(Freelist, fl); AVERT(Range, range); @@ -357,13 +384,16 @@ Res FreelistDelete(Range rangeReturn, Freelist fl, Range range) } -void FreelistIterate(Freelist fl, FreelistIterateMethod iterate, - void *closureP, Size closureS) +static void freelistIterate(Land land, LandVisitor visitor, + void *closureP, Size closureS) { + Freelist fl; FreelistBlock prev, cur, next; + AVERT(Land, land); + fl = freelistOfLand(land); AVERT(Freelist, fl); - AVER(FUNCHECK(iterate)); + AVER(FUNCHECK(visitor)); prev = NULL; cur = fl->list; @@ -372,7 +402,7 @@ void FreelistIterate(Freelist fl, FreelistIterateMethod iterate, RangeStruct range; Bool cont; RangeInit(&range, FreelistBlockBase(cur), FreelistBlockLimit(fl, cur)); - cont = (*iterate)(&delete, &range, closureP, closureS); + cont = (*visitor)(&delete, land, &range, closureP, closureS); next = FreelistBlockNext(cur); if (delete) { freelistBlockSetPrevNext(fl, prev, next, -1); @@ -405,7 +435,7 @@ static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn, AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); AVERT(Freelist, fl); - AVER(SizeIsAligned(size, fl->alignment)); + AVER(SizeIsAligned(size, freelistAlignment(fl))); AVERT(FindDelete, findDelete); AVER(prev == NULL || FreelistBlockNext(prev) == block); AVERT(FreelistBlock, block); @@ -445,15 +475,18 @@ static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn, } -Bool FreelistFindFirst(Range rangeReturn, Range oldRangeReturn, - Freelist fl, Size size, FindDelete findDelete) +static Bool freelistFindFirst(Range rangeReturn, Range oldRangeReturn, + Land land, Size size, FindDelete findDelete) { + Freelist fl; FreelistBlock prev, cur, next; AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); + AVERT(Land, land); + fl = freelistOfLand(land); AVERT(Freelist, fl); - AVER(SizeIsAligned(size, fl->alignment)); + AVER(SizeIsAligned(size, freelistAlignment(fl))); AVERT(FindDelete, findDelete); prev = NULL; @@ -473,17 +506,20 @@ Bool FreelistFindFirst(Range rangeReturn, Range oldRangeReturn, } -Bool FreelistFindLast(Range rangeReturn, Range oldRangeReturn, - Freelist fl, Size size, FindDelete findDelete) +static Bool freelistFindLast(Range rangeReturn, Range oldRangeReturn, + Land land, Size size, FindDelete findDelete) { + Freelist fl; Bool found = FALSE; FreelistBlock prev, cur, next; FreelistBlock foundPrev = NULL, foundCur = NULL; AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); + AVERT(Land, land); + fl = freelistOfLand(land); AVERT(Freelist, fl); - AVER(SizeIsAligned(size, fl->alignment)); + AVER(SizeIsAligned(size, freelistAlignment(fl))); AVERT(FindDelete, findDelete); prev = NULL; @@ -507,15 +543,18 @@ Bool FreelistFindLast(Range rangeReturn, Range oldRangeReturn, } -Bool FreelistFindLargest(Range rangeReturn, Range oldRangeReturn, - Freelist fl, Size size, FindDelete findDelete) +static Bool freelistFindLargest(Range rangeReturn, Range oldRangeReturn, + Land land, Size size, FindDelete findDelete) { + Freelist fl; Bool found = FALSE; FreelistBlock prev, cur, next; FreelistBlock bestPrev = NULL, bestCur = NULL; AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); + AVERT(Land, land); + fl = freelistOfLand(land); AVERT(Freelist, fl); AVERT(FindDelete, findDelete); @@ -541,19 +580,21 @@ Bool FreelistFindLargest(Range rangeReturn, Range oldRangeReturn, } -/* freelistDescribeIterateMethod -- Iterate method for - * FreelistDescribe. Writes a decription of the range into the stream - * pointed to by 'closureP'. +/* freelistDescribeVisitor -- visitor method for freelistDescribe. + * + * Writes a decription of the range into the stream pointed to by + * closureP. */ -static Bool freelistDescribeIterateMethod(Bool *deleteReturn, Range range, - void *closureP, Size closureS) +static Bool freelistDescribeVisitor(Bool *deleteReturn, Land land, Range range, + void *closureP, Size closureS) { Res res; mps_lib_FILE *stream = closureP; - AVER(deleteReturn != NULL); - AVERT(Range, range); - AVER(stream != NULL); + if (deleteReturn == NULL) return FALSE; + if (!TESTT(Land, land)) return FALSE; + if (!TESTT(Range, range)) return FALSE; + if (stream == NULL) return FALSE; UNUSED(closureS); res = WriteF(stream, @@ -562,64 +603,48 @@ static Bool freelistDescribeIterateMethod(Bool *deleteReturn, Range range, " {$U}\n", (WriteFU)RangeSize(range), NULL); - *deleteReturn = FALSE; return res == ResOK; } -Res FreelistDescribe(Freelist fl, mps_lib_FILE *stream) +static Res freelistDescribe(Land land, mps_lib_FILE *stream) { + Freelist fl; Res res; + if (!TESTT(Land, land)) return ResFAIL; + fl = freelistOfLand(land); if (!TESTT(Freelist, fl)) return ResFAIL; if (stream == NULL) return ResFAIL; res = WriteF(stream, "Freelist $P {\n", (WriteFP)fl, - " alignment = $U\n", (WriteFU)fl->alignment, " listSize = $U\n", (WriteFU)fl->listSize, NULL); - FreelistIterate(fl, freelistDescribeIterateMethod, stream, 0); + LandIterate(land, freelistDescribeVisitor, stream, 0); res = WriteF(stream, "}\n", NULL); return res; } -/* freelistFlushIterateMethod -- Iterate method for - * FreelistFlushToLand. Attempst to insert the range into the Land. - */ -static Bool freelistFlushIterateMethod(Bool *deleteReturn, Range range, - void *closureP, Size closureS) +typedef LandClassStruct FreelistLandClassStruct; + +DEFINE_CLASS(FreelistLandClass, class) { - Res res; - RangeStruct newRange; - Land land; - - AVER(deleteReturn != NULL); - AVERT(Range, range); - AVER(closureP != NULL); - UNUSED(closureS); - - land = closureP; - res = LandInsert(&newRange, land, range); - if (res == ResOK) { - *deleteReturn = TRUE; - return TRUE; - } else { - *deleteReturn = FALSE; - return FALSE; - } -} - - -void FreelistFlushToLand(Freelist fl, Land land) -{ - AVERT(Freelist, fl); - AVERT(Land, land); - - FreelistIterate(fl, freelistFlushIterateMethod, land, 0); + INHERIT_CLASS(class, LandClass); + class->name = "FREELIST"; + class->size = sizeof(FreelistStruct); + class->init = freelistInit; + class->finish = freelistFinish; + class->insert = freelistInsert; + class->delete = freelistDelete; + class->iterate = freelistIterate; + class->findFirst = freelistFindFirst; + class->findLast = freelistFindLast; + class->findLargest = freelistFindLargest; + class->describe = freelistDescribe; } diff --git a/mps/code/freelist.h b/mps/code/freelist.h index b9aea9bdf6c..1ba46ae338d 100644 --- a/mps/code/freelist.h +++ b/mps/code/freelist.h @@ -10,42 +10,10 @@ #define freelist_h #include "mpmtypes.h" -#include "range.h" -#define FreelistSig ((Sig)0x519F6331) /* SIGnature FREEL */ +extern Bool FreelistCheck(Freelist freelist); -typedef struct FreelistStruct *Freelist; -typedef union FreelistBlockUnion *FreelistBlock; - -typedef Bool (*FreelistIterateMethod)(Bool *deleteReturn, Range range, - void *closureP, Size closureS); - -typedef struct FreelistStruct { - Sig sig; - Align alignment; - FreelistBlock list; - Count listSize; -} FreelistStruct; - -extern Bool FreelistCheck(Freelist fl); -extern Res FreelistInit(Freelist fl, Align alignment); -extern void FreelistFinish(Freelist fl); - -extern Res FreelistInsert(Range rangeReturn, Freelist fl, Range range); -extern Res FreelistDelete(Range rangeReturn, Freelist fl, Range range); -extern Res FreelistDescribe(Freelist fl, mps_lib_FILE *stream); - -extern void FreelistIterate(Freelist abq, FreelistIterateMethod iterate, - void *closureP, Size closureS); - -extern Bool FreelistFindFirst(Range rangeReturn, Range oldRangeReturn, - Freelist fl, Size size, FindDelete findDelete); -extern Bool FreelistFindLast(Range rangeReturn, Range oldRangeReturn, - Freelist fl, Size size, FindDelete findDelete); -extern Bool FreelistFindLargest(Range rangeReturn, Range oldRangeReturn, - Freelist fl, Size size, FindDelete findDelete); - -extern void FreelistFlushToLand(Freelist fl, Land land); +extern FreelistLandClass FreelistLandClassGet(void); #endif /* freelist.h */ diff --git a/mps/code/land.c b/mps/code/land.c index 991739f7b7f..e06f0060e36 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -12,6 +12,8 @@ SRCID(land, "$Id$"); +/* LandCheck -- check land */ + Bool LandCheck(Land land) { CHECKS(Land, land); @@ -20,6 +22,12 @@ Bool LandCheck(Land land) return TRUE; } + +/* LandInit -- initialize land + * + * See + */ + Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *owner, ArgList args) { Res res; @@ -47,6 +55,12 @@ Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *own return res; } + +/* LandCreate -- allocate and initialize land + * + * See + */ + Res LandCreate(Land *landReturn, Arena arena, LandClass class, Align alignment, void *owner, ArgList args) { Res res; @@ -76,6 +90,12 @@ Res LandCreate(Land *landReturn, Arena arena, LandClass class, Align alignment, return res; } + +/* LandDestroy -- finish and deallocate land + * + * See + */ + void LandDestroy(Land land) { Arena arena; @@ -89,12 +109,27 @@ void LandDestroy(Land land) ControlFree(arena, land, class->size); } + +/* LandFinish -- finish land + * + * See + */ + void LandFinish(Land land) { AVERT(Land, land); + (*land->class->finish)(land); + + land->sig = SigInvalid; } + +/* LandInsert -- insert range of addresses into land + * + * See + */ + Res LandInsert(Range rangeReturn, Land land, Range range) { AVER(rangeReturn != NULL); @@ -105,6 +140,12 @@ Res LandInsert(Range rangeReturn, Land land, Range range) return (*land->class->insert)(rangeReturn, land, range); } + +/* LandDelete -- delete range of addresses from land + * + * See + */ + Res LandDelete(Range rangeReturn, Land land, Range range) { AVER(rangeReturn != NULL); @@ -115,6 +156,12 @@ Res LandDelete(Range rangeReturn, Land land, Range range) return (*land->class->delete)(rangeReturn, land, range); } + +/* LandIterate -- iterate over isolated ranges of addresses in land + * + * See + */ + void LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) { AVERT(Land, land); @@ -123,6 +170,12 @@ void LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) (*land->class->iterate)(land, visitor, closureP, closureS); } + +/* LandFindFirst -- find first range of given size + * + * See + */ + Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) { AVER(rangeReturn != NULL); @@ -135,6 +188,12 @@ Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size findDelete); } + +/* LandFindLast -- find last range of given size + * + * See + */ + Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) { AVER(rangeReturn != NULL); @@ -147,6 +206,12 @@ Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, findDelete); } + +/* LandFindLargest -- find largest range of at least given size + * + * See + */ + Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) { AVER(rangeReturn != NULL); @@ -159,6 +224,12 @@ Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size si findDelete); } + +/* LandFindInSize -- find range of given size in set of zones + * + * See + */ + Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high) { AVER(rangeReturn != NULL); @@ -172,6 +243,12 @@ Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size siz zoneSet, high); } + +/* LandDescribe -- describe land for debugging + * + * See + */ + Res LandDescribe(Land land, mps_lib_FILE *stream) { Res res; @@ -198,6 +275,51 @@ Res LandDescribe(Land land, mps_lib_FILE *stream) } +/* landFlushVisitor -- visitor for LandFlush. + * + * closureP 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) +{ + Res res; + RangeStruct newRange; + Land dest; + + AVER(deleteReturn != NULL); + AVERT(Range, range); + AVER(closureP != NULL); + UNUSED(closureS); + + dest = closureP; + res = LandInsert(&newRange, land, range); + if (res == ResOK) { + *deleteReturn = TRUE; + return TRUE; + } else { + *deleteReturn = FALSE; + return FALSE; + } +} + + +/* LandFlush -- move ranges from src to dest + * + * See + */ + +void LandFlush(Land dest, Land src) +{ + AVERT(Land, dest); + AVERT(Land, src); + + LandIterate(src, landFlushVisitor, dest, 0); +} + + +/* LandClassCheck -- check land class */ + Bool LandClassCheck(LandClass class) { CHECKL(ProtocolClassCheck(&class->protocol)); diff --git a/mps/code/fbmtest.c b/mps/code/landtest.c similarity index 79% rename from mps/code/fbmtest.c rename to mps/code/landtest.c index 97776deab40..5ca7305ebda 100644 --- a/mps/code/fbmtest.c +++ b/mps/code/landtest.c @@ -1,19 +1,16 @@ -/* fbmtest.c: FREE BLOCK MANAGEMENT TEST +/* landtest.c: LAND TEST * - * $Id$ + * $Id$ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * - * The MPS contains two free block management modules: + * The MPS contains two land implementations: * - * 1. the CBS (Coalescing Block Structure) module maintains free - * blocks in a splay tree for fast access with a cost in storage; + * 1. the CBS (Coalescing Block Structure) module maintains blocks in + * a splay tree for fast access with a cost in storage; * - * 2. the Freelist module maintains free blocks in an address-ordered + * 2. the Freelist module maintains blocks in an address-ordered * singly linked list for zero storage overhead with a cost in * performance. - * - * The two modules present identical interfaces, so we apply the same - * test cases to both. */ #include "cbs.h" @@ -28,7 +25,7 @@ #include #include -SRCID(fbmtest, "$Id$"); +SRCID(landtest, "$Id$"); #define ArraySize ((Size)123456) @@ -43,64 +40,46 @@ static Count NAllocateTried, NAllocateSucceeded, NDeallocateTried, static int verbose = 0; -typedef unsigned FBMType; -enum { - FBMTypeCBS = 1, - FBMTypeFreelist, - FBMTypeLimit -}; - -typedef struct FBMStateStruct { - FBMType type; +typedef struct TestStateStruct { Align align; BT allocTable; Addr block; - union { - Land land; - Freelist fl; - } the; -} FBMStateStruct, *FBMState; + Land land; +} TestStateStruct, *TestState; -typedef struct CheckFBMClosureStruct { - FBMState state; +typedef struct CheckTestClosureStruct { + TestState state; Addr limit; Addr oldLimit; -} CheckFBMClosureStruct, *CheckFBMClosure; +} CheckTestClosureStruct, *CheckTestClosure; -static Addr (addrOfIndex)(FBMState state, Index i) +static Addr (addrOfIndex)(TestState state, Index i) { return AddrAdd(state->block, (i * state->align)); } -static Index (indexOfAddr)(FBMState state, Addr a) +static Index (indexOfAddr)(TestState state, Addr a) { return (Index)(AddrOffset(state->block, a) / state->align); } -static void describe(FBMState state) { - switch (state->type) { - case FBMTypeCBS: - die(LandDescribe(state->the.land, mps_lib_get_stdout()), "LandDescribe"); - break; - case FBMTypeFreelist: - die(FreelistDescribe(state->the.fl, mps_lib_get_stdout()), "FreelistDescribe"); - break; - default: - cdie(0, "invalid state->type"); - break; - } +static void describe(TestState state) { + die(LandDescribe(state->land, mps_lib_get_stdout()), "LandDescribe"); } -static Bool checkCallback(Range range, void *closureP, Size closureS) +static Bool checkVisitor(Bool *deleteReturn, Land land, Range range, + void *closureP, Size closureS) { Addr base, limit; - CheckFBMClosure cl = (CheckFBMClosure)closureP; + CheckTestClosure cl = closureP; - UNUSED(closureS); + Insist(deleteReturn != NULL); + testlib_unused(land); + testlib_unused(closureS); Insist(cl != NULL); base = RangeBase(range); @@ -124,42 +103,15 @@ static Bool checkCallback(Range range, void *closureP, Size closureS) return TRUE; } - -static Bool checkCBSCallback(Land land, Range range, - void *closureP, Size closureS) +static void check(TestState state) { - UNUSED(land); - return checkCallback(range, closureP, closureS); -} - - -static Bool checkFLCallback(Bool *deleteReturn, Range range, - void *closureP, Size closureS) -{ - *deleteReturn = FALSE; - return checkCallback(range, closureP, closureS); -} - - -static void check(FBMState state) -{ - CheckFBMClosureStruct closure; + CheckTestClosureStruct closure; closure.state = state; closure.limit = addrOfIndex(state, ArraySize); closure.oldLimit = state->block; - switch (state->type) { - case FBMTypeCBS: - LandIterate(state->the.land, checkCBSCallback, (void *)&closure, 0); - break; - case FBMTypeFreelist: - FreelistIterate(state->the.fl, checkFLCallback, (void *)&closure, 0); - break; - default: - cdie(0, "invalid state->type"); - return; - } + LandIterate(state->land, checkVisitor, (void *)&closure, 0); if (closure.oldLimit == state->block) Insist(BTIsSetRange(state->allocTable, 0, @@ -245,7 +197,7 @@ static Index lastEdge(BT bt, Size size, Index base) * all either set or reset. */ -static void randomRange(Addr *baseReturn, Addr *limitReturn, FBMState state) +static void randomRange(Addr *baseReturn, Addr *limitReturn, TestState state) { Index base; /* the start of our range */ Index end; /* an edge (i.e. different from its predecessor) */ @@ -267,7 +219,7 @@ static void randomRange(Addr *baseReturn, Addr *limitReturn, FBMState state) } -static void allocate(FBMState state, Addr base, Addr limit) +static void allocate(TestState state, Addr base, Addr limit) { Res res; Index ib, il; /* Indexed for base and limit */ @@ -295,25 +247,15 @@ static void allocate(FBMState state, Addr base, Addr limit) total = AddrOffset(outerBase, outerLimit); /* TODO: check these values */ - UNUSED(left); - UNUSED(right); - UNUSED(total); + testlib_unused(left); + testlib_unused(right); + testlib_unused(total); } else { outerBase = outerLimit = NULL; } RangeInit(&range, base, limit); - switch (state->type) { - case FBMTypeCBS: - res = LandDelete(&oldRange, state->the.land, &range); - break; - case FBMTypeFreelist: - res = FreelistDelete(&oldRange, state->the.fl, &range); - break; - default: - cdie(0, "invalid state->type"); - return; - } + res = LandDelete(&oldRange, state->land, &range); if (verbose) { printf("allocate: [%p,%p) -- %s\n", @@ -335,7 +277,7 @@ static void allocate(FBMState state, Addr base, Addr limit) } -static void deallocate(FBMState state, Addr base, Addr limit) +static void deallocate(TestState state, Addr base, Addr limit) { Res res; Index ib, il; @@ -373,23 +315,13 @@ static void deallocate(FBMState state, Addr base, Addr limit) total = AddrOffset(outerBase, outerLimit); /* TODO: check these values */ - UNUSED(left); - UNUSED(right); - UNUSED(total); + testlib_unused(left); + testlib_unused(right); + testlib_unused(total); } RangeInit(&range, base, limit); - switch (state->type) { - case FBMTypeCBS: - res = LandInsert(&freeRange, state->the.land, &range); - break; - case FBMTypeFreelist: - res = FreelistInsert(&freeRange, state->the.fl, &range); - break; - default: - cdie(0, "invalid state->type"); - return; - } + res = LandInsert(&freeRange, state->land, &range); if (verbose) { printf("deallocate: [%p,%p) -- %s\n", @@ -412,7 +344,7 @@ static void deallocate(FBMState state, Addr base, Addr limit) } -static void find(FBMState state, Size size, Bool high, FindDelete findDelete) +static void find(TestState state, Size size, Bool high, FindDelete findDelete) { Bool expected, found; Index expectedBase, expectedLimit; @@ -453,23 +385,12 @@ static void find(FBMState state, Size size, Bool high, FindDelete findDelete) } /* TODO: check these values */ - UNUSED(oldSize); - UNUSED(newSize); + testlib_unused(oldSize); + testlib_unused(newSize); } - switch (state->type) { - case FBMTypeCBS: - found = (high ? LandFindLast : LandFindFirst) - (&foundRange, &oldRange, state->the.land, size * state->align, findDelete); - break; - case FBMTypeFreelist: - found = (high ? FreelistFindLast : FreelistFindFirst) - (&foundRange, &oldRange, state->the.fl, size * state->align, findDelete); - break; - default: - cdie(0, "invalid state->type"); - return; - } + found = (high ? LandFindLast : LandFindFirst) + (&foundRange, &oldRange, state->land, size * state->align, findDelete); if (verbose) { printf("find %s %lu: ", high ? "last" : "first", @@ -505,7 +426,7 @@ static void find(FBMState state, Size size, Bool high, FindDelete findDelete) return; } -static void test(FBMState state, unsigned n) { +static void test(TestState state, unsigned n) { Addr base, limit; unsigned i; Size size; @@ -538,7 +459,7 @@ static void test(FBMState state, unsigned n) { find(state, size, high, findDelete); break; default: - cdie(0, "invalid state->type"); + cdie(0, "invalid rnd(3)"); return; } if ((i + 1) % 1000 == 0) @@ -551,14 +472,14 @@ static void test(FBMState state, unsigned n) { extern int main(int argc, char *argv[]) { mps_arena_t mpsArena; - Arena arena; /* the ANSI arena which we use to allocate the BT */ - FBMStateStruct state; + Arena arena; + TestStateStruct state; void *p; Addr dummyBlock; BT allocTable; - FreelistStruct flStruct; CBSStruct cbsStruct; - Land land = &cbsStruct.landStruct; + FreelistStruct flStruct; + Land land; Align align; testlib_init(argc, argv); @@ -586,25 +507,26 @@ extern int main(int argc, char *argv[]) (char *)dummyBlock + ArraySize); } + land = &cbsStruct.landStruct; MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, CBSFastFind, TRUE); die((mps_res_t)LandInit(land, CBSLandClassGet(), arena, align, NULL, args), "failed to initialise CBS"); } MPS_ARGS_END(args); - state.type = FBMTypeCBS; state.align = align; state.block = dummyBlock; state.allocTable = allocTable; - state.the.land = land; + state.land = land; test(&state, nCBSOperations); LandFinish(land); - die((mps_res_t)FreelistInit(&flStruct, align), + land = &flStruct.landStruct; + die((mps_res_t)LandInit(land, FreelistLandClassGet(), arena, align, NULL, + mps_args_none), "failed to initialise Freelist"); - state.type = FBMTypeFreelist; - state.the.fl = &flStruct; + state.land = land; test(&state, nFLOperations); - FreelistFinish(&flStruct); + LandFinish(land); mps_arena_destroy(arena); diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 4e65ea83ed4..7096618f565 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -1010,6 +1010,7 @@ extern Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Siz extern Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete); extern Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high); extern Res LandDescribe(Land land, mps_lib_FILE *stream); +extern void LandFlush(Land dest, Land src); extern Bool LandClassCheck(LandClass class); extern LandClass LandClassGet(void); diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 8d7a414465b..6679dbafd75 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -665,10 +665,28 @@ typedef struct CBSStruct { Bool ownPool; /* did we create blockPool? */ /* meters for sizes of search structures at each op */ METER_DECL(treeSearch); - Sig sig; /* sig at end because embedded */ + Sig sig; /* .class.end-sig */ } CBSStruct; +/* FreelistStruct -- address-ordered freelist + * + * Freelist is a subclass of Land that maintains a collection of + * disjoint ranges in an address-ordered freelist. + * + * See . + */ + +#define FreelistSig ((Sig)0x519F6331) /* SIGnature FREEL */ + +typedef struct FreelistStruct { + LandStruct landStruct; /* superclass fields come first */ + FreelistBlock list; + Count listSize; + Sig sig; /* .class.end-sig */ +} FreelistStruct; + + /* ArenaStruct -- generic arena * * See . */ diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 8abc43bb111..424216ee0b3 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -112,10 +112,12 @@ typedef struct StackContextStruct *StackContext; typedef struct RangeStruct *Range; /* */ typedef struct LandStruct *Land; /* */ typedef struct LandClassStruct *LandClass; /* */ +typedef unsigned FindDelete; /* */ typedef LandClass CBSLandClass; /* */ typedef struct CBSStruct *CBS; /* */ -typedef LandClass FreelistClass; /* */ -typedef unsigned FindDelete; /* */ +typedef LandClass FreelistLandClass; /* */ +typedef struct FreelistStruct *Freelist; /* */ +typedef union FreelistBlockUnion *FreelistBlock; /* */ /* Arena*Method -- see */ @@ -274,7 +276,7 @@ typedef Res (*LandInitMethod)(Land land, ArgList args); typedef void (*LandFinishMethod)(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 (*LandVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS); typedef void (*LandIterateMethod)(Land land, LandVisitor visitor, void *closureP, Size closureS); typedef Bool (*LandFindMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete); typedef Res (*LandFindInZonesMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high); diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index d9ce4fdd401..c987b57b4e9 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -105,7 +105,7 @@ 2291A5DB175CB05F001D4920 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; 2291A5DD175CB05F001D4920 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; 2291A5E4175CB076001D4920 /* exposet0.c in Sources */ = {isa = PBXBuildFile; fileRef = 2291A5AA175CAA9B001D4920 /* exposet0.c */; }; - 2291A5ED175CB5E2001D4920 /* fbmtest.c in Sources */ = {isa = PBXBuildFile; fileRef = 2291A5E9175CB4EC001D4920 /* fbmtest.c */; }; + 2291A5ED175CB5E2001D4920 /* landtest.c in Sources */ = {isa = PBXBuildFile; fileRef = 2291A5E9175CB4EC001D4920 /* landtest.c */; }; 22B2BC2E18B6434F00C33E63 /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; }; 22B2BC3718B6437C00C33E63 /* scheme-advanced.c in Sources */ = {isa = PBXBuildFile; fileRef = 22B2BC2B18B6434000C33E63 /* scheme-advanced.c */; }; 22FA176916E8D6FC0098B23F /* fmtdy.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAC6156BE48D00753214 /* fmtdy.c */; }; @@ -659,7 +659,7 @@ containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; proxyType = 1; remoteGlobalIDString = 3114A64B156E9596001E0AA3; - remoteInfo = fbmtest; + remoteInfo = landtest; }; 3114A674156E9619001E0AA3 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; @@ -1249,7 +1249,7 @@ 2291A5BD175CAB2F001D4920 /* awlutth */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = awlutth; sourceTree = BUILT_PRODUCTS_DIR; }; 2291A5D1175CAFCA001D4920 /* expt825 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = expt825; sourceTree = BUILT_PRODUCTS_DIR; }; 2291A5E3175CB05F001D4920 /* exposet0 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = exposet0; sourceTree = BUILT_PRODUCTS_DIR; }; - 2291A5E9175CB4EC001D4920 /* fbmtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fbmtest.c; sourceTree = ""; }; + 2291A5E9175CB4EC001D4920 /* landtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = landtest.c; sourceTree = ""; }; 2291A5EA175CB503001D4920 /* abq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = abq.h; sourceTree = ""; }; 2291A5EB175CB53E001D4920 /* range.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = range.c; sourceTree = ""; }; 2291A5EC175CB53E001D4920 /* range.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = range.h; sourceTree = ""; }; @@ -1299,7 +1299,7 @@ 3114A633156E94DB001E0AA3 /* abqtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = abqtest; sourceTree = BUILT_PRODUCTS_DIR; }; 3114A63D156E94EA001E0AA3 /* abqtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = abqtest.c; sourceTree = ""; }; 3114A645156E9525001E0AA3 /* abq.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = abq.c; sourceTree = ""; }; - 3114A64C156E9596001E0AA3 /* fbmtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fbmtest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3114A64C156E9596001E0AA3 /* landtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = landtest; sourceTree = BUILT_PRODUCTS_DIR; }; 3114A662156E95D9001E0AA3 /* btcv */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = btcv; sourceTree = BUILT_PRODUCTS_DIR; }; 3114A66C156E95EB001E0AA3 /* btcv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = btcv.c; sourceTree = ""; }; 3114A67C156E9668001E0AA3 /* mv2test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mv2test; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2004,7 +2004,7 @@ 3114A613156E944A001E0AA3 /* bttest.c */, 2291A5AA175CAA9B001D4920 /* exposet0.c */, 2291A5AB175CAA9B001D4920 /* expt825.c */, - 2291A5E9175CB4EC001D4920 /* fbmtest.c */, + 2291A5E9175CB4EC001D4920 /* landtest.c */, 3114A5CD156E9369001E0AA3 /* finalcv.c */, 3114A5E5156E93B9001E0AA3 /* finaltest.c */, 3124CAC6156BE48D00753214 /* fmtdy.c */, @@ -2100,7 +2100,7 @@ 3114A605156E9430001E0AA3 /* bttest */, 3114A61C156E9485001E0AA3 /* teletest */, 3114A633156E94DB001E0AA3 /* abqtest */, - 3114A64C156E9596001E0AA3 /* fbmtest */, + 3114A64C156E9596001E0AA3 /* landtest */, 3114A662156E95D9001E0AA3 /* btcv */, 3114A67C156E9668001E0AA3 /* mv2test */, 3114A695156E971B001E0AA3 /* messtest */, @@ -2725,9 +2725,9 @@ productReference = 3114A633156E94DB001E0AA3 /* abqtest */; productType = "com.apple.product-type.tool"; }; - 3114A64B156E9596001E0AA3 /* fbmtest */ = { + 3114A64B156E9596001E0AA3 /* landtest */ = { isa = PBXNativeTarget; - buildConfigurationList = 3114A653156E9596001E0AA3 /* Build configuration list for PBXNativeTarget "fbmtest" */; + buildConfigurationList = 3114A653156E9596001E0AA3 /* Build configuration list for PBXNativeTarget "landtest" */; buildPhases = ( 3114A648156E9596001E0AA3 /* Sources */, 3114A649156E9596001E0AA3 /* Frameworks */, @@ -2738,9 +2738,9 @@ dependencies = ( 3114A659156E95B1001E0AA3 /* PBXTargetDependency */, ); - name = fbmtest; - productName = fbmtest; - productReference = 3114A64C156E9596001E0AA3 /* fbmtest */; + name = landtest; + productName = landtest; + productReference = 3114A64C156E9596001E0AA3 /* landtest */; productType = "com.apple.product-type.tool"; }; 3114A661156E95D9001E0AA3 /* btcv */ = { @@ -3120,7 +3120,7 @@ 318DA8C31892B0F30089718C /* djbench */, 2291A5D3175CB05F001D4920 /* exposet0 */, 2291A5C1175CAFCA001D4920 /* expt825 */, - 3114A64B156E9596001E0AA3 /* fbmtest */, + 3114A64B156E9596001E0AA3 /* landtest */, 3114A5BC156E9315001E0AA3 /* finalcv */, 3114A5D5156E93A0001E0AA3 /* finaltest */, 224CC78C175E1821002FF81B /* fotest */, @@ -3421,7 +3421,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2291A5ED175CB5E2001D4920 /* fbmtest.c in Sources */, + 2291A5ED175CB5E2001D4920 /* landtest.c in Sources */, 3114A672156E95F6001E0AA3 /* testlib.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3908,7 +3908,7 @@ }; 3114A65B156E95B4001E0AA3 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 3114A64B156E9596001E0AA3 /* fbmtest */; + target = 3114A64B156E9596001E0AA3 /* landtest */; targetProxy = 3114A65A156E95B4001E0AA3 /* PBXContainerItemProxy */; }; 3114A675156E9619001E0AA3 /* PBXTargetDependency */ = { @@ -5460,7 +5460,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 3114A653156E9596001E0AA3 /* Build configuration list for PBXNativeTarget "fbmtest" */ = { + 3114A653156E9596001E0AA3 /* Build configuration list for PBXNativeTarget "landtest" */ = { isa = XCConfigurationList; buildConfigurations = ( 3114A654156E9596001E0AA3 /* Debug */, diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index 05252eaca8f..adc0abf426f 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -52,7 +52,7 @@ static Res MVTContingencySearch(Addr *baseReturn, Addr *limitReturn, static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena); static ABQ MVTABQ(MVT mvt); static Land MVTCBS(MVT mvt); -static Freelist MVTFreelist(MVT mvt); +static Land MVTFreelist(MVT mvt); /* Types */ @@ -174,9 +174,9 @@ static Land MVTCBS(MVT mvt) } -static Freelist MVTFreelist(MVT mvt) +static Land MVTFreelist(MVT mvt) { - return &mvt->flStruct; + return &mvt->flStruct.landStruct; } @@ -280,7 +280,8 @@ static Res MVTInit(Pool pool, ArgList args) if (res != ResOK) goto failABQ; - res = FreelistInit(MVTFreelist(mvt), align); + res = LandInit(MVTFreelist(mvt), FreelistLandClassGet(), arena, align, mvt, + mps_args_none); if (res != ResOK) goto failFreelist; @@ -422,7 +423,7 @@ static void MVTFinish(Pool pool) } /* Finish the Freelist, ABQ and CBS structures */ - FreelistFinish(MVTFreelist(mvt)); + LandFinish(MVTFreelist(mvt)); ABQFinish(arena, MVTABQ(mvt)); LandFinish(MVTCBS(mvt)); } @@ -810,14 +811,14 @@ static Res MVTInsert(MVT mvt, Addr base, Addr limit) /* Attempt to flush the Freelist to the CBS to give maximum * opportunities for coalescence. */ - FreelistFlushToLand(MVTFreelist(mvt), MVTCBS(mvt)); + LandFlush(MVTCBS(mvt), MVTFreelist(mvt)); RangeInit(&range, base, limit); res = LandInsert(&newRange, MVTCBS(mvt), &range); if (ResIsAllocFailure(res)) { /* CBS ran out of memory for splay nodes: add range to emergency * free list instead. */ - res = FreelistInsert(&newRange, MVTFreelist(mvt), &range); + res = LandInsert(&newRange, MVTFreelist(mvt), &range); } if (res != ResOK) return res; @@ -866,7 +867,7 @@ static Res MVTDelete(MVT mvt, Addr base, Addr limit) AVER(res == ResOK); } else if (res == ResFAIL) { /* Not found in the CBS: try the Freelist. */ - res = FreelistDelete(&rangeOld, MVTFreelist(mvt), &range); + res = LandDelete(&rangeOld, MVTFreelist(mvt), &range); } if (res != ResOK) return res; @@ -1051,7 +1052,7 @@ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream) res = ABQDescribe(MVTABQ(mvt), (ABQDescribeElement)RangeDescribe, stream); if(res != ResOK) return res; - res = FreelistDescribe(MVTFreelist(mvt), stream); + res = LandDescribe(MVTFreelist(mvt), stream); if(res != ResOK) return res; res = METER_WRITE(mvt->segAllocs, stream); @@ -1272,13 +1273,16 @@ static Bool MVTReturnSegs(MVT mvt, Range range, Arena arena) } -/* MVTRefillCallback -- called from CBSIterate or FreelistIterate at - * the behest of MVTRefillABQIfEmpty - */ -static Bool MVTRefillCallback(MVT mvt, Range range) +static Bool MVTRefillVisitor(Bool *deleteReturn, Land land, Range range, + void *closureP, Size closureS) { - AVERT(ABQ, MVTABQ(mvt)); - AVERT(Range, range); + MVT mvt; + + AVER(deleteReturn != NULL); + AVERT(Land, land); + mvt = closureP; + AVERT(MVT, mvt); + UNUSED(closureS); if (RangeSize(range) < mvt->reuseSize) return TRUE; @@ -1287,29 +1291,6 @@ static Bool MVTRefillCallback(MVT mvt, Range range) return MVTReserve(mvt, range); } -static Bool MVTCBSRefillCallback(Land land, Range range, - void *closureP, Size closureS) -{ - MVT mvt; - AVERT(Land, land); - mvt = closureP; - AVERT(MVT, mvt); - UNUSED(closureS); - return MVTRefillCallback(mvt, range); -} - -static Bool MVTFreelistRefillCallback(Bool *deleteReturn, Range range, - void *closureP, Size closureS) -{ - MVT mvt; - mvt = closureP; - AVERT(MVT, mvt); - UNUSED(closureS); - AVER(deleteReturn != NULL); - *deleteReturn = FALSE; - return MVTRefillCallback(mvt, range); -} - /* MVTRefillABQIfEmpty -- refill the ABQ from the CBS and the Freelist if * it is empty */ @@ -1326,8 +1307,8 @@ static void MVTRefillABQIfEmpty(MVT mvt, Size size) if (mvt->abqOverflow && ABQIsEmpty(MVTABQ(mvt))) { mvt->abqOverflow = FALSE; METER_ACC(mvt->refills, size); - LandIterate(MVTCBS(mvt), &MVTCBSRefillCallback, mvt, 0); - FreelistIterate(MVTFreelist(mvt), &MVTFreelistRefillCallback, mvt, 0); + LandIterate(MVTCBS(mvt), &MVTRefillVisitor, mvt, 0); + LandIterate(MVTFreelist(mvt), &MVTRefillVisitor, mvt, 0); } } @@ -1348,19 +1329,26 @@ typedef struct MVTContigencyStruct } MVTContigencyStruct; -/* MVTContingencyCallback -- called from CBSIterate or FreelistIterate - * at the behest of MVTContingencySearch. +/* MVTContingencyVisitor -- called from LandIterate at the behest of + * MVTContingencySearch. */ -static Bool MVTContingencyCallback(MVTContigency cl, Range range) + +static Bool MVTContingencyVisitor(Bool *deleteReturn, Land land, Range range, + void *closureP, Size closureS) { MVT mvt; Size size; Addr base, limit; + MVTContigency cl; - AVER(cl != NULL); + AVER(deleteReturn != NULL); + AVERT(Land, land); + AVERT(Range, range); + AVER(closureP != NULL); + cl = closureP; mvt = cl->mvt; AVERT(MVT, mvt); - AVERT(Range, range); + UNUSED(closureS); base = RangeBase(range); limit = RangeLimit(range); @@ -1389,25 +1377,6 @@ static Bool MVTContingencyCallback(MVTContigency cl, Range range) return TRUE; } -static Bool MVTCBSContingencyCallback(Land land, Range range, - void *closureP, Size closureS) -{ - MVTContigency cl = closureP; - AVERT(Land, land); - UNUSED(closureS); - return MVTContingencyCallback(cl, range); -} - -static Bool MVTFreelistContingencyCallback(Bool *deleteReturn, Range range, - void *closureP, Size closureS) -{ - MVTContigency cl = closureP; - UNUSED(closureS); - AVER(deleteReturn != NULL); - *deleteReturn = FALSE; - return MVTContingencyCallback(cl, range); -} - /* MVTContingencySearch -- search the CBS and the Freelist for a block * of size min */ @@ -1423,11 +1392,10 @@ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn, cls.steps = 0; cls.hardSteps = 0; - FreelistFlushToLand(MVTFreelist(mvt), MVTCBS(mvt)); + LandFlush(MVTCBS(mvt), MVTFreelist(mvt)); - LandIterate(MVTCBS(mvt), MVTCBSContingencyCallback, (void *)&cls, 0); - FreelistIterate(MVTFreelist(mvt), MVTFreelistContingencyCallback, - (void *)&cls, 0); + LandIterate(MVTCBS(mvt), MVTContingencyVisitor, (void *)&cls, 0); + LandIterate(MVTFreelist(mvt), MVTContingencyVisitor, (void *)&cls, 0); if (!cls.found) return FALSE; diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 8e0f985b757..bbdb40fa510 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -59,9 +59,7 @@ typedef struct MVFFStruct { /* MVFF pool outer structure */ #define Pool2MVFF(pool) PARENT(MVFFStruct, poolStruct, pool) #define MVFF2Pool(mvff) (&((mvff)->poolStruct)) #define CBSOfMVFF(mvff) (&((mvff)->cbsStruct.landStruct)) -#define MVFFOfCBS(cbs) PARENT(MVFFStruct, cbsStruct, cbs) -#define FreelistOfMVFF(mvff) (&((mvff)->flStruct)) -#define MVFFOfFreelist(fl) PARENT(MVFFStruct, flStruct, fl) +#define FreelistOfMVFF(mvff) (&((mvff)->flStruct.landStruct)) static Bool MVFFCheck(MVFF mvff); @@ -99,7 +97,7 @@ static Res MVFFAddToFreeList(Addr *baseIO, Addr *limitIO, MVFF mvff) { if (ResIsAllocFailure(res)) { /* CBS ran out of memory for splay nodes: add range to emergency * free list instead. */ - res = FreelistInsert(&newRange, FreelistOfMVFF(mvff), &range); + res = LandInsert(&newRange, FreelistOfMVFF(mvff), &range); } if (res == ResOK) { @@ -178,7 +176,7 @@ static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit) } } else if (res == ResFAIL) { /* Not found in the CBS: must be found in the Freelist. */ - res = FreelistDelete(&oldRange, FreelistOfMVFF(mvff), &range); + res = LandDelete(&oldRange, FreelistOfMVFF(mvff), &range); AVER(res == ResOK); mvff->free -= RangeSize(&range); } @@ -297,7 +295,7 @@ static Bool MVFFFindFirstFree(Addr *baseReturn, Addr *limitReturn, AVER(size > 0); AVER(SizeIsAligned(size, PoolAlignment(MVFF2Pool(mvff)))); - FreelistFlushToLand(FreelistOfMVFF(mvff), CBSOfMVFF(mvff)); + LandFlush(CBSOfMVFF(mvff), FreelistOfMVFF(mvff)); findDelete = mvff->slotHigh ? FindDeleteHIGH : FindDeleteLOW; @@ -309,7 +307,7 @@ static Bool MVFFFindFirstFree(Addr *baseReturn, Addr *limitReturn, /* Failed to find a block in the CBS: try the emergency free list * as well. */ foundBlock = - (mvff->firstFit ? FreelistFindFirst : FreelistFindLast) + (mvff->firstFit ? LandFindFirst : LandFindLast) (&range, &oldRange, FreelistOfMVFF(mvff), size, findDelete); } @@ -411,13 +409,12 @@ static Bool MVFFFindLargest(Range range, Range oldRange, MVFF mvff, AVER(size > 0); AVERT(FindDelete, findDelete); - FreelistFlushToLand(FreelistOfMVFF(mvff), CBSOfMVFF(mvff)); + LandFlush(CBSOfMVFF(mvff), FreelistOfMVFF(mvff)); if (LandFindLargest(range, oldRange, CBSOfMVFF(mvff), size, findDelete)) return TRUE; - if (FreelistFindLargest(range, oldRange, FreelistOfMVFF(mvff), - size, findDelete)) + if (LandFindLargest(range, oldRange, FreelistOfMVFF(mvff), size, findDelete)) return TRUE; return FALSE; @@ -598,16 +595,16 @@ static Res MVFFInit(Pool pool, ArgList args) mvff->total = 0; mvff->free = 0; - res = FreelistInit(FreelistOfMVFF(mvff), align); + res = LandInit(FreelistOfMVFF(mvff), FreelistLandClassGet(), arena, align, mvff, mps_args_none); if (res != ResOK) - goto failInit; + goto failFreelistInit; MPS_ARGS_BEGIN(liArgs) { MPS_ARGS_ADD(liArgs, CBSFastFind, TRUE); res = LandInit(CBSOfMVFF(mvff), CBSLandClassGet(), arena, align, mvff, liArgs); } MPS_ARGS_END(liArgs); if (res != ResOK) - goto failInit; + goto failCBSInit; mvff->sig = MVFFSig; AVERT(MVFF, mvff); @@ -615,7 +612,9 @@ static Res MVFFInit(Pool pool, ArgList args) slotHigh, arenaHigh, firstFit); return ResOK; -failInit: +failCBSInit: + LandFinish(FreelistOfMVFF(mvff)); +failFreelistInit: ControlFree(arena, p, sizeof(SegPrefStruct)); return res; } @@ -649,7 +648,7 @@ static void MVFFFinish(Pool pool) ControlFree(arena, mvff->segPref, sizeof(SegPrefStruct)); LandFinish(CBSOfMVFF(mvff)); - FreelistFinish(FreelistOfMVFF(mvff)); + LandFinish(FreelistOfMVFF(mvff)); mvff->sig = SigInvalid; } @@ -697,7 +696,7 @@ static Res MVFFDescribe(Pool pool, mps_lib_FILE *stream) if (res != ResOK) return res; - res = FreelistDescribe(FreelistOfMVFF(mvff), stream); + res = LandDescribe(FreelistOfMVFF(mvff), stream); if (res != ResOK) return res; @@ -804,8 +803,8 @@ static Bool MVFFCheck(MVFF mvff) CHECKL(mvff->total >= mvff->free); CHECKL(SizeIsAligned(mvff->free, PoolAlignment(MVFF2Pool(mvff)))); CHECKL(SizeIsAligned(mvff->total, ArenaAlign(PoolArena(MVFF2Pool(mvff))))); - CHECKD(Land, CBSOfMVFF(mvff)); - CHECKD(Freelist, FreelistOfMVFF(mvff)); + CHECKD(CBS, &mvff->cbsStruct); + CHECKD(Freelist, &mvff->flStruct); CHECKL(BoolCheck(mvff->slotHigh)); CHECKL(BoolCheck(mvff->firstFit)); return TRUE; diff --git a/mps/design/cbs.txt b/mps/design/cbs.txt index 051889087d9..5ee2348fe54 100644 --- a/mps/design/cbs.txt +++ b/mps/design/cbs.txt @@ -20,7 +20,10 @@ eager coalescence. _`.readership`: This document is intended for any MM developer. -_`.source`: design.mps.poolmv2, design.mps.poolmvff. +_`.source`: design.mps.poolmv2_, design.mps.poolmvff_. + +.. _design.mps.poolmv2: poolmv2 +.. _design.mps.poolmvff: poolmvff _`.overview`: The "coalescing block structure" is a set of addresses (or a subset of address space), with provision for efficient @@ -33,7 +36,9 @@ Requirements ------------ In addition to the generic land requirements (see -design.mps.land.req), the CBS must satisfy: +design.mps.land_), the CBS must satisfy: + +.. _design.mps.land: land _`.req.fast`: Common operations must have a low amortized cost. @@ -45,8 +50,9 @@ storage of any subset of address space. Interface --------- -_`.land`: The interface to CBS is the generic functions for the *land* -abstract data type. See `design.mps.land `_. +_`.land`: CBS is an implementation of the *land* abstract data type, +so the interface consists of the generic functions for lands. See +design.mps.land_. External types @@ -54,8 +60,9 @@ External types ``typedef struct CBSStruct *CBS`` -_`.type.cbs`: A ``CBSStruct`` may be embedded in another structure, or -you can create it using ``LandCreate()``. +_`.type.cbs`: The type of coalescing block structures. A ``CBSStruct`` +may be embedded in another structure, or you can create it using +``LandCreate()``. External functions @@ -101,6 +108,25 @@ following optional keyword arguments: generic function. +Limitations +........... + +_`.limit.find`: CBS does not support the ``LandFindFirst()``, +``LandFindLast()``, and ``LandFindLargest()`` generic functions unless +the ``CBSFastFind`` keyword argument was set to ``TRUE``. + +_`.limit.zones`: CBS does not support the ``LandFindInZones()`` +generic function unless the ``CBSFastFind`` and ``CBSZoned`` keyword +arguments were both set to ``TRUE``. + +_`.limit.iterate`: CBS does not support visitors setting +``deleteReturn`` to ``TRUE`` when iterating over ranges with +``LandIterate()``. + +_`.limit.flush`: CBS cannot be used as the source in a call to +``LandFlush()``. + + Implementation -------------- @@ -108,7 +134,6 @@ _`.impl`: This section is concerned with describing various aspects of the implementation. It does not form part of the interface definition. - Splay tree .......... @@ -163,12 +188,12 @@ Testing _`.test`: The following testing will be performed on this module: -_`.test.fbmtest`: A generic test for land implementations. See -design.mps.land.fbmtest. +_`.test.land`: A generic test for land implementations. See +design.mps.land.test. -_`.test.pool`: Several pools (currently MVT_ and MVFF_) are implemented -on top of a CBS. These pool are subject to testing in development, QA, -and are/will be heavily exercised by customers. +_`.test.pool`: The arena and two pools (MVT_ and MVFF_) are +implemented on top of a CBS. These are subject to testing in +development, QA, and are heavily exercised by customers. .. _MVT: poolmvt .. _MVFF: poolmvff @@ -177,9 +202,9 @@ and are/will be heavily exercised by customers. Notes for future development ---------------------------- -_`.future.not-splay`: The initial implementation of CBSs is based on -splay trees. It could be revised to use any other data structure that -meets the requirements (especially `.req.fast`_). +_`.future.not-splay`: The implementation of CBSs is based on splay +trees. It could be revised to use other data structures that meet the +requirements (especially `.req.fast`_). _`.future.hybrid`: It would be possible to attenuate the problem of `.risk.overhead`_ (below) by using a single word bit set to represent diff --git a/mps/design/freelist.txt b/mps/design/freelist.txt index bc859cd3e32..680a143c1a5 100644 --- a/mps/design/freelist.txt +++ b/mps/design/freelist.txt @@ -40,174 +40,53 @@ When memory becomes available again to allocate control structures, the free lists can be "flushed" back into the more efficient data structures. -_`.bg`: The free list allocator was formerly part of the Coalescing -Block Structure module (see design.mps.cbs) but it was split into its -own module because this makes it: - -#. simpler (no need to interact with CBS) and thus more maintainable; -#. possible to test directly (no need to create a CBS and then force - its control pool to run out of memory); and -#. usable as a fallback allocator in other pools (not just in pools - that use CBS). - - -Definitions ------------ - -_`.def.range`: A (contiguous) *range* of addresses is a semi-open -interval on address space. - -_`.def.isolated`: A contiguous range is *isolated* with respect to -some property it has, if adjacent elements do not have that property. - Requirements ------------ -_`.req.set`: Must maintain a set of free address ranges. +In addition to the generic land requirements (see design.mps.land_), +free lists must satisfy: -_`.req.add`: Must be able to add free address ranges to the set. - -_`.req.remove`: Must be able to remove address ranges from the set (in -particular, when memory is allocated). - -_`.req.iterate`: Must support the iteration of all isolated contiguous -ranges. - -_`.req.protocol`: Must detect protocol violations. - -_`.req.align`: Must support an alignment (the alignment of all -addresses specifying ranges) of down to ``sizeof(void *)`` without -losing memory. +.. _design.mps.land: land _`.req.zero-overhead`: Must have zero space overhead for the storage of any set of free blocks, so that it can be used to manage memory when no memory can be allocated for control structures. -_`.req.source`: This set of requirements is derived from those of the -CBS module (see design.mps.cbs.req), except that there is no -equivalent of design.mps.cbs.req.fast, and design.mps.cbs.req.small -has been replaced with `.req.zero-overhead`_. - Interface --------- +_`.land`: Free lists are an implementation of the *land* abstract data +type, so the interface consists of the generic functions for lands. +See design.mps.land_. + Types ..... ``typedef struct FreelistStruct *Freelist`` -_`.type.freelist`: The type of free lists. The structure -``FreelistStruct`` is declared in the header so that it can be inlined -in other structures, but you should not depend on its details. - -``typedef Bool (*FreelistIterateMethod)(Bool *deleteReturn, Freelist fl, Range range, void *closureP, Size closureS)`` - -_`.type.iterate.method`: A callback function that may be passed to -``FreelistIterate()``. It is called for every isolated contiguous -range in address order, and with the closure arguments that were -originally passed to ``FreelistIterate()``. It must update -``*deleteReturn`` to ``TRUE`` if the range must be deleted from the -free lists, or ``FALSE`` if the range must be kept. The function must -return ``TRUE`` if the iteration must continue, and ``FALSE`` if the -iteration must stop (after possibly deleting the current range). +_`.type.freelist`: The type of free lists. A ``FreelistStruct`` may be +embedded in another structure, or you can create it using +``LandCreate()``. -Functions -......... +External functions +.................. -``Res FreelistInit(Freelist fl, Align alignment)`` +``LandClass FreelistLandClassGet(void)`` -_`.function.init`: Initialize the ``Freelist`` structure pointed to by -``fl``. The argument ``alignment`` is the alignment of address ranges -to be maintained. An initialised free list contains no address ranges. +_`.function.class`: The function ``FreelistLandClassGet()`` returns +the free list class, a subclass of ``LandClass`` suitable for passing +to ``LandCreate()`` or ``LandInit()``. -``void FreelistFinish(Freelist fl)`` -_`.function.finish`: Finish the free list pointed to by ``fl``. - -``Res FreelistInsert(Range rangeReturn, Freelist fl, Range range)`` - -_`.function.insert`: If any part of ``range`` is already in the free -list ``fl``, then leave the free list unchanged and return -``ResFAIL``. Otherwise, insert ``range`` into the free list ``fl``; -update ``rangeReturn`` to describe the contiguous isolated range -containing the inserted range (this may differ from ``range`` if there -was coalescence on either side) and return ``ResOK``. - -``Res FreelistDelete(Range rangeReturn, Freelist fl, Range range)`` - -_`.function.delete`: If any part of the range is not in the free list, -then leave the free list unchanged and return ``ResFAIL``. Otherwise, -remove ``range`` from the free list and update ``rangeReturn`` to -describe the contiguous isolated range that formerly contained the -deleted range (this may differ from ``range`` if there were fragments -left on either side), and return ``ResOK``. - -``void FreelistIterate(Freelist fl, FreelistIterateMethod iterate, void *closureP, Size closureS)`` - -_`.function.iterate`: Iterate all isolated contiguous ranges in the -free list ``fl`` in address order, calling ``iterate`` for each one. -See ``FreelistIterateMethod`` for details. - -``Bool FreelistFindFirst(Range rangeReturn, Range oldRangeReturn, Freelist fl, Size size, FindDelete findDelete)`` - -_`.function.find.first`: Locate the first isolated contiguous range in -address order, within the free list ``fl``, of at least ``size`` -bytes, update ``rangeReturn`` to that range, and return ``TRUE``. If -there is no such continuous range, return ``FALSE``. - -In addition, optionally delete the found range from the free list, -depending on the ``findDelete`` argument. This saves a separate call -to ``FreelistDelete()``, and uses the knowledge of exactly where we -found the range. The value of ``findDelete`` must come from this -enumeration:: - - enum { - FindDeleteNONE, /* don't delete after finding */ - FindDeleteLOW, /* delete size bytes from low end of block */ - FindDeleteHIGH, /* delete size bytes from high end of block */ - FindDeleteENTIRE /* delete entire range */ - }; - -The original contiguous isolated range in which the range was found is -returned via the ``oldRangeReturn`` argument. (If ``findDelete`` is -``FindDeleteNONE`` or ``FindDeleteENTIRE``, then this will be -identical to the range returned via the ``rangeReturn`` argument.) - -``Bool FreelistFindLast(Range rangeReturn, Range oldRangeReturn, Freelist fl, Size size, FindDelete findDelete)`` - -_`.function.find.last`: Like ``FreelistFindFirst()``, except that it -finds the last block in address order. - -``Bool FreelistFindLargest(Range rangeReturn, Range oldRangeReturn, Freelist fl, Size, size, FindDelete findDelete)`` - -_`.function.find.largest`: Locate the largest block within the free -list ``fl``, and if that block is at least as big as ``size``, return -its range via the ``rangeReturn`` argument, and return ``TRUE``. If -there are no blocks in the free list at least as large as ``size``, -return ``FALSE``. Pass 0 for ``size`` if you want the largest block -unconditionally. - -Like ``FreelistFindFirst()``, optionally delete the range from the -free list. (Always the whole range: specifying ``FindDeleteLOW`` or -``FindDeleteHIGH`` has the same effect as ``FindDeleteENTIRE``). - -``void FreelistFlushToCBS(Freelist fl, CBS cbs)`` - -Remove free address ranges from the free list ``fl`` and add them to -the Coalescing Block Structure ``cbs``. Continue until a call to -``CBSInsert()`` fails, or until the free list is empty, whichever -happens first. - -``Res FreelistDescribe(Freelist fl, mps_lib_FILE *stream)`` - -_`.function.describe`: Print a textual representation of the free -list ``fl`` to the given stream, indicating the contiguous ranges in -order. It is provided for debugging purposes only. +Keyword arguments +................. +When initializing a free list, ``LandCreate()`` and ``LandInit()`` +take no keyword arguments. Pass ``mps_args_none``. Implementation @@ -246,6 +125,23 @@ do this, such as using another tag to indicate the last block in the list, but these would be more complicated.) +Testing +------- + +_`.test`: The following testing will be performed on this module: + +_`.test.land`: A generic test for land implementations. See +design.mps.land.test. + +_`.test.pool`: Two pools (MVT_ and MVFF_) use free lists as a fallback +when low on memory. These are subject to testing in development, QA, +and are heavily exercised by customers. + +.. _MVT: poolmvt +.. _MVFF: poolmvff + + + Opportunities for improvement ----------------------------- @@ -255,8 +151,8 @@ exceed the recorded size of the list. _`.improve.maxsize`: We could maintain the maximum size of any range on the list, and use that to make an early exit from -``FreelistFindLargest()``. It's not clear that this would actually be -an improvement. +``LandFindLargest()``. It's not clear that this would actually be an +improvement. @@ -265,6 +161,8 @@ Document History - 2013-05-18 GDR_ Initial draft based on CBS "emergency block" design. +- 2014-04-01 GDR_ Moved generic material to design.mps.land_. + .. _GDR: http://www.ravenbrook.com/consultants/gdr/ diff --git a/mps/design/land.txt b/mps/design/land.txt index fcbdde02ab1..8c12c9f5a96 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -77,12 +77,15 @@ Types _`.type.land`: The type of a generic land instance. -``typedef Bool (*LandVisitor)(Land land, Range range, void *closureP, Size closureS);`` +``typedef Bool (*LandVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS);`` -_`.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. +_`.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. It may additionally +update ``*deleteReturn`` to ``TRUE`` if the range must be deleted from +the land, or ``FALSE`` if the range must be kept. (The default is to +keep the range, and not all land classes support deletion.) Generic functions @@ -220,25 +223,28 @@ the ``oldRangeReturn`` argument. ``Res LandDescribe(Land land, mps_lib_FILE *stream)`` -_`.function.describe`: ``LandDescribe()`` is a function that prints -a textual representation of the land to the given stream, indicating -the contiguous ranges in order, as well as the structure of the -underlying splay tree implementation. It is provided for debugging -purposes only. +_`.function.describe`: ``LandDescribe()`` prints a textual +representation of the land to the given stream, indicating the +contiguous ranges in order, as well as the structure of the underlying +splay tree implementation. It is provided for debugging purposes only. + +``void LandFlush(Land dest, Land src)`` + +_`.function.flush`: Delete ranges of addresses from ``src`` and insert +them into ``dest``, so long as ``LandInsert()`` remains successful. Testing ------- -_`.test.fbmtest`: There is a stress test for implementations of this -interface in impl.c.fbmtest. This allocates a large block of memory -and then simulates the allocation and deallocation of ranges within -this block using both a ``Land`` and a ``BT``. It makes both valid and -invalid requests, and compares the ``Land`` response to the correct -behaviour as determined by the ``BT``. It iterates the ranges in the -``Land``, comparing them to the ``BT``. It invokes the -``LandDescribe()`` generic function, but makes no automatic test of -the resulting output. +_`.test`: There is a stress test for implementations of this interface +in impl.c.landtest. This allocates a large block of memory and then +simulates the allocation and deallocation of ranges within this block +using both a ``Land`` and a ``BT``. It makes both valid and invalid +requests, and compares the ``Land`` response to the correct behaviour +as determined by the ``BT``. It iterates the ranges in the ``Land``, +comparing them to the ``BT``. It invokes the ``LandDescribe()`` +generic function, but makes no automatic test of the resulting output. Document History diff --git a/mps/tool/testrun.bat b/mps/tool/testrun.bat index e2b16a00260..4b713f5c748 100755 --- a/mps/tool/testrun.bat +++ b/mps/tool/testrun.bat @@ -32,10 +32,10 @@ set ALL_TEST_CASES=^ btcv.exe ^ exposet0.exe ^ expt825.exe ^ - fbmtest.exe ^ finalcv.exe ^ finaltest.exe ^ fotest.exe ^ + landtest.exe ^ locbwcss.exe ^ lockcov.exe ^ lockutw3.exe ^ diff --git a/mps/tool/testrun.sh b/mps/tool/testrun.sh index 9cecd1c6fd5..4264388d0f6 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -29,10 +29,10 @@ ALL_TEST_CASES=" btcv exposet0 expt825 - fbmtest finalcv finaltest fotest + landtest locbwcss lockcov locusss From 643ab5a49a507b7a4908c645eaca8d57e51dc164 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 2 Apr 2014 15:48:57 +0100 Subject: [PATCH 031/266] Improve clarity of product configuration so that names more explicitly indicate what they do: * CONFIG_POLL_NONE (because the user-visible consequence is that polling is no longer supported; was CONFIG_PROTECTION_NONE). * DISABLE_LOCKS (was THREAD_SINGLE). * DISABLE_SHIELD (was THREAD_SINGLE && PROTECTION_NONE) * DISABLE_REMEMBERED_SET (was PROTECTION_NONE) When the shield is disabled, ArenaLeave asserts that there are no busy traces, and ArenaPoll is a no-op. By having functions implemented using the corresponding macro, we can avoid duplicated code, and avoid testing DISABLE_SHIELD in global.c. Remove all remaining references to MPS_PROD_EPCORE. Copied from Perforce Change: 185176 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 2 +- mps/code/config.h | 26 +++++++----- mps/code/eventrep.c | 95 ------------------------------------------- mps/code/global.c | 38 +++-------------- mps/code/lock.h | 4 +- mps/code/mpm.h | 23 ++++++----- mps/code/protix.c | 3 -- mps/code/protli.c | 3 -- mps/code/protsgix.c | 3 -- mps/code/protw3.c | 3 -- mps/code/protxc.c | 3 -- mps/code/qs.c | 2 + mps/code/seg.c | 7 +++- mps/design/config.txt | 13 +++--- 14 files changed, 49 insertions(+), 176 deletions(-) diff --git a/mps/Makefile.in b/mps/Makefile.in index 448a0219681..950e2d353dc 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -69,7 +69,7 @@ install: @INSTALL_TARGET@ test-make-build: $(MAKE) clean - $(MAKE) $(TARGET_OPTS) VARIETY=hot CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE -DCONFIG_PROTECTION_NONE" testansi + $(MAKE) $(TARGET_OPTS) VARIETY=hot CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE -DCONFIG_POLL_NONE" testansi $(MAKE) clean $(MAKE) $(TARGET_OPTS) testci diff --git a/mps/code/config.h b/mps/code/config.h index a1ebc2e688a..702ed5a6723 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -172,22 +172,26 @@ */ #if defined(CONFIG_THREAD_SINGLE) -#define THREAD_SINGLE -#else -#define THREAD_MULTI +#define DISABLE_LOCKS #endif -/* CONFIG_PROTECTION_NONE -- no support for memory protection + +/* CONFIG_POLL_NONE -- no support for polling * - * This symbol causes the MPS to built for an environment where there - * is no memory protection, and so segment summaries cannot be - * maintained by seg.c. + * This symbol causes the MPS to built without support for polling. + * This means that the arena must be clamped or parked at all times, + * garbage collections can only be carried out explicitly via + * mps_arena_collect(), but it also means that protection is not + * needed, and so shield operations can be replaced with no-ops in + * mpm.h. */ -#if defined(CONFIG_PROTECTION_NONE) -#define PROTECTION_NONE -#else -#define PROTECTION +#if defined(CONFIG_POLL_NONE) +#if !defined(CONFIG_THREAD_SINGLE) +#error "CONFIG_POLL_NONE without CONFIG_THREAD_SINGLE" +#endif +#define DISABLE_REMEMBERED_SET +#define DISABLE_SHIELD #endif diff --git a/mps/code/eventrep.c b/mps/code/eventrep.c index c2f611f7070..f216e51c70a 100644 --- a/mps/code/eventrep.c +++ b/mps/code/eventrep.c @@ -142,37 +142,6 @@ static void error(const char *format, ...) MPS_BEGIN if (!(cond)) error("line %d " #cond, __LINE__); MPS_END -#ifdef MPS_PROD_EPCORE - - -/* ensurePSFormat -- return the PS format, creating it, if necessary */ - -static mps_fmt_t psFormat = NULL; - -static void ensurePSFormat(mps_fmt_t *fmtOut, mps_arena_t arena) -{ - mps_res_t eres; - - if (psFormat == NULL) { - eres = mps_fmt_create_A(&psFormat, arena, ps_fmt_A()); - verifyMPS(eres); - } - *fmtOut = psFormat; -} - - -/* finishPSFormat -- finish the PS format, if necessary */ - -static void finishPSFormat(void) -{ - if (psFormat != NULL) - mps_fmt_destroy(psFormat); -} - - -#endif - - /* objectTableCreate -- create an objectTable */ static objectTable objectTableCreate(poolSupport support) @@ -417,10 +386,6 @@ void EventReplay(Event event, Word etime) case EventArenaDestroy: { /* arena */ found = TableLookup(&entry, arenaTable, (Word)event->p.p0); verify(found); -#ifdef MPS_PROD_EPCORE - /* @@@@ assuming there's only one arena at a time */ - finishPSFormat(); -#endif mps_arena_destroy((mps_arena_t)entry); ires = TableRemove(arenaTable, (Word)event->pw.p0); verify(ires == ResOK); @@ -455,30 +420,6 @@ void EventReplay(Event event, Word etime) /* all internal only */ ++discardedEvents; } break; -#ifdef MPS_PROD_EPCORE - case EventPoolInitEPVM: { - /* pool, arena, format, maxSaveLevel, saveLevel */ - mps_arena_t arena; - mps_fmt_t format; - - found = TableLookup(&entry, arenaTable, (Word)event->pppuu.p1); - verify(found); - arena = (mps_arena_t)entry; - ensurePSFormat(&format, arena); /* We know what the format is. */ - poolRecreate(event->pppuu.p0, event->pppuu.p1, - mps_class_epvm(), supportNothing, 2, format, - (mps_epvm_save_level_t)event->pppuu.u3, - (mps_epvm_save_level_t)event->pppuu.u4); - } break; - case EventPoolInitEPDL: { - /* pool, arena, isEPDL, extendBy, avgSize, align */ - poolRecreate(event->ppuwww.p0, event->ppuwww.p1, - event->ppuwww.u2 ? mps_class_epdl() : mps_class_epdr(), - event->ppuwww.u2 ? supportTruncate : supportFree, 0, - (size_t)event->ppuwww.w3, (size_t)event->ppuwww.w4, - (size_t)event->ppuwww.w5); - } break; -#endif case EventPoolFinish: { /* pool */ found = TableLookup(&entry, poolTable, (Word)event->p.p0); if (found) { @@ -541,22 +482,6 @@ void EventReplay(Event event, Word etime) ++discardedEvents; } } break; -#ifdef MPS_PROD_EPCORE - case EventBufferInitEPVM: { /* buffer, pool, isObj */ - found = TableLookup(&entry, poolTable, (Word)event->ppu.p1); - if (found) { - poolRep rep = (poolRep)entry; - - if(rep->bufferClassLevel == 2) { /* see .bufclass */ - apRecreate(event->ppu.p0, event->ppu.p1, (mps_bool_t)event->ppu.u2); - } else { - ++discardedEvents; - } - } else { - ++discardedEvents; - } - } break; -#endif case EventBufferFinish: { /* buffer */ found = TableLookup(&entry, apTable, (Word)event->p.p0); if (found) { @@ -619,26 +544,6 @@ void EventReplay(Event event, Word etime) ++discardedEvents; } } break; -#ifdef MPS_PROD_EPCORE - case EventPoolPush: { /* pool */ - found = TableLookup(&entry, poolTable, (Word)event->p.p0); - if (found) { - poolRep rep = (poolRep)entry; - - /* It must be EPVM. */ - mps_epvm_save(rep->pool); - } - } break; - case EventPoolPop: { /* pool, level */ - found = TableLookup(&entry, poolTable, (Word)event->pu.p0); - if (found) { - poolRep rep = (poolRep)entry; - - /* It must be EPVM. */ - mps_epvm_restore(rep->pool, (mps_epvm_save_level_t)event->pu.u1); - } - } break; -#endif case EventCommitLimitSet: { /* arena, limit, succeeded */ found = TableLookup(&entry, arenaTable, (Word)event->pwu.p0); verify(found); diff --git a/mps/code/global.c b/mps/code/global.c index 2dfda251f91..bfc2777d888 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -37,10 +37,6 @@ static Bool arenaRingInit = FALSE; static RingStruct arenaRing; /* */ static Serial arenaSerial; /* */ -/* forward declarations */ -void arenaEnterLock(Arena, int); -void arenaLeaveLock(Arena, int); - /* arenaClaimRingLock, arenaReleaseRingLock -- lock/release the arena ring * @@ -509,22 +505,15 @@ Ring GlobalsRememberedSummaryRing(Globals global) /* ArenaEnter -- enter the state where you can look at the arena */ -#if defined(THREAD_SINGLE) && defined(PROTECTION_NONE) void (ArenaEnter)(Arena arena) { - /* Don't need to lock, just check. */ AVERT(Arena, arena); + ArenaEnter(arena); } -#else -void ArenaEnter(Arena arena) -{ - arenaEnterLock(arena, 0); -} -#endif /* The recursive argument specifies whether to claim the lock recursively or not. */ -void arenaEnterLock(Arena arena, int recursive) +void ArenaEnterLock(Arena arena, Bool recursive) { Lock lock; @@ -559,25 +548,18 @@ void arenaEnterLock(Arena arena, int recursive) void ArenaEnterRecursive(Arena arena) { - arenaEnterLock(arena, 1); + ArenaEnterLock(arena, TRUE); } /* ArenaLeave -- leave the state where you can look at MPM data structures */ -#if defined(THREAD_SINGLE) && defined(PROTECTION_NONE) void (ArenaLeave)(Arena arena) { - /* Don't need to lock, just check. */ AVERT(Arena, arena); + ArenaLeave(arena); } -#else -void ArenaLeave(Arena arena) -{ - arenaLeaveLock(arena, 0); -} -#endif -void arenaLeaveLock(Arena arena, int recursive) +void ArenaLeaveLock(Arena arena, Bool recursive) { Lock lock; @@ -601,7 +583,7 @@ void arenaLeaveLock(Arena arena, int recursive) void ArenaLeaveRecursive(Arena arena) { - arenaLeaveLock(arena, 1); + ArenaLeaveLock(arena, TRUE); } /* mps_exception_info -- pointer to exception info @@ -701,14 +683,7 @@ Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context) * series of manual steps for looking around. This might be worthwhile * if we introduce background activities other than tracing. */ -#ifdef MPS_PROD_EPCORE void (ArenaPoll)(Globals globals) -{ - /* Don't poll, just check. */ - AVERT(Globals, globals); -} -#else -void ArenaPoll(Globals globals) { Arena arena; Clock start; @@ -763,7 +738,6 @@ void ArenaPoll(Globals globals) globals->insidePoll = FALSE; } -#endif /* 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 diff --git a/mps/code/lock.h b/mps/code/lock.h index 5faddfa05b8..5f0cadd7065 100644 --- a/mps/code/lock.h +++ b/mps/code/lock.h @@ -195,7 +195,7 @@ extern void LockClaimGlobal(void); extern void LockReleaseGlobal(void); -#ifdef THREAD_SINGLE +#ifdef DISABLE_LOCKS #define LockSize() MPS_PF_ALIGN #define LockInit(lock) UNUSED(lock) @@ -210,7 +210,7 @@ extern void LockReleaseGlobal(void); #define LockClaimGlobal() #define LockReleaseGlobal() -#endif /* THREAD_SINGLE */ +#endif /* DISABLE_LOCKS */ #endif /* lock_h */ diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 46dcd74b880..165d2c3b7ce 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -514,24 +514,25 @@ extern Ring GlobalsRememberedSummaryRing(Globals); #define ArenaGreyRing(arena, rank) (&(arena)->greyRing[rank]) #define ArenaPoolRing(arena) (&ArenaGlobals(arena)->poolRing) +extern void ArenaEnterLock(Arena arena, Bool recursive); +extern void ArenaLeaveLock(Arena arena, Bool recursive); + extern void (ArenaEnter)(Arena arena); extern void (ArenaLeave)(Arena arena); +extern void (ArenaPoll)(Globals globals); -#if defined(THREAD_SINGLE) && defined(PROTECTION_NONE) +#ifdef DISABLE_SHIELD #define ArenaEnter(arena) UNUSED(arena) -#define ArenaLeave(arena) UNUSED(arena) +#define ArenaLeave(arena) AVER(arena->busyTraces == TraceSetEMPTY) +#define ArenaPoll(globals) UNUSED(globals) +#else +#define ArenaEnter(arena) ArenaEnterLock(arena) +#define ArenaLeave(arena) ArenaLeaveLock(arena) #endif extern void ArenaEnterRecursive(Arena arena); extern void ArenaLeaveRecursive(Arena arena); -extern void (ArenaPoll)(Globals globals); -#ifdef MPS_PROD_EPCORE -#define ArenaPoll(globals) UNUSED(globals) -#endif -/* .nogc.why: ScriptWorks doesn't use MM-provided incremental GC, so */ -/* doesn't need to poll when allocating. */ - extern Bool (ArenaStep)(Globals globals, double interval, double multiplier); extern void ArenaClamp(Globals globals); extern void ArenaRelease(Globals globals); @@ -888,7 +889,7 @@ extern void (ShieldSuspend)(Arena arena); extern void (ShieldResume)(Arena arena); extern void (ShieldFlush)(Arena arena); -#if defined(THREAD_SINGLE) && defined(PROTECTION_NONE) +#ifdef DISABLE_SHIELD #define ShieldRaise(arena, seg, mode) \ BEGIN UNUSED(arena); UNUSED(seg); UNUSED(mode); END #define ShieldLower(arena, seg, mode) \ @@ -902,7 +903,7 @@ extern void (ShieldFlush)(Arena arena); #define ShieldSuspend(arena) BEGIN UNUSED(arena); END #define ShieldResume(arena) BEGIN UNUSED(arena); END #define ShieldFlush(arena) BEGIN UNUSED(arena); END -#endif +#endif /* DISABLE_SHIELD */ /* Protection Interface diff --git a/mps/code/protix.c b/mps/code/protix.c index 31c272bc5b9..e79972af9e6 100644 --- a/mps/code/protix.c +++ b/mps/code/protix.c @@ -44,9 +44,6 @@ #if !defined(MPS_OS_LI) && !defined(MPS_OS_FR) && !defined(MPS_OS_XC) #error "protix.c is Unix-specific, currently for MPS_OS_LI FR XC" #endif -#ifndef PROTECTION -#error "protix.c implements protection, but PROTECTION is not set" -#endif #include #include diff --git a/mps/code/protli.c b/mps/code/protli.c index ba48cab7f51..dc38154f2b7 100644 --- a/mps/code/protli.c +++ b/mps/code/protli.c @@ -16,9 +16,6 @@ #ifndef MPS_OS_LI #error "protli.c is Linux-specific, but MPS_OS_LI is not set" #endif -#ifndef PROTECTION -#error "protli.c implements protection, but PROTECTION is not set" -#endif #include #include diff --git a/mps/code/protsgix.c b/mps/code/protsgix.c index 39f19c90b4c..e587ac86424 100644 --- a/mps/code/protsgix.c +++ b/mps/code/protsgix.c @@ -24,9 +24,6 @@ #if defined(MPS_OS_XC) && defined(MPS_ARCH_PP) #error "protsgix.c does not work on Darwin on PowerPC. Use protxcpp.c" #endif -#ifndef PROTECTION -#error "protsgix.c implements protection, but PROTECTION is not set" -#endif #include /* for many functions */ #include /* for getpid */ diff --git a/mps/code/protw3.c b/mps/code/protw3.c index 37d886644f6..6ebd38d6e50 100644 --- a/mps/code/protw3.c +++ b/mps/code/protw3.c @@ -12,9 +12,6 @@ #ifndef MPS_OS_W3 #error "protw3.c is Win32-specific, but MPS_OS_W3 is not set" #endif -#ifndef PROTECTION -#error "protw3.c implements protection, but PROTECTION is not set" -#endif #include "mpswin.h" diff --git a/mps/code/protxc.c b/mps/code/protxc.c index 8f62bb3a5df..62ade6ed81b 100644 --- a/mps/code/protxc.c +++ b/mps/code/protxc.c @@ -76,9 +76,6 @@ #if !defined(MPS_OS_XC) #error "protxc.c is OS X specific" #endif -#if !defined(PROTECTION) -#error "protxc.c implements protection, but PROTECTION is not defined" -#endif SRCID(protxc, "$Id$"); diff --git a/mps/code/qs.c b/mps/code/qs.c index 40e290dceec..9f6e97a9972 100644 --- a/mps/code/qs.c +++ b/mps/code/qs.c @@ -532,6 +532,8 @@ int main(int argc, char *argv[]) die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "mps_arena_create"); + mps_arena_spare_commit_limit_set(arena, 0); + mps_tramp(&r, &go, NULL, 0); mps_arena_destroy(arena); diff --git a/mps/code/seg.c b/mps/code/seg.c index 1ba5041d036..7e6ad00defa 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -309,7 +309,10 @@ void SegSetSummary(Seg seg, RefSet summary) AVERT(Seg, seg); AVER(summary == RefSetEMPTY || SegRankSet(seg) != RankSetEMPTY); -#ifdef PROTECTION_NONE +#ifdef DISABLE_REMEMBERED_SET + /* Without protection, we can't maintain the remembered set because + there are writes we don't know about. TODO: rethink this when + implementating control. */ summary = RefSetUNIV; #endif if (summary != SegSummary(seg)) @@ -324,7 +327,7 @@ void SegSetRankAndSummary(Seg seg, RankSet rankSet, RefSet summary) AVERT(Seg, seg); AVER(RankSetCheck(rankSet)); -#ifdef PROTECTION_NONE +#ifdef DISABLE_REMEMBERED_SET if (rankSet != RankSetEMPTY) { summary = RefSetUNIV; } diff --git a/mps/design/config.txt b/mps/design/config.txt index c7184ab31ee..0bc7f71857b 100644 --- a/mps/design/config.txt +++ b/mps/design/config.txt @@ -539,13 +539,12 @@ _`.opt.thread`: ``CONFIG_THREAD_SINGLE`` causes the MPS to be built for single-threaded execution only, where locks are not needed and so lock operations can be defined as no-ops by ``lock.h``. -_`.opt.prot`: ``CONFIG_PROTECTION_NONE`` causes the MPS to be built -for an environment where there is no memory protection, and so segment summaries cannot be maintained by ``seg.c``. - -_`.opt.prot.thread`: If both ``CONFIG_THREAD_SINGLE`` and -``CONFIG_PROTECTION_NONE`` are defined, then the shield is not needed -and so shield operations can be defined as no-ops by ``mpm.h``. - +_`.opt.poll`: ``CONFIG_POLL_NONE`` causes the MPS to be built without +support for polling. This means that the arena must be clamped or +parked at all this, garbage collections can only be carried out +explicitly via ``mps_arena_collect()``, but it also means that +protection is not needed, and so shield operations can be replaced +with no-ops in ``mpm.h``. To document From 05c742dc83009710c6ea24ca2eb3dadb3874330f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 2 Apr 2014 15:50:18 +0100 Subject: [PATCH 032/266] We can't run the test cases yet with config_poll_none. Copied from Perforce Change: 185177 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 950e2d353dc..17bad3471c9 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -69,7 +69,7 @@ install: @INSTALL_TARGET@ test-make-build: $(MAKE) clean - $(MAKE) $(TARGET_OPTS) VARIETY=hot CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE -DCONFIG_POLL_NONE" testansi + $(MAKE) $(TARGET_OPTS) VARIETY=hot CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE" testansi $(MAKE) clean $(MAKE) $(TARGET_OPTS) testci From d236b99b39227b8dc5b6edcb4611ffa401e4bbcf Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 2 Apr 2014 16:02:09 +0100 Subject: [PATCH 033/266] Oops: no need to set the spare commit limit here. Copied from Perforce Change: 185182 ServerID: perforce.ravenbrook.com --- mps/code/qs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/mps/code/qs.c b/mps/code/qs.c index 9f6e97a9972..89f93fb2833 100644 --- a/mps/code/qs.c +++ b/mps/code/qs.c @@ -532,7 +532,6 @@ int main(int argc, char *argv[]) die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "mps_arena_create"); - mps_arena_spare_commit_limit_set(arena, 0); mps_tramp(&r, &go, NULL, 0); mps_arena_destroy(arena); From cf6b528d6efb4a7b70a222232a66c47f76cd1df2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 2 Apr 2014 16:53:46 +0100 Subject: [PATCH 034/266] Fix the build for the usual configuration (not disabled_shield). "make test" compiles the CONFIG_POLL_NONE configuration but doesn't run any test cases (not sure which ones are expected to pass yet). Copied from Perforce Change: 185188 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 4 +++- mps/code/mpm.h | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mps/Makefile.in b/mps/Makefile.in index 17bad3471c9..4ecd4e90aea 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -68,10 +68,12 @@ make-install-dirs: install: @INSTALL_TARGET@ test-make-build: + $(MAKE) clean + $(MAKE) $(TARGET_OPTS) testci $(MAKE) clean $(MAKE) $(TARGET_OPTS) VARIETY=hot CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE" testansi $(MAKE) clean - $(MAKE) $(TARGET_OPTS) testci + $(MAKE) $(TARGET_OPTS) VARIETY=hot CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE -DCONFIG_POLL_NONE" # TODO: actually run some tests in this configuration test-xcode-build: $(XCODEBUILD) -config Release -target testci diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 165d2c3b7ce..3bbd71cbb23 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -526,8 +526,8 @@ extern void (ArenaPoll)(Globals globals); #define ArenaLeave(arena) AVER(arena->busyTraces == TraceSetEMPTY) #define ArenaPoll(globals) UNUSED(globals) #else -#define ArenaEnter(arena) ArenaEnterLock(arena) -#define ArenaLeave(arena) ArenaLeaveLock(arena) +#define ArenaEnter(arena) ArenaEnterLock(arena, FALSE) +#define ArenaLeave(arena) ArenaLeaveLock(arena, FALSE) #endif extern void ArenaEnterRecursive(Arena arena); From a3055d56c0ac479f030528af6ff27ad02a39b2f1 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 3 Apr 2014 12:52:23 +0100 Subject: [PATCH 035/266] New module failover implements a fail-over allocator as a land class. Use Failover in MVT and MVFF. Test Failover in landtest. Implementation of LandFindInZones for Freelist (untested). Remove signature from RangeStruct so we can embed it without a space cost. Copied from Perforce Change: 185196 ServerID: perforce.ravenbrook.com --- mps/code/cbs.c | 33 +-- mps/code/cbs.h | 4 +- mps/code/comm.gmk | 1 + mps/code/commpre.nmk | 1 + mps/code/failover.c | 322 +++++++++++++++++++++++++ mps/code/failover.h | 69 ++++++ mps/code/freelist.c | 131 ++++++++-- mps/code/freelist.h | 4 +- mps/code/land.c | 36 ++- mps/code/landtest.c | 43 +++- mps/code/mpm.h | 4 +- mps/code/mpmst.h | 24 +- mps/code/mpmtypes.h | 7 +- mps/code/mps.c | 1 + mps/code/mps.xcodeproj/project.pbxproj | 16 +- mps/code/poolmv2.c | 117 ++++----- mps/code/poolmvff.c | 227 +++++++---------- mps/code/range.c | 8 +- mps/code/range.h | 8 +- mps/design/cbs.txt | 27 ++- mps/design/failover.txt | 150 ++++++++++++ mps/design/index.txt | 13 +- mps/design/land.txt | 51 +++- mps/design/poolmvff.txt | 8 +- mps/design/range.txt | 10 +- mps/design/splay.txt | 12 +- mps/manual/source/design/index.rst | 1 + 27 files changed, 991 insertions(+), 337 deletions(-) create mode 100644 mps/code/failover.c create mode 100644 mps/code/failover.h create mode 100644 mps/design/failover.txt diff --git a/mps/code/cbs.c b/mps/code/cbs.c index bfd21af7746..3e99e3ca195 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -66,7 +66,7 @@ Bool CBSCheck(CBS cbs) { /* See .enter-leave.simple. */ CHECKS(CBS, cbs); - CHECKL(LandCheck(&cbs->landStruct)); + CHECKD(Land, &cbs->landStruct); CHECKD(SplayTree, cbsSplay(cbs)); /* nothing to check about treeSize */ CHECKD(Pool, cbs->blockPool); @@ -226,7 +226,7 @@ static void cbsUpdateZonedNode(SplayTree splay, Tree tree) /* cbsInit -- Initialise a CBS structure * - * See . + * See . */ ARG_DEFINE_KEY(cbs_extend_by, Size); @@ -307,7 +307,7 @@ static Res cbsInit(Land land, ArgList args) /* CBSFinish -- Finish a CBS structure * - * See . + * See . */ static void cbsFinish(Land land) @@ -645,7 +645,7 @@ static Res cbsDeleteFromTree(Range rangeReturn, Land land, Range range) /* cbsDelete -- Remove a range from a CBS * - * See . + * See . * * .delete.alloc: Will only allocate a block if the range splits * an existing range. @@ -715,7 +715,7 @@ static Res cbsSplayNodeDescribe(Tree tree, mps_lib_FILE *stream) * This is because CBSIterate uses TreeTraverse, which does not permit * modification, for speed and to avoid perturbing the splay tree balance. * - * See . + * See . */ typedef struct CBSIterateClosure { @@ -777,20 +777,6 @@ static void cbsIterate(Land land, LandVisitor visitor, } -/* FindDeleteCheck -- check method for a FindDelete value */ - -Bool FindDeleteCheck(FindDelete findDelete) -{ - CHECKL(findDelete == FindDeleteNONE - || findDelete == FindDeleteLOW - || findDelete == FindDeleteHIGH - || findDelete == FindDeleteENTIRE); - UNUSED(findDelete); /* */ - - return TRUE; -} - - /* cbsFindDeleteRange -- delete appropriate range of block found */ static void cbsFindDeleteRange(Range rangeReturn, Range oldRangeReturn, @@ -1094,7 +1080,7 @@ static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn, /* cbsDescribe -- describe a CBS * - * See . + * See . */ static Res cbsDescribe(Land land, mps_lib_FILE *stream) @@ -1129,10 +1115,7 @@ static Res cbsDescribe(Land land, mps_lib_FILE *stream) return res; } - -typedef LandClassStruct CBSLandClassStruct; - -DEFINE_CLASS(CBSLandClass, class) +DEFINE_LAND_CLASS(CBSLandClass, class) { INHERIT_CLASS(class, LandClass); class->name = "CBS"; @@ -1147,10 +1130,10 @@ DEFINE_CLASS(CBSLandClass, class) class->findLargest = cbsFindLargest; class->findInZones = cbsFindInZones; class->describe = cbsDescribe; + AVERT(LandClass, class); } - /* C. COPYRIGHT AND LICENSE * * Copyright (C) 2001-2013 Ravenbrook Limited . diff --git a/mps/code/cbs.h b/mps/code/cbs.h index 170c41d496b..e6a3dd13850 100644 --- a/mps/code/cbs.h +++ b/mps/code/cbs.h @@ -28,9 +28,11 @@ typedef struct CBSBlockStruct { ZoneSet zones; /* union zone set of all ranges in sub-tree */ } CBSBlockStruct; +typedef struct CBSStruct *CBS; + extern Bool CBSCheck(CBS cbs); -extern CBSLandClass CBSLandClassGet(void); +extern LandClass CBSLandClassGet(void); extern const struct mps_key_s _mps_key_cbs_block_pool; #define CBSBlockPool (&_mps_key_cbs_block_pool) diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index beeb542fca9..44264ed0acf 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -177,6 +177,7 @@ MPMCOMMON = \ dbgpool.c \ dbgpooli.c \ event.c \ + failover.c \ format.c \ freelist.c \ global.c \ diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index 75dbdad446e..82b51bff382 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -123,6 +123,7 @@ MPMCOMMON=\ \ \ \ + \ \ \ \ diff --git a/mps/code/failover.c b/mps/code/failover.c new file mode 100644 index 00000000000..ca0d15cad1c --- /dev/null +++ b/mps/code/failover.c @@ -0,0 +1,322 @@ +/* failover.c: FAILOVER IMPLEMENTATION + * + * $Id$ + * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * + * .design: + */ + +#include "failover.h" +#include "mpm.h" +#include "range.h" + +SRCID(failover, "$Id$"); + + +#define failoverOfLand(land) PARENT(FailoverStruct, landStruct, land) + + +ARG_DEFINE_KEY(failover_primary, Pointer); +ARG_DEFINE_KEY(failover_secondary, Pointer); + + +Bool FailoverCheck(Failover fo) +{ + CHECKS(Failover, fo); + CHECKD(Land, &fo->landStruct); + CHECKD(Land, fo->primary); + CHECKD(Land, fo->secondary); + return TRUE; +} + + +static Res failoverInit(Land land, ArgList args) +{ + Failover fo; + LandClass super; + Land primary, secondary; + ArgStruct arg; + Res res; + + AVERT(Land, land); + super = LAND_SUPERCLASS(FailoverLandClass); + res = (*super->init)(land, args); + if (res != ResOK) + return res; + + ArgRequire(&arg, args, FailoverPrimary); + primary = arg.val.p; + ArgRequire(&arg, args, FailoverSecondary); + secondary = arg.val.p; + + fo = failoverOfLand(land); + fo->primary = primary; + fo->secondary = secondary; + fo->sig = FailoverSig; + AVERT(Failover, fo); + return ResOK; +} + + +static void failoverFinish(Land land) +{ + Failover fo; + + AVERT(Land, land); + fo = failoverOfLand(land); + AVERT(Failover, fo); + + fo->sig = SigInvalid; +} + + +static Res failoverInsert(Range rangeReturn, Land land, Range range) +{ + Failover fo; + Res res; + + AVER(rangeReturn != NULL); + AVERT(Land, land); + fo = failoverOfLand(land); + AVERT(Failover, fo); + AVERT(Range, range); + + /* Provide more opportunities for coalescence. See + * . + */ + LandFlush(fo->primary, fo->secondary); + + res = LandInsert(rangeReturn, fo->primary, range); + if (ResIsAllocFailure(res)) { + /* primary ran out of memory: try secondary instead. */ + res = LandInsert(rangeReturn, fo->secondary, range); + } + + return res; +} + + +static Res failoverDelete(Range rangeReturn, Land land, Range range) +{ + Failover fo; + Res res; + RangeStruct oldRange, dummyRange, left, right; + + AVER(rangeReturn != NULL); + AVERT(Land, land); + fo = failoverOfLand(land); + AVERT(Failover, fo); + AVERT(Range, range); + + /* Prefer efficient search in the primary. See + * . + */ + LandFlush(fo->primary, fo->secondary); + + res = LandDelete(&oldRange, fo->primary, range); + + if (res == ResFAIL) { + /* Range not found in primary: try secondary. */ + return LandDelete(rangeReturn, fo->secondary, range); + } else if (ResIsAllocFailure(res)) { + /* Range was found in primary, but couldn't be deleted because the + * primary is out of memory. Delete the whole of oldRange, and + * re-insert the fragments (which might end up in the secondary). + * See . + */ + res = LandDelete(&dummyRange, fo->primary, &oldRange); + if (res != ResOK) + return res; + + AVER(RangesEqual(&oldRange, &dummyRange)); + RangeInit(&left, RangeBase(&oldRange), RangeBase(range)); + if (!RangeEmpty(&left)) { + res = LandInsert(&dummyRange, land, &left); + AVER(res == ResOK); + } + RangeInit(&right, RangeLimit(range), RangeLimit(&oldRange)); + if (!RangeEmpty(&right)) { + res = LandInsert(&dummyRange, land, &right); + AVER(res == ResOK); + } + } + if (res == ResOK) { + AVER(RangesNest(&oldRange, range)); + RangeCopy(rangeReturn, &oldRange); + } + return res; +} + + +static void failoverIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) +{ + Failover fo; + + AVERT(Land, land); + fo = failoverOfLand(land); + AVERT(Failover, fo); + AVER(visitor != NULL); + + LandIterate(fo->primary, visitor, closureP, closureS); + LandIterate(fo->secondary, visitor, closureP, closureS); +} + + +static Bool failoverFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) +{ + Failover fo; + + AVER(rangeReturn != NULL); + AVER(oldRangeReturn != NULL); + AVERT(Land, land); + fo = failoverOfLand(land); + AVERT(Failover, fo); + AVERT(FindDelete, findDelete); + + /* See . */ + LandFlush(fo->primary, fo->secondary); + + return LandFindFirst(rangeReturn, oldRangeReturn, fo->primary, size, findDelete) + || LandFindFirst(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete); +} + + +static Bool failoverFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) +{ + Failover fo; + + AVER(rangeReturn != NULL); + AVER(oldRangeReturn != NULL); + AVERT(Land, land); + fo = failoverOfLand(land); + AVERT(Failover, fo); + AVERT(FindDelete, findDelete); + + /* See . */ + LandFlush(fo->primary, fo->secondary); + + return LandFindLast(rangeReturn, oldRangeReturn, fo->primary, size, findDelete) + || LandFindLast(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete); +} + + +static Bool failoverFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) +{ + Failover fo; + + AVER(rangeReturn != NULL); + AVER(oldRangeReturn != NULL); + AVERT(Land, land); + fo = failoverOfLand(land); + AVERT(Failover, fo); + AVERT(FindDelete, findDelete); + + /* See . */ + LandFlush(fo->primary, fo->secondary); + + return LandFindLargest(rangeReturn, oldRangeReturn, fo->primary, size, findDelete) + || LandFindLargest(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete); +} + + +static Bool failoverFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high) +{ + Failover fo; + + AVER(rangeReturn != NULL); + AVER(oldRangeReturn != NULL); + AVERT(Land, land); + fo = failoverOfLand(land); + AVERT(Failover, fo); + /* AVERT(ZoneSet, zoneSet); */ + AVERT(Bool, high); + + /* See . */ + LandFlush(fo->primary, fo->secondary); + + return LandFindInZones(rangeReturn, oldRangeReturn, fo->primary, size, zoneSet, high) + || LandFindInZones(rangeReturn, oldRangeReturn, fo->secondary, size, zoneSet, high); +} + + +static Res failoverDescribe(Land land, mps_lib_FILE *stream) +{ + Failover fo; + Res res; + + if (!TESTT(Land, land)) return ResFAIL; + fo = failoverOfLand(land); + if (!TESTT(Failover, fo)) return ResFAIL; + if (stream == NULL) return ResFAIL; + + res = WriteF(stream, + "Failover $P {\n", (WriteFP)fo, + " primary = $P ($S)\n", (WriteFP)fo->primary, + fo->primary->class->name, + " secondary = $P ($S)\n", (WriteFP)fo->secondary, + fo->secondary->class->name, + "}\n", NULL); + + return res; +} + + +DEFINE_LAND_CLASS(FailoverLandClass, class) +{ + INHERIT_CLASS(class, LandClass); + class->name = "FAILOVER"; + class->size = sizeof(FailoverStruct); + class->init = failoverInit; + class->finish = failoverFinish; + class->insert = failoverInsert; + class->delete = failoverDelete; + class->iterate = failoverIterate; + class->findFirst = failoverFindFirst; + class->findLast = failoverFindLast; + class->findLargest = failoverFindLargest; + class->findInZones = failoverFindInZones; + class->describe = failoverDescribe; + AVERT(LandClass, class); +} + + +/* 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/failover.h b/mps/code/failover.h new file mode 100644 index 00000000000..56e6149e05e --- /dev/null +++ b/mps/code/failover.h @@ -0,0 +1,69 @@ +/* failover.h: FAILOVER ALLOCATOR INTERFACE + * + * $Id$ + * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * + * .source: . + */ + +#ifndef failover_h +#define failover_h + +#include "mpmtypes.h" + +typedef struct FailoverStruct *Failover; + +extern Bool FailoverCheck(Failover failover); + +extern LandClass FailoverLandClassGet(void); + +extern const struct mps_key_s _mps_key_failover_primary; +#define FailoverPrimary (&_mps_key_failover_primary) +#define FailoverPrimary_FIELD p +extern const struct mps_key_s _mps_key_failover_secondary; +#define FailoverSecondary (&_mps_key_failover_secondary) +#define FailoverSecondary_FIELD p + +#endif /* failover.h */ + + +/* 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/freelist.c b/mps/code/freelist.c index 14091c02558..4706212bcc0 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -8,6 +8,7 @@ #include "freelist.h" #include "mpm.h" +#include "range.h" SRCID(freelist, "$Id$"); @@ -22,19 +23,36 @@ typedef union FreelistBlockUnion { /* limit is (char *)this + freelistAlignment(fl) */ } small; struct { - FreelistBlock next; + FreelistBlock next; /* not tagged (low bit 0) */ Addr limit; } large; } FreelistBlockUnion; -/* See */ +/* freelistMinimumAlignment -- the minimum allowed alignment for the + * address ranges in a free list: see + */ + #define freelistMinimumAlignment ((Align)sizeof(FreelistBlock)) +/* FreelistTag -- return the tag of word */ + #define FreelistTag(word) ((word) & 1) + + +/* FreelistTagSet -- return word updated with the tag set */ + #define FreelistTagSet(word) ((FreelistBlock)((Word)(word) | 1)) + + +/* FreelistTagReset -- return word updated with the tag reset */ + #define FreelistTagReset(word) ((FreelistBlock)((Word)(word) & ~(Word)1)) + + +/* FreelistTagCopy -- return 'to' updated to have the same tag as 'from' */ + #define FreelistTagCopy(to, from) ((FreelistBlock)((Word)(to) | FreelistTag((Word)(from)))) @@ -148,7 +166,7 @@ Bool FreelistCheck(Freelist fl) Land land; CHECKS(Freelist, fl); land = &fl->landStruct; - CHECKL(LandCheck(land)); + CHECKD(Land, land); /* See */ CHECKL(AlignIsAligned(LandAlignment(land), freelistMinimumAlignment)); CHECKL((fl->list == NULL) == (fl->listSize == 0)); @@ -195,12 +213,14 @@ static void freelistFinish(Land land) /* freelistBlockSetPrevNext -- update list of blocks + * * If prev and next are both NULL, make the block list empty. * Otherwise, if prev is NULL, make next the first block in the list. * Otherwise, if next is NULL, make prev the last block in the list. * Otherwise, make next follow prev in the list. * Update the count of blocks by 'delta'. */ + static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev, FreelistBlock next, int delta) { @@ -289,12 +309,14 @@ static Res freelistInsert(Range rangeReturn, Land land, Range range) } -/* freelistDeleteFromBlock -- delete 'range' from 'block' (it is known - * to be a subset of that block); update 'rangeReturn' to the original - * range of 'block' and update the block list accordingly: 'prev' is - * the block on the list just before 'block', or NULL if 'block' is - * the first block on the list. +/* freelistDeleteFromBlock -- delete range from block + * + * range must be a subset of block. Update rangeReturn to be the + * original range of block and update the block list accordingly: prev + * is on the list just before block, or NULL if block is the first + * block on the list. */ + static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl, Range range, FreelistBlock prev, FreelistBlock block) @@ -416,14 +438,17 @@ static void freelistIterate(Land land, LandVisitor visitor, } -/* freelistFindDeleteFromBlock -- Find a chunk of 'size' bytes in - * 'block' (which is known to be at least that big) and possibly - * delete that chunk according to the instruction in 'findDelete'. - * Return the range of that chunk in 'rangeReturn'. Return the - * original range of the block in 'oldRangeReturn'. Update the block - * list accordingly, using 'prev' which is the previous block in the - * list, or NULL if 'block' is the first block in the list. +/* freelistFindDeleteFromBlock -- delete size bytes from block + * + * Find a chunk of size bytes in block (which is known to be at least + * that big) and possibly delete that chunk according to the + * instruction in findDelete. Return the range of that chunk in + * rangeReturn. Return the original range of the block in + * oldRangeReturn. Update the block list accordingly, using prev, + * which is previous in list or NULL if block is the first block in + * the list. */ + static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn, Freelist fl, Size size, FindDelete findDelete, @@ -580,11 +605,77 @@ static Bool freelistFindLargest(Range rangeReturn, Range oldRangeReturn, } -/* freelistDescribeVisitor -- visitor method for freelistDescribe. +static Res freelistFindInZones(Range rangeReturn, Range oldRangeReturn, + Land land, Size size, + ZoneSet zoneSet, Bool high) +{ + Freelist fl; + LandFindMethod landFind; + RangeInZoneSet search; + Bool found = FALSE; + FreelistBlock prev, cur, next; + FreelistBlock foundPrev = NULL, foundCur = NULL; + RangeStruct foundRange; + + AVER(FALSE); /* TODO: this code is completely untested! */ + AVER(rangeReturn != NULL); + AVER(oldRangeReturn != NULL); + AVERT(Land, land); + fl = freelistOfLand(land); + AVERT(Freelist, fl); + /* AVERT(ZoneSet, zoneSet); */ + AVERT(Bool, high); + + landFind = high ? cbsFindLast : cbsFindFirst; + search = high ? RangeInZoneSetLast : RangeInZoneSetFirst; + + if (zoneSet == ZoneSetEMPTY) + return ResFAIL; + if (zoneSet == ZoneSetUNIV) { + FindDelete fd = high ? FindDeleteHIGH : FindDeleteLOW; + if ((*landFind)(rangeReturn, oldRangeReturn, land, size, fd)) + return ResOK; + else + return ResFAIL; + } + if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(LandArena(land))) + return ResFAIL; + + prev = NULL; + cur = fl->list; + while (cur) { + Addr base, limit; + if ((*search)(&base, &limit, FreelistBlockBase(cur), + FreelistBlockLimit(fl, cur), + LandArena(land), zoneSet, size)) + { + found = TRUE; + foundPrev = prev; + foundCur = cur; + RangeInit(&foundRange, base, limit); + if (!high) + break; + } + next = FreelistBlockNext(cur); + prev = cur; + cur = next; + } + + if (!found) + return ResFAIL; + + freelistDeleteFromBlock(oldRangeReturn, fl, &foundRange, foundPrev, foundCur); + RangeCopy(rangeReturn, &foundRange); + return ResOK; +} + + +/* freelistDescribeVisitor -- visitor method for freelistDescribe * * Writes a decription of the range into the stream pointed to by * closureP. */ + static Bool freelistDescribeVisitor(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS) { @@ -593,7 +684,7 @@ static Bool freelistDescribeVisitor(Bool *deleteReturn, Land land, Range range, if (deleteReturn == NULL) return FALSE; if (!TESTT(Land, land)) return FALSE; - if (!TESTT(Range, range)) return FALSE; + if (!RangeCheck(range)) return FALSE; if (stream == NULL) return FALSE; UNUSED(closureS); @@ -629,9 +720,7 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream) } -typedef LandClassStruct FreelistLandClassStruct; - -DEFINE_CLASS(FreelistLandClass, class) +DEFINE_LAND_CLASS(FreelistLandClass, class) { INHERIT_CLASS(class, LandClass); class->name = "FREELIST"; @@ -644,7 +733,9 @@ DEFINE_CLASS(FreelistLandClass, class) class->findFirst = freelistFindFirst; class->findLast = freelistFindLast; class->findLargest = freelistFindLargest; + class->findInZones = freelistFindInZones; class->describe = freelistDescribe; + AVERT(LandClass, class); } diff --git a/mps/code/freelist.h b/mps/code/freelist.h index 1ba46ae338d..c46ab57bc15 100644 --- a/mps/code/freelist.h +++ b/mps/code/freelist.h @@ -11,9 +11,11 @@ #include "mpmtypes.h" +typedef struct FreelistStruct *Freelist; + extern Bool FreelistCheck(Freelist freelist); -extern FreelistLandClass FreelistLandClassGet(void); +extern LandClass FreelistLandClassGet(void); #endif /* freelist.h */ diff --git a/mps/code/land.c b/mps/code/land.c index e06f0060e36..fe759d85410 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -12,11 +12,26 @@ SRCID(land, "$Id$"); +/* FindDeleteCheck -- check method for a FindDelete value */ + +Bool FindDeleteCheck(FindDelete findDelete) +{ + CHECKL(findDelete == FindDeleteNONE + || findDelete == FindDeleteLOW + || findDelete == FindDeleteHIGH + || findDelete == FindDeleteENTIRE); + UNUSED(findDelete); /* */ + + return TRUE; +} + + /* LandCheck -- check land */ Bool LandCheck(Land land) { CHECKS(Land, land); + CHECKD(LandClass, land->class); CHECKU(Arena, land->arena); CHECKL(AlignCheck(land->alignment)); return TRUE; @@ -34,8 +49,8 @@ Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *own AVER(land != NULL); AVERT(LandClass, class); - AVER(AlignCheck(alignment)); - + AVERT(Align, alignment); + land->alignment = alignment; land->arena = arena; land->class = class; @@ -236,8 +251,8 @@ Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size siz AVER(oldRangeReturn != NULL); AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); - /* AVER(ZoneSetCheck(zoneSet)); */ - AVER(BoolCheck(high)); + /* AVER(ZoneSet, zoneSet); */ + AVERT(Bool, high); return (*land->class->findInZones)(rangeReturn, oldRangeReturn, land, size, zoneSet, high); @@ -288,12 +303,13 @@ static Bool landFlushVisitor(Bool *deleteReturn, Land land, Range range, Land dest; AVER(deleteReturn != NULL); + AVERT(Land, land); AVERT(Range, range); AVER(closureP != NULL); UNUSED(closureS); dest = closureP; - res = LandInsert(&newRange, land, range); + res = LandInsert(&newRange, dest, range); if (res == ResOK) { *deleteReturn = TRUE; return TRUE; @@ -434,18 +450,18 @@ DEFINE_CLASS(LandClass, class) * 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 @@ -456,7 +472,7 @@ DEFINE_CLASS(LandClass, class) * 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/landtest.c b/mps/code/landtest.c index 5ca7305ebda..4698a9f1aaf 100644 --- a/mps/code/landtest.c +++ b/mps/code/landtest.c @@ -14,6 +14,7 @@ */ #include "cbs.h" +#include "failover.h" #include "freelist.h" #include "mpm.h" #include "mps.h" @@ -34,6 +35,7 @@ SRCID(landtest, "$Id$"); * the former. */ #define nCBSOperations ((Size)125000) #define nFLOperations ((Size)12500) +#define nFOOperations ((Size)12500) static Count NAllocateTried, NAllocateSucceeded, NDeallocateTried, NDeallocateSucceeded; @@ -479,7 +481,10 @@ extern int main(int argc, char *argv[]) BT allocTable; CBSStruct cbsStruct; FreelistStruct flStruct; - Land land; + FailoverStruct foStruct; + Land cbs = &cbsStruct.landStruct; + Land fl = &flStruct.landStruct; + Land fo = &foStruct.landStruct; Align align; testlib_init(argc, argv); @@ -507,26 +512,46 @@ extern int main(int argc, char *argv[]) (char *)dummyBlock + ArraySize); } - land = &cbsStruct.landStruct; MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, CBSFastFind, TRUE); - die((mps_res_t)LandInit(land, CBSLandClassGet(), arena, align, NULL, args), + die((mps_res_t)LandInit(cbs, CBSLandClassGet(), arena, align, NULL, args), "failed to initialise CBS"); } MPS_ARGS_END(args); state.align = align; state.block = dummyBlock; state.allocTable = allocTable; - state.land = land; + state.land = cbs; test(&state, nCBSOperations); - LandFinish(land); + LandFinish(cbs); - land = &flStruct.landStruct; - die((mps_res_t)LandInit(land, FreelistLandClassGet(), arena, align, NULL, + die((mps_res_t)LandInit(fl, FreelistLandClassGet(), arena, align, NULL, mps_args_none), "failed to initialise Freelist"); - state.land = land; + state.land = fl; test(&state, nFLOperations); - LandFinish(land); + LandFinish(fl); + + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, CBSFastFind, TRUE); + die((mps_res_t)LandInit(cbs, CBSLandClassGet(), arena, align, + NULL, args), + "failed to initialise CBS"); + } MPS_ARGS_END(args); + die((mps_res_t)LandInit(fl, FreelistLandClassGet(), arena, align, NULL, + mps_args_none), + "failed to initialise Freelist"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, FailoverPrimary, cbs); + MPS_ARGS_ADD(args, FailoverSecondary, fl); + die((mps_res_t)LandInit(fo, FailoverLandClassGet(), arena, align, NULL, + args), + "failed to initialise Failover"); + } MPS_ARGS_END(args); + state.land = fo; + test(&state, nFOOperations); + LandFinish(fo); + LandFinish(fl); + LandFinish(cbs); mps_arena_destroy(arena); diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 7096618f565..69765515fe5 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -807,7 +807,7 @@ extern AllocPattern AllocPatternRamp(void); extern AllocPattern AllocPatternRampCollectAll(void); -/* FindDelete -- see and */ +/* FindDelete -- see */ extern Bool FindDeleteCheck(FindDelete findDelete); @@ -1015,6 +1015,8 @@ extern void LandFlush(Land dest, Land src); extern Bool LandClassCheck(LandClass class); extern LandClass LandClassGet(void); #define LAND_SUPERCLASS(className) ((LandClass)SUPERCLASS(className)) +#define DEFINE_LAND_CLASS(className, var) \ + DEFINE_ALIAS_CLASS(className, LandClass, var) /* Stack Probe */ diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 6679dbafd75..35684a52950 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -646,8 +646,8 @@ typedef struct LandStruct { /* CBSStruct -- coalescing block structure * - * CBS is a subclass of Land that maintains a collection of disjoint - * ranges in a splay tree. + * CBS is a Land implementation that maintains a collection of + * disjoint ranges in a splay tree. * * See . */ @@ -669,6 +669,24 @@ typedef struct CBSStruct { } CBSStruct; +/* FailoverStruct -- fail over from one land to another + * + * Failover is a Land implementation that combines two other Lands, + * using primary until it fails, and then using secondary. + * + * See . + */ + +#define FailoverSig ((Sig)0x519FA170) /* SIGnature FAILOver */ + +typedef struct FailoverStruct { + LandStruct landStruct; /* superclass fields come first */ + Land primary; /* use this land normally */ + Land secondary; /* but use this one if primary fails */ + Sig sig; /* .class.end-sig */ +} FailoverStruct; + + /* FreelistStruct -- address-ordered freelist * * Freelist is a subclass of Land that maintains a collection of @@ -679,6 +697,8 @@ typedef struct CBSStruct { #define FreelistSig ((Sig)0x519F6331) /* SIGnature FREEL */ +typedef union FreelistBlockUnion *FreelistBlock; + typedef struct FreelistStruct { LandStruct landStruct; /* superclass fields come first */ FreelistBlock list; diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 424216ee0b3..72b09af099e 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -113,11 +113,6 @@ typedef struct RangeStruct *Range; /* */ typedef struct LandStruct *Land; /* */ typedef struct LandClassStruct *LandClass; /* */ typedef unsigned FindDelete; /* */ -typedef LandClass CBSLandClass; /* */ -typedef struct CBSStruct *CBS; /* */ -typedef LandClass FreelistLandClass; /* */ -typedef struct FreelistStruct *Freelist; /* */ -typedef union FreelistBlockUnion *FreelistBlock; /* */ /* Arena*Method -- see */ @@ -439,7 +434,7 @@ enum { }; -/* FindDelete operations -- see and */ +/* FindDelete operations -- see */ enum { FindDeleteNONE = 1, /* don't delete after finding */ diff --git a/mps/code/mps.c b/mps/code/mps.c index 34c7a9b49cd..f404855310e 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -76,6 +76,7 @@ #include "freelist.c" #include "sa.c" #include "land.c" +#include "failover.c" /* Additional pool classes */ diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index c987b57b4e9..03cbf5c2bc4 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -42,11 +42,11 @@ 22B2BC3D18B643B300C33E63 /* PBXTargetDependency */, 2291A5E6175CB207001D4920 /* PBXTargetDependency */, 2291A5E8175CB20E001D4920 /* PBXTargetDependency */, - 3114A65B156E95B4001E0AA3 /* PBXTargetDependency */, 3114A5CC156E932C001E0AA3 /* PBXTargetDependency */, 3114A5EA156E93C4001E0AA3 /* PBXTargetDependency */, 224CC79D175E187C002FF81B /* PBXTargetDependency */, 22B2BC3F18B643B700C33E63 /* PBXTargetDependency */, + 3114A65B156E95B4001E0AA3 /* PBXTargetDependency */, 2231BB6D18CA986B002D6322 /* PBXTargetDependency */, 31D60034156D3D5A00337B26 /* PBXTargetDependency */, 2231BB6F18CA986D002D6322 /* PBXTargetDependency */, @@ -1258,6 +1258,11 @@ 2291A5F0175CB7A4001D4920 /* testlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = testlib.h; sourceTree = ""; }; 22B2BC2B18B6434000C33E63 /* scheme-advanced.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "scheme-advanced.c"; path = "../example/scheme/scheme-advanced.c"; sourceTree = ""; }; 22B2BC3618B6434F00C33E63 /* scheme-advanced */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "scheme-advanced"; sourceTree = BUILT_PRODUCTS_DIR; }; + 22C5C99A18EC6AEC004C63D4 /* failover.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = failover.c; sourceTree = ""; }; + 22C5C99B18EC6AEC004C63D4 /* failover.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = failover.h; sourceTree = ""; }; + 22C5C99C18EC6AEC004C63D4 /* land.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = land.c; sourceTree = ""; }; + 22DD93E118ED815F00240DD2 /* failover.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = failover.txt; path = ../design/failover.txt; sourceTree = ""; }; + 22DD93E218ED815F00240DD2 /* land.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = land.txt; path = ../design/land.txt; sourceTree = ""; }; 22FA177516E8D6FC0098B23F /* amcssth */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = amcssth; sourceTree = BUILT_PRODUCTS_DIR; }; 22FA177616E8D7A80098B23F /* amcssth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = amcssth.c; sourceTree = ""; }; 2D07B96C1636FC7200DB751B /* eventsql.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = eventsql.c; sourceTree = ""; }; @@ -1927,6 +1932,7 @@ 31160D9C1899540D0071EB17 /* config.txt */, 31160D9D1899540D0071EB17 /* critical-path.txt */, 31160D9E1899540D0071EB17 /* diag.txt */, + 22DD93E118ED815F00240DD2 /* failover.txt */, 31160D9F1899540D0071EB17 /* finalize.txt */, 31160DA01899540D0071EB17 /* fix.txt */, 31160DA11899540D0071EB17 /* freelist.txt */, @@ -1936,6 +1942,7 @@ 31160DA51899540D0071EB17 /* interface-c.txt */, 31160DA61899540D0071EB17 /* io.txt */, 31160DA71899540D0071EB17 /* keyword-arguments.txt */, + 22DD93E218ED815F00240DD2 /* land.txt */, 31160DA81899540D0071EB17 /* lib.txt */, 31160DA91899540D0071EB17 /* lock.txt */, 31160DAA1899540D0071EB17 /* locus.txt */, @@ -2004,7 +2011,6 @@ 3114A613156E944A001E0AA3 /* bttest.c */, 2291A5AA175CAA9B001D4920 /* exposet0.c */, 2291A5AB175CAA9B001D4920 /* expt825.c */, - 2291A5E9175CB4EC001D4920 /* landtest.c */, 3114A5CD156E9369001E0AA3 /* finalcv.c */, 3114A5E5156E93B9001E0AA3 /* finaltest.c */, 3124CAC6156BE48D00753214 /* fmtdy.c */, @@ -2012,6 +2018,7 @@ 3124CAE4156BE6D500753214 /* fmthe.c */, 3124CACC156BE4C200753214 /* fmtno.c */, 224CC79E175E3202002FF81B /* fotest.c */, + 2291A5E9175CB4EC001D4920 /* landtest.c */, 2231BB6818CA9834002D6322 /* locbwcss.c */, 31D60036156D3E0200337B26 /* lockcov.c */, 2231BB6918CA983C002D6322 /* locusss.c */, @@ -2152,10 +2159,13 @@ 311F2F5917398AE900C15B6A /* eventcom.h */, 311F2F5A17398AE900C15B6A /* eventdef.h */, 311F2F5C17398AE900C15B6A /* eventrep.h */, + 22C5C99A18EC6AEC004C63D4 /* failover.c */, + 22C5C99B18EC6AEC004C63D4 /* failover.h */, 31EEAC1A156AB2B200714D05 /* format.c */, 2291A5EE175CB768001D4920 /* freelist.c */, 2291A5EF175CB768001D4920 /* freelist.h */, 31EEAC07156AB27B00714D05 /* global.c */, + 22C5C99C18EC6AEC004C63D4 /* land.c */, 31EEAC2B156AB2F200714D05 /* ld.c */, 311F2F5E17398B0E00C15B6A /* lock.h */, 31EEAC08156AB27B00714D05 /* locus.c */, @@ -3120,11 +3130,11 @@ 318DA8C31892B0F30089718C /* djbench */, 2291A5D3175CB05F001D4920 /* exposet0 */, 2291A5C1175CAFCA001D4920 /* expt825 */, - 3114A64B156E9596001E0AA3 /* landtest */, 3114A5BC156E9315001E0AA3 /* finalcv */, 3114A5D5156E93A0001E0AA3 /* finaltest */, 224CC78C175E1821002FF81B /* fotest */, 6313D46718A400B200EB03EF /* gcbench */, + 3114A64B156E9596001E0AA3 /* landtest */, 2231BB4C18CA97D8002D6322 /* locbwcss */, 31D60026156D3D3E00337B26 /* lockcov */, 2231BB5A18CA97DC002D6322 /* locusss */, diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index adc0abf426f..6baa0322a53 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -53,6 +53,7 @@ static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena); static ABQ MVTABQ(MVT mvt); static Land MVTCBS(MVT mvt); static Land MVTFreelist(MVT mvt); +static Land MVTFailover(MVT mvt); /* Types */ @@ -62,6 +63,7 @@ typedef struct MVTStruct PoolStruct poolStruct; CBSStruct cbsStruct; /* The coalescing block structure */ FreelistStruct flStruct; /* The emergency free list structure */ + FailoverStruct foStruct; /* The fail-over mechanism */ ABQStruct abqStruct; /* The available block queue */ /* */ Size minSize; /* Pool parameter */ @@ -180,6 +182,12 @@ static Land MVTFreelist(MVT mvt) } +static Land MVTFailover(MVT mvt) +{ + return &mvt->foStruct.landStruct; +} + + /* Methods */ @@ -276,14 +284,23 @@ static Res MVTInit(Pool pool, ArgList args) if (res != ResOK) goto failCBS; - res = ABQInit(arena, MVTABQ(mvt), (void *)mvt, abqDepth, sizeof(RangeStruct)); - if (res != ResOK) - goto failABQ; - res = LandInit(MVTFreelist(mvt), FreelistLandClassGet(), arena, align, mvt, mps_args_none); if (res != ResOK) goto failFreelist; + + MPS_ARGS_BEGIN(foArgs) { + MPS_ARGS_ADD(foArgs, FailoverPrimary, MVTCBS(mvt)); + MPS_ARGS_ADD(foArgs, FailoverSecondary, MVTFreelist(mvt)); + res = LandInit(MVTFailover(mvt), FailoverLandClassGet(), arena, align, mvt, + foArgs); + } MPS_ARGS_END(foArgs); + if (res != ResOK) + goto failFailover; + + res = ABQInit(arena, MVTABQ(mvt), (void *)mvt, abqDepth, sizeof(RangeStruct)); + if (res != ResOK) + goto failABQ; pool->alignment = align; mvt->reuseSize = reuseSize; @@ -348,9 +365,11 @@ static Res MVTInit(Pool pool, ArgList args) reserveDepth, fragLimit); return ResOK; -failFreelist: - ABQFinish(arena, MVTABQ(mvt)); failABQ: + LandFinish(MVTFailover(mvt)); +failFailover: + LandFinish(MVTFreelist(mvt)); +failFreelist: LandFinish(MVTCBS(mvt)); failCBS: AVER(res != ResOK); @@ -370,6 +389,7 @@ static Bool MVTCheck(MVT mvt) CHECKD(ABQ, &mvt->abqStruct); /* CHECKL(ABQCheck(MVTABQ(mvt))); */ CHECKD(Freelist, &mvt->flStruct); + CHECKD(Failover, &mvt->foStruct); CHECKL(mvt->reuseSize >= 2 * mvt->fillSize); CHECKL(mvt->fillSize >= mvt->maxSize); CHECKL(mvt->maxSize >= mvt->meanSize); @@ -422,9 +442,10 @@ static void MVTFinish(Pool pool) SegFree(SegOfPoolRing(node)); } - /* Finish the Freelist, ABQ and CBS structures */ - LandFinish(MVTFreelist(mvt)); + /* Finish the ABQ, Failover, Freelist and CBS structures */ ABQFinish(arena, MVTABQ(mvt)); + LandFinish(MVTFailover(mvt)); + LandFinish(MVTFreelist(mvt)); LandFinish(MVTCBS(mvt)); } @@ -615,14 +636,7 @@ static Bool MVTABQFill(Addr *baseReturn, Addr *limitReturn, } -/* MVTContingencyFill -- try to fill a request from the CBS or Freelist - * - * (The CBS and Freelist are lumped together under the heading of - * "contingency" for historical reasons: the Freelist used to be part - * of the CBS. There is no principled reason why these two are - * searched at the same time: if it should prove convenient to - * separate them, go ahead.) - */ +/* MVTContingencyFill -- try to fill a request from the free lists */ static Bool MVTContingencyFill(Addr *baseReturn, Addr *limitReturn, MVT mvt, Size minSize) { @@ -711,8 +725,7 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn, METER_ACC(mvt->underflows, minSize); /* If fragmentation is acceptable, attempt to find a free block from - the CBS or Freelist. - */ + the free lists. */ if (mvt->available >= mvt->availLimit) { METER_ACC(mvt->fragLimitContingencies, minSize); if (MVTContingencyFill(baseReturn, limitReturn, mvt, minSize)) @@ -798,8 +811,8 @@ static Bool MVTReserve(MVT mvt, Range range) } -/* MVTInsert -- insert an address range into the CBS (or the Freelist - * if that fails) and update the ABQ accordingly. +/* MVTInsert -- insert an address range into the free lists and update + * the ABQ accordingly. */ static Res MVTInsert(MVT mvt, Addr base, Addr limit) { @@ -808,18 +821,9 @@ static Res MVTInsert(MVT mvt, Addr base, Addr limit) AVERT(MVT, mvt); AVER(base < limit); - - /* Attempt to flush the Freelist to the CBS to give maximum - * opportunities for coalescence. */ - LandFlush(MVTCBS(mvt), MVTFreelist(mvt)); RangeInit(&range, base, limit); - res = LandInsert(&newRange, MVTCBS(mvt), &range); - if (ResIsAllocFailure(res)) { - /* CBS ran out of memory for splay nodes: add range to emergency - * free list instead. */ - res = LandInsert(&newRange, MVTFreelist(mvt), &range); - } + res = LandInsert(&newRange, MVTFailover(mvt), &range); if (res != ResOK) return res; @@ -836,8 +840,8 @@ static Res MVTInsert(MVT mvt, Addr base, Addr limit) } -/* MVTDelete -- delete an address range from the CBS and the Freelist, - * and update the ABQ accordingly. +/* MVTDelete -- delete an address range from the free lists, and + * update the ABQ accordingly. */ static Res MVTDelete(MVT mvt, Addr base, Addr limit) { @@ -848,27 +852,7 @@ static Res MVTDelete(MVT mvt, Addr base, Addr limit) AVER(base < limit); RangeInit(&range, base, limit); - res = LandDelete(&rangeOld, MVTCBS(mvt), &range); - if (ResIsAllocFailure(res)) { - /* CBS ran out of memory for splay nodes, which must mean that - * there were fragments on both sides: see - * . Handle this by - * deleting the whole of rangeOld (which requires no - * allocation) and re-inserting the fragments. */ - RangeStruct rangeOld2; - res = LandDelete(&rangeOld2, MVTCBS(mvt), &rangeOld); - AVER(res == ResOK); - AVER(RangesEqual(&rangeOld2, &rangeOld)); - AVER(RangeBase(&rangeOld) != base); - res = MVTInsert(mvt, RangeBase(&rangeOld), base); - AVER(res == ResOK); - AVER(RangeLimit(&rangeOld) != limit); - res = MVTInsert(mvt, limit, RangeLimit(&rangeOld)); - AVER(res == ResOK); - } else if (res == ResFAIL) { - /* Not found in the CBS: try the Freelist. */ - res = LandDelete(&rangeOld, MVTFreelist(mvt), &range); - } + res = LandDelete(&rangeOld, MVTFailover(mvt), &range); if (res != ResOK) return res; AVER(RangesNest(&rangeOld, &range)); @@ -1048,12 +1032,12 @@ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream) res = LandDescribe(MVTCBS(mvt), stream); if(res != ResOK) return res; - - res = ABQDescribe(MVTABQ(mvt), (ABQDescribeElement)RangeDescribe, stream); - if(res != ResOK) return res; - res = LandDescribe(MVTFreelist(mvt), stream); if(res != ResOK) return res; + res = LandDescribe(MVTFailover(mvt), stream); + if(res != ResOK) return res; + res = ABQDescribe(MVTABQ(mvt), (ABQDescribeElement)RangeDescribe, stream); + if(res != ResOK) return res; res = METER_WRITE(mvt->segAllocs, stream); if (res != ResOK) return res; @@ -1291,8 +1275,8 @@ static Bool MVTRefillVisitor(Bool *deleteReturn, Land land, Range range, return MVTReserve(mvt, range); } -/* MVTRefillABQIfEmpty -- refill the ABQ from the CBS and the Freelist if - * it is empty +/* MVTRefillABQIfEmpty -- refill the ABQ from the free lists if it is + * empty. */ static void MVTRefillABQIfEmpty(MVT mvt, Size size) { @@ -1300,15 +1284,14 @@ static void MVTRefillABQIfEmpty(MVT mvt, Size size) AVER(size > 0); /* If there have never been any overflows from the ABQ back to the - * CBS/Freelist, then there cannot be any blocks in the CBS/Freelist + * free lists, then there cannot be any blocks in the free lists * that are worth adding to the ABQ. So as an optimization, we don't * bother to look. */ if (mvt->abqOverflow && ABQIsEmpty(MVTABQ(mvt))) { mvt->abqOverflow = FALSE; METER_ACC(mvt->refills, size); - LandIterate(MVTCBS(mvt), &MVTRefillVisitor, mvt, 0); - LandIterate(MVTFreelist(mvt), &MVTRefillVisitor, mvt, 0); + LandIterate(MVTFailover(mvt), &MVTRefillVisitor, mvt, 0); } } @@ -1377,8 +1360,9 @@ static Bool MVTContingencyVisitor(Bool *deleteReturn, Land land, Range range, return TRUE; } -/* MVTContingencySearch -- search the CBS and the Freelist for a block - * of size min */ +/* MVTContingencySearch -- search the free lists for a block of size + * min. + */ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn, MVT mvt, Size min) @@ -1392,10 +1376,7 @@ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn, cls.steps = 0; cls.hardSteps = 0; - LandFlush(MVTCBS(mvt), MVTFreelist(mvt)); - - LandIterate(MVTCBS(mvt), MVTContingencyVisitor, (void *)&cls, 0); - LandIterate(MVTFreelist(mvt), MVTContingencyVisitor, (void *)&cls, 0); + LandIterate(MVTFailover(mvt), MVTContingencyVisitor, (void *)&cls, 0); if (!cls.found) return FALSE; diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index bbdb40fa510..818b4f932aa 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -50,6 +50,7 @@ typedef struct MVFFStruct { /* MVFF pool outer structure */ Size free; /* total free bytes in pool */ CBSStruct cbsStruct; /* free list */ FreelistStruct flStruct; /* emergency free list */ + FailoverStruct foStruct; /* fail-over mechanism */ Bool firstFit; /* as opposed to last fit */ Bool slotHigh; /* prefers high part of large block */ Sig sig; /* */ @@ -59,7 +60,8 @@ typedef struct MVFFStruct { /* MVFF pool outer structure */ #define Pool2MVFF(pool) PARENT(MVFFStruct, poolStruct, pool) #define MVFF2Pool(mvff) (&((mvff)->poolStruct)) #define CBSOfMVFF(mvff) (&((mvff)->cbsStruct.landStruct)) -#define FreelistOfMVFF(mvff) (&((mvff)->flStruct.landStruct)) +#define FreelistOfMVFF(mvff) (&((mvff)->flStruct.landStruct)) +#define FailoverOfMVFF(mvff) (&((mvff)->foStruct.landStruct)) static Bool MVFFCheck(MVFF mvff); @@ -78,48 +80,39 @@ typedef MVFFDebugStruct *MVFFDebug; #define MVFFDebug2MVFF(mvffd) (&((mvffd)->mvffStruct)) -/* MVFFAddToFreeList -- Add given range to free list +/* MVFFInsert -- add given range to free lists * - * Updates MVFF counters for additional free space. Returns maximally - * coalesced range containing given range. Does not attempt to free + * Updates MVFF counters for additional free space. Returns maximally + * coalesced range containing given range. Does not attempt to free * segments (see MVFFFreeSegs). */ -static Res MVFFAddToFreeList(Addr *baseIO, Addr *limitIO, MVFF mvff) { +static Res MVFFInsert(Range rangeIO, MVFF mvff) { Res res; - RangeStruct range, newRange; + Size size; - AVER(baseIO != NULL); - AVER(limitIO != NULL); + AVER(rangeIO != NULL); AVERT(MVFF, mvff); - RangeInit(&range, *baseIO, *limitIO); - res = LandInsert(&newRange, CBSOfMVFF(mvff), &range); - if (ResIsAllocFailure(res)) { - /* CBS ran out of memory for splay nodes: add range to emergency - * free list instead. */ - res = LandInsert(&newRange, FreelistOfMVFF(mvff), &range); - } + size = RangeSize(rangeIO); + res = LandInsert(rangeIO, FailoverOfMVFF(mvff), rangeIO); - if (res == ResOK) { - mvff->free += RangeSize(&range); - *baseIO = RangeBase(&newRange); - *limitIO = RangeLimit(&newRange); - } + if (res == ResOK) + mvff->free += size; return res; } -/* MVFFFreeSegs -- Free segments from given range +/* MVFFFreeSegs -- free segments from given range * - * Given a free range, attempts to find entire segments within - * it, and returns them to the arena, updating total size counter. + * Given a free range, attempts to find entire segments within it, and + * returns them to the arena, updating total size counter. * - * This is usually called immediately after MVFFAddToFreeList. - * It is not combined with MVFFAddToFreeList because the latter - * is also called when new segments are added under MVFFAlloc. + * This is usually called immediately after MVFFInsert. It is not + * combined with MVFFInsert because the latter is also called when new + * segments are added under MVFFAlloc. */ -static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit) +static void MVFFFreeSegs(MVFF mvff, Range range) { Seg seg = NULL; /* suppress "may be used uninitialized" */ Arena arena; @@ -129,72 +122,42 @@ static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit) Res res; AVERT(MVFF, mvff); - AVER(base < limit); + AVERT(Range, range); /* Could profitably AVER that the given range is free, */ /* but the CBS doesn't provide that facility. */ - if (AddrOffset(base, limit) < mvff->minSegSize) + if (RangeSize(range) < mvff->minSegSize) return; /* not large enough for entire segments */ arena = PoolArena(MVFF2Pool(mvff)); - b = SegOfAddr(&seg, arena, base); + b = SegOfAddr(&seg, arena, RangeBase(range)); AVER(b); segBase = SegBase(seg); segLimit = SegLimit(seg); - while(segLimit <= limit) { /* segment ends in range */ - if (segBase >= base) { /* segment starts in range */ - RangeStruct range, oldRange; - RangeInit(&range, segBase, segLimit); - - res = LandDelete(&oldRange, CBSOfMVFF(mvff), &range); - if (res == ResOK) { - mvff->free -= RangeSize(&range); - } else if (ResIsAllocFailure(res)) { - /* CBS ran out of memory for splay nodes, which must mean that - * there were fragments on both sides: see - * . Handle this by - * deleting the whole of oldRange (which requires no - * allocation) and re-inserting the fragments. */ - RangeStruct oldRange2; - res = LandDelete(&oldRange2, CBSOfMVFF(mvff), &oldRange); - AVER(res == ResOK); - AVER(RangesEqual(&oldRange2, &oldRange)); - mvff->free -= RangeSize(&oldRange); - AVER(RangeBase(&oldRange) != segBase); - { - Addr leftBase = RangeBase(&oldRange); - Addr leftLimit = segBase; - res = MVFFAddToFreeList(&leftBase, &leftLimit, mvff); - } - AVER(RangeLimit(&oldRange) != segLimit); - { - Addr rightBase = segLimit; - Addr rightLimit = RangeLimit(&oldRange); - res = MVFFAddToFreeList(&rightBase, &rightLimit, mvff); - } - } else if (res == ResFAIL) { - /* Not found in the CBS: must be found in the Freelist. */ - res = LandDelete(&oldRange, FreelistOfMVFF(mvff), &range); - AVER(res == ResOK); - mvff->free -= RangeSize(&range); - } + while(segLimit <= RangeLimit(range)) { /* segment ends in range */ + if (segBase >= RangeBase(range)) { /* segment starts in range */ + RangeStruct delRange, oldRange; + RangeInit(&delRange, segBase, segLimit); + res = LandDelete(&oldRange, FailoverOfMVFF(mvff), &delRange); AVER(res == ResOK); - AVER(RangesNest(&oldRange, &range)); + AVER(RangesNest(&oldRange, &delRange)); /* Can't free the segment earlier, because if it was on the * Freelist rather than the CBS then it likely contains data * that needs to be read in order to update the Freelist. */ SegFree(seg); - mvff->total -= RangeSize(&range); + + mvff->free -= RangeSize(&delRange); + mvff->total -= RangeSize(&delRange); } /* Avoid calling SegNext if the next segment would fail */ /* the loop test, mainly because there might not be a */ /* next segment. */ - if (segLimit == limit) /* segment ends at end of range */ + if (segLimit == RangeLimit(range)) /* segment ends at end of range */ break; b = SegFindAboveAddr(&seg, arena, segBase); @@ -210,8 +173,8 @@ static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit) /* MVFFAddSeg -- Allocates a new segment from the arena * * Allocates a new segment from the arena (with the given - * withReservoirPermit flag) of at least the specified size. The - * specified size should be pool-aligned. Adds it to the free list. + * withReservoirPermit flag) of at least the specified size. The + * specified size should be pool-aligned. Adds it to the free lists. */ static Res MVFFAddSeg(Seg *segReturn, MVFF mvff, Size size, Bool withReservoirPermit) @@ -222,7 +185,7 @@ static Res MVFFAddSeg(Seg *segReturn, Seg seg; Res res; Align align; - Addr base, limit; + RangeStruct range; AVERT(MVFF, mvff); AVER(size > 0); @@ -257,12 +220,11 @@ static Res MVFFAddSeg(Seg *segReturn, } mvff->total += segSize; - base = SegBase(seg); - limit = AddrAdd(base, segSize); - DebugPoolFreeSplat(pool, base, limit); - res = MVFFAddToFreeList(&base, &limit, mvff); + RangeInitSize(&range, SegBase(seg), segSize); + DebugPoolFreeSplat(pool, RangeBase(&range), RangeLimit(&range)); + res = MVFFInsert(&range, mvff); AVER(res == ResOK); - AVER(base <= SegBase(seg)); + AVER(RangeBase(&range) <= SegBase(seg)); if (mvff->minSegSize > segSize) mvff->minSegSize = segSize; /* Don't call MVFFFreeSegs; that would be silly. */ @@ -272,48 +234,34 @@ static Res MVFFAddSeg(Seg *segReturn, } -/* MVFFFindFirstFree -- Finds the first (or last) suitable free block +/* MVFFFindFree -- find the first (or last) suitable free block * * Finds a free block of the given (pool aligned) size, according * to a first (or last) fit policy controlled by the MVFF fields * firstFit, slotHigh (for whether to allocate the top or bottom * portion of a larger block). * - * Will return FALSE if the free list has no large enough block. - * In particular, will not attempt to allocate a new segment. + * Will return FALSE if the free lists have no large enough block. In + * particular, will not attempt to allocate a new segment. */ -static Bool MVFFFindFirstFree(Addr *baseReturn, Addr *limitReturn, - MVFF mvff, Size size) +static Bool MVFFFindFree(Range rangeReturn, MVFF mvff, Size size) { Bool foundBlock; FindDelete findDelete; - RangeStruct range, oldRange; + RangeStruct oldRange; - AVER(baseReturn != NULL); - AVER(limitReturn != NULL); + AVER(rangeReturn != NULL); AVERT(MVFF, mvff); AVER(size > 0); AVER(SizeIsAligned(size, PoolAlignment(MVFF2Pool(mvff)))); - LandFlush(CBSOfMVFF(mvff), FreelistOfMVFF(mvff)); - findDelete = mvff->slotHigh ? FindDeleteHIGH : FindDeleteLOW; foundBlock = (mvff->firstFit ? LandFindFirst : LandFindLast) - (&range, &oldRange, CBSOfMVFF(mvff), size, findDelete); - - if (!foundBlock) { - /* Failed to find a block in the CBS: try the emergency free list - * as well. */ - foundBlock = - (mvff->firstFit ? LandFindFirst : LandFindLast) - (&range, &oldRange, FreelistOfMVFF(mvff), size, findDelete); - } + (rangeReturn, &oldRange, FailoverOfMVFF(mvff), size, findDelete); if (foundBlock) { - *baseReturn = RangeBase(&range); - *limitReturn = RangeLimit(&range); mvff->free -= size; } @@ -328,7 +276,7 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size, { Res res; MVFF mvff; - Addr base, limit; + RangeStruct range; Bool foundBlock; AVERT(Pool, pool); @@ -341,29 +289,28 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size, size = SizeAlignUp(size, PoolAlignment(pool)); - foundBlock = MVFFFindFirstFree(&base, &limit, mvff, size); + foundBlock = MVFFFindFree(&range, mvff, size); if (!foundBlock) { Seg seg; res = MVFFAddSeg(&seg, mvff, size, withReservoirPermit); if (res != ResOK) return res; - foundBlock = MVFFFindFirstFree(&base, &limit, mvff, size); + foundBlock = MVFFFindFree(&range, mvff, size); /* We know that the found range must intersect the new segment. */ /* In particular, it doesn't necessarily lie entirely within it. */ - /* The next three AVERs test for intersection of two intervals. */ - AVER(base >= SegBase(seg) || limit <= SegLimit(seg)); - AVER(base < SegLimit(seg)); - AVER(SegBase(seg) < limit); + /* The next two AVERs test for intersection of two intervals. */ + AVER(RangeBase(&range) < SegLimit(seg)); + AVER(SegBase(seg) < RangeLimit(&range)); /* We also know that the found range is no larger than the segment. */ - AVER(SegSize(seg) >= AddrOffset(base, limit)); + AVER(SegSize(seg) >= RangeSize(&range)); } AVER(foundBlock); - AVER(AddrOffset(base, limit) == size); + AVER(RangeSize(&range) == size); - *aReturn = base; + *aReturn = RangeBase(&range); return ResOK; } @@ -374,7 +321,7 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size, static void MVFFFree(Pool pool, Addr old, Size size) { Res res; - Addr base, limit; + RangeStruct range; MVFF mvff; AVERT(Pool, pool); @@ -385,41 +332,16 @@ static void MVFFFree(Pool pool, Addr old, Size size) AVER(AddrIsAligned(old, PoolAlignment(pool))); AVER(size > 0); - size = SizeAlignUp(size, PoolAlignment(pool)); - base = old; - limit = AddrAdd(base, size); + RangeInitSize(&range, old, SizeAlignUp(size, PoolAlignment(pool))); - res = MVFFAddToFreeList(&base, &limit, mvff); + res = MVFFInsert(&range, mvff); AVER(res == ResOK); if (res == ResOK) - MVFFFreeSegs(mvff, base, limit); + MVFFFreeSegs(mvff, &range); return; } -/* MVFFFindLargest -- call CBSFindLargest and then fall back to - * FreelistFindLargest if no block in the CBS was big enough. */ - -static Bool MVFFFindLargest(Range range, Range oldRange, MVFF mvff, - Size size, FindDelete findDelete) -{ - AVER(range != NULL); - AVER(oldRange != NULL); - AVERT(MVFF, mvff); - AVER(size > 0); - AVERT(FindDelete, findDelete); - - LandFlush(CBSOfMVFF(mvff), FreelistOfMVFF(mvff)); - - if (LandFindLargest(range, oldRange, CBSOfMVFF(mvff), size, findDelete)) - return TRUE; - - if (LandFindLargest(range, oldRange, FreelistOfMVFF(mvff), size, findDelete)) - return TRUE; - - return FALSE; -} - /* MVFFBufferFill -- Fill the buffer * @@ -444,13 +366,13 @@ static Res MVFFBufferFill(Addr *baseReturn, Addr *limitReturn, AVER(SizeIsAligned(size, PoolAlignment(pool))); AVERT(Bool, withReservoirPermit); - found = MVFFFindLargest(&range, &oldRange, mvff, size, FindDeleteENTIRE); + found = LandFindLargest(&range, &oldRange, FailoverOfMVFF(mvff), size, FindDeleteENTIRE); if (!found) { - /* Add a new segment to the free list and try again. */ + /* Add a new segment to the free lists and try again. */ res = MVFFAddSeg(&seg, mvff, size, withReservoirPermit); if (res != ResOK) return res; - found = MVFFFindLargest(&range, &oldRange, mvff, size, FindDeleteENTIRE); + found = LandFindLargest(&range, &oldRange, FailoverOfMVFF(mvff), size, FindDeleteENTIRE); } AVER(found); @@ -470,21 +392,22 @@ static void MVFFBufferEmpty(Pool pool, Buffer buffer, { Res res; MVFF mvff; + RangeStruct range; AVERT(Pool, pool); mvff = Pool2MVFF(pool); AVERT(MVFF, mvff); AVERT(Buffer, buffer); AVER(BufferIsReady(buffer)); - AVER(base <= limit); + RangeInit(&range, base, limit); - if (base == limit) + if (RangeEmpty(&range)) return; - res = MVFFAddToFreeList(&base, &limit, mvff); + res = MVFFInsert(&range, mvff); AVER(res == ResOK); if (res == ResOK) - MVFFFreeSegs(mvff, base, limit); + MVFFFreeSegs(mvff, &range); return; } @@ -606,12 +529,22 @@ static Res MVFFInit(Pool pool, ArgList args) if (res != ResOK) goto failCBSInit; + MPS_ARGS_BEGIN(foArgs) { + MPS_ARGS_ADD(foArgs, FailoverPrimary, CBSOfMVFF(mvff)); + MPS_ARGS_ADD(foArgs, FailoverSecondary, FreelistOfMVFF(mvff)); + res = LandInit(FailoverOfMVFF(mvff), FailoverLandClassGet(), arena, align, mvff, foArgs); + } MPS_ARGS_END(foArgs); + if (res != ResOK) + goto failFailoverInit; + mvff->sig = MVFFSig; AVERT(MVFF, mvff); EVENT8(PoolInitMVFF, pool, arena, extendBy, avgSize, align, slotHigh, arenaHigh, firstFit); return ResOK; +failFailoverInit: + LandFinish(CBSOfMVFF(mvff)); failCBSInit: LandFinish(FreelistOfMVFF(mvff)); failFreelistInit: @@ -647,8 +580,9 @@ static void MVFFFinish(Pool pool) arena = PoolArena(pool); ControlFree(arena, mvff->segPref, sizeof(SegPrefStruct)); - LandFinish(CBSOfMVFF(mvff)); + LandFinish(FailoverOfMVFF(mvff)); LandFinish(FreelistOfMVFF(mvff)); + LandFinish(CBSOfMVFF(mvff)); mvff->sig = SigInvalid; } @@ -805,6 +739,7 @@ static Bool MVFFCheck(MVFF mvff) CHECKL(SizeIsAligned(mvff->total, ArenaAlign(PoolArena(MVFF2Pool(mvff))))); CHECKD(CBS, &mvff->cbsStruct); CHECKD(Freelist, &mvff->flStruct); + CHECKD(Failover, &mvff->foStruct); CHECKL(BoolCheck(mvff->slotHigh)); CHECKL(BoolCheck(mvff->firstFit)); return TRUE; diff --git a/mps/code/range.c b/mps/code/range.c index 5e8049b4395..fb11ff091bf 100644 --- a/mps/code/range.c +++ b/mps/code/range.c @@ -15,7 +15,6 @@ SRCID(range, "$Id$"); Bool RangeCheck(Range range) { - CHECKS(Range, range); CHECKL(range->base != NULL); CHECKL(range->base <= range->limit); @@ -31,14 +30,17 @@ void RangeInit(Range range, Addr base, Addr limit) range->base = base; range->limit = limit; - range->sig = RangeSig; AVERT(Range, range); } +void RangeInitSize(Range range, Addr base, Size size) +{ + RangeInit(range, base, AddrAdd(base, size)); +} + void RangeFinish(Range range) { AVERT(Range, range); - range->sig = SigInvalid; range->base = range->limit = NULL; } diff --git a/mps/code/range.h b/mps/code/range.h index c996276cca6..2d93080f6aa 100644 --- a/mps/code/range.h +++ b/mps/code/range.h @@ -14,18 +14,15 @@ #include "mpmtypes.h" -/* Signatures */ - -#define RangeSig ((Sig)0x5196A493) /* SIGnature RANGE */ - - /* Prototypes */ #define RangeBase(range) ((range)->base) #define RangeLimit(range) ((range)->limit) #define RangeSize(range) (AddrOffset(RangeBase(range), RangeLimit(range))) +#define RangeEmpty(range) (RangeBase(range) == RangeLimit(range)) extern void RangeInit(Range range, Addr base, Addr limit); +extern void RangeInitSize(Range range, Addr base, Size size); extern void RangeFinish(Range range); extern Res RangeDescribe(Range range, mps_lib_FILE *stream); extern Bool RangeCheck(Range range); @@ -42,7 +39,6 @@ extern void RangeCopy(Range to, Range from); /* Types */ typedef struct RangeStruct { - Sig sig; Addr base; Addr limit; } RangeStruct; diff --git a/mps/design/cbs.txt b/mps/design/cbs.txt index 5ee2348fe54..ec597de1abd 100644 --- a/mps/design/cbs.txt +++ b/mps/design/cbs.txt @@ -20,9 +20,9 @@ eager coalescence. _`.readership`: This document is intended for any MM developer. -_`.source`: design.mps.poolmv2_, design.mps.poolmvff_. +_`.source`: design.mps.poolmvt_, design.mps.poolmvff_. -.. _design.mps.poolmv2: poolmv2 +.. _design.mps.poolmvt: poolmvt .. _design.mps.poolmvff: poolmvff _`.overview`: The "coalescing block structure" is a set of addresses @@ -124,23 +124,19 @@ _`.limit.iterate`: CBS does not support visitors setting ``LandIterate()``. _`.limit.flush`: CBS cannot be used as the source in a call to -``LandFlush()``. +``LandFlush()``. (Because of `.limit.iterate`_.) Implementation -------------- -_`.impl`: This section is concerned with describing various aspects of -the implementation. It does not form part of the interface definition. - - Splay tree .......... -_`.impl.splay`: The CBS is principally implemented using a splay tree -(see design.mps.splay_). Each splay tree node is embedded in a -``CBSBlock`` that represents a semi-open address range. The key passed -for comparison is the base of another range. +_`.impl.splay`: The CBS is implemented using a splay tree (see +design.mps.splay_). Each splay tree node is embedded in a ``CBSBlock`` +that represents a semi-open address range. The key passed for +comparison is the base of another range. .. _design.mps.splay: splay @@ -158,6 +154,11 @@ size. This takes time proportional to the logarithm of the size of the free list, so it's about the best you can do without maintaining a separate priority queue, just to do ``cbsFindLargest()``. +_`.impl.splay.zones`: ``cbsFindInZones()`` uses the update/refresh +facility of splay trees to store, in each ``CBSBlock()``, the union of +the zones of the ranges in the tree rooted at the corresponding splay +node. This allows rapid location of a block in a set of zones. + Low memory behaviour .................... @@ -231,7 +232,7 @@ Document History ---------------- - 1998-05-01 Gavin Matthews. This document was derived from the - outline in design.mps.poolmv2(2). + outline in design.mps.poolmvt_. - 1998-07-22 Gavin Matthews. Updated in response to approval comments in change.epcore.anchovy.160040. There is too much fragmentation in @@ -255,7 +256,7 @@ Document History talking about the deleted "emergency" free list allocator. Documented ``fastFind`` argument to ``CBSInit()``. -- 2014-04-01 GDR_ Moved generic material to design.mps.land. +- 2014-04-01 GDR_ Moved generic material to design.mps.land_. Documented new keyword arguments. .. _RB: http://www.ravenbrook.com/consultants/rb/ diff --git a/mps/design/failover.txt b/mps/design/failover.txt new file mode 100644 index 00000000000..5fdb5a9b76d --- /dev/null +++ b/mps/design/failover.txt @@ -0,0 +1,150 @@ +.. mode: -*- rst -*- + +Fail-over allocator +=================== + +:Tag: design.mps.failover +:Author: Gareth Rees +:Date: 2014-04-01 +:Status: complete design +:Revision: $Id$ +:Copyright: See section `Copyright and License`_. + + +Introduction +------------ + +_`.intro`: This is the design of the fail-over allocator, a data +structure for the management of address ranges. + +_`.readership`: This document is intended for any MPS developer. + +_`.source`: design.mps.land_, design.mps.poolmvt_, design.mps.poolmvff_. + +_`.overview`: The fail-over allocator combines two *land* instances. +It stores address ranges in one of the lands (the *primary*) unless +insertion fails, in which case it falls back to the other (the +*secondary*). The purpose is to be able to combine two lands with +different properties: with a CBS_ for the primary and a Freelist_ for +the secondary, operations are fast so long as there is memory to +allocate new nodes in the CBS, but operations can continue using the +Freelist when memory is low. + +.. _CBS: cbs +.. _Freelist: freelist +.. _design.mps.land: land +.. _design.mps.poolmvt: poolmvt +.. _design.mps.poolmvff: poolmvff + + +Interface +--------- + +_`.land`: The fail-over allocator is an implementation of the *land* +abstract data type, so the interface consists of the generic functions +for lands. See design.mps.land_. + + +External types +.............. + +``typedef struct FailoverStruct *Failover`` + +_`.type.failover`: The type of fail-over allocator structures. A +``FailoverStruct`` may be embedded in another structure, or you can +create it using ``LandCreate()``. + + +External functions +.................. + +``LandClass FailoverLandClassGet(void)`` + +_`.function.class`: The function ``FailoverLandClassGet()`` returns +the fail-over allocator class, a subclass of ``LandClass`` suitable +for passing to ``LandCreate()`` or ``LandInit()``. + + +Keyword arguments +................. + +When initializing a fail-over allocator, ``LandCreate()`` and +``LandInit()`` require these two keyword arguments: + +* ``FailoverPrimary`` (type ``Land``) is the primary land. + +* ``FailoverSecondary`` (type ``Land``) is the secondary land. + + +Implementation +-------------- + +_`.impl.assume`: The implementation assumes that the primary is fast +but space-hungry (a CBS) and the secondary is slow but space-frugal (a +Freelist). This assumption is used in the following places: + +_`.impl.assume.flush`: The fail-over allocator attempts to flush the +secondary to the primary before any operation, in order to benefit +from the speed of the primary wherever possible. In the normal case +where the secondary is empty this is cheap. + +_`.impl.assume.delete`: When deletion of a range on the primary fails +due to lack of memory, we assume that this can only happen when there +are splinters on both sides of the deleted range, one of which needs +to be allocated a new node (this is the case for CBS), and that +therefore the following procedure will be effective: first, delete the +enclosing range from the primary (leaving no splinters and thus +requiring no allocation), and re-insert the splinters (failing over to +the secondary if necessary). + + + +Document History +---------------- + +- 2014-04-03 GDR_ Created. + +.. _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/index.txt b/mps/design/index.txt index 251d598a102..b14ed257d5f 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -44,13 +44,14 @@ arena_ The design of the MPS arena arenavm_ Virtual memory arena bt_ Bit tables buffer_ Allocation buffers and allocation points -cbs_ Design for coalescing block structure +cbs_ Coalescing Block Structure allocator check_ Design of checking in MPS class-interface_ Design of the pool class interface collection_ The collection framework config_ The design of MPS configuration critical-path_ The critical path through the MPS diag_ The design of MPS diagnostic feedback +failover_ Fail-over allocator finalize_ Finalization fix_ The Design of the Generic Fix Function freelist_ Free list allocator @@ -71,11 +72,11 @@ poolamc_ The design of the automatic mostly-copying memory pool c poolams_ The design of the automatic mark-and-sweep pool class poolawl_ Automatic weak linked poollo_ Leaf object pool class -poolmfs_ The design of the manual fixed small memory pool class +poolmfs_ Manual Fixed Small pool class poolmrg_ Guardian poolclass -poolmv_ The design of the manual variable memory pool class -poolmvt_ The design of a new manual-variable memory pool class -poolmvff_ Design of the manually-managed variable-size first-fit pool +poolmv_ Manual Variable pool class +poolmvt_ Manual Variable Temporal pool class +poolmvff_ Manually Variable First-Fit pool prot_ Generic design of the protection module protan_ ANSI implementation of protection module protli_ Linux implementation of protection module @@ -119,6 +120,7 @@ writef_ The design of the MPS writef function .. _config: config .. _critical-path: critical-path .. _diag: diag +.. _failover: failover .. _finalize: finalize .. _fix: fix .. _freelist: freelist @@ -127,6 +129,7 @@ writef_ The design of the MPS writef function .. _interface-c: interface-c .. _io: io .. _keyword-arguments: keyword-arguments +.. _land: land .. _lib: lib .. _lock: lock .. _locus: locus diff --git a/mps/design/land.txt b/mps/design/land.txt index 8c12c9f5a96..3a4b81abc08 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -6,7 +6,7 @@ Lands :Tag: design.mps.land :Author: Gareth Rees :Date: 2014-04-01 -:Status: incomplete design +:Status: complete design :Revision: $Id$ :Copyright: See section `Copyright and License`_. @@ -19,7 +19,7 @@ represents a collection of contiguous address ranges. _`.readership`: This document is intended for any MPS developer. -_`.source`: `design.mps.cbs `_, `design.mps.freelist `_. +_`.source`: design.mps.cbs_, design.mps.freelist_. _`.overview`: Collections of address ranges are used in several places in the MPS: the arena stores a set of mapped address ranges; pools @@ -132,6 +132,9 @@ that does not overlap with any range in the land) can only fail if the new range is isolated and the allocation of the necessary data structure to represent it failed. +_`.function.insert.alias`: It is acceptable for ``rangeReturn`` and +``range`` to share storage. + ``Res LandDelete(Range rangeReturn, Land land, Range range)`` _`.function.delete`: If any part of the range is not in the land, @@ -153,14 +156,16 @@ This is so that the caller can try deleting the whole block (which is guaranteed to succeed) and managing the fragments using a fallback strategy. +_`.function.delete.alias`: It is acceptable for ``rangeReturn`` and +``range`` to share storage. + ``void LandIterate(Land land, LandIterateMethod iterate, void *closureP, Size closureS)`` _`.function.iterate`: ``LandIterate()`` is the function used to iterate all isolated contiguous ranges in a land. It receives a -pointer, ``Size`` closure pair to pass on to the iterator method, -and an iterator method to invoke on every range in address order. If -the iterator method returns ``FALSE``, then the iteration is -terminated. +pointer, ``Size`` closure pair to pass on to the iterator method, and +an iterator method to invoke on every range. If the iterator method +returns ``FALSE``, then the iteration is terminated. ``Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)`` @@ -211,9 +216,9 @@ argument. _`.function.find.zones`: Locate a block at least as big as ``size`` that lies entirely within the ``zoneSet``, return its range via the -``rangeReturn`` argument, and return ``TRUE``. (The first such block, +``rangeReturn`` argument, and return ``ResOK``. (The first such block, if ``high`` is ``FALSE``, or the last, if ``high`` is ``TRUE``.) If -there is no such block, , return ``FALSE``. +there is no such block, , return ``ResFAIL``. Delete the range as for ``LandFindFirst()`` and ``LastFindLast()`` (with the effect of ``FindDeleteLOW`` if ``high`` is ``FALSE`` and the @@ -221,6 +226,10 @@ effect of ``FindDeleteHIGH`` if ``high`` is ``TRUE``), and return the original contiguous isolated range in which the range was found via the ``oldRangeReturn`` argument. +_`.function.find.zones.fail`: It's possible that the range can't be +deleted from the land because that would require allocation, in which +case the result code will indicate the cause of the failure. + ``Res LandDescribe(Land land, mps_lib_FILE *stream)`` _`.function.describe`: ``LandDescribe()`` prints a textual @@ -234,6 +243,30 @@ _`.function.flush`: Delete ranges of addresses from ``src`` and insert them into ``dest``, so long as ``LandInsert()`` remains successful. +Implementations +--------------- + +There are three land implementations: + +#. CBS (Coalescing Block Structure) stores ranges in a splay tree. It + has fast (logarithmic in the number of ranges) insertion, deletion + and searching, but has substantial space overhead. See + design.mps.cbs_. + +#. Freelist stores ranges in an address-ordered free list, as in + traditional ``malloc()`` implementations. Insertion, deletion, and + searching are slow (proportional to the number of ranges) but it + does not need to allocate. See design.mps.freelist_. + +#. Failover combines two lands, using one (the *primary*) until it + fails, and then falls back to the other (the *secondary*). See + design.mps.failover_. + +.. _design.mps.cbs: cbs +.. _design.mps.freelist: freelist +.. _design.mps.failover: failover + + Testing ------- @@ -250,7 +283,7 @@ generic function, but makes no automatic test of the resulting output. Document History ---------------- -- 2014-04-01 GDR_ Created based on `design.mps.cbs `_. +- 2014-04-01 GDR_ Created based on design.mps.cbs_. .. _GDR: http://www.ravenbrook.com/consultants/gdr/ diff --git a/mps/design/poolmvff.txt b/mps/design/poolmvff.txt index 2c16b80c4a0..c842fe03a6c 100644 --- a/mps/design/poolmvff.txt +++ b/mps/design/poolmvff.txt @@ -120,11 +120,13 @@ Implementation -------------- _`.impl.free-list`: The pool stores its free list in a CBS (see -//gdr-peewit/info.ravenbrook.com/project/mps/branch/2013-05-17/emergency/design/poolmvff.txt -`design.mps.cbs `_), failing over in emergencies to a Freelist -(see design.mps.freelist) when the CBS cannot allocate new control +design.mps.cbs_), failing over in emergencies to a Freelist (see +design.mps.freelist_) when the CBS cannot allocate new control structures. This is the reason for the alignment restriction above. +.. _design.mps.cbs: cbs +.. _design.mps.freelist: freelist + Details ------- diff --git a/mps/design/range.txt b/mps/design/range.txt index 86fcab775f1..fa5b4d3867c 100644 --- a/mps/design/range.txt +++ b/mps/design/range.txt @@ -24,8 +24,8 @@ Requirements ------------ _`.req.range`: A range object must be able to represent an arbitrary -range of addresses that does not include the top grain of the address -space. +range of addresses that neither starts at ``NULL`` nor includes the +top grain of the address space. _`.req.empty`: A range object must be able to represent the empty range. @@ -50,6 +50,12 @@ between ``base`` (inclusive) and ``limit`` (exclusive). It must be the case that ``base <= limit``. If ``base == limit`` then the range is empty. +``void RangeInitSize(Range range, Addr base, Size size)`` + +Initialize a range object to represent the half-open address range +between ``base`` (inclusive) and ``base + size`` (exclusive). If +``size == 0`` then the range is empty. + ``void RangeFinish(Range range)`` Finish a range object. Because a range object uses no heap resources diff --git a/mps/design/splay.txt b/mps/design/splay.txt index 8eb1a91c2a8..28aa1147222 100644 --- a/mps/design/splay.txt +++ b/mps/design/splay.txt @@ -22,9 +22,13 @@ implementation. _`.readership`: This document is intended for any MM developer. _`.source`: The primary sources for this design are [ST85]_ and -[Sleator96]_. Also as CBS is a client, design.mps.cbs. As -PoolMVFF is an indirect client, design.mps.poolmvff(1). Also, as -PoolMV2 is an (obsolescent?) indirect client, design.mps.poolmv2. +[Sleator96]_. As CBS is a client, design.mps.cbs_. As PoolMVFF is an +indirect client, design.mps.poolmvff_. Also, as PoolMVT is an indirect +client, design.mps.poolmvt_. + +.. _design.mps.cbs: cbs +.. _design.mps.poolmvt: poolmvt +.. _design.mps.poolmvff: poolmvff _`.background`: The following background documents influence the design: guide.impl.c.adt(0). @@ -89,7 +93,7 @@ Requirements ------------ _`.req`: These requirements are drawn from those implied by -design.mps.poolmv2, design.mps.poolmvff(1), design.mps.cbs(2) and +design.mps.poolmvt_, design.mps.poolmvff_, design.mps.cbs_, and general inferred MPS requirements. _`.req.order`: Must maintain a set of abstract keys which is totally diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index f87cfdadaa2..4c501253041 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -10,6 +10,7 @@ Design cbs config critical-path + failover freelist guide.hex.trans guide.impl.c.format From b9e2c810843309c8666e4909c8857105a1d4a4b5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 3 Apr 2014 14:46:58 +0100 Subject: [PATCH 036/266] Test the failover module (both always and never failing over). Fix result code bug in failoverInsert. Test all result codes in fotest. Tidy up code and documentation. Copied from Perforce Change: 185207 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 33 +++++++++--------- mps/code/cbs.c | 9 +++-- mps/code/failover.c | 14 ++++---- mps/code/fotest.c | 40 +++++++++++++--------- mps/code/landtest.c | 74 +++++++++++++++++++++++++++++------------ mps/code/mpmst.h | 4 +-- mps/code/poolmv2.c | 39 ++++++++-------------- mps/code/poolmvff.c | 6 ++-- mps/design/cbs.txt | 2 +- mps/design/freelist.txt | 4 +-- mps/design/index.txt | 12 +++---- 11 files changed, 132 insertions(+), 105 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index afdb815f232..7c0af5ffe86 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -238,7 +238,8 @@ Res ArenaInit(Arena arena, ArenaClass class, Align alignment, ArgList args) MPS_ARGS_ADD(liArgs, CBSFastFind, TRUE); MPS_ARGS_ADD(liArgs, CBSZoned, arena->zoned); MPS_ARGS_DONE(liArgs); - res = LandInit(ArenaFreeLand(arena), CBSLandClassGet(), arena, alignment, arena, liArgs); + res = LandInit(ArenaFreeLand(arena), CBSLandClassGet(), arena, + alignment, arena, liArgs); } MPS_ARGS_END(liArgs); AVER(res == ResOK); /* no allocation, no failure expected */ if (res != ResOK) @@ -310,9 +311,9 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args) that describes the free address space in the primary chunk. */ arena->hasFreeLand = TRUE; res = ArenaFreeLandInsert(arena, - PageIndexBase(arena->primary, - arena->primary->allocBase), - arena->primary->limit); + PageIndexBase(arena->primary, + arena->primary->allocBase), + arena->primary->limit); if (res != ResOK) goto failPrimaryLand; @@ -704,10 +705,10 @@ static void arenaExcludePage(Arena arena, Range pageRange) } -/* arenaLandInsert -- add a block to an arena Land, extending pool if necessary +/* arenaLandInsert -- add range to arena's land, maybe extending block pool * - * The arena's Land can't get memory in the usual way because they are used - * in the basic allocator, so we allocate pages specially. + * 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. * * Only fails if it can't get a page for the block pool. */ @@ -722,7 +723,7 @@ static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range) res = LandInsert(rangeReturn, ArenaFreeLand(arena), range); - if (res == ResLIMIT) { /* freeLand MFS pool ran out of blocks */ + if (res == ResLIMIT) { /* CBS block pool ran out of blocks */ RangeStruct pageRange; res = arenaExtendCBSBlockPool(&pageRange, arena); if (res != ResOK) @@ -730,7 +731,7 @@ static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range) /* .insert.exclude: Must insert before exclude so that we can bootstrap when the zoned CBS is empty. */ res = LandInsert(rangeReturn, ArenaFreeLand(arena), range); - AVER(res == ResOK); /* we just gave memory to the Land */ + AVER(res == ResOK); /* we just gave memory to the CBS block pool */ arenaExcludePage(arena, &pageRange); } @@ -738,11 +739,11 @@ static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range) } -/* ArenaFreeLandInsert -- add a block to arena Land, maybe stealing memory +/* ArenaFreeLandInsert -- add range to arena's 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 nodes. + * 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. * * IMPORTANT: May update rangeIO. */ @@ -777,14 +778,14 @@ static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO) /* Try again. */ res = LandInsert(rangeReturn, ArenaFreeLand(arena), rangeIO); - AVER(res == ResOK); /* we just gave memory to the Land */ + AVER(res == ResOK); /* we just gave memory to the CBS block pool */ } AVER(res == ResOK); /* not expecting other kinds of error from the Land */ } -/* ArenaFreeLandInsert -- add block to free Land, extending pool if necessary +/* ArenaFreeLandInsert -- add range to arena's 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 @@ -812,7 +813,7 @@ Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit) } -/* ArenaFreeLandDelete -- remove a block from free Land, extending pool if necessary +/* ArenaFreeLandDelete -- remove range from arena's land, maybe extending block pool * * This is called from ChunkFinish in order to remove address space from * the arena. diff --git a/mps/code/cbs.c b/mps/code/cbs.c index 3e99e3ca195..37f597930a0 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -26,6 +26,7 @@ SRCID(cbs, "$Id$"); #define CBSBlockSize(block) AddrOffset((block)->base, (block)->limit) +#define cbsLand(cbs) (&((cbs)->landStruct)) #define cbsOfLand(land) PARENT(CBSStruct, landStruct, land) #define cbsSplay(cbs) (&((cbs)->splayTreeStruct)) #define cbsOfSplay(_splay) PARENT(CBSStruct, splayTreeStruct, _splay) @@ -66,7 +67,7 @@ Bool CBSCheck(CBS cbs) { /* See .enter-leave.simple. */ CHECKS(CBS, cbs); - CHECKD(Land, &cbs->landStruct); + CHECKD(Land, cbsLand(cbs)); CHECKD(SplayTree, cbsSplay(cbs)); /* nothing to check about treeSize */ CHECKD(Pool, cbs->blockPool); @@ -211,7 +212,7 @@ static void cbsUpdateZonedNode(SplayTree splay, Tree tree) cbsUpdateNode(splay, tree); block = cbsBlockOfTree(tree); - arena = cbsOfSplay(splay)->landStruct.arena; + arena = LandArena(cbsLand(cbsOfSplay(splay))); zones = ZoneSetOfRange(arena, CBSBlockBase(block), CBSBlockLimit(block)); if (TreeHasLeft(tree)) @@ -740,7 +741,7 @@ static Bool cbsIterateVisit(Tree tree, void *closureP, Size closureS) cbsBlock = cbsBlockOfTree(tree); RangeInit(&range, CBSBlockBase(cbsBlock), CBSBlockLimit(cbsBlock)); cont = (*closure->visitor)(&delete, land, &range, closure->closureP, closure->closureS); - AVER(!delete); + AVER(!delete); /* */ if (!cont) return FALSE; METER_ACC(cbs->treeSearch, cbs->treeSize); @@ -1101,6 +1102,8 @@ static Res cbsDescribe(Land land, mps_lib_FILE *stream) " blockPool: $P\n", (WriteFP)cbsBlockPool(cbs), " fastFind: $U\n", (WriteFU)cbs->fastFind, " inCBS: $U\n", (WriteFU)cbs->inCBS, + " ownPool: $U\n", (WriteFU)cbs->ownPool, + " zoned: $U\n", (WriteFU)cbs->zoned, " treeSize: $U\n", (WriteFU)cbs->treeSize, NULL); if (res != ResOK) return res; diff --git a/mps/code/failover.c b/mps/code/failover.c index ca0d15cad1c..b5d7588480c 100644 --- a/mps/code/failover.c +++ b/mps/code/failover.c @@ -87,10 +87,8 @@ static Res failoverInsert(Range rangeReturn, Land land, Range range) LandFlush(fo->primary, fo->secondary); res = LandInsert(rangeReturn, fo->primary, range); - if (ResIsAllocFailure(res)) { - /* primary ran out of memory: try secondary instead. */ + if (res != ResOK && res != ResFAIL) res = LandInsert(rangeReturn, fo->secondary, range); - } return res; } @@ -118,11 +116,11 @@ static Res failoverDelete(Range rangeReturn, Land land, Range range) if (res == ResFAIL) { /* Range not found in primary: try secondary. */ return LandDelete(rangeReturn, fo->secondary, range); - } else if (ResIsAllocFailure(res)) { - /* Range was found in primary, but couldn't be deleted because the - * primary is out of memory. Delete the whole of oldRange, and - * re-insert the fragments (which might end up in the secondary). - * See . + } else if (res != ResOK) { + /* Range was found in primary, but couldn't be deleted, perhaps + * because the primary is out of memory. Delete the whole of + * oldRange, and re-insert the fragments (which might end up in + * the secondary). See . */ res = LandDelete(&dummyRange, fo->primary, &oldRange); if (res != ResOK) diff --git a/mps/code/fotest.c b/mps/code/fotest.c index bef621362d7..fd3011840b9 100644 --- a/mps/code/fotest.c +++ b/mps/code/fotest.c @@ -38,28 +38,37 @@ /* Accessors for the CBS used to implement a pool. */ -extern Land _mps_mvff_cbs(mps_pool_t); -extern Land _mps_mvt_cbs(mps_pool_t); +extern Land _mps_mvff_cbs(Pool); +extern Land _mps_mvt_cbs(Pool); /* "OOM" pool class -- dummy alloc/free pool class whose alloc() - * method always returns ResMEMORY */ + * method always fails. */ -static Res OOMAlloc(Addr *pReturn, Pool pool, Size size, - Bool withReservoirPermit) +static Res oomAlloc(Addr *pReturn, Pool pool, Size size, + Bool withReservoirPermit) { UNUSED(pReturn); UNUSED(pool); UNUSED(size); UNUSED(withReservoirPermit); - return ResMEMORY; + switch (rnd() % 4) { + case 0: + return ResRESOURCE; + case 1: + return ResMEMORY; + case 2: + return ResLIMIT; + default: + return ResCOMMIT_LIMIT; + } } -extern PoolClass PoolClassOOM(void); +extern PoolClass OOMPoolClassGet(void); DEFINE_POOL_CLASS(OOMPoolClass, this) { INHERIT_CLASS(this, AbstractAllocFreePoolClass); - this->alloc = OOMAlloc; + this->alloc = oomAlloc; } @@ -81,16 +90,17 @@ static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size) /* set_oom -- set blockPool of CBS to OOM or MFS according to argument. */ -static void set_oom(CBS cbs, int oom) +static void set_oom(Land land, int oom) { - cbs->blockPool->class = oom ? EnsureOOMPoolClass() : PoolClassMFS(); + CBS cbs = PARENT(CBSStruct, landStruct, land); + cbs->blockPool->class = oom ? OOMPoolClassGet() : PoolClassMFS(); } /* stress -- create an allocation point and allocate in it */ static mps_res_t stress(size_t (*size)(unsigned long, mps_align_t), - mps_align_t alignment, mps_pool_t pool, CBS cbs) + mps_align_t alignment, mps_pool_t pool, Land cbs) { mps_res_t res = MPS_RES_OK; mps_ap_t ap; @@ -180,8 +190,8 @@ int main(int argc, char *argv[]) die(mps_pool_create_k(&pool, arena, mps_class_mvff(), args), "create MVFF"); } MPS_ARGS_END(args); { - CBS cbs = (CBS)_mps_mvff_cbs(pool); - die(stress(randomSizeAligned, alignment, pool, cbs), "stress MVFF"); + die(stress(randomSizeAligned, alignment, pool, _mps_mvff_cbs(pool)), + "stress MVFF"); } mps_pool_destroy(pool); mps_arena_destroy(arena); @@ -199,8 +209,8 @@ int main(int argc, char *argv[]) die(mps_pool_create_k(&pool, arena, mps_class_mvt(), args), "create MVFF"); } MPS_ARGS_END(args); { - CBS cbs = (CBS)_mps_mvt_cbs(pool); - die(stress(randomSizeAligned, alignment, pool, cbs), "stress MVT"); + die(stress(randomSizeAligned, alignment, pool, _mps_mvt_cbs(pool)), + "stress MVT"); } mps_pool_destroy(pool); mps_arena_destroy(arena); diff --git a/mps/code/landtest.c b/mps/code/landtest.c index 4698a9f1aaf..e820eca517f 100644 --- a/mps/code/landtest.c +++ b/mps/code/landtest.c @@ -3,7 +3,7 @@ * $Id$ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * - * The MPS contains two land implementations: + * The MPS contains three land implementations: * * 1. the CBS (Coalescing Block Structure) module maintains blocks in * a splay tree for fast access with a cost in storage; @@ -11,6 +11,9 @@ * 2. the Freelist module maintains blocks in an address-ordered * singly linked list for zero storage overhead with a cost in * performance. + * + * 3. the Failover module implements a mechanism for using CBS until + * it fails, then falling back to a Freelist. */ #include "cbs.h" @@ -20,6 +23,7 @@ #include "mps.h" #include "mpsavm.h" #include "mpstd.h" +#include "poolmfs.h" #include "testlib.h" #include @@ -479,13 +483,16 @@ extern int main(int argc, char *argv[]) void *p; Addr dummyBlock; BT allocTable; + MFSStruct blockPool; CBSStruct cbsStruct; FreelistStruct flStruct; FailoverStruct foStruct; Land cbs = &cbsStruct.landStruct; Land fl = &flStruct.landStruct; Land fo = &foStruct.landStruct; + Pool mfs = &blockPool.poolStruct; Align align; + int i; testlib_init(argc, argv); align = (1 << rnd() % 4) * MPS_PF_ALIGN; @@ -512,6 +519,8 @@ extern int main(int argc, char *argv[]) (char *)dummyBlock + ArraySize); } + /* 1. Test CBS */ + MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, CBSFastFind, TRUE); die((mps_res_t)LandInit(cbs, CBSLandClassGet(), arena, align, NULL, args), @@ -524,6 +533,8 @@ extern int main(int argc, char *argv[]) test(&state, nCBSOperations); LandFinish(cbs); + /* 2. Test Freelist */ + die((mps_res_t)LandInit(fl, FreelistLandClassGet(), arena, align, NULL, mps_args_none), "failed to initialise Freelist"); @@ -531,27 +542,46 @@ extern int main(int argc, char *argv[]) test(&state, nFLOperations); LandFinish(fl); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, CBSFastFind, TRUE); - die((mps_res_t)LandInit(cbs, CBSLandClassGet(), arena, align, - NULL, args), - "failed to initialise CBS"); - } MPS_ARGS_END(args); - die((mps_res_t)LandInit(fl, FreelistLandClassGet(), arena, align, NULL, - mps_args_none), - "failed to initialise Freelist"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, FailoverPrimary, cbs); - MPS_ARGS_ADD(args, FailoverSecondary, fl); - die((mps_res_t)LandInit(fo, FailoverLandClassGet(), arena, align, NULL, - args), - "failed to initialise Failover"); - } MPS_ARGS_END(args); - state.land = fo; - test(&state, nFOOperations); - LandFinish(fo); - LandFinish(fl); - LandFinish(cbs); + /* 3. Test CBS-failing-over-to-Freelist (always failing over on + * first iteration, never failing over on second; see fotest.c for a + * test case that randomly switches fail-over on and off) + */ + + for (i = 0; i < 2; ++i) { + MPS_ARGS_BEGIN(piArgs) { + MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSBlockStruct)); + MPS_ARGS_ADD(piArgs, MPS_KEY_EXTEND_BY, ArenaAlign(arena)); + MPS_ARGS_ADD(piArgs, MFSExtendSelf, i); + MPS_ARGS_DONE(piArgs); + die(PoolInit(mfs, arena, PoolClassMFS(), piArgs), "PoolInit"); + } MPS_ARGS_END(piArgs); + + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, CBSFastFind, TRUE); + MPS_ARGS_ADD(args, CBSBlockPool, mfs); + die((mps_res_t)LandInit(cbs, CBSLandClassGet(), arena, align, NULL, + args), + "failed to initialise CBS"); + } MPS_ARGS_END(args); + + die((mps_res_t)LandInit(fl, FreelistLandClassGet(), arena, align, NULL, + mps_args_none), + "failed to initialise Freelist"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, FailoverPrimary, cbs); + MPS_ARGS_ADD(args, FailoverSecondary, fl); + die((mps_res_t)LandInit(fo, FailoverLandClassGet(), arena, align, NULL, + args), + "failed to initialise Failover"); + } MPS_ARGS_END(args); + + state.land = fo; + test(&state, nFOOperations); + LandFinish(fo); + LandFinish(fl); + LandFinish(cbs); + PoolFinish(mfs); + } mps_arena_destroy(arena); diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 35684a52950..a36a9e7b8e8 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -701,8 +701,8 @@ typedef union FreelistBlockUnion *FreelistBlock; typedef struct FreelistStruct { LandStruct landStruct; /* superclass fields come first */ - FreelistBlock list; - Count listSize; + FreelistBlock list; /* first block in list or NULL if empty */ + Count listSize; /* number of blocks in list */ Sig sig; /* .class.end-sig */ } FreelistStruct; diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index 6baa0322a53..bbf57d586a0 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -385,9 +385,7 @@ static Bool MVTCheck(MVT mvt) CHECKD(Pool, &mvt->poolStruct); CHECKL(mvt->poolStruct.class == MVTPoolClassGet()); CHECKD(CBS, &mvt->cbsStruct); - /* CHECKL(CBSCheck(MVTCBS(mvt))); */ CHECKD(ABQ, &mvt->abqStruct); - /* CHECKL(ABQCheck(MVTABQ(mvt))); */ CHECKD(Freelist, &mvt->flStruct); CHECKD(Failover, &mvt->foStruct); CHECKL(mvt->reuseSize >= 2 * mvt->fillSize); @@ -402,8 +400,7 @@ static Bool MVTCheck(MVT mvt) if (mvt->splinter) { CHECKL(AddrOffset(mvt->splinterBase, mvt->splinterLimit) >= mvt->minSize); - /* CHECKD(Seg, mvt->splinterSeg); */ - CHECKL(SegCheck(mvt->splinterSeg)); + CHECKD(Seg, mvt->splinterSeg); CHECKL(mvt->splinterBase >= SegBase(mvt->splinterSeg)); CHECKL(mvt->splinterLimit <= SegLimit(mvt->splinterSeg)); } @@ -1257,6 +1254,10 @@ static Bool MVTReturnSegs(MVT mvt, Range range, Arena arena) } +/* MVTRefillABQIfEmpty -- refill the ABQ from the free lists if it is + * empty. + */ + static Bool MVTRefillVisitor(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS) { @@ -1275,9 +1276,6 @@ static Bool MVTRefillVisitor(Bool *deleteReturn, Land land, Range range, return MVTReserve(mvt, range); } -/* MVTRefillABQIfEmpty -- refill the ABQ from the free lists if it is - * empty. - */ static void MVTRefillABQIfEmpty(MVT mvt, Size size) { AVERT(MVT, mvt); @@ -1296,10 +1294,9 @@ static void MVTRefillABQIfEmpty(MVT mvt, Size size) } -/* Closure for MVTContingencySearch */ -typedef struct MVTContigencyStruct *MVTContigency; +/* MVTContingencySearch -- search free lists for a block of a given size */ -typedef struct MVTContigencyStruct +typedef struct MVTContigencyClosureStruct { MVT mvt; Bool found; @@ -1309,12 +1306,7 @@ typedef struct MVTContigencyStruct /* meters */ Count steps; Count hardSteps; -} MVTContigencyStruct; - - -/* MVTContingencyVisitor -- called from LandIterate at the behest of - * MVTContingencySearch. - */ +} MVTContigencyClosureStruct, *MVTContigencyClosure; static Bool MVTContingencyVisitor(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS) @@ -1322,7 +1314,7 @@ static Bool MVTContingencyVisitor(Bool *deleteReturn, Land land, Range range, MVT mvt; Size size; Addr base, limit; - MVTContigency cl; + MVTContigencyClosure cl; AVER(deleteReturn != NULL); AVERT(Land, land); @@ -1360,14 +1352,10 @@ static Bool MVTContingencyVisitor(Bool *deleteReturn, Land land, Range range, return TRUE; } -/* MVTContingencySearch -- search the free lists for a block of size - * min. - */ - static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn, MVT mvt, Size min) { - MVTContigencyStruct cls; + MVTContigencyClosureStruct cls; cls.mvt = mvt; cls.found = FALSE; @@ -1394,6 +1382,7 @@ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn, /* MVTCheckFit -- verify that segment-aligned block of size min can * fit in a candidate address range. */ + static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena) { Seg seg; @@ -1423,12 +1412,10 @@ static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena) /* Return the CBS of an MVT pool for the benefit of fotest.c. */ -extern Land _mps_mvt_cbs(mps_pool_t); -Land _mps_mvt_cbs(mps_pool_t mps_pool) { - Pool pool; +extern Land _mps_mvt_cbs(Pool); +Land _mps_mvt_cbs(Pool pool) { MVT mvt; - pool = (Pool)mps_pool; AVERT(Pool, pool); mvt = Pool2MVT(pool); AVERT(MVT, mvt); diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 818b4f932aa..a975d944cbb 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -748,12 +748,10 @@ static Bool MVFFCheck(MVFF mvff) /* Return the CBS of an MVFF pool for the benefit of fotest.c. */ -extern Land _mps_mvff_cbs(mps_pool_t); -Land _mps_mvff_cbs(mps_pool_t mps_pool) { - Pool pool; +extern Land _mps_mvff_cbs(Pool); +Land _mps_mvff_cbs(Pool pool) { MVFF mvff; - pool = (Pool)mps_pool; AVERT(Pool, pool); mvff = Pool2MVFF(pool); AVERT(MVFF, mvff); diff --git a/mps/design/cbs.txt b/mps/design/cbs.txt index ec597de1abd..1f5d2eafb39 100644 --- a/mps/design/cbs.txt +++ b/mps/design/cbs.txt @@ -232,7 +232,7 @@ Document History ---------------- - 1998-05-01 Gavin Matthews. This document was derived from the - outline in design.mps.poolmvt_. + outline in design.mps.poolmv2(2). - 1998-07-22 Gavin Matthews. Updated in response to approval comments in change.epcore.anchovy.160040. There is too much fragmentation in diff --git a/mps/design/freelist.txt b/mps/design/freelist.txt index 680a143c1a5..7dd253ed720 100644 --- a/mps/design/freelist.txt +++ b/mps/design/freelist.txt @@ -151,8 +151,8 @@ exceed the recorded size of the list. _`.improve.maxsize`: We could maintain the maximum size of any range on the list, and use that to make an early exit from -``LandFindLargest()``. It's not clear that this would actually be an -improvement. +``freelistFindLargest()``. It's not clear that this would actually be +an improvement. diff --git a/mps/design/index.txt b/mps/design/index.txt index b14ed257d5f..41db91aa4b7 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -68,15 +68,15 @@ message_ MPS to client message protocol message-gc_ Messages sent when garbage collection begins or ends object-debug_ Debugging Features for Client Objects pool_ The design of the pool and pool class mechanisms -poolamc_ The design of the automatic mostly-copying memory pool class -poolams_ The design of the automatic mark-and-sweep pool class -poolawl_ Automatic weak linked -poollo_ Leaf object pool class +poolamc_ Automatic Mostly-Copying pool class +poolams_ Automatic Mark-and-Sweep pool class +poolawl_ Automatic Weak Linked pool class +poollo_ Leaf Object pool class poolmfs_ Manual Fixed Small pool class -poolmrg_ Guardian poolclass +poolmrg_ Manual Rank Guardian pool class poolmv_ Manual Variable pool class poolmvt_ Manual Variable Temporal pool class -poolmvff_ Manually Variable First-Fit pool +poolmvff_ Manual Variable First-Fit pool class prot_ Generic design of the protection module protan_ ANSI implementation of protection module protli_ Linux implementation of protection module From 7e0a53106be1d3e3a7bca229d71a08f78229f1a5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 3 Apr 2014 15:01:53 +0100 Subject: [PATCH 037/266] Fix file-at-a-time compilation. Copied from Perforce Change: 185210 ServerID: perforce.ravenbrook.com --- mps/code/freelist.c | 2 +- mps/code/poolmv2.c | 1 + mps/code/poolmvff.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mps/code/freelist.c b/mps/code/freelist.c index 4706212bcc0..e46ee7ab773 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -626,7 +626,7 @@ static Res freelistFindInZones(Range rangeReturn, Range oldRangeReturn, /* AVERT(ZoneSet, zoneSet); */ AVERT(Bool, high); - landFind = high ? cbsFindLast : cbsFindFirst; + landFind = high ? freelistFindLast : freelistFindFirst; search = high ? RangeInZoneSetLast : RangeInZoneSetFirst; if (zoneSet == ZoneSetEMPTY) diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index bbf57d586a0..ca1a754041c 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -14,6 +14,7 @@ #include "mpscmvt.h" #include "abq.h" #include "cbs.h" +#include "failover.h" #include "freelist.h" #include "meter.h" #include "range.h" diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index a975d944cbb..ef5cafd2499 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -21,6 +21,7 @@ #include "mpscmvff.h" #include "dbgpool.h" #include "cbs.h" +#include "failover.h" #include "freelist.h" #include "mpm.h" From c8071e333214384bdc5540e473692b9d3aaa96aa Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 3 Apr 2014 15:02:20 +0100 Subject: [PATCH 038/266] Compile cool before hot because the former doesn't need to optimize and so detects errors more quickly; and because the former uses file-at-a-time compilation and so can pick up where it left off instead of having to start from the beginning of mps.c. Copied from Perforce Change: 185211 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 6 +++--- mps/code/comm.gmk | 12 ++++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/mps/Makefile.in b/mps/Makefile.in index 2d558588673..3071110cb11 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -34,12 +34,12 @@ install-make-build: make-install-dirs build-via-make $(INSTALL_PROGRAM) $(addprefix code/$(MPS_TARGET_NAME)/hot/Release/,$(EXTRA_TARGETS)) $(prefix)/bin build-via-xcode: - $(XCODEBUILD) -config Release $(XCODEBUILD) -config Debug + $(XCODEBUILD) -config Release clean-xcode-build: - $(XCODEBUILD) -config Release clean $(XCODEBUILD) -config Debug clean + $(XCODEBUILD) -config Release clean install-xcode-build: make-install-dirs build-via-xcode $(INSTALL_DATA) code/mps*.h $(prefix)/include/ @@ -72,7 +72,7 @@ test-make-build: @BUILD_TARGET@ $(MAKE) $(TARGET_OPTS) VARIETY=hot testrun test-xcode-build: - $(XCODEBUILD) -config Release -target testrun $(XCODEBUILD) -config Debug -target testrun + $(XCODEBUILD) -config Release -target testrun test: @TEST_TARGET@ diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index 44264ed0acf..a270296a914 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -342,17 +342,25 @@ clean: phony $(ECHO) "$(PFM): $@" rm -rf "$(PFM)" -# "target" builds some varieties of the target named in the TARGET macro. +# "target" builds some varieties of the target named in the TARGET +# macro. +# # %%VARIETY: When adding a new target, optionally add a recursive make call # for the new variety, if it should be built by default. It probably # shouldn't without a product design decision and an update of the readme # and build manual! +# +# Note that we build VARIETY=cool before VARIETY=hot because +# the former doesn't need to optimize and so detects errors more +# quickly; and because the former uses file-at-a-time compilation and +# so can pick up where it left off instead of having to start from the +# beginning of mps.c ifdef TARGET ifndef VARIETY target: phony - $(MAKE) -f $(PFM).gmk VARIETY=hot variety $(MAKE) -f $(PFM).gmk VARIETY=cool variety + $(MAKE) -f $(PFM).gmk VARIETY=hot variety endif endif From 0769a897c25f5b7771dad3338294958e784414a0 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 3 Apr 2014 16:50:51 +0100 Subject: [PATCH 039/266] Build cool variety before hot because the former doesn't need to optimize and so detects errors more quickly; and because the former uses file-at-a-time compilation and so can pick up where it left off instead of having to start from the beginning of mps.c. Copied from Perforce Change: 185213 ServerID: perforce.ravenbrook.com --- mps/code/commpost.nmk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk index 78095f33714..e8ec7bf6b44 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/commpost.nmk @@ -39,8 +39,8 @@ clean: !IFDEF TARGET !IFNDEF VARIETY target: - $(MAKE) /nologo /f $(PFM).nmk VARIETY=hot variety $(MAKE) /nologo /f $(PFM).nmk VARIETY=cool variety + $(MAKE) /nologo /f $(PFM).nmk VARIETY=hot variety !ENDIF !ENDIF @@ -60,8 +60,8 @@ testrun: $(TEST_TARGETS) !IFDEF VARIETY ..\tool\testrun.bat $(PFM) $(VARIETY) !ELSE - $(MAKE) /nologo /f $(PFM).nmk VARIETY=hot testrun $(MAKE) /nologo /f $(PFM).nmk VARIETY=cool testrun + $(MAKE) /nologo /f $(PFM).nmk VARIETY=hot testrun !ENDIF From b3f9ae76ae00c5874dcdd10f5db6de2a482c2333 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 7 Apr 2014 16:26:03 +0100 Subject: [PATCH 040/266] Fix the condition for splaynodeupdate. Copied from Perforce Change: 185307 ServerID: perforce.ravenbrook.com --- mps/code/splay.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mps/code/splay.c b/mps/code/splay.c index e07b40215cb..278f038b9b5 100644 --- a/mps/code/splay.c +++ b/mps/code/splay.c @@ -1323,7 +1323,8 @@ void SplayNodeUpdate(SplayTree splay, Tree node) { AVERT(SplayTree, splay); AVERT(Tree, node); - AVER(SplayTreeIsEmpty(splay)); /* otherwise, call SplayNodeRefresh */ + AVER(!TreeHasLeft(node)); /* otherwise, call SplayNodeRefresh */ + AVER(!TreeHasRight(node)); /* otherwise, call SplayNodeRefresh */ AVER(SplayHasUpdate(splay)); /* otherwise, why call? */ splay->updateNode(splay, node); From 51aac4e32d29744472a9b892f0ac50b015d8ad7c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 8 Apr 2014 00:13:50 +0100 Subject: [PATCH 041/266] No keyword arguments needed in these cbsfastlandclass initializations. Copied from Perforce Change: 185329 ServerID: perforce.ravenbrook.com --- mps/code/poolmv2.c | 5 ++--- mps/code/poolmvff.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index 5343c05ec96..9d73e358a42 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -279,9 +279,8 @@ static Res MVTInit(Pool pool, ArgList args) if (abqDepth < 3) abqDepth = 3; - MPS_ARGS_BEGIN(liArgs) { - res = LandInit(MVTCBS(mvt), CBSFastLandClassGet(), arena, align, mvt, liArgs); - } MPS_ARGS_END(liArgs); + res = LandInit(MVTCBS(mvt), CBSFastLandClassGet(), arena, align, mvt, + mps_args_none); if (res != ResOK) goto failCBS; diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 8784042111c..6a530fb94bd 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -523,9 +523,8 @@ static Res MVFFInit(Pool pool, ArgList args) if (res != ResOK) goto failFreelistInit; - MPS_ARGS_BEGIN(liArgs) { - res = LandInit(CBSOfMVFF(mvff), CBSFastLandClassGet(), arena, align, mvff, liArgs); - } MPS_ARGS_END(liArgs); + res = LandInit(CBSOfMVFF(mvff), CBSFastLandClassGet(), arena, align, mvff, + mps_args_none); if (res != ResOK) goto failCBSInit; From d0e3a88dd6ad1e316674347b4c05a37649e1b91d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 8 Apr 2014 00:14:50 +0100 Subject: [PATCH 042/266] Fix typo. Copied from Perforce Change: 185330 ServerID: perforce.ravenbrook.com --- mps/design/cbs.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/design/cbs.txt b/mps/design/cbs.txt index 70cf737eaf4..7ed38d586a1 100644 --- a/mps/design/cbs.txt +++ b/mps/design/cbs.txt @@ -172,8 +172,8 @@ Low memory behaviour _`.impl.low-mem`: When the CBS tries to allocate a new ``CBSBlock`` structure for a new isolated range as a result of either ``LandInsert()`` or ``LandDelete()``, and there is insufficient memory -to allocation the block structure, then the range is not added -to the CBS or deleted from it, and the call to ``LandInsert()`` or +to allocate the block structure, then the range is not added to the +CBS or deleted from it, and the call to ``LandInsert()`` or ``LandDelete()`` returns ``ResMEMORY``. From e4533f8d59894982e098b15f34fc54f5e1cebd4a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 8 Apr 2014 20:52:40 +0100 Subject: [PATCH 043/266] No need to put "branch/" in the branches index: just use date/task. Turn jobs into links in the description. Copied from Perforce Change: 185364 ServerID: perforce.ravenbrook.com --- mps/tool/branch | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mps/tool/branch b/mps/tool/branch index f60eccae235..faf69ffb0bc 100755 --- a/mps/tool/branch +++ b/mps/tool/branch @@ -46,9 +46,9 @@ CHILD_RE = r'(?:{}|{})$'.format(TASK_BRANCH_RE, VERSION_BRANCH_RE) TASK_BRANCH_ENTRY = ''' - {child} + {date}/{task} Changes - {description} + {desc_html} In development (diffs). @@ -60,7 +60,7 @@ VERSION_BRANCH_ENTRY = ''' None. {parent}/...@{changelevel} - {description} + {desc_html} base
@@ -161,6 +161,9 @@ def main(argv): if not args.description: args.description = fmt("Branching {parent} to {child}.") print(fmt("description={description}")) + args.desc_html = re.sub(r'\b(job\d{6})\b', + fmt(r'. - * 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/testlib.h b/mps/code/testlib.h index 0912373031d..9c197cae839 100644 --- a/mps/code/testlib.h +++ b/mps/code/testlib.h @@ -28,13 +28,10 @@ /* Suppress Pelles C warnings at warning level 2 */ -/* Some of these are also done in config.h. */ +/* This is also done in config.h. */ #ifdef MPS_BUILD_PC -/* "Structured Exception Handling is not portable." (mps_tramp). */ -#pragma warn(disable: 2008) - /* "Unreachable code" (AVER, if condition is constantly true). */ #pragma warn(disable: 2154) From 80c2ad98e78f34bea56313baee094bb00d32d951 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 10 Apr 2014 12:22:12 +0100 Subject: [PATCH 045/266] Add tip about running the same test case many times. Copied from Perforce Change: 185420 ServerID: perforce.ravenbrook.com --- mps/tool/testrun.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mps/tool/testrun.sh b/mps/tool/testrun.sh index 87559faf1d4..5950aa5d1e2 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -13,6 +13,14 @@ # Usage:: # # testrun.sh DIR ( SUITE | CASE1 CASE2 [...] ) +# +# You can use this feature 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 +# +# This runs the AMC stress test 100 times from the code/xc/Debug +# directory, reporting all failures. # Make a temporary output directory for the test logs. LOGDIR=$(mktemp -d /tmp/mps.log.XXXXXX) From 1c25a89a7095d7b8b415188fd8620c2ef7e261ed Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 10 Apr 2014 12:24:49 +0100 Subject: [PATCH 046/266] Correct the nailboard level sizes; add assertion to nailboardindex checking this. Copied from Perforce Change: 185421 ServerID: perforce.ravenbrook.com --- mps/code/nailboard.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/mps/code/nailboard.c b/mps/code/nailboard.c index 8744514662b..dc669a67ef7 100644 --- a/mps/code/nailboard.c +++ b/mps/code/nailboard.c @@ -30,26 +30,36 @@ static Count nailboardLevels(Count nails) } +/* nailboardNails -- return the total number of nails in the board */ + +static Count nailboardNails(Nailboard board) +{ + return RangeSize(&board->range) >> board->alignShift; +} + + /* nailboardLevelBits -- return the number of bits in the bit table * for the given level. */ -static Count nailboardLevelBits(Nailboard board, Index level) +static Count nailboardLevelBits(Count nails, Index level) { - /* Use <= rather than < because of .check.levels. */ - AVER(level <= board->levels); - return RangeSize(&board->range) >> (board->alignShift + level * LEVEL_SHIFT); + Shift shift = level * LEVEL_SHIFT; + return (nails + (1 << shift) - 1) >> shift; } Bool NailboardCheck(Nailboard board) { Index i; + Count nails; CHECKS(Nailboard, board); CHECKL(RangeCheck(&board->range)); CHECKL(0 < board->levels); - CHECKL(board->levels == nailboardLevels(nailboardLevelBits(board, 0))); - CHECKL(nailboardLevelBits(board, board->levels - 1) != 0); - CHECKL(nailboardLevelBits(board, board->levels) == 0); /* .check.levels */ + nails = nailboardNails(board); + CHECKL(board->levels == nailboardLevels(nails)); + CHECKL(nails == nailboardLevelBits(nails, 0)); + CHECKL(nailboardLevelBits(nails, board->levels - 1) != 0); + CHECKL(nailboardLevelBits(nails, board->levels) == 1); CHECKL(BoolCheck(board->newNails)); for (i = 0; i < board->levels; ++i) { CHECKL(board->level[i] != NULL); @@ -80,8 +90,7 @@ static Size nailboardSize(Count nails, Count levels) Size size; size = nailboardStructSize(levels); for (i = 0; i < levels; ++i) { - size += BTSize(nails); - nails >>= LEVEL_SHIFT; + size += BTSize(nailboardLevelBits(nails, i)); } return size; } @@ -130,11 +139,11 @@ Res NailboardCreate(Nailboard *boardReturn, Arena arena, Align alignment, p = PointerAdd(p, nailboardStructSize(levels)); for (i = 0; i < levels; ++i) { - AVER(nails > 0); + Count levelBits = nailboardLevelBits(nails, i); + AVER(levelBits > 0); board->level[i] = p; - BTResRange(board->level[i], 0, nails); - p = PointerAdd(p, BTSize(nails)); - nails >>= LEVEL_SHIFT; + BTResRange(board->level[i], 0, levelBits); + p = PointerAdd(p, BTSize(levelBits)); } board->sig = NailboardSig; @@ -154,7 +163,7 @@ void NailboardDestroy(Nailboard board, Arena arena) AVERT(Nailboard, board); AVERT(Arena, arena); - nails = nailboardLevelBits(board, 0); + nails = nailboardNails(board); size = nailboardSize(nails, board->levels); board->sig = SigInvalid; @@ -191,8 +200,10 @@ Bool (NailboardNewNails)(Nailboard board) static Index nailboardIndex(Nailboard board, Index level, Addr addr) { - return AddrOffset(RangeBase(&board->range), addr) + Index i = AddrOffset(RangeBase(&board->range), addr) >> (board->alignShift + level * LEVEL_SHIFT); + AVER_CRITICAL(i < nailboardLevelBits(nailboardNails(board), level)); + return i; } @@ -414,7 +425,7 @@ Res NailboardDescribe(Nailboard board, mps_lib_FILE *stream) return res; for(i = 0; i < board->levels; ++i) { - Count levelNails = nailboardLevelBits(board, i); + Count levelNails = nailboardLevelBits(nailboardNails(board), i); Count resetNails = BTCountResRange(board->level[i], 0, levelNails); res = WriteF(stream, " Level $U ($U bits, $U set): ", i, levelNails, levelNails - resetNails, NULL); From ce0ccebc2d3f86030f5ddaee124b9ff1531e64d0 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 10 Apr 2014 12:37:48 +0100 Subject: [PATCH 047/266] Document that the arena must be parked in order for mps_arena_formatted_objects_walk to visit all objects. Copied from Perforce Change: 185424 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/format.rst | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/mps/manual/source/topic/format.rst b/mps/manual/source/topic/format.rst index 91ac7ae6462..b9bbdae61bb 100644 --- a/mps/manual/source/topic/format.rst +++ b/mps/manual/source/topic/format.rst @@ -468,22 +468,27 @@ Object format introspection Each :term:`pool class` determines for which objects the stepper function is called. Typically, all validly formatted objects are - visited. During a :term:`trace` this will in general be only the - :term:`black` objects, though the :ref:`pool-lo` pool, for - example, will walk all objects since they are validly formatted - whether they are black or :term:`white`. :term:`Padding objects` - may be visited at the pool class's discretion: the :term:`client - program` should handle this case. - - .. seealso:: - - :ref:`topic-arena`. + visited. :term:`Padding objects` may be visited at the pool + class's discretion: the stepper function must handle this + case. .. note:: This function is intended for heap analysis, tuning, and debugging, not for frequent use in production. + .. warning:: + + If a garbage collection is currently in progress (that is, if + the arena is in the :term:`clamped ` or + :term:`unclamped state`), then only objects that are known to + be currently valid are visited. + + For the most reliable results, ensure the arena is in the + :term:`parked state` by calling :c:func:`mps_arena_park` + before calling this function (and release it by calling + :c:func:`mps_arena_release` afterwards, if desired). + .. c:type:: void (*mps_formatted_objects_stepper_t)(mps_addr_t addr, mps_fmt_t fmt, mps_pool_t pool, void *p, size_t s) @@ -515,10 +520,6 @@ Object format introspection It must not access other memory managed by the MPS. - .. seealso:: - - :ref:`topic-arena`. - Obsolete interface ------------------ From 966026b170c88310c4569961f8709157d0132f3f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 10 Apr 2014 13:02:22 +0100 Subject: [PATCH 048/266] Trying to create a freelist with too-small alignment is a static programming error, not a dynamic failure condition, so aver instead of returning resparam. (see job003485). Copied from Perforce Change: 185426 ServerID: perforce.ravenbrook.com --- mps/code/freelist.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mps/code/freelist.c b/mps/code/freelist.c index e46ee7ab773..5b586a82e6a 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -187,8 +187,7 @@ static Res freelistInit(Land land, ArgList args) return res; /* See */ - if (!AlignIsAligned(LandAlignment(land), freelistMinimumAlignment)) - return ResPARAM; + AVER(AlignIsAligned(LandAlignment(land), freelistMinimumAlignment)); fl = freelistOfLand(land); fl->list = NULL; From ae09ed50c5ec5066871d75fb980603e21b22278b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 10 Apr 2014 15:06:58 +0100 Subject: [PATCH 049/266] Fix amcssth -- don't try to test two incompatible features at the same time (see job003561). Set the commit limit in amcss and amcsshe so that we test that the MPS can live in a tight memory limit. Don't try to detect when the MPS has made a "dynamic" collection. This is not reliable or maintainable. Copied from Perforce Change: 185430 ServerID: perforce.ravenbrook.com --- mps/code/amcss.c | 21 +--------------- mps/code/amcsshe.c | 20 ++-------------- mps/code/amcssth.c | 58 +++++++++++++++++++++++++++++---------------- mps/code/exposet0.c | 6 ----- 4 files changed, 41 insertions(+), 64 deletions(-) diff --git a/mps/code/amcss.c b/mps/code/amcss.c index 20f4dae3740..48892a45830 100644 --- a/mps/code/amcss.c +++ b/mps/code/amcss.c @@ -78,19 +78,6 @@ static void report(mps_arena_t arena) printf(" not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); printf(" clock: %"PRIuLONGEST"\n", (ulongest_t)mps_message_clock(arena, message)); printf("}\n"); - - if(condemned > (gen1SIZE + gen2SIZE + (size_t)128) * 1024) { - /* When condemned size is larger than could happen in a gen 2 - * collection (discounting ramps, natch), guess that was a dynamic - * collection, and reset the commit limit, so it doesn't run out. - * - * GDR 2013-03-12: Fiddling with the commit limit was causing - * the test to fail sometimes (see job003440), so I've commented - * out this feature. - */ - /* die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit"); */ - } - } else { cdie(0, "unknown message type"); break; @@ -98,8 +85,6 @@ static void report(mps_arena_t arena) mps_message_discard(arena, message); } - - return; } @@ -310,11 +295,7 @@ int main(int argc, char *argv[]) "arena_create"); mps_message_type_enable(arena, mps_message_type_gc()); mps_message_type_enable(arena, mps_message_type_gc_start()); - /* GDR 2013-03-12: Fiddling with the commit limit was causing - * the test to fail sometimes (see job003440), so I've commented - * out this feature. - */ - /*die(mps_arena_commit_limit_set(arena, testArenaSIZE), "set limit");*/ + die(mps_arena_commit_limit_set(arena, 2*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 11a5950f497..8b3a0c65e36 100644 --- a/mps/code/amcsshe.c +++ b/mps/code/amcsshe.c @@ -91,18 +91,6 @@ static void report(mps_arena_t arena) printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); mps_message_discard(arena, message); - - if (condemned > (gen1SIZE + gen2SIZE + (size_t)128) * 1024) { - /* When condemned size is larger than could happen in a gen 2 - * collection (discounting ramps, natch), guess that was a dynamic - * collection, and reset the commit limit, so it doesn't run out. - * - * GDR 2013-03-07: Fiddling with the commit limit was causing - * the test to fail sometimes (see job003432), so I've commented - * out this feature. - */ - /*die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit");*/ - } } } @@ -257,14 +245,10 @@ int main(int argc, char *argv[]) testlib_init(argc, argv); - die(mps_arena_create(&arena, mps_arena_class_vm(), 3*testArenaSIZE), + die(mps_arena_create(&arena, mps_arena_class_vm(), 2*testArenaSIZE), "arena_create\n"); mps_message_type_enable(arena, mps_message_type_gc()); - /* GDR 2013-03-07: Fiddling with the commit limit was causing - * the test to fail sometimes (see job003432), so I've commented - * out this feature. - */ - /*die(mps_arena_commit_limit_set(arena, testArenaSIZE), "set limit");*/ + die(mps_arena_commit_limit_set(arena, 2*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 79eff570b0b..2f17f97ca09 100644 --- a/mps/code/amcssth.c +++ b/mps/code/amcssth.c @@ -4,11 +4,20 @@ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * Portions copyright (c) 2002 Global Graphics Software. * - * .posix: This is Posix only. + * .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. */ -#define _POSIX_C_SOURCE 199309L - #include "fmtdy.h" #include "fmtdytst.h" #include "testlib.h" @@ -19,6 +28,11 @@ #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) @@ -65,12 +79,6 @@ static void report(mps_arena_t arena) printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); mps_message_discard(arena, message); - - if (condemned > (gen1SIZE + gen2SIZE + (size_t)128) * 1024) - /* When condemned size is larger than could happen in a gen 2 - * collection (discounting ramps, natch), guess that was a dynamic - * collection, and reset the commit limit, so it doesn't run out. */ - die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit"); } } @@ -210,7 +218,7 @@ static void *kid_thread(void *arg) /* test -- the body of the test */ -static void *test(mps_class_t pool_class, size_t roots_count) +static void *test_pool(mps_class_t pool_class, size_t roots_count, int mode) { size_t i; mps_word_t collections, rampSwitch; @@ -221,6 +229,7 @@ static void *test(mps_class_t pool_class, size_t roots_count) mps_pool_t pool; testthr_t kids[10]; closure_s cl; + int walked = FALSE, ramped = FALSE; die(mps_pool_create(&pool, arena, pool_class, format, chain), "pool_create(amc)"); @@ -250,21 +259,23 @@ static void *test(mps_class_t pool_class, size_t roots_count) if (collections != c) { collections = c; - printf("\nCollection %lu started, %lu objects.\n", c, objs); + printf("\nCollection %lu started, %lu objects, committed=%lu.\n", + c, objs, (unsigned long)mps_arena_committed(arena)); report(arena); for (i = 0; i < exactRootsCOUNT; ++i) cdie(exactRoots[i] == objNULL || dylan_check(exactRoots[i]), "all roots check"); - if (collections == collectionsCOUNT / 2) { + 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) { + if (collections >= rampSwitch && !ramped) { int begin_ramp = !ramping || /* Every other time, switch back immediately. */ (collections & 1); @@ -289,6 +300,7 @@ static void *test(mps_class_t pool_class, size_t roots_count) ramping = 1; } } + ramped = TRUE; } churn(ap, roots_count); @@ -317,31 +329,37 @@ static void *test(mps_class_t pool_class, size_t roots_count) return NULL; } -int main(int argc, char *argv[]) +static void test_arena(int mode) { mps_thr_t thread; mps_root_t reg_root; void *marker = ▮ - testlib_init(argc, argv); - die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "arena_create"); + if (mode == ModeCOMMIT) + die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit"); mps_message_type_enable(arena, mps_message_type_gc()); init(); 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"); + mps_stack_scan_ambig, marker, 0), "root_create"); - test(mps_class_amc(), exactRootsCOUNT); - test(mps_class_amcz(), 0); + test_pool(mps_class_amc(), exactRootsCOUNT, mode); + test_pool(mps_class_amcz(), 0, mode); mps_root_destroy(reg_root); mps_thread_dereg(thread); - finish(); report(arena); mps_arena_destroy(arena); +} + +int main(int argc, char *argv[]) +{ + testlib_init(argc, argv); + test_arena(ModeWALK); + test_arena(ModeCOMMIT); printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); return 0; diff --git a/mps/code/exposet0.c b/mps/code/exposet0.c index f471dd2a3bc..21f2567cbaa 100644 --- a/mps/code/exposet0.c +++ b/mps/code/exposet0.c @@ -72,12 +72,6 @@ static void report(mps_arena_t arena) printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); mps_message_discard(arena, message); - - if (condemned > (gen1SIZE + gen2SIZE + (size_t)128) * 1024) - /* When condemned size is larger than could happen in a gen 2 - * collection (discounting ramps, natch), guess that was a dynamic - * collection, and reset the commit limit, so it doesn't run out. */ - die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit"); } } From 25dc0fc0739a4f8fea167762c75ad20b4b6b1e58 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 10 Apr 2014 15:36:51 +0100 Subject: [PATCH 050/266] Document the constraints on the mean and maximum size arguments to the mv pool class. remove documentation from poolmv.h: this is in the manual now. Copied from Perforce Change: 185432 ServerID: perforce.ravenbrook.com --- mps/code/poolmv.h | 37 ++++++----------------------------- mps/manual/source/pool/mv.rst | 20 ++++++++++--------- 2 files changed, 17 insertions(+), 40 deletions(-) diff --git a/mps/code/poolmv.h b/mps/code/poolmv.h index 098cd3eaa2e..8e6885254bc 100644 --- a/mps/code/poolmv.h +++ b/mps/code/poolmv.h @@ -1,41 +1,16 @@ /* poolmv.h: MANUAL VARIABLE POOL * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * .purpose: This is the interface to the manual-variable pool class. * - * .mv: Manual-variable pools manage variably-sized blocks of memory in a - * flexible manner. They have higher overheads than a fixed-size pool. + * .mv: Manual-variable pools manage variably-sized blocks of memory + * in a flexible manner. They have higher overheads than a fixed-size + * pool. * - * .init: This class adds the following arguments to PoolCreate: - * - * Size extendBy - * - * extendBy is the default number of bytes reserved by the pool at a time. - * A large size will make allocation cheaper but have a higher resource - * overhead. A typical value might be 65536. See note 2. - * - * Size avgSize - * - * avgSize is an estimate of the average size of an allocation, and is used - * to choose the size of internal tables. An accurate estimate will - * improve the efficiency of the pool. A low estimate will make the pool - * less space efficient. A high estimate will make the pool less time - * efficient. A typical value might be 32. avgSize must not be less than - * extendBy. - * - * Size maxSize - * - * maxSize is an estimate of the maximum total size that the pool will - * reach. Setting this parameter does not actually contrain the pool, but - * an accurate estimate will improve the efficiency of the pool. maxSize - * must not be less than extendBy. - * - * Notes - * 2. The documentation could suggest a segment size according to the - * distribution of allocation size requests. richard 1994-11-08 + * .design: See */ #ifndef poolmv_h @@ -59,7 +34,7 @@ extern Bool MVCheck(MV mv); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/manual/source/pool/mv.rst b/mps/manual/source/pool/mv.rst index 433525f7362..361cd41c0b5 100644 --- a/mps/manual/source/pool/mv.rst +++ b/mps/manual/source/pool/mv.rst @@ -75,17 +75,19 @@ MV interface When creating an MV pool, :c:func:`mps_pool_create_k` may take three :term:`keyword arguments`: - * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default 65536) is the - :term:`size` of segment that the pool will request from the - :term:`arena`. + * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, + default 65536) is the :term:`size` of segment that the pool will + request from the :term:`arena`. - * :c:macro:`MPS_KEY_MEAN_SIZE` (type :c:type:`size_t`, default 32) is the - predicted mean size of blocks that will be allocated from the - pool. + * :c:macro:`MPS_KEY_MEAN_SIZE` (type :c:type:`size_t`, default 32) + is the predicted mean size of blocks that will be allocated from + the pool. This value must be smaller than, or equal to, the + value for :c:macro:`MPS_KEY_EXTEND_BY`. - * :c:macro:`MPS_KEY_MAX_SIZE` (type :c:type:`size_t`, default 65536) is the - predicted maximum size of blocks that will be allocated from the - pool. + * :c:macro:`MPS_KEY_MAX_SIZE` (type :c:type:`size_t`, + default 65536) is the predicted maximum size of blocks that will + be allocated from the pool. This value must be larger than, or + equal to, the value for :c:macro:`MPS_KEY_EXTEND_BY`. The mean and maximum sizes are *hints* to the MPS: the pool will be less efficient if these are wrong, but nothing will break. From 665cb2efcc2a0cb6b2b5c66334e76fe773f1c7e4 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 10 Apr 2014 18:16:29 +0100 Subject: [PATCH 051/266] Don't turn on the alloctable in amsbufferempty when it's shared with nonwhitetable and the colour tables are in use -- this will turn any grey grains in the segment invalid. Add more checking to AMS, including the table use invariant. Copied from Perforce Change: 185434 ServerID: perforce.ravenbrook.com --- mps/code/poolams.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/mps/code/poolams.c b/mps/code/poolams.c index c67a2efd684..7d090b2470b 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -74,6 +74,11 @@ Bool AMSSegCheck(AMSSeg amsseg) CHECKD_NOSIG(BT, amsseg->nongreyTable); CHECKD_NOSIG(BT, amsseg->nonwhiteTable); + /* If tables are shared, they mustn't both be in use. */ + CHECKL(!(amsseg->ams->shareAllocTable + && amsseg->allocTableInUse + && amsseg->colourTablesInUse)); + return TRUE; } @@ -167,6 +172,10 @@ static Res amsCreateTables(AMS ams, BT *allocReturn, goto failWhite; } + /* Invalidate the colour tables in checking varieties. */ + AVER((BTResRange(nongreyTable, 0, length), TRUE)); + AVER((BTSetRange(nonwhiteTable, 0, length), TRUE)); + *allocReturn = allocTable; *nongreyReturn = nongreyTable; *nonwhiteReturn = nonwhiteTable; @@ -1023,7 +1032,8 @@ static void AMSBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit) AVER(limitIndex <= amsseg->firstFree); if (limitIndex == amsseg->firstFree) /* is it at the end? */ { amsseg->firstFree = initIndex; - } else { /* start using allocTable */ + } else if (!ams->shareAllocTable || !amsseg->colourTablesInUse) { + /* start using allocTable */ amsseg->allocTableInUse = TRUE; BTSetRange(amsseg->allocTable, 0, amsseg->firstFree); if (amsseg->firstFree < amsseg->grains) @@ -1415,16 +1425,20 @@ static Res AMSFix(Pool pool, ScanState ss, Seg seg, Ref *refIO) /* doing that here (this can be called from RootScan, during flip). */ clientRef = *refIO; + AVER_CRITICAL(SegBase(seg) <= clientRef); + AVER_CRITICAL(clientRef < SegLimit(seg)); /* see .ref-limit */ base = AddrSub((Addr)clientRef, format->headerSize); /* can get an ambiguous reference too close to the base of the * segment, so when we subtract the header we are not in the * segment any longer. This isn't a real reference, * so we can just skip it. */ if (base < SegBase(seg)) { - return ResOK; + AVER_CRITICAL(ss->rank == RankAMBIG); + return ResOK; } i = AMS_ADDR_INDEX(seg, base); + AVER_CRITICAL(i < amsseg->grains); AVER_CRITICAL(!AMS_IS_INVALID_COLOUR(seg, i)); ss->wasMarked = TRUE; From 66eda4805bd27492d1512d2d1539742678fe2224 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 10 Apr 2014 19:17:42 +0100 Subject: [PATCH 052/266] Add release note for job001549. Copied from Perforce Change: 185436 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 83e23aea3c3..b93ffc786f5 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -30,6 +30,14 @@ New features Other changes ............. +#. The :ref:`pool-ams` pool class no longer triggers the assertion + ``!AMS_IS_INVALID_COLOUR(seg, i)`` under rare circumstances + (namely, detaching an :term:`allocation point` from a :term:`grey` + segment when :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` is + ``FALSE``). See job001549_. + + .. _job001549: https://www.ravenbrook.com/project/mps/issue/job001549/ + #. The alignment of :ref:`pool-awl` pools is now configurable via the object format, as documented, and is no longer always :c:macro:`MPS_PF_ALIGN`. See job003745_. From 44ec318081f6f98414b0bb231970a38568381521 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 10 Apr 2014 19:40:42 +0100 Subject: [PATCH 053/266] Must ensure the consistency of a segment even if we are just about to free it, because the segment must pass the segcheck inside segfree. Copied from Perforce Change: 185440 ServerID: perforce.ravenbrook.com --- mps/code/poolams.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mps/code/poolams.c b/mps/code/poolams.c index 7d090b2470b..d769630f009 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -1598,12 +1598,13 @@ static void AMSReclaim(Pool pool, Trace trace, Seg seg) /* preservedInPlaceCount is updated on fix */ trace->preservedInPlaceSize += (grains - amsseg->free) << ams->grainShift; + /* Ensure consistency of segment even if are just about to free it */ + amsseg->colourTablesInUse = FALSE; + SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace)); + if (amsseg->free == grains && SegBuffer(seg) == NULL) { /* No survivors */ SegFree(seg); - } else { - amsseg->colourTablesInUse = FALSE; - SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace)); } } From b70e268929732bb005a0c966253c275ea37f7f4d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 11 Apr 2014 00:26:48 +0100 Subject: [PATCH 054/266] Fix problems found by coverity. see for full analysis. Copied from Perforce Change: 185445 ServerID: perforce.ravenbrook.com --- mps/code/abq.c | 20 +++------- mps/code/airtest.c | 2 +- mps/code/arenavm.c | 3 +- mps/code/cbs.c | 3 +- mps/code/djbench.c | 1 + mps/code/eventcnv.c | 6 +++ mps/code/gcbench.c | 10 ++--- mps/code/meter.h | 11 ++++-- mps/code/mpm.c | 8 ++-- mps/code/mpm.h | 6 ++- mps/code/poolmv2.c | 93 +++++++++++++++------------------------------ mps/code/sac.c | 15 +++++--- mps/code/trace.c | 3 +- mps/code/vman.c | 10 ++--- mps/code/vmix.c | 8 ++-- mps/code/vmw3.c | 7 ++-- 16 files changed, 92 insertions(+), 114 deletions(-) diff --git a/mps/code/abq.c b/mps/code/abq.c index b915bb42c9b..22286354c77 100644 --- a/mps/code/abq.c +++ b/mps/code/abq.c @@ -1,7 +1,7 @@ /* abq.c: QUEUE IMPLEMENTATION * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .purpose: A fixed-length FIFO queue. * @@ -185,18 +185,10 @@ Res ABQDescribe(ABQ abq, ABQDescribeElement describeElement, mps_lib_FILE *strea if(res != ResOK) return res; - res = METER_WRITE(abq->push, stream); - if(res != ResOK) - return res; - res = METER_WRITE(abq->pop, stream); - if(res != ResOK) - return res; - res = METER_WRITE(abq->peek, stream); - if(res != ResOK) - return res; - res = METER_WRITE(abq->delete, stream); - if(res != ResOK) - return res; + METER_WRITE(abq->push, stream); + METER_WRITE(abq->pop, stream); + METER_WRITE(abq->peek, stream); + METER_WRITE(abq->delete, stream); res = WriteF(stream, "}\n", NULL); if(res != ResOK) @@ -311,7 +303,7 @@ static void *ABQElement(ABQ abq, Index index) { /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/airtest.c b/mps/code/airtest.c index 31932bb4286..9da2c768f84 100644 --- a/mps/code/airtest.c +++ b/mps/code/airtest.c @@ -35,7 +35,7 @@ #include "fmtscheme.h" #define OBJ_LEN (1u << 4) -#define OBJ_COUNT 1 +#define OBJ_COUNT 10 static void test_air(int interior, int stack) { diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 1bcc6272f35..15b79bbed51 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -593,6 +593,8 @@ static void VMArenaFinish(Arena arena) AVERT(VMArena, vmArena); arenaVM = vmArena->vm; + EVENT1(ArenaDestroy, vmArena); + /* destroy all chunks, including the primary */ arena->primary = NULL; RING_FOR(node, &arena->chunkRing, next) { @@ -612,7 +614,6 @@ static void VMArenaFinish(Arena arena) VMUnmap(arenaVM, VMBase(arenaVM), VMLimit(arenaVM)); VMDestroy(arenaVM); - EVENT1(ArenaDestroy, vmArena); } diff --git a/mps/code/cbs.c b/mps/code/cbs.c index 176a15fef16..118d226a603 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -1077,8 +1077,7 @@ Res CBSDescribe(CBS cbs, mps_lib_FILE *stream) res = SplayTreeDescribe(cbsSplay(cbs), stream, &cbsSplayNodeDescribe); if (res != ResOK) return res; - res = METER_WRITE(cbs->treeSearch, stream); - if (res != ResOK) return res; + METER_WRITE(cbs->treeSearch, stream); res = WriteF(stream, "}\n", NULL); return res; diff --git a/mps/code/djbench.c b/mps/code/djbench.c index 59f05130cf2..c1f37f412b2 100644 --- a/mps/code/djbench.c +++ b/mps/code/djbench.c @@ -56,6 +56,7 @@ static mps_bool_t zoned = TRUE; /* arena allocates using zones */ \ for (k = 0; k < nblocks; ++k) { \ blocks[k].p = NULL; \ + blocks[k].s = 0; \ } \ \ for (j = 0; j < npass; ++j) { \ diff --git a/mps/code/eventcnv.c b/mps/code/eventcnv.c index 355b6efa2a2..7b7e060470f 100644 --- a/mps/code/eventcnv.c +++ b/mps/code/eventcnv.c @@ -197,6 +197,12 @@ static Res eventRead(Bool *eofOut, EventUnion *event, FILE *stream) return ResIO; } + if (event->any.size < sizeof(event->any)) + return ResFAIL; /* invalid size: too small */ + + if (event->any.size > sizeof(*event)) + return ResFAIL; /* invalid size: too large */ + /* Read the rest of the event. */ rest = event->any.size - sizeof(event->any); if (rest > 0) { diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c index 80c68d7f711..2a18d1a7d10 100644 --- a/mps/code/gcbench.c +++ b/mps/code/gcbench.c @@ -318,8 +318,8 @@ int main(int argc, char *argv[]) { double mort = 0.0; cap = (size_t)strtoul(optarg, &p, 10); switch(toupper(*p)) { - case 'G': cap *= 1024; /* fall through */ - case 'M': cap *= 1024; /* fall through */ + case 'G': cap <<= 20; p++; break; + case 'M': cap <<= 10; p++; break; case 'K': p++; break; default: cap = 0; break; } @@ -340,9 +340,9 @@ int main(int argc, char *argv[]) { char *p; arenasize = (unsigned)strtoul(optarg, &p, 10); switch(toupper(*p)) { - case 'G': arenasize *= 1024; - case 'M': arenasize *= 1024; - case 'K': arenasize *= 1024; break; + case 'G': arenasize <<= 30; break; + case 'M': arenasize <<= 20; break; + case 'K': arenasize <<= 10; break; case '\0': break; default: fprintf(stderr, "Bad arena size %s\n", optarg); diff --git a/mps/code/meter.h b/mps/code/meter.h index 7a7f8266e87..f1731400e42 100644 --- a/mps/code/meter.h +++ b/mps/code/meter.h @@ -1,7 +1,7 @@ /* meter.h: METER INTERFACE * * $Id$ - * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .sources: mps.design.metrics. * @@ -45,9 +45,12 @@ extern void MeterEmit(Meter meter); #define METER_ACC(meter, delta) \ STATISTIC(MeterAccumulate(&(meter), delta)) #if defined(STATISTICS) -#define METER_WRITE(meter, stream) MeterWrite(&(meter), stream) +#define METER_WRITE(meter, stream) BEGIN \ + Res _res = MeterWrite(&(meter), (stream)); \ + if (_res != ResOK) return _res; \ + END #elif defined(STATISTICS_NONE) -#define METER_WRITE(meter, stream) (ResOK) +#define METER_WRITE(meter, stream) NOOP #else #error "No statistics configured." #endif @@ -59,7 +62,7 @@ extern void MeterEmit(Meter meter); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2013 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpm.c b/mps/code/mpm.c index f544acca401..a46fdf5fb10 100644 --- a/mps/code/mpm.c +++ b/mps/code/mpm.c @@ -174,16 +174,16 @@ Word (WordAlignDown)(Word word, Align alignment) /* SizeIsP2 -- test whether a size is a power of two */ -Bool SizeIsP2(Size size) +Bool (SizeIsP2)(Size size) { - return WordIsP2((Word)size); + return SizeIsP2(size); } /* WordIsP2 -- tests whether a word is a power of two */ -Bool WordIsP2(Word word) +Bool (WordIsP2)(Word word) { - return word > 0 && (word & (word - 1)) == 0; + return WordIsP2(word); } diff --git a/mps/code/mpm.h b/mps/code/mpm.h index d830674512f..3423ffdb03c 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -143,11 +143,13 @@ extern Bool ResIsAllocFailure(Res res); * SizeFloorLog2 returns the floor of the logarithm in base 2 of size. * size can be any positive non-zero value. */ -extern Bool SizeIsP2(Size size); +extern Bool (SizeIsP2)(Size size); +#define SizeIsP2(size) WordIsP2((Word)size) extern Shift SizeLog2(Size size); extern Shift SizeFloorLog2(Size size); -extern Bool WordIsP2(Word word); +extern Bool (WordIsP2)(Word word); +#define WordIsP2(word) ((word) > 0 && ((word) & ((word) - 1)) == 0) /* Formatted Output -- see , */ diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index b2903481b45..51b346e9f43 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -1050,68 +1050,37 @@ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream) res = FreelistDescribe(MVTFreelist(mvt), stream); if(res != ResOK) return res; - res = METER_WRITE(mvt->segAllocs, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->segFrees, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->bufferFills, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->bufferEmpties, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->poolFrees, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->poolSize, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->poolAllocated, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->poolAvailable, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->poolUnavailable, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->poolUtilization, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->finds, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->overflows, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->underflows, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->refills, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->refillPushes, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->returns, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->perfectFits, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->firstFits, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->secondFits, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->failures, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->emergencyContingencies, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->fragLimitContingencies, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->contingencySearches, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->contingencyHardSearches, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->splinters, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->splintersUsed, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->splintersDropped, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->sawdust, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->exceptions, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->exceptionSplinters, stream); - if (res != ResOK) return res; - res = METER_WRITE(mvt->exceptionReturns, stream); - if (res != ResOK) return res; + METER_WRITE(mvt->segAllocs, stream); + METER_WRITE(mvt->segFrees, stream); + METER_WRITE(mvt->bufferFills, stream); + METER_WRITE(mvt->bufferEmpties, stream); + METER_WRITE(mvt->poolFrees, stream); + METER_WRITE(mvt->poolSize, stream); + METER_WRITE(mvt->poolAllocated, stream); + METER_WRITE(mvt->poolAvailable, stream); + METER_WRITE(mvt->poolUnavailable, stream); + METER_WRITE(mvt->poolUtilization, stream); + METER_WRITE(mvt->finds, stream); + METER_WRITE(mvt->overflows, stream); + METER_WRITE(mvt->underflows, stream); + METER_WRITE(mvt->refills, stream); + METER_WRITE(mvt->refillPushes, stream); + METER_WRITE(mvt->returns, stream); + METER_WRITE(mvt->perfectFits, stream); + METER_WRITE(mvt->firstFits, stream); + METER_WRITE(mvt->secondFits, stream); + METER_WRITE(mvt->failures, stream); + METER_WRITE(mvt->emergencyContingencies, stream); + METER_WRITE(mvt->fragLimitContingencies, stream); + METER_WRITE(mvt->contingencySearches, stream); + METER_WRITE(mvt->contingencyHardSearches, stream); + METER_WRITE(mvt->splinters, stream); + METER_WRITE(mvt->splintersUsed, stream); + METER_WRITE(mvt->splintersDropped, stream); + METER_WRITE(mvt->sawdust, stream); + METER_WRITE(mvt->exceptions, stream); + METER_WRITE(mvt->exceptionSplinters, stream); + METER_WRITE(mvt->exceptionReturns, stream); res = WriteF(stream, "}\n", NULL); return res; diff --git a/mps/code/sac.c b/mps/code/sac.c index 435988cf867..3caf9ab893f 100644 --- a/mps/code/sac.c +++ b/mps/code/sac.c @@ -48,18 +48,20 @@ static Bool SACCheck(SAC sac) CHECKL(esac->_middle > 0); /* check classes above middle */ prevSize = esac->_middle; - for (j = sac->middleIndex + 1, i = 0; - j <= sac->classesCount; ++j, i += 2) { + for (j = sac->middleIndex + 1, i = 0; j < sac->classesCount; ++j, i += 2) { CHECKL(prevSize < esac->_freelists[i]._size); b = sacFreeListBlockCheck(&(esac->_freelists[i])); if (!b) return b; prevSize = esac->_freelists[i]._size; } /* check overlarge class */ - CHECKL(esac->_freelists[i-2]._size == SizeMAX); - CHECKL(esac->_freelists[i-2]._count == 0); - CHECKL(esac->_freelists[i-2]._count_max == 0); - CHECKL(esac->_freelists[i-2]._blocks == NULL); + CHECKL(prevSize < esac->_freelists[i]._size); + b = sacFreeListBlockCheck(&(esac->_freelists[i])); + if (!b) return b; + CHECKL(esac->_freelists[i]._size == SizeMAX); + CHECKL(esac->_freelists[i]._count == 0); + CHECKL(esac->_freelists[i]._count_max == 0); + CHECKL(esac->_freelists[i]._blocks == NULL); /* check classes below middle */ prevSize = esac->_middle; for (j = sac->middleIndex, i = 1; j > 0; --j, i += 2) { @@ -69,6 +71,7 @@ static Bool SACCheck(SAC sac) prevSize = esac->_freelists[i]._size; } /* check smallest class */ + CHECKL(prevSize > esac->_freelists[i]._size); CHECKL(esac->_freelists[i]._size == 0); b = sacFreeListBlockCheck(&(esac->_freelists[i])); return b; diff --git a/mps/code/trace.c b/mps/code/trace.c index 924badcd541..c726d8b8597 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -797,10 +797,11 @@ void TraceDestroy(Trace trace) (TraceStatReclaim, trace, trace->reclaimCount, trace->reclaimSize)); + EVENT1(TraceDestroy, trace); + trace->sig = SigInvalid; trace->arena->busyTraces = TraceSetDel(trace->arena->busyTraces, trace); trace->arena->flippedTraces = TraceSetDel(trace->arena->flippedTraces, trace); - EVENT1(TraceDestroy, trace); } diff --git a/mps/code/vman.c b/mps/code/vman.c index db7795c9f2e..6ba3d0b9dff 100644 --- a/mps/code/vman.c +++ b/mps/code/vman.c @@ -1,7 +1,7 @@ /* vman.c: ANSI VM: MALLOC-BASED PSEUDO MEMORY MAPPING * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. */ #include "mpm.h" @@ -117,13 +117,13 @@ void VMDestroy(VM vm) AVER(vm->mapped == (Size)0); AVER(vm->reserved == AddrOffset(vm->base, vm->limit)); + EVENT1(VMDestroy, vm); + memset((void *)vm->base, VMJunkBYTE, AddrOffset(vm->base, vm->limit)); free(vm->block); vm->sig = SigInvalid; - free(vm); - - EVENT1(VMDestroy, vm); + free(vm); } @@ -215,7 +215,7 @@ void VMUnmap(VM vm, Addr base, Addr limit) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/vmix.c b/mps/code/vmix.c index 01a0919b820..0903a031a2c 100644 --- a/mps/code/vmix.c +++ b/mps/code/vmix.c @@ -1,7 +1,7 @@ /* vmix.c: VIRTUAL MEMORY MAPPING FOR UNIX (ISH) * * $Id$ - * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .purpose: This is the implementation of the virtual memory mapping * interface (vm.h) for Unix-like operating systems. It was created @@ -186,6 +186,8 @@ void VMDestroy(VM vm) AVERT(VM, vm); AVER(vm->mapped == (Size)0); + EVENT1(VMDestroy, vm); + /* This appears to be pretty pointless, since the descriptor */ /* page is about to vanish completely. However, munmap might fail */ /* for some reason, and this would ensure that it was still */ @@ -197,8 +199,6 @@ void VMDestroy(VM vm) r = munmap((void *)vm, (size_t)SizeAlignUp(sizeof(VMStruct), vm->align)); AVER(r == 0); - - EVENT1(VMDestroy, vm); } @@ -304,7 +304,7 @@ void VMUnmap(VM vm, Addr base, Addr limit) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2013 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/vmw3.c b/mps/code/vmw3.c index e82f14ccd51..5be8153c73c 100644 --- a/mps/code/vmw3.c +++ b/mps/code/vmw3.c @@ -1,7 +1,7 @@ /* vmw3.c: VIRTUAL MEMORY MAPPING FOR WIN32 * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .design: See . * @@ -191,6 +191,8 @@ void VMDestroy(VM vm) AVERT(VM, vm); AVER(vm->mapped == 0); + EVENT1(VMDestroy, vm); + /* This appears to be pretty pointless, since the vm descriptor page * is about to vanish completely. However, the VirtualFree might * fail and it would be nice to have a dead sig there. */ @@ -201,7 +203,6 @@ void VMDestroy(VM vm) b = VirtualFree((LPVOID)vm, (SIZE_T)0, MEM_RELEASE); AVER(b != 0); - EVENT1(VMDestroy, vm); } @@ -303,7 +304,7 @@ void VMUnmap(VM vm, Addr base, Addr limit) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From 8c63b8134268a8ec3a94a01e4b5d28f3130656b4 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 11 Apr 2014 12:06:28 +0100 Subject: [PATCH 055/266] Add -wconversion to options for gcc and clang. Ensure that the MPS builds with this option with Clang. Copied from Perforce Change: 185457 ServerID: perforce.ravenbrook.com --- mps/code/gc.gmk | 1 + mps/code/ll.gmk | 1 + mps/code/nailboard.c | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mps/code/gc.gmk b/mps/code/gc.gmk index 826cb0ef659..d3716ca9f18 100644 --- a/mps/code/gc.gmk +++ b/mps/code/gc.gmk @@ -16,6 +16,7 @@ CFLAGSCOMPILER := \ -Waggregate-return \ -Wall \ -Wcast-qual \ + -Wconversion \ -Werror \ -Wextra \ -Winline \ diff --git a/mps/code/ll.gmk b/mps/code/ll.gmk index dc2595c511f..6a8c96e6731 100644 --- a/mps/code/ll.gmk +++ b/mps/code/ll.gmk @@ -17,6 +17,7 @@ CFLAGSCOMPILER := \ -Waggregate-return \ -Wall \ -Wcast-qual \ + -Wconversion \ -Werror \ -Wextra \ -Winline \ diff --git a/mps/code/nailboard.c b/mps/code/nailboard.c index dc669a67ef7..709fd915121 100644 --- a/mps/code/nailboard.c +++ b/mps/code/nailboard.c @@ -44,7 +44,7 @@ static Count nailboardNails(Nailboard board) static Count nailboardLevelBits(Count nails, Index level) { - Shift shift = level * LEVEL_SHIFT; + Shift shift = (Shift)(level * LEVEL_SHIFT); return (nails + (1 << shift) - 1) >> shift; } From 24aef39a773d3f0b1e49d320cf3404b7f8058ee6 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 11 Apr 2014 12:17:39 +0100 Subject: [PATCH 056/266] Not ready for gcc -wconversion. Copied from Perforce Change: 185459 ServerID: perforce.ravenbrook.com --- mps/code/gc.gmk | 1 - 1 file changed, 1 deletion(-) diff --git a/mps/code/gc.gmk b/mps/code/gc.gmk index d3716ca9f18..826cb0ef659 100644 --- a/mps/code/gc.gmk +++ b/mps/code/gc.gmk @@ -16,7 +16,6 @@ CFLAGSCOMPILER := \ -Waggregate-return \ -Wall \ -Wcast-qual \ - -Wconversion \ -Werror \ -Wextra \ -Winline \ From fb2443daaaab9a39a4137d09084fa3d5fdb66ce2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 11 Apr 2014 12:42:26 +0100 Subject: [PATCH 057/266] Fix the build for gcc on os x: gcc warns about the missing return in protcatchthread, but we don't want to add one because that would be unreachable code. so use __attribute__((__noreturn__)) instead. Copied from Perforce Change: 185461 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 10 ++++++++++ mps/code/protxc.c | 1 + 2 files changed, 11 insertions(+) diff --git a/mps/code/config.h b/mps/code/config.h index e29127c153c..b781f1da591 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -231,6 +231,16 @@ #define ATTRIBUTE_NO_SANITIZE_ADDRESS #endif +/* Attribute for functions that do not return. + * GCC: + * Clang: + */ +#if defined(MPS_BUILD_GC) || defined(MPS_BUILD_LL) +#define ATTRIBUTE_NORETURN __attribute__((__noreturn__)) +#else +#define ATTRIBUTE_NORETURN +#endif + /* EPVMDefaultSubsequentSegSIZE is a default for the alignment of * subsequent segments (non-initial at each save level) in EPVM. See diff --git a/mps/code/protxc.c b/mps/code/protxc.c index 8f62bb3a5df..58dee81a179 100644 --- a/mps/code/protxc.c +++ b/mps/code/protxc.c @@ -282,6 +282,7 @@ static void protCatchOne(void) * handler won't cause a deadlock. */ +ATTRIBUTE_NORETURN static void *protCatchThread(void *p) { UNUSED(p); for (;;) From 391e7e6c83c17ca05991cebc00305401cf9c87d2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 11 Apr 2014 14:25:15 +0100 Subject: [PATCH 058/266] Add -wconversion to the options for gcc. ensure that the mps builds. Copied from Perforce Change: 185463 ServerID: perforce.ravenbrook.com --- mps/code/buffer.c | 6 +++--- mps/code/eventcom.h | 10 +++++++--- mps/code/fbmtest.c | 2 +- mps/code/fotest.c | 4 ++-- mps/code/gc.gmk | 1 + mps/code/global.c | 2 +- mps/code/misc.h | 15 +++++++++++++-- mps/code/mpm.h | 8 ++++---- mps/code/mpmst.h | 8 ++++---- mps/code/mpmtypes.h | 2 +- mps/code/nailboard.c | 2 +- mps/code/poolmfs.c | 2 +- mps/code/poolmvff.c | 2 +- mps/code/seg.c | 12 ++++++------ mps/code/trace.c | 2 +- 15 files changed, 47 insertions(+), 31 deletions(-) diff --git a/mps/code/buffer.c b/mps/code/buffer.c index baa553a19a2..90aec0b7a45 100644 --- a/mps/code/buffer.c +++ b/mps/code/buffer.c @@ -1075,7 +1075,7 @@ static Res bufferTrivInit(Buffer buffer, Pool pool, ArgList args) AVERT(Buffer, buffer); AVERT(Pool, pool); UNUSED(args); - EVENT3(BufferInit, buffer, pool, buffer->isMutator); + EVENT3(BufferInit, buffer, pool, BOOL(buffer->isMutator)); return ResOK; } @@ -1288,7 +1288,7 @@ static Res segBufInit(Buffer buffer, Pool pool, ArgList args) segbuf->rankSet = RankSetEMPTY; AVERT(SegBuf, segbuf); - EVENT3(BufferInitSeg, buffer, pool, buffer->isMutator); + EVENT3(BufferInitSeg, buffer, pool, BOOL(buffer->isMutator)); return ResOK; } @@ -1515,7 +1515,7 @@ static Res rankBufInit(Buffer buffer, Pool pool, ArgList args) BufferSetRankSet(buffer, RankSetSingle(rank)); /* There's nothing to check that the superclass doesn't, so no AVERT. */ - EVENT4(BufferInitRank, buffer, pool, buffer->isMutator, rank); + EVENT4(BufferInitRank, buffer, pool, BOOL(buffer->isMutator), rank); return ResOK; } diff --git a/mps/code/eventcom.h b/mps/code/eventcom.h index 6114b045d48..d2c43a31c60 100644 --- a/mps/code/eventcom.h +++ b/mps/code/eventcom.h @@ -1,6 +1,6 @@ /* -- Event Logging Common Definitions * - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * $Id$ * * .sources: mps.design.telemetry @@ -89,7 +89,11 @@ typedef Word EventFW; /* word */ typedef unsigned EventFU; /* unsigned integer */ typedef char EventFS[EventStringLengthMAX + sizeof('\0')]; /* string */ typedef double EventFD; /* double */ -typedef int EventFB; /* boolean */ +/* EventFB must be unsigned (even though Bool is a typedef for int) + * because it used as the type of a bitfield with width 1, and we need + * the legals values of the field to be 0 and 1 (not 0 and -1 which + * would be the case for int : 1). */ +typedef unsigned EventFB; /* Boolean */ /* Event packing bitfield specifiers */ #define EventFP_BITFIELD @@ -133,7 +137,7 @@ typedef union EventUnion { /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/fbmtest.c b/mps/code/fbmtest.c index 9f3754b3496..231d02482a7 100644 --- a/mps/code/fbmtest.c +++ b/mps/code/fbmtest.c @@ -560,7 +560,7 @@ extern int main(int argc, char *argv[]) Align align; testlib_init(argc, argv); - align = (1 << rnd() % 4) * MPS_PF_ALIGN; + align = sizeof(void *) << (rnd() % 4); NAllocateTried = NAllocateSucceeded = NDeallocateTried = NDeallocateSucceeded = 0; diff --git a/mps/code/fotest.c b/mps/code/fotest.c index 9dab6650ede..2e63d4e121b 100644 --- a/mps/code/fotest.c +++ b/mps/code/fotest.c @@ -171,7 +171,7 @@ int main(int argc, char *argv[]) die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "mps_arena_create"); - alignment = (1 << (rnd() % 4)) * MPS_PF_ALIGN; + alignment = sizeof(void *) << (rnd() % 4); MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, (64 + rnd() % 64) * 1024); MPS_ARGS_ADD(args, MPS_KEY_MEAN_SIZE, (1 + rnd() % 8) * 8); @@ -190,7 +190,7 @@ int main(int argc, char *argv[]) die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "mps_arena_create"); - alignment = (1 << (rnd() % 4)) * MPS_PF_ALIGN; + alignment = sizeof(void *) << (rnd() % 4); MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_ALIGN, alignment); MPS_ARGS_ADD(args, MPS_KEY_MIN_SIZE, (1 + rnd() % 4) * 4); diff --git a/mps/code/gc.gmk b/mps/code/gc.gmk index 826cb0ef659..d3716ca9f18 100644 --- a/mps/code/gc.gmk +++ b/mps/code/gc.gmk @@ -16,6 +16,7 @@ CFLAGSCOMPILER := \ -Waggregate-return \ -Wall \ -Wcast-qual \ + -Wconversion \ -Werror \ -Wextra \ -Winline \ diff --git a/mps/code/global.c b/mps/code/global.c index 22326aa391f..da97184130c 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -1131,7 +1131,7 @@ void ArenaSetEmergency(Arena arena, Bool emergency) AVERT(Arena, arena); AVERT(Bool, emergency); - EVENT2(ArenaSetEmergency, arena, emergency); + EVENT2(ArenaSetEmergency, arena, BOOL(emergency)); arena->emergency = emergency; } diff --git a/mps/code/misc.h b/mps/code/misc.h index 6ba4be5f49d..444df857317 100644 --- a/mps/code/misc.h +++ b/mps/code/misc.h @@ -1,7 +1,7 @@ /* misc.h: MISCELLANEOUS DEFINITIONS * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2001 Global Graphics Software. * * Small general things which are useful for C but aren't part of the @@ -170,6 +170,16 @@ typedef const struct SrcIdStruct { ((type *)(void *)((char *)(p) - offsetof(type, field))) +/* BITFIELD -- coerce a value into a bitfield + * + * This coerces value to the given width and type in a way that avoids + * warnings from gcc -Wconversion about possible loss of data. + */ + +#define BITFIELD(type, value, width) ((type)value & (((type)1 << (width)) - 1)) +#define BOOL(v) BITFIELD(unsigned, (v), 1) + + /* Bit Sets -- sets of integers in [0,N-1]. * * Can be used on any unsigned integral type, ty. These definitions @@ -191,6 +201,7 @@ typedef const struct SrcIdStruct { #define BS_SUB(s1, s2) BS_SUPER((s2), (s1)) #define BS_IS_SINGLE(s) ( ((s) != 0) && (((s) & ((s)-1)) == 0) ) #define BS_SYM_DIFF(s1, s2) ((s1) ^ (s2)) +#define BS_BITFIELD(ty, s) BITFIELD(ty ## Set, (s), ty ## LIMIT) #endif /* misc_h */ @@ -198,7 +209,7 @@ typedef const struct SrcIdStruct { /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 3423ffdb03c..0cbad2b0f1c 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -711,10 +711,10 @@ extern Addr (SegLimit)(Seg seg); #define SegSummary(seg) (((GCSeg)(seg))->summary) -#define SegSetPM(seg, mode) ((void)((seg)->pm = (mode))) -#define SegSetSM(seg, mode) ((void)((seg)->sm = (mode))) -#define SegSetDepth(seg, d) ((void)((seg)->depth = (d))) -#define SegSetNailed(seg, ts) ((void)((seg)->nailed = (ts))) +#define SegSetPM(seg, mode) ((void)((seg)->pm = BS_BITFIELD(Access, (mode)))) +#define SegSetSM(seg, mode) ((void)((seg)->sm = BS_BITFIELD(Access, (mode)))) +#define SegSetDepth(seg, d) ((void)((seg)->depth = BITFIELD(unsigned, (d), ShieldDepthWIDTH))) +#define SegSetNailed(seg, ts) ((void)((seg)->nailed = BS_BITFIELD(Trace, (ts)))) /* Buffer Interface -- see */ diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 85e95a78ec1..5d38f3a3319 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-2013 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2001 Global Graphics Software. * * .design: This header file crosses module boundaries. The relevant @@ -275,8 +275,8 @@ typedef struct SegStruct { /* segment structure */ RingStruct poolRing; /* link in list of segs in pool */ Addr limit; /* limit of segment */ unsigned depth : ShieldDepthWIDTH; /* see */ - AccessSet pm : AccessSetWIDTH; /* protection mode, */ - AccessSet sm : AccessSetWIDTH; /* shield mode, */ + AccessSet pm : AccessLIMIT; /* protection mode, */ + AccessSet sm : AccessLIMIT; /* shield mode, */ TraceSet grey : TraceLIMIT; /* traces for which seg is grey */ TraceSet white : TraceLIMIT; /* traces for which seg is white */ TraceSet nailed : TraceLIMIT; /* traces for which seg has nailed objects */ @@ -738,7 +738,7 @@ typedef struct AllocPatternStruct { /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2013 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 693a2262247..e22e77d8f69 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -271,7 +271,7 @@ typedef struct TraceMessageStruct *TraceMessage; /* trace end */ #define AccessSetEMPTY ((AccessSet)0) /* */ #define AccessREAD ((AccessSet)(1<<0)) #define AccessWRITE ((AccessSet)(1<<1)) -#define AccessSetWIDTH (2) +#define AccessLIMIT (2) #define RefSetEMPTY BS_EMPTY(RefSet) #define RefSetUNIV BS_UNIV(RefSet) #define ZoneSetEMPTY BS_EMPTY(ZoneSet) diff --git a/mps/code/nailboard.c b/mps/code/nailboard.c index 709fd915121..852c98949e7 100644 --- a/mps/code/nailboard.c +++ b/mps/code/nailboard.c @@ -45,7 +45,7 @@ static Count nailboardNails(Nailboard board) static Count nailboardLevelBits(Count nails, Index level) { Shift shift = (Shift)(level * LEVEL_SHIFT); - return (nails + (1 << shift) - 1) >> shift; + return (nails + ((Count)1 << shift) - 1) >> shift; } Bool NailboardCheck(Nailboard board) diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c index fbb125a71f2..214b2b232d3 100644 --- a/mps/code/poolmfs.c +++ b/mps/code/poolmfs.c @@ -136,7 +136,7 @@ static Res MFSInit(Pool pool, ArgList args) mfs->sig = MFSSig; AVERT(MFS, mfs); - EVENT5(PoolInitMFS, pool, arena, extendBy, extendSelf, unitSize); + EVENT5(PoolInitMFS, pool, arena, extendBy, BOOL(extendSelf), unitSize); return ResOK; } diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 201d2047104..fc4307d50a2 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -610,7 +610,7 @@ static Res MVFFInit(Pool pool, ArgList args) mvff->sig = MVFFSig; AVERT(MVFF, mvff); EVENT8(PoolInitMVFF, pool, arena, extendBy, avgSize, align, - slotHigh, arenaHigh, firstFit); + BOOL(slotHigh), BOOL(arenaHigh), BOOL(firstFit)); return ResOK; failInit: diff --git a/mps/code/seg.c b/mps/code/seg.c index 069b2c50049..31dd0759ff9 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -593,7 +593,7 @@ Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi, if (ResOK != res) goto failMerge; - EVENT3(SegMerge, segLo, segHi, withReservoirPermit); + EVENT3(SegMerge, segLo, segHi, BOOL(withReservoirPermit)); /* Deallocate segHi object */ ControlFree(arena, segHi, class->size); AVERT(Seg, segLo); @@ -1200,7 +1200,7 @@ static void gcSegSetGreyInternal(Seg seg, TraceSet oldGrey, TraceSet grey) /* Internal method. Parameters are checked by caller */ gcseg = SegGCSeg(seg); arena = PoolArena(SegPool(seg)); - seg->grey = grey; + seg->grey = BS_BITFIELD(Trace, grey); /* If the segment is now grey and wasn't before, add it to the */ /* appropriate grey list so that TraceFindGrey can locate it */ @@ -1313,11 +1313,11 @@ static void gcSegSetWhite(Seg seg, TraceSet white) AVERT_CRITICAL(Tract, tract); AVER_CRITICAL(TRACT_SEG(&trseg, tract) && (trseg == seg)); - TractSetWhite(tract, white); + TractSetWhite(tract, BS_BITFIELD(Trace, white)); } AVER(addr == limit); - seg->white = white; + seg->white = BS_BITFIELD(Trace, white); } @@ -1350,7 +1350,7 @@ static void gcSegSetRankSet(Seg seg, RankSet rankSet) arena = PoolArena(SegPool(seg)); oldRankSet = seg->rankSet; - seg->rankSet = rankSet; + seg->rankSet = BS_BITFIELD(Rank, rankSet); if (oldRankSet == RankSetEMPTY) { if (rankSet != RankSetEMPTY) { @@ -1427,7 +1427,7 @@ static void gcSegSetRankSummary(Seg seg, RankSet rankSet, RefSet summary) wasShielded = (seg->rankSet != RankSetEMPTY && gcseg->summary != RefSetUNIV); willbeShielded = (rankSet != RankSetEMPTY && summary != RefSetUNIV); - seg->rankSet = rankSet; + seg->rankSet = BS_BITFIELD(Rank, rankSet); gcseg->summary = summary; if (willbeShielded && !wasShielded) { diff --git a/mps/code/trace.c b/mps/code/trace.c index c726d8b8597..61e9d396155 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1570,7 +1570,7 @@ static void TraceStartPoolGen(Chain chain, GenDesc desc, Bool top, Index i) Ring n, nn; RING_FOR(n, &desc->locusRing, nn) { PoolGen gen = RING_ELT(PoolGen, genRing, n); - EVENT11(TraceStartPoolGen, chain, top, i, desc, + EVENT11(TraceStartPoolGen, chain, BOOL(top), i, desc, desc->capacity, desc->mortality, desc->zones, gen->pool, gen->nr, gen->totalSize, gen->newSizeAtCreate); From ab57c07df5996d3c0d0a63f68eadc6f0b5c9e8b0 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 11 Apr 2014 15:17:20 +0100 Subject: [PATCH 059/266] Turn on -wduplicate-enum and -wmissing-variable-declarations options for clang. ensure the mps compiles with these options. Copied from Perforce Change: 185466 ServerID: perforce.ravenbrook.com --- mps/code/amcssth.c | 10 +++++----- mps/code/arg.h | 5 +++-- mps/code/buffer.c | 4 ++-- mps/code/event.c | 4 ++-- mps/code/eventcom.h | 3 ++- mps/code/eventtxt.c | 2 +- mps/code/fmtscheme.c | 10 ++-------- mps/code/global.c | 1 + mps/code/ll.gmk | 2 ++ mps/code/lockut.c | 2 +- mps/code/misc.h | 1 + mps/code/poolawl.c | 4 ++++ mps/code/qs.c | 2 +- mps/code/steptest.c | 26 +++++++++++++------------- mps/code/version.c | 2 ++ 15 files changed, 42 insertions(+), 36 deletions(-) diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c index 2f17f97ca09..2f91edee93e 100644 --- a/mps/code/amcssth.c +++ b/mps/code/amcssth.c @@ -83,11 +83,11 @@ static void report(mps_arena_t arena) } -mps_arena_t arena; -mps_fmt_t format; -mps_chain_t chain; -mps_root_t exactRoot, ambigRoot; -unsigned long objs = 0; +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; /* make -- create one new object */ diff --git a/mps/code/arg.h b/mps/code/arg.h index dd458efe7b7..bb184dddad9 100644 --- a/mps/code/arg.h +++ b/mps/code/arg.h @@ -1,7 +1,7 @@ /* arg.h: Keyword argument lists * * $Id$ - * Copyright (c) 2013 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2013-2014 Ravenbrook Limited. See end of file for license. * * .source: See . */ @@ -28,6 +28,7 @@ typedef struct mps_key_s { } KeyStruct; #define ARG_DEFINE_KEY(id, type) \ + extern const KeyStruct _mps_key_##id; \ const KeyStruct _mps_key_##id = {KeySig, #id, ArgCheck##type} #define argsNone mps_args_none @@ -62,7 +63,7 @@ extern Bool ArgCheckPool(Arg arg); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2013 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/buffer.c b/mps/code/buffer.c index 90aec0b7a45..27314924600 100644 --- a/mps/code/buffer.c +++ b/mps/code/buffer.c @@ -980,14 +980,14 @@ Bool BufferIsTrappedByMutator(Buffer buffer) * * Just represent the two patterns by two different pointers to dummies. */ -AllocPatternStruct AllocPatternRampStruct = {'\0'}; +static AllocPatternStruct AllocPatternRampStruct = {'\0'}; AllocPattern AllocPatternRamp(void) { return &AllocPatternRampStruct; } -AllocPatternStruct AllocPatternRampCollectAllStruct = {'\0'}; +static AllocPatternStruct AllocPatternRampCollectAllStruct = {'\0'}; AllocPattern AllocPatternRampCollectAll(void) { diff --git a/mps/code/event.c b/mps/code/event.c index 2e7468c3752..d2166dbba2d 100644 --- a/mps/code/event.c +++ b/mps/code/event.c @@ -44,13 +44,13 @@ char EventBuffer[EventKindLIMIT][EventBufferSIZE]; char *EventLast[EventKindLIMIT]; /* Pointers to the last even written out of each buffer. */ -char *EventWritten[EventKindLIMIT]; +static char *EventWritten[EventKindLIMIT]; EventControlSet EventKindControl; /* Bit set used to control output. */ /* A single event structure output once per buffer flush. */ -EventEventClockSyncStruct eventClockSyncStruct; +static EventEventClockSyncStruct eventClockSyncStruct; /* eventClockSync -- Populate and write the clock sync event. */ diff --git a/mps/code/eventcom.h b/mps/code/eventcom.h index d2c43a31c60..931c975596d 100644 --- a/mps/code/eventcom.h +++ b/mps/code/eventcom.h @@ -56,7 +56,8 @@ ENUM_DECLARE(EventKind) enum EventDefinitionsEnum { EVENT_LIST(EVENT_ENUM, X) - EventEnumWarningSuppressor /* suppress comma-at-end-of-enum warning */ + /* suppress comma-at-end-of-enum warning */ + EventEnumWarningSuppressor = USHRT_MAX }; diff --git a/mps/code/eventtxt.c b/mps/code/eventtxt.c index 5b7f7ab1312..692aa348296 100644 --- a/mps/code/eventtxt.c +++ b/mps/code/eventtxt.c @@ -171,7 +171,7 @@ static double parseDouble(char **pInOut) #define MAX_STRING_LENGTH 1024 -char strBuf[MAX_STRING_LENGTH]; +static char strBuf[MAX_STRING_LENGTH]; static char *parseString(char **pInOut) { diff --git a/mps/code/fmtscheme.c b/mps/code/fmtscheme.c index 5299c8f3525..11900130a71 100644 --- a/mps/code/fmtscheme.c +++ b/mps/code/fmtscheme.c @@ -12,14 +12,8 @@ /* special objects */ -obj_t obj_empty; /* (), the empty list */ -obj_t obj_eof; /* end of file */ -obj_t obj_error; /* error indicator */ -obj_t obj_true; /* #t, boolean true */ -obj_t obj_false; /* #f, boolean false */ -obj_t obj_undefined; /* undefined result indicator */ -obj_t obj_tail; /* tail recursion indicator */ -obj_t obj_deleted; /* deleted key in hashtable */ +static obj_t obj_true; /* #t, boolean true */ +static obj_t obj_false; /* #f, boolean false */ /* MPS globals */ diff --git a/mps/code/global.c b/mps/code/global.c index da97184130c..9bfe9c20dc0 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -617,6 +617,7 @@ void ArenaLeaveRecursive(Arena arena) * version. The format is platform-specific. We won't necessarily * publish this. */ +extern MutatorFaultContext mps_exception_info; MutatorFaultContext mps_exception_info = NULL; diff --git a/mps/code/ll.gmk b/mps/code/ll.gmk index 6a8c96e6731..24dd32b9efe 100644 --- a/mps/code/ll.gmk +++ b/mps/code/ll.gmk @@ -18,10 +18,12 @@ CFLAGSCOMPILER := \ -Wall \ -Wcast-qual \ -Wconversion \ + -Wduplicate-enum \ -Werror \ -Wextra \ -Winline \ -Wmissing-prototypes \ + -Wmissing-variable-declarations \ -Wnested-externs \ -Wno-extended-offsetof \ -Wpointer-arith \ diff --git a/mps/code/lockut.c b/mps/code/lockut.c index ec22369bc13..8b8e677b382 100644 --- a/mps/code/lockut.c +++ b/mps/code/lockut.c @@ -15,7 +15,7 @@ #define nTHREADS 4 static Lock lock; -unsigned long shared, tmp; +static unsigned long shared, tmp; static void incR(unsigned long i) diff --git a/mps/code/misc.h b/mps/code/misc.h index 444df857317..809fd7e954a 100644 --- a/mps/code/misc.h +++ b/mps/code/misc.h @@ -50,6 +50,7 @@ typedef const struct SrcIdStruct { #define SRCID(id, scmid) \ static SrcIdStruct id ## FileSrcIdStruct = \ {__FILE__, (scmid), __DATE__, __TIME__}; \ + extern SrcId id ## SrcId; \ SrcId id ## SrcId = &id ## FileSrcIdStruct diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index edcae788e3c..cbece0b41fe 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -305,10 +305,14 @@ DEFINE_SEG_CLASS(AWLSegClass, class) * it's possible to tweak them in a debugger. */ +extern Count AWLSegSALimit; Count AWLSegSALimit = AWL_SEG_SA_LIMIT; +extern Bool AWLHaveSegSALimit; Bool AWLHaveSegSALimit = AWL_HAVE_SEG_SA_LIMIT; +extern Count AWLTotalSALimit; Count AWLTotalSALimit = AWL_TOTAL_SA_LIMIT; +extern Bool AWLHaveTotalSALimit; Bool AWLHaveTotalSALimit = AWL_HAVE_TOTAL_SA_LIMIT; diff --git a/mps/code/qs.c b/mps/code/qs.c index 4d78fc6bcb8..50fe8c48723 100644 --- a/mps/code/qs.c +++ b/mps/code/qs.c @@ -50,7 +50,7 @@ static mps_addr_t isMoved(mps_addr_t object); static void copy(mps_addr_t object, mps_addr_t to); static void pad(mps_addr_t base, size_t size); -struct mps_fmt_A_s fmt_A_s = +static struct mps_fmt_A_s fmt_A_s = { (mps_align_t)4, scan, skip, copy, diff --git a/mps/code/steptest.c b/mps/code/steptest.c index c1af5b01089..deee85fef2e 100644 --- a/mps/code/steptest.c +++ b/mps/code/steptest.c @@ -71,19 +71,19 @@ static mps_addr_t ambigRoots[ambigRootsCOUNT]; /* Things we want to measure. Times are all in microseconds. */ -double alloc_time; /* Time spent allocating */ -double max_alloc_time; /* Max time taken to allocate one object */ -double step_time; /* Time spent in mps_arena_step returning 1 */ -double max_step_time; /* Max time of mps_arena_step returning 1 */ -double no_step_time; /* Time spent in mps_arena_step returning 0 */ -double max_no_step_time; /* Max time of mps_arena_step returning 0 */ +static double alloc_time; /* Time spent allocating */ +static double max_alloc_time; /* Max time taken to allocate one object */ +static double step_time; /* Time spent in mps_arena_step returning 1 */ +static double max_step_time; /* Max time of mps_arena_step returning 1 */ +static double no_step_time; /* Time spent in mps_arena_step returning 0 */ +static double max_no_step_time; /* Max time of mps_arena_step returning 0 */ -double total_clock_time; /* Time spent reading the clock */ -long clock_reads; /* Number of times clock is read */ -long steps; /* # of mps_arena_step calls returning 1 */ -long no_steps; /* # of mps_arena_step calls returning 0 */ -size_t alloc_bytes; /* # of bytes allocated */ -long commit_failures; /* # of times mps_commit fails */ +static double total_clock_time; /* Time spent reading the clock */ +static long clock_reads; /* Number of times clock is read */ +static long steps; /* # of mps_arena_step calls returning 1 */ +static long no_steps; /* # of mps_arena_step calls returning 0 */ +static size_t alloc_bytes; /* # of bytes allocated */ +static long commit_failures; /* # of times mps_commit fails */ /* Operating-system dependent timing. Defines two functions, void @@ -151,7 +151,7 @@ static double my_clock(void) * on thrush.ravenbrook.com on 2002-06-28, clock_time goes from 5.43 * us near process start to 7.45 us later). */ -double clock_time; /* current estimate of time to read the clock */ +static double clock_time; /* current estimate of time to read the clock */ /* take at least this many microseconds to set the clock */ #define CLOCK_TIME_SET 10000 diff --git a/mps/code/version.c b/mps/code/version.c index 9f8d644e47a..4771c8a7c69 100644 --- a/mps/code/version.c +++ b/mps/code/version.c @@ -47,6 +47,7 @@ SRCID(version, "$Id$"); * (assuming we've made any substantial changes to the library this year). */ +extern char MPSCopyrightNotice[]; char MPSCopyrightNotice[] = "Portions copyright (c) 2010-2014 Ravenbrook Limited and Global Graphics Software."; @@ -59,6 +60,7 @@ char MPSCopyrightNotice[] = * see also guide.mps.version. */ +extern char MPSVersionString[]; char MPSVersionString[] = "@(#)Ravenbrook MPS, " "product." MPS_PROD_STRING ", " MPS_RELEASE ", platform." MPS_PF_STRING From 20f55386c40ef94ee5602bc590e1d0892361bd1b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 11 Apr 2014 15:28:03 +0100 Subject: [PATCH 060/266] Turn -wconversion off again. (the mps builds with this option with gcc 4.8 but not with gcc 4.6.3 on the travis buildbots.) Copied from Perforce Change: 185467 ServerID: perforce.ravenbrook.com --- mps/code/gc.gmk | 1 - 1 file changed, 1 deletion(-) diff --git a/mps/code/gc.gmk b/mps/code/gc.gmk index d3716ca9f18..826cb0ef659 100644 --- a/mps/code/gc.gmk +++ b/mps/code/gc.gmk @@ -16,7 +16,6 @@ CFLAGSCOMPILER := \ -Waggregate-return \ -Wall \ -Wcast-qual \ - -Wconversion \ -Werror \ -Wextra \ -Winline \ From 235027d67e95b534945da58f69a21abdb5ac73f2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 11 Apr 2014 20:37:42 +0100 Subject: [PATCH 061/266] Exclude coverage data files from perforce. Copied from Perforce Change: 185470 ServerID: perforce.ravenbrook.com --- mps/.p4ignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mps/.p4ignore b/mps/.p4ignore index fb2e5c024e5..b640360caf6 100644 --- a/mps/.p4ignore +++ b/mps/.p4ignore @@ -18,3 +18,5 @@ code/*/*/*.d *.pyc test/test/log test/test/obj +....gcda +....gcno \ No newline at end of file From 8624638093e33c462d362428a503f614a134d166 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 11 Apr 2014 21:15:09 +0100 Subject: [PATCH 062/266] Default value for mps_key_arena_size makes it easier to create arenas. Copied from Perforce Change: 185472 ServerID: perforce.ravenbrook.com --- mps/code/arenavm.c | 6 +++--- mps/code/config.h | 2 ++ mps/manual/source/topic/arena.rst | 31 ++++++++++++++++--------------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 15b79bbed51..81e0684c436 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -480,7 +480,7 @@ ARG_DEFINE_KEY(arena_contracted, Fun); static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args) { - Size userSize; /* size requested by user */ + Size userSize = VM_ARENA_SIZE_DEFAULT; /* size requested by user */ Size chunkSize; /* size actually created */ Size vmArenaSize; /* aligned size of VMArenaStruct */ Res res; @@ -495,8 +495,8 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args) AVER(class == VMArenaClassGet()); AVERT(ArgList, args); - ArgRequire(&arg, args, MPS_KEY_ARENA_SIZE); - userSize = arg.val.size; + if (ArgPick(&arg, args, MPS_KEY_ARENA_SIZE)) + userSize = arg.val.size; AVER(userSize > 0); diff --git a/mps/code/config.h b/mps/code/config.h index b781f1da591..0afa66c06bb 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -366,6 +366,8 @@ pool to be very heavily used. */ #define CONTROL_EXTEND_BY 4096 +#define VM_ARENA_SIZE_DEFAULT ((Size)1 << 20) + /* Stack configuration */ diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index 5220ece4007..1925117cc84 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -233,18 +233,18 @@ Virtual memory arenas more efficient. When creating a virtual memory arena, :c:func:`mps_arena_create_k` - requires one :term:`keyword argument`: + accepts one :term:`keyword argument` on all platforms: - * :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type:`size_t`). is the - initial amount of virtual address space, in :term:`bytes (1)`, - that the arena will reserve (this space is initially reserved so - that the arena can subsequently use it without interference from - other parts of the program, but most of it is not committed, so - it doesn't require any RAM or backing store). The arena may - allocate more virtual address space beyond this initial - reservation as and when it deems it necessary. The MPS is most - efficient if you reserve an address space that is several times - larger than your peak memory usage. + * :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type:`size_t`, default + 2\ :superscript:`20`) is the initial amount of virtual address + space, in :term:`bytes (1)`, that the arena will reserve (this + space is initially reserved so that the arena can subsequently + use it without interference from other parts of the program, but + most of it is not committed, so it doesn't require any RAM or + backing store). The arena may allocate more virtual address + space beyond this initial reservation as and when it deems it + necessary. The MPS is most efficient if you reserve an address + space that is several times larger than your peak memory usage. .. note:: @@ -252,8 +252,8 @@ Virtual memory arenas more times it has to extend its address space, the less efficient garbage collection will become. - An optional :term:`keyword argument` may be passed, but is - only used on the Windows operating system: + A second 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 @@ -273,8 +273,9 @@ Virtual memory arenas If the MPS fails to allocate memory for the internal arena structures, :c:func:`mps_arena_create_k` returns - :c:macro:`MPS_RES_MEMORY`. Either ``size`` was far too small or - the operating system refused to provide enough memory. + :c:macro:`MPS_RES_MEMORY`. Either :c:macro:`MPS_KEY_ARENA_SIZE` + was far too small or the operating system refused to provide + enough memory. For example:: From 2aef76c48cce07ed16d677d31a0ce3d699b562cf Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 11 Apr 2014 21:18:23 +0100 Subject: [PATCH 063/266] Ensure that mpseventsql compiles with gcc -wmissing-variable-declarations. Copied from Perforce Change: 185473 ServerID: perforce.ravenbrook.com --- mps/code/eventsql.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mps/code/eventsql.c b/mps/code/eventsql.c index 46bfa688a9b..e1c9ea22381 100644 --- a/mps/code/eventsql.c +++ b/mps/code/eventsql.c @@ -102,7 +102,7 @@ typedef sqlite3_int64 int64; * and for reporting errors. */ -unsigned int verbosity = 0; +static unsigned int verbosity = 0; #define LOG_ALWAYS 0 #define LOG_OFTEN 1 @@ -533,7 +533,7 @@ static void logFileCompleted(sqlite3 *db, /* An array of table-creation statement strings. */ -const char *createStatements[] = { +static const char *createStatements[] = { "CREATE TABLE IF NOT EXISTS event_kind (name TEXT," " description TEXT," " enum INTEGER PRIMARY KEY)", @@ -571,7 +571,7 @@ static void makeTables(sqlite3 *db) } } -const char *glueTables[] = { +static const char *glueTables[] = { "event_kind", "event_type", "event_param", From 28d6cd9612148b0e2e54cacde9a94c01aa480fd7 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 11 Apr 2014 21:27:31 +0100 Subject: [PATCH 064/266] Use the mps to manage memory in test cases, not malloc! Copied from Perforce Change: 185474 ServerID: perforce.ravenbrook.com --- mps/code/abqtest.c | 23 ++++++++++++++--------- mps/code/airtest.c | 6 +----- mps/code/lockcov.c | 29 ++++++++++++++++++++++++----- mps/code/lockut.c | 21 +++++++++++++++++++-- 4 files changed, 58 insertions(+), 21 deletions(-) diff --git a/mps/code/abqtest.c b/mps/code/abqtest.c index 49d285c761f..367bafe730b 100644 --- a/mps/code/abqtest.c +++ b/mps/code/abqtest.c @@ -7,16 +7,16 @@ #include "abq.h" #include "mps.h" #include "mpsavm.h" +#include "mpscmfs.h" #include "mpstd.h" #include "testlib.h" -#include /* free, malloc */ #include /* printf */ SRCID(abqtest, "$Id$"); - +static mps_pool_t pool; static ABQStruct abq; /* the ABQ which we will use */ static Size abqSize; /* the size of the current ABQ */ @@ -51,9 +51,12 @@ static TestBlock testBlocks = NULL; static TestBlock CreateTestBlock(unsigned no) { - TestBlock b = malloc(sizeof(TestBlockStruct)); - cdie(b != NULL, "malloc"); + TestBlock b; + mps_addr_t p; + die(mps_alloc(&p, pool, sizeof(TestBlockStruct)), "alloc"); + + b = p; b->next = testBlocks; b->id = no; b->base = 0; @@ -79,7 +82,7 @@ static void DestroyTestBlock(TestBlock b) } } - free(b); + mps_free(pool, b, sizeof(TestBlockStruct)); } typedef struct TestClosureStruct *TestClosure; @@ -147,9 +150,6 @@ static void step(void) } } - -#define testArenaSIZE (((size_t)4)<<20) - extern int main(int argc, char *argv[]) { mps_arena_t arena; @@ -159,9 +159,14 @@ extern int main(int argc, char *argv[]) abqSize = 0; - die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), + die(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none), "mps_arena_create"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, sizeof(TestBlockStruct)); + die(mps_pool_create_k(&pool, arena, mps_class_mfs(), args), "pool_create"); + } MPS_ARGS_END(args); + die(ABQInit((Arena)arena, &abq, NULL, ABQ_SIZE, sizeof(TestBlock)), "ABQInit"); diff --git a/mps/code/airtest.c b/mps/code/airtest.c index 9da2c768f84..946e585bc2f 100644 --- a/mps/code/airtest.c +++ b/mps/code/airtest.c @@ -99,11 +99,7 @@ static void test_main(int interior, int stack) mps_root_t reg_root = NULL; void *marker = ▮ - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 1 << 20); - MPS_ARGS_DONE(args); - res = mps_arena_create_k(&scheme_arena, mps_arena_class_vm(), args); - } MPS_ARGS_END(args); + res = mps_arena_create_k(&scheme_arena, mps_arena_class_vm(), mps_args_none); if (res != MPS_RES_OK) error("Couldn't create arena"); res = mps_chain_create(&obj_chain, scheme_arena, diff --git a/mps/code/lockcov.c b/mps/code/lockcov.c index a7289dca9ce..75ded6f202a 100644 --- a/mps/code/lockcov.c +++ b/mps/code/lockcov.c @@ -4,21 +4,37 @@ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. */ +#include "mps.h" +#include "mpsavm.h" +#include "mpscmfs.h" #include "mpm.h" #include "testlib.h" #include "mpslib.h" #include /* printf */ -#include /* free, malloc */ int main(int argc, char *argv[]) { - Lock a = malloc(LockSize()); - Lock b = malloc(LockSize()); + mps_arena_t arena; + mps_pool_t pool; + mps_addr_t p; + Lock a, b; testlib_init(argc, argv); + die(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none), + "arena_create"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, LockSize()); + die(mps_pool_create_k(&pool, arena, mps_class_mfs(), args), "pool_create"); + } MPS_ARGS_END(args); + + die(mps_alloc(&p, pool, LockSize()), "alloc a"); + a = p; + die(mps_alloc(&p, pool, LockSize()), "alloc b"); + b = p; + Insist(a != NULL); Insist(b != NULL); @@ -46,8 +62,11 @@ int main(int argc, char *argv[]) LockReleaseMPM(a); LockFinish(a); LockReleaseGlobalRecursive(); - free(a); - free(b); + + mps_free(pool, a, LockSize()); + mps_free(pool, b, LockSize()); + mps_pool_destroy(pool); + mps_arena_destroy(arena); printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); return 0; diff --git a/mps/code/lockut.c b/mps/code/lockut.c index 8b8e677b382..e93bdea6815 100644 --- a/mps/code/lockut.c +++ b/mps/code/lockut.c @@ -4,12 +4,14 @@ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. */ +#include "mps.h" +#include "mpsavm.h" +#include "mpscmfs.h" #include "mpm.h" #include "testlib.h" #include "testthr.h" #include /* printf */ -#include /* malloc */ #define nTHREADS 4 @@ -63,12 +65,23 @@ static void *thread0(void *p) int main(int argc, char *argv[]) { + mps_arena_t arena; + mps_pool_t pool; + mps_addr_t p; testthr_t t[10]; unsigned i; testlib_init(argc, argv); - lock = malloc(LockSize()); + die(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none), + "arena_create"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, LockSize()); + die(mps_pool_create_k(&pool, arena, mps_class_mfs(), args), "pool_create"); + } MPS_ARGS_END(args); + + die(mps_alloc(&p, pool, LockSize()), "alloc"); + lock = p; Insist(lock != NULL); LockInit(lock); @@ -86,6 +99,10 @@ int main(int argc, char *argv[]) LockFinish(lock); + mps_free(pool, lock, LockSize()); + mps_pool_destroy(pool); + mps_arena_destroy(arena); + printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); return 0; } From 6d923be672289aae260866d767e0279e8a3f1ddd Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Apr 2014 15:34:43 +0100 Subject: [PATCH 065/266] Eventtxt no longer reports an error if there are multiple labels associated with an address. instead, it store all the labels encountered, and prints the one that was in force at the time of each event. Use the MPS to manage memory, not malloc/free. Recommend sort before mpseventtxt and not afterwards (data is smaller; labelling is more accurate). Copied from Perforce Change: 185477 ServerID: perforce.ravenbrook.com --- mps/code/eventtxt.c | 188 +++++++++++++++++++------- mps/manual/source/topic/telemetry.rst | 2 +- 2 files changed, 142 insertions(+), 48 deletions(-) diff --git a/mps/code/eventtxt.c b/mps/code/eventtxt.c index 692aa348296..70962450d9f 100644 --- a/mps/code/eventtxt.c +++ b/mps/code/eventtxt.c @@ -29,15 +29,19 @@ * $Id$ */ +#include "mps.h" +#include "mpsavm.h" +#include "mpscmvff.h" #include "config.h" #include "eventdef.h" #include "eventcom.h" #include "table.h" #include "testlib.h" /* for ulongest_t and associated print formats */ +#include #include -#include -#include +#include /* exit, EXIT_FAILURE, EXIT_SUCCESS */ +#include /* strcpy, strlen */ static const char *prog; /* program name */ static const char *logFileName = NULL; @@ -106,15 +110,19 @@ static void parseArgs(int argc, char *argv[]) static void *tableAlloc(void *closure, size_t size) { - UNUSED(closure); - return malloc(size); + mps_pool_t pool = closure; + mps_addr_t p; + mps_res_t res; + res = mps_alloc(&p, pool, size); + if (res != MPS_RES_OK) + everror("allocation failed: %d", res); + return p; } static void tableFree(void *closure, void *p, size_t size) { - UNUSED(closure); - UNUSED(size); - free(p); + mps_pool_t pool = closure; + mps_free(pool, p, size); } /* Printing routines */ @@ -215,21 +223,21 @@ static Table internTable; /* dictionary of intern ids to strings */ static Table labelTable; /* dictionary of addrs to intern ids */ -static void createTables(void) +static void createTables(mps_pool_t pool) { Res res; /* MPS intern IDs are serials from zero up, so we can use -1 * and -2 as specials. */ res = TableCreate(&internTable, (size_t)1<<4, - tableAlloc, tableFree, NULL, + tableAlloc, tableFree, pool, (Word)-1, (Word)-2); if (res != ResOK) everror("Couldn't make intern table."); /* We assume that 0 and 1 are invalid as Addrs. */ res = TableCreate(&labelTable, (size_t)1<<7, - tableAlloc, tableFree, NULL, + tableAlloc, tableFree, pool, 0, 1); if (res != ResOK) everror("Couldn't make label table."); @@ -238,19 +246,19 @@ static void createTables(void) /* recordIntern -- record an interned string in the table. a copy of * the string from the parsed buffer into a newly-allocated block. */ -static void recordIntern(char *p) +static void recordIntern(mps_pool_t pool, char *p) { ulongest_t stringId; char *string; - char *copy; + mps_addr_t copy; size_t len; Res res; stringId = parseHex(&p); string = parseString(&p); len = strlen(string); - copy = malloc(len+1); - if (copy == NULL) + res = mps_alloc(©, pool, len + 1); + if (res != MPS_RES_OK) everror("Couldn't allocate space for a string."); (void)strcpy(copy, string); res = TableDefine(internTable, (Word)stringId, (void *)copy); @@ -258,12 +266,55 @@ static void recordIntern(char *p) everror("Couldn't create an intern mapping."); } -/* recordLabel records a label (an association between an address and - * a string ID). Note that the event log may have been generated on a - * platform with addresses larger than Word on the current platform. - * If that happens then we are scuppered because our Table code uses - * Word as the key type: there's nothing we can do except detect this - * bad case (see also the EventInit handling and warning code). +/* Over time there may be multiple labels associated with an address, + * so we keep a list, recording for each label the clock when the + * association was made. This means that printAddr can select the + * label that was in force at the time of the event. + */ + +typedef struct LabelStruct *Label; +typedef struct LabelStruct { + ulongest_t clock; /* clock of this label */ + ulongest_t id; /* string id of this label */ +} LabelStruct; + +typedef struct LabelListStruct *LabelList; +typedef struct LabelListStruct { + size_t n; /* number of labels in array */ + Label labels; /* labels, sorted in order by clock */ +} LabelListStruct; + +/* labelFind returns the index of the first entry in list with a clock + * value that's greater than 'clock', or list->n if there is no such + * label. The list is assumed to be sorted. + */ + +static size_t labelFind(LabelList list, ulongest_t clock) +{ + size_t low = 0, high = list->n; + while (low < high) { + size_t mid = (low + high) / 2; + assert(0 <= mid && mid < list->n); + if (list->labels[mid].clock > clock) { + high = mid; + } else { + low = mid + 1; + } + } + assert(0 <= low && low <= list->n); + assert(low == list->n || list->labels[low].clock > clock); + return low; +} + +/* recordLabel records a label: an association (made at the time given + * by 'clock') between an address and a string ID. These are encoded + * as two hexadecimal numbers in the string pointed to by 'p'. + * + * Note that the event log may have been generated on a platform with + * addresses larger than Word on the current platform. If that happens + * then we are scuppered because our Table code uses Word as the key + * type: there's nothing we can do except detect this bad case (see + * also the EventInit handling and warning code). * * We can and do handle the case where string IDs (which are Words on * the MPS platform) are larger than void* on the current platform. @@ -274,25 +325,50 @@ static void recordIntern(char *p) * probably a bad idea and maybe doomed to failure. */ -static void recordLabel(char *p) +static void recordLabel(mps_pool_t pool, ulongest_t clock, char *p) { ulongest_t address; - ulongest_t *stringIdP; + LabelList list; + Label newlabels; + mps_addr_t tmp; + size_t pos; Res res; - + address = parseHex(&p); if (address > (Word)-1) { (void)printf("label address too large!"); return; } - - stringIdP = malloc(sizeof(ulongest_t)); - if (stringIdP == NULL) - everror("Can't allocate space for a string's ID"); - *stringIdP = parseHex(&p); - res = TableDefine(labelTable, (Word)address, (void *)stringIdP); + + if (TableLookup(&tmp, labelTable, address)) { + list = tmp; + } else { + /* First label for this address */ + res = mps_alloc(&tmp, pool, sizeof(LabelListStruct)); + if (res != MPS_RES_OK) + everror("Can't allocate space for a label list"); + list = tmp; + list->n = 0; + res = TableDefine(labelTable, (Word)address, list); + if (res != ResOK) + everror("Couldn't create a label mapping."); + } + + res = mps_alloc(&tmp, pool, sizeof(LabelStruct) * (list->n + 1)); if (res != ResOK) - everror("Couldn't create an intern mapping."); + everror("Couldn't allocate space for list of labels."); + newlabels = tmp; + + pos = labelFind(list, clock); + memcpy(newlabels, list->labels, sizeof(LabelStruct) * pos); + newlabels[pos].clock = clock; + newlabels[pos].id = parseHex(&p); + memcpy(newlabels + pos + 1, list->labels + pos, + sizeof(LabelStruct) * (list->n - pos)); + if (list->n > 0) + mps_free(pool, list->labels, sizeof(LabelStruct) * list->n); + list->labels = newlabels; + ++ list->n; } /* output code */ @@ -308,20 +384,23 @@ static int hexWordWidth = (MPS_WORD_WIDTH+3)/4; /* printAddr -- output a ulongest_t in hex, with the interned string * if the value is in the label table */ -static void printAddr(ulongest_t addr, const char *ident) +static void printAddr(ulongest_t clock, ulongest_t addr, const char *ident) { - ulongest_t label; - void *alias; + void *tmp; printf("%s:%0*" PRIXLONGEST, ident, hexWordWidth, addr); - if (TableLookup(&alias, labelTable, addr)) { - label = *(ulongest_t*)alias; - putchar('['); - if (TableLookup(&alias, internTable, label)) - printStr((char *)alias); - else - printf("unknown label %" PRIuLONGEST, label); - putchar(']'); + if (TableLookup(&tmp, labelTable, addr)) { + LabelList list = tmp; + size_t pos = labelFind(list, clock); + if (pos > 0) { + putchar('['); + ulongest_t id = list->labels[pos - 1].id; + if (TableLookup(&tmp, internTable, id)) + printStr((char *)tmp); + else + printf("unknown label %" PRIXLONGEST, id); + putchar(']'); + } } putchar(' '); } @@ -332,7 +411,7 @@ static void printAddr(ulongest_t addr, const char *ident) #define processParamA(ident) \ val_hex = parseHex(&p); \ - printAddr(val_hex, #ident); + printAddr(clock, val_hex, #ident); #define processParamP processParamA #define processParamW processParamA @@ -375,7 +454,7 @@ static const char *eventName[EventCodeMAX+EventCodeMAX]; /* readLog -- read and parse log. Returns the number of events written. */ -static void readLog(FILE *input) +static void readLog(mps_pool_t pool, FILE *input) { int i; @@ -415,9 +494,9 @@ static void readLog(FILE *input) /* for a few particular codes, we do local processing. */ if (code == EventInternCode) { - recordIntern(q); + recordIntern(pool, q); } else if (code == EventLabelCode) { - recordLabel(q); + recordLabel(pool, clock, q); } else if (code == EventEventInitCode) { ulongest_t major, median, minor, maxCode, maxNameLen, wordWidth, clocksPerSec; major = parseHex(&q); /* EVENT_VERSION_MAJOR */ @@ -476,6 +555,9 @@ static void readLog(FILE *input) int main(int argc, char *argv[]) { + mps_arena_t arena; + mps_pool_t pool; + mps_res_t res; FILE *input; parseArgs(argc, argv); @@ -488,8 +570,20 @@ int main(int argc, char *argv[]) everror("unable to open %s", logFileName); } - createTables(); - readLog(input); + res = mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none); + if (res != MPS_RES_OK) + everror("failed to create arena: %d", res); + + res = mps_pool_create_k(&pool, arena, mps_class_mvff(), mps_args_none); + if (res != MPS_RES_OK) + everror("failed to create pool: %d", res); + + createTables(pool); + readLog(pool, input); + + mps_pool_destroy(pool); + mps_arena_destroy(arena); + (void)fclose(input); return 0; } diff --git a/mps/manual/source/topic/telemetry.rst b/mps/manual/source/topic/telemetry.rst index f33de3516ce..a665aaf4b07 100644 --- a/mps/manual/source/topic/telemetry.rst +++ b/mps/manual/source/topic/telemetry.rst @@ -110,7 +110,7 @@ The MPS writes the telemetry to the log in an encoded form for speed. It can be decoded using the :ref:`mpseventcnv ` and :ref:`mpseventtxt ` programs:: - (gdb) shell mpseventcnv | mpseventtxt | sort > mpsio.txt + (gdb) shell mpseventcnv | sort | mpseventtxt > mpsio.txt The ``sort`` is useful because the events are not necessarily written to the telemetry file in time order, but each event starts with a From 305d168e162577c60442e9f6366c8b29d1079742 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Apr 2014 16:22:20 +0100 Subject: [PATCH 066/266] Release notes for job003747 and job003756. Copied from Perforce Change: 185479 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 b93ffc786f5..4a57665a23b 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -27,6 +27,15 @@ New features calling :c:func:`mps_pool_create_k`. +Interface changes +................. + +#. There is now a default value (currently 1 \ :term:`megabyte`) for + the :c:macro:`MPS_KEY_ARENA_SIZE` keyword argument to + :c:func:`mps_arena_create_k` when creating a virtual memory arena. + See :c:func:`mps_arena_class_vm`. + + Other changes ............. @@ -44,6 +53,13 @@ Other changes .. _job003745: https://www.ravenbrook.com/project/mps/issue/job003745/ +#. :program:`mpseventtxt` now successfully processes a telemetry log + containing multiple labels associated with the same address. See + job003756_. + + .. _job003756: https://www.ravenbrook.com/project/mps/issue/job003756/ + + .. _release-notes-1.113: From c3c54ce4112ad37c8a6c950e3fe2ddaf0b429c0b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Apr 2014 20:58:56 +0100 Subject: [PATCH 067/266] The assertion that you get when destroying an arena without having destroyed all pools has moved from arenavm.c to sa.c. Remove AMS_IS_INVALID_COLOUR assertion from manual: explanation of cause is incorrect. Copied from Perforce Change: 185481 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/error.rst | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 97ec2f73216..6b2e9452fc2 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -232,7 +232,7 @@ assertion that is listed here but for which you discovered a different cause), please :ref:`let us know ` so that we can improve this documentation. -``arenavm.c: BTIsResRange(vmChunk->pageTableMapped, 0, chunk->pageTablePages)`` +``sa.c: BTIsResRange(sa->mapped, 0, sa->length)`` The client program called :c:func:`mps_arena_destroy` without having destroyed all pools in that arena first. (The assertion is @@ -283,14 +283,6 @@ this documentation. point` instead. -``poolams.c: !AMS_IS_INVALID_COLOUR(seg, i)`` - - The client program failed to :term:`fix` a reference to an object - in an :ref:`pool-ams` pool, violating the :term:`tri-colour - invariant` that the MPS depends on for the correctness of its - :term:`incremental garbage collection`. - - ``poolams.c: AMS_ALLOCED(seg, i)`` The client program tried to :term:`fix` a :term:`reference` to a From 3887d08d298de9b236e6144844f1fa9d019c7e78 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Apr 2014 21:33:29 +0100 Subject: [PATCH 068/266] Fix compilation of eventtxt.c on lii6gc. Copied from Perforce Change: 185483 ServerID: perforce.ravenbrook.com --- mps/code/eventtxt.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mps/code/eventtxt.c b/mps/code/eventtxt.c index 70962450d9f..4c50ac994f9 100644 --- a/mps/code/eventtxt.c +++ b/mps/code/eventtxt.c @@ -32,6 +32,7 @@ #include "mps.h" #include "mpsavm.h" #include "mpscmvff.h" +#include "check.h" #include "config.h" #include "eventdef.h" #include "eventcom.h" @@ -294,14 +295,14 @@ static size_t labelFind(LabelList list, ulongest_t clock) size_t low = 0, high = list->n; while (low < high) { size_t mid = (low + high) / 2; - assert(0 <= mid && mid < list->n); + assert(NONNEGATIVE(mid) && mid < list->n); if (list->labels[mid].clock > clock) { high = mid; } else { low = mid + 1; } } - assert(0 <= low && low <= list->n); + assert(NONNEGATIVE(low) && low <= list->n); assert(low == list->n || list->labels[low].clock > clock); return low; } @@ -393,8 +394,8 @@ static void printAddr(ulongest_t clock, ulongest_t addr, const char *ident) LabelList list = tmp; size_t pos = labelFind(list, clock); if (pos > 0) { - putchar('['); ulongest_t id = list->labels[pos - 1].id; + putchar('['); if (TableLookup(&tmp, internTable, id)) printStr((char *)tmp); else From 532cd901ac8e2d1fcdaa9a2164464be5cefcd454 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Apr 2014 21:44:18 +0100 Subject: [PATCH 069/266] Avoid strict aliasing warnings from gcc 4.8. Copied from Perforce Change: 185484 ServerID: perforce.ravenbrook.com --- mps/code/event.c | 2 +- mps/code/prmci3xc.c | 18 +++++++++--------- mps/code/protxc.c | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mps/code/event.c b/mps/code/event.c index d2166dbba2d..475fa4f875c 100644 --- a/mps/code/event.c +++ b/mps/code/event.c @@ -422,7 +422,7 @@ void EventDump(mps_lib_FILE *stream) for (kind = 0; kind < EventKindLIMIT; ++kind) { for (event = (Event)EventLast[kind]; - event < (Event)(EventBuffer[kind] + EventBufferSIZE); + (char *)event < EventBuffer[kind] + EventBufferSIZE; event = (Event)((char *)event + event->any.size)) { /* Try to keep going even if there's an error, because this is used as a backtrace and we'll take what we can get. */ diff --git a/mps/code/prmci3xc.c b/mps/code/prmci3xc.c index 786145fc084..1fcf5b149df 100644 --- a/mps/code/prmci3xc.c +++ b/mps/code/prmci3xc.c @@ -44,17 +44,17 @@ MRef Prmci3AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum) config.h. */ /* TODO: The current arrangement of the fix operation (taking a Ref *) forces us to pun these registers (actually `int` on LII3GC). We can - suppress the warning my casting through `char *` and this might make + suppress the warning by casting through `void *` and this might make it safe, but does it really? RB 2012-09-10 */ switch (regnum) { - case 0: return (MRef)((char *)&mfc->threadState->__eax); - case 1: return (MRef)((char *)&mfc->threadState->__ecx); - case 2: return (MRef)((char *)&mfc->threadState->__edx); - case 3: return (MRef)((char *)&mfc->threadState->__ebx); - case 4: return (MRef)((char *)&mfc->threadState->__esp); - case 5: return (MRef)((char *)&mfc->threadState->__ebp); - case 6: return (MRef)((char *)&mfc->threadState->__esi); - case 7: return (MRef)((char *)&mfc->threadState->__edi); + case 0: return (void *)&mfc->threadState->__eax; + case 1: return (void *)&mfc->threadState->__ecx; + case 2: return (void *)&mfc->threadState->__edx; + case 3: return (void *)&mfc->threadState->__ebx; + case 4: return (void *)&mfc->threadState->__esp; + case 5: return (void *)&mfc->threadState->__ebp; + case 6: return (void *)&mfc->threadState->__esi; + case 7: return (void *)&mfc->threadState->__edi; default: NOTREACHED; return NULL; /* Avoids compiler warning. */ diff --git a/mps/code/protxc.c b/mps/code/protxc.c index 58dee81a179..1d2ae27917c 100644 --- a/mps/code/protxc.c +++ b/mps/code/protxc.c @@ -243,7 +243,7 @@ static void protCatchOne(void) different size" warnings in GCC, for the XCI3GC build. */ mfcStruct.address = (Addr)(Word)request.code[1]; AVER(sizeof(*mfcStruct.threadState) == sizeof(THREAD_STATE_S)); - mfcStruct.threadState = (THREAD_STATE_S *)request.old_state; + mfcStruct.threadState = (void *)request.old_state; if (ArenaAccess(mfcStruct.address, AccessREAD | AccessWRITE, From 298735312584b6ded132aeaacf593fb4b72149bc Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 13 Apr 2014 20:51:10 +0100 Subject: [PATCH 070/266] Check rings before destroying the control pool, so that you get an assertion when a ring points into space that is about to be unmapped, instead of a crash after it has been unmapped. Copied from Perforce Change: 185495 ServerID: perforce.ravenbrook.com --- mps/code/global.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/mps/code/global.c b/mps/code/global.c index 9bfe9c20dc0..9fb6c1cb4eb 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -397,25 +397,7 @@ void GlobalsFinish(Globals arenaGlobals) Arena arena; Rank rank; - /* Check that the tear-down is complete: that the client has - * destroyed all data structures associated with the arena. We do - * this *before* calling AVERT(Globals, arenaGlobals) because the - * AVERT will crash if there are any remaining data structures, and - * it is politer to assert than to crash. (The crash would happen - * because by this point in the code the control pool has been - * destroyed and so the address space containing all these rings has - * potentially been unmapped, and so RingCheck dereferences a - * pointer into that unmapped memory.) See job000652. */ arena = GlobalsArena(arenaGlobals); - AVER(RingIsSingle(&arena->formatRing)); - AVER(RingIsSingle(&arena->chainRing)); - AVER(RingIsSingle(&arena->messageRing)); - AVER(RingIsSingle(&arena->threadRing)); - for(rank = 0; rank < RankLIMIT; ++rank) - AVER(RingIsSingle(&arena->greyRing[rank])); - AVER(RingIsSingle(&arenaGlobals->poolRing)); - AVER(RingIsSingle(&arenaGlobals->rootRing)); - AVERT(Globals, arenaGlobals); STATISTIC_STAT(EVENT2(ArenaWriteFaults, arena, @@ -445,6 +427,7 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) TraceId ti; Trace trace; Chain defaultChain; + Rank rank; AVERT(Globals, arenaGlobals); @@ -499,6 +482,23 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) arena->finalPool = NULL; PoolDestroy(pool); } + + /* 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 + * is called, the control pool has been destroyed and so the address + * space containing all these rings has potentially been unmapped, + * and so RingCheck dereferences a pointer into that unmapped memory + * and we get a crash instead of an assertion. See job000652. + */ + AVER(RingIsSingle(&arena->formatRing)); + AVER(RingIsSingle(&arena->chainRing)); + AVER(RingIsSingle(&arena->messageRing)); + AVER(RingIsSingle(&arena->threadRing)); + AVER(RingIsSingle(&arenaGlobals->rootRing)); + for(rank = 0; rank < RankLIMIT; ++rank) + AVER(RingIsSingle(&arena->greyRing[rank])); + /* poolRing is not yet single (control pool etc. still exist) */ } From 339cc8e3644047e966c17f42c0897d7e35a7105a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 14 Apr 2014 11:34:20 +0100 Subject: [PATCH 071/266] Simpler casting and more checking. Copied from Perforce Change: 185502 ServerID: perforce.ravenbrook.com --- mps/code/prmci6xc.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/mps/code/prmci6xc.c b/mps/code/prmci6xc.c index 02ccb840b6c..131447cd0cc 100644 --- a/mps/code/prmci6xc.c +++ b/mps/code/prmci6xc.c @@ -31,33 +31,38 @@ SRCID(prmci6li, "$Id$"); MRef Prmci6AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum) { + THREAD_STATE_S *threadState; + + AVER(mfc != NULL); AVER(NONNEGATIVE(regnum)); AVER(regnum <= 15); + AVER(mfc->threadState != NULL); + threadState = mfc->threadState; /* .assume.regref */ /* The register numbers (REG_RAX etc.) are defined in but only if _XOPEN_SOURCE is defined: see .feature.xc in config.h. */ /* MRef (a Word *) is not compatible with pointers to the register - types (actually a __uint64_t). To avoid aliasing optimization - problems, The registers are cast through (char *) */ + types (actually a __uint64_t). To avoid aliasing optimization + problems, the registers are cast through (void *). */ switch (regnum) { - case 0: return (MRef)((char *)&mfc->threadState->__rax); - case 1: return (MRef)((char *)&mfc->threadState->__rcx); - case 2: return (MRef)((char *)&mfc->threadState->__rdx); - case 3: return (MRef)((char *)&mfc->threadState->__rbx); - case 4: return (MRef)((char *)&mfc->threadState->__rsp); - case 5: return (MRef)((char *)&mfc->threadState->__rbp); - case 6: return (MRef)((char *)&mfc->threadState->__rsi); - case 7: return (MRef)((char *)&mfc->threadState->__rdi); - case 8: return (MRef)((char *)&mfc->threadState->__r8); - case 9: return (MRef)((char *)&mfc->threadState->__r9); - case 10: return (MRef)((char *)&mfc->threadState->__r10); - case 11: return (MRef)((char *)&mfc->threadState->__r11); - case 12: return (MRef)((char *)&mfc->threadState->__r12); - case 13: return (MRef)((char *)&mfc->threadState->__r13); - case 14: return (MRef)((char *)&mfc->threadState->__r14); - case 15: return (MRef)((char *)&mfc->threadState->__r15); + case 0: return (void *)&threadState->__rax; + case 1: return (void *)&threadState->__rcx; + case 2: return (void *)&threadState->__rdx; + case 3: return (void *)&threadState->__rbx; + case 4: return (void *)&threadState->__rsp; + case 5: return (void *)&threadState->__rbp; + case 6: return (void *)&threadState->__rsi; + case 7: return (void *)&threadState->__rdi; + case 8: return (void *)&threadState->__r8; + case 9: return (void *)&threadState->__r9; + case 10: return (void *)&threadState->__r10; + case 11: return (void *)&threadState->__r11; + case 12: return (void *)&threadState->__r12; + case 13: return (void *)&threadState->__r13; + case 14: return (void *)&threadState->__r14; + case 15: return (void *)&threadState->__r15; default: NOTREACHED; return NULL; /* Avoids compiler warning. */ From da2a61ae243f561ccae5ed2ab4c025552af1a50e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 14 Apr 2014 12:07:14 +0100 Subject: [PATCH 072/266] Simpler casting, and more checking. Copied from Perforce Change: 185505 ServerID: perforce.ravenbrook.com --- mps/code/prmci6li.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mps/code/prmci6li.c b/mps/code/prmci6li.c index 2f8bf9afc62..c00c1359014 100644 --- a/mps/code/prmci6li.c +++ b/mps/code/prmci6li.c @@ -33,12 +33,19 @@ SRCID(prmci6li, "$Id$"); MRef Prmci6AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum) { - Word *gregs; + MRef gregs; + AVER(mfc != NULL); AVER(NONNEGATIVE(regnum)); AVER(regnum <= 15); + AVER(mfc->ucontext != NULL); - gregs = (Word *)&mfc->ucontext->uc_mcontext.gregs; + /* TODO: The current arrangement of the fix operation (taking a Ref *) + forces us to pun these registers (actually `int` on LII6GC). We can + suppress the warning by casting through `void *` and this might make + it safe, but does it really? RB 2012-09-10 */ + AVER(sizeof(void *) == sizeof(*mfc->ucontext->uc_mcontext.gregs)); + gregs = (void *)mfc->ucontext->uc_mcontext.gregs; /* .assume.regref */ /* The register numbers (REG_RAX etc.) are defined in From 97f6f2565508728a4d2aa2fa73792c01e62bd11b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 14 Apr 2014 12:13:22 +0100 Subject: [PATCH 073/266] Avoid warning on lii3gc. Copied from Perforce Change: 185506 ServerID: perforce.ravenbrook.com --- mps/code/finaltest.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mps/code/finaltest.c b/mps/code/finaltest.c index 02c1448d137..88895027286 100644 --- a/mps/code/finaltest.c +++ b/mps/code/finaltest.c @@ -167,7 +167,8 @@ static void test_trees(const char *name, mps_arena_t arena, mps_ap_t ap, } finals += final_this_time; printf("%"PRIuLONGEST" objects finalized: total %"PRIuLONGEST - " of %"PRIuLONGEST"\n", final_this_time, finals, object_count); + " of %"PRIuLONGEST"\n", (ulongest_t)final_this_time, + (ulongest_t)finals, (ulongest_t)object_count); } cdie(finals == object_count, "Not all objects were finalized."); } From e2c67f1bb7c8de9252bb1a60124a79386be55131 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 14 Apr 2014 12:13:31 +0100 Subject: [PATCH 074/266] Simpler cast, more checking. Copied from Perforce Change: 185507 ServerID: perforce.ravenbrook.com --- mps/code/prmci3li.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/mps/code/prmci3li.c b/mps/code/prmci3li.c index 6a36ae7db2b..5b5d150b8cc 100644 --- a/mps/code/prmci3li.c +++ b/mps/code/prmci3li.c @@ -36,27 +36,34 @@ SRCID(prmci3li, "$Id$"); MRef Prmci3AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum) { + MRef gregs; + + AVER(mfc != NULL); AVER(NONNEGATIVE(regnum)); AVER(regnum <= 7); + AVER(mfc->ucontext != NULL); + + /* TODO: The current arrangement of the fix operation (taking a Ref *) + forces us to pun these registers (actually `int` on LII3GC). We can + suppress the warning by casting through `void *` and this might make + it safe, but does it really? RB 2012-09-10 */ + AVER(sizeof(void *) == sizeof(*mfc->ucontext->uc_mcontext.gregs)); + gregs = (void *)mfc->ucontext->uc_mcontext.gregs; /* .source.i486 */ /* .assume.regref */ /* The register numbers (REG_EAX etc.) are defined in but only if _GNU_SOURCE is defined: see .feature.li in config.h. */ - /* TODO: The current arrangement of the fix operation (taking a Ref *) - forces us to pun these registers (actually `int` on LII3GC). We can - suppress the warning my casting through `char *` and this might make - it safe, but does it really? RB 2012-09-10 */ switch (regnum) { - case 0: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_EAX]); - case 1: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_ECX]); - case 2: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_EDX]); - case 3: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_EBX]); - case 4: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_ESP]); - case 5: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_EBP]); - case 6: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_ESI]); - case 7: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_EDI]); + case 0: return &gregs[REG_EAX]; + case 1: return &gregs[REG_ECX]; + case 2: return &gregs[REG_EDX]; + case 3: return &gregs[REG_EBX]; + case 4: return &gregs[REG_ESP]; + case 5: return &gregs[REG_EBP]; + case 6: return &gregs[REG_ESI]; + case 7: return &gregs[REG_EDI]; default: NOTREACHED; return NULL; /* Avoids compiler warning. */ From 113f2ff5d08c3ee384001e35187b9f31d3cd8c25 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 14 Apr 2014 12:32:18 +0100 Subject: [PATCH 075/266] Simpler cast, more checking. Copied from Perforce Change: 185510 ServerID: perforce.ravenbrook.com --- mps/code/prmci3xc.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/mps/code/prmci3xc.c b/mps/code/prmci3xc.c index 1fcf5b149df..eafeff61540 100644 --- a/mps/code/prmci3xc.c +++ b/mps/code/prmci3xc.c @@ -34,8 +34,13 @@ SRCID(prmci3li, "$Id$"); MRef Prmci3AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum) { + THREAD_STATE_S *threadState; + + AVER(mfc != NULL); AVER(NONNEGATIVE(regnum)); AVER(regnum <= 7); + AVER(mfc->threadState != NULL); + threadState = mfc->threadState; /* .source.i486 */ /* .assume.regref */ @@ -47,14 +52,14 @@ MRef Prmci3AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum) suppress the warning by casting through `void *` and this might make it safe, but does it really? RB 2012-09-10 */ switch (regnum) { - case 0: return (void *)&mfc->threadState->__eax; - case 1: return (void *)&mfc->threadState->__ecx; - case 2: return (void *)&mfc->threadState->__edx; - case 3: return (void *)&mfc->threadState->__ebx; - case 4: return (void *)&mfc->threadState->__esp; - case 5: return (void *)&mfc->threadState->__ebp; - case 6: return (void *)&mfc->threadState->__esi; - case 7: return (void *)&mfc->threadState->__edi; + case 0: return (void *)&threadState->__eax; + case 1: return (void *)&threadState->__ecx; + case 2: return (void *)&threadState->__edx; + case 3: return (void *)&threadState->__ebx; + case 4: return (void *)&threadState->__esp; + case 5: return (void *)&threadState->__ebp; + case 6: return (void *)&threadState->__esi; + case 7: return (void *)&threadState->__edi; default: NOTREACHED; return NULL; /* Avoids compiler warning. */ From f6eb7789ac1699422c36d9aada8983bad80a3c72 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 14 Apr 2014 16:39:55 +0100 Subject: [PATCH 076/266] New program p4-bisect finds, by binary search, the change that introduced a bug. Copied from Perforce Change: 185519 ServerID: perforce.ravenbrook.com --- mps/tool/p4-bisect | 155 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 mps/tool/p4-bisect diff --git a/mps/tool/p4-bisect b/mps/tool/p4-bisect new file mode 100644 index 00000000000..768b2ba6f0b --- /dev/null +++ b/mps/tool/p4-bisect @@ -0,0 +1,155 @@ +#!/usr/bin/env python +# +# +# Ravenbrook +# +# +# P4-BISECT -- FIND CHANGE THAT INTRODUCED A BUG +# +# Gareth Rees, Ravenbrook Limited, 2014-04-14 +# +# +# 1. INTRODUCTION +# +# This script automates (or partly automates) the process of finding, +# by binary search, the change that introduced a bug. +# +# The interface is modelled closely on git-bisect(1). + +import argparse +from functools import partial +import json +from os import unlink +import p4 +import subprocess +import sys + +BISECT_FILE = '.p4-bisect' + +class State(object): + def __init__(self, **d): + self.filespec = d['filespec'] + self.changes = d['changes'] + if 'current' in d: + self.current = d['current'] + + @classmethod + def load(cls): + with open(BISECT_FILE, 'r') as f: + return cls(**json.load(f)) + + def save(self): + with open(BISECT_FILE, 'w') as f: + json.dump(vars(self), f) + + def update(self): + n = len(self.changes) + if n == 0: + print("no changes remaining.".format(**vars(self))) + elif n == 1: + print("{} change remaining: {}.".format(n, self.changes[0])) + elif n == 2: + print("{} changes remaining: [{}, {}]." + .format(n, self.changes[0], self.changes[-1])) + else: + print("{} changes remaining: [{}, ..., {}]." + .format(n, self.changes[0], self.changes[-1])) + if n > 0: + self.current = self.changes[n // 2] + print("Syncing to changelevel {current}.".format(**vars(self))) + p4.do('update', '{filespec}@{current}'.format(**vars(self))) + self.save() + +def help(parser, args): + parser.print_help() + +def start(args): + changes = sorted(int(c['change']) for c in p4.run('changes', args.filespec)) + if not changes: + parser.error("No changes for {filespec}".format(**vars(args))) + if args.first is None: + args.first = changes[0] + if args.last is None: + args.last = changes[-1] + state = State(filespec=args.filespec, + changes=[c for c in changes if args.first <= c <= args.last]) + state.update() + +def good(args): + state = State.load() + print("Change {current} good.".format(**vars(state))) + state.changes = [c for c in state.changes if c > state.current] + state.update() + +def bad(args): + state = State.load() + print("Change {current} bad.".format(**vars(state))) + state.changes = [c for c in state.changes if c < state.current] + state.update() + +def skip(args): + state = State.load() + print("Skipping change {current}.".format(**vars(state))) + state.changes.remove(state.current) + state.update() + +def reset(args): + state = State.load() + p4.do('update', state.filespec) + unlink(BISECT_FILE) + +def run(args): + while True: + state = State.load() + if not state.changes: + break + result = subprocess.call([args.cmd] + args.args) + if result == 0: + good(None) + elif result == 125: + skip(None) + elif 0 < result < 128: + bad(None) + else: + exit(result) + +def main(argv): + parser = argparse.ArgumentParser(prog='p4-bisect') + subparsers = parser.add_subparsers() + a = subparsers.add_parser + + help_parser = a('help', help='show this help message') + help_parser.set_defaults(func=partial(help, help_parser)) + + start_parser = a('start', help='start a p4-bisect session') + aa = start_parser.add_argument + start_parser.add_argument('-f', '--filespec', default='...', + help='filespec to search') + start_parser.add_argument('first', nargs='?', type=int, + help='earliest changelevel to examine') + start_parser.add_argument('last', nargs='?', type=int, + help='latest changelevel to examine') + start_parser.set_defaults(func=start) + + good_parser = a('good', help='declare current revision good') + good_parser.set_defaults(func=good) + + bad_parser = a('bad', help='declare current revision bad') + bad_parser.set_defaults(func=bad) + + reset_parser = a('reset', help='finish p4-bisect session') + reset_parser.set_defaults(func=reset) + + run_parser = a('run', help='run p4-bisect session automatically') + run_parser.add_argument('cmd', + help='command that determines if current ' + 'changelevel is good or bad') + run_parser.add_argument('args', nargs=argparse.REMAINDER, + help='arguments to pass to cmd') + run_parser.set_defaults(func=run) + + args = parser.parse_args(argv[1:]) + args.func(args) + +if __name__ == '__main__': + main(sys.argv) From a3708e5cc22e461b28947bbcfc3cb960f6e802b4 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 14 Apr 2014 17:50:27 +0100 Subject: [PATCH 077/266] Update open dylan configuration procedure. Copied from Perforce Change: 185521 ServerID: perforce.ravenbrook.com --- mps/tool/testopendylan | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mps/tool/testopendylan b/mps/tool/testopendylan index 9c18938ef1e..a8aee4a0025 100755 --- a/mps/tool/testopendylan +++ b/mps/tool/testopendylan @@ -104,7 +104,7 @@ if [ -f "$REPO/Makefile" ]; then else ( cd -- "$REPO" && ./autogen.sh && - ./configure --with-mps="$MPS" --prefix="$PREFIX" + ./configure --with-gc=mps --with-gc-path="$MPS" --prefix="$PREFIX" ) fi ( cd -- "$REPO" && @@ -128,6 +128,9 @@ else ( # # 2014-03-20 GDR Created based on [WELCOME]. # +# 2014-04-14 GDR Updated configure args based on revised build +# instructions [WELCOME]. +# # # C. COPYRIGHT AND LICENCE # From 27aab674972b60c3bb994c8d66fe97b6e373e617 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 14 Apr 2014 17:53:49 +0100 Subject: [PATCH 078/266] Fix branch tool (missing quote). Copied from Perforce Change: 185522 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 faf69ffb0bc..686cdefa244 100755 --- a/mps/tool/branch +++ b/mps/tool/branch @@ -162,7 +162,7 @@ def main(argv): args.description = fmt("Branching {parent} to {child}.") print(fmt("description={description}")) args.desc_html = re.sub(r'\b(job\d{6})\b', - fmt(r'\1'), args.description) # Create the branch specification From 06ea755daf1ae5aa25f8fe95b61cff87d9331f32 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 14 Apr 2014 18:37:31 +0100 Subject: [PATCH 079/266] Move the marker down the stack so that gcc's aggressive inline won't scupper it. Copied from Perforce Change: 185524 ServerID: perforce.ravenbrook.com --- mps/code/airtest.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mps/code/airtest.c b/mps/code/airtest.c index 946e585bc2f..56e1bd8c129 100644 --- a/mps/code/airtest.c +++ b/mps/code/airtest.c @@ -90,14 +90,13 @@ static mps_gen_param_s obj_gen_params[] = { { 170, 0.45 } }; -static void test_main(int interior, int stack) +static void test_main(void *marker, int interior, int stack) { mps_res_t res; mps_chain_t obj_chain; mps_fmt_t obj_fmt; mps_thr_t thread; mps_root_t reg_root = NULL; - void *marker = ▮ res = mps_arena_create_k(&scheme_arena, mps_arena_class_vm(), mps_args_none); if (res != MPS_RES_OK) error("Couldn't create arena"); @@ -145,12 +144,14 @@ static void test_main(int interior, int stack) int main(int argc, char *argv[]) { + void *marker = ▮ + testlib_init(argc, argv); - test_main(TRUE, TRUE); - test_main(TRUE, FALSE); - /* not test_main(FALSE, TRUE) -- see .fail.lii6ll. */ - test_main(FALSE, FALSE); + test_main(marker, TRUE, TRUE); + test_main(marker, TRUE, FALSE); + /* not test_main(marker, FALSE, TRUE) -- see .fail.lii6ll. */ + test_main(marker, FALSE, FALSE); printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); return 0; From e425fc00ecb3b66671512132d13e1281cf32bda8 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 14 Apr 2014 18:55:00 +0100 Subject: [PATCH 080/266] Update file type to kxtext. Copied from Perforce Change: 185525 ServerID: perforce.ravenbrook.com --- mps/tool/p4-bisect | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 mps/tool/p4-bisect diff --git a/mps/tool/p4-bisect b/mps/tool/p4-bisect old mode 100644 new mode 100755 From 4e48a196e56f9b6a81924e99a0d00c2dc71dbf01 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 14 Apr 2014 22:31:24 +0100 Subject: [PATCH 081/266] Check the poolring so that there is an assertion failure (not a crash) if the client fails to destroy a pool. Copied from Perforce Change: 185527 ServerID: perforce.ravenbrook.com --- mps/code/global.c | 10 +++++++++- mps/code/ring.c | 14 ++++++++++++-- mps/code/ring.h | 5 +++-- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/mps/code/global.c b/mps/code/global.c index 9fb6c1cb4eb..5f635206bd9 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -498,7 +498,15 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) AVER(RingIsSingle(&arenaGlobals->rootRing)); for(rank = 0; rank < RankLIMIT; ++rank) AVER(RingIsSingle(&arena->greyRing[rank])); - /* poolRing is not yet single (control pool etc. still exist) */ + + /* 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 + */ + AVER(RingLength(&arenaGlobals->poolRing) == 5); } diff --git a/mps/code/ring.c b/mps/code/ring.c index ff60149ce40..54902ec3818 100644 --- a/mps/code/ring.c +++ b/mps/code/ring.c @@ -1,7 +1,7 @@ /* ring.c: RING IMPLEMENTATION * * $Id$ - * Copyright (c) 2001,2003 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .intro: This is a portable implementation of Rings. * @@ -52,6 +52,16 @@ Bool RingIsSingle(Ring ring) return (ring->next == ring); } +Size RingLength(Ring ring) +{ + Size size = 0; + Ring node, next; + AVERT(Ring, ring); + RING_FOR(node, ring, next) + ++ size; + return size; +} + /* RingInit -- initialize a ring node */ @@ -131,7 +141,7 @@ Ring (RingPrev)(Ring ring) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2003 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/ring.h b/mps/code/ring.h index d5b64076f6c..cbde6afe814 100644 --- a/mps/code/ring.h +++ b/mps/code/ring.h @@ -1,7 +1,7 @@ /* ring.h: RING INTERFACE * * $Id$ - * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2001 Global Graphics Software. */ @@ -30,6 +30,7 @@ typedef struct RingStruct { /* double-ended queue structure */ extern Bool RingCheck(Ring ring); extern Bool RingCheckSingle(Ring ring); extern Bool RingIsSingle(Ring ring); +extern Size RingLength(Ring ring); /* .ring.init: */ extern void (RingInit)(Ring ring); @@ -115,7 +116,7 @@ extern Ring (RingPrev)(Ring ring); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2013 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From 72ba071b4cb2a787e071f5357e42b38180ba4406 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 14 Apr 2014 23:38:54 +0100 Subject: [PATCH 082/266] Fix arenarootswalk: 1. Blacken the segments again after scanning the roots, so that the roots can be walked again. 2. Don't cast RootGrey to a RootIterateFn -- the types are not compatible. MMQA test function/122.c now passes. Copied from Perforce Change: 185530 ServerID: perforce.ravenbrook.com --- mps/code/walk.c | 26 +++++++++++++++++++++++++- mps/test/function/122.c | 2 +- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/mps/code/walk.c b/mps/code/walk.c index 3f7f67f99e1..4dd0d6b9e98 100644 --- a/mps/code/walk.c +++ b/mps/code/walk.c @@ -273,6 +273,20 @@ static Res rootWalk(Root root, void *p) } +/* rootWalkGrey -- make the root grey for the trace passed as p */ + +static Res rootWalkGrey(Root root, void *p) +{ + Trace trace = p; + + AVERT(Root, root); + AVERT(Trace, trace); + + RootGrey(root, trace); + return ResOK; +} + + /* ArenaRootsWalk -- walks all the root in the arena */ static Res ArenaRootsWalk(Globals arenaGlobals, mps_roots_stepper_t f, @@ -315,7 +329,7 @@ static Res ArenaRootsWalk(Globals arenaGlobals, mps_roots_stepper_t f, } /* Make the roots grey so that they are scanned */ - res = RootsIterate(arenaGlobals, (RootIterateFn)RootGrey, (void *)trace); + res = RootsIterate(arenaGlobals, rootWalkGrey, trace); /* Make this trace look like any other trace. */ arena->flippedTraces = TraceSetAdd(arena->flippedTraces, trace); @@ -330,6 +344,16 @@ static Res ArenaRootsWalk(Globals arenaGlobals, mps_roots_stepper_t f, break; } + /* Turn segments black again. */ + if (SegFirst(&seg, arena)) { + do { + if (PoolHasAttr(SegPool(seg), AttrGC)) { + SegSetGrey(seg, TraceSetDel(SegGrey(seg), trace)); + SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace)); + } + } while (SegNext(&seg, arena, seg)); + } + rootsStepClosureFinish(rsc); /* Make this trace look like any other finished trace. */ trace->state = TraceFINISHED; diff --git a/mps/test/function/122.c b/mps/test/function/122.c index 6f1465289cb..4ba0c0c6090 100644 --- a/mps/test/function/122.c +++ b/mps/test/function/122.c @@ -133,7 +133,7 @@ static void test(void) die(allocrdumb(&a[0], aplo, 64, mps_rank_exact()), "alloc"); die(allocrdumb(&a[1], apamc, 64, mps_rank_exact()), "alloc"); die(allocrdumb(&a[3], apawl, 64, mps_rank_exact()), "alloc"); - a[2] = (mycell *)((int)a[3] | 4); + a[2] = (mycell *)((mps_word_t)a[3] | 4); die(allocrdumb(&b[0], aplo, 64, mps_rank_exact()), "alloc"); die(allocrdumb(&b[1], apamc, 64, mps_rank_exact()), "alloc"); From cd1e68813ce7a39e46945eed6afd043aaddcb8af Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 15 Apr 2014 00:18:29 +0100 Subject: [PATCH 083/266] Update passing list and release notes to reflect job003496 fix. Copied from Perforce Change: 185533 ServerID: perforce.ravenbrook.com --- mps/manual/source/release.rst | 5 +++++ mps/test/testsets/passing | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 4a57665a23b..18cc8ed72e9 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -47,6 +47,11 @@ Other changes .. _job001549: https://www.ravenbrook.com/project/mps/issue/job001549/ +#. :c:func:`mps_arena_roots_walk` no longer triggers an assertion + failure when run twice in succession. See job003496_. + + .. _job003496: https://www.ravenbrook.com/project/mps/issue/job003496/ + #. The alignment of :ref:`pool-awl` pools is now configurable via the object format, as documented, and is no longer always :c:macro:`MPS_PF_ALIGN`. See job003745_. diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index 64c72fe2982..fc00f37feb0 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -110,7 +110,7 @@ function/118.c function/119.c function/120.c % function/121.c -- job003495 -% function/122.c -- job003496 +function/122.c function/123.c function/124.c function/125.c From 680956c4ea00c0a568954ba9455ddc1ab5d27770 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 15 Apr 2014 00:18:47 +0100 Subject: [PATCH 084/266] Avoid bad cast on 64-bit. Copied from Perforce Change: 185534 ServerID: perforce.ravenbrook.com --- mps/test/function/40.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/test/function/40.c b/mps/test/function/40.c index c57f8c62ba5..5257e1fcfc1 100644 --- a/mps/test/function/40.c +++ b/mps/test/function/40.c @@ -66,7 +66,7 @@ static void test(void) comment("%i of 10.", i); UC; z[i] = allocone(ap, 1, 1); - if (i % 8 == 0) { z[i] = (mycell *) ((int)z[i] + 4); } /* error to scan this! */ + if (i % 8 == 0) { z[i] = (mycell *) ((mps_word_t)z[i] + 4); } /* error to scan this! */ } for (i=0; i<1000; i++) { From 7aff0aedca414525f5ffeb38683c1a3a29576b76 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 15 Apr 2014 09:21:01 +0100 Subject: [PATCH 085/266] P4-bisect improvements: Add skip command. Allow multiple -f options. Better error messages. Copied from Perforce Change: 185536 ServerID: perforce.ravenbrook.com --- mps/tool/p4-bisect | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/mps/tool/p4-bisect b/mps/tool/p4-bisect index 768b2ba6f0b..85c1c8e151e 100755 --- a/mps/tool/p4-bisect +++ b/mps/tool/p4-bisect @@ -26,6 +26,11 @@ import sys BISECT_FILE = '.p4-bisect' +def error(msg): + sys.stderr.write(msg) + sys.stderr.write('\n') + exit(1) + class State(object): def __init__(self, **d): self.filespec = d['filespec'] @@ -35,8 +40,11 @@ class State(object): @classmethod def load(cls): - with open(BISECT_FILE, 'r') as f: - return cls(**json.load(f)) + try: + with open(BISECT_FILE, 'r') as f: + return cls(**json.load(f)) + except FileNotFoundError: + error("p4-bisect not in progress here.") def save(self): with open(BISECT_FILE, 'w') as f: @@ -57,16 +65,18 @@ class State(object): if n > 0: self.current = self.changes[n // 2] print("Syncing to changelevel {current}.".format(**vars(self))) - p4.do('update', '{filespec}@{current}'.format(**vars(self))) + p4.do('sync', *['{}@{}'.format(f, self.current) + for f in self.filespec]) self.save() def help(parser, args): parser.print_help() def start(args): - changes = sorted(int(c['change']) for c in p4.run('changes', args.filespec)) + args.filespec = args.filespec or ['...'] + changes = sorted(int(c['change']) for c in p4.run('changes', *args.filespec)) if not changes: - parser.error("No changes for {filespec}".format(**vars(args))) + error("No changes for {}".format(' '.join(args.filespec))) if args.first is None: args.first = changes[0] if args.last is None: @@ -95,7 +105,7 @@ def skip(args): def reset(args): state = State.load() - p4.do('update', state.filespec) + p4.do('sync', *state.filespec) unlink(BISECT_FILE) def run(args): @@ -119,11 +129,11 @@ def main(argv): a = subparsers.add_parser help_parser = a('help', help='show this help message') - help_parser.set_defaults(func=partial(help, help_parser)) + help_parser.set_defaults(func=partial(help, parser)) start_parser = a('start', help='start a p4-bisect session') aa = start_parser.add_argument - start_parser.add_argument('-f', '--filespec', default='...', + start_parser.add_argument('-f', '--filespec', action='append', help='filespec to search') start_parser.add_argument('first', nargs='?', type=int, help='earliest changelevel to examine') @@ -137,6 +147,9 @@ def main(argv): bad_parser = a('bad', help='declare current revision bad') bad_parser.set_defaults(func=bad) + skip_parser = a('skip', help='skip current revision') + skip_parser.set_defaults(func=skip) + reset_parser = a('reset', help='finish p4-bisect session') reset_parser.set_defaults(func=reset) From 536998d9d6ca2b219034ec8033937ab5079b8ec2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 15 Apr 2014 09:30:09 +0100 Subject: [PATCH 086/266] Better handling of "file(s) up-to-date" error. Copied from Perforce Change: 185537 ServerID: perforce.ravenbrook.com --- mps/tool/p4-bisect | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/mps/tool/p4-bisect b/mps/tool/p4-bisect index 85c1c8e151e..97ff39dad74 100755 --- a/mps/tool/p4-bisect +++ b/mps/tool/p4-bisect @@ -31,6 +31,13 @@ def error(msg): sys.stderr.write('\n') exit(1) +def sync(*filespecs): + try: + p4.do('sync', *filespecs) + except p4.Error as e: + if 'file(s) up-to-date' not in e.args[0]: + raise + class State(object): def __init__(self, **d): self.filespec = d['filespec'] @@ -65,8 +72,7 @@ class State(object): if n > 0: self.current = self.changes[n // 2] print("Syncing to changelevel {current}.".format(**vars(self))) - p4.do('sync', *['{}@{}'.format(f, self.current) - for f in self.filespec]) + sync(*['{}@{}'.format(f, self.current) for f in self.filespec]) self.save() def help(parser, args): @@ -105,7 +111,7 @@ def skip(args): def reset(args): state = State.load() - p4.do('sync', *state.filespec) + sync(*state.filespec) unlink(BISECT_FILE) def run(args): From 062fd078132f8b119a2d26a840ba0699fbd6f6e4 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 15 Apr 2014 10:39:52 +0100 Subject: [PATCH 087/266] Branching master to branch/2014-04-15/shared. Copied from Perforce Change: 185539 ServerID: perforce.ravenbrook.com From 992ab111d6414164e0b49412e84b8f19785bad7e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 15 Apr 2014 11:02:05 +0100 Subject: [PATCH 088/266] Build and install a shared library on unix platforms. Copied from Perforce Change: 185543 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 6 +- mps/code/comm.gmk | 20 ++-- mps/code/mps.xcodeproj/project.pbxproj | 153 +++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 10 deletions(-) diff --git a/mps/Makefile.in b/mps/Makefile.in index 2d558588673..ccc56ff2bd4 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -1,7 +1,7 @@ # Makefile.in -- source for autoconf Makefile # # $Id$ -# Copyright (C) 2012-2013 Ravenbrook Limited. See end of file for license. +# Copyright (C) 2012-2014 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. @@ -30,7 +30,9 @@ clean-make-build: install-make-build: make-install-dirs build-via-make $(INSTALL_DATA) code/mps*.h $(prefix)/include/ $(INSTALL_DATA) code/$(MPS_TARGET_NAME)/cool/mps.a $(prefix)/lib/libmps-debug.a + $(INSTALL_DATA) code/$(MPS_TARGET_NAME)/cool/libmps.so $(prefix)/lib/libmps-debug.so $(INSTALL_DATA) code/$(MPS_TARGET_NAME)/hot/mps.a $(prefix)/lib/libmps.a + $(INSTALL_DATA) code/$(MPS_TARGET_NAME)/hot/libmps.so $(prefix)/lib/libmps.so $(INSTALL_PROGRAM) $(addprefix code/$(MPS_TARGET_NAME)/hot/Release/,$(EXTRA_TARGETS)) $(prefix)/bin build-via-xcode: @@ -44,7 +46,9 @@ clean-xcode-build: install-xcode-build: make-install-dirs build-via-xcode $(INSTALL_DATA) code/mps*.h $(prefix)/include/ $(INSTALL_DATA) code/xc/Debug/libmps.a $(prefix)/lib/libmps-debug.a + $(INSTALL_DATA) code/xc/Debug/libmps.dylib $(prefix)/lib/libmps-debug.dylib $(INSTALL_DATA) code/xc/Release/libmps.a $(prefix)/lib/libmps.a + $(INSTALL_DATA) code/xc/Release/libmps.dylib $(prefix)/lib/libmps.dylib $(INSTALL_PROGRAM) $(addprefix code/xc/Release/,$(EXTRA_TARGETS)) $(prefix)/bin Makefile: Makefile.in config.status diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index 70fed15d507..ce46bba68f4 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -170,7 +170,7 @@ MPMCOMMON = abq.c arena.c arenacl.c arenavm.c arg.c boot.c bt.c \ global.c ld.c locus.c message.c meter.c mpm.c mpsi.c nailboard.c \ pool.c poolabs.c poolmfs.c poolmrg.c poolmv.c protocol.c range.c \ ref.c reserv.c ring.c root.c sa.c sac.c seg.c shield.c splay.c ss.c \ - table.c trace.c traceanc.c tract.c tree.c walk.c + table.c trace.c traceanc.c tract.c tree.c version.c walk.c MPM = $(MPMCOMMON) $(MPMPF) @@ -223,7 +223,7 @@ endif # %%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.a mpsplan.a +LIB_TARGETS=mps.a libmps.so # Test executables go in TEST_TARGETS. @@ -352,10 +352,10 @@ endif # %%VARIETY: When adding a new variety, add a rule for how to build the # MPS library for the variety. -$(PFM)/rash/mps.a: $(PFM)/rash/mps.o -$(PFM)/hot/mps.a: $(PFM)/hot/mps.o +$(PFM)/rash/libmps.so $(PFM)/rash/mps.a: $(PFM)/rash/mps.o +$(PFM)/hot/libmps.so $(PFM)/hot/mps.a: $(PFM)/hot/mps.o -$(PFM)/cool/mps.a: \ +$(PFM)/cool/libmps.so $(PFM)/cool/mps.a: \ $(MPMOBJ) $(AMCOBJ) $(AMSOBJ) $(AWLOBJ) $(LOOBJ) $(SNCOBJ) \ $(MV2OBJ) $(MVFFOBJ) $(PLINTHOBJ) $(POOLNOBJ) @@ -508,8 +508,6 @@ $(PFM)/$(VARIETY)/replay: $(PFM)/$(VARIETY)/replay.o \ $(PFM)/$(VARIETY)/table.o \ $(PFM)/$(VARIETY)/mps.a -$(PFM)/$(VARIETY)/mpsplan.a: $(PLINTHOBJ) - endif @@ -604,10 +602,14 @@ endif $(PFM)/$(VARIETY)/%.a: $(ECHO) "$(PFM): $@" rm -f $@ - $(CC) $(CFLAGS) -c -o $(PFM)/$(VARIETY)/version.o version.c - $(AR) $(ARFLAGS) $@ $^ $(PFM)/$(VARIETY)/version.o + $(AR) $(ARFLAGS) $@ $^ $(RANLIB) $@ +$(PFM)/$(VARIETY)/%.so: + $(ECHO) "$(PFM): $@" + rm -f $@ + $(CC) $(CFLAGS) $(LINKFLAGS) -shared -o $@ $^ + # Executable $(PFM)/$(VARIETY)/%: diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index 88f110bab01..b3547175c39 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -26,6 +26,7 @@ ); dependencies = ( 3104AFF6156D37BC000A585A /* PBXTargetDependency */, + 223A19AB18FD2CF300AF81C1 /* PBXTargetDependency */, 3114A644156E94FB001E0AA3 /* PBXTargetDependency */, 22FACEF1188809B5000FDBC1 /* PBXTargetDependency */, 3104AFF8156D37BE000A585A /* PBXTargetDependency */, @@ -85,6 +86,7 @@ 2231BB6118CA97DC002D6322 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; 2231BB6A18CA984F002D6322 /* locusss.c in Sources */ = {isa = PBXBuildFile; fileRef = 2231BB6918CA983C002D6322 /* locusss.c */; }; 2231BB6B18CA9861002D6322 /* locbwcss.c in Sources */ = {isa = PBXBuildFile; fileRef = 2231BB6818CA9834002D6322 /* locbwcss.c */; }; + 223A19AC18FD2D2900AF81C1 /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; }; 224CC791175E1821002FF81B /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; 224CC793175E1821002FF81B /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; 224CC79F175E321C002FF81B /* mv2test.c in Sources */ = {isa = PBXBuildFile; fileRef = 3114A686156E9674001E0AA3 /* mv2test.c */; }; @@ -315,6 +317,13 @@ remoteGlobalIDString = 2231BB5A18CA97DC002D6322; remoteInfo = locusss; }; + 223A19AA18FD2CF300AF81C1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 223A19A418FD2CE200AF81C1; + remoteInfo = "mps-shared"; + }; 224CC78E175E1821002FF81B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; @@ -1327,6 +1336,7 @@ 2231BB6718CA97DC002D6322 /* locusss */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locusss; sourceTree = BUILT_PRODUCTS_DIR; }; 2231BB6818CA9834002D6322 /* locbwcss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = locbwcss.c; sourceTree = ""; }; 2231BB6918CA983C002D6322 /* locusss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = locusss.c; sourceTree = ""; }; + 223A19A518FD2CE200AF81C1 /* libmps.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libmps.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 224CC799175E1821002FF81B /* fotest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fotest; sourceTree = BUILT_PRODUCTS_DIR; }; 224CC79E175E3202002FF81B /* fotest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fotest.c; sourceTree = ""; }; 22561A9618F4263300372C66 /* testthr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = testthr.h; sourceTree = ""; }; @@ -1652,6 +1662,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 223A19A218FD2CE200AF81C1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 224CC792175E1821002FF81B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -2266,6 +2283,7 @@ 22FACEED18880983000FDBC1 /* airtest */, 22C2ACAF18BE400A006B3677 /* nailboardtest */, 22F846BD18F437B900982BA7 /* lockut */, + 223A19A518FD2CE200AF81C1 /* libmps.dylib */, ); name = Products; sourceTree = ""; @@ -2441,6 +2459,13 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ + 223A19A318FD2CE200AF81C1 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 31EEABF9156AAF9D00714D05 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -2487,6 +2512,23 @@ productReference = 2231BB6718CA97DC002D6322 /* locusss */; productType = "com.apple.product-type.tool"; }; + 223A19A418FD2CE200AF81C1 /* mps-shared */ = { + isa = PBXNativeTarget; + buildConfigurationList = 223A19A918FD2CE300AF81C1 /* Build configuration list for PBXNativeTarget "mps-shared" */; + buildPhases = ( + 223A19A118FD2CE200AF81C1 /* Sources */, + 223A19A218FD2CE200AF81C1 /* Frameworks */, + 223A19A318FD2CE200AF81C1 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "mps-shared"; + productName = "mps-shared"; + productReference = 223A19A518FD2CE200AF81C1 /* libmps.dylib */; + productType = "com.apple.product-type.library.dynamic"; + }; 224CC78C175E1821002FF81B /* fotest */ = { isa = PBXNativeTarget; buildConfigurationList = 224CC795175E1821002FF81B /* Build configuration list for PBXNativeTarget "fotest" */; @@ -3313,6 +3355,7 @@ 3104AFF1156D37A0000A585A /* all */, 22CDE8EF16E9E97D00366D0A /* testrun */, 31EEABFA156AAF9D00714D05 /* mps */, + 223A19A418FD2CE200AF81C1 /* mps-shared */, 3114A632156E94DB001E0AA3 /* abqtest */, 22FACEE018880983000FDBC1 /* airtest */, 3124CAEA156BE7F300753214 /* amcss */, @@ -3399,6 +3442,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 223A19A118FD2CE200AF81C1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 223A19AC18FD2D2900AF81C1 /* mps.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 224CC78F175E1821002FF81B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -3896,6 +3947,11 @@ target = 2231BB5A18CA97DC002D6322 /* locusss */; targetProxy = 2231BB6E18CA986D002D6322 /* PBXContainerItemProxy */; }; + 223A19AB18FD2CF300AF81C1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 223A19A418FD2CE200AF81C1 /* mps-shared */; + targetProxy = 223A19AA18FD2CF300AF81C1 /* PBXContainerItemProxy */; + }; 224CC78D175E1821002FF81B /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 31EEABFA156AAF9D00714D05 /* mps */; @@ -4361,6 +4417,94 @@ }; name = RASH; }; + 223A19A618FD2CE200AF81C1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + EXECUTABLE_PREFIX = lib; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + MACOSX_DEPLOYMENT_TARGET = 10.9; + PRODUCT_NAME = mps; + }; + name = Debug; + }; + 223A19A718FD2CE200AF81C1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + EXECUTABLE_PREFIX = lib; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + MACOSX_DEPLOYMENT_TARGET = 10.9; + PRODUCT_NAME = mps; + }; + name = Release; + }; + 223A19A818FD2CE200AF81C1 /* RASH */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + EXECUTABLE_PREFIX = lib; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + MACOSX_DEPLOYMENT_TARGET = 10.9; + PRODUCT_NAME = mps; + }; + name = RASH; + }; 224CC796175E1821002FF81B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5577,6 +5721,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 223A19A918FD2CE300AF81C1 /* Build configuration list for PBXNativeTarget "mps-shared" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 223A19A618FD2CE200AF81C1 /* Debug */, + 223A19A718FD2CE200AF81C1 /* Release */, + 223A19A818FD2CE200AF81C1 /* RASH */, + ); + defaultConfigurationIsVisible = 0; + }; 224CC795175E1821002FF81B /* Build configuration list for PBXNativeTarget "fotest" */ = { isa = XCConfigurationList; buildConfigurations = ( From 0fef8519a615ed873a6a8857430047a6982b30e4 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 15 Apr 2014 11:13:54 +0100 Subject: [PATCH 089/266] Be clearer in the output of configure that configure/make is one way to build the mps, but alternative approaches may be better. Copied from Perforce Change: 185544 ServerID: perforce.ravenbrook.com --- mps/configure | 21 +++++++++++---------- mps/configure.ac | 3 ++- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/mps/configure b/mps/configure index e491a01208f..9b4df170d39 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.113.0. +# Generated by GNU Autoconf 2.69 for Memory Pool System Kit release/1.114.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.113.0' -PACKAGE_STRING='Memory Pool System Kit release/1.113.0' +PACKAGE_VERSION='release/1.114.0' +PACKAGE_STRING='Memory Pool System Kit release/1.114.0' PACKAGE_BUGREPORT='mps-questions@ravenbrook.com' PACKAGE_URL='http://www.ravenbrook.com/project/mps/' @@ -1243,7 +1243,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.113.0 to adapt to many kinds of systems. +\`configure' configures Memory Pool System Kit release/1.114.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1308,7 +1308,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.113.0:";; + short | recursive ) echo "Configuration of Memory Pool System Kit release/1.114.0:";; esac cat <<\_ACEOF @@ -1389,7 +1389,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -Memory Pool System Kit configure release/1.113.0 +Memory Pool System Kit configure release/1.114.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1691,7 +1691,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.113.0, which was +It was created by Memory Pool System Kit $as_me release/1.114.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4126,7 +4126,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.113.0, which was +This file was extended by Memory Pool System Kit $as_me release/1.114.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4180,7 +4180,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.113.0 +Memory Pool System Kit config.status release/1.114.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -4748,4 +4748,5 @@ $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -echo 1>&2 "CONFIGURE/MAKE IS NOT THE BEST WAY TO BUILD THE MPS -- see " +echo 1>&2 "CONFIGURE/MAKE MAY NOT BE THE BEST WAY TO BUILD THE MPS +-- see for alternative approaches" diff --git a/mps/configure.ac b/mps/configure.ac index 6ee47ca05a6..4ebb0aee578 100644 --- a/mps/configure.ac +++ b/mps/configure.ac @@ -124,4 +124,5 @@ AC_CONFIG_FILES(Makefile example/scheme/Makefile) AC_OUTPUT -echo 1>&2 "CONFIGURE/MAKE IS NOT THE BEST WAY TO BUILD THE MPS -- see " +echo 1>&2 "CONFIGURE/MAKE MAY NOT BE THE BEST WAY TO BUILD THE MPS +-- see for alternative approaches" From 82e38aaf7c912c172285dfe2ff554098bb2429a1 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 15 Apr 2014 11:15:21 +0100 Subject: [PATCH 090/266] Fix installation on linux and freebsd. Copied from Perforce Change: 185545 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 ccc56ff2bd4..7eb319c27d8 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -33,7 +33,7 @@ install-make-build: make-install-dirs build-via-make $(INSTALL_DATA) code/$(MPS_TARGET_NAME)/cool/libmps.so $(prefix)/lib/libmps-debug.so $(INSTALL_DATA) code/$(MPS_TARGET_NAME)/hot/mps.a $(prefix)/lib/libmps.a $(INSTALL_DATA) code/$(MPS_TARGET_NAME)/hot/libmps.so $(prefix)/lib/libmps.so - $(INSTALL_PROGRAM) $(addprefix code/$(MPS_TARGET_NAME)/hot/Release/,$(EXTRA_TARGETS)) $(prefix)/bin + $(INSTALL_PROGRAM) $(addprefix code/$(MPS_TARGET_NAME)/hot/,$(EXTRA_TARGETS)) $(prefix)/bin build-via-xcode: $(XCODEBUILD) -config Release From eeaf8b887a997a7cea0d4186ea824cc74e1e9fad Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 15 Apr 2014 12:39:51 +0100 Subject: [PATCH 091/266] Revert hasty merge of branch/2014-04-15/shared -- broke xcode build. Copied from Perforce Change: 185553 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 8 +- mps/code/comm.gmk | 20 ++-- mps/code/mps.xcodeproj/project.pbxproj | 153 ------------------------- mps/configure | 21 ++-- mps/configure.ac | 3 +- 5 files changed, 22 insertions(+), 183 deletions(-) diff --git a/mps/Makefile.in b/mps/Makefile.in index 7eb319c27d8..2d558588673 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-2013 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. @@ -30,10 +30,8 @@ clean-make-build: install-make-build: make-install-dirs build-via-make $(INSTALL_DATA) code/mps*.h $(prefix)/include/ $(INSTALL_DATA) code/$(MPS_TARGET_NAME)/cool/mps.a $(prefix)/lib/libmps-debug.a - $(INSTALL_DATA) code/$(MPS_TARGET_NAME)/cool/libmps.so $(prefix)/lib/libmps-debug.so $(INSTALL_DATA) code/$(MPS_TARGET_NAME)/hot/mps.a $(prefix)/lib/libmps.a - $(INSTALL_DATA) code/$(MPS_TARGET_NAME)/hot/libmps.so $(prefix)/lib/libmps.so - $(INSTALL_PROGRAM) $(addprefix code/$(MPS_TARGET_NAME)/hot/,$(EXTRA_TARGETS)) $(prefix)/bin + $(INSTALL_PROGRAM) $(addprefix code/$(MPS_TARGET_NAME)/hot/Release/,$(EXTRA_TARGETS)) $(prefix)/bin build-via-xcode: $(XCODEBUILD) -config Release @@ -46,9 +44,7 @@ clean-xcode-build: install-xcode-build: make-install-dirs build-via-xcode $(INSTALL_DATA) code/mps*.h $(prefix)/include/ $(INSTALL_DATA) code/xc/Debug/libmps.a $(prefix)/lib/libmps-debug.a - $(INSTALL_DATA) code/xc/Debug/libmps.dylib $(prefix)/lib/libmps-debug.dylib $(INSTALL_DATA) code/xc/Release/libmps.a $(prefix)/lib/libmps.a - $(INSTALL_DATA) code/xc/Release/libmps.dylib $(prefix)/lib/libmps.dylib $(INSTALL_PROGRAM) $(addprefix code/xc/Release/,$(EXTRA_TARGETS)) $(prefix)/bin Makefile: Makefile.in config.status diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index ce46bba68f4..70fed15d507 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -170,7 +170,7 @@ MPMCOMMON = abq.c arena.c arenacl.c arenavm.c arg.c boot.c bt.c \ global.c ld.c locus.c message.c meter.c mpm.c mpsi.c nailboard.c \ pool.c poolabs.c poolmfs.c poolmrg.c poolmv.c protocol.c range.c \ ref.c reserv.c ring.c root.c sa.c sac.c seg.c shield.c splay.c ss.c \ - table.c trace.c traceanc.c tract.c tree.c version.c walk.c + table.c trace.c traceanc.c tract.c tree.c walk.c MPM = $(MPMCOMMON) $(MPMPF) @@ -223,7 +223,7 @@ endif # %%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.a libmps.so +LIB_TARGETS=mps.a mpsplan.a # Test executables go in TEST_TARGETS. @@ -352,10 +352,10 @@ endif # %%VARIETY: When adding a new variety, add a rule for how to build the # MPS library for the variety. -$(PFM)/rash/libmps.so $(PFM)/rash/mps.a: $(PFM)/rash/mps.o -$(PFM)/hot/libmps.so $(PFM)/hot/mps.a: $(PFM)/hot/mps.o +$(PFM)/rash/mps.a: $(PFM)/rash/mps.o +$(PFM)/hot/mps.a: $(PFM)/hot/mps.o -$(PFM)/cool/libmps.so $(PFM)/cool/mps.a: \ +$(PFM)/cool/mps.a: \ $(MPMOBJ) $(AMCOBJ) $(AMSOBJ) $(AWLOBJ) $(LOOBJ) $(SNCOBJ) \ $(MV2OBJ) $(MVFFOBJ) $(PLINTHOBJ) $(POOLNOBJ) @@ -508,6 +508,8 @@ $(PFM)/$(VARIETY)/replay: $(PFM)/$(VARIETY)/replay.o \ $(PFM)/$(VARIETY)/table.o \ $(PFM)/$(VARIETY)/mps.a +$(PFM)/$(VARIETY)/mpsplan.a: $(PLINTHOBJ) + endif @@ -602,14 +604,10 @@ endif $(PFM)/$(VARIETY)/%.a: $(ECHO) "$(PFM): $@" rm -f $@ - $(AR) $(ARFLAGS) $@ $^ + $(CC) $(CFLAGS) -c -o $(PFM)/$(VARIETY)/version.o version.c + $(AR) $(ARFLAGS) $@ $^ $(PFM)/$(VARIETY)/version.o $(RANLIB) $@ -$(PFM)/$(VARIETY)/%.so: - $(ECHO) "$(PFM): $@" - rm -f $@ - $(CC) $(CFLAGS) $(LINKFLAGS) -shared -o $@ $^ - # Executable $(PFM)/$(VARIETY)/%: diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index b3547175c39..88f110bab01 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -26,7 +26,6 @@ ); dependencies = ( 3104AFF6156D37BC000A585A /* PBXTargetDependency */, - 223A19AB18FD2CF300AF81C1 /* PBXTargetDependency */, 3114A644156E94FB001E0AA3 /* PBXTargetDependency */, 22FACEF1188809B5000FDBC1 /* PBXTargetDependency */, 3104AFF8156D37BE000A585A /* PBXTargetDependency */, @@ -86,7 +85,6 @@ 2231BB6118CA97DC002D6322 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; 2231BB6A18CA984F002D6322 /* locusss.c in Sources */ = {isa = PBXBuildFile; fileRef = 2231BB6918CA983C002D6322 /* locusss.c */; }; 2231BB6B18CA9861002D6322 /* locbwcss.c in Sources */ = {isa = PBXBuildFile; fileRef = 2231BB6818CA9834002D6322 /* locbwcss.c */; }; - 223A19AC18FD2D2900AF81C1 /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; }; 224CC791175E1821002FF81B /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; 224CC793175E1821002FF81B /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; 224CC79F175E321C002FF81B /* mv2test.c in Sources */ = {isa = PBXBuildFile; fileRef = 3114A686156E9674001E0AA3 /* mv2test.c */; }; @@ -317,13 +315,6 @@ remoteGlobalIDString = 2231BB5A18CA97DC002D6322; remoteInfo = locusss; }; - 223A19AA18FD2CF300AF81C1 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 223A19A418FD2CE200AF81C1; - remoteInfo = "mps-shared"; - }; 224CC78E175E1821002FF81B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; @@ -1336,7 +1327,6 @@ 2231BB6718CA97DC002D6322 /* locusss */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locusss; sourceTree = BUILT_PRODUCTS_DIR; }; 2231BB6818CA9834002D6322 /* locbwcss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = locbwcss.c; sourceTree = ""; }; 2231BB6918CA983C002D6322 /* locusss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = locusss.c; sourceTree = ""; }; - 223A19A518FD2CE200AF81C1 /* libmps.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libmps.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 224CC799175E1821002FF81B /* fotest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fotest; sourceTree = BUILT_PRODUCTS_DIR; }; 224CC79E175E3202002FF81B /* fotest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fotest.c; sourceTree = ""; }; 22561A9618F4263300372C66 /* testthr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = testthr.h; sourceTree = ""; }; @@ -1662,13 +1652,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 223A19A218FD2CE200AF81C1 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 224CC792175E1821002FF81B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -2283,7 +2266,6 @@ 22FACEED18880983000FDBC1 /* airtest */, 22C2ACAF18BE400A006B3677 /* nailboardtest */, 22F846BD18F437B900982BA7 /* lockut */, - 223A19A518FD2CE200AF81C1 /* libmps.dylib */, ); name = Products; sourceTree = ""; @@ -2459,13 +2441,6 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 223A19A318FD2CE200AF81C1 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 31EEABF9156AAF9D00714D05 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -2512,23 +2487,6 @@ productReference = 2231BB6718CA97DC002D6322 /* locusss */; productType = "com.apple.product-type.tool"; }; - 223A19A418FD2CE200AF81C1 /* mps-shared */ = { - isa = PBXNativeTarget; - buildConfigurationList = 223A19A918FD2CE300AF81C1 /* Build configuration list for PBXNativeTarget "mps-shared" */; - buildPhases = ( - 223A19A118FD2CE200AF81C1 /* Sources */, - 223A19A218FD2CE200AF81C1 /* Frameworks */, - 223A19A318FD2CE200AF81C1 /* Headers */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "mps-shared"; - productName = "mps-shared"; - productReference = 223A19A518FD2CE200AF81C1 /* libmps.dylib */; - productType = "com.apple.product-type.library.dynamic"; - }; 224CC78C175E1821002FF81B /* fotest */ = { isa = PBXNativeTarget; buildConfigurationList = 224CC795175E1821002FF81B /* Build configuration list for PBXNativeTarget "fotest" */; @@ -3355,7 +3313,6 @@ 3104AFF1156D37A0000A585A /* all */, 22CDE8EF16E9E97D00366D0A /* testrun */, 31EEABFA156AAF9D00714D05 /* mps */, - 223A19A418FD2CE200AF81C1 /* mps-shared */, 3114A632156E94DB001E0AA3 /* abqtest */, 22FACEE018880983000FDBC1 /* airtest */, 3124CAEA156BE7F300753214 /* amcss */, @@ -3442,14 +3399,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 223A19A118FD2CE200AF81C1 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 223A19AC18FD2D2900AF81C1 /* mps.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 224CC78F175E1821002FF81B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -3947,11 +3896,6 @@ target = 2231BB5A18CA97DC002D6322 /* locusss */; targetProxy = 2231BB6E18CA986D002D6322 /* PBXContainerItemProxy */; }; - 223A19AB18FD2CF300AF81C1 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 223A19A418FD2CE200AF81C1 /* mps-shared */; - targetProxy = 223A19AA18FD2CF300AF81C1 /* PBXContainerItemProxy */; - }; 224CC78D175E1821002FF81B /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 31EEABFA156AAF9D00714D05 /* mps */; @@ -4417,94 +4361,6 @@ }; name = RASH; }; - 223A19A618FD2CE200AF81C1 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - EXECUTABLE_PREFIX = lib; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - MACOSX_DEPLOYMENT_TARGET = 10.9; - PRODUCT_NAME = mps; - }; - name = Debug; - }; - 223A19A718FD2CE200AF81C1 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - COPY_PHASE_STRIP = YES; - ENABLE_NS_ASSERTIONS = NO; - EXECUTABLE_PREFIX = lib; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - MACOSX_DEPLOYMENT_TARGET = 10.9; - PRODUCT_NAME = mps; - }; - name = Release; - }; - 223A19A818FD2CE200AF81C1 /* RASH */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - COPY_PHASE_STRIP = YES; - ENABLE_NS_ASSERTIONS = NO; - EXECUTABLE_PREFIX = lib; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - MACOSX_DEPLOYMENT_TARGET = 10.9; - PRODUCT_NAME = mps; - }; - name = RASH; - }; 224CC796175E1821002FF81B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5721,15 +5577,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 223A19A918FD2CE300AF81C1 /* Build configuration list for PBXNativeTarget "mps-shared" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 223A19A618FD2CE200AF81C1 /* Debug */, - 223A19A718FD2CE200AF81C1 /* Release */, - 223A19A818FD2CE200AF81C1 /* RASH */, - ); - defaultConfigurationIsVisible = 0; - }; 224CC795175E1821002FF81B /* Build configuration list for PBXNativeTarget "fotest" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/mps/configure b/mps/configure index 9b4df170d39..e491a01208f 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.113.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.113.0' +PACKAGE_STRING='Memory Pool System Kit release/1.113.0' PACKAGE_BUGREPORT='mps-questions@ravenbrook.com' PACKAGE_URL='http://www.ravenbrook.com/project/mps/' @@ -1243,7 +1243,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.113.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1308,7 +1308,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.113.0:";; esac cat <<\_ACEOF @@ -1389,7 +1389,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.113.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1691,7 +1691,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.113.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4126,7 +4126,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.113.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4180,7 +4180,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.113.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -4748,5 +4748,4 @@ $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -echo 1>&2 "CONFIGURE/MAKE MAY NOT BE THE BEST WAY TO BUILD THE MPS --- see for alternative approaches" +echo 1>&2 "CONFIGURE/MAKE IS NOT THE BEST WAY TO BUILD THE MPS -- see " diff --git a/mps/configure.ac b/mps/configure.ac index 4ebb0aee578..6ee47ca05a6 100644 --- a/mps/configure.ac +++ b/mps/configure.ac @@ -124,5 +124,4 @@ AC_CONFIG_FILES(Makefile example/scheme/Makefile) AC_OUTPUT -echo 1>&2 "CONFIGURE/MAKE MAY NOT BE THE BEST WAY TO BUILD THE MPS --- see for alternative approaches" +echo 1>&2 "CONFIGURE/MAKE IS NOT THE BEST WAY TO BUILD THE MPS -- see " From 8275bf6aceb6fedde8c86c7a4d1d904d773ecba6 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 15 Apr 2014 12:40:15 +0100 Subject: [PATCH 092/266] Ignore test objects and design images. Copied from Perforce Change: 185555 ServerID: perforce.ravenbrook.com --- mps/.p4ignore | 1 + mps/manual/source/design/.p4ignore | 1 + 2 files changed, 2 insertions(+) diff --git a/mps/.p4ignore b/mps/.p4ignore index b640360caf6..25cd419ae6d 100644 --- a/mps/.p4ignore +++ b/mps/.p4ignore @@ -16,6 +16,7 @@ TAGS *.dSYM code/*/*/*.d *.pyc +test/obj test/test/log test/test/obj ....gcda diff --git a/mps/manual/source/design/.p4ignore b/mps/manual/source/design/.p4ignore index 0e9be69cee0..2457ad19192 100644 --- a/mps/manual/source/design/.p4ignore +++ b/mps/manual/source/design/.p4ignore @@ -1,5 +1,6 @@ # The files in this directory are generated by the "mps" extension to Sphinx, # except the index and the "old designs" index. *.rst +*.svg !index.rst !old.rst From e933748bd68e6c9ee21852ae8a62ddce3ed2b1e8 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 15 Apr 2014 12:41:10 +0100 Subject: [PATCH 093/266] Mvt does not actually need to use gcsegs: in fact, gcsegs create difficulties because buffers need to be detached. so switch to using ordinary segs just like mvff. Copied from Perforce Change: 185556 ServerID: perforce.ravenbrook.com --- mps/code/poolmv2.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index 51b346e9f43..f6d85b1b134 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -78,7 +78,6 @@ typedef struct MVTStruct Bool abqOverflow; /* ABQ dropped some candidates */ /* .* */ Bool splinter; /* Saved splinter */ - Seg splinterSeg; /* Saved splinter seg */ Addr splinterBase; /* Saved splinter base */ Addr splinterLimit; /* Saved splinter size */ @@ -133,7 +132,7 @@ typedef struct MVTStruct DEFINE_POOL_CLASS(MVTPoolClass, this) { - INHERIT_CLASS(this, AbstractSegBufPoolClass); + INHERIT_CLASS(this, AbstractBufferPoolClass); this->name = "MVT"; this->size = sizeof(MVTStruct); this->offset = offsetof(MVTStruct, poolStruct); @@ -292,7 +291,6 @@ static Res MVTInit(Pool pool, ArgList args) mvt->maxSize = maxSize; mvt->fragLimit = fragLimit; mvt->splinter = FALSE; - mvt->splinterSeg = NULL; mvt->splinterBase = (Addr)0; mvt->splinterLimit = (Addr)0; @@ -378,9 +376,7 @@ static Bool MVTCheck(MVT mvt) if (mvt->splinter) { CHECKL(AddrOffset(mvt->splinterBase, mvt->splinterLimit) >= mvt->minSize); - CHECKD(Seg, mvt->splinterSeg); - CHECKL(mvt->splinterBase >= SegBase(mvt->splinterSeg)); - CHECKL(mvt->splinterLimit <= SegLimit(mvt->splinterSeg)); + CHECKL(mvt->splinterBase < mvt->splinterLimit); } CHECKL(mvt->size == mvt->allocated + mvt->available + mvt->unavailable); @@ -951,7 +947,6 @@ static void MVTBufferEmpty(Pool pool, Buffer buffer, } mvt->splinter = TRUE; - mvt->splinterSeg = BufferSeg(buffer); mvt->splinterBase = base; mvt->splinterLimit = limit; } @@ -998,8 +993,6 @@ static void MVTFree(Pool pool, Addr base, Size size) AVER(mvt->size == mvt->allocated + mvt->available + mvt->unavailable); METER_ACC(mvt->exceptionReturns, SegSize(seg)); - if (SegBuffer(seg) != NULL) - BufferDetach(SegBuffer(seg), MVT2Pool(mvt)); MVTSegFree(mvt, seg); return; } @@ -1031,7 +1024,6 @@ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream) " availLimit: $U \n", (WriteFU)mvt->availLimit, " abqOverflow: $S \n", mvt->abqOverflow?"TRUE":"FALSE", " splinter: $S \n", mvt->splinter?"TRUE":"FALSE", - " splinterSeg: $P \n", (WriteFP)mvt->splinterSeg, " splinterBase: $A \n", (WriteFA)mvt->splinterBase, " splinterLimit: $A \n", (WriteFU)mvt->splinterLimit, " size: $U \n", (WriteFU)mvt->size, @@ -1158,7 +1150,7 @@ static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size, { /* Can't use plain old SegClass here because we need to call * SegBuffer() in MVTFree(). */ - Res res = SegAlloc(segReturn, GCSegClassGet(), + Res res = SegAlloc(segReturn, SegClassGet(), SegPrefDefault(), size, MVT2Pool(mvt), withReservoirPermit, argsNone); @@ -1182,7 +1174,6 @@ static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size, */ static void MVTSegFree(MVT mvt, Seg seg) { - Buffer buffer; Size size; size = SegSize(seg); @@ -1192,16 +1183,6 @@ static void MVTSegFree(MVT mvt, Seg seg) mvt->size -= size; mvt->availLimit = mvt->size * mvt->fragLimit / 100; AVER(mvt->size == mvt->allocated + mvt->available + mvt->unavailable); - - /* If the client program allocates the exactly the entire buffer then - frees the allocated memory then we'll try to free the segment with - the buffer still attached. It's safe, but we must detach the buffer - first. See job003520 and job003672. */ - buffer = SegBuffer(seg); - if (buffer != NULL) { - AVER(BufferAP(buffer)->init == SegLimit(seg)); - BufferDetach(buffer, MVT2Pool(mvt)); - } SegFree(seg); METER_ACC(mvt->segFrees, size); From d0881bf1e1db85faa87b2dfaa00001cbb364f45e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 15 Apr 2014 14:23:53 +0100 Subject: [PATCH 094/266] Lands maintain the total size of the address ranges they maintain. (this avoids the need to do free size accounting in mvff.) Copied from Perforce Change: 185567 ServerID: perforce.ravenbrook.com --- mps/code/land.c | 75 +++++++++++++++++++++++++++++++++++++++------ mps/code/mpm.h | 1 + mps/code/mpmst.h | 1 + mps/code/poolmvff.c | 29 ++++-------------- 4 files changed, 73 insertions(+), 33 deletions(-) diff --git a/mps/code/land.c b/mps/code/land.c index fe759d85410..6c59cb193a6 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -34,6 +34,8 @@ Bool LandCheck(Land land) CHECKD(LandClass, land->class); CHECKU(Arena, land->arena); CHECKL(AlignCheck(land->alignment)); + CHECKL(SizeIsAligned(land->size, land->alignment)); + /* too expensive to check land->size against contents */ return TRUE; } @@ -51,6 +53,7 @@ Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *own AVERT(LandClass, class); AVERT(Align, alignment); + land->size = 0; land->alignment = alignment; land->arena = arena; land->class = class; @@ -147,12 +150,21 @@ void LandFinish(Land land) Res LandInsert(Range rangeReturn, Land land, Range range) { + Res res; + Size size; + AVER(rangeReturn != NULL); AVERT(Land, land); AVERT(Range, range); AVER(RangeIsAligned(range, land->alignment)); - return (*land->class->insert)(rangeReturn, land, range); + /* rangeReturn is allowed to alias with range, so take size first. + * See */ + size = RangeSize(range); + res = (*land->class->insert)(rangeReturn, land, range); + if (res == ResOK) + land->size += size; + return res; } @@ -163,12 +175,22 @@ Res LandInsert(Range rangeReturn, Land land, Range range) Res LandDelete(Range rangeReturn, Land land, Range range) { + Res res; + Size size; + AVER(rangeReturn != NULL); AVERT(Land, land); AVERT(Range, range); AVER(RangeIsAligned(range, land->alignment)); - return (*land->class->delete)(rangeReturn, land, range); + /* rangeReturn is allowed to alias with range, so take size first. + * See */ + size = RangeSize(range); + AVER(land->size >= size); + res = (*land->class->delete)(rangeReturn, land, range); + if (res == ResOK) + land->size -= size; + return res; } @@ -193,14 +215,22 @@ void LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) { + Bool res; + AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); AVER(FindDeleteCheck(findDelete)); - return (*land->class->findFirst)(rangeReturn, oldRangeReturn, land, size, - findDelete); + res = (*land->class->findFirst)(rangeReturn, oldRangeReturn, land, size, + findDelete); + if (res && findDelete != FindDeleteNONE) { + AVER(RangeIsAligned(rangeReturn, land->alignment)); + AVER(land->size >= RangeSize(rangeReturn)); + land->size -= RangeSize(rangeReturn); + } + return res; } @@ -211,14 +241,22 @@ Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) { + Bool res; + AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); AVER(FindDeleteCheck(findDelete)); - return (*land->class->findLast)(rangeReturn, oldRangeReturn, land, size, - findDelete); + res = (*land->class->findLast)(rangeReturn, oldRangeReturn, land, size, + findDelete); + if (res && findDelete != FindDeleteNONE) { + AVER(RangeIsAligned(rangeReturn, land->alignment)); + AVER(land->size >= RangeSize(rangeReturn)); + land->size -= RangeSize(rangeReturn); + } + return res; } @@ -229,14 +267,22 @@ Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) { + Bool res; + AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); AVER(FindDeleteCheck(findDelete)); - return (*land->class->findLargest)(rangeReturn, oldRangeReturn, land, size, - findDelete); + res = (*land->class->findLargest)(rangeReturn, oldRangeReturn, land, size, + findDelete); + if (res && findDelete != FindDeleteNONE) { + AVER(RangeIsAligned(rangeReturn, land->alignment)); + AVER(land->size >= RangeSize(rangeReturn)); + land->size -= RangeSize(rangeReturn); + } + return res; } @@ -247,6 +293,8 @@ Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size si Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high) { + Res res; + AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); AVERT(Land, land); @@ -254,8 +302,14 @@ Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size siz /* AVER(ZoneSet, zoneSet); */ AVERT(Bool, high); - return (*land->class->findInZones)(rangeReturn, oldRangeReturn, land, size, - zoneSet, high); + res = (*land->class->findInZones)(rangeReturn, oldRangeReturn, land, size, + zoneSet, high); + if (res == ResOK) { + AVER(RangeIsAligned(rangeReturn, land->alignment)); + AVER(land->size >= RangeSize(rangeReturn)); + land->size -= RangeSize(rangeReturn); + } + return res; } @@ -277,6 +331,7 @@ Res LandDescribe(Land land, mps_lib_FILE *stream) " (\"$S\")\n", land->class->name, " arena $P\n", (WriteFP)land->arena, " align $U\n", (WriteFU)land->alignment, + " align $U\n", (WriteFU)land->size, NULL); if (res != ResOK) return res; diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 422327453dc..406aaf7c107 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -1002,6 +1002,7 @@ extern Size VMMapped(VM vm); extern Bool LandCheck(Land land); #define LandArena(land) ((land)->arena) #define LandAlignment(land) ((land)->alignment) +#define LandSize(land) ((land)->size) extern Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *owner, ArgList args); extern Res LandCreate(Land *landReturn, Arena arena, LandClass class, Align alignment, void *owner, ArgList args); diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 80bbd298090..7f355ed4ec8 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -641,6 +641,7 @@ typedef struct LandStruct { LandClass class; /* land class structure */ Arena arena; /* owning arena */ Align alignment; /* alignment of addresses */ + Size size; /* total size of ranges in land */ } LandStruct; diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index e50cf077f80..73bb4ff19eb 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -48,7 +48,6 @@ typedef struct MVFFStruct { /* MVFF pool outer structure */ Size minSegSize; /* minimum size of segment */ Size avgSize; /* client estimate of allocation size */ Size total; /* total bytes in pool */ - Size free; /* total free bytes in pool */ CBSStruct cbsStruct; /* free list */ FreelistStruct flStruct; /* emergency free list */ FailoverStruct foStruct; /* fail-over mechanism */ @@ -88,19 +87,10 @@ typedef MVFFDebugStruct *MVFFDebug; * segments (see MVFFFreeSegs). */ static Res MVFFInsert(Range rangeIO, MVFF mvff) { - Res res; - Size size; - - AVER(rangeIO != NULL); + AVERT(Range, rangeIO); AVERT(MVFF, mvff); - size = RangeSize(rangeIO); - res = LandInsert(rangeIO, FailoverOfMVFF(mvff), rangeIO); - - if (res == ResOK) - mvff->free += size; - - return res; + return LandInsert(rangeIO, FailoverOfMVFF(mvff), rangeIO); } @@ -151,7 +141,6 @@ static void MVFFFreeSegs(MVFF mvff, Range range) * that needs to be read in order to update the Freelist. */ SegFree(seg); - mvff->free -= RangeSize(&delRange); mvff->total -= RangeSize(&delRange); } @@ -262,10 +251,6 @@ static Bool MVFFFindFree(Range rangeReturn, MVFF mvff, Size size) (mvff->firstFit ? LandFindFirst : LandFindLast) (rangeReturn, &oldRange, FailoverOfMVFF(mvff), size, findDelete); - if (foundBlock) { - mvff->free -= size; - } - return foundBlock; } @@ -378,7 +363,6 @@ static Res MVFFBufferFill(Addr *baseReturn, Addr *limitReturn, AVER(found); AVER(RangeSize(&range) >= size); - mvff->free -= RangeSize(&range); *baseReturn = RangeBase(&range); *limitReturn = RangeLimit(&range); @@ -517,7 +501,6 @@ static Res MVFFInit(Pool pool, ArgList args) SegPrefExpress(mvff->segPref, arenaHigh ? SegPrefHigh : SegPrefLow, NULL); mvff->total = 0; - mvff->free = 0; res = LandInit(FreelistOfMVFF(mvff), FreelistLandClassGet(), arena, align, mvff, mps_args_none); if (res != ResOK) @@ -620,7 +603,6 @@ static Res MVFFDescribe(Pool pool, mps_lib_FILE *stream) " extendBy $W\n", (WriteFW)mvff->extendBy, " avgSize $W\n", (WriteFW)mvff->avgSize, " total $U\n", (WriteFU)mvff->total, - " free $U\n", (WriteFU)mvff->free, NULL); if (res != ResOK) return res; @@ -698,13 +680,15 @@ size_t mps_mvff_free_size(mps_pool_t mps_pool) { Pool pool; MVFF mvff; + Land land; pool = (Pool)mps_pool; AVERT(Pool, pool); mvff = Pool2MVFF(pool); AVERT(MVFF, mvff); + land = FailoverOfMVFF(mvff); - return (size_t)mvff->free; + return (size_t)LandSize(land); } /* Total owned bytes. See */ @@ -735,8 +719,7 @@ static Bool MVFFCheck(MVFF mvff) CHECKL(mvff->minSegSize >= ArenaAlign(PoolArena(MVFF2Pool(mvff)))); CHECKL(mvff->avgSize > 0); /* see .arg.check */ CHECKL(mvff->avgSize <= mvff->extendBy); /* see .arg.check */ - CHECKL(mvff->total >= mvff->free); - CHECKL(SizeIsAligned(mvff->free, PoolAlignment(MVFF2Pool(mvff)))); + CHECKL(mvff->total >= LandSize(FailoverOfMVFF(mvff))); CHECKL(SizeIsAligned(mvff->total, ArenaAlign(PoolArena(MVFF2Pool(mvff))))); CHECKD(CBS, &mvff->cbsStruct); CHECKD(Freelist, &mvff->flStruct); From a94cc2ed780a4240547b07d2a43e2e9373c26aad Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 15 Apr 2014 16:35:34 +0100 Subject: [PATCH 095/266] New generic function landsize returns the total size of ranges in a land (if the land supports it). implement it for all land classes. The MVFF pool class doesn't have to maintain its free size any more: it can just call LandSize. Move re-entrancy protection from CBS to Land. This allows us to remove some CBS functions. (But requires some adjustment in failoverDelete.) In MVFF, do more checking of mvff->total. Copied from Perforce Change: 185569 ServerID: perforce.ravenbrook.com --- mps/code/cbs.c | 158 ++++++++++++++------------------------------ mps/code/failover.c | 23 ++++++- mps/code/freelist.c | 24 ++++++- mps/code/land.c | 138 +++++++++++++++++++++++++++----------- mps/code/mpm.h | 4 +- mps/code/mpmst.h | 6 +- mps/code/mpmtypes.h | 1 + mps/code/poolmvff.c | 19 ++++-- mps/design/land.txt | 5 ++ 9 files changed, 218 insertions(+), 160 deletions(-) diff --git a/mps/code/cbs.c b/mps/code/cbs.c index 8aa21f87ca7..177388bc0cb 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -40,43 +40,20 @@ SRCID(cbs, "$Id$"); #define cbsBlockPool(cbs) RVALUE((cbs)->blockPool) -/* cbsEnter, cbsLeave -- Avoid re-entrance - * - * .enter-leave: The callbacks are restricted in what they may call. - * These functions enforce this. - * - * .enter-leave.simple: Simple queries may be called from callbacks. - */ - -static void cbsEnter(CBS cbs) -{ - /* Don't need to check as always called from interface function. */ - AVER(!cbs->inCBS); - cbs->inCBS = TRUE; - return; -} - -static void cbsLeave(CBS cbs) -{ - /* Don't need to check as always called from interface function. */ - AVER(cbs->inCBS); - cbs->inCBS = FALSE; - return; -} - - /* CBSCheck -- Check CBS */ Bool CBSCheck(CBS cbs) { /* See .enter-leave.simple. */ + Land land; CHECKS(CBS, cbs); - CHECKD(Land, cbsLand(cbs)); + land = cbsLand(cbs); + CHECKD(Land, land); CHECKD(SplayTree, cbsSplay(cbs)); - /* nothing to check about treeSize */ CHECKD(Pool, cbs->blockPool); - CHECKL(BoolCheck(cbs->inCBS)); CHECKL(BoolCheck(cbs->ownPool)); + CHECKL(SizeIsAligned(cbs->size, LandAlignment(land))); + CHECKL((cbs->size == 0) == (cbs->treeSize == 0)); return TRUE; } @@ -84,7 +61,6 @@ Bool CBSCheck(CBS cbs) static Bool CBSBlockCheck(CBSBlock block) { - /* See .enter-leave.simple. */ UNUSED(block); /* Required because there is no signature */ CHECKL(block != NULL); /* Can't use CHECKD_NOSIG because TreeEMPTY is NULL. */ @@ -277,16 +253,15 @@ static Res cbsInitComm(Land land, ArgList args, SplayUpdateNodeMethod update, cbs->ownPool = TRUE; } cbs->treeSize = 0; + cbs->size = 0; cbs->blockStructSize = blockStructSize; - cbs->inCBS = TRUE; METER_INIT(cbs->treeSearch, "size of tree", (void *)cbs); cbs->sig = CBSSig; AVERT(CBS, cbs); - cbsLeave(cbs); return ResOK; } @@ -309,7 +284,7 @@ static Res cbsInitZoned(Land land, ArgList args) } -/* CBSFinish -- Finish a CBS structure +/* cbsFinish -- Finish a CBS structure * * See . */ @@ -321,7 +296,6 @@ static void cbsFinish(Land land) AVERT(Land, land); cbs = cbsOfLand(land); AVERT(CBS, cbs); - cbsEnter(cbs); METER_EMIT(&cbs->treeSearch); @@ -333,6 +307,23 @@ static void cbsFinish(Land land) } +/* cbsSize -- total size of ranges in CBS + * + * See . + */ + +static Size cbsSize(Land land) +{ + CBS cbs; + + AVERT(Land, land); + cbs = cbsOfLand(land); + AVERT(CBS, cbs); + + return cbs->size; +} + + /* Node change operators * * These four functions are called whenever blocks are created, @@ -343,14 +334,18 @@ static void cbsFinish(Land land) static void cbsBlockDelete(CBS cbs, CBSBlock block) { Bool b; + Size size; AVERT(CBS, cbs); AVERT(CBSBlock, block); + size = CBSBlockSize(block); METER_ACC(cbs->treeSearch, cbs->treeSize); b = SplayTreeDelete(cbsSplay(cbs), cbsBlockTree(block)); AVER(b); /* expect block to be in the tree */ STATISTIC(--cbs->treeSize); + AVER(cbs->size >= size); + cbs->size -= size; /* make invalid */ block->limit = block->base; @@ -367,8 +362,10 @@ static void cbsBlockShrunk(CBS cbs, CBSBlock block, Size oldSize) newSize = CBSBlockSize(block); AVER(oldSize > newSize); + AVER(cbs->size >= oldSize - newSize); SplayNodeRefresh(cbsSplay(cbs), cbsBlockTree(block)); + cbs->size -= oldSize - newSize; } static void cbsBlockGrew(CBS cbs, CBSBlock block, Size oldSize) @@ -382,6 +379,7 @@ static void cbsBlockGrew(CBS cbs, CBSBlock block, Size oldSize) AVER(oldSize < newSize); SplayNodeRefresh(cbsSplay(cbs), cbsBlockTree(block)); + cbs->size += newSize - oldSize; } /* cbsBlockAlloc -- allocate a new block and set its base and limit, @@ -431,12 +429,19 @@ static void cbsBlockInsert(CBS cbs, CBSBlock block) b = SplayTreeInsert(cbsSplay(cbs), cbsBlockTree(block)); AVER(b); STATISTIC(++cbs->treeSize); + cbs->size += CBSBlockSize(block); } -/* cbsInsertIntoTree -- Insert a range into the tree */ +/* cbsInsert -- Insert a range into the CBS + * + * See . + * + * .insert.alloc: Will only allocate a block if the range does not + * abut an existing range. + */ -static Res cbsInsertIntoTree(Range rangeReturn, Land land, Range range) +static Res cbsInsert(Range rangeReturn, Land land, Range range) { CBS cbs; Bool b; @@ -533,38 +538,15 @@ static Res cbsInsertIntoTree(Range rangeReturn, Land land, Range range) } -/* cbsInsert -- Insert a range into the CBS +/* cbsDelete -- Remove a range from a CBS * - * See . + * See . * - * .insert.alloc: Will only allocate a block if the range does not - * abut an existing range. + * .delete.alloc: Will only allocate a block if the range splits + * an existing range. */ -static Res cbsInsert(Range rangeReturn, Land land, Range range) -{ - CBS cbs; - Res res; - - AVERT(Land, land); - cbs = cbsOfLand(land); - AVERT(CBS, cbs); - cbsEnter(cbs); - - AVER(rangeReturn != NULL); - AVERT(Range, range); - AVER(RangeIsAligned(range, LandAlignment(land))); - - res = cbsInsertIntoTree(rangeReturn, land, range); - - cbsLeave(cbs); - return res; -} - - -/* cbsDeleteFromTree -- delete blocks from the tree */ - -static Res cbsDeleteFromTree(Range rangeReturn, Land land, Range range) +static Res cbsDelete(Range rangeReturn, Land land, Range range) { CBS cbs; Res res; @@ -642,35 +624,6 @@ static Res cbsDeleteFromTree(Range rangeReturn, Land land, Range range) } -/* cbsDelete -- Remove a range from a CBS - * - * See . - * - * .delete.alloc: Will only allocate a block if the range splits - * an existing range. - */ - -static Res cbsDelete(Range rangeReturn, Land land, Range range) -{ - CBS cbs; - Res res; - - AVERT(Land, land); - cbs = cbsOfLand(land); - AVERT(CBS, cbs); - cbsEnter(cbs); - - AVER(rangeReturn != NULL); - AVERT(Range, range); - AVER(RangeIsAligned(range, LandAlignment(land))); - - res = cbsDeleteFromTree(rangeReturn, land, range); - - cbsLeave(cbs); - return res; -} - - static Res cbsBlockDescribe(CBSBlock block, mps_lib_FILE *stream) { Res res; @@ -813,7 +766,6 @@ static void cbsIterate(Land land, LandVisitor visitor, AVERT(Land, land); cbs = cbsOfLand(land); AVERT(CBS, cbs); - cbsEnter(cbs); AVER(FUNCHECK(visitor)); splay = cbsSplay(cbs); @@ -827,9 +779,6 @@ static void cbsIterate(Land land, LandVisitor visitor, closure.closureS = closureS; (void)TreeTraverse(SplayTreeRoot(splay), splay->compare, splay->nodeKey, cbsIterateVisit, &closure, 0); - - cbsLeave(cbs); - return; } @@ -882,10 +831,10 @@ static void cbsFindDeleteRange(Range rangeReturn, Range oldRangeReturn, if (callDelete) { Res res; - res = cbsDeleteFromTree(oldRangeReturn, land, rangeReturn); + res = cbsDelete(oldRangeReturn, land, rangeReturn); /* Can't have run out of memory, because all our callers pass in blocks that were just found in the tree, and we only - deleted from one end of the block, so cbsDeleteFromTree did not + deleted from one end of the block, so cbsDelete did not need to allocate a new block. */ AVER(res == ResOK); } @@ -905,7 +854,6 @@ static Bool cbsFindFirst(Range rangeReturn, Range oldRangeReturn, cbs = cbsOfLand(land); AVERT(CBS, cbs); AVER(IsLandSubclass(cbsLand(cbs), CBSFastLandClass)); - cbsEnter(cbs); AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); @@ -927,7 +875,6 @@ static Bool cbsFindFirst(Range rangeReturn, Range oldRangeReturn, size, findDelete); } - cbsLeave(cbs); return found; } @@ -992,7 +939,6 @@ static Bool cbsFindLast(Range rangeReturn, Range oldRangeReturn, cbs = cbsOfLand(land); AVERT(CBS, cbs); AVER(IsLandSubclass(cbsLand(cbs), CBSFastLandClass)); - cbsEnter(cbs); AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); @@ -1014,7 +960,6 @@ static Bool cbsFindLast(Range rangeReturn, Range oldRangeReturn, size, findDelete); } - cbsLeave(cbs); return found; } @@ -1031,7 +976,6 @@ static Bool cbsFindLargest(Range rangeReturn, Range oldRangeReturn, cbs = cbsOfLand(land); AVERT(CBS, cbs); AVER(IsLandSubclass(cbsLand(cbs), CBSFastLandClass)); - cbsEnter(cbs); AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); @@ -1058,7 +1002,6 @@ static Bool cbsFindLargest(Range rangeReturn, Range oldRangeReturn, } } - cbsLeave(cbs); return found; } @@ -1101,8 +1044,6 @@ static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn, /* It would be nice if there were a neat way to eliminate all runs of zones in zoneSet too small for size.*/ - cbsEnter(cbs); - closure.arena = LandArena(land); closure.zoneSet = zoneSet; closure.size = size; @@ -1123,7 +1064,7 @@ static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn, RangeInit(&rangeStruct, closure.base, AddrAdd(closure.base, size)); else RangeInit(&rangeStruct, AddrSub(closure.limit, size), closure.limit); - res = cbsDeleteFromTree(&oldRangeStruct, land, &rangeStruct); + res = cbsDelete(&oldRangeStruct, land, &rangeStruct); if (res == ResOK) { /* enough memory to split block */ RangeCopy(rangeReturn, &rangeStruct); RangeCopy(oldRangeReturn, &oldRangeStruct); @@ -1131,7 +1072,6 @@ static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn, } else res = ResFAIL; - cbsLeave(cbs); return res; } @@ -1158,7 +1098,6 @@ static Res cbsDescribe(Land land, mps_lib_FILE *stream) res = WriteF(stream, "CBS $P {\n", (WriteFP)cbs, " blockPool: $P\n", (WriteFP)cbsBlockPool(cbs), - " inCBS: $U\n", (WriteFU)cbs->inCBS, " ownPool: $U\n", (WriteFU)cbs->ownPool, " treeSize: $U\n", (WriteFU)cbs->treeSize, NULL); @@ -1187,6 +1126,7 @@ DEFINE_LAND_CLASS(CBSLandClass, class) class->size = sizeof(CBSStruct); class->init = cbsInit; class->finish = cbsFinish; + class->sizeMethod = cbsSize; class->insert = cbsInsert; class->delete = cbsDelete; class->iterate = cbsIterate; diff --git a/mps/code/failover.c b/mps/code/failover.c index 3f633acd34d..e8a0dbc7dae 100644 --- a/mps/code/failover.c +++ b/mps/code/failover.c @@ -70,6 +70,18 @@ static void failoverFinish(Land land) } +static Size failoverSize(Land land) +{ + Failover fo; + + AVERT(Land, land); + fo = failoverOfLand(land); + AVERT(Failover, fo); + + return LandSize(fo->primary) + LandSize(fo->secondary); +} + + static Res failoverInsert(Range rangeReturn, Land land, Range range) { Failover fo; @@ -129,12 +141,18 @@ static Res failoverDelete(Range rangeReturn, Land land, Range range) AVER(RangesEqual(&oldRange, &dummyRange)); RangeInit(&left, RangeBase(&oldRange), RangeBase(range)); if (!RangeIsEmpty(&left)) { - res = LandInsert(&dummyRange, land, &left); + /* Don't call LandInsert(..., land, ...) here: that would be + * re-entrant and fail the landEnter check. */ + res = LandInsert(&dummyRange, fo->primary, &left); + if (res != ResOK && res != ResFAIL) + res = LandInsert(&dummyRange, fo->secondary, &left); AVER(res == ResOK); } RangeInit(&right, RangeLimit(range), RangeLimit(&oldRange)); if (!RangeIsEmpty(&right)) { - res = LandInsert(&dummyRange, land, &right); + res = LandInsert(&dummyRange, fo->primary, &right); + if (res != ResOK && res != ResFAIL) + res = LandInsert(&dummyRange, fo->secondary, &right); AVER(res == ResOK); } } @@ -266,6 +284,7 @@ DEFINE_LAND_CLASS(FailoverLandClass, class) class->size = sizeof(FailoverStruct); class->init = failoverInit; class->finish = failoverFinish; + class->sizeMethod = failoverSize; class->insert = failoverInsert; class->delete = failoverDelete; class->iterate = failoverIterate; diff --git a/mps/code/freelist.c b/mps/code/freelist.c index 5b586a82e6a..13f83bd4aad 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -168,8 +168,11 @@ Bool FreelistCheck(Freelist fl) land = &fl->landStruct; CHECKD(Land, land); /* See */ - CHECKL(AlignIsAligned(LandAlignment(land), freelistMinimumAlignment)); + CHECKL(AlignIsAligned(freelistAlignment(fl), freelistMinimumAlignment)); CHECKL((fl->list == NULL) == (fl->listSize == 0)); + CHECKL((fl->list == NULL) == (fl->size == 0)); + CHECKL(SizeIsAligned(fl->size, freelistAlignment(fl))); + return TRUE; } @@ -192,6 +195,7 @@ static Res freelistInit(Land land, ArgList args) fl = freelistOfLand(land); fl->list = NULL; fl->listSize = 0; + fl->size = 0; fl->sig = FreelistSig; AVERT(Freelist, fl); @@ -211,6 +215,17 @@ static void freelistFinish(Land land) } +static Size freelistSize(Land land) +{ + Freelist fl; + + AVERT(Land, land); + fl = freelistOfLand(land); + AVERT(Freelist, fl); + return fl->size; +} + + /* freelistBlockSetPrevNext -- update list of blocks * * If prev and next are both NULL, make the block list empty. @@ -303,6 +318,7 @@ static Res freelistInsert(Range rangeReturn, Land land, Range range) freelistBlockSetPrevNext(fl, prev, new, +1); } + fl->size += RangeSize(range); RangeInit(rangeReturn, base, limit); return ResOK; } @@ -360,6 +376,8 @@ static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl, freelistBlockSetPrevNext(fl, block, new, +1); } + AVER(fl->size >= RangeSize(range)); + fl->size -= RangeSize(range); RangeInit(rangeReturn, blockBase, blockLimit); } @@ -426,7 +444,10 @@ static void freelistIterate(Land land, LandVisitor visitor, cont = (*visitor)(&delete, land, &range, closureP, closureS); next = FreelistBlockNext(cur); if (delete) { + Size size = FreelistBlockSize(fl, cur); freelistBlockSetPrevNext(fl, prev, next, -1); + AVER(fl->size >= size); + fl->size -= size; } else { prev = cur; } @@ -726,6 +747,7 @@ DEFINE_LAND_CLASS(FreelistLandClass, class) class->size = sizeof(FreelistStruct); class->init = freelistInit; class->finish = freelistFinish; + class->sizeMethod = freelistSize; class->insert = freelistInsert; class->delete = freelistDelete; class->iterate = freelistIterate; diff --git a/mps/code/land.c b/mps/code/land.c index 6c59cb193a6..9ff8257151c 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -26,16 +26,41 @@ Bool FindDeleteCheck(FindDelete findDelete) } +/* landEnter, landLeave -- Avoid re-entrance + * + * .enter-leave: The visitor function passed to LandIterate is not + * allowed to call methods of that land. These functions enforce this. + * + * .enter-leave.simple: Some simple queries are fine to call from + * visitor functions. These are marked with the tag of this comment. + */ + +static void landEnter(Land land) +{ + /* Don't need to check as always called from interface function. */ + AVER(!land->inLand); + land->inLand = TRUE; + return; +} + +static void landLeave(Land land) +{ + /* Don't need to check as always called from interface function. */ + AVER(land->inLand); + land->inLand = FALSE; + return; +} + + /* LandCheck -- check land */ Bool LandCheck(Land land) { + /* .enter-leave.simple */ CHECKS(Land, land); CHECKD(LandClass, land->class); CHECKU(Arena, land->arena); CHECKL(AlignCheck(land->alignment)); - CHECKL(SizeIsAligned(land->size, land->alignment)); - /* too expensive to check land->size against contents */ return TRUE; } @@ -53,7 +78,7 @@ Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *own AVERT(LandClass, class); AVERT(Align, alignment); - land->size = 0; + land->inLand = TRUE; land->alignment = alignment; land->arena = arena; land->class = class; @@ -66,6 +91,7 @@ Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *own goto failInit; EVENT2(LandInit, land, owner); + landLeave(land); return ResOK; failInit: @@ -136,6 +162,7 @@ void LandDestroy(Land land) void LandFinish(Land land) { AVERT(Land, land); + landEnter(land); (*land->class->finish)(land); @@ -143,6 +170,20 @@ void LandFinish(Land land) } +/* LandSize -- return the total size of ranges in land + * + * See + */ + +Size LandSize(Land land) +{ + /* .enter-leave.simple */ + AVERT(Land, land); + + return (*land->class->sizeMethod)(land); +} + + /* LandInsert -- insert range of addresses into land * * See @@ -151,19 +192,16 @@ void LandFinish(Land land) Res LandInsert(Range rangeReturn, Land land, Range range) { Res res; - Size size; AVER(rangeReturn != NULL); AVERT(Land, land); AVERT(Range, range); AVER(RangeIsAligned(range, land->alignment)); + landEnter(land); - /* rangeReturn is allowed to alias with range, so take size first. - * See */ - size = RangeSize(range); res = (*land->class->insert)(rangeReturn, land, range); - if (res == ResOK) - land->size += size; + + landLeave(land); return res; } @@ -176,20 +214,16 @@ Res LandInsert(Range rangeReturn, Land land, Range range) Res LandDelete(Range rangeReturn, Land land, Range range) { Res res; - Size size; AVER(rangeReturn != NULL); AVERT(Land, land); AVERT(Range, range); AVER(RangeIsAligned(range, land->alignment)); + landEnter(land); - /* rangeReturn is allowed to alias with range, so take size first. - * See */ - size = RangeSize(range); - AVER(land->size >= size); res = (*land->class->delete)(rangeReturn, land, range); - if (res == ResOK) - land->size -= size; + + landLeave(land); return res; } @@ -203,8 +237,11 @@ void LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) { AVERT(Land, land); AVER(FUNCHECK(visitor)); + landEnter(land); (*land->class->iterate)(land, visitor, closureP, closureS); + + landLeave(land); } @@ -222,14 +259,12 @@ Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); AVER(FindDeleteCheck(findDelete)); + landEnter(land); res = (*land->class->findFirst)(rangeReturn, oldRangeReturn, land, size, findDelete); - if (res && findDelete != FindDeleteNONE) { - AVER(RangeIsAligned(rangeReturn, land->alignment)); - AVER(land->size >= RangeSize(rangeReturn)); - land->size -= RangeSize(rangeReturn); - } + + landLeave(land); return res; } @@ -248,14 +283,12 @@ Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); AVER(FindDeleteCheck(findDelete)); + landEnter(land); res = (*land->class->findLast)(rangeReturn, oldRangeReturn, land, size, findDelete); - if (res && findDelete != FindDeleteNONE) { - AVER(RangeIsAligned(rangeReturn, land->alignment)); - AVER(land->size >= RangeSize(rangeReturn)); - land->size -= RangeSize(rangeReturn); - } + + landLeave(land); return res; } @@ -274,14 +307,12 @@ Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size si AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); AVER(FindDeleteCheck(findDelete)); + landEnter(land); res = (*land->class->findLargest)(rangeReturn, oldRangeReturn, land, size, findDelete); - if (res && findDelete != FindDeleteNONE) { - AVER(RangeIsAligned(rangeReturn, land->alignment)); - AVER(land->size >= RangeSize(rangeReturn)); - land->size -= RangeSize(rangeReturn); - } + + landLeave(land); return res; } @@ -301,14 +332,12 @@ Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size siz AVER(SizeIsAligned(size, land->alignment)); /* AVER(ZoneSet, zoneSet); */ AVERT(Bool, high); + landEnter(land); res = (*land->class->findInZones)(rangeReturn, oldRangeReturn, land, size, zoneSet, high); - if (res == ResOK) { - AVER(RangeIsAligned(rangeReturn, land->alignment)); - AVER(land->size >= RangeSize(rangeReturn)); - land->size -= RangeSize(rangeReturn); - } + + landLeave(land); return res; } @@ -331,7 +360,7 @@ Res LandDescribe(Land land, mps_lib_FILE *stream) " (\"$S\")\n", land->class->name, " arena $P\n", (WriteFP)land->arena, " align $U\n", (WriteFU)land->alignment, - " align $U\n", (WriteFU)land->size, + " inLand: $U\n", (WriteFU)land->inLand, NULL); if (res != ResOK) return res; @@ -424,6 +453,40 @@ static void landTrivFinish(Land land) NOOP; } +static Size landNoSize(Land land) +{ + UNUSED(land); + NOTREACHED; + return 0; +} + +/* LandSlowSize -- generic size method but slow */ + +static Bool landSizeVisitor(Bool *deleteReturn, Land land, Range range, + void *closureP, Size closureS) +{ + Size *size; + + AVER(deleteReturn != NULL); + AVERT(Land, land); + AVERT(Range, range); + AVER(closureP != NULL); + UNUSED(closureS); + + size = closureP; + *size += RangeSize(range); + *deleteReturn = FALSE; + + return TRUE; +} + +Size LandSlowSize(Land land) +{ + Size size = 0; + LandIterate(land, landSizeVisitor, &size, 0); + return size; +} + static Res landNoInsert(Range rangeReturn, Land land, Range range) { AVER(rangeReturn != NULL); @@ -486,6 +549,7 @@ DEFINE_CLASS(LandClass, class) class->name = "LAND"; class->size = sizeof(LandStruct); class->init = landTrivInit; + class->sizeMethod = landNoSize; class->finish = landTrivFinish; class->insert = landNoInsert; class->delete = landNoDelete; diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 406aaf7c107..070d749bb80 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -1002,8 +1002,7 @@ extern Size VMMapped(VM vm); extern Bool LandCheck(Land land); #define LandArena(land) ((land)->arena) #define LandAlignment(land) ((land)->alignment) -#define LandSize(land) ((land)->size) - +extern Size LandSize(Land land); extern Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *owner, ArgList args); extern Res LandCreate(Land *landReturn, Arena arena, LandClass class, Align alignment, void *owner, ArgList args); extern void LandDestroy(Land land); @@ -1018,6 +1017,7 @@ extern Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, S extern Res LandDescribe(Land land, mps_lib_FILE *stream); extern void LandFlush(Land dest, Land src); +extern Size LandSlowSize(Land land); extern Bool LandClassCheck(LandClass class); extern LandClass LandClassGet(void); #define LAND_SUPERCLASS(className) ((LandClass)SUPERCLASS(className)) diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 7f355ed4ec8..8ce4d14f01a 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -615,6 +615,7 @@ typedef struct LandClassStruct { ProtocolClassStruct protocol; const char *name; /* class name string */ size_t size; /* size of outer structure */ + LandSizeMethod sizeMethod; /* total size of ranges in land */ LandInitMethod init; /* initialize the land */ LandFinishMethod finish; /* finish the land */ LandInsertMethod insert; /* insert a range into the land */ @@ -641,7 +642,7 @@ typedef struct LandStruct { LandClass class; /* land class structure */ Arena arena; /* owning arena */ Align alignment; /* alignment of addresses */ - Size size; /* total size of ranges in land */ + Bool inLand; /* prevent reentrance */ } LandStruct; @@ -661,8 +662,8 @@ typedef struct CBSStruct { STATISTIC_DECL(Count treeSize); Pool blockPool; /* pool that manages blocks */ Size blockStructSize; /* size of block structure */ - Bool inCBS; /* prevent reentrance */ Bool ownPool; /* did we create blockPool? */ + Size size; /* total size of ranges in CBS */ /* meters for sizes of search structures at each op */ METER_DECL(treeSearch); Sig sig; /* .class.end-sig */ @@ -703,6 +704,7 @@ typedef struct FreelistStruct { LandStruct landStruct; /* superclass fields come first */ FreelistBlock list; /* first block in list or NULL if empty */ Count listSize; /* number of blocks in list */ + Size size; /* total size of ranges in list */ Sig sig; /* .class.end-sig */ } FreelistStruct; diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index d8eebb7bcd6..04f73a7e42d 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -268,6 +268,7 @@ typedef struct TraceMessageStruct *TraceMessage; /* trace end */ typedef Res (*LandInitMethod)(Land land, ArgList args); 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)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS); diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 73bb4ff19eb..4fb5c5ce724 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -141,6 +141,7 @@ static void MVFFFreeSegs(MVFF mvff, Range range) * that needs to be read in order to update the Freelist. */ SegFree(seg); + AVER(mvff->total >= RangeSize(&delRange)); mvff->total -= RangeSize(&delRange); } @@ -502,7 +503,8 @@ static Res MVFFInit(Pool pool, ArgList args) mvff->total = 0; - res = LandInit(FreelistOfMVFF(mvff), FreelistLandClassGet(), arena, align, mvff, mps_args_none); + res = LandInit(FreelistOfMVFF(mvff), FreelistLandClassGet(), arena, align, + mvff, mps_args_none); if (res != ResOK) goto failFreelistInit; @@ -514,7 +516,8 @@ static Res MVFFInit(Pool pool, ArgList args) MPS_ARGS_BEGIN(foArgs) { MPS_ARGS_ADD(foArgs, FailoverPrimary, CBSOfMVFF(mvff)); MPS_ARGS_ADD(foArgs, FailoverSecondary, FreelistOfMVFF(mvff)); - res = LandInit(FailoverOfMVFF(mvff), FailoverLandClassGet(), arena, align, mvff, foArgs); + res = LandInit(FailoverOfMVFF(mvff), FailoverLandClassGet(), arena, align, + mvff, foArgs); } MPS_ARGS_END(foArgs); if (res != ResOK) goto failFailoverInit; @@ -541,7 +544,6 @@ static void MVFFFinish(Pool pool) { MVFF mvff; Arena arena; - Seg seg; Ring ring, node, nextNode; AVERT(Pool, pool); @@ -550,14 +552,17 @@ static void MVFFFinish(Pool pool) ring = PoolSegRing(pool); RING_FOR(node, ring, nextNode) { + Size size; + Seg seg; seg = SegOfPoolRing(node); AVER(SegPool(seg) == pool); + size = AddrOffset(SegBase(seg), SegLimit(seg)); + AVER(size <= mvff->total); + mvff->total -= size; SegFree(seg); } - /* Could maintain mvff->total here and check it falls to zero, */ - /* but that would just make the function slow. If only we had */ - /* a way to do operations only if AVERs are turned on. */ + AVER(mvff->total == 0); arena = PoolArena(pool); ControlFree(arena, mvff->segPref, sizeof(SegPrefStruct)); @@ -719,11 +724,11 @@ static Bool MVFFCheck(MVFF mvff) CHECKL(mvff->minSegSize >= ArenaAlign(PoolArena(MVFF2Pool(mvff)))); CHECKL(mvff->avgSize > 0); /* see .arg.check */ CHECKL(mvff->avgSize <= mvff->extendBy); /* see .arg.check */ - CHECKL(mvff->total >= LandSize(FailoverOfMVFF(mvff))); CHECKL(SizeIsAligned(mvff->total, ArenaAlign(PoolArena(MVFF2Pool(mvff))))); CHECKD(CBS, &mvff->cbsStruct); CHECKD(Freelist, &mvff->flStruct); CHECKD(Failover, &mvff->foStruct); + CHECKL(mvff->total >= LandSize(FailoverOfMVFF(mvff))); CHECKL(BoolCheck(mvff->slotHigh)); CHECKL(BoolCheck(mvff->firstFit)); return TRUE; diff --git a/mps/design/land.txt b/mps/design/land.txt index 3a4b81abc08..11f192fa6ff 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -117,6 +117,11 @@ finish the land structure, and then frees its memory. _`.function.finish`: ``LandFinish()`` finishes the land structure and discards any other resources associated with the land. +``void LandSize(Land land)`` + +_`.function.size`: ``LandSize()`` returns the total size of the ranges +stored in the land. + ``Res LandInsert(Range rangeReturn, Land land, Range range)`` _`.function.insert`: If any part of ``range`` is already in the From acccc01ec4c1cb6ca1eefbc3c197e471b43945f8 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 16 Apr 2014 10:24:26 +0100 Subject: [PATCH 096/266] Move cbsfindinzones so that diff is cleaner. Copied from Perforce Change: 185578 ServerID: perforce.ravenbrook.com --- mps/code/cbs.c | 139 ++++++++++++++++++++++++------------------------- 1 file changed, 69 insertions(+), 70 deletions(-) diff --git a/mps/code/cbs.c b/mps/code/cbs.c index 177388bc0cb..8531fa0673b 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -925,6 +925,75 @@ static Bool cbsTestTreeInZones(SplayTree splay, Tree tree, && ZoneSetInter(zonedBlock->zones, closure->zoneSet) != ZoneSetEMPTY; } +static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn, + Land land, Size size, + ZoneSet zoneSet, Bool high) +{ + CBS cbs; + Tree tree; + cbsTestNodeInZonesClosureStruct closure; + Res res; + LandFindMethod landFind; + SplayFindMethod splayFind; + + AVER(rangeReturn != NULL); + AVER(oldRangeReturn != NULL); + AVERT(Land, land); + cbs = cbsOfLand(land); + AVERT(CBS, cbs); + AVER(IsLandSubclass(cbsLand(cbs), CBSZonedLandClass)); + /* AVERT(ZoneSet, zoneSet); */ + AVER(BoolCheck(high)); + + landFind = high ? cbsFindLast : cbsFindFirst; + splayFind = high ? SplayFindLast : SplayFindFirst; + + if (zoneSet == ZoneSetEMPTY) + return ResFAIL; + if (zoneSet == ZoneSetUNIV) { + FindDelete fd = high ? FindDeleteHIGH : FindDeleteLOW; + if ((*landFind)(rangeReturn, oldRangeReturn, land, size, fd)) + return ResOK; + else + return ResFAIL; + } + if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(LandArena(land))) + return ResFAIL; + + /* It would be nice if there were a neat way to eliminate all runs of + zones in zoneSet too small for size.*/ + + closure.arena = LandArena(land); + closure.zoneSet = zoneSet; + closure.size = size; + closure.high = high; + if (splayFind(&tree, cbsSplay(cbs), + cbsTestNodeInZones, + cbsTestTreeInZones, + &closure, sizeof(closure))) { + CBSBlock block = cbsBlockOfTree(tree); + RangeStruct rangeStruct, oldRangeStruct; + + AVER(CBSBlockBase(block) <= closure.base); + AVER(AddrOffset(closure.base, closure.limit) >= size); + AVER(ZoneSetSub(ZoneSetOfRange(LandArena(land), closure.base, closure.limit), zoneSet)); + AVER(closure.limit <= CBSBlockLimit(block)); + + if (!high) + RangeInit(&rangeStruct, closure.base, AddrAdd(closure.base, size)); + else + RangeInit(&rangeStruct, AddrSub(closure.limit, size), closure.limit); + res = cbsDelete(&oldRangeStruct, land, &rangeStruct); + if (res == ResOK) { /* enough memory to split block */ + RangeCopy(rangeReturn, &rangeStruct); + RangeCopy(oldRangeReturn, &oldRangeStruct); + } + } else + res = ResFAIL; + + return res; +} + /* cbsFindLast -- find the last block of at least the given size */ @@ -1006,76 +1075,6 @@ static Bool cbsFindLargest(Range rangeReturn, Range oldRangeReturn, } -static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn, - Land land, Size size, - ZoneSet zoneSet, Bool high) -{ - CBS cbs; - Tree tree; - cbsTestNodeInZonesClosureStruct closure; - Res res; - LandFindMethod landFind; - SplayFindMethod splayFind; - - AVER(rangeReturn != NULL); - AVER(oldRangeReturn != NULL); - AVERT(Land, land); - cbs = cbsOfLand(land); - AVERT(CBS, cbs); - AVER(IsLandSubclass(cbsLand(cbs), CBSZonedLandClass)); - /* AVERT(ZoneSet, zoneSet); */ - AVER(BoolCheck(high)); - - landFind = high ? cbsFindLast : cbsFindFirst; - splayFind = high ? SplayFindLast : SplayFindFirst; - - if (zoneSet == ZoneSetEMPTY) - return ResFAIL; - if (zoneSet == ZoneSetUNIV) { - FindDelete fd = high ? FindDeleteHIGH : FindDeleteLOW; - if ((*landFind)(rangeReturn, oldRangeReturn, land, size, fd)) - return ResOK; - else - return ResFAIL; - } - if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(LandArena(land))) - return ResFAIL; - - /* It would be nice if there were a neat way to eliminate all runs of - zones in zoneSet too small for size.*/ - - closure.arena = LandArena(land); - closure.zoneSet = zoneSet; - closure.size = size; - closure.high = high; - if (splayFind(&tree, cbsSplay(cbs), - cbsTestNodeInZones, - cbsTestTreeInZones, - &closure, sizeof(closure))) { - CBSBlock block = cbsBlockOfTree(tree); - RangeStruct rangeStruct, oldRangeStruct; - - AVER(CBSBlockBase(block) <= closure.base); - AVER(AddrOffset(closure.base, closure.limit) >= size); - AVER(ZoneSetSub(ZoneSetOfRange(LandArena(land), closure.base, closure.limit), zoneSet)); - AVER(closure.limit <= CBSBlockLimit(block)); - - if (!high) - RangeInit(&rangeStruct, closure.base, AddrAdd(closure.base, size)); - else - RangeInit(&rangeStruct, AddrSub(closure.limit, size), closure.limit); - res = cbsDelete(&oldRangeStruct, land, &rangeStruct); - if (res == ResOK) { /* enough memory to split block */ - RangeCopy(rangeReturn, &rangeStruct); - RangeCopy(oldRangeReturn, &oldRangeStruct); - } - } else - res = ResFAIL; - - return res; -} - - /* cbsDescribe -- describe a CBS * * See . From 02c40ddb7e271dbcefa6f593c0c4e19e08ba89b5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 16 Apr 2014 10:48:21 +0100 Subject: [PATCH 097/266] =?UTF-8?q?Use=20x=20and=20x=5Fnone=20for=20x=20?= =?UTF-8?q?=E2=88=88=20{lock,=20plinth,=20remembered=5Fset,=20shield}=20to?= =?UTF-8?q?=20match=20the=20other=20settings=20(aver=5Fand=5Fcheck,=20even?= =?UTF-8?q?t,=20statistics).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copied from Perforce Change: 185580 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 15 +++++++++++---- mps/code/lock.h | 10 ++++++---- mps/code/mpm.h | 16 +++++++++++----- mps/code/mps.c | 2 +- mps/code/seg.c | 9 +++++++-- 5 files changed, 36 insertions(+), 16 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index 3e6158c1c7c..d68d1b52361 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -147,7 +147,9 @@ * cc -O2 -c -DCONFIG_PLINTH_NONE mps.c */ -#if defined(CONFIG_PLINTH_NONE) +#if !defined(CONFIG_PLINTH_NONE) +#define PLINTH +#else #define PLINTH_NONE #endif @@ -172,7 +174,9 @@ */ #if defined(CONFIG_THREAD_SINGLE) -#define DISABLE_LOCKS +#define LOCK +#else +#define LOCK_NONE #endif @@ -190,8 +194,11 @@ #if !defined(CONFIG_THREAD_SINGLE) #error "CONFIG_POLL_NONE without CONFIG_THREAD_SINGLE" #endif -#define DISABLE_REMEMBERED_SET -#define DISABLE_SHIELD +#define REMEMBERED_SET +#define SHIELD +#else +#define REMEMBERED_SET_NONE +#define SHIELD_NONE #endif diff --git a/mps/code/lock.h b/mps/code/lock.h index 5f0cadd7065..4fcd591a0f2 100644 --- a/mps/code/lock.h +++ b/mps/code/lock.h @@ -195,8 +195,9 @@ extern void LockClaimGlobal(void); extern void LockReleaseGlobal(void); -#ifdef DISABLE_LOCKS - +#if defined(LOCK) +/* Nothing to do: functions declared in all lock configurations. */ +#elif defined(LOCK_NONE) #define LockSize() MPS_PF_ALIGN #define LockInit(lock) UNUSED(lock) #define LockFinish(lock) UNUSED(lock) @@ -209,8 +210,9 @@ extern void LockReleaseGlobal(void); #define LockReleaseGlobalRecursive() #define LockClaimGlobal() #define LockReleaseGlobal() - -#endif /* DISABLE_LOCKS */ +#else +#error "No lock configuration." +#endif /* LOCK */ #endif /* lock_h */ diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 7876330de65..8c030acaa77 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -524,14 +524,16 @@ extern void (ArenaEnter)(Arena arena); extern void (ArenaLeave)(Arena arena); extern void (ArenaPoll)(Globals globals); -#ifdef DISABLE_SHIELD +#if defined(SHIELD) #define ArenaEnter(arena) UNUSED(arena) #define ArenaLeave(arena) AVER(arena->busyTraces == TraceSetEMPTY) #define ArenaPoll(globals) UNUSED(globals) -#else +#elif defined(SHIELD_NONE) #define ArenaEnter(arena) ArenaEnterLock(arena, FALSE) #define ArenaLeave(arena) ArenaLeaveLock(arena, FALSE) -#endif +#else +#error "No shield configuration." +#endif /* SHIELD */ extern void ArenaEnterRecursive(Arena arena); extern void ArenaLeaveRecursive(Arena arena); @@ -892,7 +894,9 @@ extern void (ShieldSuspend)(Arena arena); extern void (ShieldResume)(Arena arena); extern void (ShieldFlush)(Arena arena); -#ifdef DISABLE_SHIELD +#if defined(SHIELD) +/* Nothing to do: functions declared in all shield configurations. */ +#elif defined(SHIELD_NONE) #define ShieldRaise(arena, seg, mode) \ BEGIN UNUSED(arena); UNUSED(seg); UNUSED(mode); END #define ShieldLower(arena, seg, mode) \ @@ -906,7 +910,9 @@ extern void (ShieldFlush)(Arena arena); #define ShieldSuspend(arena) BEGIN UNUSED(arena); END #define ShieldResume(arena) BEGIN UNUSED(arena); END #define ShieldFlush(arena) BEGIN UNUSED(arena); END -#endif /* DISABLE_SHIELD */ +#else +#error "No shield configuration." +#endif /* SHIELD */ /* Protection Interface diff --git a/mps/code/mps.c b/mps/code/mps.c index 2125d2d4a3c..200f63e894c 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -91,7 +91,7 @@ /* ANSI Plinth */ -#if !defined(PLINTH_NONE) /* see CONFIG_PLINTH_NONE in config.h */ +#if defined(PLINTH) /* see CONFIG_PLINTH_NONE in config.h */ #include "mpsliban.c" #include "mpsioan.c" #endif diff --git a/mps/code/seg.c b/mps/code/seg.c index dea2b7d7ff7..62a7397dfeb 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -309,12 +309,17 @@ void SegSetSummary(Seg seg, RefSet summary) AVERT(Seg, seg); AVER(summary == RefSetEMPTY || SegRankSet(seg) != RankSetEMPTY); -#ifdef DISABLE_REMEMBERED_SET +#if defined(REMEMBERED_SET) +/* Nothing to do. */ +#elif defined(REMEMBERED_SET_NONE) /* Without protection, we can't maintain the remembered set because there are writes we don't know about. TODO: rethink this when implementating control. */ summary = RefSetUNIV; -#endif +#else +#error "No remembered set configuration." +#endif /* REMEMBERED_SET */ + if (summary != SegSummary(seg)) seg->class->setSummary(seg, summary); } From 4ac5e3a9ceba2c344590b19d9e27b18e5d53593b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 16 Apr 2014 10:55:39 +0100 Subject: [PATCH 098/266] Oops: sense of test was wrong way round. Copied from Perforce Change: 185581 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 10 +++++----- mps/code/mpm.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index d68d1b52361..a4d8da21eb2 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -173,7 +173,7 @@ * can be defined as no-ops by lock.h. */ -#if defined(CONFIG_THREAD_SINGLE) +#if !defined(CONFIG_THREAD_SINGLE) #define LOCK #else #define LOCK_NONE @@ -190,13 +190,13 @@ * mpm.h. */ -#if defined(CONFIG_POLL_NONE) -#if !defined(CONFIG_THREAD_SINGLE) -#error "CONFIG_POLL_NONE without CONFIG_THREAD_SINGLE" -#endif +#if !defined(CONFIG_POLL_NONE) #define REMEMBERED_SET #define SHIELD #else +#if !defined(CONFIG_THREAD_SINGLE) +#error "CONFIG_POLL_NONE without CONFIG_THREAD_SINGLE" +#endif #define REMEMBERED_SET_NONE #define SHIELD_NONE #endif diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 8c030acaa77..8ed0d6aa608 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -525,12 +525,12 @@ extern void (ArenaLeave)(Arena arena); extern void (ArenaPoll)(Globals globals); #if defined(SHIELD) +#define ArenaEnter(arena) ArenaEnterLock(arena, FALSE) +#define ArenaLeave(arena) ArenaLeaveLock(arena, FALSE) +#elif defined(SHIELD_NONE) #define ArenaEnter(arena) UNUSED(arena) #define ArenaLeave(arena) AVER(arena->busyTraces == TraceSetEMPTY) #define ArenaPoll(globals) UNUSED(globals) -#elif defined(SHIELD_NONE) -#define ArenaEnter(arena) ArenaEnterLock(arena, FALSE) -#define ArenaLeave(arena) ArenaLeaveLock(arena, FALSE) #else #error "No shield configuration." #endif /* SHIELD */ From 66554a8b42746e6924b6d13d16ceed462464822b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 16 Apr 2014 11:19:55 +0100 Subject: [PATCH 099/266] Put cbsfindinzones back where it was (moving it broke the build). Copied from Perforce Change: 185584 ServerID: perforce.ravenbrook.com --- mps/code/cbs.c | 139 +++++++++++++++++++++++++------------------------ 1 file changed, 70 insertions(+), 69 deletions(-) diff --git a/mps/code/cbs.c b/mps/code/cbs.c index 8531fa0673b..177388bc0cb 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -925,75 +925,6 @@ static Bool cbsTestTreeInZones(SplayTree splay, Tree tree, && ZoneSetInter(zonedBlock->zones, closure->zoneSet) != ZoneSetEMPTY; } -static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn, - Land land, Size size, - ZoneSet zoneSet, Bool high) -{ - CBS cbs; - Tree tree; - cbsTestNodeInZonesClosureStruct closure; - Res res; - LandFindMethod landFind; - SplayFindMethod splayFind; - - AVER(rangeReturn != NULL); - AVER(oldRangeReturn != NULL); - AVERT(Land, land); - cbs = cbsOfLand(land); - AVERT(CBS, cbs); - AVER(IsLandSubclass(cbsLand(cbs), CBSZonedLandClass)); - /* AVERT(ZoneSet, zoneSet); */ - AVER(BoolCheck(high)); - - landFind = high ? cbsFindLast : cbsFindFirst; - splayFind = high ? SplayFindLast : SplayFindFirst; - - if (zoneSet == ZoneSetEMPTY) - return ResFAIL; - if (zoneSet == ZoneSetUNIV) { - FindDelete fd = high ? FindDeleteHIGH : FindDeleteLOW; - if ((*landFind)(rangeReturn, oldRangeReturn, land, size, fd)) - return ResOK; - else - return ResFAIL; - } - if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(LandArena(land))) - return ResFAIL; - - /* It would be nice if there were a neat way to eliminate all runs of - zones in zoneSet too small for size.*/ - - closure.arena = LandArena(land); - closure.zoneSet = zoneSet; - closure.size = size; - closure.high = high; - if (splayFind(&tree, cbsSplay(cbs), - cbsTestNodeInZones, - cbsTestTreeInZones, - &closure, sizeof(closure))) { - CBSBlock block = cbsBlockOfTree(tree); - RangeStruct rangeStruct, oldRangeStruct; - - AVER(CBSBlockBase(block) <= closure.base); - AVER(AddrOffset(closure.base, closure.limit) >= size); - AVER(ZoneSetSub(ZoneSetOfRange(LandArena(land), closure.base, closure.limit), zoneSet)); - AVER(closure.limit <= CBSBlockLimit(block)); - - if (!high) - RangeInit(&rangeStruct, closure.base, AddrAdd(closure.base, size)); - else - RangeInit(&rangeStruct, AddrSub(closure.limit, size), closure.limit); - res = cbsDelete(&oldRangeStruct, land, &rangeStruct); - if (res == ResOK) { /* enough memory to split block */ - RangeCopy(rangeReturn, &rangeStruct); - RangeCopy(oldRangeReturn, &oldRangeStruct); - } - } else - res = ResFAIL; - - return res; -} - /* cbsFindLast -- find the last block of at least the given size */ @@ -1075,6 +1006,76 @@ static Bool cbsFindLargest(Range rangeReturn, Range oldRangeReturn, } +static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn, + Land land, Size size, + ZoneSet zoneSet, Bool high) +{ + CBS cbs; + Tree tree; + cbsTestNodeInZonesClosureStruct closure; + Res res; + LandFindMethod landFind; + SplayFindMethod splayFind; + + AVER(rangeReturn != NULL); + AVER(oldRangeReturn != NULL); + AVERT(Land, land); + cbs = cbsOfLand(land); + AVERT(CBS, cbs); + AVER(IsLandSubclass(cbsLand(cbs), CBSZonedLandClass)); + /* AVERT(ZoneSet, zoneSet); */ + AVER(BoolCheck(high)); + + landFind = high ? cbsFindLast : cbsFindFirst; + splayFind = high ? SplayFindLast : SplayFindFirst; + + if (zoneSet == ZoneSetEMPTY) + return ResFAIL; + if (zoneSet == ZoneSetUNIV) { + FindDelete fd = high ? FindDeleteHIGH : FindDeleteLOW; + if ((*landFind)(rangeReturn, oldRangeReturn, land, size, fd)) + return ResOK; + else + return ResFAIL; + } + if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(LandArena(land))) + return ResFAIL; + + /* It would be nice if there were a neat way to eliminate all runs of + zones in zoneSet too small for size.*/ + + closure.arena = LandArena(land); + closure.zoneSet = zoneSet; + closure.size = size; + closure.high = high; + if (splayFind(&tree, cbsSplay(cbs), + cbsTestNodeInZones, + cbsTestTreeInZones, + &closure, sizeof(closure))) { + CBSBlock block = cbsBlockOfTree(tree); + RangeStruct rangeStruct, oldRangeStruct; + + AVER(CBSBlockBase(block) <= closure.base); + AVER(AddrOffset(closure.base, closure.limit) >= size); + AVER(ZoneSetSub(ZoneSetOfRange(LandArena(land), closure.base, closure.limit), zoneSet)); + AVER(closure.limit <= CBSBlockLimit(block)); + + if (!high) + RangeInit(&rangeStruct, closure.base, AddrAdd(closure.base, size)); + else + RangeInit(&rangeStruct, AddrSub(closure.limit, size), closure.limit); + res = cbsDelete(&oldRangeStruct, land, &rangeStruct); + if (res == ResOK) { /* enough memory to split block */ + RangeCopy(rangeReturn, &rangeStruct); + RangeCopy(oldRangeReturn, &oldRangeStruct); + } + } else + res = ResFAIL; + + return res; +} + + /* cbsDescribe -- describe a CBS * * See . From bca0a066fb6071e79335fcc4b0a76b65b7f0e5c5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 16 Apr 2014 13:23:56 +0100 Subject: [PATCH 100/266] Avoid avers with side effects, as requested by rb in Copied from Perforce Change: 185595 ServerID: perforce.ravenbrook.com --- mps/code/poolams.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/mps/code/poolams.c b/mps/code/poolams.c index d769630f009..8c1db1e990e 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -172,9 +172,14 @@ static Res amsCreateTables(AMS ams, BT *allocReturn, goto failWhite; } - /* Invalidate the colour tables in checking varieties. */ - AVER((BTResRange(nongreyTable, 0, length), TRUE)); - AVER((BTSetRange(nonwhiteTable, 0, length), TRUE)); +#if defined(AVER_AND_CHECK) + /* Invalidate the colour tables in checking varieties. The algorithm + * is designed not to depend on the initial values of these tables, + * so by invalidating them we get some checking of this. + */ + BTResRange(nongreyTable, 0, length); + BTSetRange(nonwhiteTable, 0, length); +#endif *allocReturn = allocTable; *nongreyReturn = nongreyTable; From 96f104609fa8ea96c49e14de553c24cc75d322f9 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 16 Apr 2014 13:42:46 +0100 Subject: [PATCH 101/266] Good,bad are better names than first,last for the arguments to p4-bisect start. Copied from Perforce Change: 185601 ServerID: perforce.ravenbrook.com --- mps/tool/p4-bisect | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mps/tool/p4-bisect b/mps/tool/p4-bisect index 97ff39dad74..5fa77639e30 100755 --- a/mps/tool/p4-bisect +++ b/mps/tool/p4-bisect @@ -83,12 +83,12 @@ def start(args): changes = sorted(int(c['change']) for c in p4.run('changes', *args.filespec)) if not changes: error("No changes for {}".format(' '.join(args.filespec))) - if args.first is None: - args.first = changes[0] - if args.last is None: - args.last = changes[-1] + if args.good is None: + args.good = changes[0] + if args.bad is None: + args.bad = changes[-1] state = State(filespec=args.filespec, - changes=[c for c in changes if args.first <= c <= args.last]) + changes=[c for c in changes if args.good <= c <= args.bad]) state.update() def good(args): @@ -140,11 +140,11 @@ def main(argv): start_parser = a('start', help='start a p4-bisect session') aa = start_parser.add_argument start_parser.add_argument('-f', '--filespec', action='append', - help='filespec to search') - start_parser.add_argument('first', nargs='?', type=int, - help='earliest changelevel to examine') - start_parser.add_argument('last', nargs='?', type=int, - help='latest changelevel to examine') + help='filespec(s) to search') + start_parser.add_argument('good', nargs='?', type=int, + help='known good changelevel') + start_parser.add_argument('bad', nargs='?', type=int, + help='known bad changelevel') start_parser.set_defaults(func=start) good_parser = a('good', help='declare current revision good') From 1e432589338740fad59f5c91a3af4aea7960d1e2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 16 Apr 2014 13:59:33 +0100 Subject: [PATCH 102/266] Explain reasoning in amsbufferempty, as requested by rb . Copied from Perforce Change: 185603 ServerID: perforce.ravenbrook.com --- mps/code/poolams.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/mps/code/poolams.c b/mps/code/poolams.c index 8c1db1e990e..65b2dcf754f 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -1037,7 +1037,19 @@ static void AMSBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit) AVER(limitIndex <= amsseg->firstFree); if (limitIndex == amsseg->firstFree) /* is it at the end? */ { amsseg->firstFree = initIndex; - } else if (!ams->shareAllocTable || !amsseg->colourTablesInUse) { + } else if (ams->shareAllocTable && amsseg->colourTablesInUse) { + /* The nonwhiteTable is shared with allocTable and in use, so we + * mustn't start using allocTable. In this case we know: 1. the + * segment has been condemned (because colour tables are turned + * on in AMSCondemn); 2. the segment has not yet been reclaimed + * (because colour tables are turned off in AMSReclaim); 3. the + * unused portion of the buffer is black (see AMSCondemn). So we + * need to whiten the unused portion of the buffer. The + * allocTable will be turned back on (if necessary) in + * AMSReclaim, when we know that the nonwhite grains are exactly + * the allocated grains. + */ + } else { /* start using allocTable */ amsseg->allocTableInUse = TRUE; BTSetRange(amsseg->allocTable, 0, amsseg->firstFree); From 195344e6202162953c27fc4710cb8343292a5e44 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 16 Apr 2014 17:04:08 +0100 Subject: [PATCH 103/266] Use "active" rather than "in development" to avoid ugly wrapping in the table. Copied from Perforce Change: 185610 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 686cdefa244..790dceb0eba 100755 --- a/mps/tool/branch +++ b/mps/tool/branch @@ -49,7 +49,7 @@ TASK_BRANCH_ENTRY = ''' {date}/{task} Changes {desc_html} - In development (diffs). + Active (diffs). ''' From 7d651f853791ae8005d7f4b2419fd2c3c283bd6c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 17 Apr 2014 00:11:01 +0100 Subject: [PATCH 104/266] Fix typos. Copied from Perforce Change: 185616 ServerID: perforce.ravenbrook.com --- mps/design/cbs.txt | 3 +-- mps/design/freelist.txt | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mps/design/cbs.txt b/mps/design/cbs.txt index 7ed38d586a1..c0661f2f792 100644 --- a/mps/design/cbs.txt +++ b/mps/design/cbs.txt @@ -121,7 +121,7 @@ _`.limit.find`: ``CBSLandClass`` does not support the generic functions (the subclasses do support these operations). _`.limit.zones`: ``CBSLandClass`` and ``CBSFastLandClass`` do not -support the ``LandFindInZones()`` generic function (the suclass +support the ``LandFindInZones()`` generic function (the subclass ``CBSZonedLandClass`` does support this operation). _`.limit.iterate`: CBS does not support visitors setting @@ -233,7 +233,6 @@ the size of that area. [Four words per two grains.] The CBS structure is thus suitable only for managing large enough ranges. - Document History ---------------- diff --git a/mps/design/freelist.txt b/mps/design/freelist.txt index 344d6e3b34e..f26fd37a891 100644 --- a/mps/design/freelist.txt +++ b/mps/design/freelist.txt @@ -100,7 +100,7 @@ an address-ordered singly linked free list. (As in traditional _`.impl.block`: If the free address range is large enough to contain an inline block descriptor consisting of two pointers, then the two pointers stored are to the next free range in address order (or -``NULL`` if there are no more ranges), and to the limit of current +``NULL`` if there are no more ranges), and to the limit of the current free address range, in that order. _`.impl.grain`: Otherwise, the free address range must be large enough From 230ee1f936f87c207a9601e0d768e5ea32b93310 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 17 Apr 2014 00:19:45 +0100 Subject: [PATCH 105/266] Use freelistend instead of null as the special value. Copied from Perforce Change: 185617 ServerID: perforce.ravenbrook.com --- mps/code/freelist.c | 96 +++++++++++++++++++++++------------------ mps/design/freelist.txt | 11 ++--- 2 files changed, 61 insertions(+), 46 deletions(-) diff --git a/mps/code/freelist.c b/mps/code/freelist.c index 13f83bd4aad..171493544e3 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -29,6 +29,18 @@ typedef union FreelistBlockUnion { } FreelistBlockUnion; +/* freelistEND -- the end of a list + * + * The end of a list should not be represented with NULL, as this is + * ambiguous. However, freelistEND in fact a null pointer for + * performance. To check whether you have it right, try temporarily + * defining freelistEND as ((FreelistBlock)2) or similar (it must be + * an even number because of the use of a tag). + */ + +#define freelistEND ((FreelistBlock)0) + + /* freelistMinimumAlignment -- the minimum allowed alignment for the * address ranges in a free list: see */ @@ -85,7 +97,7 @@ static Bool FreelistBlockCheck(FreelistBlock block) { CHECKL(block != NULL); /* block list is address-ordered */ - CHECKL(FreelistTagReset(block->small.next) == NULL + CHECKL(FreelistTagReset(block->small.next) == freelistEND || block < FreelistTagReset(block->small.next)); CHECKL(FreelistBlockIsSmall(block) || (Addr)block < block->large.limit); @@ -93,8 +105,8 @@ static Bool FreelistBlockCheck(FreelistBlock block) } -/* FreelistBlockNext -- return the next block in the list, or NULL if - * there are no more blocks. +/* FreelistBlockNext -- return the next block in the list, or + * freelistEND if there are no more blocks. */ static FreelistBlock FreelistBlockNext(FreelistBlock block) { @@ -154,7 +166,7 @@ static FreelistBlock FreelistBlockInit(Freelist fl, Addr base, Addr limit) AVER(AddrIsAligned(limit, freelistAlignment(fl))); block = (FreelistBlock)base; - block->small.next = FreelistTagSet(NULL); + block->small.next = FreelistTagSet(freelistEND); FreelistBlockSetLimit(fl, block, limit); AVERT(FreelistBlock, block); return block; @@ -169,8 +181,8 @@ Bool FreelistCheck(Freelist fl) CHECKD(Land, land); /* See */ CHECKL(AlignIsAligned(freelistAlignment(fl), freelistMinimumAlignment)); - CHECKL((fl->list == NULL) == (fl->listSize == 0)); - CHECKL((fl->list == NULL) == (fl->size == 0)); + CHECKL((fl->list == freelistEND) == (fl->listSize == 0)); + CHECKL((fl->list == freelistEND) == (fl->size == 0)); CHECKL(SizeIsAligned(fl->size, freelistAlignment(fl))); return TRUE; @@ -193,7 +205,7 @@ static Res freelistInit(Land land, ArgList args) AVER(AlignIsAligned(LandAlignment(land), freelistMinimumAlignment)); fl = freelistOfLand(land); - fl->list = NULL; + fl->list = freelistEND; fl->listSize = 0; fl->size = 0; @@ -211,7 +223,7 @@ static void freelistFinish(Land land) fl = freelistOfLand(land); AVERT(Freelist, fl); fl->sig = SigInvalid; - fl->list = NULL; + fl->list = freelistEND; } @@ -228,9 +240,9 @@ static Size freelistSize(Land land) /* freelistBlockSetPrevNext -- update list of blocks * - * If prev and next are both NULL, make the block list empty. - * Otherwise, if prev is NULL, make next the first block in the list. - * Otherwise, if next is NULL, make prev the last block in the list. + * If prev and next are both freelistEND, make the block list empty. + * Otherwise, if prev is freelistEND, make next the first block in the list. + * 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'. */ @@ -240,11 +252,13 @@ static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev, { AVERT(Freelist, fl); - if (prev) { - AVER(next == NULL || FreelistBlockLimit(fl, prev) < FreelistBlockBase(next)); - FreelistBlockSetNext(prev, next); - } else { + if (prev == freelistEND) { fl->list = next; + } else { + /* Isolated range invariant (design.mps.freelist.impl.invariant). */ + AVER(next == freelistEND + || FreelistBlockLimit(fl, prev) < FreelistBlockBase(next)); + FreelistBlockSetNext(prev, next); } if (delta < 0) { AVER(fl->listSize >= (Count)-delta); @@ -272,15 +286,15 @@ static Res freelistInsert(Range rangeReturn, Land land, Range range) base = RangeBase(range); limit = RangeLimit(range); - prev = NULL; + prev = freelistEND; cur = fl->list; - while (cur) { + while (cur != freelistEND) { if (base < FreelistBlockLimit(fl, cur) && FreelistBlockBase(cur) < limit) return ResFAIL; /* range overlaps with cur */ if (limit <= FreelistBlockBase(cur)) break; next = FreelistBlockNext(cur); - if (next) + if (next != freelistEND) /* Isolated range invariant (design.mps.freelist.impl.invariant). */ AVER(FreelistBlockLimit(fl, cur) < FreelistBlockBase(next)); prev = cur; @@ -291,8 +305,8 @@ static Res freelistInsert(Range rangeReturn, Land land, Range range) * coalesces then it does so with prev on the left, and cur on the * right. */ - coalesceLeft = (prev && base == FreelistBlockLimit(fl, prev)); - coalesceRight = (cur && limit == FreelistBlockBase(cur)); + coalesceLeft = (prev != freelistEND && base == FreelistBlockLimit(fl, prev)); + coalesceRight = (cur != freelistEND && limit == FreelistBlockBase(cur)); if (coalesceLeft && coalesceRight) { base = FreelistBlockBase(prev); @@ -328,8 +342,8 @@ static Res freelistInsert(Range rangeReturn, Land land, Range range) * * range must be a subset of block. Update rangeReturn to be the * original range of block and update the block list accordingly: prev - * is on the list just before block, or NULL if block is the first - * block on the list. + * is on the list just before block, or freelistEND if block is the + * first block on the list. */ static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl, @@ -343,7 +357,7 @@ static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl, AVERT(Freelist, fl); AVERT(Range, range); AVER(RangeIsAligned(range, freelistAlignment(fl))); - AVER(prev == NULL || FreelistBlockNext(prev) == block); + AVER(prev == freelistEND || FreelistBlockNext(prev) == block); AVERT(FreelistBlock, block); AVER(FreelistBlockBase(block) <= RangeBase(range)); AVER(RangeLimit(range) <= FreelistBlockLimit(fl, block)); @@ -397,9 +411,9 @@ static Res freelistDelete(Range rangeReturn, Land land, Range range) base = RangeBase(range); limit = RangeLimit(range); - prev = NULL; + prev = freelistEND; cur = fl->list; - while (cur) { + while (cur != freelistEND) { Addr blockBase, blockLimit; blockBase = FreelistBlockBase(cur); blockLimit = FreelistBlockLimit(fl, cur); @@ -434,9 +448,9 @@ static void freelistIterate(Land land, LandVisitor visitor, AVERT(Freelist, fl); AVER(FUNCHECK(visitor)); - prev = NULL; + prev = freelistEND; cur = fl->list; - while (cur) { + while (cur != freelistEND) { Bool delete = FALSE; RangeStruct range; Bool cont; @@ -465,8 +479,8 @@ static void freelistIterate(Land land, LandVisitor visitor, * instruction in findDelete. Return the range of that chunk in * rangeReturn. Return the original range of the block in * oldRangeReturn. Update the block list accordingly, using prev, - * which is previous in list or NULL if block is the first block in - * the list. + * which is previous in list or freelistEND if block is the first + * block in the list. */ static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn, @@ -482,7 +496,7 @@ static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn, AVERT(Freelist, fl); AVER(SizeIsAligned(size, freelistAlignment(fl))); AVERT(FindDelete, findDelete); - AVER(prev == NULL || FreelistBlockNext(prev) == block); + AVER(prev == freelistEND || FreelistBlockNext(prev) == block); AVERT(FreelistBlock, block); AVER(FreelistBlockSize(fl, block) >= size); @@ -534,9 +548,9 @@ static Bool freelistFindFirst(Range rangeReturn, Range oldRangeReturn, AVER(SizeIsAligned(size, freelistAlignment(fl))); AVERT(FindDelete, findDelete); - prev = NULL; + prev = freelistEND; cur = fl->list; - while (cur) { + while (cur != freelistEND) { if (FreelistBlockSize(fl, cur) >= size) { freelistFindDeleteFromBlock(rangeReturn, oldRangeReturn, fl, size, findDelete, prev, cur); @@ -557,7 +571,7 @@ static Bool freelistFindLast(Range rangeReturn, Range oldRangeReturn, Freelist fl; Bool found = FALSE; FreelistBlock prev, cur, next; - FreelistBlock foundPrev = NULL, foundCur = NULL; + FreelistBlock foundPrev = freelistEND, foundCur = freelistEND; AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); @@ -567,9 +581,9 @@ static Bool freelistFindLast(Range rangeReturn, Range oldRangeReturn, AVER(SizeIsAligned(size, freelistAlignment(fl))); AVERT(FindDelete, findDelete); - prev = NULL; + prev = freelistEND; cur = fl->list; - while (cur) { + while (cur != freelistEND) { if (FreelistBlockSize(fl, cur) >= size) { found = TRUE; foundPrev = prev; @@ -594,7 +608,7 @@ static Bool freelistFindLargest(Range rangeReturn, Range oldRangeReturn, Freelist fl; Bool found = FALSE; FreelistBlock prev, cur, next; - FreelistBlock bestPrev = NULL, bestCur = NULL; + FreelistBlock bestPrev = freelistEND, bestCur = freelistEND; AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); @@ -603,9 +617,9 @@ static Bool freelistFindLargest(Range rangeReturn, Range oldRangeReturn, AVERT(Freelist, fl); AVERT(FindDelete, findDelete); - prev = NULL; + prev = freelistEND; cur = fl->list; - while (cur) { + while (cur != freelistEND) { if (FreelistBlockSize(fl, cur) >= size) { found = TRUE; size = FreelistBlockSize(fl, cur); @@ -634,7 +648,7 @@ static Res freelistFindInZones(Range rangeReturn, Range oldRangeReturn, RangeInZoneSet search; Bool found = FALSE; FreelistBlock prev, cur, next; - FreelistBlock foundPrev = NULL, foundCur = NULL; + FreelistBlock foundPrev = freelistEND, foundCur = freelistEND; RangeStruct foundRange; AVER(FALSE); /* TODO: this code is completely untested! */ @@ -661,9 +675,9 @@ static Res freelistFindInZones(Range rangeReturn, Range oldRangeReturn, if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(LandArena(land))) return ResFAIL; - prev = NULL; + prev = freelistEND; cur = fl->list; - while (cur) { + while (cur != freelistEND) { Addr base, limit; if ((*search)(&base, &limit, FreelistBlockBase(cur), FreelistBlockLimit(fl, cur), diff --git a/mps/design/freelist.txt b/mps/design/freelist.txt index f26fd37a891..b0654468de1 100644 --- a/mps/design/freelist.txt +++ b/mps/design/freelist.txt @@ -100,12 +100,13 @@ an address-ordered singly linked free list. (As in traditional _`.impl.block`: If the free address range is large enough to contain an inline block descriptor consisting of two pointers, then the two pointers stored are to the next free range in address order (or -``NULL`` if there are no more ranges), and to the limit of the current -free address range, in that order. +``freelistEND`` if there are no more ranges), and to the limit of the +current free address range, in that order. _`.impl.grain`: Otherwise, the free address range must be large enough to contain a single pointer. The pointer stored is to the next free -range in address order, or ``NULL`` if there are no more ranges. +range in address order, or ``freelistEND`` if there are no more +ranges. _`.impl.tag`: Grains and blocks are distinguished by a one-bit tag in the low bit of the first word (the one containing the pointer to the @@ -118,8 +119,8 @@ _`.impl.merge`: When a free address range is added to the free list, it is merged with adjacent ranges so as to maintain `.impl.invariant`_. -_`.impl.rule.break`: The use of ``NULL`` to mark the end of the list -violates the rule that exceptional values should not be used to +_`.impl.rule.break`: The use of ``freelistEND`` to mark the end of the +list violates the rule that exceptional values should not be used to distinguish exeptional situations. This infraction allows the implementation to meet `.req.zero-overhead`_. (There are other ways to do this, such as using another tag to indicate the last block in the From c17907476261cd01b50672d51891564ac792216c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 17 Apr 2014 18:03:18 +0100 Subject: [PATCH 106/266] Test script that clones and builds emscripten. Copied from Perforce Change: 185642 ServerID: perforce.ravenbrook.com --- mps/tool/testemscripten | 137 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100755 mps/tool/testemscripten diff --git a/mps/tool/testemscripten b/mps/tool/testemscripten new file mode 100755 index 00000000000..4639e9e69a4 --- /dev/null +++ b/mps/tool/testemscripten @@ -0,0 +1,137 @@ +#!/bin/sh +# +# Ravenbrook +# +# +# TESTEMSCRIPTEN -- TEST THE MPS WITH EMSCRIPTEN +# +# Gareth Rees, Ravenbrook Limited, 2014-04-17 +# +# +# 1. INTRODUCTION +# +# This shell script pulls Emscripten from GitHub and uses it to build +# the MPS. +# +# Supported platforms: ?. +# +# +# 1.1. PREREQUISITES +# +# clang, curl, git, nodejs +# +# "python" needs to be Python 2 (otherwise configure fails), so you +# may need to run: +# +# port select --set python python27 +# +# You need to have a program "python2" on your path (which runs Python +# 2.7.3), so on OS X with MacPorts you need to run: +# +# ln -s /opt/local/bin/python2.7 /opt/local/bin/python2 + + +# 2. CONFIGURATION + +# Emscripten git repository +EMSCRIPTEN_REMOTE=https://github.com/kripken/emscripten.git + +# Fastcomp git repository +FASTCOMP_REMOTE=https://github.com/kripken/emscripten-fastcomp.git + +# Fastcomp clang git repository +CLANG_REMOTE=https://github.com/kripken/emscripten-fastcomp-clang + +# Directory to put everything in +TESTDIR="$PWD/.test" +mkdir -p -- "$TESTDIR" +cd -- "$TESTDIR" + + +# 3. UTILITIES + +# 3.1. checkout REPO REMOTE -- clone a git repository and pull + +checkout () { + REPO=$1 + REMOTE=$2 + if [ -d "$REPO" ]; then + echo "$REPO exists: skipping clone." + else + echo "cloning $REMOTE into $REPO." + git clone --recursive -- "$REMOTE" "$REPO" + fi + ( + cd -- "$REPO" + git pull + ) +} + + +# 4. PROCEDURE + +checkout emscripten "$EMSCRIPTEN_REMOTE" + + +# See [FASTCOMP]. + +checkout emscripten-fastcomp "$FASTCOMP_REMOTE" +( + cd emscripten-fastcomp + ( + cd tools + checkout clang "$CLANG_REMOTE"; + ) + mkdir -p build + ( + cd build + ../configure --enable-optimized --disable-assertions --enable-targets=host,js + make; + ) +) + + +# A. REFERENCES +# +# [EMPSCRIPTEN] "Emscripten SDK" +# +# +# [FASTCOMP] "LLVM Backend, aka fastcomp" +# +# +# +# B. DOCUMENT HISTORY +# +# 2014-04-17 GDR Created based on [EMSCRIPTEN] and [FASTCOMP]. +# +# +# C. COPYRIGHT AND LICENCE +# +# Copyright (c) 2014 Ravenbrook Ltd. All rights reserved. +# +# 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. +# +# 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 AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +# 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. +# +# +# $Id$ From 0c292ada722c7e1fbb4c9c204869ad92998a35c6 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 17 Apr 2014 23:39:45 +0100 Subject: [PATCH 107/266] Fix typo. Copied from Perforce Change: 185645 ServerID: perforce.ravenbrook.com --- mps/design/splay.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/design/splay.txt b/mps/design/splay.txt index 8e8b02e292c..4290b703ac1 100644 --- a/mps/design/splay.txt +++ b/mps/design/splay.txt @@ -103,7 +103,7 @@ general inferred MPS requirements. _`.req.order`: Must maintain a set of abstract keys which is totally ordered for a comparator. -_`.req.splay`: Common operations must have low amortized cost. +_`.req.fast`: Common operations must have low amortized cost. _`.req.add`: Must be able to add new nodes. This is a common operation. From 33944478501e1756edce661d38fc7446f27f65f4 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 17 Apr 2014 23:40:07 +0100 Subject: [PATCH 108/266] Function now called rangecopy. Copied from Perforce Change: 185646 ServerID: perforce.ravenbrook.com --- mps/design/range.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/design/range.txt b/mps/design/range.txt index bf0f924430e..1b42d69ac22 100644 --- a/mps/design/range.txt +++ b/mps/design/range.txt @@ -51,7 +51,7 @@ between ``base`` (inclusive) and ``limit`` (exclusive). It must be the case that ``base <= limit``. If ``base == limit`` then the range is empty. -``void RangeInitCopy(Range dest, Range src)`` +``void RangeCopy(Range dest, Range src)`` Initialize ``dest`` to be a copy of ``src``. From e90f3b7f4dd59acb20bb5fef184608b919589e31 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 17 Apr 2014 23:41:09 +0100 Subject: [PATCH 109/266] Explain how to declare and update boolean bitfields. SegPrefs are not necessarily to do with segments. Copied from Perforce Change: 185647 ServerID: perforce.ravenbrook.com --- mps/design/type.txt | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/mps/design/type.txt b/mps/design/type.txt index 6ce0da3c035..900980970dc 100644 --- a/mps/design/type.txt +++ b/mps/design/type.txt @@ -151,6 +151,14 @@ compared ``w3i3mv\hi\amcss.exe`` running with and without the macro for ``BoolCheck`` on the PC Aaron. "With" ran in 97.7% of the time (averaged over 3 runs). +_`.bool.bitfield`: When a Boolean needs to be stored in a bitfield, +the type of the bitfield must be ``unsigned:1``, not ``Bool:1``. +(That's because the two values of the type ``Bool:1`` are ``0`` and +``-1``, which means that assigning ``TRUE`` would require a sign +conversion.) To avoid warnings about loss of data from GCC with the +``-Wconversion`` option, ``misc.h`` provides the ``BOOL`` macro for +coercing a value to an unsigned single-bit field. + ``typedef unsigned BufferMode`` @@ -235,7 +243,8 @@ objects. ``typedef Size Epoch`` _`.epoch`: An ``Epoch`` is a count of the number of flips that have -occurred. It is used in the implementation of location dependencies. +occurred, in which objects may have moved. It is used in the +implementation of location dependencies. ``Epoch`` is converted to ``mps_word_t`` in the MPS C Interface, as a field of ``mps_ld_s``. @@ -351,7 +360,7 @@ references must be scanned in order to respect the properties of references of the ranks. Therefore they are declared explicitly with their integer values. -.. note:: Could ``Rank`` be a ``short``? +.. note:: Could ``Rank`` be an ``unsigned short`` or ``unsigned char``? .. note:: @@ -459,30 +468,35 @@ create a valid registered constant root that contains any references. become invalid; but you can't add them afterwards because the root is supposed to be constant.) -_`.rootmode.conv.c`: ``RootMode`` is converted to ``mps_rm_t`` in the MPS C -Interface. +_`.rootmode.conv.c`: ``RootMode`` is converted to ``mps_rm_t`` in the +MPS C Interface. ``typedef int RootVar`` -_`.rootvar`: The type ``RootVar`` is the type of the -discriminator for the union within ``RootStruct``. +_`.rootvar`: The type ``RootVar`` is the type of the discriminator for +the union within ``RootStruct``. ``typedef int SegPrefKind`` -_`.segprefkind`: The type ``SegPrefKind`` expresses a preference about -where the arena should place a segment. It takes one of the following +_`.segprefkind`: The type ``SegPrefKind`` expresses a preference for +addresses within an address space. It takes one of the following values: ================== ==================================================== Kind Description ================== ==================================================== -``SegPrefHigh`` Place the segment high in the address space. -``SegPrefLow`` Place the segment low in the address space. -``SegPrefZoneSet`` Place the segment in specified zones. +``SegPrefHigh`` Prefer high addresses. +``SegPrefLow`` Prefer low addresses. +``SegPrefZoneSet`` Prefer addresses in specified zones. ================== ==================================================== +.. note:: + + The name is misleading as this is used to refer to address + preferences in general, not just addresses of segments. + ``typedef unsigned Serial`` @@ -490,9 +504,8 @@ _`.serial`: A ``Serial`` is a number which is assigned to a structure when it is initialized. The serial number is taken from a field in the parent structure, which is incremented. Thus, every instance of a structure has a unique "name" which is a path of structures from the -global root. For example:: - - space[3].pool[5].buffer[2] +global root. For example, "the third arena's fifth pool's second +buffer". Why? Consistency checking, debugging, and logging. Not well thought out. @@ -509,6 +522,8 @@ right-hand operand of the ``<<`` or ``>>`` operators) is intended, to make the code clear. It should also be used for structure fields which have this use. +.. note:: Could ``Shift`` be an ``unsigned short`` or ``unsigned char``? + ``typedef unsigned long Sig`` @@ -640,7 +655,7 @@ _`.word.ops`: ``WordIsAligned()``, ``WordAlignUp()``, ``typedef Word ZoneSet`` _`.zoneset`: ``ZoneSet`` is a conservative approximation to a set of -zone. See design.mps.refset_. +zones. See design.mps.refset_. Abstract types From 610909ca66964a2c3b5dc9d27503cd62a40dbde5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 17 Apr 2014 23:41:18 +0100 Subject: [PATCH 110/266] Learn some more types. Copied from Perforce Change: 185648 ServerID: perforce.ravenbrook.com --- mps/manual/source/extensions/mps/designs.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mps/manual/source/extensions/mps/designs.py b/mps/manual/source/extensions/mps/designs.py index 57959f1ea0c..230594e9392 100644 --- a/mps/manual/source/extensions/mps/designs.py +++ b/mps/manual/source/extensions/mps/designs.py @@ -22,10 +22,11 @@ Arena Attr Bool BootBlock BT Buffer BufferMode Byte Chain Chunk Clock Compare Count Epoch FindDelete Format FrameState Fun Globals Index Land LD Lock Message MessageType MutatorFaultContext Page - Pointer Pool PThreadext Range Rank RankSet Ref Res Reservoir Ring - Root RootMode RootVar ScanState Seg SegBuf SegPref SegPrefKind - Serial Shift Sig Size Space SplayNode SplayTree StackContext - Thread Trace TraceId TraceSet ULongest VM Word ZoneSet + Pointer Pool PThreadext Range Rank RankSet Ref RefSet Res + Reservoir Ring Root RootMode RootVar ScanState Seg SegBuf SegPref + SegPrefKind Serial Shift Sig Size Space SplayNode SplayTree + StackContext Thread Trace TraceId TraceSet TraceStartWhy + TraceState ULongest VM Word ZoneSet ''' From b6c1faff3502eff43ac03d241afc7adcd9620098 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 18 Apr 2014 00:41:33 +0100 Subject: [PATCH 111/266] Fix typo. Copied from Perforce Change: 185649 ServerID: perforce.ravenbrook.com --- mps/manual/source/pool/awl.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mps/manual/source/pool/awl.rst b/mps/manual/source/pool/awl.rst index 79df0258804..094335ba3b8 100644 --- a/mps/manual/source/pool/awl.rst +++ b/mps/manual/source/pool/awl.rst @@ -283,9 +283,9 @@ the format of objects allocated in it: "Aligned pointer" means a word whose numeric value (that is, its value when treated as an unsigned integer) is a multiple of the size - of a pointer. For you're using a 32-bit architecture, that means - that an aligned pointer is a multiple of 4 and its bottom two bits - are both zero. + of a pointer. If you're using a 64-bit architecture, that means that + an aligned pointer is a multiple of 8 and its bottom three bits are + zero. The bottom line is that references from an object in an AWL pool must be untagged and aligned, and integers must be tagged with a From a591006905814aa14cb38f539d7f9f9e00bc3205 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 18 Apr 2014 08:55:26 +0100 Subject: [PATCH 112/266] Building open dylan side by side with boehm or mps. Copied from Perforce Change: 185650 ServerID: perforce.ravenbrook.com --- mps/tool/testopendylan | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/mps/tool/testopendylan b/mps/tool/testopendylan index a8aee4a0025..0c185ff2fd0 100755 --- a/mps/tool/testopendylan +++ b/mps/tool/testopendylan @@ -20,8 +20,21 @@ # 2. CONFIGURATION -# MPS sources we are testing against -MPS=$(cd -- "$(dirname "$0")/.." && pwd) +# Check command-line argument +GC=$1 +case "$GC" in + mps) + # MPS sources we are testing against + CONFIGURE=--with-gc-path=$(cd -- "$(dirname "$0")/.." && pwd) + ;; + boehm) + CONFIGURE= + ;; + *) + echo "Backend '$GC' not supported: choose mps or boehm." + exit 1 +esac + # OpenDylan version for bootstrapping VERSION=2013.2 @@ -30,7 +43,7 @@ VERSION=2013.2 REMOTE=https://github.com/dylan-lang/opendylan.git # Directory to put everything in -TESTDIR="$PWD/.test" +TESTDIR="$PWD/.test/$GC" mkdir -p -- "$TESTDIR" cd -- "$TESTDIR" @@ -104,7 +117,7 @@ if [ -f "$REPO/Makefile" ]; then else ( cd -- "$REPO" && ./autogen.sh && - ./configure --with-gc=mps --with-gc-path="$MPS" --prefix="$PREFIX" + ./configure --with-gc="$GC" --prefix="$PREFIX" $CONFIGURE ) fi ( cd -- "$REPO" && From 6f13e1c1309a7d367e905c100b5ad64ace6ac409 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 18 Apr 2014 10:24:36 +0100 Subject: [PATCH 113/266] Fix typo. Copied from Perforce Change: 185659 ServerID: perforce.ravenbrook.com --- mps/procedure/release-build.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mps/procedure/release-build.rst b/mps/procedure/release-build.rst index bdce60df4ca..ee65b5f645d 100644 --- a/mps/procedure/release-build.rst +++ b/mps/procedure/release-build.rst @@ -47,7 +47,7 @@ All relative paths are relative to 1.111.0), where *VERSION* is the number of the version you’re releasing, and *N* is the first unused release number (starting at zero). Look in the index of releases (``release/index.html``) for - existing release numbers for your version:: + existing release numbers for your version. :: VERSION=A.BBB RELEASE=$VERSION.N @@ -111,7 +111,7 @@ Run the script ``tool/release``, passing the options: * ``-P mps`` — project name * ``-b BRANCH`` — branch to make the release from: for example ``version/1.113`` * ``-C CHANGELEVEL`` — changelevel at which to make the release -* ``-d "DESCRIPTION"`` — changelevel at which to make the release +* ``-d "DESCRIPTION"`` — description of the release * ``-y`` — yes, really make the release If omitted, the project and branch are deduced from the current @@ -231,8 +231,6 @@ A. References Ravenbrook Limited; 2008-10-16; http://info.ravenbrook.com/mail/2008/10/16/13-08-20/0.txt -.. [Sphinx] "Sphinx: Python document generator"; http://sphinx-doc.org/ - B. Document History ------------------- From 3e00005a6a04910b3650b869581cb4c2d3402bd3 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 20 Apr 2014 22:53:49 +0100 Subject: [PATCH 114/266] Improve help text. Copied from Perforce Change: 185701 ServerID: perforce.ravenbrook.com --- mps/tool/p4-bisect | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mps/tool/p4-bisect b/mps/tool/p4-bisect index 5fa77639e30..2886d823c59 100755 --- a/mps/tool/p4-bisect +++ b/mps/tool/p4-bisect @@ -130,7 +130,9 @@ def run(args): exit(result) def main(argv): - parser = argparse.ArgumentParser(prog='p4-bisect') + parser = argparse.ArgumentParser( + prog='p4-bisect', epilog='For help on CMD, use p4-bisect CMD -h') + parser.set_defaults(func=partial(help, parser)) subparsers = parser.add_subparsers() a = subparsers.add_parser From 4cca37c61cfafbaaa3aa5c87629a2ab5fdbbf277 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 22 Apr 2014 14:45:51 +0100 Subject: [PATCH 115/266] Branching master to branch/2014-04-22/condemn. Copied from Perforce Change: 185735 ServerID: perforce.ravenbrook.com From e7d41a8fdeae24d55b46364563f60bdc79d7355c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 22 Apr 2014 17:53:47 +0100 Subject: [PATCH 116/266] Fix bugs in condemn logic: 1. TraceStartCollectAll now condemns all segments in pools with AttrGC (not just pools attached to generation zero of some chain, as before). 2. ChainDeferral now looks at all generations in the chain, so that the chain is condemned if any generation's new size is greater than its capacity (not just generation zero, as before). 3. ChainCondemnAuto now condemns all generations up to and including the highest generation whose new size is greater than its capacity (rather than, as before, up to and excluding the lowest generation whose new size is lower than its capacity). Update finaltest.c so that it has a mode in which it allocates in generation 1 of a chain and with the arena released so that the above fixes are tested. Remove the MPS_KEY_GEN workarounds from awlut and awluthe as these are no longer needed. Copied from Perforce Change: 185741 ServerID: perforce.ravenbrook.com --- mps/code/awlut.c | 3 -- mps/code/awluthe.c | 3 -- mps/code/chain.h | 1 - mps/code/finaltest.c | 104 +++++++++++++++++++++++++++++++++---------- mps/code/locus.c | 100 +++++++++++++++++------------------------ mps/code/trace.c | 28 ++++++++---- 6 files changed, 140 insertions(+), 99 deletions(-) diff --git a/mps/code/awlut.c b/mps/code/awlut.c index c62153ed44c..464a2dba91f 100644 --- a/mps/code/awlut.c +++ b/mps/code/awlut.c @@ -275,9 +275,6 @@ static void *setup(void *v, size_t s) die(mps_fmt_create_A(&dylanweakfmt, arena, dylan_fmt_A_weak()), "Format Create (weak)\n"); MPS_ARGS_BEGIN(args) { - /* Ask the leafpool to allocate in the nursery, as we're using it to test - weaknesss and want things to die in it promptly. */ - MPS_ARGS_ADD(args, MPS_KEY_GEN, 0); MPS_ARGS_ADD(args, MPS_KEY_FORMAT, dylanfmt); die(mps_pool_create_k(&leafpool, arena, mps_class_lo(), args), "Leaf Pool Create\n"); diff --git a/mps/code/awluthe.c b/mps/code/awluthe.c index d3b2d572319..6ea468977f1 100644 --- a/mps/code/awluthe.c +++ b/mps/code/awluthe.c @@ -277,9 +277,6 @@ static void *setup(void *v, size_t s) die(EnsureHeaderFormat(&dylanfmt, arena), "EnsureHeaderFormat"); die(EnsureHeaderWeakFormat(&dylanweakfmt, arena), "EnsureHeaderWeakFormat"); MPS_ARGS_BEGIN(args) { - /* Ask the leafpool to allocate in the nursery, as we're using it to test - weaknesss and want things to die in it promptly. */ - MPS_ARGS_ADD(args, MPS_KEY_GEN, 0); MPS_ARGS_ADD(args, MPS_KEY_FORMAT, dylanfmt); die(mps_pool_create_k(&leafpool, arena, mps_class_lo(), args), "Leaf Pool Create\n"); diff --git a/mps/code/chain.h b/mps/code/chain.h index e47f8000c0b..ec5bc228ebf 100644 --- a/mps/code/chain.h +++ b/mps/code/chain.h @@ -81,7 +81,6 @@ extern Bool ChainCheck(Chain chain); extern double ChainDeferral(Chain chain); extern Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace); -extern Res ChainCondemnAll(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/finaltest.c b/mps/code/finaltest.c index 88895027286..a9580bfcbdf 100644 --- a/mps/code/finaltest.c +++ b/mps/code/finaltest.c @@ -6,6 +6,20 @@ * * DESIGN * + * .mode: This test has two modes. + * + * .mode.park: In this mode, we use the arena's default generation + * chain, leave the arena parked and call mps_arena_collect. This + * tests that the default generation chain works and that all segments + * get condemned via TraceStartCollectAll. (See job003771 item 4.) + * + * .mode.poll: In this mode, we use our own generation chain (with + * small generations), allocate into generation 1, unclamp the arena, + * and provoke collection by allocating. This tests that custom + * generation chains work, and that segments get condemned via + * TracePoll even if there is no allocation into generation 0 of the + * chain. (See job003771 item 5.) + * * DEPENDENCIES * * This test uses the dylan object format, but the reliance on this @@ -16,6 +30,7 @@ * This code was created by first copying */ +#include "mpm.h" #include "testlib.h" #include "mpslib.h" #include "mps.h" @@ -30,10 +45,15 @@ #include /* fflush, printf, stdout */ +enum { + ModePARK, /* .mode.park */ + ModePOLL /* .mode.poll */ +}; + #define testArenaSIZE ((size_t)16<<20) #define rootCOUNT 20 -#define maxtreeDEPTH 10 +#define maxtreeDEPTH 9 #define collectionCOUNT 10 @@ -126,17 +146,21 @@ static mps_addr_t test_awl_find_dependent(mps_addr_t addr) static void *root[rootCOUNT]; -static void test_trees(const char *name, mps_arena_t arena, mps_ap_t ap, +static void test_trees(int mode, const char *name, mps_arena_t arena, + mps_ap_t ap, mps_word_t (*make)(mps_word_t, mps_ap_t), void (*reg)(mps_word_t, mps_arena_t)) { size_t collections = 0; size_t finals = 0; size_t i; + int object_alloc; object_count = 0; printf("Making some %s finalized trees of objects.\n", name); + mps_arena_park(arena); + /* make some trees */ for(i = 0; i < rootCOUNT; ++i) { root[i] = (void *)(*make)(maxtreeDEPTH, ap); @@ -151,10 +175,23 @@ static void test_trees(const char *name, mps_arena_t arena, mps_ap_t ap, while (finals < object_count && collections < collectionCOUNT) { mps_word_t final_this_time = 0; - printf("Collecting..."); - (void)fflush(stdout); - die(mps_arena_collect(arena), "collect"); - printf(" Done.\n"); + switch (mode) { + default: + case ModePARK: + printf("Collecting..."); + (void)fflush(stdout); + die(mps_arena_collect(arena), "collect"); + printf(" Done.\n"); + break; + case ModePOLL: + mps_arena_release(arena); + printf("Allocating..."); + (void)fflush(stdout); + object_alloc = 0; + while (object_alloc < 1000 && !mps_message_poll(arena)) + (void)DYLAN_INT(object_alloc++); + break; + } ++ collections; while (mps_message_poll(arena)) { mps_message_t message; @@ -170,10 +207,14 @@ static void test_trees(const char *name, mps_arena_t arena, mps_ap_t ap, " of %"PRIuLONGEST"\n", (ulongest_t)final_this_time, (ulongest_t)finals, (ulongest_t)object_count); } - cdie(finals == object_count, "Not all objects were finalized."); + if (finals != object_count) + error("Not all objects were finalized for %s in mode %s.", + BufferOfAP(ap)->pool->class->name, + mode == ModePOLL ? "POLL" : "PARK"); } -static void *test(mps_arena_t arena, mps_class_t pool_class) +static void test_pool(int mode, mps_arena_t arena, mps_chain_t chain, + mps_class_t pool_class) { mps_ap_t ap; mps_fmt_t fmt; @@ -182,10 +223,13 @@ static void *test(mps_arena_t arena, mps_class_t pool_class) die(mps_fmt_create_A(&fmt, arena, dylan_fmt_A()), "fmt_create\n"); MPS_ARGS_BEGIN(args) { - /* Allocate into generation 0 so that they get finalized quickly. */ - MPS_ARGS_ADD(args, MPS_KEY_GEN, 0); MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt); - MPS_ARGS_ADD(args, MPS_KEY_AWL_FIND_DEPENDENT, test_awl_find_dependent); + if (mode == ModePOLL) { + MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); + MPS_ARGS_ADD(args, MPS_KEY_GEN, 1); + } + if (pool_class == mps_class_awl()) + MPS_ARGS_ADD(args, MPS_KEY_AWL_FIND_DEPENDENT, test_awl_find_dependent); die(mps_pool_create_k(&pool, arena, pool_class, args), "pool_create\n"); } MPS_ARGS_END(args); @@ -194,19 +238,25 @@ static void *test(mps_arena_t arena, mps_class_t pool_class) "root_create\n"); die(mps_ap_create(&ap, pool, mps_rank_exact()), "ap_create\n"); - mps_message_type_enable(arena, mps_message_type_finalization()); - - mps_arena_park(arena); - - test_trees("numbered", arena, ap, make_numbered_tree, register_numbered_tree); - test_trees("indirect", arena, ap, make_indirect_tree, register_indirect_tree); + test_trees(mode, "numbered", arena, ap, make_numbered_tree, + register_numbered_tree); + test_trees(mode, "indirect", arena, ap, make_indirect_tree, + register_indirect_tree); mps_ap_destroy(ap); mps_root_destroy(mps_root); mps_pool_destroy(pool); mps_fmt_destroy(fmt); +} - return NULL; + +static void test_mode(int mode, mps_arena_t arena, mps_chain_t chain) +{ + test_pool(mode, arena, chain, mps_class_amc()); + test_pool(mode, arena, chain, mps_class_amcz()); + test_pool(mode, arena, chain, mps_class_ams()); + /* test_pool(mode, arena, chain, mps_class_lo()); TODO: job003772 */ + /* test_pool(mode, arena, chain, mps_class_awl()); TODO: job003772 */ } @@ -214,19 +264,27 @@ int main(int argc, char *argv[]) { mps_arena_t arena; mps_thr_t thread; + mps_chain_t chain; + mps_gen_param_s params[2]; + size_t gens = 2; + size_t i; testlib_init(argc, argv); die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "arena_create\n"); + mps_message_type_enable(arena, mps_message_type_finalization()); die(mps_thread_reg(&thread, arena), "thread_reg\n"); + for (i = 0; i < gens; ++i) { + params[i].mps_capacity = 1; + params[i].mps_mortality = 0.5; + } + die(mps_chain_create(&chain, arena, gens, params), "chain_create\n"); - test(arena, mps_class_amc()); - test(arena, mps_class_amcz()); - test(arena, mps_class_ams()); - test(arena, mps_class_awl()); - /* TODO: test(arena, mps_class_lo()); */ + test_mode(ModePOLL, arena, chain); + test_mode(ModePARK, arena, NULL); + mps_chain_destroy(chain); mps_thread_dereg(thread); mps_arena_destroy(arena); diff --git a/mps/code/locus.c b/mps/code/locus.c index a704c8b820b..e69b276ab93 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -287,13 +287,20 @@ Res ChainAlloc(Seg *segReturn, Chain chain, Serial genNr, SegClass class, double ChainDeferral(Chain chain) { + double time = DBL_MAX; + size_t i; + AVERT(Chain, chain); - if (chain->activeTraces != TraceSetEMPTY) - return DBL_MAX; - else - return chain->gens[0].capacity * 1024.0 - - (double)GenDescNewSize(&chain->gens[0]); + if (chain->activeTraces == TraceSetEMPTY) + for (i = 0; i < chain->genCount; ++i) { + double genTime = chain->gens[i].capacity * 1024.0 + - (double)GenDescNewSize(&chain->gens[i]); + if (genTime < time) + time = genTime; + } + + return time; } @@ -306,7 +313,7 @@ double ChainDeferral(Chain chain) Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace) { Res res; - Serial topCondemnedGenSerial, currGenSerial; + size_t topCondemnedGen, i; GenDesc gen; ZoneSet condemnedSet = ZoneSetEMPTY; Size condemnedSize = 0, survivorSize = 0, genNewSize, genTotalSize; @@ -314,33 +321,39 @@ Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace) AVERT(Chain, chain); AVERT(Trace, trace); - /* Find lowest gen within its capacity, set topCondemnedGenSerial to the */ - /* preceeding one. */ - currGenSerial = 0; - gen = &chain->gens[0]; - AVERT(GenDesc, gen); - genNewSize = GenDescNewSize(gen); - do { /* At this point, we've decided to collect currGenSerial. */ - topCondemnedGenSerial = currGenSerial; + /* 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); - - /* is there another one to consider? */ - currGenSerial += 1; - if (currGenSerial >= chain->genCount) - break; /* reached the top */ - gen = &chain->gens[currGenSerial]; - AVERT(GenDesc, gen); - genNewSize = GenDescNewSize(gen); - } while (genNewSize >= gen->capacity * (Size)1024); + } AVER(condemnedSet != ZoneSetEMPTY || condemnedSize == 0); - EVENT3(ChainCondemnAuto, chain, topCondemnedGenSerial, chain->genCount); - UNUSED(topCondemnedGenSerial); /* only used for EVENT */ + EVENT3(ChainCondemnAuto, chain, topCondemnedGen, chain->genCount); /* Condemn everything in these zones. */ if (condemnedSet != ZoneSetEMPTY) { @@ -354,41 +367,6 @@ Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace) } -/* ChainCondemnAll -- condemn everything in the chain */ - -Res ChainCondemnAll(Chain chain, Trace trace) -{ - Ring node, nextNode; - Bool haveWhiteSegs = FALSE; - Res res; - - /* Condemn every segment in every pool using this chain. */ - /* Finds the pools by iterating over the PoolGens in gen 0. */ - RING_FOR(node, &chain->gens[0].locusRing, nextNode) { - PoolGen nursery = RING_ELT(PoolGen, genRing, node); - Pool pool = nursery->pool; - Ring segNode, nextSegNode; - - AVERT(Pool, pool); - AVER(PoolHasAttr(pool, AttrGC)); - RING_FOR(segNode, PoolSegRing(pool), nextSegNode) { - Seg seg = SegOfPoolRing(segNode); - - res = TraceAddWhite(trace, seg); - if (res != ResOK) - goto failBegin; - haveWhiteSegs = TRUE; - } - } - - return ResOK; - -failBegin: - AVER(!haveWhiteSegs); /* Would leave white sets inconsistent. */ - return res; -} - - /* ChainStartGC -- called to notify start of GC for this chain */ void ChainStartGC(Chain chain, Trace trace) @@ -416,9 +394,11 @@ void ChainEndGC(Chain chain, Trace trace) Res PoolGenInit(PoolGen gen, Chain chain, Serial nr, Pool pool) { /* Can't check gen, because it's not been initialized. */ + AVER(gen != NULL); AVERT(Chain, chain); AVER(nr <= chain->genCount); AVERT(Pool, pool); + AVER(PoolHasAttr(pool, AttrGC)); gen->nr = nr; gen->pool = pool; diff --git a/mps/code/trace.c b/mps/code/trace.c index 61e9d396155..5a656e9489d 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1503,21 +1503,31 @@ static Res traceCondemnAll(Trace trace) { Res res; Arena arena; - Ring chainNode, nextChainNode; + Ring poolNode, nextPoolNode, chainNode, nextChainNode; Bool haveWhiteSegs = FALSE; arena = trace->arena; AVERT(Arena, arena); - /* Condemn all the chains. */ - RING_FOR(chainNode, &arena->chainRing, nextChainNode) { - Chain chain = RING_ELT(Chain, chainRing, chainNode); - AVERT(Chain, chain); - res = ChainCondemnAll(chain, trace); - if(res != ResOK) - goto failBegin; - haveWhiteSegs = TRUE; + /* Condemn all segments in pools with the GC attribute. */ + RING_FOR(poolNode, &ArenaGlobals(arena)->poolRing, nextPoolNode) { + Pool pool = RING_ELT(Pool, arenaRing, poolNode); + AVERT(Pool, pool); + + if (PoolHasAttr(pool, AttrGC)) { + 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; + haveWhiteSegs = TRUE; + } + } } + /* Notify all the chains. */ RING_FOR(chainNode, &arena->chainRing, nextChainNode) { Chain chain = RING_ELT(Chain, chainRing, chainNode); From 932d72770b996d30fde5a71b3412aa0f45c7171d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 22 Apr 2014 21:40:59 +0100 Subject: [PATCH 117/266] Separate jobs for lo and awl finalization. Copied from Perforce Change: 185743 ServerID: perforce.ravenbrook.com --- mps/code/finaltest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/finaltest.c b/mps/code/finaltest.c index a9580bfcbdf..f449d7e1acf 100644 --- a/mps/code/finaltest.c +++ b/mps/code/finaltest.c @@ -255,7 +255,7 @@ static void test_mode(int mode, mps_arena_t arena, mps_chain_t chain) test_pool(mode, arena, chain, mps_class_amc()); test_pool(mode, arena, chain, mps_class_amcz()); test_pool(mode, arena, chain, mps_class_ams()); - /* test_pool(mode, arena, chain, mps_class_lo()); TODO: job003772 */ + /* test_pool(mode, arena, chain, mps_class_lo()); TODO: job003773 */ /* test_pool(mode, arena, chain, mps_class_awl()); TODO: job003772 */ } From 5b54651076ab26c81ac154124ccd685a193c0746 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 22 Apr 2014 21:57:16 +0100 Subject: [PATCH 118/266] Fix indentation. Copied from Perforce Change: 185746 ServerID: perforce.ravenbrook.com --- mps/code/locus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mps/code/locus.c b/mps/code/locus.c index e69b276ab93..6e6e22128b7 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -292,12 +292,13 @@ double ChainDeferral(Chain chain) AVERT(Chain, chain); - if (chain->activeTraces == TraceSetEMPTY) + if (chain->activeTraces == TraceSetEMPTY) { for (i = 0; i < chain->genCount; ++i) { double genTime = chain->gens[i].capacity * 1024.0 - (double)GenDescNewSize(&chain->gens[i]); if (genTime < time) time = genTime; + } } return time; From 294c4a97cd8d19093042a162642b4e6cfac16013 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 22 Apr 2014 23:18:42 +0100 Subject: [PATCH 119/266] Test the arena default chain. set the commit limit to make sure that the collector can make progress. Copied from Perforce Change: 185749 ServerID: perforce.ravenbrook.com --- mps/code/amsss.c | 90 +++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/mps/code/amsss.c b/mps/code/amsss.c index 1d04f199349..e4e66ae0529 100644 --- a/mps/code/amsss.c +++ b/mps/code/amsss.c @@ -27,7 +27,7 @@ #define totalSizeSTEP 200 * (size_t)1024 /* objNULL needs to be odd so that it's ignored in exactRoots. */ #define objNULL ((mps_addr_t)MPS_WORD_CONST(0xDECEA5ED)) -#define testArenaSIZE ((size_t)16<<20) +#define testArenaSIZE ((size_t)1<<20) #define initTestFREQ 3000 #define splatTestFREQ 6000 static mps_gen_param_s testChain[1] = { { 160, 0.90 } }; @@ -107,7 +107,8 @@ static mps_addr_t make(void) static mps_pool_debug_option_s freecheckOptions = { NULL, 0, (const void *)"Dead", 4 }; -static void *test(void *arg, size_t haveAmbigous) +static void test_pool(mps_class_t pool_class, mps_arg_s args[], + size_t haveAmbiguous) { mps_pool_t pool; mps_root_t exactRoot, ambigRoot = NULL; @@ -116,14 +117,13 @@ static void *test(void *arg, size_t haveAmbigous) mps_ap_t busy_ap; mps_addr_t busy_init; - pool = (mps_pool_t)arg; - + die(mps_pool_create_k(&pool, arena, pool_class, args), "pool_create"); die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate"); die(mps_ap_create(&busy_ap, pool, mps_rank_exact()), "BufferCreate 2"); for(i = 0; i < exactRootsCOUNT; ++i) exactRoots[i] = objNULL; - if (haveAmbigous) + if (haveAmbiguous) for(i = 0; i < ambigRootsCOUNT; ++i) ambigRoots[i] = rnd_addr(); @@ -132,7 +132,7 @@ static void *test(void *arg, size_t haveAmbigous) &exactRoots[0], exactRootsCOUNT, (mps_word_t)1), "root_create_table(exact)"); - if (haveAmbigous) + if (haveAmbiguous) die(mps_root_create_table(&ambigRoot, arena, mps_rank_ambig(), (mps_rm_t)0, &ambigRoots[0], ambigRootsCOUNT), @@ -154,7 +154,7 @@ static void *test(void *arg, size_t haveAmbigous) } r = (size_t)rnd(); - if (!haveAmbigous || (r & 1)) { + if (!haveAmbiguous || (r & 1)) { i = (r >> 1) % exactRootsCOUNT; if (exactRoots[i] != objNULL) cdie(dylan_check(exactRoots[i]), "dying root check"); @@ -187,10 +187,10 @@ static void *test(void *arg, size_t haveAmbigous) mps_ap_destroy(busy_ap); mps_ap_destroy(ap); mps_root_destroy(exactRoot); - if (haveAmbigous) + if (haveAmbiguous) mps_root_destroy(ambigRoot); - return NULL; + mps_pool_destroy(pool); } @@ -199,68 +199,66 @@ int main(int argc, char *argv[]) mps_thr_t thread; mps_fmt_t format; mps_chain_t chain; - mps_pool_t pool; - void *r; testlib_init(argc, argv); die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "arena_create"); + 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()); die(mps_thread_reg(&thread, arena), "thread_reg"); die(mps_fmt_create_A(&format, arena, dylan_fmt_A()), "fmt_create"); die(mps_chain_create(&chain, arena, 1, testChain), "chain_create"); - /* TODO: Add tests using the arena default chain. */ + printf("\n\n*** AMS with !CHAIN and SUPPORT_AMBIGUOUS\n"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, TRUE); + test_pool(mps_class_ams(), args, TRUE); + } MPS_ARGS_END(args); - printf("\n\n****************************** Testing AMS Debug\n"); + printf("\n\n*** AMS with !CHAIN and !SUPPORT_AMBIGUOUS\n"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, FALSE); + test_pool(mps_class_ams(), args, FALSE); + } MPS_ARGS_END(args); + + printf("\n\n*** AMS with CHAIN and SUPPORT_AMBIGUOUS\n"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, TRUE); + test_pool(mps_class_ams(), args, TRUE); + } MPS_ARGS_END(args); + + printf("\n\n*** AMS with CHAIN and !SUPPORT_AMBIGUOUS\n"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, FALSE); + test_pool(mps_class_ams(), args, FALSE); + } MPS_ARGS_END(args); + + printf("\n\n*** AMS Debug with CHAIN and !SUPPORT_AMBIGUOUS\n"); MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, FALSE); MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &freecheckOptions); - die(mps_pool_create_k(&pool, arena, mps_class_ams_debug(), args), - "pool_create(ams_debug,share)"); + test_pool(mps_class_ams_debug(), args, FALSE); } MPS_ARGS_END(args); - mps_tramp(&r, test, pool, 0); - mps_pool_destroy(pool); - printf("\n\n****************************** Testing AMS Debug\n"); + printf("\n\n*** AMS Debug with CHAIN and SUPPORT_AMBIGUOUS\n"); MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, TRUE); MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &freecheckOptions); - die(mps_pool_create_k(&pool, arena, mps_class_ams_debug(), args), - "pool_create(ams_debug,ambig)"); + test_pool(mps_class_ams_debug(), args, TRUE); } MPS_ARGS_END(args); - mps_tramp(&r, test, pool, 1); - mps_pool_destroy(pool); - - printf("\n\n****************************** Testing AMS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, TRUE); - MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &freecheckOptions); - die(mps_pool_create_k(&pool, arena, mps_class_ams(), args), - "pool_create(ams,ambig)"); - } MPS_ARGS_END(args); - mps_tramp(&r, test, pool, 1); - mps_pool_destroy(pool); - - printf("\n\n****************************** Testing AMS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, FALSE); - MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &freecheckOptions); - die(mps_pool_create_k(&pool, arena, mps_class_ams(), args), - "pool_create(ams,share)"); - } MPS_ARGS_END(args); - mps_tramp(&r, test, pool, 0); - mps_pool_destroy(pool); mps_chain_destroy(chain); mps_fmt_destroy(format); From 61bea5cdb12f8a3c34d75fb50fa9e8099679f957 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 23 Apr 2014 09:12:20 +0100 Subject: [PATCH 120/266] Branching master to branch/2014-04-23/awl. Copied from Perforce Change: 185751 ServerID: perforce.ravenbrook.com From 1821ccc3096ed10dcb814dd0d5d3e8fa542c6c4d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 23 Apr 2014 19:42:27 +0100 Subject: [PATCH 121/266] Test all 8 combinations of debug, chain, ambig. Copied from Perforce Change: 185763 ServerID: perforce.ravenbrook.com --- mps/code/amsss.c | 65 ++++++++++++++---------------------------------- 1 file changed, 18 insertions(+), 47 deletions(-) diff --git a/mps/code/amsss.c b/mps/code/amsss.c index e4e66ae0529..8538fd354e2 100644 --- a/mps/code/amsss.c +++ b/mps/code/amsss.c @@ -196,6 +196,7 @@ static void test_pool(mps_class_t pool_class, mps_arg_s args[], int main(int argc, char *argv[]) { + int i; mps_thr_t thread; mps_fmt_t format; mps_chain_t chain; @@ -212,53 +213,23 @@ int main(int argc, char *argv[]) die(mps_fmt_create_A(&format, arena, dylan_fmt_A()), "fmt_create"); die(mps_chain_create(&chain, arena, 1, testChain), "chain_create"); - printf("\n\n*** AMS with !CHAIN and SUPPORT_AMBIGUOUS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, TRUE); - test_pool(mps_class_ams(), args, TRUE); - } MPS_ARGS_END(args); - - printf("\n\n*** AMS with !CHAIN and !SUPPORT_AMBIGUOUS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, FALSE); - test_pool(mps_class_ams(), args, FALSE); - } MPS_ARGS_END(args); - - printf("\n\n*** AMS with CHAIN and SUPPORT_AMBIGUOUS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, TRUE); - test_pool(mps_class_ams(), args, TRUE); - } MPS_ARGS_END(args); - - printf("\n\n*** AMS with CHAIN and !SUPPORT_AMBIGUOUS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, FALSE); - test_pool(mps_class_ams(), args, FALSE); - } MPS_ARGS_END(args); - - printf("\n\n*** AMS Debug with CHAIN and !SUPPORT_AMBIGUOUS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, FALSE); - MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &freecheckOptions); - test_pool(mps_class_ams_debug(), args, FALSE); - } MPS_ARGS_END(args); - - printf("\n\n*** AMS Debug with CHAIN and SUPPORT_AMBIGUOUS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, TRUE); - MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &freecheckOptions); - test_pool(mps_class_ams_debug(), args, TRUE); - } MPS_ARGS_END(args); + for (i = 0; i < 8; i++) { + int debug = i % 2; + int ownChain = (i / 2) % 2; + int ambig = (i / 4) % 2; + printf("\n\n*** AMS%s with %sCHAIN and %sSUPPORT_AMBIGUOUS\n", + debug ? " Debug" : "", + ownChain ? "" : "!", + ambig ? "" : "!"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + if (chain) + MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); + MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, ambig); + MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &freecheckOptions); + test_pool(debug ? mps_class_ams_debug() : mps_class_ams(), args, TRUE); + } MPS_ARGS_END(args); + } mps_chain_destroy(chain); mps_fmt_destroy(format); From fb56a08e49185009b92653ddb4f6d6da7a890047 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 23 Apr 2014 20:22:19 +0100 Subject: [PATCH 122/266] Tracecondemnzones could leave the white set inconsistent if traceaddwhite failed. add an assertion to cover this case (corresponding to the similar assertion in tracecondemnall). Copied from Perforce Change: 185765 ServerID: perforce.ravenbrook.com --- mps/code/trace.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mps/code/trace.c b/mps/code/trace.c index 5a656e9489d..76769583748 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -390,6 +390,7 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet) Seg seg; Arena arena; Res res; + Bool haveWhiteSegs = FALSE; AVERT(Trace, trace); AVER(condemnedSet != ZoneSetEMPTY); @@ -414,8 +415,11 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet) && ZoneSetSuper(condemnedSet, ZoneSetOfSeg(arena, seg))) { res = TraceAddWhite(trace, seg); - if(res != ResOK) + if(res != ResOK) { + AVER(!haveWhiteSegs); /* Would leave white sets inconsistent. */ return res; + } + haveWhiteSegs = TRUE; } } while (SegNext(&seg, arena, seg)); } From 28a6bfe289067477c804506de29fd9e2f0d2e98e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 25 Apr 2014 17:41:56 +0100 Subject: [PATCH 123/266] Explain traceaddwhite failure logic as requested by nb in . Copied from Perforce Change: 185800 ServerID: perforce.ravenbrook.com --- mps/code/trace.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/mps/code/trace.c b/mps/code/trace.c index 76769583748..f94d245fbf7 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -415,10 +415,8 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet) && ZoneSetSuper(condemnedSet, ZoneSetOfSeg(arena, seg))) { res = TraceAddWhite(trace, seg); - if(res != ResOK) { - AVER(!haveWhiteSegs); /* Would leave white sets inconsistent. */ - return res; - } + if(res != ResOK) + goto failBegin; haveWhiteSegs = TRUE; } } while (SegNext(&seg, arena, seg)); @@ -430,6 +428,10 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet) AVER(ZoneSetSuper(condemnedSet, trace->white)); return ResOK; + +failBegin: + AVER(!haveWhiteSegs); /* See .whiten.fail. */ + return res; } @@ -1541,7 +1543,14 @@ static Res traceCondemnAll(Trace trace) return ResOK; failBegin: - AVER(!haveWhiteSegs); /* Would leave white sets inconsistent. */ + /* .whiten.fail: If we successfully whitened one or more segments, + * but failed to whiten them all, then the white sets would now be + * inconsistent. This can't happen in practice (at time of writing) + * because all PoolWhiten methods always succeed. If we ever have a + * 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); return res; } From 54ee6e42921c7b5326c5d699e8b4ec87c8620300 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 26 Apr 2014 11:12:45 +0100 Subject: [PATCH 124/266] Fix amsss. Copied from Perforce Change: 185813 ServerID: perforce.ravenbrook.com --- mps/code/amsss.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mps/code/amsss.c b/mps/code/amsss.c index 8538fd354e2..9128561ecf2 100644 --- a/mps/code/amsss.c +++ b/mps/code/amsss.c @@ -108,7 +108,7 @@ static mps_pool_debug_option_s freecheckOptions = { NULL, 0, (const void *)"Dead", 4 }; static void test_pool(mps_class_t pool_class, mps_arg_s args[], - size_t haveAmbiguous) + mps_bool_t haveAmbiguous) { mps_pool_t pool; mps_root_t exactRoot, ambigRoot = NULL; @@ -223,11 +223,11 @@ int main(int argc, char *argv[]) ambig ? "" : "!"); MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - if (chain) + if (ownChain) MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, ambig); MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &freecheckOptions); - test_pool(debug ? mps_class_ams_debug() : mps_class_ams(), args, TRUE); + test_pool(debug ? mps_class_ams_debug() : mps_class_ams(), args, ambig); } MPS_ARGS_END(args); } From fb7363db2e9b532105d7d0a5f40d5edfe7ea82ad Mon Sep 17 00:00:00 2001 From: David Lovemore Date: Mon, 28 Apr 2014 13:14:04 +0100 Subject: [PATCH 125/266] Rename bool(v) to boolof(v) to fix clash with the windows header file windows.h Copied from Perforce Change: 185841 ServerID: perforce.ravenbrook.com --- mps/code/buffer.c | 6 +++--- mps/code/global.c | 2 +- mps/code/misc.h | 2 +- mps/code/poolmfs.c | 2 +- mps/code/poolmvff.c | 2 +- mps/code/seg.c | 2 +- mps/code/trace.c | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mps/code/buffer.c b/mps/code/buffer.c index 27314924600..bbae1f3eacd 100644 --- a/mps/code/buffer.c +++ b/mps/code/buffer.c @@ -1075,7 +1075,7 @@ static Res bufferTrivInit(Buffer buffer, Pool pool, ArgList args) AVERT(Buffer, buffer); AVERT(Pool, pool); UNUSED(args); - EVENT3(BufferInit, buffer, pool, BOOL(buffer->isMutator)); + EVENT3(BufferInit, buffer, pool, BOOLOF(buffer->isMutator)); return ResOK; } @@ -1288,7 +1288,7 @@ static Res segBufInit(Buffer buffer, Pool pool, ArgList args) segbuf->rankSet = RankSetEMPTY; AVERT(SegBuf, segbuf); - EVENT3(BufferInitSeg, buffer, pool, BOOL(buffer->isMutator)); + EVENT3(BufferInitSeg, buffer, pool, BOOLOF(buffer->isMutator)); return ResOK; } @@ -1515,7 +1515,7 @@ static Res rankBufInit(Buffer buffer, Pool pool, ArgList args) BufferSetRankSet(buffer, RankSetSingle(rank)); /* There's nothing to check that the superclass doesn't, so no AVERT. */ - EVENT4(BufferInitRank, buffer, pool, BOOL(buffer->isMutator), rank); + EVENT4(BufferInitRank, buffer, pool, BOOLOF(buffer->isMutator), rank); return ResOK; } diff --git a/mps/code/global.c b/mps/code/global.c index 5f635206bd9..ce4ebbe6faa 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -1140,7 +1140,7 @@ void ArenaSetEmergency(Arena arena, Bool emergency) AVERT(Arena, arena); AVERT(Bool, emergency); - EVENT2(ArenaSetEmergency, arena, BOOL(emergency)); + EVENT2(ArenaSetEmergency, arena, BOOLOF(emergency)); arena->emergency = emergency; } diff --git a/mps/code/misc.h b/mps/code/misc.h index 809fd7e954a..fed416157dd 100644 --- a/mps/code/misc.h +++ b/mps/code/misc.h @@ -178,7 +178,7 @@ typedef const struct SrcIdStruct { */ #define BITFIELD(type, value, width) ((type)value & (((type)1 << (width)) - 1)) -#define BOOL(v) BITFIELD(unsigned, (v), 1) +#define BOOLOF(v) BITFIELD(unsigned, (v), 1) /* Bit Sets -- sets of integers in [0,N-1]. diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c index 214b2b232d3..139b3f5c872 100644 --- a/mps/code/poolmfs.c +++ b/mps/code/poolmfs.c @@ -136,7 +136,7 @@ static Res MFSInit(Pool pool, ArgList args) mfs->sig = MFSSig; AVERT(MFS, mfs); - EVENT5(PoolInitMFS, pool, arena, extendBy, BOOL(extendSelf), unitSize); + EVENT5(PoolInitMFS, pool, arena, extendBy, BOOLOF(extendSelf), unitSize); return ResOK; } diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index fc4307d50a2..4971550c76a 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -610,7 +610,7 @@ static Res MVFFInit(Pool pool, ArgList args) mvff->sig = MVFFSig; AVERT(MVFF, mvff); EVENT8(PoolInitMVFF, pool, arena, extendBy, avgSize, align, - BOOL(slotHigh), BOOL(arenaHigh), BOOL(firstFit)); + BOOLOF(slotHigh), BOOLOF(arenaHigh), BOOLOF(firstFit)); return ResOK; failInit: diff --git a/mps/code/seg.c b/mps/code/seg.c index 31dd0759ff9..7f0cd4bc907 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -593,7 +593,7 @@ Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi, if (ResOK != res) goto failMerge; - EVENT3(SegMerge, segLo, segHi, BOOL(withReservoirPermit)); + EVENT3(SegMerge, segLo, segHi, BOOLOF(withReservoirPermit)); /* Deallocate segHi object */ ControlFree(arena, segHi, class->size); AVERT(Seg, segLo); diff --git a/mps/code/trace.c b/mps/code/trace.c index f94d245fbf7..bd2b871fb11 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1593,7 +1593,7 @@ static void TraceStartPoolGen(Chain chain, GenDesc desc, Bool top, Index i) Ring n, nn; RING_FOR(n, &desc->locusRing, nn) { PoolGen gen = RING_ELT(PoolGen, genRing, n); - EVENT11(TraceStartPoolGen, chain, BOOL(top), i, desc, + EVENT11(TraceStartPoolGen, chain, BOOLOF(top), i, desc, desc->capacity, desc->mortality, desc->zones, gen->pool, gen->nr, gen->totalSize, gen->newSizeAtCreate); From e517351deb2e08f6a901c5ab9a1f1d2e3c625134 Mon Sep 17 00:00:00 2001 From: David Lovemore Date: Mon, 28 Apr 2014 15:30:37 +0100 Subject: [PATCH 126/266] Allow branching from custom/*/main. Copied from Perforce Change: 185845 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 790dceb0eba..db54da83ce1 100755 --- a/mps/tool/branch +++ b/mps/tool/branch @@ -154,7 +154,7 @@ def main(argv): m = re.match(CHILD_RE, args.child) if not m: raise Error(fmt("Invalid child: {child}")) - if args.customer != m.group(3): + if not args.task and args.customer != m.group(3): raise Error(fmt("Customer mismatch between {parent} and {child}.")) args.date, args.task, _, args.version = m.groups() From 4ccfc3a7f052aad64b402644dc264727455974fa Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 09:48:08 +0100 Subject: [PATCH 127/266] Rename bool to boolof to match change 185841. Copied from Perforce Change: 185868 ServerID: perforce.ravenbrook.com --- mps/design/type.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/design/type.txt b/mps/design/type.txt index 900980970dc..baee04ef3d2 100644 --- a/mps/design/type.txt +++ b/mps/design/type.txt @@ -156,7 +156,7 @@ the type of the bitfield must be ``unsigned:1``, not ``Bool:1``. (That's because the two values of the type ``Bool:1`` are ``0`` and ``-1``, which means that assigning ``TRUE`` would require a sign conversion.) To avoid warnings about loss of data from GCC with the -``-Wconversion`` option, ``misc.h`` provides the ``BOOL`` macro for +``-Wconversion`` option, ``misc.h`` provides the ``BOOLOF`` macro for coercing a value to an unsigned single-bit field. From 47d68878901641204ee2442cf9835476729cb588 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 10:16:28 +0100 Subject: [PATCH 128/266] Branching master to branch/2014-04-30/poolgen. Copied from Perforce Change: 185871 ServerID: perforce.ravenbrook.com From f4e63e0bddba94b00b73f63754be98f0c53c9989 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 11:08:23 +0100 Subject: [PATCH 129/266] No need for prod_checklevel_initial (was unused). Copied from Perforce Change: 185876 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 1 - 1 file changed, 1 deletion(-) diff --git a/mps/code/config.h b/mps/code/config.h index a4d8da21eb2..4a3595e1f17 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -585,7 +585,6 @@ #define MPS_PROD_STRING "mps" #define MPS_PROD_MPS -#define PROD_CHECKLEVEL_INITIAL CheckLevelSHALLOW /* TODO: This should be proportional to the memory usage of the MPS, not a constant. That will require design, and then some interface and From b3d827b6fb98ed5072f7a2a87114a89a55793682 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 11:18:44 +0100 Subject: [PATCH 130/266] Pool generations now refer directly to their generation (not via a chain and a generation number). Allocation into a generation now via PoolGenAlloc (not ChainAlloc). The "top generation" logic is encapsulated in the function ChainGen. Copied from Perforce Change: 185877 ServerID: perforce.ravenbrook.com --- mps/code/chain.h | 18 +++----- mps/code/eventdef.h | 11 ++--- mps/code/locus.c | 108 +++++++++++++++++++++++--------------------- mps/code/poolamc.c | 48 ++++++++++---------- mps/code/poolams.c | 14 ++---- mps/code/poolams.h | 1 - mps/code/poolawl.c | 9 ++-- mps/code/poollo.c | 20 ++++---- mps/code/segsmss.c | 17 ++++--- mps/code/trace.c | 5 +- 10 files changed, 122 insertions(+), 129 deletions(-) diff --git a/mps/code/chain.h b/mps/code/chain.h index ec5bc228ebf..eb4e9e78df7 100644 --- a/mps/code/chain.h +++ b/mps/code/chain.h @@ -44,9 +44,8 @@ typedef struct PoolGenStruct *PoolGen; typedef struct PoolGenStruct { Sig sig; - Serial nr; /* generation number */ Pool pool; /* pool this belongs to */ - Chain chain; /* chain this belongs to */ + GenDesc gen; /* generation this belongs to */ /* link in ring of all PoolGen's in this GenDesc (locus) */ RingStruct genRing; Size totalSize; /* total size of segs in gen in this pool */ @@ -84,16 +83,13 @@ 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); -extern Res ChainAlloc(Seg *segReturn, Chain chain, Serial genNr, - SegClass class, Size size, Pool pool, - Bool withReservoirPermit, ArgList args); - -extern Bool PoolGenCheck(PoolGen gen); -extern Res PoolGenInit(PoolGen gen, Chain chain, Serial nr, Pool pool); -extern void PoolGenFinish(PoolGen gen); -extern void PoolGenFlip(PoolGen gen); -#define PoolGenNr(gen) ((gen)->nr) +extern GenDesc ChainGen(Chain chain, Index gen); +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); #endif /* chain_h */ diff --git a/mps/code/eventdef.h b/mps/code/eventdef.h index 4ce313dcfc8..c4918d38413 100644 --- a/mps/code/eventdef.h +++ b/mps/code/eventdef.h @@ -36,8 +36,8 @@ */ #define EVENT_VERSION_MAJOR ((unsigned)1) -#define EVENT_VERSION_MEDIAN ((unsigned)1) -#define EVENT_VERSION_MINOR ((unsigned)7) +#define EVENT_VERSION_MEDIAN ((unsigned)2) +#define EVENT_VERSION_MINOR ((unsigned)0) /* EVENT_LIST -- list of event types and general properties @@ -722,9 +722,8 @@ PARAM(X, 5, D, mortality) /* mortality of generation */ \ PARAM(X, 6, W, zone) /* zone set of generation */ \ PARAM(X, 7, P, pool) /* pool */ \ - PARAM(X, 8, W, serial) /* pool gen serial number */ \ - PARAM(X, 9, W, totalSize) /* total size of pool gen */ \ - PARAM(X, 10, W, newSizeAtCreate) /* new size of pool gen at trace create */ + PARAM(X, 8, W, totalSize) /* total size of pool gen */ \ + PARAM(X, 9, W, newSizeAtCreate) /* new size of pool gen at trace create */ #define EVENT_TraceCondemnZones_PARAMS(PARAM, X) \ PARAM(X, 0, P, trace) /* the trace */ \ @@ -733,7 +732,7 @@ #define EVENT_ArenaGenZoneAdd_PARAMS(PARAM, X) \ PARAM(X, 0, P, arena) /* the arena */ \ - PARAM(X, 1, W, gen) /* the generation number */ \ + PARAM(X, 1, P, gendesc) /* the generation description */ \ PARAM(X, 2, W, zoneSet) /* the new zoneSet */ #define EVENT_ArenaUseFreeZone_PARAMS(PARAM, X) \ diff --git a/mps/code/locus.c b/mps/code/locus.c index 6e6e22128b7..942d3f1f405 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -212,7 +212,8 @@ void ChainDestroy(Chain chain) AVERT(Chain, chain); - arena = chain->arena; genCount = chain->genCount; + arena = chain->arena; + genCount = chain->genCount; RingRemove(&chain->chainRing); chain->sig = SigInvalid; for (i = 0; i < genCount; ++i) { @@ -234,55 +235,67 @@ size_t ChainGens(Chain chain) } -/* ChainAlloc -- allocate tracts in a generation */ +/* ChainGen -- return a generation in a chain, or the arena top generation */ -Res ChainAlloc(Seg *segReturn, Chain chain, Serial genNr, SegClass class, - Size size, Pool pool, Bool withReservoirPermit, - ArgList args) +GenDesc ChainGen(Chain chain, Index gen) +{ + AVERT(Chain, chain); + AVER(gen <= chain->genCount); + + if (gen < chain->genCount) + return &chain->gens[gen]; + else + return &chain->arena->topGen; +} + + +/* PoolGenAlloc -- allocate a segment in a pool generation */ + +Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size, + Bool withReservoirPermit, ArgList args) { SegPrefStruct pref; Res res; Seg seg; ZoneSet zones, moreZones; Arena arena; + GenDesc gen; - AVERT(Chain, chain); - AVER(genNr <= chain->genCount); + AVER(segReturn != NULL); + AVERT(PoolGen, pgen); + AVERT(SegClass, class); + AVER(size > 0); + AVERT(Bool, withReservoirPermit); + AVERT(ArgList, args); - arena = chain->arena; - if (genNr < chain->genCount) - zones = chain->gens[genNr].zones; - else - zones = arena->topGen.zones; + arena = PoolArena(pgen->pool); + gen = pgen->gen; + zones = gen->zones; SegPrefInit(&pref); pref.high = FALSE; pref.zones = zones; pref.avoid = ZoneSetBlacklist(arena); - res = SegAlloc(&seg, class, &pref, size, pool, withReservoirPermit, args); + res = SegAlloc(&seg, class, &pref, size, pgen->pool, withReservoirPermit, + args); if (res != ResOK) return res; moreZones = ZoneSetUnion(zones, ZoneSetOfSeg(arena, seg)); + gen->zones = moreZones; if (!ZoneSetSuper(zones, moreZones)) { - /* Tracking the whole zoneset for each generation number gives - * more understandable telemetry than just reporting the added + /* Tracking the whole zoneset for each generation gives more + * understandable telemetry than just reporting the added * zones. */ - EVENT3(ArenaGenZoneAdd, arena, genNr, moreZones); + EVENT3(ArenaGenZoneAdd, arena, gen, moreZones); } - if (genNr < chain->genCount) - chain->gens[genNr].zones = moreZones; - else - chain->arena->topGen.zones = moreZones; - *segReturn = seg; return ResOK; } - /* ChainDeferral -- time until next ephemeral GC for this chain */ double ChainDeferral(Chain chain) @@ -392,55 +405,48 @@ void ChainEndGC(Chain chain, Trace trace) /* PoolGenInit -- initialize a PoolGen */ -Res PoolGenInit(PoolGen gen, Chain chain, Serial nr, Pool pool) +Res PoolGenInit(PoolGen pgen, GenDesc gen, Pool pool) { - /* Can't check gen, because it's not been initialized. */ - AVER(gen != NULL); - AVERT(Chain, chain); - AVER(nr <= chain->genCount); + /* Can't check pgen, because it's not been initialized. */ + AVER(pgen != NULL); + AVERT(GenDesc, gen); AVERT(Pool, pool); AVER(PoolHasAttr(pool, AttrGC)); - gen->nr = nr; - gen->pool = pool; - gen->chain = chain; - RingInit(&gen->genRing); - gen->totalSize = (Size)0; - gen->newSize = (Size)0; - gen->sig = PoolGenSig; + pgen->pool = pool; + pgen->gen = gen; + RingInit(&pgen->genRing); + pgen->totalSize = (Size)0; + pgen->newSize = (Size)0; + pgen->sig = PoolGenSig; + AVERT(PoolGen, pgen); - if(nr != chain->genCount) { - RingAppend(&chain->gens[nr].locusRing, &gen->genRing); - } else { - /* Dynamic generation is linked to the arena, not the chain. */ - RingAppend(&chain->arena->topGen.locusRing, &gen->genRing); - } - AVERT(PoolGen, gen); + RingAppend(&gen->locusRing, &pgen->genRing); return ResOK; } /* PoolGenFinish -- finish a PoolGen */ -void PoolGenFinish(PoolGen gen) +void PoolGenFinish(PoolGen pgen) { - AVERT(PoolGen, gen); + AVERT(PoolGen, pgen); - gen->sig = SigInvalid; - RingRemove(&gen->genRing); + pgen->sig = SigInvalid; + RingRemove(&pgen->genRing); } /* PoolGenCheck -- check a PoolGen */ -Bool PoolGenCheck(PoolGen gen) +Bool PoolGenCheck(PoolGen pgen) { - CHECKS(PoolGen, gen); + CHECKS(PoolGen, pgen); /* nothing to check about serial */ - CHECKU(Pool, gen->pool); - CHECKU(Chain, gen->chain); - CHECKD_NOSIG(Ring, &gen->genRing); - CHECKL(gen->newSize <= gen->totalSize); + CHECKU(Pool, pgen->pool); + CHECKU(GenDesc, pgen->gen); + CHECKD_NOSIG(Ring, &pgen->genRing); + CHECKL(pgen->newSize <= pgen->totalSize); return TRUE; } diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index aeb04454efe..6677ddc337c 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -453,7 +453,6 @@ typedef struct AMCStruct { /* */ RankSet rankSet; /* rankSet for entire pool */ RingStruct genRing; /* ring of generations */ Bool gensBooted; /* used during boot (init) */ - Chain chain; /* chain used by this pool */ size_t gens; /* number of generations */ amcGen *gen; /* (pointer to) array of generations */ amcGen nursery; /* the default mutator generation */ @@ -639,12 +638,12 @@ DEFINE_BUFFER_CLASS(amcBufClass, class) /* amcGenCreate -- create a generation */ -static Res amcGenCreate(amcGen *genReturn, AMC amc, Serial genNr) +static Res amcGenCreate(amcGen *genReturn, AMC amc, GenDesc gen) { Arena arena; Buffer buffer; Pool pool; - amcGen gen; + amcGen amcgen; Res res; void *p; @@ -654,25 +653,25 @@ static Res amcGenCreate(amcGen *genReturn, AMC amc, Serial genNr) res = ControlAlloc(&p, arena, sizeof(amcGenStruct), FALSE); if(res != ResOK) goto failControlAlloc; - gen = (amcGen)p; + amcgen = (amcGen)p; res = BufferCreate(&buffer, EnsureamcBufClass(), pool, FALSE, argsNone); if(res != ResOK) goto failBufferCreate; - res = PoolGenInit(&gen->pgen, amc->chain, genNr, pool); + res = PoolGenInit(&amcgen->pgen, gen, pool); if(res != ResOK) goto failGenInit; - RingInit(&gen->amcRing); - gen->segs = 0; - gen->forward = buffer; - gen->sig = amcGenSig; + RingInit(&amcgen->amcRing); + amcgen->segs = 0; + amcgen->forward = buffer; + amcgen->sig = amcGenSig; - AVERT(amcGen, gen); + AVERT(amcGen, amcgen); - RingAppend(&amc->genRing, &gen->amcRing); - EVENT2(AMCGenCreate, amc, gen); - *genReturn = gen; + RingAppend(&amc->genRing, &amcgen->amcRing); + EVENT2(AMCGenCreate, amc, amcgen); + *genReturn = amcgen; return ResOK; failGenInit: @@ -715,8 +714,7 @@ static Res amcGenDescribe(amcGen gen, mps_lib_FILE *stream) return ResFAIL; res = WriteF(stream, - " amcGen $P ($U) {\n", - (WriteFP)gen, (WriteFU)amcGenNr(gen), + " amcGen $P {\n", (WriteFP)gen, " buffer $P\n", gen->forward, " segs $U, totalSize $U, newSize $U\n", (WriteFU)gen->segs, @@ -798,6 +796,7 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args) size_t genArraySize; size_t genCount; Bool interior = AMC_INTERIOR_DEFAULT; + Chain chain; ArgStruct arg; /* Suppress a warning about this structure not being used when there @@ -818,14 +817,14 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args) ArgRequire(&arg, args, MPS_KEY_FORMAT); pool->format = arg.val.format; if (ArgPick(&arg, args, MPS_KEY_CHAIN)) - amc->chain = arg.val.chain; + chain = arg.val.chain; else - amc->chain = ArenaGlobals(arena)->defaultChain; + chain = ArenaGlobals(arena)->defaultChain; if (ArgPick(&arg, args, MPS_KEY_INTERIOR)) interior = arg.val.b; AVERT(Format, pool->format); - AVERT(Chain, amc->chain); + AVERT(Chain, chain); pool->alignment = pool->format->alignment; amc->rankSet = rankSet; @@ -861,7 +860,7 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args) AVERT(AMC, amc); /* Init generations. */ - genCount = ChainGens(amc->chain); + genCount = ChainGens(chain); { void *p; @@ -871,11 +870,10 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args) if(res != ResOK) goto failGensAlloc; amc->gen = p; - for(i = 0; i < genCount + 1; ++i) { - res = amcGenCreate(&amc->gen[i], amc, (Serial)i); - if(res != ResOK) { + for (i = 0; i <= genCount; ++i) { + res = amcGenCreate(&amc->gen[i], amc, ChainGen(chain, i)); + if (res != ResOK) goto failGenAlloc; - } } /* Set up forwarding buffers. */ for(i = 0; i < genCount; ++i) { @@ -1017,8 +1015,8 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn, alignedSize = SizeAlignUp(size, ArenaAlign(arena)); MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD_FIELD(args, amcKeySegGen, p, gen); - res = ChainAlloc(&seg, amc->chain, PoolGenNr(pgen), amcSegClassGet(), - alignedSize, pool, withReservoirPermit, args); + res = PoolGenAlloc(&seg, pgen, amcSegClassGet(), alignedSize, + withReservoirPermit, args); } MPS_ARGS_END(args); if(res != ResOK) return res; diff --git a/mps/code/poolams.c b/mps/code/poolams.c index 65b2dcf754f..17d2312ade4 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -691,14 +691,14 @@ static Res AMSSegCreate(Seg *segReturn, Pool pool, Size size, if (res != ResOK) goto failSize; - res = ChainAlloc(&seg, ams->chain, ams->pgen.nr, (*ams->segClass)(), - prefSize, pool, withReservoirPermit, argsNone); + res = PoolGenAlloc(&seg, &ams->pgen, (*ams->segClass)(), prefSize, + withReservoirPermit, argsNone); if (res != ResOK) { /* try to allocate one that's just large enough */ Size minSize = SizeAlignUp(size, ArenaAlign(arena)); if (minSize == prefSize) goto failSeg; - res = ChainAlloc(&seg, ams->chain, ams->pgen.nr, (*ams->segClass)(), - prefSize, pool, withReservoirPermit, argsNone); + res = PoolGenAlloc(&seg, &ams->pgen, (*ams->segClass)(), prefSize, + withReservoirPermit, argsNone); if (res != ResOK) goto failSeg; } @@ -822,8 +822,7 @@ Res AMSInitInternal(AMS ams, Format format, Chain chain, unsigned gen, pool->alignment = pool->format->alignment; ams->grainShift = SizeLog2(PoolAlignment(pool)); - ams->chain = chain; - res = PoolGenInit(&ams->pgen, ams->chain, gen, pool); + res = PoolGenInit(&ams->pgen, ChainGen(chain, gen), pool); if (res != ResOK) return res; @@ -1666,8 +1665,6 @@ static Res AMSDescribe(Pool pool, mps_lib_FILE *stream) " size $W\n", (WriteFW)ams->size, " grain shift $U\n", (WriteFU)ams->grainShift, - " chain $P\n", - (WriteFP)ams->chain, NULL); if (res != ResOK) return res; @@ -1761,7 +1758,6 @@ Bool AMSCheck(AMS ams) CHECKL(IsSubclassPoly(AMS2Pool(ams)->class, AMSPoolClassGet())); CHECKL(PoolAlignment(AMS2Pool(ams)) == ((Size)1 << ams->grainShift)); CHECKL(PoolAlignment(AMS2Pool(ams)) == AMS2Pool(ams)->format->alignment); - CHECKD(Chain, ams->chain); CHECKD(PoolGen, &ams->pgen); CHECKL(SizeIsAligned(ams->size, ArenaAlign(PoolArena(AMS2Pool(ams))))); CHECKL(FUNCHECK(ams->segSize)); diff --git a/mps/code/poolams.h b/mps/code/poolams.h index 96cec6c6c7b..dd5a85889ed 100644 --- a/mps/code/poolams.h +++ b/mps/code/poolams.h @@ -41,7 +41,6 @@ typedef Res (*AMSSegSizePolicyFunction)(Size *sizeReturn, typedef struct AMSStruct { PoolStruct poolStruct; /* generic pool structure */ Shift grainShift; /* log2 of grain size */ - Chain chain; /* chain used by this pool */ PoolGenStruct pgen; /* generation representing the pool */ Size size; /* total segment size of the pool */ AMSSegSizePolicyFunction segSize; /* SegSize policy */ diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index cbece0b41fe..46478e95bb9 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -84,7 +84,6 @@ typedef Addr (*FindDependentMethod)(Addr object); typedef struct AWLStruct { PoolStruct poolStruct; Shift alignShift; - Chain chain; /* dummy chain */ PoolGenStruct pgen; /* generation representing the pool */ Size size; /* allocated size in bytes */ Count succAccesses; /* number of successive single accesses */ @@ -472,8 +471,8 @@ static Res AWLSegCreate(AWLSeg *awlsegReturn, return ResMEMORY; MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD_FIELD(args, awlKeySegRankSet, u, rankSet); - res = ChainAlloc(&seg, awl->chain, awl->pgen.nr, AWLSegClassGet(), - size, pool, reservoirPermit, args); + res = PoolGenAlloc(&seg, &awl->pgen, AWLSegClassGet(), size, + reservoirPermit, args); } MPS_ARGS_END(args); if (res != ResOK) return res; @@ -569,9 +568,8 @@ static Res AWLInit(Pool pool, ArgList args) AVERT(Chain, chain); AVER(gen <= ChainGens(chain)); - awl->chain = chain; - res = PoolGenInit(&awl->pgen, chain, gen, pool); + res = PoolGenInit(&awl->pgen, ChainGen(chain, gen), pool); if (res != ResOK) goto failGenInit; @@ -1305,7 +1303,6 @@ static Bool AWLCheck(AWL awl) CHECKD(Pool, &awl->poolStruct); CHECKL(awl->poolStruct.class == AWLPoolClassGet()); CHECKL((Align)1 << awl->alignShift == awl->poolStruct.alignment); - CHECKD(Chain, awl->chain); /* Nothing to check about succAccesses. */ CHECKL(FUNCHECK(awl->findDependent)); /* Don't bother to check stats. */ diff --git a/mps/code/poollo.c b/mps/code/poollo.c index d8f23584fba..8836d2563d0 100644 --- a/mps/code/poollo.c +++ b/mps/code/poollo.c @@ -24,7 +24,6 @@ typedef struct LOStruct *LO; typedef struct LOStruct { PoolStruct poolStruct; /* generic pool structure */ Shift alignShift; /* log_2 of pool alignment */ - Chain chain; /* chain used by this pool */ PoolGenStruct pgen; /* generation representing the pool */ Sig sig; } LOStruct; @@ -291,9 +290,9 @@ static Res loSegCreate(LOSeg *loSegReturn, Pool pool, Size size, lo = PoolPoolLO(pool); AVERT(LO, lo); - res = ChainAlloc(&seg, lo->chain, lo->pgen.nr, EnsureLOSegClass(), - SizeAlignUp(size, ArenaAlign(PoolArena(pool))), - pool, withReservoirPermit, argsNone); + res = PoolGenAlloc(&seg, &lo->pgen, EnsureLOSegClass(), + SizeAlignUp(size, ArenaAlign(PoolArena(pool))), + withReservoirPermit, argsNone); if (res != ResOK) return res; @@ -473,9 +472,11 @@ static Res LOInit(Pool pool, ArgList args) Arena arena; Res res; ArgStruct arg; + Chain chain; unsigned gen = LO_GEN_DEFAULT; AVERT(Pool, pool); + AVERT(ArgList, args); arena = PoolArena(pool); @@ -484,22 +485,22 @@ static Res LOInit(Pool pool, ArgList args) ArgRequire(&arg, args, MPS_KEY_FORMAT); pool->format = arg.val.format; if (ArgPick(&arg, args, MPS_KEY_CHAIN)) - lo->chain = arg.val.chain; + chain = arg.val.chain; else { - lo->chain = ArenaGlobals(arena)->defaultChain; + chain = ArenaGlobals(arena)->defaultChain; gen = 1; /* avoid the nursery of the default chain by default */ } if (ArgPick(&arg, args, MPS_KEY_GEN)) gen = arg.val.u; AVERT(Format, pool->format); - AVERT(Chain, lo->chain); - AVER(gen <= ChainGens(lo->chain)); + AVERT(Chain, chain); + AVER(gen <= ChainGens(chain)); pool->alignment = pool->format->alignment; lo->alignShift = SizeLog2((Size)PoolAlignment(pool)); - res = PoolGenInit(&lo->pgen, lo->chain, gen, pool); + res = PoolGenInit(&lo->pgen, ChainGen(chain, gen), pool); if (res != ResOK) goto failGenInit; @@ -812,7 +813,6 @@ static Bool LOCheck(LO lo) CHECKL(lo->poolStruct.class == EnsureLOPoolClass()); CHECKL(ShiftCheck(lo->alignShift)); CHECKL((Align)1 << lo->alignShift == PoolAlignment(&lo->poolStruct)); - CHECKD(Chain, lo->chain); CHECKD(PoolGen, &lo->pgen); return TRUE; } diff --git a/mps/code/segsmss.c b/mps/code/segsmss.c index 978c352e0dd..e3ed646865e 100644 --- a/mps/code/segsmss.c +++ b/mps/code/segsmss.c @@ -40,7 +40,6 @@ extern PoolClass AMSTPoolClassGet(void); typedef struct AMSTStruct { AMSStruct amsStruct; /* generic AMS structure */ - Chain chain; /* chain to use */ Bool failSegs; /* fail seg splits & merges when true */ Count splits; /* count of successful segment splits */ Count merges; /* count of successful segment merges */ @@ -333,17 +332,23 @@ static Res AMSTInit(Pool pool, ArgList args) Format format; Chain chain; Res res; - static GenParamStruct genParam = { 1024, 0.2 }; + unsigned gen = AMS_GEN_DEFAULT; ArgStruct arg; AVERT(Pool, pool); + AVERT(ArgList, args); + if (ArgPick(&arg, args, MPS_KEY_CHAIN)) + chain = arg.val.chain; + else { + chain = ArenaGlobals(PoolArena(pool))->defaultChain; + gen = 1; /* avoid the nursery of the default chain by default */ + } + if (ArgPick(&arg, args, MPS_KEY_GEN)) + gen = arg.val.u; ArgRequire(&arg, args, MPS_KEY_FORMAT); format = arg.val.format; - res = ChainCreate(&chain, pool->arena, 1, &genParam); - if (res != ResOK) - return res; res = AMSInitInternal(Pool2AMS(pool), format, chain, 0, FALSE); if (res != ResOK) return res; @@ -351,7 +356,6 @@ static Res AMSTInit(Pool pool, ArgList args) ams = Pool2AMS(pool); ams->segSize = AMSTSegSizePolicy; ams->segClass = AMSTSegClassGet; - amst->chain = chain; amst->failSegs = TRUE; amst->splits = 0; amst->merges = 0; @@ -386,7 +390,6 @@ static void AMSTFinish(Pool pool) AMSFinish(pool); amst->sig = SigInvalid; - ChainDestroy(amst->chain); } diff --git a/mps/code/trace.c b/mps/code/trace.c index bd2b871fb11..999d5047a5c 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1593,10 +1593,9 @@ static void TraceStartPoolGen(Chain chain, GenDesc desc, Bool top, Index i) Ring n, nn; RING_FOR(n, &desc->locusRing, nn) { PoolGen gen = RING_ELT(PoolGen, genRing, n); - EVENT11(TraceStartPoolGen, chain, BOOLOF(top), i, desc, + EVENT10(TraceStartPoolGen, chain, BOOLOF(top), i, desc, desc->capacity, desc->mortality, desc->zones, - gen->pool, gen->nr, gen->totalSize, - gen->newSizeAtCreate); + gen->pool, gen->totalSize, gen->newSizeAtCreate); } } From 5cacd3e0fc51c4cbadf70ba0df674dbdf3348027 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 12:09:09 +0100 Subject: [PATCH 131/266] Pass gen parameter to amsinitinternal. Set up segsmss with same chain as before. Copied from Perforce Change: 185885 ServerID: perforce.ravenbrook.com --- mps/code/segsmss.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mps/code/segsmss.c b/mps/code/segsmss.c index e3ed646865e..f6e86010cd5 100644 --- a/mps/code/segsmss.c +++ b/mps/code/segsmss.c @@ -349,7 +349,7 @@ static Res AMSTInit(Pool pool, ArgList args) ArgRequire(&arg, args, MPS_KEY_FORMAT); format = arg.val.format; - res = AMSInitInternal(Pool2AMS(pool), format, chain, 0, FALSE); + res = AMSInitInternal(Pool2AMS(pool), format, chain, gen, FALSE); if (res != ResOK) return res; amst = Pool2AMST(pool); @@ -759,14 +759,19 @@ static void *test(void *arg, size_t s) mps_ap_t busy_ap; mps_addr_t busy_init; const char *indent = " "; + mps_chain_t chain; + static mps_gen_param_s genParam = {1024, 0.2}; arena = (mps_arena_t)arg; (void)s; /* unused */ die(mps_fmt_create_A(&format, arena, dylan_fmt_A()), "fmt_create"); + die(mps_chain_create(&chain, arena, 1, &genParam), "chain_create"); MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); + MPS_ARGS_ADD(args, MPS_KEY_GEN, 0); die(mps_pool_create_k(&pool, arena, mps_class_amst(), args), "pool_create(amst)"); } MPS_ARGS_END(args); @@ -842,6 +847,7 @@ static void *test(void *arg, size_t s) mps_root_destroy(exactRoot); mps_root_destroy(ambigRoot); mps_pool_destroy(pool); + mps_chain_destroy(chain); mps_fmt_destroy(format); return NULL; From 25d595211ab88d0678ded1e5cb16d7f11fa54672 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 12:56:30 +0100 Subject: [PATCH 132/266] Undo seghasbuffer change, to simplify the diffs. Copied from Perforce Change: 185890 ServerID: perforce.ravenbrook.com --- mps/code/buffer.c | 2 +- mps/code/mpm.h | 1 - mps/code/poolamc.c | 33 +++++++++++++++++---------------- mps/code/poolams.c | 11 ++++++----- mps/code/poolawl.c | 13 +++++++------ mps/code/poollo.c | 13 +++++++------ mps/code/poolsnc.c | 4 ++-- mps/code/segsmss.c | 3 +-- 8 files changed, 41 insertions(+), 39 deletions(-) diff --git a/mps/code/buffer.c b/mps/code/buffer.c index c6ac0c980ce..bbae1f3eacd 100644 --- a/mps/code/buffer.c +++ b/mps/code/buffer.c @@ -1333,7 +1333,7 @@ static void segBufAttach(Buffer buffer, Addr base, Addr limit, found = SegOfAddr(&seg, arena, base); AVER(found); AVER(segbuf->seg == NULL); - AVER(!SegHasBuffer(seg)); + AVER(SegBuffer(seg) == NULL); AVER(SegBase(seg) <= base); AVER(limit <= SegLimit(seg)); diff --git a/mps/code/mpm.h b/mps/code/mpm.h index ef45cbf5b48..e732ca8ee9f 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -708,7 +708,6 @@ extern Addr (SegLimit)(Seg seg); #define SegOfPoolRing(node) (RING_ELT(Seg, poolRing, (node))) #define SegOfGreyRing(node) (&(RING_ELT(GCSeg, greyRing, (node)) \ ->segStruct)) -#define SegHasBuffer(seg) (SegBuffer(seg) != NULL) #define SegSummary(seg) (((GCSeg)(seg))->summary) #define SegSetPM(seg, mode) ((void)((seg)->pm = BS_BITFIELD(Access, (mode)))) diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index f80c50fa137..72331270583 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -169,6 +169,7 @@ static Res AMCSegInit(Seg seg, Pool pool, Addr base, Size size, static void AMCSegSketch(Seg seg, char *pbSketch, size_t cbSketch) { amcSeg amcseg; + Buffer buffer; AVER(pbSketch); AVER(cbSketch >= 5); @@ -196,8 +197,10 @@ static void AMCSegSketch(Seg seg, char *pbSketch, size_t cbSketch) pbSketch[2] = 'W'; /* White */ } - if (SegHasBuffer(seg)) { - Buffer buffer = SegBuffer(seg); + buffer = SegBuffer(seg); + if(buffer == NULL) { + pbSketch[3] = '_'; + } else { Bool mut = BufferIsMutator(buffer); Bool flipped = ((buffer->mode & BufferModeFLIPPED) != 0); Bool trapped = BufferIsTrapped(buffer); @@ -220,8 +223,6 @@ static void AMCSegSketch(Seg seg, char *pbSketch, size_t cbSketch) } else { /* I don't know what's going on! */ } - } else { - pbSketch[3] = '_'; } pbSketch[4] = '\0'; @@ -287,7 +288,7 @@ static Res AMCSegDescribe(Seg seg, mps_lib_FILE *stream) if(res != ResOK) return res; - if (SegHasBuffer(seg)) + if(SegBuffer(seg) != NULL) init = BufferGetInit(SegBuffer(seg)); else init = limit; @@ -669,7 +670,6 @@ static Res amcGenCreate(amcGen *genReturn, AMC amc, GenDesc gen) if(res != ResOK) goto failGenInit; RingInit(&amcgen->amcRing); - amcgen->segs = 0; amcgen->forward = buffer; amcgen->sig = amcGenSig; @@ -1200,6 +1200,7 @@ static Res AMCWhiten(Pool pool, Trace trace, Seg seg) Size condemned = 0; amcGen gen; AMC amc; + Buffer buffer; amcSeg amcseg; Res res; @@ -1208,8 +1209,8 @@ static Res AMCWhiten(Pool pool, Trace trace, Seg seg) AVERT(Seg, seg); amcseg = Seg2amcSeg(seg); - if (SegHasBuffer(seg)) { - Buffer buffer = SegBuffer(seg); + buffer = SegBuffer(seg); + if(buffer != NULL) { AVERT(Buffer, buffer); if(!BufferIsMutator(buffer)) { /* forwarding buffer */ @@ -1380,7 +1381,7 @@ static Res amcScanNailedOnce(Bool *totalReturn, Bool *moreReturn, NailboardClearNewNails(board); p = SegBase(seg); - while (SegHasBuffer(seg)) { + while(SegBuffer(seg) != NULL) { limit = BufferScanLimit(SegBuffer(seg)); if(p >= limit) { AVER(p == limit); @@ -1485,7 +1486,7 @@ static Res AMCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg) base = AddrAdd(SegBase(seg), format->headerSize); /* */ - while (SegHasBuffer(seg)) { + while(SegBuffer(seg) != NULL) { limit = AddrAdd(BufferScanLimit(SegBuffer(seg)), format->headerSize); if(base >= limit) { @@ -1929,7 +1930,7 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg) headerSize = format->headerSize; ShieldExpose(arena, seg); p = SegBase(seg); - if (SegHasBuffer(seg)) { + if(SegBuffer(seg) != NULL) { limit = BufferScanLimit(SegBuffer(seg)); } else { limit = SegLimit(seg); @@ -1982,13 +1983,13 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg) /* Free the seg if we can; fixes .nailboard.limitations.middle. */ if(preservedInPlaceCount == 0 - && !SegHasBuffer(seg) + && (SegBuffer(seg) == NULL) && (SegNailed(seg) == TraceSetEMPTY)) { amcGen gen = amcSegGen(seg); /* We may not free a buffered seg. */ - AVER(!SegHasBuffer(seg)); + AVER(SegBuffer(seg) == NULL); PoolGenReclaim(&gen->pgen, SegSize(seg), Seg2amcSeg(seg)->deferred); PoolGenFree(&gen->pgen, seg); @@ -2065,7 +2066,7 @@ static void AMCReclaim(Pool pool, Trace trace, Seg seg) /* We may not free a buffered seg. (But all buffered + condemned */ /* segs should have been nailed anyway). */ - AVER(!SegHasBuffer(seg)); + AVER(SegBuffer(seg) == NULL); trace->reclaimSize += SegSize(seg); @@ -2134,7 +2135,7 @@ static void AMCWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f, /* If the segment is buffered, only walk as far as the end */ /* of the initialized objects. cf. AMCScan */ - if(SegHasBuffer(seg)) + if(SegBuffer(seg) != NULL) limit = BufferScanLimit(SegBuffer(seg)); else limit = SegLimit(seg); @@ -2232,7 +2233,7 @@ static Res AMCAddrObject(Addr *pReturn, Pool pool, Seg seg, Addr addr) arena = PoolArena(pool); base = SegBase(seg); - if (SegHasBuffer(seg)) { + if (SegBuffer(seg) != NULL) { /* We use BufferGetInit here (and not BufferScanLimit) because we * want to be able to find objects that have been allocated and * committed since the last flip. These objects lie between the diff --git a/mps/code/poolams.c b/mps/code/poolams.c index e3b7939a941..f822c9323d4 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -288,7 +288,7 @@ static void AMSSegFinish(Seg seg) ams = amsseg->ams; AVERT(AMS, ams); arena = PoolArena(AMS2Pool(ams)); - AVER(!SegHasBuffer(seg)); + AVER(SegBuffer(seg) == NULL); /* keep the destructions in step with AMSSegInit failure cases */ amsDestroyTables(ams, amsseg->allocTable, amsseg->nongreyTable, @@ -972,7 +972,7 @@ static Res AMSBufferFill(Addr *baseReturn, Addr *limitReturn, seg = AMSSeg2Seg(amsseg); if (SegRankSet(seg) == rankSet - && !SegHasBuffer(seg) + && SegBuffer(seg) == NULL /* Can't use a white or grey segment, see d.m.p.fill.colour. */ && SegWhite(seg) == TraceSetEMPTY && SegGrey(seg) == TraceSetEMPTY) @@ -1105,6 +1105,7 @@ static Res AMSWhiten(Pool pool, Trace trace, Seg seg) { AMS ams; AMSSeg amsseg; + Buffer buffer; /* the seg's buffer, if it has one */ Count uncondemned; AVERT(Pool, pool); @@ -1144,8 +1145,8 @@ static Res AMSWhiten(Pool pool, Trace trace, Seg seg) amsseg->allocTableInUse = TRUE; } - if (SegHasBuffer(seg)) { /* */ - Buffer buffer = SegBuffer(seg); + buffer = SegBuffer(seg); + if (buffer != NULL) { /* */ Index scanLimitIndex, limitIndex; scanLimitIndex = AMS_ADDR_INDEX(seg, BufferScanLimit(buffer)); limitIndex = AMS_ADDR_INDEX(seg, BufferLimit(buffer)); @@ -1631,7 +1632,7 @@ static void AMSReclaim(Pool pool, Trace trace, Seg seg) amsseg->colourTablesInUse = FALSE; SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace)); - if (amsseg->freeGrains == grains && !SegHasBuffer(seg)) + if (amsseg->freeGrains == grains && SegBuffer(seg) == NULL) /* No survivors */ PoolGenFree(&ams->pgen, seg); } diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 05c4ecdc57b..d57f70877c6 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -654,7 +654,7 @@ static Res AWLBufferFill(Addr *baseReturn, Addr *limitReturn, /* Only try to allocate in the segment if it is not already */ /* buffered, and has the same ranks as the buffer. */ - if (!SegHasBuffer(seg) + if (SegBuffer(seg) == NULL && SegRankSet(seg) == BufferRankSet(buffer) && AWLGrainsSize(awl, awlseg->freeGrains) >= size && AWLSegAlloc(&base, &limit, awlseg, awl, size)) @@ -749,6 +749,7 @@ static Res AWLWhiten(Pool pool, Trace trace, Seg seg) { AWL awl; AWLSeg awlseg; + Buffer buffer; Count uncondemned; /* All parameters checked by generic PoolWhiten. */ @@ -757,17 +758,17 @@ static Res AWLWhiten(Pool pool, Trace trace, Seg seg) AVERT(AWL, awl); awlseg = Seg2AWLSeg(seg); AVERT(AWLSeg, awlseg); + buffer = SegBuffer(seg); /* Can only whiten for a single trace, */ /* see */ AVER(SegWhite(seg) == TraceSetEMPTY); - if (!SegHasBuffer(seg)) { + if(buffer == NULL) { awlRangeWhiten(awlseg, 0, awlseg->grains); uncondemned = (Count)0; } else { /* Whiten everything except the buffer. */ - Buffer buffer = SegBuffer(seg); Addr base = SegBase(seg); Index scanLimitIndex = awlIndexOfAddr(base, awl, BufferScanLimit(buffer)); Index limitIndex = awlIndexOfAddr(base, awl, BufferLimit(buffer)); @@ -825,7 +826,7 @@ static void AWLGrey(Pool pool, Trace trace, Seg seg) AVERT(AWLSeg, awlseg); SegSetGrey(seg, TraceSetAdd(SegGrey(seg), trace)); - if (SegHasBuffer(seg)) { + if (SegBuffer(seg) != NULL) { Addr base = SegBase(seg); Buffer buffer = SegBuffer(seg); @@ -1130,7 +1131,7 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg) continue; } p = awlAddrOfIndex(base, awl, i); - if (SegHasBuffer(seg)) { + if (SegBuffer(seg) != NULL) { Buffer buffer = SegBuffer(seg); if(p == BufferScanLimit(buffer) @@ -1248,7 +1249,7 @@ static void AWLWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f, Addr next; Index i; - if (SegHasBuffer(seg)) { + if (SegBuffer(seg) != NULL) { Buffer buffer = SegBuffer(seg); if (object == BufferScanLimit(buffer) && BufferScanLimit(buffer) != BufferLimit(buffer)) { diff --git a/mps/code/poollo.c b/mps/code/poollo.c index 883275b2a1c..f53beeb3226 100644 --- a/mps/code/poollo.c +++ b/mps/code/poollo.c @@ -252,7 +252,7 @@ static Bool loSegFindFree(Addr *bReturn, Addr *lReturn, AVER(agrains <= loseg->freeGrains); AVER(size <= SegSize(seg)); - if (SegHasBuffer(seg)) + if (SegBuffer(seg) != NULL) /* Don't bother trying to allocate from a buffered segment */ return FALSE; @@ -338,11 +338,11 @@ static void loSegReclaim(LOSeg loseg, Trace trace) */ p = base; while(p < limit) { + Buffer buffer = SegBuffer(seg); Addr q; Index i; - if (SegHasBuffer(seg)) { - Buffer buffer = SegBuffer(seg); + if(buffer != NULL) { marked = TRUE; if (p == BufferScanLimit(buffer) && BufferScanLimit(buffer) != BufferLimit(buffer)) { @@ -429,7 +429,7 @@ static void LOWalk(Pool pool, Seg seg, Addr next; Index j; - if (SegHasBuffer(seg)) { + if(SegBuffer(seg) != NULL) { Buffer buffer = SegBuffer(seg); if(object == BufferScanLimit(buffer) && BufferScanLimit(buffer) != BufferLimit(buffer)) { @@ -676,6 +676,7 @@ static Res LOWhiten(Pool pool, Trace trace, Seg seg) { LO lo; LOSeg loseg; + Buffer buffer; Count grains, uncondemned; AVERT(Pool, pool); @@ -691,8 +692,8 @@ static Res LOWhiten(Pool pool, Trace trace, Seg seg) grains = loSegGrains(loseg); /* Whiten allocated objects; leave free areas black. */ - if (SegHasBuffer(seg)) { - Buffer buffer = SegBuffer(seg); + buffer = SegBuffer(seg); + if (buffer != NULL) { Addr base = SegBase(seg); Index scanLimitIndex = loIndexOfAddr(base, lo, BufferScanLimit(buffer)); Index limitIndex = loIndexOfAddr(base, lo, BufferLimit(buffer)); diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c index 9a21d0b2fba..e9afe98a96b 100644 --- a/mps/code/poolsnc.c +++ b/mps/code/poolsnc.c @@ -520,7 +520,7 @@ static Res SNCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg) /* If the segment is buffered, only walk as far as the end */ /* of the initialized objects. */ - if (SegHasBuffer(seg)) { + if (SegBuffer(seg) != NULL) { limit = BufferScanLimit(SegBuffer(seg)); } else { limit = SegLimit(seg); @@ -648,7 +648,7 @@ static void SNCWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f, /* If the segment is buffered, only walk as far as the end */ /* of the initialized objects. Cf. SNCScan. */ - if (SegHasBuffer(seg)) + if (SegBuffer(seg) != NULL) limit = BufferScanLimit(SegBuffer(seg)); else limit = SegLimit(seg); diff --git a/mps/code/segsmss.c b/mps/code/segsmss.c index b29ec3a8a74..49f75e681e2 100644 --- a/mps/code/segsmss.c +++ b/mps/code/segsmss.c @@ -334,7 +334,6 @@ static Res AMSTInit(Pool pool, ArgList args) Res res; unsigned gen = AMS_GEN_DEFAULT; ArgStruct arg; - unsigned gen = AMS_GEN_DEFAULT; AVERT(Pool, pool); AVERT(ArgList, args); @@ -556,7 +555,7 @@ static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn, if (SegLimit(seg) == limit && SegBase(seg) == base) { if (amstseg->prev != NULL) { Seg segLo = AMSTSeg2Seg(amstseg->prev); - if (!SegHasBuffer(segLo) && SegGrey(segLo) == SegGrey(seg)) { + if (SegBuffer(segLo) == NULL && SegGrey(segLo) == SegGrey(seg)) { /* .merge */ Seg mergedSeg; Res mres; From 405fde886fe683653eab87ab0f6b09d2ffe62c12 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 12:59:04 +0100 Subject: [PATCH 133/266] Revert a couple of whitespace changes to simplify the diffs. Copied from Perforce Change: 185891 ServerID: perforce.ravenbrook.com --- mps/code/poolawl.c | 2 +- mps/code/poollo.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index d57f70877c6..72a717fa7b9 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -1131,7 +1131,7 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg) continue; } p = awlAddrOfIndex(base, awl, i); - if (SegBuffer(seg) != NULL) { + if(SegBuffer(seg) != NULL) { Buffer buffer = SegBuffer(seg); if(p == BufferScanLimit(buffer) diff --git a/mps/code/poollo.c b/mps/code/poollo.c index f53beeb3226..9d97f261f63 100644 --- a/mps/code/poollo.c +++ b/mps/code/poollo.c @@ -252,7 +252,7 @@ static Bool loSegFindFree(Addr *bReturn, Addr *lReturn, AVER(agrains <= loseg->freeGrains); AVER(size <= SegSize(seg)); - if (SegBuffer(seg) != NULL) + if(SegBuffer(seg) != NULL) /* Don't bother trying to allocate from a buffered segment */ return FALSE; From cd099a2aae7d3160f25a6398513b6ab95b659baa Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 13:49:26 +0100 Subject: [PATCH 134/266] Better names for poolgen functions. Accounting for segment splitting and merging. Accounting for allocation and freeing in segsmss. Copied from Perforce Change: 185894 ServerID: perforce.ravenbrook.com --- mps/code/chain.h | 8 +++--- mps/code/locus.c | 67 +++++++++++++++++++++++++++++----------------- mps/code/mpm.h | 1 + mps/code/poolamc.c | 4 +-- mps/code/poolams.c | 6 +++-- mps/code/poolawl.c | 4 +-- mps/code/poollo.c | 4 +-- mps/code/seg.c | 4 +++ mps/code/segsmss.c | 18 ++++++++----- 9 files changed, 74 insertions(+), 42 deletions(-) diff --git a/mps/code/chain.h b/mps/code/chain.h index 889c0fc886f..9666eac943e 100644 --- a/mps/code/chain.h +++ b/mps/code/chain.h @@ -98,12 +98,14 @@ 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); -extern void PoolGenBufferFill(PoolGen pgen, Size size, Bool deferred); +extern void PoolGenFree(PoolGen pgen, Seg seg); +extern void PoolGenFill(PoolGen pgen, Size size, Bool deferred); +extern void PoolGenEmpty(PoolGen pgen, Size unused, Bool deferred); extern void PoolGenAge(PoolGen pgen, Size aged, Bool deferred); extern void PoolGenReclaim(PoolGen pgen, Size reclaimed, Bool deferred); -extern void PoolGenBufferEmpty(PoolGen pgen, Size unused, Bool deferred); extern void PoolGenUndefer(PoolGen pgen, Size oldSize, Size newSize); -extern void PoolGenFree(PoolGen pgen, Seg seg); +extern void PoolGenSegSplit(PoolGen pgen); +extern void PoolGenSegMerge(PoolGen pgen); #endif /* chain_h */ diff --git a/mps/code/locus.c b/mps/code/locus.c index 8c547edd582..ec7ae24f1ea 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -465,12 +465,12 @@ Bool PoolGenCheck(PoolGen pgen) } -/* PoolGenBufferFill -- accounting for buffer fill +/* PoolGenFill -- accounting for allocation * - * The buffer was free, is now new (or newDeferred). + * The memory was free, is now new (or newDeferred). */ -void PoolGenBufferFill(PoolGen pgen, Size size, Bool ramping) +void PoolGenFill(PoolGen pgen, Size size, Bool ramping) { AVERT(PoolGen, pgen); AVERT(Bool, ramping); @@ -484,6 +484,27 @@ void PoolGenBufferFill(PoolGen pgen, Size size, Bool ramping) } +/* PoolGenEmpty -- accounting for emptying a buffer + * + * The unused part of the buffer was new (or newDeferred) and is now free. + */ + +void PoolGenEmpty(PoolGen pgen, Size unused, Bool ramping) +{ + AVERT(PoolGen, pgen); + AVERT(Bool, ramping); + + if (ramping) { + AVER(pgen->newDeferredSize >= unused); + pgen->newDeferredSize -= unused; + } else { + AVER(pgen->newSize >= unused); + pgen->newSize -= unused; + } + pgen->freeSize += unused; +} + + /* PoolGenAge -- accounting for condemning a segment * * The memory was new (or newDeferred), is now old (or oldDeferred) @@ -526,27 +547,6 @@ void PoolGenReclaim(PoolGen pgen, Size reclaimed, Bool ramping) } -/* PoolGenBufferEmpty -- accounting for emptying a buffer - * - * The unused part of the buffer was new (or newDeferred) and is now free. - */ - -void PoolGenBufferEmpty(PoolGen pgen, Size unused, Bool ramping) -{ - AVERT(PoolGen, pgen); - AVERT(Bool, ramping); - - if (ramping) { - AVER(pgen->newDeferredSize >= unused); - pgen->newDeferredSize -= unused; - } else { - AVER(pgen->newSize >= unused); - pgen->newSize -= unused; - } - pgen->freeSize += unused; -} - - /* PoolGenUndefer -- accounting for end of ramp mode * * The memory was oldDeferred or newDeferred, is now old or new. @@ -564,6 +564,25 @@ void PoolGenUndefer(PoolGen pgen, Size oldSize, Size newSize) } +/* PoolGenSegSplit -- accounting for splitting a segment */ + +void PoolGenSegSplit(PoolGen pgen) +{ + AVERT(PoolGen, pgen); + ++ pgen->segs; +} + + +/* PoolGenSegMerge -- accounting for merging a segment */ + +void PoolGenSegMerge(PoolGen pgen) +{ + AVERT(PoolGen, pgen); + AVER(pgen->segs > 0); + -- pgen->segs; +} + + /* PoolGenFree -- free a segment and update accounting * * The segment is assumed to finish free. diff --git a/mps/code/mpm.h b/mps/code/mpm.h index e732ca8ee9f..0cbad2b0f1c 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -708,6 +708,7 @@ extern Addr (SegLimit)(Seg seg); #define SegOfPoolRing(node) (RING_ELT(Seg, poolRing, (node))) #define SegOfGreyRing(node) (&(RING_ELT(GCSeg, greyRing, (node)) \ ->segStruct)) + #define SegSummary(seg) (((GCSeg)(seg))->summary) #define SegSetPM(seg, mode) ((void)((seg)->pm = BS_BITFIELD(Access, (mode)))) diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 72331270583..4baf8cb1789 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -1062,7 +1062,7 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn, } } - PoolGenBufferFill(pgen, SegSize(seg), Seg2amcSeg(seg)->deferred); + PoolGenFill(pgen, SegSize(seg), Seg2amcSeg(seg)->deferred); *baseReturn = base; *limitReturn = limit; return ResOK; @@ -1107,7 +1107,7 @@ static void AMCBufferEmpty(Pool pool, Buffer buffer, ShieldCover(arena, seg); } - PoolGenBufferEmpty(&amcSegGen(seg)->pgen, 0, Seg2amcSeg(seg)->deferred); + PoolGenEmpty(&amcSegGen(seg)->pgen, 0, Seg2amcSeg(seg)->deferred); } diff --git a/mps/code/poolams.c b/mps/code/poolams.c index f822c9323d4..5ad40ed0153 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -399,6 +399,7 @@ static Res AMSSegMerge(Seg seg, Seg segHi, amssegHi->sig = SigInvalid; AVERT(AMSSeg, amsseg); + PoolGenSegMerge(&ams->pgen); return ResOK; failSuper: @@ -504,6 +505,7 @@ static Res AMSSegSplit(Seg seg, Seg segHi, amssegHi->sig = AMSSegSig; AVERT(AMSSeg, amsseg); AVERT(AMSSeg, amssegHi); + PoolGenSegSplit(&ams->pgen); return ResOK; failSuper: @@ -997,7 +999,7 @@ static Res AMSBufferFill(Addr *baseReturn, Addr *limitReturn, DebugPoolFreeCheck(pool, baseAddr, limitAddr); allocatedSize = AddrOffset(baseAddr, limitAddr); - PoolGenBufferFill(&ams->pgen, allocatedSize, FALSE); + PoolGenFill(&ams->pgen, allocatedSize, FALSE); *baseReturn = baseAddr; *limitReturn = limitAddr; return ResOK; @@ -1079,7 +1081,7 @@ static void AMSBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit) AVER(amsseg->newGrains >= limitIndex - initIndex); amsseg->newGrains -= limitIndex - initIndex; size = AddrOffset(init, limit); - PoolGenBufferEmpty(&ams->pgen, size, FALSE); + PoolGenEmpty(&ams->pgen, size, FALSE); } diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 72a717fa7b9..d0d5b75cd5a 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -685,7 +685,7 @@ static Res AWLBufferFill(Addr *baseReturn, Addr *limitReturn, AVER(awlseg->freeGrains >= j - i); awlseg->freeGrains -= j - i; awlseg->newGrains += j - i; - PoolGenBufferFill(&awl->pgen, AddrOffset(base, limit), FALSE); + PoolGenFill(&awl->pgen, AddrOffset(base, limit), FALSE); } *baseReturn = base; *limitReturn = limit; @@ -724,7 +724,7 @@ static void AWLBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit) AVER(awlseg->newGrains >= j - i); awlseg->newGrains -= j - i; awlseg->freeGrains += j - i; - PoolGenBufferEmpty(&awl->pgen, AddrOffset(init, limit), FALSE); + PoolGenEmpty(&awl->pgen, AddrOffset(init, limit), FALSE); } } diff --git a/mps/code/poollo.c b/mps/code/poollo.c index 9d97f261f63..0bab8336998 100644 --- a/mps/code/poollo.c +++ b/mps/code/poollo.c @@ -610,7 +610,7 @@ static Res LOBufferFill(Addr *baseReturn, Addr *limitReturn, loseg->newGrains += limitIndex - baseIndex; } - PoolGenBufferFill(&lo->pgen, AddrOffset(base, limit), FALSE); + PoolGenFill(&lo->pgen, AddrOffset(base, limit), FALSE); *baseReturn = base; *limitReturn = limit; @@ -665,7 +665,7 @@ static void LOBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit) AVER(loseg->newGrains >= limitIndex - initIndex); loseg->newGrains -= limitIndex - initIndex; loseg->freeGrains += limitIndex - initIndex; - PoolGenBufferEmpty(&lo->pgen, AddrOffset(init, limit), FALSE); + PoolGenEmpty(&lo->pgen, AddrOffset(init, limit), FALSE); } } diff --git a/mps/code/seg.c b/mps/code/seg.c index 7f0cd4bc907..fe965dbbda4 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -636,6 +636,10 @@ Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at, AVER(at < limit); AVERT(Bool, withReservoirPermit); + /* Can only split a buffered segment if the entire buffer is below + * the split point. */ + AVER(SegBuffer(seg) == NULL || BufferLimit(SegBuffer(seg)) <= at); + ShieldFlush(arena); /* see */ /* Allocate the new segment object from the control pool */ diff --git a/mps/code/segsmss.c b/mps/code/segsmss.c index 49f75e681e2..ea57a4475a2 100644 --- a/mps/code/segsmss.c +++ b/mps/code/segsmss.c @@ -434,7 +434,7 @@ static Bool AMSSegRegionIsFree(Seg seg, Addr base, Addr limit) * Used as a means of overriding the behaviour of AMSBufferFill. * The code is similar to AMSBufferEmpty. */ -static void AMSUnallocateRange(Seg seg, Addr base, Addr limit) +static void AMSUnallocateRange(AMS ams, Seg seg, Addr base, Addr limit) { AMSSeg amsseg; Index baseIndex, limitIndex; @@ -465,6 +465,7 @@ static void AMSUnallocateRange(Seg seg, Addr base, Addr limit) amsseg->freeGrains += limitIndex - baseIndex; AVER(amsseg->newGrains >= limitIndex - baseIndex); amsseg->newGrains -= limitIndex - baseIndex; + PoolGenEmpty(&ams->pgen, AddrOffset(base, limit), FALSE); } @@ -473,7 +474,7 @@ static void AMSUnallocateRange(Seg seg, Addr base, Addr limit) * Used as a means of overriding the behaviour of AMSBufferFill. * The code is similar to AMSUnallocateRange. */ -static void AMSAllocateRange(Seg seg, Addr base, Addr limit) +static void AMSAllocateRange(AMS ams, Seg seg, Addr base, Addr limit) { AMSSeg amsseg; Index baseIndex, limitIndex; @@ -504,6 +505,7 @@ static void AMSAllocateRange(Seg seg, Addr base, Addr limit) AVER(amsseg->freeGrains >= limitIndex - baseIndex); amsseg->freeGrains -= limitIndex - baseIndex; amsseg->newGrains += limitIndex - baseIndex; + PoolGenFill(&ams->pgen, AddrOffset(base, limit), FALSE); } @@ -528,6 +530,7 @@ static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn, PoolClass super; Addr base, limit; Arena arena; + AMS ams; AMST amst; Bool b; Seg seg; @@ -539,6 +542,7 @@ static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn, AVER(limitReturn != NULL); /* other parameters are checked by next method */ arena = PoolArena(pool); + ams = Pool2AMS(pool); amst = Pool2AMST(pool); /* call next method */ @@ -560,14 +564,14 @@ static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn, Seg mergedSeg; Res mres; - AMSUnallocateRange(seg, base, limit); + AMSUnallocateRange(ams, seg, base, limit); mres = SegMerge(&mergedSeg, segLo, seg, withReservoirPermit); if (ResOK == mres) { /* successful merge */ - AMSAllocateRange(mergedSeg, base, limit); + AMSAllocateRange(ams, mergedSeg, base, limit); /* leave range as-is */ } else { /* failed to merge */ AVER(amst->failSegs); /* deliberate fails only */ - AMSAllocateRange(seg, base, limit); + AMSAllocateRange(ams, seg, base, limit); } } @@ -578,13 +582,13 @@ static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn, Addr mid = AddrAdd(base, half); Seg segLo, segHi; Res sres; - AMSUnallocateRange(seg, mid, limit); + AMSUnallocateRange(ams, seg, mid, limit); sres = SegSplit(&segLo, &segHi, seg, mid, withReservoirPermit); if (ResOK == sres) { /* successful split */ limit = mid; /* range is lower segment */ } else { /* failed to split */ AVER(amst->failSegs); /* deliberate fails only */ - AMSAllocateRange(seg, mid, limit); + AMSAllocateRange(ams, seg, mid, limit); } } From 9e73b7d3d875bcc9442c82fe4e2da93aefeffccd Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 15:07:00 +0100 Subject: [PATCH 135/266] Correct links to task branches. Copied from Perforce Change: 185895 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 db54da83ce1..5a3b4d8652d 100755 --- a/mps/tool/branch +++ b/mps/tool/branch @@ -46,7 +46,7 @@ CHILD_RE = r'(?:{}|{})$'.format(TASK_BRANCH_RE, VERSION_BRANCH_RE) TASK_BRANCH_ENTRY = ''' - {date}/{task} + {date}/{task} Changes {desc_html} Active (diffs). From b9ccc0af7a01f4dcf6e3e07b56d4d2b60a6b66c6 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 15:24:26 +0100 Subject: [PATCH 136/266] Fix problems identified by dl in . Copied from Perforce Change: 185897 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 2 +- mps/code/comm.gmk | 3 ++- mps/code/commpost.nmk | 4 ++-- mps/code/poolamc.c | 14 ++++++++++---- mps/code/seg.c | 10 +++++++--- mps/code/ssan.c | 2 ++ mps/design/config.txt | 9 ++++----- mps/tool/testcases.txt | 11 ++++++----- mps/tool/testrun.bat | 3 +++ mps/tool/testrun.sh | 1 + 10 files changed, 38 insertions(+), 21 deletions(-) diff --git a/mps/Makefile.in b/mps/Makefile.in index 4ecd4e90aea..4d4a7d43be7 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -73,7 +73,7 @@ test-make-build: $(MAKE) clean $(MAKE) $(TARGET_OPTS) VARIETY=hot CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE" testansi $(MAKE) clean - $(MAKE) $(TARGET_OPTS) VARIETY=hot CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE -DCONFIG_POLL_NONE" # TODO: actually run some tests in this configuration + $(MAKE) $(TARGET_OPTS) VARIETY=hot CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE -DCONFIG_POLL_NONE" testpoll test-xcode-build: $(XCODEBUILD) -config Release -target testci diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index 72615cc8417..589b6db40ba 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -288,8 +288,9 @@ 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 -TEST_SUITES=testrun testci testall testansi +TEST_SUITES=testrun testci testall testansi testpoll $(addprefix $(PFM)/$(VARIETY)/,$(TEST_SUITES)): $(TEST_TARGETS) ../tool/testrun.sh "$(PFM)/$(VARIETY)" "$(notdir $@)" diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk index 9c34bb18f9d..ca44c8a7db2 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/commpost.nmk @@ -53,10 +53,10 @@ variety: $(PFM)\$(VARIETY)\$(TARGET) !ENDIF !ENDIF -# testrun testci testall testansi +# testrun testci testall testansi testpoll # Runs automated test cases. -testrun testci testall testansi: $(TEST_TARGETS) +testrun testci testall testansi testpoll: $(TEST_TARGETS) !IFDEF VARIETY ..\tool\testrun.bat $(PFM) $(VARIETY) $@ !ELSE diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index aeb04454efe..d62fd48b54a 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -1719,10 +1719,13 @@ static Res AMCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO) /* Since we're moving an object from one segment to another, */ /* union the greyness and the summaries together. */ grey = SegGrey(seg); - if(SegRankSet(seg) != RankSetEMPTY) /* not for AMCZ */ + if(SegRankSet(seg) != RankSetEMPTY) { /* not for AMCZ */ grey = TraceSetUnion(grey, ss->traces); + SegSetSummary(toSeg, RefSetUnion(SegSummary(toSeg), SegSummary(seg))); + } else { + AVER(SegRankSet(toSeg) == RankSetEMPTY); + } SegSetGrey(toSeg, TraceSetUnion(SegGrey(toSeg), grey)); - SegSetSummary(toSeg, RefSetUnion(SegSummary(toSeg), SegSummary(seg))); /* */ (void)AddrCopy(newRef, ref, length); /* .exposed.seg */ @@ -1867,10 +1870,13 @@ static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO) /* Since we're moving an object from one segment to another, */ /* union the greyness and the summaries together. */ grey = SegGrey(seg); - if(SegRankSet(seg) != RankSetEMPTY) /* not for AMCZ */ + if(SegRankSet(seg) != RankSetEMPTY) { /* not for AMCZ */ grey = TraceSetUnion(grey, ss->traces); + SegSetSummary(toSeg, RefSetUnion(SegSummary(toSeg), SegSummary(seg))); + } else { + AVER(SegRankSet(toSeg) == RankSetEMPTY); + } SegSetGrey(toSeg, TraceSetUnion(SegGrey(toSeg), grey)); - SegSetSummary(toSeg, RefSetUnion(SegSummary(toSeg), SegSummary(seg))); /* */ (void)AddrCopy(newBase, AddrSub(ref, headerSize), length); /* .exposed.seg */ diff --git a/mps/code/seg.c b/mps/code/seg.c index 62a7397dfeb..2fb680c7094 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -310,7 +310,7 @@ void SegSetSummary(Seg seg, RefSet summary) AVER(summary == RefSetEMPTY || SegRankSet(seg) != RankSetEMPTY); #if defined(REMEMBERED_SET) -/* Nothing to do. */ + /* Nothing to do. */ #elif defined(REMEMBERED_SET_NONE) /* Without protection, we can't maintain the remembered set because there are writes we don't know about. TODO: rethink this when @@ -332,11 +332,15 @@ void SegSetRankAndSummary(Seg seg, RankSet rankSet, RefSet summary) AVERT(Seg, seg); AVERT(RankSet, rankSet); -#ifdef DISABLE_REMEMBERED_SET +#if defined(REMEMBERED_SET) + /* Nothing to do. */ +#elif defined(REMEMBERED_SET_NONE) if (rankSet != RankSetEMPTY) { summary = RefSetUNIV; } -#endif +#else +#error "No remembered set configuration." +#endif /* REMEMBERED_SET */ seg->class->setRankSummary(seg, rankSet, summary); } diff --git a/mps/code/ssan.c b/mps/code/ssan.c index 603895dbf49..27233e7b9f6 100644 --- a/mps/code/ssan.c +++ b/mps/code/ssan.c @@ -33,6 +33,8 @@ Res StackScan(ScanState ss, Addr *stackBot) */ AVER(stackTop < (void *)stackBot); + (void)setjmp(jb); + return StackScanInner(ss, stackBot, stackTop, sizeof jb / sizeof(Addr*)); } diff --git a/mps/design/config.txt b/mps/design/config.txt index 0bc7f71857b..b99191d7ab6 100644 --- a/mps/design/config.txt +++ b/mps/design/config.txt @@ -540,11 +540,10 @@ for single-threaded execution only, where locks are not needed and so lock operations can be defined as no-ops by ``lock.h``. _`.opt.poll`: ``CONFIG_POLL_NONE`` causes the MPS to be built without -support for polling. This means that the arena must be clamped or -parked at all this, garbage collections can only be carried out -explicitly via ``mps_arena_collect()``, but it also means that -protection is not needed, and so shield operations can be replaced -with no-ops in ``mpm.h``. +support for polling. This means that garbage collections will only +happen if requested explicitly via ``mps_arena_collect()`` or +``mps_arena_step()``, but it also means that protection is not needed, +and so shield operations can be replaced with no-ops in ``mpm.h``. To document diff --git a/mps/tool/testcases.txt b/mps/tool/testcases.txt index e75de947f88..ba49ae6f717 100644 --- a/mps/tool/testcases.txt +++ b/mps/tool/testcases.txt @@ -3,9 +3,9 @@ Test case Flags Notes ============= ================ ========================================== abqtest airtest -amcss -amcsshe -amcssth =B =T job003561, job003703 +amcss =P +amcsshe =P +amcssth =B =P =T job003561, job003703 amsss =B job001549 amssshe =B job001549 apss @@ -16,10 +16,10 @@ awlutth =T btcv bttest =N interactive djbench =N benchmark -exposet0 +exposet0 =P expt825 fbmtest -finalcv +finalcv =P finaltest fotest gcbench =N benchmark @@ -50,6 +50,7 @@ Key to flags B -- known Bad L -- Long runtime N -- Not an automated test case + P -- relies on Polling T -- multi-Threaded W -- Windows-only X -- Unix-only diff --git a/mps/tool/testrun.bat b/mps/tool/testrun.bat index b8f7c89d314..2aaf8aa4956 100755 --- a/mps/tool/testrun.bat +++ b/mps/tool/testrun.bat @@ -15,6 +15,8 @@ @echo off @rem Find test case database in same directory as this script. +@rem The incantation %%~dpF% expands %%F to a drive letter and path only. +@rem See "help for" for more details. for %%F in ("%0") do set TEST_CASE_DB=%%~dpF%testcases.txt set PFM=%1 @@ -37,6 +39,7 @@ 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 @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 5950aa5d1e2..3d296a15513 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -42,6 +42,7 @@ if [ $# -eq 1 ]; then testci) EXCLUDE="BNW" ;; testall) EXCLUDE="NW" ;; testansi) EXCLUDE="LNTW" ;; + testpoll) EXCLUDE="LNPTW" ;; *) echo "Test suite $TEST_SUITE not recognized." exit 1 ;; From 6f9fffb26aac452cb9076082dd5288b1988da00d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 16:06:40 +0100 Subject: [PATCH 137/266] Use variety=cool to get more checking. Copied from Perforce Change: 185900 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mps/Makefile.in b/mps/Makefile.in index 4d4a7d43be7..aaab5a677f2 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -31,7 +31,7 @@ install-make-build: make-install-dirs build-via-make $(INSTALL_DATA) code/mps*.h $(prefix)/include/ $(INSTALL_DATA) code/$(MPS_TARGET_NAME)/cool/mps.a $(prefix)/lib/libmps-debug.a $(INSTALL_DATA) code/$(MPS_TARGET_NAME)/hot/mps.a $(prefix)/lib/libmps.a - $(INSTALL_PROGRAM) $(addprefix code/$(MPS_TARGET_NAME)/hot/Release/,$(EXTRA_TARGETS)) $(prefix)/bin + $(INSTALL_PROGRAM) $(addprefix code/$(MPS_TARGET_NAME)/hot/,$(EXTRA_TARGETS)) $(prefix)/bin build-via-xcode: $(XCODEBUILD) -config Release @@ -71,9 +71,9 @@ test-make-build: $(MAKE) clean $(MAKE) $(TARGET_OPTS) testci $(MAKE) clean - $(MAKE) $(TARGET_OPTS) VARIETY=hot CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE" testansi + $(MAKE) $(TARGET_OPTS) VARIETY=cool CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE" testansi $(MAKE) clean - $(MAKE) $(TARGET_OPTS) VARIETY=hot CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE -DCONFIG_POLL_NONE" testpoll + $(MAKE) $(TARGET_OPTS) VARIETY=cool CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE -DCONFIG_POLL_NONE" testpoll test-xcode-build: $(XCODEBUILD) -config Release -target testci From bd0e9da9ceed1e90226add4727e91357b1497a73 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 16:29:42 +0100 Subject: [PATCH 138/266] All prottramp implementations are now the same, so there is no need for separate implementations. Copied from Perforce Change: 185901 ServerID: perforce.ravenbrook.com --- mps/code/mpm.h | 2 -- mps/code/mpsi.c | 2 +- mps/code/protan.c | 17 ++--------------- mps/code/protix.c | 23 ++--------------------- mps/code/protw3.c | 22 ++-------------------- mps/design/prot.txt | 4 ---- mps/design/protli.txt | 5 ----- mps/design/protsu.txt | 5 ----- 8 files changed, 7 insertions(+), 73 deletions(-) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 0cbad2b0f1c..499ca555113 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -922,8 +922,6 @@ extern void (ShieldFlush)(Arena arena); extern void ProtSetup(void); extern void ProtSet(Addr base, Addr limit, AccessSet mode); -extern void ProtTramp(void **resultReturn, void *(*f)(void *, size_t), - void *p, size_t s); extern void ProtSync(Arena arena); extern Bool ProtCanStepInstruction(MutatorFaultContext context); extern Res ProtStepInstruction(MutatorFaultContext context); diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 3df0913df83..45ffff50166 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1380,7 +1380,7 @@ void (mps_tramp)(void **r_o, AVER(FUNCHECK(f)); /* Can't check p and s as they are interpreted by the client */ - ProtTramp(r_o, f, p, s); + *r_o = (*f)(p, s); } diff --git a/mps/code/protan.c b/mps/code/protan.c index 51b2edd6df8..3709e88be59 100644 --- a/mps/code/protan.c +++ b/mps/code/protan.c @@ -1,7 +1,7 @@ /* protan.c: ANSI MEMORY PROTECTION * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * * DESIGN @@ -65,22 +65,9 @@ void ProtSync(Arena arena) } -/* ProtTramp -- protection trampoline */ - -void ProtTramp(void **rReturn, void *(*f)(void *, size_t), - void *p, size_t s) -{ - AVER(rReturn != NULL); - AVER(FUNCHECK(f)); - /* Can't check p and s as they are interpreted by the client */ - - *(rReturn) = (*(f))(p, s); -} - - /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/protix.c b/mps/code/protix.c index 31c272bc5b9..854bfc98174 100644 --- a/mps/code/protix.c +++ b/mps/code/protix.c @@ -1,7 +1,7 @@ /* protix.c: PROTECTION FOR UNIX * * $Id$ - * Copyright (c) 2001,2007 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * Somewhat generic across different Unix systems. Shared between * Darwin (OS X), FreeBSD, and Linux. @@ -114,28 +114,9 @@ void ProtSync(Arena arena) } -/* ProtTramp -- protection trampoline - * - * The protection trampoline is trivial under Unix, as there is - * nothing that needs to be done in the dynamic context of the mutator in - * order to catch faults. (Contrast this with Win32 Structured Exception - * Handling.) - */ - -void ProtTramp(void **resultReturn, void *(*f)(void *, size_t), - void *p, size_t s) -{ - AVER(resultReturn != NULL); - AVER(FUNCHECK(f)); - /* Can't check p and s as they are interpreted by the client */ - - *resultReturn = (*f)(p, s); -} - - /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2007 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/protw3.c b/mps/code/protw3.c index 43e0522c074..84ef680ffb9 100644 --- a/mps/code/protw3.c +++ b/mps/code/protw3.c @@ -1,7 +1,7 @@ /* protw3.c: PROTECTION FOR WIN32 * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. */ #include "mpm.h" @@ -131,27 +131,9 @@ void ProtSync(Arena arena) } -/* ProtTramp -- wrap a mutator thread in a Structured Exception Handler filter - * - * This was the method by which we installed an exception handler on Windows - * prior to MPS 1.111. Now we are using Vectored Exception Handlers, so this - * is deprecated and just calls through to the mutator function. - */ - -void ProtTramp(void **resultReturn, void *(*f)(void *, size_t), - void *p, size_t s) -{ - AVER(resultReturn != NULL); - AVER(FUNCHECK(f)); - /* Can't check p and s as they are interpreted by the client */ - - *resultReturn = f(p, s); -} - - /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/design/prot.txt b/mps/design/prot.txt index a56e53db096..0d30017fede 100644 --- a/mps/design/prot.txt +++ b/mps/design/prot.txt @@ -47,10 +47,6 @@ forbidden. A request to forbid read accesses (that is, ``AccessREAD`` is set) may also forbid write accesses, but read accesses will not be forbidden unless ``AccessREAD`` is set. -``void ProtTramp(void **resultReturn, void *(*f)(void *, size_t), void *p, size_t s)`` - -_`.if.tramp`: [undocumented] - ``void ProtSync(Space space)`` _`.if.sync`: ``ProtSync()`` is called to ensure that the actual diff --git a/mps/design/protli.txt b/mps/design/protli.txt index a5cc1d57a15..9b0958ac191 100644 --- a/mps/design/protli.txt +++ b/mps/design/protli.txt @@ -88,11 +88,6 @@ underlying object). _`.fun.sync`: ``ProtSync()`` does nothing in this implementation as ``ProtSet()`` sets the protection without any delay. -_`.fun.tramp`: The protection trampoline, ``ProtTramp()``, is trivial -under Linux, as there is nothing that needs to be done in the dynamic -context of the mutator in order to catch faults. (Contrast this with -Win32 Structured Exception Handling.) - Threads ------- diff --git a/mps/design/protsu.txt b/mps/design/protsu.txt index 616d9134c88..1bd57e1004a 100644 --- a/mps/design/protsu.txt +++ b/mps/design/protsu.txt @@ -110,11 +110,6 @@ access that is compatible with the access of the underlying object). _`.fun.sync`: ``ProtSync()``. This does nothing in this implementation as ProtSet sets the protection without any delay. -_`.fun.tramp`: ``ProtTramp()``. The protection trampoline is trivial -under SunOS, as there is nothing that needs to be done in the dynamic -context of the mutator in order to catch faults. (Contrast this with -Win32 Structured Exception Handling.) - Document History ---------------- From 282b0cb8309ec58125bb9377d9a7ef6f0a470aeb Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 16:30:01 +0100 Subject: [PATCH 139/266] Update comment to match design. Copied from Perforce Change: 185902 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index 4a3595e1f17..d304d57a87a 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -183,11 +183,10 @@ /* CONFIG_POLL_NONE -- no support for polling * * This symbol causes the MPS to built without support for polling. - * This means that the arena must be clamped or parked at all times, - * garbage collections can only be carried out explicitly via - * mps_arena_collect(), but it also means that protection is not - * needed, and so shield operations can be replaced with no-ops in - * mpm.h. + * This means that garbage collections will only happen if requested + * explicitly via mps_arena_collect() or mps_arena_step(), but it also + * means that protection is not needed, and so shield operations can + * be replaced with no-ops in mpm.h. */ #if !defined(CONFIG_POLL_NONE) From d9e0b8883c728ca6d5875f8eeb8b581a0e3fdacb Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 16:34:40 +0100 Subject: [PATCH 140/266] Awl now returns segments to the arena when they are free. Copied from Perforce Change: 185906 ServerID: perforce.ravenbrook.com --- mps/code/poolawl.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index d0d5b75cd5a..42528eaa014 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -1100,6 +1100,7 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg) Addr base; AWL awl; AWLSeg awlseg; + Buffer buffer; Index i; Count oldFree; Format format; @@ -1119,6 +1120,7 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg) format = pool->format; base = SegBase(seg); + buffer = SegBuffer(seg); i = 0; oldFree = awlseg->freeGrains; @@ -1131,15 +1133,12 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg) continue; } p = awlAddrOfIndex(base, awl, i); - if(SegBuffer(seg) != NULL) { - Buffer buffer = SegBuffer(seg); - - if(p == BufferScanLimit(buffer) - && BufferScanLimit(buffer) != BufferLimit(buffer)) - { - i = awlIndexOfAddr(base, awl, BufferLimit(buffer)); - continue; - } + if (buffer != NULL + && p == BufferScanLimit(buffer) + && BufferScanLimit(buffer) != BufferLimit(buffer)) + { + i = awlIndexOfAddr(base, awl, BufferLimit(buffer)); + continue; } q = format->skip(AddrAdd(p, format->headerSize)); q = AddrSub(q, format->headerSize); @@ -1172,7 +1171,10 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg) trace->preservedInPlaceCount += preservedInPlaceCount; trace->preservedInPlaceSize += preservedInPlaceSize; SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace)); - /* @@@@ never frees a segment, see job001687. */ + + if (awlseg->freeGrains == awlseg->grains && buffer == NULL) + /* No survivors */ + PoolGenFree(&awl->pgen, seg); } From 93db817d30e57e6ca34b137e804b6b82cd803b44 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 17:00:11 +0100 Subject: [PATCH 141/266] Arenarelease now calls arenapoll (not tracepoll) so that it doesn't break in config_poll_none. Copied from Perforce Change: 185908 ServerID: perforce.ravenbrook.com --- mps/code/traceanc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/traceanc.c b/mps/code/traceanc.c index 675e18e1f95..8e0be12dac9 100644 --- a/mps/code/traceanc.c +++ b/mps/code/traceanc.c @@ -560,7 +560,7 @@ void ArenaRelease(Globals globals) AVERT(Globals, globals); arenaForgetProtection(globals); globals->clamped = FALSE; - (void)TracePoll(globals); + ArenaPoll(globals); } From 9ad6005a186a13ce8fae04a0809edc0a921b8081 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 17:38:51 +0100 Subject: [PATCH 142/266] Add testpoll on os x. Copied from Perforce Change: 185910 ServerID: perforce.ravenbrook.com --- mps/code/mps.xcodeproj/project.pbxproj | 94 ++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 12 deletions(-) diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index e5408fe2c93..4a1dc5ed506 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -17,7 +17,7 @@ 225F0AFD18E4453A003F2183 /* PBXTargetDependency */, ); name = testci; - productName = testrun; + productName = testci; }; 225F0B0418E44549003F2183 /* testall */ = { isa = PBXAggregateTarget; @@ -29,7 +29,7 @@ 225F0B0518E44549003F2183 /* PBXTargetDependency */, ); name = testall; - productName = testrun; + productName = testall; }; 2291B6E318E4754D0004B79C /* testansi */ = { isa = PBXAggregateTarget; @@ -41,7 +41,19 @@ 2291B6E418E4754D0004B79C /* PBXTargetDependency */, ); name = testansi; - productName = testrun; + productName = testansi; + }; + 22965BB219115D4600138A8F /* testpoll */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 22965BB619115D4600138A8F /* Build configuration list for PBXAggregateTarget "testpoll" */; + buildPhases = ( + 22965BB519115D4600138A8F /* ShellScript */, + ); + dependencies = ( + 22965BB319115D4600138A8F /* PBXTargetDependency */, + ); + name = testpoll; + productName = testpoll; }; 22CDE8EF16E9E97D00366D0A /* testrun */ = { isa = PBXAggregateTarget; @@ -442,6 +454,13 @@ remoteGlobalIDString = 3104AFF1156D37A0000A585A; remoteInfo = all; }; + 22965BB419115D4600138A8F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3104AFF1156D37A0000A585A; + remoteInfo = all; + }; 22B2BC3818B643AD00C33E63 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; @@ -3372,6 +3391,7 @@ 225F0AFC18E4453A003F2183 /* testci */, 225F0B0418E44549003F2183 /* testall */, 2291B6E318E4754D0004B79C /* testansi */, + 22965BB219115D4600138A8F /* testpoll */, 31EEABFA156AAF9D00714D05 /* mps */, 3114A632156E94DB001E0AA3 /* abqtest */, 22FACEE018880983000FDBC1 /* airtest */, @@ -3466,6 +3486,20 @@ shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\""; showEnvVarsInLog = 0; }; + 22965BB519115D4600138A8F /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\""; + showEnvVarsInLog = 0; + }; 22CDE8F416E9E9D400366D0A /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -4063,6 +4097,11 @@ target = 3104AFF1156D37A0000A585A /* all */; targetProxy = 2291B6E518E4754D0004B79C /* PBXContainerItemProxy */; }; + 22965BB319115D4600138A8F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3104AFF1156D37A0000A585A /* all */; + targetProxy = 22965BB419115D4600138A8F /* PBXContainerItemProxy */; + }; 22B2BC3918B643AD00C33E63 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 31FCAE0917692403008C034C /* scheme */; @@ -4495,42 +4534,42 @@ 225F0B0118E4453A003F2183 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = "testrun copy"; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 225F0B0218E4453A003F2183 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = "testrun copy"; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 225F0B0318E4453A003F2183 /* RASH */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = "testrun copy"; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = RASH; }; 225F0B0918E44549003F2183 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = "testrun copy copy"; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 225F0B0A18E44549003F2183 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = "testrun copy copy"; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 225F0B0B18E44549003F2183 /* RASH */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = "testrun copy copy"; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = RASH; }; @@ -4579,21 +4618,42 @@ 2291B6E818E4754D0004B79C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = "testall copy"; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 2291B6E918E4754D0004B79C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = "testall copy"; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 2291B6EA18E4754D0004B79C /* RASH */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = "testall copy"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = RASH; + }; + 22965BB719115D4600138A8F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 22965BB819115D4600138A8F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 22965BB919115D4600138A8F /* RASH */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = RASH; }; @@ -5819,6 +5879,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 22965BB619115D4600138A8F /* Build configuration list for PBXAggregateTarget "testpoll" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 22965BB719115D4600138A8F /* Debug */, + 22965BB819115D4600138A8F /* Release */, + 22965BB919115D4600138A8F /* RASH */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 22B2BC3218B6434F00C33E63 /* Build configuration list for PBXNativeTarget "scheme-advanced" */ = { isa = XCConfigurationList; buildConfigurations = ( From 799ecf04204f137de1f7074c8c78c25c000b4778 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 30 Apr 2014 17:39:37 +0100 Subject: [PATCH 143/266] Output all the pool generation accounting information. Copied from Perforce Change: 185911 ServerID: perforce.ravenbrook.com --- mps/code/eventdef.h | 7 ++++++- mps/code/trace.c | 6 ++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mps/code/eventdef.h b/mps/code/eventdef.h index c7e076a9251..4999be4ee69 100644 --- a/mps/code/eventdef.h +++ b/mps/code/eventdef.h @@ -720,7 +720,12 @@ PARAM(X, 3, W, zone) /* zone set of generation */ \ PARAM(X, 4, P, pool) /* pool */ \ PARAM(X, 5, W, totalSize) /* total size of pool gen */ \ - PARAM(X, 6, W, newSizeAtCreate) /* new size of pool gen at trace create */ + PARAM(X, 6, W, freeSize) /* free size of pool gen */ \ + PARAM(X, 7, W, oldSize) /* old size of pool gen */ \ + PARAM(X, 8, W, newSize) /* new size of pool gen */ \ + PARAM(X, 9, W, oldDeferredSize) /* old size (deferred) of pool gen */ \ + PARAM(X, 10, W, newDeferredSize) /* new size (deferred) of pool gen */ \ + PARAM(X, 11, W, newSizeAtCreate) /* new size of pool gen at trace create */ #define EVENT_TraceCondemnZones_PARAMS(PARAM, X) \ PARAM(X, 0, P, trace) /* the trace */ \ diff --git a/mps/code/trace.c b/mps/code/trace.c index 93dddda955d..74144774564 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1593,8 +1593,10 @@ static void TraceStartPoolGen(GenDesc gen) Ring n, nn; RING_FOR(n, &gen->locusRing, nn) { PoolGen pgen = RING_ELT(PoolGen, genRing, n); - EVENT7(TraceStartPoolGen, gen, gen->capacity, gen->mortality, gen->zones, - pgen->pool, pgen->totalSize, pgen->newSizeAtCreate); + EVENT12(TraceStartPoolGen, gen, gen->capacity, gen->mortality, gen->zones, + pgen->pool, pgen->totalSize, pgen->freeSize, pgen->oldSize, + pgen->newSize, pgen->oldDeferredSize, pgen->newDeferredSize, + pgen->newSizeAtCreate); } } From 4c655eba6afc0904ca0c253ec5d533f2d4e2b981 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 1 May 2014 12:18:00 +0100 Subject: [PATCH 144/266] Fix rash build on os x by adding the unused attribute to functions declared static that are not called in the rash variety. Copied from Perforce Change: 185915 ServerID: perforce.ravenbrook.com --- mps/code/arenacl.c | 2 ++ mps/code/arenavm.c | 2 ++ mps/code/buffer.c | 1 + mps/code/cbs.c | 1 + mps/code/config.h | 9 +++++++++ mps/code/freelist.c | 5 +++-- mps/code/locus.c | 1 + mps/code/mpsi.c | 1 + mps/code/poolamc.c | 5 +++++ mps/code/poolawl.c | 2 ++ mps/code/poollo.c | 3 +++ mps/code/poolmrg.c | 4 ++++ mps/code/poolmv.c | 2 ++ mps/code/poolmv2.c | 1 + mps/code/poolmvff.c | 1 + mps/code/poolsnc.c | 3 +++ mps/code/reserv.c | 1 + mps/code/sac.c | 1 + mps/code/segsmss.c | 2 ++ mps/code/walk.c | 2 ++ 20 files changed, 47 insertions(+), 2 deletions(-) diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c index 3d07f529779..1a0fcf3c6e3 100644 --- a/mps/code/arenacl.c +++ b/mps/code/arenacl.c @@ -61,6 +61,7 @@ typedef struct ClientChunkStruct { /* ClientChunkCheck -- check the consistency of a client chunk */ +ATTRIBUTE_UNUSED static Bool ClientChunkCheck(ClientChunk clChunk) { Chunk chunk; @@ -77,6 +78,7 @@ static Bool ClientChunkCheck(ClientChunk clChunk) /* ClientArenaCheck -- check the consistency of a client arena */ +ATTRIBUTE_UNUSED static Bool ClientArenaCheck(ClientArena clientArena) { CHECKS(ClientArena, clientArena); diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 81e0684c436..f878092bd01 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -93,6 +93,7 @@ static void VMCompact(Arena arena, Trace trace); /* VMChunkCheck -- check the consistency of a VM chunk */ +ATTRIBUTE_UNUSED static Bool VMChunkCheck(VMChunk vmchunk) { Chunk chunk; @@ -152,6 +153,7 @@ static Bool VMChunkCheck(VMChunk vmchunk) /* VMArenaCheck -- check the consistency of an arena structure */ +ATTRIBUTE_UNUSED static Bool VMArenaCheck(VMArena vmArena) { Arena arena; diff --git a/mps/code/buffer.c b/mps/code/buffer.c index bbae1f3eacd..a6cb2bee187 100644 --- a/mps/code/buffer.c +++ b/mps/code/buffer.c @@ -994,6 +994,7 @@ AllocPattern AllocPatternRampCollectAll(void) return &AllocPatternRampCollectAllStruct; } +ATTRIBUTE_UNUSED static Bool AllocPatternCheck(AllocPattern pattern) { CHECKL(pattern == &AllocPatternRampCollectAllStruct diff --git a/mps/code/cbs.c b/mps/code/cbs.c index 118d226a603..addebd398ad 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -80,6 +80,7 @@ Bool CBSCheck(CBS cbs) } +ATTRIBUTE_UNUSED static Bool CBSBlockCheck(CBSBlock block) { /* See .enter-leave.simple. */ diff --git a/mps/code/config.h b/mps/code/config.h index 0afa66c06bb..c07f646a0af 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -241,6 +241,15 @@ #define ATTRIBUTE_NORETURN #endif +/* Attribute for functions that may be unused in some build configurations. + * GCC: + */ +#if defined(MPS_BUILD_GC) || defined(MPS_BUILD_LL) +#define ATTRIBUTE_UNUSED __attribute__((__unused__)) +#else +#define ATTRIBUTE_UNUSED +#endif + /* EPVMDefaultSubsequentSegSIZE is a default for the alignment of * subsequent segments (non-initial at each save level) in EPVM. See diff --git a/mps/code/freelist.c b/mps/code/freelist.c index 6260451ff59..1abc3f73cc8 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 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2013-2014 Ravenbrook Limited. See end of file for license. * * .sources: . */ @@ -60,6 +60,7 @@ static Addr FreelistBlockLimit(Freelist fl, FreelistBlock block) /* FreelistBlockCheck -- check a block. */ +ATTRIBUTE_UNUSED static Bool FreelistBlockCheck(FreelistBlock block) { CHECKL(block != NULL); @@ -626,7 +627,7 @@ void FreelistFlushToCBS(Freelist fl, CBS cbs) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2013 Ravenbrook Limited . + * Copyright (C) 2013-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/locus.c b/mps/code/locus.c index 6e6e22128b7..10eae03840f 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -80,6 +80,7 @@ void SegPrefExpress(SegPref pref, SegPrefKind kind, void *p) /* GenDescCheck -- check a GenDesc */ +ATTRIBUTE_UNUSED static Bool GenDescCheck(GenDesc gen) { CHECKS(GenDesc, gen); diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 45ffff50166..f4e3f9e6f02 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -65,6 +65,7 @@ SRCID(mpsi, "$Id$"); * .check.enum.cast: enum comparisons have to be cast to avoid a warning * from the SunPro C compiler. See builder.sc.warn.enum. */ +ATTRIBUTE_UNUSED static Bool mpsi_check(void) { CHECKL(COMPATTYPE(mps_res_t, Res)); diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index aeb04454efe..6ae51fc4fe6 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -96,6 +96,7 @@ typedef struct amcSegStruct { #define amcSeg2Seg(amcseg) ((Seg)(amcseg)) +ATTRIBUTE_UNUSED static Bool amcSegCheck(amcSeg amcseg) { CHECKS(amcSeg, amcseg); @@ -475,6 +476,7 @@ typedef struct AMCStruct { /* */ /* amcGenCheck -- check consistency of a generation structure */ +ATTRIBUTE_UNUSED static Bool amcGenCheck(amcGen gen) { Arena arena; @@ -524,6 +526,7 @@ typedef struct amcBufStruct { /* amcBufCheck -- check consistency of an amcBuf */ +ATTRIBUTE_UNUSED static Bool amcBufCheck(amcBuf amcbuf) { CHECKS(amcBuf, amcbuf); @@ -2445,6 +2448,8 @@ void mps_amc_apply(mps_pool_t mps_pool, * * See . */ + +ATTRIBUTE_UNUSED static Bool AMCCheck(AMC amc) { CHECKS(AMC, amc); diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index cbece0b41fe..21edaaec1cb 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -131,6 +131,7 @@ typedef struct AWLSegStruct { extern SegClass AWLSegClassGet(void); +ATTRIBUTE_UNUSED static Bool AWLSegCheck(AWLSeg awlseg) { CHECKS(AWLSeg, awlseg); @@ -1299,6 +1300,7 @@ mps_class_t mps_class_awl(void) /* AWLCheck -- check an AWL pool */ +ATTRIBUTE_UNUSED static Bool AWLCheck(AWL awl) { CHECKS(AWL, awl); diff --git a/mps/code/poollo.c b/mps/code/poollo.c index d8f23584fba..3420e22b9ab 100644 --- a/mps/code/poollo.c +++ b/mps/code/poollo.c @@ -79,6 +79,7 @@ DEFINE_SEG_CLASS(LOSegClass, class) /* LOSegCheck -- check an LO segment */ +ATTRIBUTE_UNUSED static Bool LOSegCheck(LOSeg loseg) { CHECKS(LOSeg, loseg); @@ -184,6 +185,7 @@ static void loSegFinish(Seg seg) } +ATTRIBUTE_UNUSED static Count loSegBits(LOSeg loseg) { LO lo; @@ -805,6 +807,7 @@ mps_class_t mps_class_lo(void) /* LOCheck -- check an LO pool */ +ATTRIBUTE_UNUSED static Bool LOCheck(LO lo) { CHECKS(LO, lo); diff --git a/mps/code/poolmrg.c b/mps/code/poolmrg.c index 93d9f8bd25e..ace97865f1b 100644 --- a/mps/code/poolmrg.c +++ b/mps/code/poolmrg.c @@ -125,6 +125,7 @@ typedef struct MRGStruct { /* MRGCheck -- check an MRG pool */ +ATTRIBUTE_UNUSED static Bool MRGCheck(MRG mrg) { CHECKS(MRG, mrg); @@ -178,6 +179,8 @@ extern SegClass MRGRefSegClassGet(void); * field will be NULL. This will be initialized when the reference * segment is initialized. See . */ + +ATTRIBUTE_UNUSED static Bool MRGLinkSegCheck(MRGLinkSeg linkseg) { Seg seg; @@ -193,6 +196,7 @@ static Bool MRGLinkSegCheck(MRGLinkSeg linkseg) return TRUE; } +ATTRIBUTE_UNUSED static Bool MRGRefSegCheck(MRGRefSeg refseg) { Seg seg; diff --git a/mps/code/poolmv.c b/mps/code/poolmv.c index 0ce4f28c95d..ccce962e42a 100644 --- a/mps/code/poolmv.c +++ b/mps/code/poolmv.c @@ -72,6 +72,7 @@ typedef struct MVBlockStruct { /* MVBlockCheck -- check the consistency of a block structure */ +ATTRIBUTE_UNUSED static Bool MVBlockCheck(MVBlock block) { AVER(block != NULL); @@ -130,6 +131,7 @@ typedef struct MVSpanStruct { /* MVSpanCheck -- check the consistency of a span structure */ +ATTRIBUTE_UNUSED static Bool MVSpanCheck(MVSpan span) { Addr addr, base, limit; diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index f6d85b1b134..b4ac6913fdf 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -356,6 +356,7 @@ static Res MVTInit(Pool pool, ArgList args) /* MVTCheck -- validate an MVT Pool */ +ATTRIBUTE_UNUSED static Bool MVTCheck(MVT mvt) { CHECKS(MVT, mvt); diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 4971550c76a..3d569058697 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -791,6 +791,7 @@ size_t mps_mvff_size(mps_pool_t mps_pool) /* MVFFCheck -- check the consistency of an MVFF structure */ +ATTRIBUTE_UNUSED static Bool MVFFCheck(MVFF mvff) { CHECKS(MVFF, mvff); diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c index e9afe98a96b..139865fc5ec 100644 --- a/mps/code/poolsnc.c +++ b/mps/code/poolsnc.c @@ -84,6 +84,7 @@ typedef struct SNCBufStruct { /* SNCBufCheck -- check consistency of an SNCBuf */ +ATTRIBUTE_UNUSED static Bool SNCBufCheck(SNCBuf sncbuf) { SegBuf segbuf; @@ -214,6 +215,7 @@ typedef struct SNCSegStruct { #define sncSegSetNext(seg, nextseg) \ ((void)(SegSNCSeg(seg)->next = SegSNCSeg(nextseg))) +ATTRIBUTE_UNUSED static Bool SNCSegCheck(SNCSeg sncseg) { CHECKS(SNCSeg, sncseg); @@ -696,6 +698,7 @@ mps_class_t mps_class_snc(void) /* SNCCheck -- Check an SNC pool */ +ATTRIBUTE_UNUSED static Bool SNCCheck(SNC snc) { CHECKS(SNC, snc); diff --git a/mps/code/reserv.c b/mps/code/reserv.c index 02b18d66d88..c7dd0507482 100644 --- a/mps/code/reserv.c +++ b/mps/code/reserv.c @@ -107,6 +107,7 @@ Bool ReservoirCheck(Reservoir reservoir) /* reservoirIsConsistent -- returns FALSE if the reservoir is corrupt */ +ATTRIBUTE_UNUSED static Bool reservoirIsConsistent(Reservoir reservoir) { Size alignment, size = 0; diff --git a/mps/code/sac.c b/mps/code/sac.c index 3caf9ab893f..c85956c8f82 100644 --- a/mps/code/sac.c +++ b/mps/code/sac.c @@ -32,6 +32,7 @@ static Bool sacFreeListBlockCheck(SACFreeListBlock fb) return TRUE; } +ATTRIBUTE_UNUSED static Bool SACCheck(SAC sac) { Index i, j; diff --git a/mps/code/segsmss.c b/mps/code/segsmss.c index 978c352e0dd..7efac5c64a5 100644 --- a/mps/code/segsmss.c +++ b/mps/code/segsmss.c @@ -59,6 +59,7 @@ typedef struct AMSTStruct *AMST; /* AMSTCheck -- the check method for an AMST */ +ATTRIBUTE_UNUSED static Bool AMSTCheck(AMST amst) { CHECKS(AMST, amst); @@ -96,6 +97,7 @@ typedef struct AMSTSegStruct { /* AMSTSegCheck -- check the AMST segment */ +ATTRIBUTE_UNUSED static Bool AMSTSegCheck(AMSTSeg amstseg) { CHECKS(AMSTSeg, amstseg); diff --git a/mps/code/walk.c b/mps/code/walk.c index 4dd0d6b9e98..544c9644498 100644 --- a/mps/code/walk.c +++ b/mps/code/walk.c @@ -26,6 +26,7 @@ typedef struct FormattedObjectsStepClosureStruct { } FormattedObjectsStepClosureStruct; +ATTRIBUTE_UNUSED static Bool FormattedObjectsStepClosureCheck(FormattedObjectsStepClosure c) { CHECKS(FormattedObjectsStepClosure, c); @@ -164,6 +165,7 @@ typedef struct rootsStepClosureStruct { /* rootsStepClosureCheck -- check a rootsStepClosure */ +ATTRIBUTE_UNUSED static Bool rootsStepClosureCheck(rootsStepClosure rsc) { CHECKS(rootsStepClosure, rsc); From 4ac304fd3824fa90a36b81b27a7f9a679abe4fc2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 1 May 2014 12:21:17 +0100 Subject: [PATCH 145/266] Fix problems with the xcode project file (introduced in bad merges): * airtest got built as mv2test in the RASH config * airtest and nailboardtest got build with profiling in Debug config * airtest still had bogus WE config Copied from Perforce Change: 185916 ServerID: perforce.ravenbrook.com --- mps/code/mps.xcodeproj/project.pbxproj | 76 +++++++++----------------- 1 file changed, 25 insertions(+), 51 deletions(-) diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index 88f110bab01..29e47139571 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -2644,7 +2644,7 @@ 22FACEE118880983000FDBC1 /* PBXTargetDependency */, ); name = airtest; - productName = mv2test; + productName = airtest; productReference = 22FACEED18880983000FDBC1 /* airtest */; productType = "com.apple.product-type.tool"; }; @@ -4322,42 +4322,42 @@ 2231BB5618CA97D8002D6322 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = locbwcss; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 2231BB5718CA97D8002D6322 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = locbwcss; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 2231BB5818CA97D8002D6322 /* RASH */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = locbwcss; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = RASH; }; 2231BB6418CA97DC002D6322 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = locusss; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 2231BB6518CA97DC002D6322 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = locusss; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 2231BB6618CA97DC002D6322 /* RASH */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = locusss; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = RASH; }; @@ -4421,7 +4421,7 @@ isa = XCBuildConfiguration; buildSettings = { GCC_TREAT_WARNINGS_AS_ERRORS = NO; - PRODUCT_NAME = "scheme-advanced"; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; @@ -4429,7 +4429,7 @@ isa = XCBuildConfiguration; buildSettings = { GCC_TREAT_WARNINGS_AS_ERRORS = NO; - PRODUCT_NAME = "scheme-advanced"; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; @@ -4437,41 +4437,35 @@ isa = XCBuildConfiguration; buildSettings = { GCC_TREAT_WARNINGS_AS_ERRORS = NO; - PRODUCT_NAME = "scheme-advanced"; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = RASH; }; 22C2ACA118BE3FEC006B3677 /* RASH */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = mv2test; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = RASH; }; 22C2ACAC18BE400A006B3677 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_GENERATE_TEST_COVERAGE_FILES = YES; - GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = YES; - PRODUCT_NAME = nailboardtest; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 22C2ACAD18BE400A006B3677 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_GENERATE_TEST_COVERAGE_FILES = NO; - GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO; - PRODUCT_NAME = nailboardtest; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 22C2ACAE18BE400A006B3677 /* RASH */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_GENERATE_TEST_COVERAGE_FILES = NO; - GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO; - PRODUCT_NAME = nailboardtest; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = RASH; }; @@ -4492,21 +4486,21 @@ 22F846BA18F437B900982BA7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = lockut; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 22F846BB18F437B900982BA7 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = lockut; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 22F846BC18F437B900982BA7 /* RASH */ = { isa = XCBuildConfiguration; buildSettings = { - PRODUCT_NAME = lockut; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = RASH; }; @@ -4527,30 +4521,17 @@ 22FACEEA18880983000FDBC1 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_GENERATE_TEST_COVERAGE_FILES = YES; - GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = YES; - PRODUCT_NAME = airtest; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 22FACEEB18880983000FDBC1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_GENERATE_TEST_COVERAGE_FILES = NO; - GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO; - PRODUCT_NAME = airtest; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; - 22FACEEC18880983000FDBC1 /* WE */ = { - isa = XCBuildConfiguration; - buildSettings = { - GCC_GENERATE_TEST_COVERAGE_FILES = NO; - GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO; - PRODUCT_NAME = airtest; - }; - name = WE; - }; 2D07B9751636FC9900DB751B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4626,7 +4607,6 @@ 3104AFF3156D37A0000A585A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - COMBINE_HIDPI_IMAGES = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -4634,7 +4614,6 @@ 3104AFF4156D37A0000A585A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - COMBINE_HIDPI_IMAGES = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -4923,7 +4902,7 @@ isa = XCBuildConfiguration; buildSettings = { GCC_TREAT_WARNINGS_AS_ERRORS = NO; - PRODUCT_NAME = djbench; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; @@ -4931,7 +4910,7 @@ isa = XCBuildConfiguration; buildSettings = { GCC_TREAT_WARNINGS_AS_ERRORS = NO; - PRODUCT_NAME = djbench; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; @@ -4991,7 +4970,6 @@ 318DA8D51892C0D00089718C /* RASH */ = { isa = XCBuildConfiguration; buildSettings = { - COMBINE_HIDPI_IMAGES = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = RASH; @@ -5000,7 +4978,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - COMBINE_HIDPI_IMAGES = YES; EXECUTABLE_PREFIX = lib; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -5285,7 +5262,7 @@ isa = XCBuildConfiguration; buildSettings = { GCC_TREAT_WARNINGS_AS_ERRORS = NO; - PRODUCT_NAME = djbench; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = RASH; }; @@ -5484,7 +5461,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - COMBINE_HIDPI_IMAGES = YES; EXECUTABLE_PREFIX = lib; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -5494,7 +5470,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - COMBINE_HIDPI_IMAGES = YES; EXECUTABLE_PREFIX = lib; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -5534,7 +5509,7 @@ isa = XCBuildConfiguration; buildSettings = { GCC_TREAT_WARNINGS_AS_ERRORS = NO; - PRODUCT_NAME = gcbench; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; @@ -5542,7 +5517,7 @@ isa = XCBuildConfiguration; buildSettings = { GCC_TREAT_WARNINGS_AS_ERRORS = NO; - PRODUCT_NAME = gcbench; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; @@ -5550,7 +5525,7 @@ isa = XCBuildConfiguration; buildSettings = { GCC_TREAT_WARNINGS_AS_ERRORS = NO; - PRODUCT_NAME = gcbench; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = RASH; }; @@ -5672,7 +5647,6 @@ buildConfigurations = ( 22FACEEA18880983000FDBC1 /* Debug */, 22FACEEB18880983000FDBC1 /* Release */, - 22FACEEC18880983000FDBC1 /* WE */, 22C2ACA118BE3FEC006B3677 /* RASH */, ); defaultConfigurationIsVisible = 0; From 610da3aaa4c327d425cc2a854ffa1eda7187209b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 1 May 2014 15:51:26 +0100 Subject: [PATCH 146/266] Reorganize the mps branch index so that it contains a roughly prioritized list of branches that are ready for review. Copied from Perforce Change: 185920 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 5a3b4d8652d..bb54f0d4527 100755 --- a/mps/tool/branch +++ b/mps/tool/branch @@ -49,7 +49,7 @@ TASK_BRANCH_ENTRY = ''' {date}/{task} Changes {desc_html} - Active (diffs). + Diffs ''' From 6ffd06065715e86b0da0a61a2e83af3746e6fcab Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 1 May 2014 17:38:14 +0100 Subject: [PATCH 147/266] Add refsetsub assertion to the list of common assertions and their causes. Copied from Perforce Change: 185924 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/error.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 6b2e9452fc2..fb55c9785f1 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -293,6 +293,16 @@ this documentation. condition? +``trace.c: RefSetSub(ScanStateUnfixedSummary(ss), SegSummary(seg))`` + + The client program's :term:`scan method` failed to update a + 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." + + .. index:: single: error handling; varieties single: variety From d377539ae7f9fb63890c3ec8349e3186eba1ccae Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 1 May 2014 18:02:53 +0100 Subject: [PATCH 148/266] Default value for mps_key_ams_support_ambiguous is now the safer value true. Copied from Perforce Change: 185927 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 2 +- mps/manual/source/pool/ams.rst | 12 ++++++------ mps/manual/source/release.rst | 5 +++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index c07f646a0af..1dfd7858f86 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -290,7 +290,7 @@ /* Pool AMS Configuration -- see */ -#define AMS_SUPPORT_AMBIGUOUS_DEFAULT FALSE +#define AMS_SUPPORT_AMBIGUOUS_DEFAULT TRUE #define AMS_GEN_DEFAULT 0 diff --git a/mps/manual/source/pool/ams.rst b/mps/manual/source/pool/ams.rst index cb7966661a3..ae1d43f8bed 100644 --- a/mps/manual/source/pool/ams.rst +++ b/mps/manual/source/pool/ams.rst @@ -55,10 +55,11 @@ AMS properties never promoted out of the generation in which they are allocated. * Blocks may contain :term:`exact references` to blocks in the same or - other pools, or :term:`ambiguous references` (if the + other pools, or :term:`ambiguous references` (unless the :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` keyword argument is set to - true when creating the pool). Blocks may not contain :term:`weak - references (1)`, and may not use :term:`remote references`. + ``FALSE`` when creating the pool). Blocks may not contain + :term:`weak references (1)`, and may not use :term:`remote + references`. * Allocations may be variable in size. @@ -126,14 +127,13 @@ AMS interface blocks remain in this generation and are not promoted. * :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` (type - :c:type:`mps_bool_t`, default false) specifies whether references - may be ambiguous. + :c:type:`mps_bool_t`, default ``TRUE``) specifies whether + references to blocks in the pool may be ambiguous. For example:: MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, 1); res = mps_pool_create_k(&pool, arena, mps_class_ams(), args); } MPS_ARGS_END(args); diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 18cc8ed72e9..f9fc0054de5 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -35,6 +35,11 @@ Interface changes :c:func:`mps_arena_create_k` when creating a virtual memory arena. See :c:func:`mps_arena_class_vm`. +#. The keyword argument :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` now + defaults to ``TRUE`` in order to better support the general case: + the value ``FALSE`` is appropriate only when you know that all + references are exact. See :ref:`pool-ams`. + Other changes ............. From 04591f2a4996ab61f8fd050aa24695425daa258e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 1 May 2014 18:46:15 +0100 Subject: [PATCH 149/266] Update manual to describe new condemn logic resulting from fix for job003771. Copied from Perforce Change: 185929 ServerID: perforce.ravenbrook.com --- mps/manual/source/release.rst | 21 +++++++++++++++++++++ mps/manual/source/topic/collection.rst | 25 ++++++++++++------------- mps/manual/source/topic/pattern.rst | 16 ++++++++++++++-- 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index f9fc0054de5..0ac53f9020a 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -26,6 +26,20 @@ New features :c:macro:`MPS_KEY_INTERIOR` keyword argument to ``FALSE`` when calling :c:func:`mps_pool_create_k`. +#. The logic for deciding which generations should be collected has + changed. Now, a chain may be scheduled for collection if the new + size of *any* of its generations exceeds its capacity, and when a + chain is collected, all generations are collected up to, and + including, the highest generation whose new size exceeds its + capacity. This ensures that all generations are collected reliably + on chains where there is no allocation into the nursery generation. + See :ref:`topic-collection-schedule`. + + (Previously, only the nursery generation in each chain + was considered, and a chain was collected up to, but not including, + the lowest generation whose new size was within its capacity.) + + Interface changes ................. @@ -69,6 +83,13 @@ Other changes .. _job003756: https://www.ravenbrook.com/project/mps/issue/job003756/ +#. :ref:`pool-ams` pools get reliably collected, even in the case + where an AMS pool is the only pool on its generation chain and is + allocating into some generation other than the nursery. See + job003771_. + + .. _job003771: https://www.ravenbrook.com/project/mps/issue/job003771/ + .. _release-notes-1.113: diff --git a/mps/manual/source/topic/collection.rst b/mps/manual/source/topic/collection.rst index de5629e52d6..adf7c058e9e 100644 --- a/mps/manual/source/topic/collection.rst +++ b/mps/manual/source/topic/collection.rst @@ -57,9 +57,9 @@ Create a generation chain by preparing an array of kilobytes) and *predicted mortality* (between 0 and 1) of each generation, and passing them to :c:func:`mps_chain_create`. -When the size of the generation exceeds the capacity, the MPS will be -prepared to start collecting the generation. See -:ref:`topic-collection-schedule` below. +When the *new size* of a generation exceeds its capacity, the MPS will +be prepared to start collecting the chain to which the generation +belongs. See :ref:`topic-collection-schedule` below. For example:: @@ -163,20 +163,19 @@ size* of each generation (other than the topmost) is the same as its total size, but in pools like :ref:`pool-ams` where survivors do not get promoted, the two sizes can be different. -The first generation in a pool's chain is the :term:`nursery space`. -When the nursery's *new size* exceeds its capacity, the MPS considers -collecting the pool. (How long it takes to get around to it depends on -which other collections on other pools are in progress.) +When a generation's *new size* exceeds its capacity, the MPS considers +collecting the chain to which the generation belongs. (How long it +takes to get around to it depends on which other collections are in +progress.) .. note:: - You can affect the decision as to when to collect the nursery - space by using the :ref:`ramp allocation pattern - `. + You can affect the decision as to when to collect the chain by + using the :ref:`ramp allocation pattern `. -If the MPS decides to collect a pool at all, all generations are -collected below the first generation whose *new size* is less than its -capacity. +If the MPS decides to collect a chain, all generations are collected +up to, and including, the highest generation whose *new size* exceeds +its capacity. In pools such as :ref:`pool-amc`, blocks in generation *g* that survive collection get promoted to generation *g*\+1. If the last diff --git a/mps/manual/source/topic/pattern.rst b/mps/manual/source/topic/pattern.rst index 4d798c00b78..f460e019fba 100644 --- a/mps/manual/source/topic/pattern.rst +++ b/mps/manual/source/topic/pattern.rst @@ -110,10 +110,22 @@ cutoff and decline in the live size. This pattern is useful if you are building a structure that involves temporarily allocating much more memory than will fit into your -:term:`nursery generation`. The ramp allocation pattern causes the -collection of the nursery generation to be deferred until the ramp +:term:`nursery generation`. By applying the ramp allocation pattern, +the collection of that generation can be deferred until the ramp allocation is over. +In detail: if the ramp allocation pattern is applied to an +:term:`allocation point`, then allocation on that AP is ignored by the +MPS when it is deciding whether to schedule a collection of the chain +containing the generation into which the AP is allocating. See :ref:`topic-collection-schedule`. + +.. note:: + + This does not prevent the generation from being collected + altogether: there may be other APs allocating into the generation, + or the MPS may have to collect the generation in order to avoid + running out of memory. + .. note:: Ramp allocation is only supported by :ref:`pool-amc`. From 641a75cf5e75556b4b7050712bef303a14f5e42b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 1 May 2014 19:00:08 +0100 Subject: [PATCH 150/266] Avoid the need for newsizeatcreate by emitting events for the pool generations in tracecreate instead of tracestart. Get rid of proflow member of GenDescStruct (it was unused). Use STATISTIC to avoid updating segs, freeSize, oldSize, and oldDeferredSize in non-checking varieties. Add design for pool generation accounting. Copied from Perforce Change: 185930 ServerID: perforce.ravenbrook.com --- mps/code/chain.h | 24 +++---- mps/code/eventdef.h | 13 ++-- mps/code/locus.c | 117 ++++++++++++++++++-------------- mps/code/trace.c | 96 +++++++++----------------- mps/design/strategy.txt | 147 +++++++++++++++++++++++++++++----------- 5 files changed, 222 insertions(+), 175 deletions(-) diff --git a/mps/code/chain.h b/mps/code/chain.h index 9666eac943e..706838610ec 100644 --- a/mps/code/chain.h +++ b/mps/code/chain.h @@ -31,7 +31,6 @@ typedef struct GenDescStruct { ZoneSet zones; /* zoneset for this generation */ Size capacity; /* capacity in kB */ double mortality; - double proflow; /* predicted proportion of survivors promoted */ RingStruct locusRing; /* Ring of all PoolGen's in this GenDesc (locus) */ } GenDescStruct; @@ -49,21 +48,14 @@ typedef struct PoolGenStruct { /* link in ring of all PoolGen's in this GenDesc (locus) */ RingStruct genRing; - /* Accounting of memory in this generation for this pool */ - Size segs; /* number of segments */ - Size totalSize; /* total (sum of segment sizes) */ - Size freeSize; /* unused (free or lost to fragmentation) */ - Size oldSize; /* allocated prior to last collection */ - Size newSize; /* allocated since last collection */ - Size oldDeferredSize; /* allocated prior to last collection (deferred) */ - Size newDeferredSize; /* allocated since last collection (deferred) */ - - /* newSize when TraceCreate was called. This is used in the - * TraceStartPoolGen event emitted at the start of a trace; at that - * time, newSize has already been diminished by Whiten so we can't - * use that value. TODO: This will not work well with multiple - * traces. */ - Size newSizeAtCreate; + /* Accounting of memory in this generation for this pool */ + STATISTIC_DECL(Size segs); /* number of segments */ + Size totalSize; /* total (sum of segment sizes) */ + STATISTIC_DECL(Size freeSize); /* unused (free or lost to fragmentation) */ + Size newSize; /* allocated since last collection */ + STATISTIC_DECL(Size oldSize); /* allocated prior to last collection */ + Size newDeferredSize; /* new (but deferred) */ + STATISTIC_DECL(Size oldDeferredSize); /* old (but deferred) */ } PoolGenStruct; diff --git a/mps/code/eventdef.h b/mps/code/eventdef.h index 4999be4ee69..d47e434b868 100644 --- a/mps/code/eventdef.h +++ b/mps/code/eventdef.h @@ -187,7 +187,7 @@ EVENT(X, VMCompact , 0x0079, TRUE, Arena) \ EVENT(X, amcScanNailed , 0x0080, TRUE, Seg) \ EVENT(X, AMCTraceEnd , 0x0081, TRUE, Trace) \ - EVENT(X, TraceStartPoolGen , 0x0082, TRUE, Trace) \ + EVENT(X, TraceCreatePoolGen , 0x0082, TRUE, Trace) \ /* new events for performance analysis of large heaps. */ \ EVENT(X, TraceCondemnZones , 0x0083, TRUE, Trace) \ EVENT(X, ArenaGenZoneAdd , 0x0084, TRUE, Arena) \ @@ -713,7 +713,7 @@ PARAM(X, 19, W, pRL) \ PARAM(X, 20, W, pRLr) -#define EVENT_TraceStartPoolGen_PARAMS(PARAM, X) \ +#define EVENT_TraceCreatePoolGen_PARAMS(PARAM, X) \ PARAM(X, 0, P, gendesc) /* generation description */ \ PARAM(X, 1, W, capacity) /* capacity of generation */ \ PARAM(X, 2, D, mortality) /* mortality of generation */ \ @@ -721,11 +721,10 @@ PARAM(X, 4, P, pool) /* pool */ \ PARAM(X, 5, W, totalSize) /* total size of pool gen */ \ PARAM(X, 6, W, freeSize) /* free size of pool gen */ \ - PARAM(X, 7, W, oldSize) /* old size of pool gen */ \ - PARAM(X, 8, W, newSize) /* new size of pool gen */ \ - PARAM(X, 9, W, oldDeferredSize) /* old size (deferred) of pool gen */ \ - PARAM(X, 10, W, newDeferredSize) /* new size (deferred) of pool gen */ \ - PARAM(X, 11, W, newSizeAtCreate) /* new size of pool gen at trace create */ + PARAM(X, 7, W, newSize) /* new size of pool gen */ \ + PARAM(X, 8, W, oldSize) /* old size of pool gen */ \ + PARAM(X, 9, W, newDeferredSize) /* new size (deferred) of pool gen */ \ + PARAM(X, 10, W, oldDeferredSize) /* old size (deferred) of pool gen */ #define EVENT_TraceCondemnZones_PARAMS(PARAM, X) \ PARAM(X, 0, P, trace) /* the trace */ \ diff --git a/mps/code/locus.c b/mps/code/locus.c index ec7ae24f1ea..eca1256fffd 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -6,7 +6,8 @@ * DESIGN * * See and for basic locus stuff. - * See for chains. + * See for chains. See for the + * collection strategy. */ #include "chain.h" @@ -87,8 +88,6 @@ static Bool GenDescCheck(GenDesc gen) /* nothing to check for capacity */ CHECKL(gen->mortality >= 0.0); CHECKL(gen->mortality <= 1.0); - CHECKL(gen->proflow >= 0.0); - CHECKL(gen->proflow <= 1.0); CHECKD_NOSIG(Ring, &gen->locusRing); return TRUE; } @@ -156,9 +155,9 @@ Res ChainCreate(Chain *chainReturn, Arena arena, size_t genCount, gens[i].zones = ZoneSetEMPTY; gens[i].capacity = params[i].capacity; gens[i].mortality = params[i].mortality; - gens[i].proflow = 1.0; /* @@@@ temporary */ RingInit(&gens[i].locusRing); gens[i].sig = GenDescSig; + AVERT(GenDesc, &gens[i]); } res = ControlAlloc(&p, arena, sizeof(ChainStruct), FALSE); @@ -291,10 +290,12 @@ Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size, EVENT3(ArenaGenZoneAdd, arena, gen, moreZones); } - ++ pgen->segs; size = SegSize(seg); pgen->totalSize += size; - pgen->freeSize += size; + STATISTIC_STAT ({ + ++ pgen->segs; + pgen->freeSize += size; + }); *segReturn = seg; return ResOK; } @@ -420,13 +421,13 @@ Res PoolGenInit(PoolGen pgen, GenDesc gen, Pool pool) pgen->pool = pool; pgen->gen = gen; RingInit(&pgen->genRing); - pgen->segs = 0; + STATISTIC(pgen->segs = 0); pgen->totalSize = 0; - pgen->freeSize = 0; + STATISTIC(pgen->freeSize = 0); pgen->newSize = 0; - pgen->oldSize = 0; + STATISTIC(pgen->oldSize = 0); pgen->newDeferredSize = 0; - pgen->oldDeferredSize = 0; + STATISTIC(pgen->oldDeferredSize = 0); pgen->sig = PoolGenSig; AVERT(PoolGen, pgen); @@ -440,8 +441,15 @@ Res PoolGenInit(PoolGen pgen, GenDesc gen, Pool pool) void PoolGenFinish(PoolGen pgen) { AVERT(PoolGen, pgen); - AVER(pgen->segs == 0); AVER(pgen->totalSize == 0); + AVER(pgen->newSize == 0); + AVER(pgen->newDeferredSize == 0); + STATISTIC_STAT ({ + AVER(pgen->segs == 0); + AVER(pgen->freeSize == 0); + AVER(pgen->oldSize == 0); + AVER(pgen->oldDeferredSize == 0); + }); pgen->sig = SigInvalid; RingRemove(&pgen->genRing); @@ -457,10 +465,12 @@ Bool PoolGenCheck(PoolGen pgen) CHECKU(Pool, pgen->pool); CHECKU(GenDesc, pgen->gen); CHECKD_NOSIG(Ring, &pgen->genRing); - CHECKL((pgen->totalSize == 0) == (pgen->segs == 0)); - CHECKL(pgen->totalSize >= pgen->segs * ArenaAlign(PoolArena(pgen->pool))); - CHECKL(pgen->totalSize == pgen->freeSize + pgen->oldSize + pgen->newSize - + pgen->oldDeferredSize + pgen->newDeferredSize); + STATISTIC_STAT ({ + CHECKL((pgen->totalSize == 0) == (pgen->segs == 0)); + CHECKL(pgen->totalSize >= pgen->segs * ArenaAlign(PoolArena(pgen->pool))); + CHECKL(pgen->totalSize == pgen->freeSize + pgen->newSize + pgen->oldSize + + pgen->newDeferredSize + pgen->oldDeferredSize); + }); return TRUE; } @@ -470,14 +480,16 @@ Bool PoolGenCheck(PoolGen pgen) * The memory was free, is now new (or newDeferred). */ -void PoolGenFill(PoolGen pgen, Size size, Bool ramping) +void PoolGenFill(PoolGen pgen, Size size, Bool deferred) { AVERT(PoolGen, pgen); - AVERT(Bool, ramping); + AVERT(Bool, deferred); - AVER(pgen->freeSize >= size); - pgen->freeSize -= size; - if (ramping) + STATISTIC_STAT ({ + AVER(pgen->freeSize >= size); + pgen->freeSize -= size; + }); + if (deferred) pgen->newDeferredSize += size; else pgen->newSize += size; @@ -489,19 +501,19 @@ void PoolGenFill(PoolGen pgen, Size size, Bool ramping) * The unused part of the buffer was new (or newDeferred) and is now free. */ -void PoolGenEmpty(PoolGen pgen, Size unused, Bool ramping) +void PoolGenEmpty(PoolGen pgen, Size unused, Bool deferred) { AVERT(PoolGen, pgen); - AVERT(Bool, ramping); + AVERT(Bool, deferred); - if (ramping) { + if (deferred) { AVER(pgen->newDeferredSize >= unused); pgen->newDeferredSize -= unused; } else { AVER(pgen->newSize >= unused); pgen->newSize -= unused; } - pgen->freeSize += unused; + STATISTIC(pgen->freeSize += unused); } @@ -510,18 +522,18 @@ void PoolGenEmpty(PoolGen pgen, Size unused, Bool ramping) * The memory was new (or newDeferred), is now old (or oldDeferred) */ -void PoolGenAge(PoolGen pgen, Size size, Bool ramping) +void PoolGenAge(PoolGen pgen, Size size, Bool deferred) { AVERT(PoolGen, pgen); - if (ramping) { + if (deferred) { AVER(pgen->newDeferredSize >= size); pgen->newDeferredSize -= size; - pgen->oldDeferredSize += size; + STATISTIC(pgen->oldDeferredSize += size); } else { AVER(pgen->newSize >= size); pgen->newSize -= size; - pgen->oldSize += size; + STATISTIC(pgen->oldSize += size); } } @@ -531,19 +543,21 @@ void PoolGenAge(PoolGen pgen, Size size, Bool ramping) * The reclaimed memory was old, and is now free. */ -void PoolGenReclaim(PoolGen pgen, Size reclaimed, Bool ramping) +void PoolGenReclaim(PoolGen pgen, Size reclaimed, Bool deferred) { AVERT(PoolGen, pgen); - AVERT(Bool, ramping); + AVERT(Bool, deferred); - if (ramping) { - AVER(pgen->oldDeferredSize >= reclaimed); - pgen->oldDeferredSize -= reclaimed; - } else { - AVER(pgen->oldSize >= reclaimed); - pgen->oldSize -= reclaimed; - } - pgen->freeSize += reclaimed; + STATISTIC_STAT ({ + if (deferred) { + AVER(pgen->oldDeferredSize >= reclaimed); + pgen->oldDeferredSize -= reclaimed; + } else { + AVER(pgen->oldSize >= reclaimed); + pgen->oldSize -= reclaimed; + } + pgen->freeSize += reclaimed; + }); } @@ -555,9 +569,11 @@ void PoolGenReclaim(PoolGen pgen, Size reclaimed, Bool ramping) void PoolGenUndefer(PoolGen pgen, Size oldSize, Size newSize) { AVERT(PoolGen, pgen); - AVER(pgen->oldDeferredSize >= oldSize); - pgen->oldDeferredSize -= oldSize; - pgen->oldSize += oldSize; + STATISTIC_STAT ({ + AVER(pgen->oldDeferredSize >= oldSize); + pgen->oldDeferredSize -= oldSize; + pgen->oldSize += oldSize; + }); AVER(pgen->newDeferredSize >= newSize); pgen->newDeferredSize -= newSize; pgen->newSize += newSize; @@ -569,7 +585,7 @@ void PoolGenUndefer(PoolGen pgen, Size oldSize, Size newSize) void PoolGenSegSplit(PoolGen pgen) { AVERT(PoolGen, pgen); - ++ pgen->segs; + STATISTIC(++ pgen->segs); } @@ -578,8 +594,10 @@ void PoolGenSegSplit(PoolGen pgen) void PoolGenSegMerge(PoolGen pgen) { AVERT(PoolGen, pgen); - AVER(pgen->segs > 0); - -- pgen->segs; + STATISTIC_STAT ({ + AVER(pgen->segs > 0); + -- pgen->segs; + }); } @@ -595,13 +613,15 @@ void PoolGenFree(PoolGen pgen, Seg seg) AVERT(PoolGen, pgen); AVERT(Seg, seg); - AVER(pgen->segs > 0); - -- pgen->segs; size = SegSize(seg); AVER(pgen->totalSize >= size); pgen->totalSize -= size; - AVER(pgen->freeSize >= size); - pgen->freeSize -= size; + STATISTIC_STAT ({ + AVER(pgen->segs > 0); + -- pgen->segs; + AVER(pgen->freeSize >= size); + pgen->freeSize -= size; + }); SegFree(seg); } @@ -619,7 +639,6 @@ void LocusInit(Arena arena) gen->zones = ZoneSetEMPTY; gen->capacity = 0; /* unused */ gen->mortality = 0.51; - gen->proflow = 0.0; RingInit(&gen->locusRing); gen->sig = GenDescSig; } diff --git a/mps/code/trace.c b/mps/code/trace.c index 74144774564..1f5358bd1e9 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -634,33 +634,6 @@ static Res traceFlip(Trace trace) return res; } -/* traceCopySizes -- preserve size information for later use - * - * A PoolGen's newSize is important information that we want to emit in - * a diagnostic message at TraceStart. In order to do that we must copy - * the information before Whiten changes it. This function does that. - */ - -static void traceCopySizes(Trace trace) -{ - Ring node, nextNode; - Index i; - Arena arena = trace->arena; - - RING_FOR(node, &arena->chainRing, nextNode) { - Chain chain = RING_ELT(Chain, chainRing, node); - - for(i = 0; i < chain->genCount; ++i) { - Ring n, nn; - GenDesc desc = &chain->gens[i]; - RING_FOR(n, &desc->locusRing, nn) { - PoolGen gen = RING_ELT(PoolGen, genRing, n); - gen->newSizeAtCreate = gen->newSize; - } - } - } - return; -} /* TraceCreate -- create a Trace object * @@ -677,6 +650,17 @@ static void traceCopySizes(Trace trace) * This code is written to be adaptable to allocating Trace objects * dynamically. */ +static void TraceCreatePoolGen(GenDesc gen) +{ + Ring n, nn; + RING_FOR(n, &gen->locusRing, nn) { + PoolGen pgen = RING_ELT(PoolGen, genRing, n); + EVENT11(TraceCreatePoolGen, gen, gen->capacity, gen->mortality, gen->zones, + pgen->pool, pgen->totalSize, pgen->freeSize, pgen->newSize, + pgen->oldSize, pgen->newDeferredSize, pgen->oldDeferredSize); + } +} + Res TraceCreate(Trace *traceReturn, Arena arena, int why) { TraceId ti; @@ -747,7 +731,24 @@ Res TraceCreate(Trace *traceReturn, Arena arena, int why) /* .. _request.dylan.160098: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160098 */ ShieldSuspend(arena); - traceCopySizes(trace); + STATISTIC_STAT ({ + /* Iterate over all chains, all GenDescs within a chain, and all + * PoolGens within a GenDesc. */ + Ring node; + Ring nextNode; + + RING_FOR(node, &arena->chainRing, nextNode) { + Chain chain = RING_ELT(Chain, chainRing, node); + Index i; + for (i = 0; i < chain->genCount; ++i) { + GenDesc gen = &chain->gens[i]; + TraceCreatePoolGen(gen); + } + } + + /* Now do topgen GenDesc, and all PoolGens within it. */ + TraceCreatePoolGen(&arena->topGen); + }); *traceReturn = trace; return ResOK; @@ -1564,9 +1565,9 @@ double TraceWorkFactor = 0.25; * * TraceStart should be passed a trace with state TraceINIT, i.e., * recently returned from TraceCreate, with some condemned segments - * added. mortality is the fraction of the condemned set expected to - * survive. finishingTime is relative to the current polling clock, see - * . + * added. mortality is the fraction of the condemned set expected not + * to survive. finishingTime is relative to the current polling clock, + * see . * * .start.black: All segments are black w.r.t. a newly allocated trace. * However, if TraceStart initialized segments to black when it @@ -1588,19 +1589,6 @@ static Res rootGrey(Root root, void *p) } -static void TraceStartPoolGen(GenDesc gen) -{ - Ring n, nn; - RING_FOR(n, &gen->locusRing, nn) { - PoolGen pgen = RING_ELT(PoolGen, genRing, n); - EVENT12(TraceStartPoolGen, gen, gen->capacity, gen->mortality, gen->zones, - pgen->pool, pgen->totalSize, pgen->freeSize, pgen->oldSize, - pgen->newSize, pgen->oldDeferredSize, pgen->newDeferredSize, - pgen->newSizeAtCreate); - } -} - - /* TraceStart -- start a trace whose white set has been established * * The main job of TraceStart is to set up the grey list for a trace. The @@ -1665,26 +1653,6 @@ Res TraceStart(Trace trace, double mortality, double finishingTime) } while (SegNext(&seg, arena, seg)); } - STATISTIC_STAT ({ - /* @@ */ - /* Iterate over all chains, all GenDescs within a chain, */ - /* (and all PoolGens within a GenDesc). */ - Ring node; - Ring nextNode; - Index i; - - RING_FOR(node, &arena->chainRing, nextNode) { - Chain chain = RING_ELT(Chain, chainRing, node); - for(i = 0; i < chain->genCount; ++i) { - GenDesc gen = &chain->gens[i]; - TraceStartPoolGen(gen); - } - } - - /* Now do topgen GenDesc (and all PoolGens within it). */ - TraceStartPoolGen(&arena->topGen); - }); - res = RootsIterate(ArenaGlobals(arena), rootGrey, (void *)trace); AVER(res == ResOK); diff --git a/mps/design/strategy.txt b/mps/design/strategy.txt index 4b09c3cc004..f4d3cdb6e49 100644 --- a/mps/design/strategy.txt +++ b/mps/design/strategy.txt @@ -175,46 +175,113 @@ new segment occupies. Note that this zoneset can never shrink. + +Parameters +.......... + +_`.param.intro`: A generation has two parameters, *capacity* and +*mortality*, specified by the client program. + +_`.param.capacity`: The *capacity* of a generation is the amount of +*new* allocation in that generation (that is, allocation since the +last time the generation was condemned) that will cause the generation +to be collected by ``TracePoll()``. + +_`.param.capacity.misnamed`: The name *capacity* is unfortunate since +it suggests that the total amount of memory in the generation will not +exceed this value. But that will only be the case for pool classes +that always promote survivors to another generation. When there is +*old* allocation in the generation (that is, prior to the last time +the generation was condemned), as there is in the case of non-moving +pool classes, the size of a generation is unrelated to its capacity. + +_`.param.mortality`: The *mortality* of a generation is the proportion +(between 0 and 1) of memory in the generation that is expected to be +dead when the generation is collected. It is used in ``TraceStart()`` +to estimate the amount of data that will have to be scanned in order +to complete the trace. + + Accounting .......... -- ``gen[N].mortality`` +_`.accounting.intro`: Pool generations maintain the sizes of various +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: - - Specified by the client. - - TODO: fill in how this is used. +_`.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()``. -- ``gen[N].capacity`` +_`.accounting.condemn`: ``ChainCondemnAuto()`` 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. - - Specified by the client. - - TODO: fill in how this is used. +_`.accounting.check`: Computing the new size for a pool generation is +far from straightforward: see job003772_ for some (former) errors in +this code. In order to assist with checking that this has been +computed correctly, the locus module uses a double-entry book-keeping +system to account for every byte in each pool generation. This uses +six accounts: -- ``amcSeg->new`` +.. _job003772: http://www.ravenbrook.com/project/mps/issue/job003772/ - - TODO: fill this in +_`.account.total`: Memory acquired from the arena. -- ``pgen->totalSize``: +_`.account.total.negated`: From the point of view of the double-entry +system, the *total* should be negative as it is owing to the arena, +but it is inconvenient to represent negative sizes, and so the +positive value is stored instead. - - incremented by ``AMCBufferFill()``; - - decremented by ``amcReclaimNailed()`` and ``AMCReclaim()``; - - added up by ``GenDescTotalSize(gen)``. +_`.account.total.negated.justification`: We don't have a type for +signed sizes; but if we represented it in two's complement using the +unsigned ``Size`` type then Clang's unsigned integer overflow detector +would complain. -- ``pgen->newSize``: +_`.account.free`: Memory that is not in use (free or lost to +fragmentation). - - incremented by ``AMCBufferFill()`` (*when not ramping*) and ``AMCRampEnd()``; - - decremented by ``AMCWhiten()``, - - added up by ``GenDescNewSize(gen)``. +_`.account.new`: Memory in use by the client program, allocated +since the last time the generation was condemned. -- ``gen[N].proflow``: +_`.account.old`: Memory in use by the client program, allocated +prior to the last time the generation was condemned. - - set to 1.0 by ``ChainCreate()``; - - ``arena->topGen.proflow`` set to 0.0 by ``LocusInit(arena)``; - - *The value of this field is never used*. +_`.account.newDeferred`: Memory in use by the client program, +allocated since the last time the generation was condemned, but which +should not cause collections via ``TracePoll()``. (Due to ramping; see +below.) +_`.account.oldDeferred`: Memory in use by the client program, +allocated prior to the last time the generation was condemned, but +which should not cause collections via ``TracePoll()``. (Due to +ramping; see below.) -- ``pgen->newSizeAtCreate``: +_`.accounting.op`: The following operations are provided: + +_`.accounting.op.alloc`: Allocate a segment in a pool generation. +Debit *total*, credit *free*. (But see `.account.total.negated`_.) + +_`.accounting.op.free`: Free a segment. Debit *free*, credit *total*. +(But see `.account.total.negated`_.) + +_`.accounting.op.fill`: Allocate memory, for example by filling a +buffer. Debit *free*, credit *new* or *newDeferred*. + +_`.accounting.op.empty`: Deallocate memory, for example by emptying +the unused portion of a buffer. Debit *new* or *newDeferred*, credit +*free*. + +_`.accounting.op.age`: Condemn memory. Debit *new* or *newDeferred*, +credit *old* or *oldDeferred*. + +_`.accounting.op.reclaim`: Reclaim dead memory. Debit *old* or +*oldDeferred*, credit *free*. + +_`.accounting.op.undefer`: Stop deferring the accounting of memory. Debit *oldDeferred*, credit *old*. Debit *newDeferred*, credit *new*. - - set by ``traceCopySizes()`` (that is its purpose); - - output in the ``TraceStartPoolGen`` telemetry event. Ramps ..... @@ -289,29 +356,31 @@ Reclaiming any AMC segment: Now, some deductions: #. When OUTSIDE, the count is always zero, because (a) it starts that -way, and the only ways to go OUTSIDE are (b) by leaving an outermost -ramp (count goes to zero) or (c) by reclaiming when the count is zero. + way, and the only ways to go OUTSIDE are (b) by leaving an + outermost ramp (count goes to zero) or (c) by reclaiming when the + count is zero. #. When BEGIN, the count is never zero (consider the transitions to -BEGIN and the transition to zero). + BEGIN and the transition to zero). -#. When RAMPING, the count is never zero (again consider transitions to -RAMPING and the transition to zero). +#. When RAMPING, the count is never zero (again consider transitions + to RAMPING and the transition to zero). -#. When FINISH, the count can be anything (the transition to FINISH has -zero count, but the Enter transition when FINISH can change that and -then it can increment to any value). +#. When FINISH, the count can be anything (the transition to FINISH + has zero count, but the Enter transition when FINISH can change + that and then it can increment to any value). #. When COLLECTING, the count can be anything (from the previous fact, -and the transition to COLLECTING). + and the transition to COLLECTING). -#. *This is a bug!!* The ramp generation is not always reset (to forward -to the after-ramp generation). If we get into FINISH and then see -another ramp before the next condemnation of the ramp generation, we -will Enter followed by Leave. The Enter will keep us in FINISH, and -the Leave will take us back to OUTSIDE, skipping the transition to the -COLLECTING state which is what resets the ramp generation forwarding -buffer. [TODO: check whether I made an issue and/or fixed it; NB 2013-06-04] +#. *This is a bug!!* The ramp generation is not always reset (to + forward to the after-ramp generation). If we get into FINISH and + then see another ramp before the next condemnation of the ramp + generation, we will Enter followed by Leave. The Enter will keep us + in FINISH, and the Leave will take us back to OUTSIDE, skipping the + transition to the COLLECTING state which is what resets the ramp + generation forwarding buffer. [TODO: check whether I made an issue + and/or fixed it; NB 2013-06-04] The simplest change to fix this is to change the behaviour of the Leave transition, which should only take us OUTSIDE if we are in BEGIN or From 7b9e9ab0d925baa3878bdb3c24f19f0498c11500 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 1 May 2014 22:06:47 +0100 Subject: [PATCH 151/266] Store flags as bitfields to save space in segment structure. Copied from Perforce Change: 185932 ServerID: perforce.ravenbrook.com --- mps/code/poolamc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 4baf8cb1789..35dabd62441 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -94,8 +94,8 @@ typedef struct amcSegStruct { GCSegStruct gcSegStruct; /* superclass fields must come first */ amcGen gen; /* generation this segment belongs to */ Nailboard board; /* nailboard for this segment or NULL if none */ - Bool old; /* .seg.old */ - Bool deferred; /* .seg.deferred */ + unsigned old : 1; /* .seg.old */ + unsigned deferred : 1; /* .seg.deferred */ Sig sig; /* */ } amcSegStruct; From 3a627e6bbb29b1df9f2421108ad3d23b6ae3a5f6 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 2 May 2014 11:34:38 +0100 Subject: [PATCH 152/266] The mps_args_add_field and mps_args_done now check that the number of arguments is in bounds. Copied from Perforce Change: 185938 ServerID: perforce.ravenbrook.com --- mps/code/airtest.c | 1 - mps/code/fmtscheme.c | 1 - mps/code/mps.h | 19 ++++++++++--------- mps/code/mpsi.c | 18 ++++++++++++++++++ 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/mps/code/airtest.c b/mps/code/airtest.c index 56e1bd8c129..bf840957414 100644 --- a/mps/code/airtest.c +++ b/mps/code/airtest.c @@ -112,7 +112,6 @@ static void test_main(void *marker, int interior, int stack) MPS_ARGS_ADD(args, MPS_KEY_CHAIN, obj_chain); MPS_ARGS_ADD(args, MPS_KEY_FORMAT, obj_fmt); MPS_ARGS_ADD(args, MPS_KEY_INTERIOR, interior); - MPS_ARGS_DONE(args); die(mps_pool_create_k(&obj_pool, scheme_arena, mps_class_amc(), args), "mps_pool_create_k"); } MPS_ARGS_END(args); diff --git a/mps/code/fmtscheme.c b/mps/code/fmtscheme.c index 11900130a71..f43990ec619 100644 --- a/mps/code/fmtscheme.c +++ b/mps/code/fmtscheme.c @@ -452,7 +452,6 @@ void scheme_fmt(mps_fmt_t *fmt) MPS_ARGS_ADD(args, MPS_KEY_FMT_FWD, obj_fwd); MPS_ARGS_ADD(args, MPS_KEY_FMT_ISFWD, obj_isfwd); MPS_ARGS_ADD(args, MPS_KEY_FMT_PAD, obj_pad); - MPS_ARGS_DONE(args); res = mps_fmt_create_k(fmt, scheme_arena, args); } MPS_ARGS_END(args); if (res != MPS_RES_OK) error("Couldn't create obj format"); diff --git a/mps/code/mps.h b/mps/code/mps.h index b948a5f8d7d..18767cec60f 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-2013 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * Portions copyright (c) 2002 Global Graphics Software. * * THIS HEADER IS NOT DOCUMENTATION. @@ -227,20 +227,22 @@ extern const struct mps_key_s _mps_key_fmt_class; /* Maximum length of a keyword argument list. */ #define MPS_ARGS_MAX 32 +extern void _mps_args_set_key(mps_arg_s args[MPS_ARGS_MAX], unsigned i, + mps_key_t key); + #define MPS_ARGS_BEGIN(_var) \ MPS_BEGIN \ mps_arg_s _var[MPS_ARGS_MAX]; \ unsigned _var##_i = 0; \ - _var[_var##_i].key = MPS_KEY_ARGS_END; \ + _mps_args_set_key(_var, _var##_i, MPS_KEY_ARGS_END); \ MPS_BEGIN #define MPS_ARGS_ADD_FIELD(_var, _key, _field, _val) \ MPS_BEGIN \ - /* TODO: AVER(_var##_i + 1 < MPS_ARGS_MAX); */ \ - _var[_var##_i].key = (_key); \ + _mps_args_set_key(_var, _var##_i, _key); \ _var[_var##_i].val._field = (_val); \ ++_var##_i; \ - _var[_var##_i].key = MPS_KEY_ARGS_END; \ + _mps_args_set_key(_var, _var##_i, MPS_KEY_ARGS_END); \ MPS_END #define MPS_ARGS_ADD(_var, _key, _val) \ @@ -248,9 +250,8 @@ extern const struct mps_key_s _mps_key_fmt_class; #define MPS_ARGS_DONE(_var) \ MPS_BEGIN \ - /* TODO: AVER(_var##_i < MPS_ARGS_MAX); */ \ - _var[_var##_i].key = MPS_KEY_ARGS_END; \ - /* TODO: _var##_i = MPS_ARGS_MAX; */ \ + _mps_args_set_key(_var, _var##_i, MPS_KEY_ARGS_END); \ + _var##_i = MPS_ARGS_MAX; \ MPS_END #define MPS_ARGS_END(_var) \ @@ -812,7 +813,7 @@ extern mps_res_t _mps_fix2(mps_ss_t, mps_addr_t *); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2013 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index f4e3f9e6f02..0573a6d4256 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1929,6 +1929,24 @@ void mps_chain_destroy(mps_chain_t chain) } +/* _mps_args_set_key -- set the key for a keyword argument + * + * This sets the key for the i'th keyword argument in the array args, + * with bounds checking on i. It is used by the MPS_ARGS_BEGIN, + * MPS_ARGS_ADD, and MPS_ARGS_DONE macros in mps.h. + * + * We implement this in a function here, rather than in a macro in + * mps.h, so that we can use AVER to do the bounds checking. + */ + +void _mps_args_set_key(mps_arg_s args[MPS_ARGS_MAX], unsigned i, + mps_key_t key) +{ + AVER(i < MPS_ARGS_MAX); + args[i].key = key; +} + + /* C. COPYRIGHT AND LICENSE * * Copyright (C) 2001-2014 Ravenbrook Limited . From b4512c164be5b6e227a88ec4011646395cc9845e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 2 May 2014 11:43:52 +0100 Subject: [PATCH 153/266] Document the assertion that you get when you failed to destroy an object. Copied from Perforce Change: 185939 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/error.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index fb55c9785f1..29fefc6e1b6 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -232,13 +232,6 @@ assertion that is listed here but for which you discovered a different cause), please :ref:`let us know ` so that we can improve this documentation. -``sa.c: BTIsResRange(sa->mapped, 0, sa->length)`` - - The client program called :c:func:`mps_arena_destroy` without - having destroyed all pools in that arena first. (The assertion is - from the virtual memory manager which is checking that all pages - have been unmapped.) - ``dbgpool.c: fencepost check on free`` @@ -293,6 +286,15 @@ this documentation. condition? +``ring.c: ring->next == ring`` + + 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. + + ``trace.c: RefSetSub(ScanStateUnfixedSummary(ss), SegSummary(seg))`` The client program's :term:`scan method` failed to update a From 33e5e5a0839ab5e270d85f3738be071754580716 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 3 May 2014 10:43:12 +0100 Subject: [PATCH 154/266] Add note explaining that objects are not reclaimed immediately after discarding the finalization message, so you need to ensure they remain valid. Copied from Perforce Change: 185946 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/finalization.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mps/manual/source/topic/finalization.rst b/mps/manual/source/topic/finalization.rst index 32f618f19e7..2542f2ba1c7 100644 --- a/mps/manual/source/topic/finalization.rst +++ b/mps/manual/source/topic/finalization.rst @@ -85,6 +85,15 @@ calling :c:func:`mps_message_discard`. will cause it to be finalized again should all strong references disappear again. +.. note:: + + Calling :c:func:`mps_message_discard` does not reclaim the space + occupied by the finalized block (that happens at the next + collection, if the block is found to be dead at that point), and + so the block must remain validly formatted (:term:`scannable `, :term:`skippable `, and so on). You might + choose to replace it with a :term:`padding object`. + See :ref:`topic-message` for details of the message mechanism. From 9ddb915453aed444f0b241c5522ff65c99cd1ba9 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 3 May 2014 10:45:50 +0100 Subject: [PATCH 155/266] Fix typo. Copied from Perforce Change: 185947 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/finalization.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mps/manual/source/topic/finalization.rst b/mps/manual/source/topic/finalization.rst index 2542f2ba1c7..745feefed16 100644 --- a/mps/manual/source/topic/finalization.rst +++ b/mps/manual/source/topic/finalization.rst @@ -91,8 +91,8 @@ calling :c:func:`mps_message_discard`. occupied by the finalized block (that happens at the next collection, if the block is found to be dead at that point), and so the block must remain validly formatted (:term:`scannable `, :term:`skippable `, and so on). You might - choose to replace it with a :term:`padding object`. + method>`, :term:`skippable `, and so on). It might + make sense to replace it with a :term:`padding object`. See :ref:`topic-message` for details of the message mechanism. @@ -132,12 +132,12 @@ Cautions finalization. The MPS does not finalize a block until it determines that the block is finalizable, which may require a full garbage collection in the worst case, and such a collection may - not :ref:`scheduled ` for some time. Or - the block may never become finalizable because it is incorrectly - determined to be reachable due to an :term:`ambiguous reference` - pointing to it. Or the block may never become finalizable because - it remains reachable through a reference, even if that reference - might never be used. + not be :ref:`scheduled ` for some time. + Or the block may never become finalizable because it is + incorrectly determined to be reachable due to an :term:`ambiguous + reference` pointing to it. Or the block may never become + finalizable because it remains reachable through a reference, even + if that reference might never be used. #. Even when blocks are finalized in a reasonably timely fashion, the client needs to process the finalization messages in time to avoid From debf5bce1851d50ffd37529875057fd42215f185 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 4 May 2014 20:39:31 +0100 Subject: [PATCH 156/266] Scheme constructors now take an allocation point. Copied from Perforce Change: 185959 ServerID: perforce.ravenbrook.com --- mps/code/airtest.c | 6 ++-- mps/code/fmtscheme.c | 68 ++++++++++++++++++++++---------------------- mps/code/fmtscheme.h | 26 +++++++++-------- 3 files changed, 51 insertions(+), 49 deletions(-) diff --git a/mps/code/airtest.c b/mps/code/airtest.c index bf840957414..a4537a390db 100644 --- a/mps/code/airtest.c +++ b/mps/code/airtest.c @@ -50,14 +50,14 @@ static void test_air(int interior, int stack) } mps_message_type_enable(scheme_arena, mps_message_type_finalization()); for (j = 0; j < OBJ_COUNT; ++j) { - obj_t n = scheme_make_integer((long)j); - obj_t obj = scheme_make_vector(OBJ_LEN, n); + obj_t n = scheme_make_integer(obj_ap, (long)j); + obj_t obj = scheme_make_vector(obj_ap, OBJ_LEN, n); mps_addr_t ref = obj; mps_finalize(scheme_arena, &ref); s[j] = obj->vector.vector; } for (i = 1; i < OBJ_LEN; ++i) { - obj_t n = scheme_make_integer((long)i); + obj_t n = scheme_make_integer(obj_ap, (long)i); mps_message_t msg; for (j = 0; j + 1 < OBJ_COUNT; ++j) { *++s[j] = n; diff --git a/mps/code/fmtscheme.c b/mps/code/fmtscheme.c index f43990ec619..24fa06db871 100644 --- a/mps/code/fmtscheme.c +++ b/mps/code/fmtscheme.c @@ -44,86 +44,86 @@ obj_t scheme_make_bool(int condition) return condition ? obj_true : obj_false; } -obj_t scheme_make_pair(obj_t car, obj_t cdr) +obj_t scheme_make_pair(mps_ap_t ap, obj_t car, obj_t cdr) { obj_t obj; mps_addr_t addr; size_t size = ALIGN_OBJ(sizeof(pair_s)); do { - mps_res_t res = mps_reserve(&addr, obj_ap, size); + mps_res_t res = mps_reserve(&addr, ap, size); if (res != MPS_RES_OK) error("out of memory in make_pair"); obj = addr; obj->pair.type = TYPE_PAIR; CAR(obj) = car; CDR(obj) = cdr; - } while(!mps_commit(obj_ap, addr, size)); + } while(!mps_commit(ap, addr, size)); return obj; } -obj_t scheme_make_integer(long integer) +obj_t scheme_make_integer(mps_ap_t ap, long integer) { obj_t obj; mps_addr_t addr; size_t size = ALIGN_OBJ(sizeof(integer_s)); do { - mps_res_t res = mps_reserve(&addr, obj_ap, size); + mps_res_t res = mps_reserve(&addr, ap, size); if (res != MPS_RES_OK) error("out of memory in make_integer"); obj = addr; obj->integer.type = TYPE_INTEGER; obj->integer.integer = integer; - } while(!mps_commit(obj_ap, addr, size)); + } while(!mps_commit(ap, addr, size)); return obj; } -obj_t scheme_make_symbol(size_t length, char string[]) +obj_t scheme_make_symbol(mps_ap_t ap, size_t length, char string[]) { obj_t obj; mps_addr_t addr; size_t size = ALIGN_OBJ(offsetof(symbol_s, string) + length+1); do { - mps_res_t res = mps_reserve(&addr, obj_ap, size); + mps_res_t res = mps_reserve(&addr, ap, size); if (res != MPS_RES_OK) error("out of memory in make_symbol"); obj = addr; obj->symbol.type = TYPE_SYMBOL; obj->symbol.length = length; memcpy(obj->symbol.string, string, length+1); - } while(!mps_commit(obj_ap, addr, size)); + } while(!mps_commit(ap, addr, size)); return obj; } -obj_t scheme_make_string(size_t length, char string[]) +obj_t scheme_make_string(mps_ap_t ap, size_t length, char string[]) { obj_t obj; mps_addr_t addr; size_t size = ALIGN_OBJ(offsetof(string_s, string) + length+1); do { - mps_res_t res = mps_reserve(&addr, obj_ap, size); + mps_res_t res = mps_reserve(&addr, ap, size); if (res != MPS_RES_OK) error("out of memory in make_string"); obj = addr; obj->string.type = TYPE_STRING; obj->string.length = length; if (string) memcpy(obj->string.string, string, length+1); else memset(obj->string.string, 0, length+1); - } while(!mps_commit(obj_ap, addr, size)); + } while(!mps_commit(ap, addr, size)); return obj; } -obj_t scheme_make_special(char *string) +obj_t scheme_make_special(mps_ap_t ap, char *string) { obj_t obj; mps_addr_t addr; size_t size = ALIGN_OBJ(sizeof(special_s)); do { - mps_res_t res = mps_reserve(&addr, obj_ap, size); + mps_res_t res = mps_reserve(&addr, ap, size); if (res != MPS_RES_OK) error("out of memory in make_special"); obj = addr; obj->special.type = TYPE_SPECIAL; obj->special.name = string; - } while(!mps_commit(obj_ap, addr, size)); + } while(!mps_commit(ap, addr, size)); return obj; } -obj_t scheme_make_operator(char *name, +obj_t scheme_make_operator(mps_ap_t ap, char *name, entry_t entry, obj_t arguments, obj_t body, obj_t env, obj_t op_env) { @@ -131,7 +131,7 @@ obj_t scheme_make_operator(char *name, mps_addr_t addr; size_t size = ALIGN_OBJ(sizeof(operator_s)); do { - mps_res_t res = mps_reserve(&addr, obj_ap, size); + mps_res_t res = mps_reserve(&addr, ap, size); if (res != MPS_RES_OK) error("out of memory in make_operator"); obj = addr; obj->operator.type = TYPE_OPERATOR; @@ -141,70 +141,70 @@ obj_t scheme_make_operator(char *name, obj->operator.body = body; obj->operator.env = env; obj->operator.op_env = op_env; - } while(!mps_commit(obj_ap, addr, size)); + } while(!mps_commit(ap, addr, size)); return obj; } -obj_t scheme_make_port(obj_t name, FILE *stream) +obj_t scheme_make_port(mps_ap_t ap, obj_t name, FILE *stream) { mps_addr_t port_ref; obj_t obj; mps_addr_t addr; size_t size = ALIGN_OBJ(sizeof(port_s)); do { - mps_res_t res = mps_reserve(&addr, obj_ap, size); + mps_res_t res = mps_reserve(&addr, ap, size); if (res != MPS_RES_OK) error("out of memory in make_port"); obj = addr; obj->port.type = TYPE_PORT; obj->port.name = name; obj->port.stream = stream; - } while(!mps_commit(obj_ap, addr, size)); + } while(!mps_commit(ap, addr, size)); port_ref = obj; mps_finalize(scheme_arena, &port_ref); return obj; } -obj_t scheme_make_character(char c) +obj_t scheme_make_character(mps_ap_t ap, char c) { obj_t obj; mps_addr_t addr; size_t size = ALIGN_OBJ(sizeof(character_s)); do { - mps_res_t res = mps_reserve(&addr, obj_ap, size); + mps_res_t res = mps_reserve(&addr, ap, size); if (res != MPS_RES_OK) error("out of memory in make_character"); obj = addr; obj->character.type = TYPE_CHARACTER; obj->character.c = c; - } while(!mps_commit(obj_ap, addr, size)); + } while(!mps_commit(ap, addr, size)); return obj; } -obj_t scheme_make_vector(size_t length, obj_t fill) +obj_t scheme_make_vector(mps_ap_t ap, size_t length, obj_t fill) { obj_t obj; mps_addr_t addr; size_t size = ALIGN_OBJ(offsetof(vector_s, vector) + length * sizeof(obj_t)); do { size_t i; - mps_res_t res = mps_reserve(&addr, obj_ap, size); + mps_res_t res = mps_reserve(&addr, ap, size); if (res != MPS_RES_OK) error("out of memory in make_vector"); obj = addr; obj->vector.type = TYPE_VECTOR; obj->vector.length = length; for(i = 0; i < length; ++i) obj->vector.vector[i] = fill; - } while(!mps_commit(obj_ap, addr, size)); + } while(!mps_commit(ap, addr, size)); return obj; } -obj_t scheme_make_buckets(size_t length) +obj_t scheme_make_buckets(mps_ap_t ap, size_t length) { obj_t obj; mps_addr_t addr; size_t size = ALIGN_OBJ(offsetof(buckets_s, bucket) + length * sizeof(obj->buckets.bucket[0])); do { size_t i; - mps_res_t res = mps_reserve(&addr, obj_ap, size); + mps_res_t res = mps_reserve(&addr, ap, size); if (res != MPS_RES_OK) error("out of memory in make_buckets"); obj = addr; obj->buckets.type = TYPE_BUCKETS; @@ -215,27 +215,27 @@ obj_t scheme_make_buckets(size_t length) obj->buckets.bucket[i].key = NULL; obj->buckets.bucket[i].value = NULL; } - } while(!mps_commit(obj_ap, addr, size)); + } while(!mps_commit(ap, addr, size)); return obj; } -obj_t scheme_make_table(size_t length, hash_t hashf, cmp_t cmpf) +obj_t scheme_make_table(mps_ap_t ap, size_t length, hash_t hashf, cmp_t cmpf) { obj_t obj; mps_addr_t addr; size_t l, size = ALIGN_OBJ(sizeof(table_s)); do { - mps_res_t res = mps_reserve(&addr, obj_ap, size); + mps_res_t res = mps_reserve(&addr, ap, size); if (res != MPS_RES_OK) error("out of memory in make_table"); obj = addr; obj->table.type = TYPE_TABLE; obj->table.buckets = NULL; - } while(!mps_commit(obj_ap, addr, size)); + } while(!mps_commit(ap, addr, size)); obj->table.hash = hashf; obj->table.cmp = cmpf; /* round up to next power of 2 */ for(l = 1; l < length; l *= 2); - obj->table.buckets = scheme_make_buckets(l); + obj->table.buckets = scheme_make_buckets(ap, l); mps_ld_reset(&obj->table.ld, scheme_arena); return obj; } diff --git a/mps/code/fmtscheme.h b/mps/code/fmtscheme.h index fbbbddf8ccd..95a62a53cef 100644 --- a/mps/code/fmtscheme.h +++ b/mps/code/fmtscheme.h @@ -168,18 +168,20 @@ typedef union obj_u { extern obj_t scheme_make_bool(int condition); -extern obj_t scheme_make_pair(obj_t car, obj_t cdr); -extern obj_t scheme_make_integer(long integer); -extern obj_t scheme_make_symbol(size_t length, char string[]); -extern obj_t scheme_make_string(size_t length, char string[]); -extern obj_t scheme_make_special(char *string); -extern obj_t scheme_make_operator(char *name, entry_t entry, obj_t arguments, - obj_t body, obj_t env, obj_t op_env); -extern obj_t scheme_make_port(obj_t name, FILE *stream); -extern obj_t scheme_make_character(char c); -extern obj_t scheme_make_vector(size_t length, obj_t fill); -extern obj_t scheme_make_buckets(size_t length); -extern obj_t scheme_make_table(size_t length, hash_t hashf, cmp_t cmpf); +extern obj_t scheme_make_pair(mps_ap_t ap, obj_t car, obj_t cdr); +extern obj_t scheme_make_integer(mps_ap_t ap, long integer); +extern obj_t scheme_make_symbol(mps_ap_t ap, size_t length, char string[]); +extern obj_t scheme_make_string(mps_ap_t ap, size_t length, char string[]); +extern obj_t scheme_make_special(mps_ap_t ap, char *string); +extern obj_t scheme_make_operator(mps_ap_t ap, char *name, entry_t entry, + obj_t arguments, obj_t body, obj_t env, + obj_t op_env); +extern obj_t scheme_make_port(mps_ap_t ap, obj_t name, FILE *stream); +extern obj_t scheme_make_character(mps_ap_t ap, char c); +extern obj_t scheme_make_vector(mps_ap_t ap, size_t length, obj_t fill); +extern obj_t scheme_make_buckets(mps_ap_t ap, size_t length); +extern obj_t scheme_make_table(mps_ap_t ap, size_t length, hash_t hashf, + cmp_t cmpf); extern void scheme_fmt(mps_fmt_t *fmt); extern mps_arena_t scheme_arena; From a329ad7348d8b9f1f92f6116b89e2eb5785629a7 Mon Sep 17 00:00:00 2001 From: David Lovemore Date: Tue, 6 May 2014 12:19:06 +0100 Subject: [PATCH 157/266] Only include tract loop ion segcheck when check level > minimal. This is to speed up SegCheck in HOT variety. Copied from Perforce Change: 185971 ServerID: perforce.ravenbrook.com --- mps/code/seg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mps/code/seg.c b/mps/code/seg.c index 7f0cd4bc907..c9ff20913c9 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -701,6 +701,7 @@ Bool SegCheck(Seg seg) CHECKL(seg->limit > TractBase(seg->firstTract)); /* Each tract of the segment must agree about white traces */ +#ifdef CHECKLEVEL > CheckLevelMINIMAL TRACT_TRACT_FOR(tract, addr, arena, seg->firstTract, seg->limit) { Seg trseg = NULL; /* suppress compiler warning */ @@ -709,6 +710,7 @@ Bool SegCheck(Seg seg) CHECKL(TractWhite(tract) == seg->white); CHECKL(TractPool(tract) == pool); } +#endif CHECKL(addr == seg->limit); /* The segment must belong to some pool, so it should be on a */ From 90fb6c09b3648baabac2788b5e185a2772427dbd Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 7 May 2014 23:33:22 +0100 Subject: [PATCH 158/266] Fix typos. Copied from Perforce Change: 185977 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/arena.rst | 6 +++--- mps/manual/source/topic/interface.rst | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index 1925117cc84..c62d3c58aae 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -396,8 +396,8 @@ Arena properties (over-)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 ``mps_arena_committed() - - mps_arena_spare_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 :c:func:`mps_arena_commit_limit`. @@ -457,7 +457,7 @@ Arena properties Non-virtual-memory arena classes (for example, a :term:`client arena`) do not have spare committed memory. For these arenas, this - function functions sets a value but has no other effect. + 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 diff --git a/mps/manual/source/topic/interface.rst b/mps/manual/source/topic/interface.rst index 478c22b8026..a939ddf302b 100644 --- a/mps/manual/source/topic/interface.rst +++ b/mps/manual/source/topic/interface.rst @@ -226,7 +226,7 @@ Macros implemented as a macro defined in the header, so a library function should not be declared explicitly if its header is included. Any macro definition of a function can be suppressed - locally be enclosing the name of the function in parentheses, + locally by enclosing the name of the function in parentheses, because the name is then not followed by the left parenthesis that indicates expansion of a macro function name. [...] Any invocation of a library function that is implemented as a From 5a672665360374dd67a7be61761e9126c51c02aa Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 7 May 2014 23:38:51 +0100 Subject: [PATCH 159/266] Better to put the example first and discuss it afterwards. Copied from Perforce Change: 185978 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/arena.rst | 66 +++++++++++++++---------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index c62d3c58aae..86e0a39550f 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -506,7 +506,7 @@ An arena is always in one of three states. In the *unclamped state*, garbage collection may take place, objects may move in memory, references may be updated, :term:`location dependencies` may become stale, virtual memory may - be requested from or return to the operating system, and other + be requested from or returned to the operating system, and other kinds of background activity may occur. This is the normal state. #. .. index:: @@ -531,19 +531,19 @@ An arena is always in one of three states. Here's a summary: -======================================== ================================== ============================= =========================== -State unclamped clamped parked -======================================== ================================== ============================= =========================== -Collections may be running? yes yes no -New collections may start? yes no no -Objects may move? yes no no -Location dependencies may become stale? yes no no -Memory may be returned to the OS? yes no no -Functions that leave arena in this state :c:func:`mps_arena_create`, :c:func:`mps_arena_clamp`, :c:func:`mps_arena_park`, - :c:func:`mps_arena_release`, :c:func:`mps_arena_step` :c:func:`mps_arena_collect` - :c:func:`mps_arena_start_collect`, - :c:func:`mps_arena_step` -======================================== ================================== ============================= =========================== +============================================ ================================== ============================= =========================== +State unclamped clamped parked +============================================ ================================== ============================= =========================== +Collections may be running? yes yes no +New collections may start? yes no no +Objects may move? yes no no +Location dependencies may become stale? yes no no +Memory may be returned to the OS? yes no no +Functions that leave the arena in this state :c:func:`mps_arena_create`, :c:func:`mps_arena_clamp`, :c:func:`mps_arena_park`, + :c:func:`mps_arena_release`, :c:func:`mps_arena_step` :c:func:`mps_arena_collect` + :c:func:`mps_arena_start_collect`, + :c:func:`mps_arena_step` +============================================ ================================== ============================= =========================== The clamped and parked states are important when introspecting and debugging. If you are examining the contents of the heap, you don't @@ -556,7 +556,7 @@ before inspecting memory, and:: (gdb) print mps_arena_release(arena) -afterward. +afterwards. The results of introspection functions like :c:func:`mps_arena_has_addr` only remain valid while the arena remains @@ -692,24 +692,7 @@ provides a function, :c:func:`mps_arena_step`, for making use of idle time to make memory management progress. Here's an example illustrating the use of this function in a program's -event loop. When the program is idle (there are no client actions to -perform), it requests that the MPS spend up to 10 milliseconds on -incremental work, by calling ``mps_arena_step(arena, 0.010, -0.0)``. When this returns false to indicate that there is no more work -to do, the program blocks on the client for two seconds: if this times -out, it predicts that the user will remain idle for at least a further -second, so it calls ``mps_arena_step(arena, 0.010, 100.0)`` to tell -that it's a good time to start a collection taking up to 10 ms × 100 -= 1 second, but not to pause for more than 10 ms. - -The program remains responsive: the MPS doesn't take control for more -than a few milliseconds at a time (at most 10). But at the same time, -major collection work can get done at times when the program would -otherwise be idle. Of course the numbers here are only for -illustration and should be chosen based on the requirements of the -application. - -:: +event loop. :: for (;;) { /* event loop */ for (;;) { @@ -729,6 +712,23 @@ application. } } +When the program is idle (there are no client actions to perform), it +requests that the MPS spend up to 10 milliseconds on incremental work, +by calling ``mps_arena_step(arena, 0.010, 0.0)``. When this returns +false to indicate that there is no more work to do, the program blocks +on the client for two seconds: if this times out, it predicts that the +user will remain idle for at least a further second, so it calls +``mps_arena_step(arena, 0.010, 100.0)`` to tell that it's a good time +to start a collection taking up to 10 ms × 100 = 1 second, but not to +pause for more than 10 ms. + +The program remains responsive: the MPS doesn't take control for more +than a few milliseconds at a time (at most 10). But at the same time, +major collection work can get done at times when the program would +otherwise be idle. Of course the numbers here are only for +illustration; they should be chosen based on the requirements of the +application. + .. c:function:: mps_bool_t mps_arena_step(mps_arena_t arena, double interval, double multiplier) From 7d7d668ed4ecf7586819af0b3acd0c420781bfc7 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 10 May 2014 09:44:25 +0100 Subject: [PATCH 160/266] Fix compilation of seg.c. 1. "#ifdef CHECKLEVEL > CheckLevelMINIMAL" was bogus: the #ifdef should have been #if, but even then it would not be right, because in the CHECKLEVEL_DYNAMIC configuration, CHECKLEVEL is a variable rather than a preprocessor constant. So use the condition defined(AVER_AND_CHECK_ALL) instead. 2. The final CHECKL(addr == seg->limit) only makes sense if the loop was executed. 3. The variables used by the loop need to be inside the #if to avoid warnings about unused variables. 4. Add reference to the job from a comment. Copied from Perforce Change: 185992 ServerID: perforce.ravenbrook.com --- mps/code/seg.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/mps/code/seg.c b/mps/code/seg.c index c9ff20913c9..45a61abd185 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -678,10 +678,8 @@ Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at, Bool SegCheck(Seg seg) { - Tract tract; Arena arena; Pool pool; - Addr addr; Size align; CHECKS(Seg, seg); @@ -700,18 +698,25 @@ Bool SegCheck(Seg seg) CHECKL(AddrIsAligned(seg->limit, align)); CHECKL(seg->limit > TractBase(seg->firstTract)); - /* Each tract of the segment must agree about white traces */ -#ifdef CHECKLEVEL > CheckLevelMINIMAL - TRACT_TRACT_FOR(tract, addr, arena, seg->firstTract, seg->limit) { - Seg trseg = NULL; /* suppress compiler warning */ + /* Each tract of the segment must agree about white traces. Note + * that even if the CHECKs are compiled away there is still a + * significant cost in looping over the tracts, hence the guard. See + * job003778. */ +#if defined(AVER_AND_CHECK_ALL) + { + Tract tract; + Addr addr; + TRACT_TRACT_FOR(tract, addr, arena, seg->firstTract, seg->limit) { + Seg trseg = NULL; /* suppress compiler warning */ - CHECKD_NOSIG(Tract, tract); - CHECKL(TRACT_SEG(&trseg, tract) && (trseg == seg)); - CHECKL(TractWhite(tract) == seg->white); - CHECKL(TractPool(tract) == pool); + CHECKD_NOSIG(Tract, tract); + CHECKL(TRACT_SEG(&trseg, tract) && (trseg == seg)); + CHECKL(TractWhite(tract) == seg->white); + CHECKL(TractPool(tract) == pool); + } + CHECKL(addr == seg->limit); } -#endif - CHECKL(addr == seg->limit); +#endif /* AVER_AND_CHECK_ALL */ /* The segment must belong to some pool, so it should be on a */ /* pool's segment ring. (Actually, this isn't true just after */ From c7810cd7a5ebb4a82863a09209fbde499e32f8ab Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 10 May 2014 09:45:26 +0100 Subject: [PATCH 161/266] Defined(aver_and_check_all) is a better condition for invalidating the colour tables. Copied from Perforce Change: 185993 ServerID: perforce.ravenbrook.com --- mps/code/poolams.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/poolams.c b/mps/code/poolams.c index 65b2dcf754f..134d1228be0 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -172,7 +172,7 @@ static Res amsCreateTables(AMS ams, BT *allocReturn, goto failWhite; } -#if defined(AVER_AND_CHECK) +#if defined(AVER_AND_CHECK_ALL) /* Invalidate the colour tables in checking varieties. The algorithm * is designed not to depend on the initial values of these tables, * so by invalidating them we get some checking of this. From 80d10acf0f863e08ed60ef31277743da681a1a73 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 10 May 2014 09:47:58 +0100 Subject: [PATCH 162/266] Remove some unused headers. Copied from Perforce Change: 185994 ServerID: perforce.ravenbrook.com --- mps/code/clock.h | 1 - mps/code/misc.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/mps/code/clock.h b/mps/code/clock.h index 253f7a5e0e4..d5fd7bc0e4e 100644 --- a/mps/code/clock.h +++ b/mps/code/clock.h @@ -7,7 +7,6 @@ #ifndef clock_h #define clock_h -#include #include "mpmtypes.h" /* for Word */ diff --git a/mps/code/misc.h b/mps/code/misc.h index fed416157dd..7380421d5c5 100644 --- a/mps/code/misc.h +++ b/mps/code/misc.h @@ -13,8 +13,6 @@ #ifndef misc_h #define misc_h -#include - typedef int Bool; /* */ enum BoolEnum { From e75322e735dd0d5a3e84e4debb488d4a4be3dd64 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 11 May 2014 18:16:46 +0100 Subject: [PATCH 163/266] Use xcrun so that we support xcode-select. Copied from Perforce Change: 185998 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 4 ++-- mps/tool/testcoverage | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mps/Makefile.in b/mps/Makefile.in index 2d558588673..e8899cce95c 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -1,7 +1,7 @@ # Makefile.in -- source for autoconf Makefile # # $Id$ -# Copyright (C) 2012-2013 Ravenbrook Limited. See end of file for license. +# Copyright (C) 2012-2014 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. @@ -17,7 +17,7 @@ MPS_TARGET_NAME=@MPS_TARGET_NAME@ EXTRA_TARGETS=@EXTRA_TARGETS@ prefix=$(DESTDIR)@prefix@ TARGET_OPTS=-C code -f $(MPS_TARGET_NAME).gmk EXTRA_TARGETS="$(EXTRA_TARGETS)" -XCODEBUILD=xcodebuild -project code/mps.xcodeproj +XCODEBUILD=xcrun xcodebuild -project code/mps.xcodeproj all: @BUILD_TARGET@ diff --git a/mps/tool/testcoverage b/mps/tool/testcoverage index ff1967031dd..dacae8cd5f4 100755 --- a/mps/tool/testcoverage +++ b/mps/tool/testcoverage @@ -26,14 +26,14 @@ case "$ARCH-$OS" in CONFIGURATION=Debug ( cd -- "$CODE" - xcodebuild -config "$CONFIGURATION" clean - xcodebuild -config "$CONFIGURATION" -target testrun \ + xcrun xcodebuild -config "$CONFIGURATION" clean + xcrun xcodebuild -config "$CONFIGURATION" -target testrun \ GCC_GENERATE_TEST_COVERAGE_FILES=YES \ GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES ) ( cd -- "$CODE/xc/$PROJECT.build/$CONFIGURATION/$PROJECT.build/Objects-normal/$ARCH" - gcov mps.c 2> /dev/null + xcrun gcov mps.c 2> /dev/null ) | "$TOOL/gcovfmt" ;; *) From 3c10ea5cddcbad977db054ce3a4b1d58b780001c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 11 May 2014 18:17:40 +0100 Subject: [PATCH 164/266] Check keyword arguments after picking them. Copied from Perforce Change: 185999 ServerID: perforce.ravenbrook.com --- mps/code/arg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mps/code/arg.c b/mps/code/arg.c index e3fea68754d..407487b4060 100644 --- a/mps/code/arg.c +++ b/mps/code/arg.c @@ -159,6 +159,7 @@ Bool ArgPick(ArgStruct *argOut, ArgList args, Key key) { return FALSE; found: + AVER(key->check(&args[i])); *argOut = args[i]; for(;;) { args[i] = args[i + 1]; From a853b9570efdc4b7b8f5276a0f0764feb8fcf829 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 11 May 2014 18:52:53 +0100 Subject: [PATCH 165/266] Remove unused function mfsgetinfo and unused type mfsinfo. Copied from Perforce Change: 186004 ServerID: perforce.ravenbrook.com --- mps/code/poolmfs.c | 10 ---------- mps/code/poolmfs.h | 12 ++---------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c index 139b3f5c872..b40094d839c 100644 --- a/mps/code/poolmfs.c +++ b/mps/code/poolmfs.c @@ -57,18 +57,8 @@ typedef struct MFSHeaderStruct { } HeaderStruct, *Header; - #define UNIT_MIN sizeof(HeaderStruct) -MFSInfo MFSGetInfo(void) -{ - static const struct MFSInfoStruct info = - { - /* unitSizeMin */ UNIT_MIN - }; - return &info; -} - Pool (MFSPool)(MFS mfs) { diff --git a/mps/code/poolmfs.h b/mps/code/poolmfs.h index 7ab337d4393..5f2fd0780ed 100644 --- a/mps/code/poolmfs.h +++ b/mps/code/poolmfs.h @@ -2,7 +2,7 @@ * * $Id$ * - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * The MFS pool is used to manage small fixed-size chunks of memory. It * stores control structures in the memory it manages, rather than to one @@ -39,14 +39,6 @@ extern Bool MFSCheck(MFS mfs); extern Pool (MFSPool)(MFS mfs); -typedef const struct MFSInfoStruct *MFSInfo; - -struct MFSInfoStruct { - Size unitSizeMin; /* minimum unit size */ -}; - -extern MFSInfo MFSGetInfo(void); - extern const struct mps_key_s _mps_key_MFSExtendSelf; #define MFSExtendSelf (&_mps_key_MFSExtendSelf) #define MFSExtendSelf_FIELD b @@ -63,7 +55,7 @@ extern void MFSFinishTracts(Pool pool, MFSTractVisitor visitor, /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From 32cd7e343baf3fb7a05a44aff687b6690f7c809e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 11 May 2014 19:09:44 +0100 Subject: [PATCH 166/266] Remove mps_key_cbs_extend_by and mfsextendself keyword arguments to cbsinit. these were unused and obsoleted by cbsblockpool. Copied from Perforce Change: 186006 ServerID: perforce.ravenbrook.com --- mps/code/cbs.c | 9 --------- mps/code/config.h | 5 ----- mps/code/mps.h | 3 --- 3 files changed, 17 deletions(-) diff --git a/mps/code/cbs.c b/mps/code/cbs.c index addebd398ad..3e3411023eb 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -232,14 +232,11 @@ static void cbsUpdateZonedNode(SplayTree splay, Tree tree) * See . */ -ARG_DEFINE_KEY(cbs_extend_by, Size); ARG_DEFINE_KEY(cbs_block_pool, Pool); Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment, Bool fastFind, Bool zoned, ArgList args) { - Size extendBy = CBS_EXTEND_BY_DEFAULT; - Bool extendSelf = TRUE; ArgStruct arg; Res res; Pool blockPool = NULL; @@ -253,10 +250,6 @@ Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment, if (ArgPick(&arg, args, CBSBlockPool)) blockPool = arg.val.pool; - if (ArgPick(&arg, args, MPS_KEY_CBS_EXTEND_BY)) - extendBy = arg.val.size; - if (ArgPick(&arg, args, MFSExtendSelf)) - extendSelf = arg.val.b; update = SplayTrivUpdate; if (fastFind) @@ -274,8 +267,6 @@ Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment, } else { MPS_ARGS_BEGIN(pcArgs) { MPS_ARGS_ADD(pcArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSBlockStruct)); - MPS_ARGS_ADD(pcArgs, MPS_KEY_EXTEND_BY, extendBy); - MPS_ARGS_ADD(pcArgs, MFSExtendSelf, extendSelf); res = PoolCreate(&cbs->blockPool, arena, PoolClassMFS(), pcArgs); } MPS_ARGS_END(pcArgs); if (res != ResOK) diff --git a/mps/code/config.h b/mps/code/config.h index 1dfd7858f86..5d2eff42104 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -264,11 +264,6 @@ #define BUFFER_RANK_DEFAULT (mps_rank_exact()) -/* CBS Configuration -- see */ - -#define CBS_EXTEND_BY_DEFAULT ((Size)4096) - - /* Format defaults: see */ #define FMT_ALIGN_DEFAULT ((Align)MPS_PF_ALIGN) diff --git a/mps/code/mps.h b/mps/code/mps.h index 18767cec60f..049a489f96d 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -188,9 +188,6 @@ extern const struct mps_key_s _mps_key_max_size; extern const struct mps_key_s _mps_key_align; #define MPS_KEY_ALIGN (&_mps_key_align) #define MPS_KEY_ALIGN_FIELD align -extern const struct mps_key_s _mps_key_cbs_extend_by; -#define MPS_KEY_CBS_EXTEND_BY (&_mps_key_cbs_extend_by) -#define MPS_KEY_CBS_EXTEND_BY_FIELD size extern const struct mps_key_s _mps_key_interior; #define MPS_KEY_INTERIOR (&_mps_key_interior) #define MPS_KEY_INTERIOR_FIELD b From 026662618cc280fcee984a14fb489859339221a7 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 11 May 2014 19:18:54 +0100 Subject: [PATCH 167/266] Check the argument using argcheck. Copied from Perforce Change: 186007 ServerID: perforce.ravenbrook.com --- mps/code/arg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/arg.c b/mps/code/arg.c index 407487b4060..784a7e57f30 100644 --- a/mps/code/arg.c +++ b/mps/code/arg.c @@ -159,7 +159,7 @@ Bool ArgPick(ArgStruct *argOut, ArgList args, Key key) { return FALSE; found: - AVER(key->check(&args[i])); + AVERT(Arg, &args[i]); *argOut = args[i]; for(;;) { args[i] = args[i + 1]; From a4044d0dc325101532472d2d0c2a5542ceb630bc Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 11 May 2014 21:47:20 +0100 Subject: [PATCH 168/266] It is an error to destroy a chain if there is an active trace using the chain. Copied from Perforce Change: 186013 ServerID: perforce.ravenbrook.com --- mps/code/amcss.c | 2 ++ mps/code/amcsshe.c | 2 ++ mps/code/amsss.c | 1 + mps/code/amssshe.c | 2 ++ mps/code/locus.c | 1 + 5 files changed, 8 insertions(+) diff --git a/mps/code/amcss.c b/mps/code/amcss.c index 48892a45830..20e86f80897 100644 --- a/mps/code/amcss.c +++ b/mps/code/amcss.c @@ -275,6 +275,7 @@ static void test(mps_arena_t arena, mps_class_t pool_class, size_t roots_count) } (void)mps_commit(busy_ap, busy_init, 64); + mps_arena_park(arena); mps_ap_destroy(busy_ap); mps_ap_destroy(ap); mps_root_destroy(exactRoot); @@ -282,6 +283,7 @@ static void test(mps_arena_t arena, mps_class_t pool_class, size_t roots_count) mps_pool_destroy(pool); mps_chain_destroy(chain); mps_fmt_destroy(format); + mps_arena_release(arena); } int main(int argc, char *argv[]) diff --git a/mps/code/amcsshe.c b/mps/code/amcsshe.c index 8b3a0c65e36..cd19b4219e6 100644 --- a/mps/code/amcsshe.c +++ b/mps/code/amcsshe.c @@ -225,6 +225,7 @@ static void *test(mps_arena_t arena, mps_class_t pool_class, size_t roots_count) } (void)mps_commit(busy_ap, busy_init, 64); + mps_arena_park(arena); mps_ap_destroy(busy_ap); mps_ap_destroy(ap); mps_root_destroy(exactRoot); @@ -233,6 +234,7 @@ static void *test(mps_arena_t arena, mps_class_t pool_class, size_t roots_count) mps_pool_destroy(pool); mps_chain_destroy(chain); mps_fmt_destroy(format); + mps_arena_release(arena); return NULL; } diff --git a/mps/code/amsss.c b/mps/code/amsss.c index 9128561ecf2..d87ebe95c02 100644 --- a/mps/code/amsss.c +++ b/mps/code/amsss.c @@ -231,6 +231,7 @@ int main(int argc, char *argv[]) } MPS_ARGS_END(args); } + mps_arena_park(arena); mps_chain_destroy(chain); mps_fmt_destroy(format); mps_thread_dereg(thread); diff --git a/mps/code/amssshe.c b/mps/code/amssshe.c index ce5dd4800c8..206e7c29ffe 100644 --- a/mps/code/amssshe.c +++ b/mps/code/amssshe.c @@ -139,6 +139,7 @@ static void *test(void *arg, size_t s) } (void)mps_commit(busy_ap, busy_init, 64); + mps_arena_park(arena); mps_ap_destroy(busy_ap); mps_ap_destroy(ap); mps_root_destroy(exactRoot); @@ -146,6 +147,7 @@ static void *test(void *arg, size_t s) mps_pool_destroy(pool); mps_chain_destroy(chain); mps_fmt_destroy(format); + mps_arena_release(arena); return NULL; } diff --git a/mps/code/locus.c b/mps/code/locus.c index 10eae03840f..62b0b3be13e 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -212,6 +212,7 @@ void ChainDestroy(Chain chain) size_t i; AVERT(Chain, chain); + AVER(chain->activeTraces == TraceSetEMPTY); arena = chain->arena; genCount = chain->genCount; RingRemove(&chain->chainRing); From e7f41fe61b5a6bddc59c0de3ecb0c3654e7c34bb Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 11:19:57 +0100 Subject: [PATCH 169/266] Park the arena before destroying the default chain, to ensure that there are no traces using that chain. Fix test cases that used automatic collection, but destroyed data structures without parking the arena. Document the requirement on mps_chain_destroy and add the assertion to "common assertions and their causes". Copied from Perforce Change: 186021 ServerID: perforce.ravenbrook.com --- mps/code/amcssth.c | 39 +++++++++++--------------- mps/code/exposet0.c | 1 + mps/code/global.c | 4 +++ mps/code/qs.c | 2 ++ mps/manual/source/topic/collection.rst | 8 ++++-- mps/manual/source/topic/error.rst | 11 +++++++- 6 files changed, 39 insertions(+), 26 deletions(-) diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c index 2f91edee93e..b96df985028 100644 --- a/mps/code/amcssth.c +++ b/mps/code/amcssth.c @@ -149,17 +149,6 @@ static void init(void) } -/* finish -- finish roots and chain */ - -static void finish(void) -{ - mps_root_destroy(exactRoot); - mps_root_destroy(ambigRoot); - mps_chain_destroy(chain); - mps_fmt_destroy(format); -} - - /* churn -- create an object and install into roots */ static void churn(mps_ap_t ap, size_t roots_count) @@ -218,7 +207,7 @@ static void *kid_thread(void *arg) /* test -- the body of the test */ -static void *test_pool(mps_class_t pool_class, size_t roots_count, int mode) +static void test_pool(mps_pool_t pool, size_t roots_count, int mode) { size_t i; mps_word_t collections, rampSwitch; @@ -226,14 +215,10 @@ static void *test_pool(mps_class_t pool_class, size_t roots_count, int mode) int ramping; mps_ap_t ap, busy_ap; mps_addr_t busy_init; - mps_pool_t pool; testthr_t kids[10]; closure_s cl; int walked = FALSE, ramped = FALSE; - die(mps_pool_create(&pool, arena, pool_class, format, chain), - "pool_create(amc)"); - cl.pool = pool; cl.roots_count = roots_count; @@ -323,16 +308,13 @@ static void *test_pool(mps_class_t pool_class, size_t roots_count, int mode) for (i = 0; i < sizeof(kids)/sizeof(kids[0]); ++i) testthr_join(&kids[i], NULL); - - mps_pool_destroy(pool); - - return NULL; } static void test_arena(int mode) { mps_thr_t thread; mps_root_t reg_root; + mps_pool_t amc_pool, amcz_pool; void *marker = ▮ die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), @@ -345,12 +327,23 @@ static void test_arena(int mode) die(mps_root_create_reg(®_root, arena, mps_rank_ambig(), 0, thread, mps_stack_scan_ambig, marker, 0), "root_create"); - test_pool(mps_class_amc(), exactRootsCOUNT, mode); - test_pool(mps_class_amcz(), 0, mode); + die(mps_pool_create(&amc_pool, arena, mps_class_amc(), format, chain), + "pool_create(amc)"); + 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); + + mps_arena_park(arena); + mps_pool_destroy(amc_pool); + mps_pool_destroy(amcz_pool); mps_root_destroy(reg_root); mps_thread_dereg(thread); - finish(); + mps_root_destroy(exactRoot); + mps_root_destroy(ambigRoot); + mps_chain_destroy(chain); + mps_fmt_destroy(format); report(arena); mps_arena_destroy(arena); } diff --git a/mps/code/exposet0.c b/mps/code/exposet0.c index 21f2567cbaa..a1e8fcdc6e8 100644 --- a/mps/code/exposet0.c +++ b/mps/code/exposet0.c @@ -222,6 +222,7 @@ static void *test(void *arg, size_t s) } (void)mps_commit(busy_ap, busy_init, 64); + mps_arena_park(arena); mps_ap_destroy(busy_ap); mps_ap_destroy(ap); mps_root_destroy(exactRoot); diff --git a/mps/code/global.c b/mps/code/global.c index ce4ebbe6faa..4e3528ad7f3 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -431,6 +431,10 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) AVERT(Globals, arenaGlobals); + /* Park the arena before destroying the default chain, to ensure + * that there are no traces using that chain. */ + ArenaPark(arenaGlobals); + arena = GlobalsArena(arenaGlobals); arenaDenounce(arena); diff --git a/mps/code/qs.c b/mps/code/qs.c index 50fe8c48723..ec3b9cb28d2 100644 --- a/mps/code/qs.c +++ b/mps/code/qs.c @@ -367,6 +367,7 @@ static void *go(void *p, size_t s) qsort(list, listl, sizeof(mps_word_t), &compare); validate(); + mps_arena_park(arena); mps_root_destroy(regroot); mps_root_destroy(actroot); mps_ap_destroy(ap); @@ -374,6 +375,7 @@ static void *go(void *p, size_t s) mps_pool_destroy(mpool); mps_chain_destroy(chain); mps_fmt_destroy(format); + mps_arena_release(arena); return NULL; } diff --git a/mps/manual/source/topic/collection.rst b/mps/manual/source/topic/collection.rst index adf7c058e9e..f061d946ad8 100644 --- a/mps/manual/source/topic/collection.rst +++ b/mps/manual/source/topic/collection.rst @@ -134,8 +134,12 @@ For example:: ``chain`` is the generation chain. - It is an error to destroy a generation chain if there exists a - :term:`pool` using the chain. The pool must be destroyed first. + It is an error to destroy a generation chain if there is a garbage + collection in progress on the chain, or if there are any + :term:`pools` using the chain. Before calling this function, the + arena should be parked (by calling :c:func:`mps_arena_park`) to + ensure that there are no collections in progress, and pools using + the chain must be destroyed. .. index:: diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 29fefc6e1b6..200c20af8bb 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -262,6 +262,15 @@ this documentation. :term:`format methods` and :term:`stepper functions`. +``locus.c: chain->activeTraces == TraceSetEMPTY)`` + + The client program called :c:func:`mps_chain_destroy`, but there + was a garbage collection in progress on that chain. + + Park the arena before destroying the chain by calling + :c:func:`mps_arena_park`. + + ``mpsi.c: SizeIsAligned(size, BufferPool(buf)->alignment)`` The client program reserved a block by calling @@ -269,7 +278,7 @@ this documentation. alignment required by the pool's :term:`object format`. -``pool.c: (pool->class->attr & AttrALLOC) != 0`` +``pool.c: PoolHasAttr(pool, AttrALLOC)`` The client program called :c:func:`mps_alloc` on a pool that does not support this form of allocation. Use an :term:`allocation From 08822ad7e0053b1e3c81936bf3fe879efaa88936 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 12:30:46 +0100 Subject: [PATCH 170/266] Mpseventtxt must not itself output telemetry, otherwise it is likely to overwrite the telemetry it is converting. Copied from Perforce Change: 186023 ServerID: perforce.ravenbrook.com --- mps/code/eventtxt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mps/code/eventtxt.c b/mps/code/eventtxt.c index 4c50ac994f9..bc0d550d122 100644 --- a/mps/code/eventtxt.c +++ b/mps/code/eventtxt.c @@ -40,9 +40,10 @@ #include "testlib.h" /* for ulongest_t and associated print formats */ #include +#include #include #include /* exit, EXIT_FAILURE, EXIT_SUCCESS */ -#include /* strcpy, strlen */ +#include /* strcpy, strerror, strlen */ static const char *prog; /* program name */ static const char *logFileName = NULL; @@ -571,6 +572,11 @@ int main(int argc, char *argv[]) everror("unable to open %s", logFileName); } + /* Ensure no telemetry output. */ + res = setenv("MPS_TELEMETRY_CONTROL", "0", 1); + if (res != 0) + everror("failed to set MPS_TELEMETRY_CONTROL: %s", strerror(errno)); + res = mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none); if (res != MPS_RES_OK) everror("failed to create arena: %d", res); From 435722442e6b37449ab3903cb21895ec9de9b5d4 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 12:53:46 +0100 Subject: [PATCH 171/266] Park the arena before calling mps_chain_destroy. Speed up mpsicv by reducing number of objects and by only running the test once (there's no inlined mps_tramp any more). Copied from Perforce Change: 186024 ServerID: perforce.ravenbrook.com --- mps/code/expt825.c | 1 + mps/code/finalcv.c | 1 + mps/code/finaltest.c | 1 + mps/code/gcbench.c | 1 + mps/code/mpsicv.c | 5 +++-- mps/code/steptest.c | 2 ++ mps/code/walkt0.c | 3 +++ mps/code/zcoll.c | 1 + mps/code/zmess.c | 1 + 9 files changed, 14 insertions(+), 2 deletions(-) diff --git a/mps/code/expt825.c b/mps/code/expt825.c index 5e775455909..bd6c5f2b1e0 100644 --- a/mps/code/expt825.c +++ b/mps/code/expt825.c @@ -250,6 +250,7 @@ static void *test(void *arg, size_t s) (ulongest_t)object_count); } + mps_arena_park(arena); mps_ap_destroy(ap); mps_root_destroy(mps_root); mps_pool_destroy(amc); diff --git a/mps/code/finalcv.c b/mps/code/finalcv.c index 1466e514ff8..931503cf9bb 100644 --- a/mps/code/finalcv.c +++ b/mps/code/finalcv.c @@ -199,6 +199,7 @@ static void *test(void *arg, size_t s) /* @@@@ missing */ + mps_arena_park(arena); mps_ap_destroy(ap); mps_root_destroy(mps_root[1]); mps_root_destroy(mps_root[0]); diff --git a/mps/code/finaltest.c b/mps/code/finaltest.c index f449d7e1acf..a34dccec3be 100644 --- a/mps/code/finaltest.c +++ b/mps/code/finaltest.c @@ -284,6 +284,7 @@ int main(int argc, char *argv[]) test_mode(ModePOLL, arena, chain); test_mode(ModePARK, arena, NULL); + mps_arena_park(arena); mps_chain_destroy(chain); mps_thread_dereg(thread); mps_arena_destroy(arena); diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c index 2a18d1a7d10..c958128ce4f 100644 --- a/mps/code/gcbench.c +++ b/mps/code/gcbench.c @@ -243,6 +243,7 @@ static void arena_setup(gcthread_fn_t fn, RESMUST(mps_pool_create_k(&pool, arena, pool_class, args)); } MPS_ARGS_END(args); watch(fn, name); + mps_arena_park(arena); mps_pool_destroy(pool); mps_fmt_destroy(format); if (ngen > 0) diff --git a/mps/code/mpsicv.c b/mps/code/mpsicv.c index 55396aee3fe..6a241561a22 100644 --- a/mps/code/mpsicv.c +++ b/mps/code/mpsicv.c @@ -21,7 +21,7 @@ #define exactRootsCOUNT 49 #define ambigRootsCOUNT 49 -#define OBJECTS 200000 +#define OBJECTS 100000 #define patternFREQ 100 /* objNULL needs to be odd so that it's ignored in exactRoots. */ @@ -552,6 +552,8 @@ static void *test(void *arg, size_t s) mps_free(mv, alloced_obj, 32); alloc_v_test(mv); + + mps_arena_park(arena); mps_pool_destroy(mv); mps_ap_destroy(ap); mps_root_destroy(fmtRoot); @@ -589,7 +591,6 @@ int main(int argc, char *argv[]) marker, (size_t)0), "root_create_reg"); - (mps_tramp)(&r, test, arena, 0); /* non-inlined trampoline */ mps_tramp(&r, test, arena, 0); mps_root_destroy(reg_root); mps_thread_dereg(thread); diff --git a/mps/code/steptest.c b/mps/code/steptest.c index deee85fef2e..546eaa7e417 100644 --- a/mps/code/steptest.c +++ b/mps/code/steptest.c @@ -478,6 +478,8 @@ static void *test(void *arg, size_t s) printf(" %"PRIuLONGEST" clock reads; ", (ulongest_t)clock_reads); print_time("", total_clock_time / clock_reads, " per read;"); print_time(" recently measured as ", clock_time, ").\n"); + + mps_arena_park(arena); mps_ap_destroy(ap); mps_root_destroy(exactRoot); mps_root_destroy(ambigRoot); diff --git a/mps/code/walkt0.c b/mps/code/walkt0.c index 929408fc4b4..6b0002000d4 100644 --- a/mps/code/walkt0.c +++ b/mps/code/walkt0.c @@ -191,11 +191,14 @@ static void *test(mps_arena_t arena, mps_class_t pool_class) /* Note: stepper finds more than we expect, due to pad objects */ /* printf("stepper found %ld objs\n", sd->count); */ + + mps_arena_park(arena); mps_ap_destroy(ap); mps_root_destroy(exactRoot); mps_pool_destroy(pool); mps_chain_destroy(chain); mps_fmt_destroy(format); + mps_arena_release(arena); return NULL; } diff --git a/mps/code/zcoll.c b/mps/code/zcoll.c index 06ef499f5b7..220368f39d3 100644 --- a/mps/code/zcoll.c +++ b/mps/code/zcoll.c @@ -774,6 +774,7 @@ static void *testscriptB(void *arg, size_t s) testscriptC(arena, ap, script); printf(" Destroy roots, pools, arena etc.\n\n"); + mps_arena_park(arena); mps_root_destroy(root_stackreg); mps_ap_destroy(ap); mps_root_destroy(root_table_Exact); diff --git a/mps/code/zmess.c b/mps/code/zmess.c index 555e7377d2c..4cfaf9944f3 100644 --- a/mps/code/zmess.c +++ b/mps/code/zmess.c @@ -381,6 +381,7 @@ static void *testscriptB(void *arg, size_t s) testscriptC(arena, script); + mps_arena_park(arena); mps_ap_destroy(ap); mps_root_destroy(root_table); mps_pool_destroy(amc); From 5ae19ee234b5a73d92d42cea355befcf4612587a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 12:54:33 +0100 Subject: [PATCH 172/266] Improve coverage of events by turning on mps_telemetry_control=all and by running mpseventcnv, mpseventtxt and (if available) mpseventsql. Copied from Perforce Change: 186025 ServerID: perforce.ravenbrook.com --- mps/tool/testcoverage | 2 ++ mps/tool/testrun.sh | 22 +++++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/mps/tool/testcoverage b/mps/tool/testcoverage index dacae8cd5f4..cf4c62ae703 100755 --- a/mps/tool/testcoverage +++ b/mps/tool/testcoverage @@ -20,6 +20,8 @@ OS=$(uname -s) PROJECT=mps TOOL=$(dirname "$0") CODE=$TOOL/../code +MPS_TELEMETRY_CONTROL=all +export MPS_TELEMETRY_CONTROL case "$ARCH-$OS" in *-Darwin) diff --git a/mps/tool/testrun.sh b/mps/tool/testrun.sh index 175443bf820..f1719e7549a 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -67,13 +67,17 @@ echo "Test directory: $TEST_DIR" shift TEST_CASES=${*:-${ALL_TEST_CASES}} -SEPARATOR="----------------------------------------" +SEPARATOR=---------------------------------------- TEST_COUNT=0 PASS_COUNT=0 FAIL_COUNT=0 for TESTCASE in $TEST_CASES; do - TEST="$(basename -- "$TESTCASE")" - LOGTEST="$LOGDIR/$TEST" + TEST=$(basename -- "$TESTCASE") + LOGTEST=$LOGDIR/$TEST + TELEMETRY=$LOGDIR/$TEST-io + MPS_TELEMETRY_FILENAME=$TELEMETRY.log + export MPS_TELEMETRY_FILENAME + echo "Running $TEST" TEST_COUNT=$(expr $TEST_COUNT + 1) if "$TEST_DIR/$TESTCASE" > "$LOGTEST" 2>&1; then @@ -86,6 +90,18 @@ for TESTCASE in $TEST_CASES; do echo ${SEPARATOR}${SEPARATOR} FAIL_COUNT=$(expr $FAIL_COUNT + 1) fi + + if [ -f "$MPS_TELEMETRY_FILENAME" ]; then + "$TEST_DIR/mpseventcnv" -f "$MPS_TELEMETRY_FILENAME" > "$TELEMETRY.cnv" + gzip "$MPS_TELEMETRY_FILENAME" + "$TEST_DIR/mpseventtxt" < "$TELEMETRY.cnv" > "$TELEMETRY.txt" + if [ -x "$TEST_DIR/mpseventsql" ]; then + MPS_TELEMETRY_DATABASE=$TELEMETRY.db + export MPS_TELEMETRY_DATABASE + "$TEST_DIR/mpseventsql" < "$TELEMETRY.cnv" >> "$LOGTEST" 2>&1 + fi + rm -f "$TELEMETRY.cnv" "$TELEMETRY.txt" "$TELEMETRY.db" + fi done if [ $FAIL_COUNT = 0 ]; then echo "Tests: $TEST_COUNT. All tests pass." From 95ee3a45688e33f6a1efee0224794ee624e8ac66 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 13:35:21 +0100 Subject: [PATCH 173/266] Check the trace argument to tracequantum. Copied from Perforce Change: 186027 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 bd2b871fb11..219c6d89a2c 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1738,7 +1738,10 @@ Res TraceStart(Trace trace, double mortality, double finishingTime) void TraceQuantum(Trace trace) { Size pollEnd; - Arena arena = trace->arena; + Arena arena; + + AVERT(Trace, trace); + arena = trace->arena; pollEnd = traceWorkClock(trace) + trace->rate; do { From 467f35d5f1a7388a70f04c61bbfaa47a91216346 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 15:58:16 +0100 Subject: [PATCH 174/266] Test cases must call mps_arena_park before mps_chain_destroy. Reduce the amount of work done by some test cases, to make the suite easier to run. Update the list of passing test cases. Copied from Perforce Change: 186030 ServerID: perforce.ravenbrook.com --- mps/test/function/10.c | 8 +++++--- mps/test/function/103.c | 1 + mps/test/function/104.c | 1 + mps/test/function/105.c | 1 + mps/test/function/106.c | 1 + mps/test/function/107.c | 1 + mps/test/function/108.c | 1 + mps/test/function/109.c | 1 + mps/test/function/11.c | 1 + mps/test/function/110.c | 2 ++ mps/test/function/111.c | 1 + mps/test/function/112.c | 1 + mps/test/function/113.c | 5 +++-- mps/test/function/114.c | 5 +++-- mps/test/function/116.c | 1 + mps/test/function/118.c | 1 + mps/test/function/12.c | 1 + mps/test/function/122.c | 1 + mps/test/function/123.c | 1 + mps/test/function/124.c | 3 ++- mps/test/function/125.c | 1 + mps/test/function/126.c | 1 + mps/test/function/127.c | 3 ++- mps/test/function/128.c | 3 ++- mps/test/function/129.c | 3 ++- mps/test/function/12p.c | 1 + mps/test/function/13.c | 1 + mps/test/function/130.c | 1 + mps/test/function/131.c | 1 + mps/test/function/132.c | 1 + mps/test/function/133.c | 1 + mps/test/function/134.c | 3 ++- mps/test/function/138.c | 1 + mps/test/function/14.c | 1 + mps/test/function/147.c | 1 + mps/test/function/148.c | 1 + mps/test/function/149.c | 1 + mps/test/function/15.c | 1 + mps/test/function/150.c | 2 ++ mps/test/function/151.c | 1 + mps/test/function/152.c | 1 + mps/test/function/153.c | 1 + mps/test/function/16.c | 1 + mps/test/function/17.c | 1 + mps/test/function/171.c | 1 + mps/test/function/2.c | 1 + mps/test/function/215.c | 1 + mps/test/function/223.c | 1 + mps/test/function/226.c | 1 + mps/test/function/227.c | 1 + mps/test/function/23.c | 2 ++ mps/test/function/24.c | 9 ++++++--- mps/test/function/25.c | 1 + mps/test/function/27.c | 2 +- mps/test/function/28.c | 1 + mps/test/function/29.c | 1 + mps/test/function/3.c | 1 + mps/test/function/30.c | 1 + mps/test/function/31.c | 1 + mps/test/function/32.c | 1 + mps/test/function/33.c | 1 + mps/test/function/34.c | 1 + mps/test/function/35.c | 1 + mps/test/function/36.c | 1 + mps/test/function/37.c | 1 + mps/test/function/38.c | 1 + mps/test/function/39.c | 1 + mps/test/function/4.c | 1 + mps/test/function/40.c | 1 + mps/test/function/41.c | 1 + mps/test/function/42.c | 1 + mps/test/function/43.c | 1 + mps/test/function/44.c | 1 + mps/test/function/45.c | 1 + mps/test/function/46.c | 1 + mps/test/function/47.c | 1 + mps/test/function/48.c | 1 + mps/test/function/49.c | 1 + mps/test/function/5.c | 1 + mps/test/function/50.c | 2 ++ mps/test/function/51.c | 1 + mps/test/function/52.c | 1 + mps/test/function/53.c | 1 + mps/test/function/54.c | 1 + mps/test/function/55.c | 1 + mps/test/function/56.c | 1 + mps/test/function/57.c | 1 + mps/test/function/6.c | 2 ++ mps/test/function/60.c | 7 ++++--- mps/test/function/61.c | 1 + mps/test/function/62.c | 1 + mps/test/function/63.c | 1 + mps/test/function/64.c | 1 + mps/test/function/65.c | 1 + mps/test/function/66.c | 1 + mps/test/function/69.c | 1 + mps/test/function/72.c | 1 + mps/test/function/73.c | 1 + mps/test/function/74.c | 1 + mps/test/function/75.c | 1 + mps/test/function/76.c | 1 + mps/test/function/77.c | 1 + mps/test/function/78.c | 1 + mps/test/function/79.c | 1 + mps/test/function/80.c | 1 + mps/test/function/81.c | 1 + mps/test/function/83.c | 1 + mps/test/function/9.c | 1 + mps/test/function/96.c | 1 + mps/test/function/97.c | 1 + mps/test/function/99.c | 1 + mps/test/testsets/passing | 6 +++--- 112 files changed, 140 insertions(+), 22 deletions(-) diff --git a/mps/test/function/10.c b/mps/test/function/10.c index 912901881a5..47cb48f5e0d 100644 --- a/mps/test/function/10.c +++ b/mps/test/function/10.c @@ -10,6 +10,7 @@ END_HEADER #include "testlib.h" #include "mpscamc.h" +#define OBJSIZE (1u << 20) #define genCOUNT (3) static mps_gen_param_s testChain[genCOUNT] = { @@ -26,7 +27,7 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) static mps_addr_t myskip(mps_addr_t object) { - return (mps_addr_t) ((char *) object + 1); + return (mps_addr_t) ((char *) object + OBJSIZE); } static void mycopy(mps_addr_t object, mps_addr_t to) @@ -99,12 +100,13 @@ static void test(void) for(i=0; i<1000; i++) { do - { die(mps_reserve(&p, ap, 1024*1024), "Reserve: "); + { die(mps_reserve(&p, ap, OBJSIZE), "Reserve: "); } - while (!mps_commit(ap, p, 1024*1024)); + while (!mps_commit(ap, p, OBJSIZE)); comment("%i megabytes allocated", i); } + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_fmt_destroy(format); diff --git a/mps/test/function/103.c b/mps/test/function/103.c index c8c27225160..fc4a7fa160a 100644 --- a/mps/test/function/103.c +++ b/mps/test/function/103.c @@ -136,6 +136,7 @@ static void test(void) mps_arena_collect(arena); } + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/104.c b/mps/test/function/104.c index b267b9b07fe..6faba1afab9 100644 --- a/mps/test/function/104.c +++ b/mps/test/function/104.c @@ -213,6 +213,7 @@ static void test(void) comment("ok"); } + mps_arena_park(arena); mps_ap_destroy(apamc); mps_ap_destroy(aplo); mps_ap_destroy(apawl); diff --git a/mps/test/function/105.c b/mps/test/function/105.c index 888a0f74fa3..c3bf5c69a16 100644 --- a/mps/test/function/105.c +++ b/mps/test/function/105.c @@ -67,6 +67,7 @@ static void test(void) b = allocone(apamc, 1, mps_rank_exact()); a = allocone(apweak, 1, mps_rank_weak()); + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_ap_destroy(apweak); diff --git a/mps/test/function/106.c b/mps/test/function/106.c index 8f751cfaeb2..2ba628970c0 100644 --- a/mps/test/function/106.c +++ b/mps/test/function/106.c @@ -102,6 +102,7 @@ static void test(void) c = conc(string_ch("Hello there"), string_ch(" folks!")); } + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/107.c b/mps/test/function/107.c index 0a83d04a15d..91b5f02fc21 100644 --- a/mps/test/function/107.c +++ b/mps/test/function/107.c @@ -103,6 +103,7 @@ static void test(void) z = alloclo(ap, 0x4000); } + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/108.c b/mps/test/function/108.c index 10631e5eb5c..6dab9f5839d 100644 --- a/mps/test/function/108.c +++ b/mps/test/function/108.c @@ -82,6 +82,7 @@ static void test(void) b = allocdumb(apamc, 0x400*64, 0); } + mps_arena_park(arena); mps_ap_destroy(aplo); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/109.c b/mps/test/function/109.c index 0fccb523989..bccb5cfec7f 100644 --- a/mps/test/function/109.c +++ b/mps/test/function/109.c @@ -267,6 +267,7 @@ static void test(void) report("count2", "%d", final_count); + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_ap_destroy(aplo); diff --git a/mps/test/function/11.c b/mps/test/function/11.c index 286b06a385f..72009080e7f 100644 --- a/mps/test/function/11.c +++ b/mps/test/function/11.c @@ -77,6 +77,7 @@ static void test(void) comment("%d: %x", j, (int) a); } + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/110.c b/mps/test/function/110.c index e61536040de..bbf5aa0dc6d 100644 --- a/mps/test/function/110.c +++ b/mps/test/function/110.c @@ -262,6 +262,7 @@ static void test(void) finalpoll(&z, FINAL_DISCARD); } + mps_arena_park(arena); mps_root_destroy(root0); mps_root_destroy(root1); comment("Destroyed roots."); @@ -280,6 +281,7 @@ static void test(void) report("count2", "%d", final_count); + mps_arena_park(arena); mps_pool_destroy(poolamc); mps_pool_destroy(poolawl); mps_pool_destroy(poollo); diff --git a/mps/test/function/111.c b/mps/test/function/111.c index f7544f82917..6117a82d29c 100644 --- a/mps/test/function/111.c +++ b/mps/test/function/111.c @@ -193,6 +193,7 @@ static void test(void) /* now to test leaving messages open for a long time! */ + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_ap_destroy(aplo); diff --git a/mps/test/function/112.c b/mps/test/function/112.c index 6626add3d9e..e22a67e4dfc 100644 --- a/mps/test/function/112.c +++ b/mps/test/function/112.c @@ -67,6 +67,7 @@ static void test(void) { /* (total allocated is 1000 M) */ + mps_arena_park(arena); mps_root_destroy(root0); mps_root_destroy(root1); comment("Destroyed roots."); diff --git a/mps/test/function/113.c b/mps/test/function/113.c index 83a42fb1709..a897c7fb60a 100644 --- a/mps/test/function/113.c +++ b/mps/test/function/113.c @@ -73,9 +73,9 @@ static void test(void) b = allocone(apamc, 1, mps_rank_exact()); - for (j=1; j<100; j++) + for (j=1; j<=10; j++) { - comment("%i of 100.", j); + comment("%i of 10.", j); a = allocone(apamc, 5, mps_rank_exact()); b = a; c = a; @@ -100,6 +100,7 @@ static void test(void) } } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); comment("Destroyed aps."); diff --git a/mps/test/function/114.c b/mps/test/function/114.c index 6510796a9bb..c273f30cd52 100644 --- a/mps/test/function/114.c +++ b/mps/test/function/114.c @@ -73,9 +73,9 @@ static void test(void) b = allocone(apamc, 1, mps_rank_exact()); - for (j=1; j<100; j++) + for (j=1; j<=10; j++) { - comment("%i of 100.", j); + comment("%i of 10.", j); a = allocone(apamc, 5, mps_rank_exact()); b = a; c = a; @@ -100,6 +100,7 @@ static void test(void) } } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); comment("Destroyed aps."); diff --git a/mps/test/function/116.c b/mps/test/function/116.c index b065af6103e..d843e2b4691 100644 --- a/mps/test/function/116.c +++ b/mps/test/function/116.c @@ -96,6 +96,7 @@ static void test(void) report("postdie", "%s", err_text(res)); } + mps_arena_park(arena); mps_ap_destroy(ap2); comment("Destroyed ap."); diff --git a/mps/test/function/118.c b/mps/test/function/118.c index 4185a586dd6..a77ec4f8f8b 100644 --- a/mps/test/function/118.c +++ b/mps/test/function/118.c @@ -127,6 +127,7 @@ static void test(void) /* now simulate rest of commit */ (void)(busy_ap->limit != 0 || mps_ap_trip(busy_ap, busy_init, objSIZE)); + mps_arena_park(arena); mps_ap_destroy(busy_ap); mps_ap_destroy(ap); mps_pool_destroy(pool); diff --git a/mps/test/function/12.c b/mps/test/function/12.c index 9ac936dc763..5ebaec0dbb4 100644 --- a/mps/test/function/12.c +++ b/mps/test/function/12.c @@ -181,6 +181,7 @@ static void test(void) mps_ap_destroy(ap[i]); } + mps_arena_park(arena); mps_pool_destroy(pool); comment("Destroyed pool."); mps_chain_destroy(chain); diff --git a/mps/test/function/122.c b/mps/test/function/122.c index 4ba0c0c6090..349e5699628 100644 --- a/mps/test/function/122.c +++ b/mps/test/function/122.c @@ -156,6 +156,7 @@ static void test(void) report("count2", "%ld", rootcount); report("countspec", "%ld", speccount); + mps_arena_park(arena); mps_ap_destroy(apamc); mps_ap_destroy(aplo); mps_ap_destroy(apawl); diff --git a/mps/test/function/123.c b/mps/test/function/123.c index 280f05760cc..4166f30f685 100644 --- a/mps/test/function/123.c +++ b/mps/test/function/123.c @@ -95,6 +95,7 @@ static void test(void) setref(a, 0, b); } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); comment("Destroyed aps."); diff --git a/mps/test/function/124.c b/mps/test/function/124.c index 5b84bea864f..cb4620b49de 100644 --- a/mps/test/function/124.c +++ b/mps/test/function/124.c @@ -30,7 +30,7 @@ static mps_gen_param_s testChain[genCOUNT] = { #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (1000000ul) +#define ITERATIONS (100000ul) #define RAMP_INTERFACE /* @@ -137,6 +137,7 @@ static void test(void) } } + mps_arena_park(arena); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); mps_chain_destroy(chain); diff --git a/mps/test/function/125.c b/mps/test/function/125.c index d457f9adc99..1ca2f61fe4a 100644 --- a/mps/test/function/125.c +++ b/mps/test/function/125.c @@ -79,6 +79,7 @@ static void test(void) mps_arena_collect(arena); } + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/126.c b/mps/test/function/126.c index 988205232f9..f72256a1095 100644 --- a/mps/test/function/126.c +++ b/mps/test/function/126.c @@ -81,6 +81,7 @@ static void test(void) comment("reserved %ld, committed %ld", mps_arena_reserved(arena), mps_arena_committed(arena)); + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/127.c b/mps/test/function/127.c index afdb013e7c5..55c67961987 100644 --- a/mps/test/function/127.c +++ b/mps/test/function/127.c @@ -24,7 +24,7 @@ END_HEADER #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (1000000ul) +#define ITERATIONS (100000ul) /* #define RAMP_INTERFACE @@ -137,6 +137,7 @@ static void test(void) { } } + mps_arena_park(arena); mps_ap_destroy(apamc); comment("Destroyed ap."); diff --git a/mps/test/function/128.c b/mps/test/function/128.c index bfb406a23a2..6414e41d976 100644 --- a/mps/test/function/128.c +++ b/mps/test/function/128.c @@ -24,7 +24,7 @@ END_HEADER #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (1000000ul) +#define ITERATIONS (100000ul) /* #define RAMP_INTERFACE @@ -137,6 +137,7 @@ static void test(void) { } } + mps_arena_park(arena); mps_ap_destroy(apamc); comment("Destroyed ap."); diff --git a/mps/test/function/129.c b/mps/test/function/129.c index dd59be650f5..94512cf6e16 100644 --- a/mps/test/function/129.c +++ b/mps/test/function/129.c @@ -24,7 +24,7 @@ END_HEADER #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (1000000ul) +#define ITERATIONS (100000ul) #define RAMP_INTERFACE /* @@ -136,6 +136,7 @@ static void test(void) { } } + mps_arena_park(arena); mps_ap_destroy(apamc); comment("Destroyed ap."); diff --git a/mps/test/function/12p.c b/mps/test/function/12p.c index f748b8eddb7..db389e7f14f 100644 --- a/mps/test/function/12p.c +++ b/mps/test/function/12p.c @@ -196,6 +196,7 @@ cells = allocone(ap[0], NCELLS); mps_ap_destroy(ap[i]); } + mps_arena_park(arena); mps_pool_destroy(pool); comment("Destroyed pool."); diff --git a/mps/test/function/13.c b/mps/test/function/13.c index cd7662a8098..aa5ca31b3ee 100644 --- a/mps/test/function/13.c +++ b/mps/test/function/13.c @@ -192,6 +192,7 @@ cells = allocone(ap[0], NCELLS); mps_ap_destroy(ap[i]); } + mps_arena_park(arena); mps_pool_destroy(pool); comment("Destroyed pool."); diff --git a/mps/test/function/130.c b/mps/test/function/130.c index 1a4a6da3fec..4809d7bc74e 100644 --- a/mps/test/function/130.c +++ b/mps/test/function/130.c @@ -96,6 +96,7 @@ static void test(void) die(allocrone(&a, ap2, 128, mps_rank_exact()), "alloc failed"); + mps_arena_park(arena); mps_ap_destroy(ap2); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/131.c b/mps/test/function/131.c index 5256efeb141..06495ced080 100644 --- a/mps/test/function/131.c +++ b/mps/test/function/131.c @@ -101,6 +101,7 @@ static void test(void) report("postdie", "%s", err_text(res)); } + mps_arena_park(arena); mps_ap_destroy(ap2); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/132.c b/mps/test/function/132.c index f7cae603ce8..b617427cdfa 100644 --- a/mps/test/function/132.c +++ b/mps/test/function/132.c @@ -166,6 +166,7 @@ static void test(void) 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); diff --git a/mps/test/function/133.c b/mps/test/function/133.c index 0556d5cc9d3..d0ca1297af6 100644 --- a/mps/test/function/133.c +++ b/mps/test/function/133.c @@ -120,6 +120,7 @@ static void test(void) { /* destroy everything remaining */ + mps_arena_park(arena); mps_ap_destroy(apamc); comment("Destroyed ap."); diff --git a/mps/test/function/134.c b/mps/test/function/134.c index 178894d7316..5eee39e5c4f 100644 --- a/mps/test/function/134.c +++ b/mps/test/function/134.c @@ -24,7 +24,7 @@ END_HEADER #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (1000000ul) +#define ITERATIONS (100000ul) #define RAMP_INTERFACE /* @@ -137,6 +137,7 @@ static void test(void) { } } + mps_arena_park(arena); mps_ap_destroy(apamc); comment("Destroyed ap."); diff --git a/mps/test/function/138.c b/mps/test/function/138.c index 8c823c6c8a9..d4cfa5d5d4f 100644 --- a/mps/test/function/138.c +++ b/mps/test/function/138.c @@ -66,6 +66,7 @@ static void test(void) mps_arena_collect(arena); } + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/14.c b/mps/test/function/14.c index 9f0e9a4f26e..e77bafeb658 100644 --- a/mps/test/function/14.c +++ b/mps/test/function/14.c @@ -98,6 +98,7 @@ static void test(void) comment("Finished"); + mps_arena_park(arena); mps_ap_destroy(apA); mps_ap_destroy(apB); diff --git a/mps/test/function/147.c b/mps/test/function/147.c index 21c76bcdbdf..1911f05a54e 100644 --- a/mps/test/function/147.c +++ b/mps/test/function/147.c @@ -79,6 +79,7 @@ static void test(void) } } + mps_arena_park(arena); mps_ap_destroy(sap); comment("Destroyed ap."); diff --git a/mps/test/function/148.c b/mps/test/function/148.c index ee80c9169bf..d78b9631450 100644 --- a/mps/test/function/148.c +++ b/mps/test/function/148.c @@ -124,6 +124,7 @@ static void test(void) report("inc4", "%ld", (com2-com1)/BIGSIZE); + mps_arena_park(arena); mps_ap_destroy(ap); mps_ap_destroy(sap); mps_pool_destroy(pool); diff --git a/mps/test/function/149.c b/mps/test/function/149.c index a9d47dac8dc..0792068fd28 100644 --- a/mps/test/function/149.c +++ b/mps/test/function/149.c @@ -168,6 +168,7 @@ static void test(void) { 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."); diff --git a/mps/test/function/15.c b/mps/test/function/15.c index e84ad74313b..cf04dd75545 100644 --- a/mps/test/function/15.c +++ b/mps/test/function/15.c @@ -54,6 +54,7 @@ static void test(void) allocdumb(ap, 1024*256); } + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); diff --git a/mps/test/function/150.c b/mps/test/function/150.c index 1ff43383d3e..40202f6b482 100644 --- a/mps/test/function/150.c +++ b/mps/test/function/150.c @@ -286,6 +286,7 @@ static void test(void) messagepoll(&z, FINAL_DISCARD); } + mps_arena_park(arena); mps_root_destroy(root0); mps_root_destroy(root1); comment("Destroyed roots."); @@ -304,6 +305,7 @@ static void test(void) report("count2", "%d", final_count); + mps_arena_park(arena); mps_pool_destroy(poolamc); mps_pool_destroy(poolawl); mps_pool_destroy(poollo); diff --git a/mps/test/function/151.c b/mps/test/function/151.c index c6bfb05de0b..9a1c20da6b2 100644 --- a/mps/test/function/151.c +++ b/mps/test/function/151.c @@ -59,6 +59,7 @@ static void test(void) comment("%i of %i", i, ITERATIONS); } + mps_arena_park(arena); mps_ap_destroy(sap); comment("Destroyed ap."); diff --git a/mps/test/function/152.c b/mps/test/function/152.c index 784a40a2a19..1836637668e 100644 --- a/mps/test/function/152.c +++ b/mps/test/function/152.c @@ -100,6 +100,7 @@ static void test(void) report("com", "%ld", com1); report("inc2", "%ld", (com1-com)/BIGSIZE); + mps_arena_park(arena); mps_ap_destroy(ap); mps_ap_destroy(sap); comment("Destroyed ap."); diff --git a/mps/test/function/153.c b/mps/test/function/153.c index 97dac39277f..fb23c98dee1 100644 --- a/mps/test/function/153.c +++ b/mps/test/function/153.c @@ -58,6 +58,7 @@ static void test(void) comment("%i of %i", i, ITERATIONS); } + mps_arena_park(arena); mps_ap_destroy(sap); comment("Destroyed ap."); diff --git a/mps/test/function/16.c b/mps/test/function/16.c index d89940f6542..f3088208377 100644 --- a/mps/test/function/16.c +++ b/mps/test/function/16.c @@ -88,6 +88,7 @@ static void test(void) comment("Finished"); + mps_arena_park(arena); mps_ap_destroy(apA); mps_ap_destroy(apB); diff --git a/mps/test/function/17.c b/mps/test/function/17.c index f029f9a742f..a8f665d3ab7 100644 --- a/mps/test/function/17.c +++ b/mps/test/function/17.c @@ -47,6 +47,7 @@ static void test(void) pool1=pool; } + mps_arena_park(arena); mps_pool_destroy(pool); mps_chain_destroy(chain); mps_fmt_destroy(format); diff --git a/mps/test/function/171.c b/mps/test/function/171.c index b6a0037aa5e..4473aae0f35 100644 --- a/mps/test/function/171.c +++ b/mps/test/function/171.c @@ -138,6 +138,7 @@ static void test(void) { } } + mps_arena_park(arena); mps_ap_destroy(apamc); comment("Destroyed ap."); diff --git a/mps/test/function/2.c b/mps/test/function/2.c index 2133f56f47a..7c0c6974919 100644 --- a/mps/test/function/2.c +++ b/mps/test/function/2.c @@ -82,6 +82,7 @@ static void test(void) b = b->ref[0]; } + mps_arena_park(arena); mps_ap_destroy(ap); comment("Destroyed ap."); diff --git a/mps/test/function/215.c b/mps/test/function/215.c index ad55e9df432..14ad7a1b808 100644 --- a/mps/test/function/215.c +++ b/mps/test/function/215.c @@ -150,6 +150,7 @@ static void test(void) { } } + mps_arena_park(arena); mps_ap_destroy(apamc); comment("Destroyed ap."); diff --git a/mps/test/function/223.c b/mps/test/function/223.c index 9340e44f456..7418a356518 100644 --- a/mps/test/function/223.c +++ b/mps/test/function/223.c @@ -150,6 +150,7 @@ static void test(void) { } } + mps_arena_park(arena); mps_ap_destroy(apamc); comment("Destroyed ap."); diff --git a/mps/test/function/226.c b/mps/test/function/226.c index 361c7cf1848..712b35972db 100644 --- a/mps/test/function/226.c +++ b/mps/test/function/226.c @@ -171,6 +171,7 @@ static void test(void) { } } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); comment("Destroyed aps."); diff --git a/mps/test/function/227.c b/mps/test/function/227.c index 89e40fdae74..af07e083a32 100644 --- a/mps/test/function/227.c +++ b/mps/test/function/227.c @@ -164,6 +164,7 @@ static void test(void) { } } + mps_arena_park(arena); mps_ap_destroy(apamc1); mps_ap_destroy(apamc2); comment("Destroyed ap."); diff --git a/mps/test/function/23.c b/mps/test/function/23.c index 02f08029a68..afcf764a059 100644 --- a/mps/test/function/23.c +++ b/mps/test/function/23.c @@ -103,6 +103,8 @@ static void test(void) r = mps_alloc(&p, poolMV, 1024*1024); report("refuse4", "%s", err_text(r)); } + + mps_arena_park(arena); mps_pool_destroy(poolMV); mps_ap_destroy(ap); diff --git a/mps/test/function/24.c b/mps/test/function/24.c index a16cdcec6e8..e28de201019 100644 --- a/mps/test/function/24.c +++ b/mps/test/function/24.c @@ -10,6 +10,8 @@ END_HEADER #include "testlib.h" #include "mpscamc.h" +#define OBJSIZE (10 * (1u << 20)) + #define genCOUNT (3) static mps_gen_param_s testChain[genCOUNT] = { @@ -27,7 +29,7 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) static mps_addr_t myskip(mps_addr_t object) { - return (mps_addr_t) ((char *) object + 1); + return (mps_addr_t) ((char *) object + OBJSIZE); } static void mycopy(mps_addr_t object, mps_addr_t to) @@ -100,13 +102,14 @@ static void test(void) for(i=1; i<1000; i++) { do - { die(mps_reserve(&p, ap, 10*1024*1024), "Reserve: "); + { die(mps_reserve(&p, ap, OBJSIZE), "Reserve: "); } - while (!mps_commit(ap, p, 10*1024*1024)); + while (!mps_commit(ap, p, OBJSIZE)); comment("%i at %p", i, p); comment("%i objects of 10 megabytes each allocated", i); } + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_fmt_destroy(format); diff --git a/mps/test/function/25.c b/mps/test/function/25.c index 5ee683d2ccf..040202bacdf 100644 --- a/mps/test/function/25.c +++ b/mps/test/function/25.c @@ -94,6 +94,7 @@ static void test(void) { c = conc(string_ch("Hello there"), string_ch(" folks!")); } + mps_arena_park(arena); mps_ap_destroy(ap); comment("Destroyed ap."); diff --git a/mps/test/function/27.c b/mps/test/function/27.c index f0c186f3972..2f30b1a81c6 100644 --- a/mps/test/function/27.c +++ b/mps/test/function/27.c @@ -70,8 +70,8 @@ static void test(void) } + mps_arena_park(arena); mps_ap_destroy(ap); - mps_pool_destroy(pool); mps_chain_destroy(chain); mps_fmt_destroy(format); diff --git a/mps/test/function/28.c b/mps/test/function/28.c index 2ebfcd55bd2..5cbf8e803f4 100644 --- a/mps/test/function/28.c +++ b/mps/test/function/28.c @@ -96,6 +96,7 @@ static void test(void) checkfrom(a); + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/29.c b/mps/test/function/29.c index d3294f348b0..70ef940a948 100644 --- a/mps/test/function/29.c +++ b/mps/test/function/29.c @@ -94,6 +94,7 @@ static void test(void) { z = alloclo(ap, 0x4000); } + mps_arena_park(arena); mps_ap_destroy(ap); comment("Destroyed ap."); diff --git a/mps/test/function/3.c b/mps/test/function/3.c index ffc2a533b40..02400bd0e77 100644 --- a/mps/test/function/3.c +++ b/mps/test/function/3.c @@ -82,6 +82,7 @@ static void test(void) comment("%d: %x", j, (int) a); } + mps_arena_park(arena); mps_ap_destroy(ap); comment("Destroyed ap."); diff --git a/mps/test/function/30.c b/mps/test/function/30.c index 748cf8b56a7..583429d8bc2 100644 --- a/mps/test/function/30.c +++ b/mps/test/function/30.c @@ -85,6 +85,7 @@ static void test(void) checkfrom(a); + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_fmt_destroy(format); diff --git a/mps/test/function/31.c b/mps/test/function/31.c index 2221ed53e01..3000a11f1cc 100644 --- a/mps/test/function/31.c +++ b/mps/test/function/31.c @@ -83,6 +83,7 @@ static void test(void) comment("%d of 1000.", i); } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); comment("Destroyed aps."); diff --git a/mps/test/function/32.c b/mps/test/function/32.c index f3cb17f155b..465899c6a13 100644 --- a/mps/test/function/32.c +++ b/mps/test/function/32.c @@ -83,6 +83,7 @@ static void test(void) b = allocdumb(apamc, 0x400*64, 0); } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/33.c b/mps/test/function/33.c index a883b7a7677..31eaeb1164f 100644 --- a/mps/test/function/33.c +++ b/mps/test/function/33.c @@ -82,6 +82,7 @@ static void test(void) b = allocdumb(apamc, 0x400*64, 0); } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/34.c b/mps/test/function/34.c index de1ad4ab423..3d513c75dfe 100644 --- a/mps/test/function/34.c +++ b/mps/test/function/34.c @@ -85,6 +85,7 @@ static void test(void) b = allocdumb(apamc, 0x400*64, 0); } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/35.c b/mps/test/function/35.c index a79ab52c99c..42def83780a 100644 --- a/mps/test/function/35.c +++ b/mps/test/function/35.c @@ -107,6 +107,7 @@ static void test(void) checkfrom(*a); + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/36.c b/mps/test/function/36.c index 3d4482311a3..609d9f9210b 100644 --- a/mps/test/function/36.c +++ b/mps/test/function/36.c @@ -90,6 +90,7 @@ static void test(void) setref(a[j], z, a[k]); } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/37.c b/mps/test/function/37.c index 275cd58dce4..664e9a3dd68 100644 --- a/mps/test/function/37.c +++ b/mps/test/function/37.c @@ -109,6 +109,7 @@ static void test(void) checkfrom(*a); + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/38.c b/mps/test/function/38.c index 409cc6a97b8..e3512864442 100644 --- a/mps/test/function/38.c +++ b/mps/test/function/38.c @@ -151,6 +151,7 @@ static void test(void) } } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolmv); diff --git a/mps/test/function/39.c b/mps/test/function/39.c index 5b27b4ec94b..e2972230a8d 100644 --- a/mps/test/function/39.c +++ b/mps/test/function/39.c @@ -84,6 +84,7 @@ static void test(void) b = allocdumb(apamc, 0x400*64, 0); } + mps_arena_park(arena); mps_ap_destroy(aplo); mps_ap_destroy(apamc); comment("Destroyed aps."); diff --git a/mps/test/function/4.c b/mps/test/function/4.c index 3294eb0a03e..e730bc77ff3 100644 --- a/mps/test/function/4.c +++ b/mps/test/function/4.c @@ -94,6 +94,7 @@ static void test(void) time0 = time1; } + mps_arena_park(arena); mps_ap_destroy(ap); comment("Destroyed ap."); diff --git a/mps/test/function/40.c b/mps/test/function/40.c index 5257e1fcfc1..de0e4dbe462 100644 --- a/mps/test/function/40.c +++ b/mps/test/function/40.c @@ -75,6 +75,7 @@ static void test(void) DC; DMC; + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/41.c b/mps/test/function/41.c index b394e5f37f8..8fcdb372a6d 100644 --- a/mps/test/function/41.c +++ b/mps/test/function/41.c @@ -110,6 +110,7 @@ static void test(void) DMC; } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/42.c b/mps/test/function/42.c index 093246cba11..b56a61f2a09 100644 --- a/mps/test/function/42.c +++ b/mps/test/function/42.c @@ -106,6 +106,7 @@ static void test(void) DMC; } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/43.c b/mps/test/function/43.c index da73237b90b..1b955f268b7 100644 --- a/mps/test/function/43.c +++ b/mps/test/function/43.c @@ -114,6 +114,7 @@ static void test(void) DMC; } + mps_arena_park(arena); mps_ap_destroy(apweak); mps_ap_destroy(apexact); mps_ap_destroy(apamc); diff --git a/mps/test/function/44.c b/mps/test/function/44.c index 949fa922813..f38e36a06e0 100644 --- a/mps/test/function/44.c +++ b/mps/test/function/44.c @@ -166,6 +166,7 @@ static void test(void) RC; } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/45.c b/mps/test/function/45.c index 0442a4dbd35..e3c7f412931 100644 --- a/mps/test/function/45.c +++ b/mps/test/function/45.c @@ -191,6 +191,7 @@ static void test(void) mps_ap_destroy(ap[i]); } + mps_arena_park(arena); mps_pool_destroy(pool); mps_chain_destroy(chain); mps_fmt_destroy(format); diff --git a/mps/test/function/46.c b/mps/test/function/46.c index c5cd9437859..715ba899090 100644 --- a/mps/test/function/46.c +++ b/mps/test/function/46.c @@ -140,6 +140,7 @@ static void test(void) RC; } + mps_arena_park(arena); mps_ap_destroy(apamc); comment("Destroyed aps."); diff --git a/mps/test/function/47.c b/mps/test/function/47.c index 28682810db0..ee7c5605c2e 100644 --- a/mps/test/function/47.c +++ b/mps/test/function/47.c @@ -87,6 +87,7 @@ static void test(void) { + mps_arena_park(arena); mps_ap_destroy(apawl); comment("Destroyed ap."); diff --git a/mps/test/function/48.c b/mps/test/function/48.c index 700c565dc63..3343684fdbf 100644 --- a/mps/test/function/48.c +++ b/mps/test/function/48.c @@ -115,6 +115,7 @@ static void test(void) DMC; } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_ap_destroy(apweak); diff --git a/mps/test/function/49.c b/mps/test/function/49.c index 5fd7f437e91..27864e380e9 100644 --- a/mps/test/function/49.c +++ b/mps/test/function/49.c @@ -273,6 +273,7 @@ static void test(void) report("count2", "%d", final_count); + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_ap_destroy(aplo); diff --git a/mps/test/function/5.c b/mps/test/function/5.c index ae5d74dd5af..7a91636ee30 100644 --- a/mps/test/function/5.c +++ b/mps/test/function/5.c @@ -78,6 +78,7 @@ static void test(void) q->data.size = OBJ_SIZE; (void) mps_commit(apA, p, OBJ_SIZE); + mps_arena_park(arena); mps_ap_destroy(apA); comment("Destroyed apA."); mps_ap_destroy(apB); diff --git a/mps/test/function/50.c b/mps/test/function/50.c index cae53e67e10..741f865eb98 100644 --- a/mps/test/function/50.c +++ b/mps/test/function/50.c @@ -263,6 +263,7 @@ static void test(void) finalpoll(&z, FINAL_DISCARD); } + mps_arena_park(arena); mps_root_destroy(root0); mps_root_destroy(root1); comment("Destroyed roots."); @@ -281,6 +282,7 @@ static void test(void) report("count2", "%d", final_count); + mps_arena_park(arena); mps_pool_destroy(poolamc); mps_pool_destroy(poolawl); mps_pool_destroy(poollo); diff --git a/mps/test/function/51.c b/mps/test/function/51.c index 779445218ae..bdf1a87ad70 100644 --- a/mps/test/function/51.c +++ b/mps/test/function/51.c @@ -219,6 +219,7 @@ static void test(void) /* now to test leaving messages open for a long time! */ + mps_arena_park(arena); mps_ap_destroy(apamc); mps_ap_destroy(apamcz); mps_ap_destroy(apams); diff --git a/mps/test/function/52.c b/mps/test/function/52.c index 4663f49e65e..d0c757a3059 100644 --- a/mps/test/function/52.c +++ b/mps/test/function/52.c @@ -87,6 +87,7 @@ static void test(void) time0 = time1; } + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/53.c b/mps/test/function/53.c index 4fc78b1b187..6012a05befc 100644 --- a/mps/test/function/53.c +++ b/mps/test/function/53.c @@ -103,6 +103,7 @@ static void test(void) DMC; } + mps_arena_park(arena); mps_ap_destroy(apamc); mps_ap_destroy(aplo); comment("Destroyed aps."); diff --git a/mps/test/function/54.c b/mps/test/function/54.c index cbf4044a0e6..f2c712ac15a 100644 --- a/mps/test/function/54.c +++ b/mps/test/function/54.c @@ -105,6 +105,7 @@ static void test(void) DMC; } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/55.c b/mps/test/function/55.c index c8ed50f3c0c..f34a2fb1856 100644 --- a/mps/test/function/55.c +++ b/mps/test/function/55.c @@ -104,6 +104,7 @@ static void test(void) DMC; } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/56.c b/mps/test/function/56.c index 87f9a29b97a..697b2e04b6c 100644 --- a/mps/test/function/56.c +++ b/mps/test/function/56.c @@ -102,6 +102,7 @@ static void test(void) DMC; } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/57.c b/mps/test/function/57.c index 5e0177b10b4..dbaab342bd9 100644 --- a/mps/test/function/57.c +++ b/mps/test/function/57.c @@ -99,6 +99,7 @@ static void test(void) DMC; } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/6.c b/mps/test/function/6.c index 7e56e09317a..bbbe1217b3e 100644 --- a/mps/test/function/6.c +++ b/mps/test/function/6.c @@ -79,6 +79,8 @@ static void test(void) } } + mps_arena_park(arena); + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/60.c b/mps/test/function/60.c index 51008852af2..b075e0b938e 100644 --- a/mps/test/function/60.c +++ b/mps/test/function/60.c @@ -68,11 +68,11 @@ static void test(void) mps_ap_create(&ap2, poolawl2, mps_rank_exact()), "create ap"); - for (j=1; j<100; j++) + for (j=1; j<=10; j++) { - comment("%i of 100.", j); + comment("%i of 10.", j); - for (i=1; i<10000; i++) + for (i=1; i<=1000; i++) { UC; a = allocone(ap1, 100, 1); @@ -85,6 +85,7 @@ static void test(void) DMC; } + mps_arena_park(arena); mps_ap_destroy(ap1); mps_ap_destroy(ap2); comment("Destroyed aps."); diff --git a/mps/test/function/61.c b/mps/test/function/61.c index 1d3df5e90e2..9ccd97d77de 100644 --- a/mps/test/function/61.c +++ b/mps/test/function/61.c @@ -79,6 +79,7 @@ static void test(void) DMC; } + mps_arena_park(arena); mps_ap_destroy(ap1); mps_ap_destroy(ap2); mps_pool_destroy(poolamc1); diff --git a/mps/test/function/62.c b/mps/test/function/62.c index cc99e36c7c9..1ea9ff432b3 100644 --- a/mps/test/function/62.c +++ b/mps/test/function/62.c @@ -79,6 +79,7 @@ static void test(void) DMC; } + mps_arena_park(arena); mps_ap_destroy(ap1); mps_ap_destroy(ap2); mps_pool_destroy(poolamc1); diff --git a/mps/test/function/63.c b/mps/test/function/63.c index a46c993b3f6..1e9b63693e3 100644 --- a/mps/test/function/63.c +++ b/mps/test/function/63.c @@ -73,6 +73,7 @@ static void test(void) DMC; } + mps_arena_park(arena); mps_ap_destroy(ap1); mps_pool_destroy(poolamc1); mps_chain_destroy(chain); diff --git a/mps/test/function/64.c b/mps/test/function/64.c index 7e9bb633d95..390567b7117 100644 --- a/mps/test/function/64.c +++ b/mps/test/function/64.c @@ -104,6 +104,7 @@ static void test(void) DMC; } + mps_arena_park(arena); mps_ap_destroy(apamc); mps_ap_destroy(aplo); mps_pool_destroy(poolamc); diff --git a/mps/test/function/65.c b/mps/test/function/65.c index 3300ca895ff..3305d96cd72 100644 --- a/mps/test/function/65.c +++ b/mps/test/function/65.c @@ -179,6 +179,7 @@ static void test(void) mps_arena_release(arena); comment("released."); + mps_arena_park(arena); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); mps_chain_destroy(chain); diff --git a/mps/test/function/66.c b/mps/test/function/66.c index 069a4b99358..d395dbb3637 100644 --- a/mps/test/function/66.c +++ b/mps/test/function/66.c @@ -155,6 +155,7 @@ static void test(void) { } } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); comment("Destroyed aps."); diff --git a/mps/test/function/69.c b/mps/test/function/69.c index c86abc37fe4..bbc758b7f42 100644 --- a/mps/test/function/69.c +++ b/mps/test/function/69.c @@ -94,6 +94,7 @@ static void test(void) { mps_message_discard(arena, message); + mps_arena_park(arena); mps_root_destroy(root); mps_ap_destroy(ap); mps_pool_destroy(pool); diff --git a/mps/test/function/72.c b/mps/test/function/72.c index 2eb6b178529..946844d9492 100644 --- a/mps/test/function/72.c +++ b/mps/test/function/72.c @@ -80,6 +80,7 @@ static void test(void) fail(); + mps_arena_park(arena); mps_ap_destroy(ap); comment("Destroyed ap."); diff --git a/mps/test/function/73.c b/mps/test/function/73.c index 492aa6cd919..f38e6d1847a 100644 --- a/mps/test/function/73.c +++ b/mps/test/function/73.c @@ -60,6 +60,7 @@ static void test(void) { /* (total allocated is 1000 M) */ + mps_arena_park(arena); mps_root_destroy(root0); mps_root_destroy(root1); comment("Destroyed roots."); diff --git a/mps/test/function/74.c b/mps/test/function/74.c index 40f86f09e14..58e280b544f 100644 --- a/mps/test/function/74.c +++ b/mps/test/function/74.c @@ -60,6 +60,7 @@ static void test(void) { /* (total allocated is 1000 M) */ + mps_arena_park(arena); mps_root_destroy(root0); mps_root_destroy(root1); comment("Destroyed roots."); diff --git a/mps/test/function/75.c b/mps/test/function/75.c index d6e4a38e870..859471cfbbc 100644 --- a/mps/test/function/75.c +++ b/mps/test/function/75.c @@ -69,6 +69,7 @@ static void test(void) /* (total allocated is 1000 M) */ + mps_arena_park(arena); mps_root_destroy(root0); mps_root_destroy(root1); comment("Destroyed roots."); diff --git a/mps/test/function/76.c b/mps/test/function/76.c index 89120d6aa97..72f2977f80c 100644 --- a/mps/test/function/76.c +++ b/mps/test/function/76.c @@ -121,6 +121,7 @@ static void test(void) /* now to test leaving messages open for a long time! */ + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_ap_destroy(aplo); diff --git a/mps/test/function/77.c b/mps/test/function/77.c index 7a32973ecd2..e2cae02611b 100644 --- a/mps/test/function/77.c +++ b/mps/test/function/77.c @@ -94,6 +94,7 @@ static void test(void) } } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/78.c b/mps/test/function/78.c index 75c371f7395..331c0f2b2be 100644 --- a/mps/test/function/78.c +++ b/mps/test/function/78.c @@ -97,6 +97,7 @@ static void test(void) } } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/79.c b/mps/test/function/79.c index 42163242b73..78857b4c3be 100644 --- a/mps/test/function/79.c +++ b/mps/test/function/79.c @@ -94,6 +94,7 @@ static void test(void) } } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/80.c b/mps/test/function/80.c index bdc5843fcc8..2d373206f73 100644 --- a/mps/test/function/80.c +++ b/mps/test/function/80.c @@ -94,6 +94,7 @@ static void test(void) } } + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/function/81.c b/mps/test/function/81.c index ccaad2111bb..4443612896a 100644 --- a/mps/test/function/81.c +++ b/mps/test/function/81.c @@ -78,6 +78,7 @@ static void test(void) mps_arena_collect(arena); + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/83.c b/mps/test/function/83.c index 5524e4ebd26..baad036e364 100644 --- a/mps/test/function/83.c +++ b/mps/test/function/83.c @@ -107,6 +107,7 @@ static void test(void) report("d", "%p", d); + mps_arena_park(arena); mps_ap_destroy(ap1); mps_ap_destroy(ap2); mps_pool_destroy(pool1); diff --git a/mps/test/function/9.c b/mps/test/function/9.c index 9f205a1654a..6f124f5609c 100644 --- a/mps/test/function/9.c +++ b/mps/test/function/9.c @@ -58,6 +58,7 @@ static void test(void) a = allocdumb(ap, 1024*1024*80); + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/96.c b/mps/test/function/96.c index 3ccdb838495..210fbf46542 100644 --- a/mps/test/function/96.c +++ b/mps/test/function/96.c @@ -128,6 +128,7 @@ static void test(void) mps_arena_collect(arena); } + mps_arena_park(arena); mps_ap_destroy(ap); mps_pool_destroy(pool); mps_chain_destroy(chain); diff --git a/mps/test/function/97.c b/mps/test/function/97.c index cc7f49ef433..fabbc1136ab 100644 --- a/mps/test/function/97.c +++ b/mps/test/function/97.c @@ -222,6 +222,7 @@ static void test(void) comment("ok"); } + mps_arena_park(arena); mps_ap_destroy(apamc); mps_ap_destroy(aplo); mps_ap_destroy(apawl); diff --git a/mps/test/function/99.c b/mps/test/function/99.c index d2594f1a5e7..939991c1551 100644 --- a/mps/test/function/99.c +++ b/mps/test/function/99.c @@ -94,6 +94,7 @@ static void test(void) } } + mps_arena_park(arena); mps_ap_destroy(apamcz); mps_ap_destroy(apamc); mps_pool_destroy(poolamc); diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index fc00f37feb0..b77e04ddd82 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -47,7 +47,7 @@ function/41.c function/42.c function/43.c function/44.c -function/45.c +% function/45.c -- setref: to non-data object @@@@ function/46.c function/47.c function/48.c @@ -60,7 +60,7 @@ function/55.c function/56.c function/57.c % 58-59 -- no such test -% function/60.c -- slow +function/60.c function/61.c function/62.c function/63.c @@ -87,7 +87,7 @@ function/83.c % 84-95 -- no such test function/96.c function/97.c -function/98.c +% function/98.c -- tries to exhaust memory by mps_arena_create function/99.c function/100.c function/101.c From dddc8e2e7bb9f51f570a58e98ecd039ab02ce45c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 15:58:36 +0100 Subject: [PATCH 175/266] Add instructions for running the test suite on os x. Copied from Perforce Change: 186031 ServerID: perforce.ravenbrook.com --- mps/test/test/README | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/mps/test/test/README b/mps/test/test/README index 78ac29bdbe7..f9759c09bef 100644 --- a/mps/test/test/README +++ b/mps/test/test/README @@ -5,6 +5,20 @@ perl 5 (or higher). Go "perl qa help" for help, "perl qa options" to see what version of the harness you have (or look at the file "test/version"). -Some brief instructions are in guide.mm-qa in MM Information; ask - (ext 3822) if you need help, want to complain, &c. +Running on OS X +--------------- + +On OS X you can invoke the test suite like this:: + + $ cd test + $ alias qa="perl test/qa -i ../code -l ../code/xc/mps.build/Debug/mps.build/Objects-normal/x86_64/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/Darwin_12.3.0_i386__unix/tmp_test`` so you can debug it +with:: + + $ lldb test/obj/Darwin_12.3.0_i386__unix/tmp_test From 3072f03b787c0e35a38acbbaf27445fe112fcd2f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 15:59:21 +0100 Subject: [PATCH 176/266] Improve the assertion output so that it is less suggestive of a bug in the mps and more suggestive of a problem that needs investigation. Copied from Perforce Change: 186032 ServerID: perforce.ravenbrook.com --- mps/code/mpsliban.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/mps/code/mpsliban.c b/mps/code/mpsliban.c index 75a3d48d518..5e7cfdddc8b 100644 --- a/mps/code/mpsliban.c +++ b/mps/code/mpsliban.c @@ -61,13 +61,19 @@ int mps_lib_fputs(const char *s, mps_lib_FILE *stream) } -static void mps_lib_assert_fail_default(const char *file, - unsigned line, +static void mps_lib_assert_fail_default(const char *file, unsigned line, const char *condition) { - (void)fflush(stdout); /* synchronize */ - (void)fprintf(stderr, "%s:%u: MPS ASSERTION FAILED: %s\n", file, line, condition); - (void)fflush(stderr); /* make sure the message is output */ + /* Synchronize with stdout. */ + (void)fflush(stdout); + (void)fprintf(stderr, + "The MPS detected a problem!\n" + "%s:%u: MPS ASSERTION FAILED: %s\n" + "See the \"Assertions\" section in the reference manual:\n" + "http://ravenbrook.com/project/mps/master/manual/html/topic/error.html#assertions\n", + file, line, condition); + /* Ensure the message is output even if stderr is buffered. */ + (void)fflush(stderr); ASSERT_ABORT(); /* see config.h */ } From ea61771e1ae9883a062bed40653f46f429e34210 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 17:13:00 +0100 Subject: [PATCH 177/266] Fix many mmqa test cases: * Use commit limit to test exhaustion instead of trying to exhaust virtual memory. * Use exact roots where possible so that we don't have to worry about local variables pinning down memory. * Reduce sizes and iterations so that tests complete in a reasonable amount of time. * Use "MVT" instead of "MV2". Update the list of passing test cases. Copied from Perforce Change: 186035 ServerID: perforce.ravenbrook.com --- mps/test/function/116.c | 1 + mps/test/function/130.c | 36 +++++++------------- mps/test/function/131.c | 38 +++++++-------------- mps/test/function/132.c | 4 +-- mps/test/function/133.c | 2 +- mps/test/function/149.c | 4 +-- mps/test/function/18.c | 3 +- mps/test/function/19.c | 3 +- mps/test/function/20.c | 3 +- mps/test/function/203.c | 69 +++++++++++++++++++-------------------- mps/test/function/204.c | 67 ++++++++++++++++++------------------- mps/test/function/205.c | 67 ++++++++++++++++++------------------- mps/test/function/214.c | 18 ++++------ mps/test/function/223.c | 15 ++++----- mps/test/function/224.c | 8 +++-- mps/test/function/77.c | 4 +-- mps/test/testsets/passing | 32 +++++++++--------- 17 files changed, 169 insertions(+), 205 deletions(-) diff --git a/mps/test/function/116.c b/mps/test/function/116.c index d843e2b4691..8c87bae4458 100644 --- a/mps/test/function/116.c +++ b/mps/test/function/116.c @@ -42,6 +42,7 @@ static void test(void) cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*30)), "create arena"); + die(mps_arena_commit_limit_set(arena, 1ul << 20), "commit_limit_set"); cdie(mps_thread_reg(&thread, arena), "register thread"); diff --git a/mps/test/function/130.c b/mps/test/function/130.c index 4809d7bc74e..f871d5944f8 100644 --- a/mps/test/function/130.c +++ b/mps/test/function/130.c @@ -19,8 +19,6 @@ static mps_gen_param_s testChain[genCOUNT] = { { 6000, 0.90 }, { 8000, 0.65 }, { 16000, 0.50 } }; -void *stackpointer; - mps_pool_t poolmv; mps_arena_t arena; @@ -28,28 +26,18 @@ mps_arena_t arena; static void test(void) { mps_pool_t pool; - mps_thr_t thread; - mps_root_t root; - mps_fmt_t format; mps_chain_t chain; mps_ap_t ap, ap2; - - mycell *a, *b; - + mycell *a[2]; mps_res_t res; int i; /* create an arena that can't grow beyond 30 M */ cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*30)), "create arena"); - mps_arena_commit_limit_set(arena, (size_t) (1024*1024*40)); - - 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 root"); + die(mps_arena_commit_limit_set(arena, 1u << 20), "commit_limit_set"); cdie(mps_fmt_create_A(&format, arena, &fmtA), "create format"); @@ -64,12 +52,14 @@ static void test(void) /* allocate until full */ i = 0; - b = NULL; + a[0] = a[1] = NULL; + cdie(mps_root_create_table(&root, arena, mps_rank_ambig(), 0, (void *)&a, 2), + "create root"); - while (allocrone(&a, ap, 128, mps_rank_exact()) == MPS_RES_OK) { + while (allocrone(&a[0], ap, 128, mps_rank_exact()) == MPS_RES_OK) { i++; - setref(a, 0, b); - b = a; + setref(a[0], 0, a[1]); + a[1] = a[0]; } comment("%d objs allocated.", i); @@ -81,7 +71,7 @@ static void test(void) mps_ap_destroy(ap); for (i = 0; i < 10; i++) { - res = allocrone(&a, ap2, 128, mps_rank_exact()); + res = allocrone(&a[0], ap2, 128, mps_rank_exact()); report("predie", "%s", err_text(res)); } @@ -90,18 +80,17 @@ static void test(void) mps_root_destroy(root); for (i = 0; i < 10; i++) { - res = allocrone(&a, ap2, 128, mps_rank_exact()); + res = allocrone(&a[0], ap2, 128, mps_rank_exact()); report("postdie", "%s", err_text(res)); } - die(allocrone(&a, ap2, 128, mps_rank_exact()), "alloc failed"); + die(allocrone(&a[0], ap2, 128, mps_rank_exact()), "alloc failed"); mps_arena_park(arena); mps_ap_destroy(ap2); mps_pool_destroy(pool); mps_chain_destroy(chain); mps_fmt_destroy(format); - mps_thread_dereg(thread); mps_arena_destroy(arena); comment("Destroyed arena."); } @@ -109,9 +98,6 @@ static void test(void) int main(void) { - void *m; - stackpointer=&m; /* hack to get stack pointer */ - easy_tramp(test); pass(); return 0; diff --git a/mps/test/function/131.c b/mps/test/function/131.c index 06495ced080..0b0ae7be024 100644 --- a/mps/test/function/131.c +++ b/mps/test/function/131.c @@ -24,8 +24,6 @@ static mps_gen_param_s testChain[genCOUNT] = { { 6000, 0.90 }, { 8000, 0.65 }, { 16000, 0.50 } }; -void *stackpointer; - mps_pool_t poolmv; mps_arena_t arena; @@ -33,28 +31,18 @@ mps_arena_t arena; static void test(void) { mps_pool_t pool; - mps_thr_t thread; - mps_root_t root; - mps_fmt_t format; mps_chain_t chain; mps_ap_t ap, ap2; - - mycell *a, *b; - + mycell *a[2]; mps_res_t res; int i; - /* create an arena that can't grow beyond 30 M */ - cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*40)), + /* create an arena that can't grow beyond 1 M */ + cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*4)), "create arena"); - mps_arena_commit_limit_set(arena, (size_t) (1024*1024*30)); - - 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 root"); + mps_arena_commit_limit_set(arena, (size_t) (1024*1024*1)); cdie( mps_fmt_create_A(&format, arena, &fmtA), @@ -71,12 +59,14 @@ static void test(void) /* allocate until full */ i = 0; - b = NULL; + a[0] = a[1] = NULL; + cdie(mps_root_create_table(&root, arena, mps_rank_ambig(), 0, (void *)&a, 2), + "create root"); - while (allocrone(&a, ap, 128, mps_rank_exact()) == MPS_RES_OK) { + while (allocrone(&a[0], ap, 128, mps_rank_exact()) == MPS_RES_OK) { i++; - setref(a, 0, b); - b = a; + setref(a[0], 0, a[1]); + a[1] = a[0]; } comment("%d objs allocated.", i); @@ -88,7 +78,7 @@ static void test(void) mps_ap_destroy(ap); for (i = 0; i < 10; i++) { - res = allocrone(&a, ap2, 128, mps_rank_exact()); + res = allocrone(&a[0], ap2, 128, mps_rank_exact()); report("predie", "%s", err_text(res)); } @@ -97,7 +87,7 @@ static void test(void) mps_root_destroy(root); for (i = 0; i < 10; i++) { - res = allocrone(&a, ap2, 128, mps_rank_exact()); + res = allocrone(&a[0], ap2, 128, mps_rank_exact()); report("postdie", "%s", err_text(res)); } @@ -106,7 +96,6 @@ static void test(void) mps_pool_destroy(pool); mps_chain_destroy(chain); mps_fmt_destroy(format); - mps_thread_dereg(thread); mps_arena_destroy(arena); comment("Destroyed arena."); } @@ -114,9 +103,6 @@ static void test(void) int main(void) { - void *m; - stackpointer=&m; /* hack to get stack pointer */ - easy_tramp(test); pass(); return 0; diff --git a/mps/test/function/132.c b/mps/test/function/132.c index b617427cdfa..b69e6cbcecf 100644 --- a/mps/test/function/132.c +++ b/mps/test/function/132.c @@ -23,8 +23,8 @@ OUTPUT_SPEC spill5 <= 0 grow5 = 0 avail5 > 1500000 - allocfail2 > 10000 - failres2 = MEMORY + allocfail2 > 5000 + failres2 = COMMIT_LIMIT shrink6 > 1000000 spill6 <= 0 completed = yes diff --git a/mps/test/function/133.c b/mps/test/function/133.c index d0ca1297af6..1f717b11660 100644 --- a/mps/test/function/133.c +++ b/mps/test/function/133.c @@ -5,7 +5,7 @@ TEST_HEADER language = c link = testlib.o rankfmt.o OUTPUT_SPEC - allocfail3 > 8000 + allocfail3 > 3000 failres3 = COMMIT_LIMIT spill8 <= 0 spill9 <= 0 diff --git a/mps/test/function/149.c b/mps/test/function/149.c index 0792068fd28..a26f510ebdc 100644 --- a/mps/test/function/149.c +++ b/mps/test/function/149.c @@ -23,8 +23,8 @@ OUTPUT_SPEC spill5 <= 0 grow5 = 0 avail5 > 1500000 - allocfail2 > 10000 - failres2 = MEMORY + allocfail2 > 5000 + failres2 = COMMIT_LIMIT shrink6 > 1000000 spill6 <= 0 completed = yes diff --git a/mps/test/function/18.c b/mps/test/function/18.c index 21f2c38e696..60a17e52d57 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: MEMORY + errtext = create pool: COMMIT_LIMIT END_HEADER */ @@ -39,6 +39,7 @@ static void test(void) cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); + die(mps_arena_commit_limit_set(arena, 1ul << 30), "commit_limit_set"); die(mps_thread_reg(&thread, arena), "register thread"); die(mps_root_create_reg(&root, arena, mps_rank_ambig(), 0, thread, mps_stack_scan_ambig, stackpointer, 0), diff --git a/mps/test/function/19.c b/mps/test/function/19.c index 7727f45310b..bdbe02f88f8 100644 --- a/mps/test/function/19.c +++ b/mps/test/function/19.c @@ -5,7 +5,7 @@ TEST_HEADER language = c link = testlib.o newfmt.o OUTPUT_SPEC - errtext = create ap: MEMORY + errtext = create ap: COMMIT_LIMIT END_HEADER */ @@ -40,6 +40,7 @@ static void test(void) cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); + die(mps_arena_commit_limit_set(arena, 1ul << 30), "commit_limit_set"); die(mps_thread_reg(&thread, arena), "register thread"); die(mps_root_create_reg(&root, arena, mps_rank_ambig(), 0, thread, mps_stack_scan_ambig, stackpointer, 0), diff --git a/mps/test/function/20.c b/mps/test/function/20.c index 5a95e314397..b66f96d4e67 100644 --- a/mps/test/function/20.c +++ b/mps/test/function/20.c @@ -5,7 +5,7 @@ TEST_HEADER language = c link = testlib.o newfmt.o OUTPUT_SPEC - errtext = create format: MEMORY + errtext = create format: COMMIT_LIMIT END_HEADER */ @@ -27,6 +27,7 @@ static void test(void) { int p; die(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create"); + die(mps_arena_commit_limit_set(arena, 1ul << 30), "commit_limit_set"); die(mps_thread_reg(&thread, arena), "register thread"); die(mps_root_create_reg(&root, arena, mps_rank_ambig(), 0, thread, mps_stack_scan_ambig, stackpointer, 0), "create root"); diff --git a/mps/test/function/203.c b/mps/test/function/203.c index bd3cf8d92e2..207937d1d35 100644 --- a/mps/test/function/203.c +++ b/mps/test/function/203.c @@ -1,7 +1,7 @@ /* TEST_HEADER id = $Id$ - summary = new MV2 allocation test + summary = new MVT allocation test language = c link = testlib.o END_HEADER @@ -9,14 +9,10 @@ END_HEADER #include #include "testlib.h" -#include "mpscmv2.h" +#include "mpscmvt.h" #include "mpsavm.h" -#define MAXNUMBER 1000000 - -/* this shouldn't be necessary, but it's not provided anywhere */ - -typedef MPS_T_WORD mps_count_t; +#define MAXNUMBER 100000 void *stackpointer; mps_arena_t arena; @@ -42,7 +38,7 @@ static void setobj(mps_addr_t a, size_t size, unsigned char val) } } -static mps_res_t mv2_alloc(mps_addr_t *ref, mps_ap_t ap, size_t size) { +static mps_res_t mvt_alloc(mps_addr_t *ref, mps_ap_t ap, size_t size) { mps_res_t res; size = ((size+7)/8)*8; @@ -73,7 +69,7 @@ static int chkobj(mps_addr_t a, size_t size, unsigned char val) static void dt(int kind, size_t minSize, size_t avgSize, size_t maxSize, - mps_count_t depth, mps_count_t fragLimit, + mps_word_t depth, mps_word_t fragLimit, size_t mins, size_t maxs, int number, int iter) { mps_pool_t pool; @@ -89,9 +85,9 @@ static void dt(int kind, asserts(time0 != -1, "processor time not available"); die( - mps_pool_create(&pool, arena, mps_class_mv2(), + mps_pool_create(&pool, arena, mps_class_mvt(), minSize, avgSize, maxSize, depth, fragLimit), - "create MV2 pool"); + "create MVT pool"); die(mps_ap_create(&ap, pool, mps_rank_ambig()), "create ap"); @@ -104,7 +100,7 @@ static void dt(int kind, } else { - die(mv2_alloc(&queue[hd].addr, ap, size), "alloc"); + die(mvt_alloc(&queue[hd].addr, ap, size), "alloc"); setobj(queue[hd].addr, size, (unsigned char) (hd%256)); queue[hd].size = size; } @@ -136,12 +132,13 @@ static void dt(int kind, } else { - die(mv2_alloc(&queue[hd].addr, ap, size),"alloc"); + die(mvt_alloc(&queue[hd].addr, ap, size),"alloc"); setobj(queue[hd].addr, size, (unsigned char) (hd%256)); queue[hd].size = size; } } + mps_ap_destroy(ap); mps_pool_destroy(pool); time1=clock(); @@ -157,7 +154,7 @@ static void test(void) { mps_thr_t thread; size_t mins; - mps_count_t dep, frag; + mps_word_t dep, frag; cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*100)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); @@ -170,34 +167,34 @@ static void test(void) comment("Frag: %i", frag); - dt(SEQ, 8, 8, 9, dep, frag, 8, 9, 5, 1000); - dt(RANGAP, 64, 64, 64, dep, frag, 8, 128, 100, 100000); + dt(SEQ, 8, 8, 9, dep, frag, 8, 9, 5, 100); + dt(RANGAP, 64, 64, 64, dep, frag, 8, 128, 100, 10000); - dt(DUMMY, 8, 32, 64, dep, frag, 8, 64, 1000, 1000000); - dt(SEQ, 8, 32, 64, dep, frag, 8, 64, 1000, 1000000); - dt(RAN, 8, 32, 64, dep, frag, 8, 64, 1000, 1000000); - dt(SEQGAP, 8, 32, 64, dep, frag, 8, 64, 1000, 1000000); - dt(RANGAP, 8, 32, 64, dep, frag, 8, 64, 1000, 1000000); + 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, 100, 116, 132, dep, frag, 100, 132, 1000, 1000000); - dt(SEQ, 100, 116, 132, dep, frag, 100, 132, 1000, 1000000); - dt(RAN, 100, 116, 132, dep, frag, 100, 132, 1000, 1000000); - dt(SEQGAP, 100, 116, 132, dep, frag, 100, 132, 1000, 1000000); - dt(RANGAP, 100, 116, 132, dep, frag, 100, 132, 1000, 1000000); + 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, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(SEQ, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(RAN, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(SEQGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(RANGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 10000); + 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); /* try again using exceptional obj for anything over 16K */ - dt(DUMMY, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(SEQ, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(RAN, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(SEQGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(RANGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 10000); + 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); } diff --git a/mps/test/function/204.c b/mps/test/function/204.c index 73e40029dff..d1a00731086 100644 --- a/mps/test/function/204.c +++ b/mps/test/function/204.c @@ -1,7 +1,7 @@ /* TEST_HEADER id = $Id$ - summary = new MV2 allocation test, extra shallow + summary = new MVT allocation test, extra shallow language = c link = testlib.o END_HEADER @@ -9,15 +9,11 @@ END_HEADER #include #include "testlib.h" -#include "mpscmv2.h" +#include "mpscmvt.h" #include "mpsavm.h" #define MAXNUMBER 1000000 -/* this shouldn't be necessary, but it's not provided anywhere */ - -typedef MPS_T_WORD mps_count_t; - void *stackpointer; mps_arena_t arena; @@ -42,7 +38,7 @@ static void setobj(mps_addr_t a, size_t size, unsigned char val) } } -static mps_res_t mv2_alloc(mps_addr_t *ref, mps_ap_t ap, size_t size) { +static mps_res_t mvt_alloc(mps_addr_t *ref, mps_ap_t ap, size_t size) { mps_res_t res; size = ((size+7)/8)*8; @@ -73,7 +69,7 @@ static int chkobj(mps_addr_t a, size_t size, unsigned char val) static void dt(int kind, size_t minSize, size_t avgSize, size_t maxSize, - mps_count_t depth, mps_count_t fragLimit, + mps_word_t depth, mps_word_t fragLimit, size_t mins, size_t maxs, int number, int iter) { mps_pool_t pool; @@ -89,9 +85,9 @@ static void dt(int kind, asserts(time0 != -1, "processor time not available"); die( - mps_pool_create(&pool, arena, mps_class_mv2(), + mps_pool_create(&pool, arena, mps_class_mvt(), minSize, avgSize, maxSize, depth, fragLimit), - "create MV2 pool"); + "create MVT pool"); die(mps_ap_create(&ap, pool, mps_rank_ambig()), "create ap"); @@ -104,7 +100,7 @@ static void dt(int kind, } else { - die(mv2_alloc(&queue[hd].addr, ap, size), "alloc"); + die(mvt_alloc(&queue[hd].addr, ap, size), "alloc"); setobj(queue[hd].addr, size, (unsigned char) (hd%256)); queue[hd].size = size; } @@ -136,12 +132,13 @@ static void dt(int kind, } else { - die(mv2_alloc(&queue[hd].addr, ap, size),"alloc"); + die(mvt_alloc(&queue[hd].addr, ap, size),"alloc"); setobj(queue[hd].addr, size, (unsigned char) (hd%256)); queue[hd].size = size; } } + mps_ap_destroy(ap); mps_pool_destroy(pool); time1=clock(); @@ -157,7 +154,7 @@ static void test(void) { mps_thr_t thread; size_t mins; - mps_count_t dep, frag; + mps_word_t dep, frag; cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*100)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); @@ -170,34 +167,34 @@ static void test(void) comment("Frag: %i", frag); - dt(SEQ, 8, 8, 9, dep, frag, 8, 9, 5, 1000); - dt(RANGAP, 64, 64, 64, dep, frag, 8, 128, 100, 100000); + dt(SEQ, 8, 8, 9, dep, frag, 8, 9, 5, 100); + dt(RANGAP, 64, 64, 64, dep, frag, 8, 128, 100, 10000); - dt(DUMMY, 8, 32, 64, dep, frag, 8, 64, 1000, 1000000); - dt(SEQ, 8, 32, 64, dep, frag, 8, 64, 1000, 1000000); - dt(RAN, 8, 32, 64, dep, frag, 8, 64, 1000, 1000000); - dt(SEQGAP, 8, 32, 64, dep, frag, 8, 64, 1000, 1000000); - dt(RANGAP, 8, 32, 64, dep, frag, 8, 64, 1000, 1000000); + 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, 100, 116, 132, dep, frag, 100, 132, 1000, 1000000); - dt(SEQ, 100, 116, 132, dep, frag, 100, 132, 1000, 1000000); - dt(RAN, 100, 116, 132, dep, frag, 100, 132, 1000, 1000000); - dt(SEQGAP, 100, 116, 132, dep, frag, 100, 132, 1000, 1000000); - dt(RANGAP, 100, 116, 132, dep, frag, 100, 132, 1000, 1000000); + 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, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(SEQ, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(RAN, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(SEQGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(RANGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 10000); + 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); /* try again using exceptional obj for anything over 16K */ - dt(DUMMY, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(SEQ, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(RAN, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(SEQGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(RANGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 10000); + 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); } diff --git a/mps/test/function/205.c b/mps/test/function/205.c index e7b4e7c812d..d067d6a5ada 100644 --- a/mps/test/function/205.c +++ b/mps/test/function/205.c @@ -1,7 +1,7 @@ /* TEST_HEADER id = $Id$ - summary = new MV2 allocation test, extra deep + summary = new MVT allocation test, extra deep language = c link = testlib.o END_HEADER @@ -9,15 +9,11 @@ END_HEADER #include #include "testlib.h" -#include "mpscmv2.h" +#include "mpscmvt.h" #include "mpsavm.h" #define MAXNUMBER 1000000 -/* this shouldn't be necessary, but it's not provided anywhere */ - -typedef MPS_T_WORD mps_count_t; - void *stackpointer; mps_arena_t arena; @@ -42,7 +38,7 @@ static void setobj(mps_addr_t a, size_t size, unsigned char val) } } -static mps_res_t mv2_alloc(mps_addr_t *ref, mps_ap_t ap, size_t size) { +static mps_res_t mvt_alloc(mps_addr_t *ref, mps_ap_t ap, size_t size) { mps_res_t res; size = ((size+7)/8)*8; @@ -73,7 +69,7 @@ static int chkobj(mps_addr_t a, size_t size, unsigned char val) static void dt(int kind, size_t minSize, size_t avgSize, size_t maxSize, - mps_count_t depth, mps_count_t fragLimit, + mps_word_t depth, mps_word_t fragLimit, size_t mins, size_t maxs, int number, int iter) { mps_pool_t pool; @@ -89,9 +85,9 @@ static void dt(int kind, asserts(time0 != -1, "processor time not available"); die( - mps_pool_create(&pool, arena, mps_class_mv2(), + mps_pool_create(&pool, arena, mps_class_mvt(), minSize, avgSize, maxSize, depth, fragLimit), - "create MV2 pool"); + "create MVT pool"); die(mps_ap_create(&ap, pool, mps_rank_ambig()), "create ap"); @@ -104,7 +100,7 @@ static void dt(int kind, } else { - die(mv2_alloc(&queue[hd].addr, ap, size), "alloc"); + die(mvt_alloc(&queue[hd].addr, ap, size), "alloc"); setobj(queue[hd].addr, size, (unsigned char) (hd%256)); queue[hd].size = size; } @@ -136,12 +132,13 @@ static void dt(int kind, } else { - die(mv2_alloc(&queue[hd].addr, ap, size),"alloc"); + die(mvt_alloc(&queue[hd].addr, ap, size),"alloc"); setobj(queue[hd].addr, size, (unsigned char) (hd%256)); queue[hd].size = size; } } + mps_ap_destroy(ap); mps_pool_destroy(pool); time1=clock(); @@ -157,7 +154,7 @@ static void test(void) { mps_thr_t thread; size_t mins; - mps_count_t dep, frag; + mps_word_t dep, frag; cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*100)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); @@ -170,34 +167,34 @@ static void test(void) comment("Frag: %i", frag); - dt(SEQ, 8, 8, 9, dep, frag, 8, 9, 5, 1000); - dt(RANGAP, 64, 64, 64, dep, frag, 8, 128, 100, 100000); + dt(SEQ, 8, 8, 9, dep, frag, 8, 9, 5, 100); + dt(RANGAP, 64, 64, 64, dep, frag, 8, 128, 100, 10000); - dt(DUMMY, 8, 32, 64, dep, frag, 8, 64, 1000, 1000000); - dt(SEQ, 8, 32, 64, dep, frag, 8, 64, 1000, 1000000); - dt(RAN, 8, 32, 64, dep, frag, 8, 64, 1000, 1000000); - dt(SEQGAP, 8, 32, 64, dep, frag, 8, 64, 1000, 1000000); - dt(RANGAP, 8, 32, 64, dep, frag, 8, 64, 1000, 1000000); + 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, 100, 116, 132, dep, frag, 100, 132, 1000, 1000000); - dt(SEQ, 100, 116, 132, dep, frag, 100, 132, 1000, 1000000); - dt(RAN, 100, 116, 132, dep, frag, 100, 132, 1000, 1000000); - dt(SEQGAP, 100, 116, 132, dep, frag, 100, 132, 1000, 1000000); - dt(RANGAP, 100, 116, 132, dep, frag, 100, 132, 1000, 1000000); + 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, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(SEQ, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(RAN, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(SEQGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(RANGAP, mins, 60*1024, 120*1024, dep, frag, mins, 128*1024, 100, 10000); + 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); /* try again using exceptional obj for anything over 16K */ - dt(DUMMY, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(SEQ, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(RAN, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(SEQGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 10000); - dt(RANGAP, mins, 8*1024, 16*1024, dep, frag, mins, 128*1024, 100, 10000); + 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); } diff --git a/mps/test/function/214.c b/mps/test/function/214.c index d84e4b71be4..81fe5c5cfe6 100644 --- a/mps/test/function/214.c +++ b/mps/test/function/214.c @@ -1,7 +1,7 @@ /* TEST_HEADER id = $Id$ - summary = MV2 greed test + summary = MVT greed test language = c link = testlib.o parameters = OBJECTS=1000 OBJSIZE=8192 DEPTH=2 FRAGLIMIT=50 @@ -9,19 +9,15 @@ END_HEADER */ #include "testlib.h" -#include "mpscmv2.h" +#include "mpscmvt.h" #include "mpsavm.h" -/* this shouldn't be necessary, but it's not provided anywhere */ - -typedef MPS_T_WORD mps_count_t; - void *stackpointer; mps_arena_t arena; static mps_addr_t objs[OBJECTS]; -static mps_res_t mv2_alloc(mps_addr_t *ref, mps_ap_t ap, size_t size) { +static mps_res_t mvt_alloc(mps_addr_t *ref, mps_ap_t ap, size_t size) { mps_res_t res; size = ((size+7)/8)*8; @@ -43,20 +39,20 @@ static void test (void) { cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*100)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); die( - mps_pool_create(&pool, arena, mps_class_mv2(), + mps_pool_create(&pool, arena, mps_class_mvt(), OBJSIZE, OBJSIZE, OBJSIZE, DEPTH, FRAGLIMIT), - "create MV2 pool"); + "create MVT pool"); die(mps_ap_create(&ap, pool, mps_rank_ambig()), "create ap"); for (i = 0; i < OBJECTS; i++) { - die(mv2_alloc(&objs[i], ap, OBJSIZE), "alloc"); + die(mvt_alloc(&objs[i], ap, OBJSIZE), "alloc"); } report("size1", "%ld", mps_arena_committed(arena)); for (i = 0; i < OBJECTS; i+=2) { mps_free(pool, objs[i], OBJSIZE); - die(mv2_alloc(&objs[i], ap, OBJSIZE), "alloc"); + die(mvt_alloc(&objs[i], ap, OBJSIZE), "alloc"); } report("size2", "%ld", mps_arena_committed(arena)); diff --git a/mps/test/function/223.c b/mps/test/function/223.c index 7418a356518..6a402d1c831 100644 --- a/mps/test/function/223.c +++ b/mps/test/function/223.c @@ -24,7 +24,7 @@ END_HEADER #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (1000000ul) +#define ITERATIONS (100000ul) #define RAMP_INTERFACE /* @@ -97,7 +97,7 @@ static void test(void) { mps_ap_create(&apamc, poolamc, mps_rank_exact()), "create ap"); - mps_message_type_enable(arena, mps_message_type_collection_stats()); + mps_message_type_enable(arena, mps_message_type_gc()); inramp = 0; @@ -138,14 +138,13 @@ static void test(void) { rsize = 0; } } - if(mps_message_get(&message, arena, mps_message_type_collection_stats())) { + if(mps_message_get(&message, arena, mps_message_type_gc())) { unsigned long live, condemned, notCondemned; - live = mps_message_collection_stats_live_size(arena, message); - condemned = mps_message_collection_stats_condemned_size(arena, message); - notCondemned = - mps_message_collection_stats_not_condemned_size(arena, message); + live = mps_message_gc_live_size(arena, message); + condemned = mps_message_gc_condemned_size(arena, message); + notCondemned = mps_message_gc_not_condemned_size(arena, message); comment("Collection: live=%ld, condemned=%ld, not condemned = %ld", - live, condemned, notCondemned); + live, condemned, notCondemned); mps_message_discard(arena, message); } } diff --git a/mps/test/function/224.c b/mps/test/function/224.c index cd648209bfc..0cec33e1cd8 100644 --- a/mps/test/function/224.c +++ b/mps/test/function/224.c @@ -6,6 +6,8 @@ TEST_HEADER link = testlib.o harness = 2.5 parameters = EXTENDBY=65536 AVGSIZE=32 PROMISE=64 ITERATE=2000 +OUTPUT_SPEC + errtext = alloc: COMMIT_LIMIT END_HEADER This one is supposed to fail, telling us that MV is badly fragmented. @@ -16,7 +18,7 @@ This one is supposed to fail, telling us that MV is badly fragmented. #include "mpsavm.h" -#define VMNZSIZE ((size_t) 30*1024*1024) +#define VMSIZE ((size_t) 30*1024*1024) static void test(void) @@ -26,8 +28,8 @@ static void test(void) mps_addr_t q; int p; - die(mps_arena_create(&arena, mps_arena_class_vmnz(), VMNZSIZE), "create"); - die(mps_arena_commit_limit_set(arena, VMNZSIZE), "commit limit"); + die(mps_arena_create(&arena, mps_arena_class_vm(), VMSIZE), "create"); + die(mps_arena_commit_limit_set(arena, VMSIZE), "commit limit"); die(mps_pool_create(&pool, arena, mps_class_mv(), EXTENDBY, AVGSIZE, EXTENDBY), diff --git a/mps/test/function/77.c b/mps/test/function/77.c index e2cae02611b..f57ea4bc2f6 100644 --- a/mps/test/function/77.c +++ b/mps/test/function/77.c @@ -69,8 +69,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<=10; j++) { + comment("%i of 10.", j); a = allocone(apamc, 5, mps_rank_exact()); b = a; c = a; diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index b77e04ddd82..4b0a0cbe1b5 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -20,9 +20,9 @@ function/14.c function/15.c function/16.c function/17.c -% function/18.c -- tries to exhaust memory by mps_alloc -% function/19.c -- tries to exhaust memory by mps_alloc -% function/20.c -- tries to exhaust memory by mps_alloc +function/18.c +function/19.c +function/20.c function/21.c function/22.c % function/23.c -- interactive test, can't run unattended @@ -77,7 +77,7 @@ function/73.c function/74.c function/75.c function/76.c -% function/77.c -- slow +function/77.c function/78.c function/79.c function/80.c @@ -104,7 +104,7 @@ function/112.c function/113.c function/114.c % 115 -- no such test -% function/116.c -- tries to exhaust memory by mps_alloc +function/116.c function/117.c function/118.c function/119.c @@ -118,10 +118,10 @@ function/126.c function/127.c function/128.c function/129.c -% function/130.c -- tries to exhaust memory by mps_alloc -% function/131.c -- tries to exhaust memory by mps_alloc -% function/132.c -- failed on allocfail2: wanted > 10000, was 6840 @@@@ -% function/133.c -- failed on allocfail3: wanted > 8000, was 3060 @@@@ +% function/130.c -- job003789 +% function/131.c -- job003789 +function/132.c +function/133.c function/134.c function/135.c function/136.c @@ -134,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 -- failed on allocfail2: wanted > 10000, was 6858 @@@@ +function/149.c function/150.c function/151.c function/152.c @@ -155,15 +155,15 @@ function/167.c % function/171.c -- job003495 function/200.c % 201-202 -- no such test -% function/203.c -- requires mps_count_t and mps_class_mv2 -% function/204.c -- requires mps_count_t and mps_class_mv2 -% function/205.c -- requires mps_count_t and mps_class_mv2 +function/203.c +function/204.c +function/205.c function/206.c function/207.c % 208-213 -- no such test -% function/214.c -- requires mps_count_t and mps_class_mv2 +function/214.c function/215.c -% function/223.c -- requires mps_message_type_collection_stats -% function/224.c -- COMMIT_LIMIT @@@@ +function/223.c +function/224.c % 225 -- no such test function/226.c From 9836b47c70428db42a213942fd1396b219e74c3d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 18:22:40 +0100 Subject: [PATCH 178/266] Fix problems identified in nb's review . Copied from Perforce Change: 186038 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 12 ++++----- mps/code/anangc.gmk | 66 +++++++++++++++++++++++++++++++++++++++++++++ mps/code/ananll.gmk | 66 +++++++++++++++++++++++++++++++++++++++++++++ mps/code/gc.gmk | 2 +- mps/code/ll.gmk | 2 +- mps/code/seg.c | 20 +++++--------- mps/configure | 52 +++++++++++++++++++++++------------ mps/configure.ac | 32 ++++++++++++++++------ 8 files changed, 205 insertions(+), 47 deletions(-) create mode 100644 mps/code/anangc.gmk create mode 100644 mps/code/ananll.gmk diff --git a/mps/Makefile.in b/mps/Makefile.in index aaab5a677f2..37d1d96fb07 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -13,7 +13,10 @@ INSTALL=@INSTALL@ INSTALL_DATA=@INSTALL_DATA@ INSTALL_PROGRAM=@INSTALL_PROGRAM@ MAKE=@MAKE@ -MPS_TARGET_NAME=@MPS_TARGET_NAME@ +MPS_OS_NAME=@MPS_OS_NAME@ +MPS_ARCH_NAME=@MPS_ARCH_NAME@ +MPS_BUILD_NAME=@MPS_BUILD_NAME@ +MPS_TARGET_NAME=$(MPS_OS_NAME)$(MPS_ARCH_NAME)$(MPS_BUILD_NAME) EXTRA_TARGETS=@EXTRA_TARGETS@ prefix=$(DESTDIR)@prefix@ TARGET_OPTS=-C code -f $(MPS_TARGET_NAME).gmk EXTRA_TARGETS="$(EXTRA_TARGETS)" @@ -68,12 +71,9 @@ make-install-dirs: install: @INSTALL_TARGET@ test-make-build: - $(MAKE) clean $(MAKE) $(TARGET_OPTS) testci - $(MAKE) clean - $(MAKE) $(TARGET_OPTS) VARIETY=cool CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE" testansi - $(MAKE) clean - $(MAKE) $(TARGET_OPTS) VARIETY=cool CFLAGS="-DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE -DCONFIG_POLL_NONE" testpoll + $(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 test-xcode-build: $(XCODEBUILD) -config Release -target testci diff --git a/mps/code/anangc.gmk b/mps/code/anangc.gmk new file mode 100644 index 00000000000..7ebccd8b72e --- /dev/null +++ b/mps/code/anangc.gmk @@ -0,0 +1,66 @@ +# -*- makefile -*- +# +# anangc.gmk: BUILD FOR ANSI/ANSI/GCC PLATFORM +# +# $Id$ +# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + +PFM = anangc + +MPMPF = \ + lockan.c \ + prmcan.c \ + protan.c \ + span.c \ + ssan.c \ + than.c \ + vman.c + +LIBS = -lm + +include gc.gmk + +CFLAGSCOMPILER += -DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE + +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/ananll.gmk b/mps/code/ananll.gmk new file mode 100644 index 00000000000..cdfda39b300 --- /dev/null +++ b/mps/code/ananll.gmk @@ -0,0 +1,66 @@ +# -*- makefile -*- +# +# ananll.gmk: BUILD FOR ANSI/ANSI/Clang PLATFORM +# +# $Id$ +# Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + +PFM = ananll + +MPMPF = \ + lockan.c \ + prmcan.c \ + protan.c \ + span.c \ + ssan.c \ + than.c \ + vman.c + +LIBS = -lm + +include ll.gmk + +CFLAGSCOMPILER += -DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE + +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/gc.gmk b/mps/code/gc.gmk index 826cb0ef659..76716dc0785 100644 --- a/mps/code/gc.gmk +++ b/mps/code/gc.gmk @@ -41,7 +41,7 @@ CFLAGSCOMPILERLAX := # If interrupted, this is liable to leave a zero-length file behind. define gendep - $(SHELL) -ec "$(CC) $(CFLAGS) -MM $< | \ + $(SHELL) -ec "$(CC) $(CFLAGSSTRICT) -MM $< | \ sed '/:/s!$*.o!$(@D)/& $(@D)/$*.d!' > $@" [ -s $@ ] || rm -f $@ endef diff --git a/mps/code/ll.gmk b/mps/code/ll.gmk index 55e4b6cff5d..787380fb3ed 100644 --- a/mps/code/ll.gmk +++ b/mps/code/ll.gmk @@ -46,7 +46,7 @@ CFLAGSCOMPILERLAX := # If interrupted, this is liable to leave a zero-length file behind. define gendep - $(SHELL) -ec "$(CC) $(CFLAGS) -MM $< | \ + $(SHELL) -ec "$(CC) $(CFLAGSSTRICT) -MM $< | \ sed '/:/s!$*.o!$(@D)/& $(@D)/$*.d!' > $@" [ -s $@ ] || rm -f $@ endef diff --git a/mps/code/seg.c b/mps/code/seg.c index cfa224a8368..742423383e3 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -309,16 +309,11 @@ void SegSetSummary(Seg seg, RefSet summary) AVERT(Seg, seg); AVER(summary == RefSetEMPTY || SegRankSet(seg) != RankSetEMPTY); -#if defined(REMEMBERED_SET) - /* Nothing to do. */ -#elif defined(REMEMBERED_SET_NONE) +#if defined(REMEMBERED_SET_NONE) /* Without protection, we can't maintain the remembered set because - there are writes we don't know about. TODO: rethink this when - implementating control. */ + there are writes we don't know about. */ summary = RefSetUNIV; -#else -#error "No remembered set configuration." -#endif /* REMEMBERED_SET */ +#endif if (summary != SegSummary(seg)) seg->class->setSummary(seg, summary); @@ -332,15 +327,12 @@ void SegSetRankAndSummary(Seg seg, RankSet rankSet, RefSet summary) AVERT(Seg, seg); AVERT(RankSet, rankSet); -#if defined(REMEMBERED_SET) - /* Nothing to do. */ -#elif defined(REMEMBERED_SET_NONE) +#if defined(REMEMBERED_SET_NONE) if (rankSet != RankSetEMPTY) { summary = RefSetUNIV; } -#else -#error "No remembered set configuration." -#endif /* REMEMBERED_SET */ +#endif + seg->class->setRankSummary(seg, rankSet, summary); } diff --git a/mps/configure b/mps/configure index e491a01208f..edbc7320304 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.113.0. +# Generated by GNU Autoconf 2.69 for Memory Pool System Kit release/1.114.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.113.0' -PACKAGE_STRING='Memory Pool System Kit release/1.113.0' +PACKAGE_VERSION='release/1.114.0' +PACKAGE_STRING='Memory Pool System Kit release/1.114.0' PACKAGE_BUGREPORT='mps-questions@ravenbrook.com' PACKAGE_URL='http://www.ravenbrook.com/project/mps/' @@ -629,7 +629,9 @@ TEST_TARGET INSTALL_TARGET CLEAN_TARGET BUILD_TARGET -MPS_TARGET_NAME +MPS_BUILD_NAME +MPS_ARCH_NAME +MPS_OS_NAME MAKE host_os host_vendor @@ -1243,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.113.0 to adapt to many kinds of systems. +\`configure' configures Memory Pool System Kit release/1.114.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1308,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.113.0:";; + short | recursive ) echo "Configuration of Memory Pool System Kit release/1.114.0:";; esac cat <<\_ACEOF @@ -1389,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.113.0 +Memory Pool System Kit configure release/1.114.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1691,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.113.0, which was +It was created by Memory Pool System Kit $as_me release/1.114.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3455,25 +3457,33 @@ case $host/$CLANG in i*86-*-linux*/no) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Linux x86" >&5 $as_echo "Linux x86" >&6; } - MPS_TARGET_NAME=lii3gc + MPS_OS_NAME=li + MPS_ARCH_NAME=i3 + MPS_BUILD_NAME=gc PFMCFLAGS="$CFLAGS_GC" ;; x86_64-*-linux*/no) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Linux x86_64" >&5 $as_echo "Linux x86_64" >&6; } - MPS_TARGET_NAME=lii6gc + MPS_OS_NAME=li + MPS_ARCH_NAME=i6 + MPS_BUILD_NAME=gc PFMCFLAGS="$CFLAGS_GC" ;; x86_64-*-linux*/yes) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Linux x86_64" >&5 $as_echo "Linux x86_64" >&6; } - MPS_TARGET_NAME=lii6ll + MPS_OS_NAME=li + MPS_ARCH_NAME=i6 + MPS_BUILD_NAME=ll PFMCFLAGS="$CFLAGS_LL" ;; i*86-*-darwin*/*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Mac OS X x86" >&5 $as_echo "Mac OS X x86" >&6; } - MPS_TARGET_NAME=xci3ll + MPS_OS_NAME=xc + MPS_ARCH_NAME=i3 + MPS_BUILD_NAME=ll BUILD_TARGET=build-via-xcode CLEAN_TARGET=clean-xcode-build INSTALL_TARGET=install-xcode-build @@ -3483,7 +3493,9 @@ $as_echo "Mac OS X x86" >&6; } x86_64-apple-darwin*/*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Mac OS X x86_64" >&5 $as_echo "Mac OS X x86_64" >&6; } - MPS_TARGET_NAME=xci6ll + MPS_OS_NAME=xc + MPS_ARCH_NAME=i6 + MPS_BUILD_NAME=ll BUILD_TARGET=build-via-xcode CLEAN_TARGET=clean-xcode-build INSTALL_TARGET=install-xcode-build @@ -3493,7 +3505,9 @@ $as_echo "Mac OS X x86_64" >&6; } i*86-*-freebsd*/no) { $as_echo "$as_me:${as_lineno-$LINENO}: result: FreeBSD x86" >&5 $as_echo "FreeBSD x86" >&6; } - MPS_TARGET_NAME=fri3gc + MPS_OS_NAME=fr + MPS_ARCH_NAME=i3 + MPS_BUILD_NAME=gc # Need /usr/local/include in order to find sqlite3.h CFLAGS="-I/usr/local/include" CPP="$CC -I/usr/local/include -E" @@ -3502,7 +3516,9 @@ $as_echo "FreeBSD x86" >&6; } 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_TARGET_NAME=fri6gc + MPS_OS_NAME=fr + MPS_ARCH_NAME=i6 + MPS_BUILD_NAME=gc # Need /usr/local/include in order to find sqlite3.h CFLAGS="-I/usr/local/include" CPP="$CC -I/usr/local/include -E" @@ -3581,6 +3597,8 @@ CFLAGS="$CFLAGS $PFMCFLAGS" + + ac_config_files="$ac_config_files Makefile example/scheme/Makefile" @@ -4126,7 +4144,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.113.0, which was +This file was extended by Memory Pool System Kit $as_me release/1.114.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4180,7 +4198,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.113.0 +Memory Pool System Kit config.status release/1.114.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 6ee47ca05a6..f564f047d5e 100644 --- a/mps/configure.ac +++ b/mps/configure.ac @@ -47,22 +47,30 @@ TEST_TARGET=test-make-build case $host/$CLANG in i*86-*-linux*/no) AC_MSG_RESULT([Linux x86]) - MPS_TARGET_NAME=lii3gc + MPS_OS_NAME=li + MPS_ARCH_NAME=i3 + MPS_BUILD_NAME=gc PFMCFLAGS="$CFLAGS_GC" ;; x86_64-*-linux*/no) AC_MSG_RESULT([Linux x86_64]) - MPS_TARGET_NAME=lii6gc + MPS_OS_NAME=li + MPS_ARCH_NAME=i6 + MPS_BUILD_NAME=gc PFMCFLAGS="$CFLAGS_GC" ;; x86_64-*-linux*/yes) AC_MSG_RESULT([Linux x86_64]) - MPS_TARGET_NAME=lii6ll + MPS_OS_NAME=li + MPS_ARCH_NAME=i6 + MPS_BUILD_NAME=ll PFMCFLAGS="$CFLAGS_LL" ;; i*86-*-darwin*/*) AC_MSG_RESULT([Mac OS X x86]) - MPS_TARGET_NAME=xci3ll + MPS_OS_NAME=xc + MPS_ARCH_NAME=i3 + MPS_BUILD_NAME=ll BUILD_TARGET=build-via-xcode CLEAN_TARGET=clean-xcode-build INSTALL_TARGET=install-xcode-build @@ -71,7 +79,9 @@ case $host/$CLANG in ;; x86_64-apple-darwin*/*) AC_MSG_RESULT([Mac OS X x86_64]) - MPS_TARGET_NAME=xci6ll + MPS_OS_NAME=xc + MPS_ARCH_NAME=i6 + MPS_BUILD_NAME=ll BUILD_TARGET=build-via-xcode CLEAN_TARGET=clean-xcode-build INSTALL_TARGET=install-xcode-build @@ -80,7 +90,9 @@ case $host/$CLANG in ;; i*86-*-freebsd*/no) AC_MSG_RESULT([FreeBSD x86]) - MPS_TARGET_NAME=fri3gc + MPS_OS_NAME=fr + MPS_ARCH_NAME=i3 + MPS_BUILD_NAME=gc # Need /usr/local/include in order to find sqlite3.h CFLAGS="-I/usr/local/include" CPP="$CC -I/usr/local/include -E" @@ -88,7 +100,9 @@ case $host/$CLANG in ;; amd64-*-freebsd*/no | x86_64-*-freebsd*/no) AC_MSG_RESULT([FreeBSD x86_64]) - MPS_TARGET_NAME=fri6gc + MPS_OS_NAME=fr + MPS_ARCH_NAME=i6 + MPS_BUILD_NAME=gc # Need /usr/local/include in order to find sqlite3.h CFLAGS="-I/usr/local/include" CPP="$CC -I/usr/local/include -E" @@ -111,7 +125,9 @@ AC_CHECK_HEADER([sqlite3.h], [EXTRA_TARGETS="$EXTRA_TARGETS mpseventsql"]) # those flags. CFLAGS="$CFLAGS $PFMCFLAGS" -AC_SUBST(MPS_TARGET_NAME) +AC_SUBST(MPS_OS_NAME) +AC_SUBST(MPS_ARCH_NAME) +AC_SUBST(MPS_BUILD_NAME) AC_SUBST(BUILD_TARGET) AC_SUBST(CLEAN_TARGET) AC_SUBST(INSTALL_TARGET) From 21a69d0bfc1c3c690260723f9896acb97777a564 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 18:53:10 +0100 Subject: [PATCH 179/266] Fumbled the merge. Copied from Perforce Change: 186043 ServerID: perforce.ravenbrook.com --- mps/tool/testrun.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mps/tool/testrun.sh b/mps/tool/testrun.sh index f44b74217e2..cdb41ac458b 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -24,12 +24,8 @@ # Make a temporary output directory for the test logs. LOGDIR=$(mktemp -d /tmp/mps.log.XXXXXX) -TEST_DIR=$1 echo "MPS test suite" echo "Logging test output to $LOGDIR" -echo "Test directory: $TEST_DIR" -shift -TEST_CASES=${*:-${ALL_TEST_CASES}} # First argument is the directory containing the test cases. TEST_DIR=$1 From b38051bdfb0546f3168e7f0a80ecb1e56b791d7b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 19:11:07 +0100 Subject: [PATCH 180/266] Steptest uses incremental collection, so can't be run under config_poll_none. Copied from Perforce Change: 186046 ServerID: perforce.ravenbrook.com --- mps/tool/testcases.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/tool/testcases.txt b/mps/tool/testcases.txt index 0c536f0a336..3f8e9c7b70d 100644 --- a/mps/tool/testcases.txt +++ b/mps/tool/testcases.txt @@ -37,7 +37,7 @@ poolncv qs sacss segsmss -steptest +steptest =P teletest =N interactive walkt0 zcoll =L @@ -50,7 +50,7 @@ Key to flags B -- known Bad L -- Long runtime N -- Not an automated test case - P -- relies on Polling + P -- relies on Polling or incremental collection T -- multi-Threaded W -- Windows-only X -- Unix-only From 598bd93af856b2dcbfa776474b730bb4ce4249b9 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 19:48:01 +0100 Subject: [PATCH 181/266] Setenv requires _gnu_source, so get the headers in the right order so that the feature macros are set up in config.h before any system header is included. Don't update _XOPEN_SOURCE if it's already set to a high enough value. Copied from Perforce Change: 186049 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 8 +++++++- mps/code/eventtxt.c | 8 ++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index 1dd6a2e07f5..1792e8cbaba 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -454,6 +454,7 @@ * * Source Symbols Header Feature * =========== ========================= ============= ==================== + * eventtxt.c setenv _GNU_SOURCE * lockli.c pthread_mutexattr_settype _XOPEN_SOURCE >= 500 * prmci3li.c REG_EAX etc. _GNU_SOURCE * prmci6li.c REG_RAX etc. _GNU_SOURCE @@ -472,9 +473,14 @@ #if defined(MPS_OS_LI) +#if defined(_XOPEN_SOURCE) && _XOPEN_SOURCE < 500 +#undef _XOPEN_SOURCE +#endif +#if !defined(_XOPEN_SOURCE) #define _XOPEN_SOURCE 500 +#endif -#ifndef _GNU_SOURCE +#if !defined(_GNU_SOURCE) #define _GNU_SOURCE #endif diff --git a/mps/code/eventtxt.c b/mps/code/eventtxt.c index bc0d550d122..01b071aee3a 100644 --- a/mps/code/eventtxt.c +++ b/mps/code/eventtxt.c @@ -29,13 +29,13 @@ * $Id$ */ +#include "check.h" +#include "config.h" +#include "eventcom.h" +#include "eventdef.h" #include "mps.h" #include "mpsavm.h" #include "mpscmvff.h" -#include "check.h" -#include "config.h" -#include "eventdef.h" -#include "eventcom.h" #include "table.h" #include "testlib.h" /* for ulongest_t and associated print formats */ From 51ae9e9343352aced56a12ff845ac392ad722a90 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 19:48:39 +0100 Subject: [PATCH 182/266] Segsmss needs to park the arena (because otherwise there might be a collection running on the amst pool's chain). Copied from Perforce Change: 186050 ServerID: perforce.ravenbrook.com --- mps/code/segsmss.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mps/code/segsmss.c b/mps/code/segsmss.c index 7efac5c64a5..2843b900dfb 100644 --- a/mps/code/segsmss.c +++ b/mps/code/segsmss.c @@ -836,6 +836,8 @@ static void *test(void *arg, size_t s) } (void)mps_commit(busy_ap, busy_init, 64); + + mps_arena_park(arena); mps_ap_destroy(busy_ap); mps_ap_destroy(ap); mps_root_destroy(exactRoot); From 84ee41b58b83a0df241d7e058ebfe37b64b244ef Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 19:51:54 +0100 Subject: [PATCH 183/266] Increase the commit limit for exposet0 so that the test always passes. Copied from Perforce Change: 186051 ServerID: perforce.ravenbrook.com --- mps/code/exposet0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/exposet0.c b/mps/code/exposet0.c index a1e8fcdc6e8..7e097d6b034 100644 --- a/mps/code/exposet0.c +++ b/mps/code/exposet0.c @@ -245,7 +245,7 @@ int main(int argc, char *argv[]) die(mps_arena_create(&arena, mps_arena_class_vm(), 2*testArenaSIZE), "arena_create"); mps_message_type_enable(arena, mps_message_type_gc()); - die(mps_arena_commit_limit_set(arena, testArenaSIZE), "set limit"); + die(mps_arena_commit_limit_set(arena, 2*testArenaSIZE), "set limit"); die(mps_thread_reg(&thread, arena), "thread_reg"); mps_tramp(&r, test, arena, 0); mps_thread_dereg(thread); From eaae595b79ac23a275bc104d585dc858052062c6 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 21:01:58 +0100 Subject: [PATCH 184/266] Fix p4-bisect interface Copied from Perforce Change: 186053 ServerID: perforce.ravenbrook.com --- mps/tool/p4-bisect | 1 - 1 file changed, 1 deletion(-) diff --git a/mps/tool/p4-bisect b/mps/tool/p4-bisect index 2886d823c59..10af68cfc0c 100755 --- a/mps/tool/p4-bisect +++ b/mps/tool/p4-bisect @@ -132,7 +132,6 @@ def run(args): def main(argv): parser = argparse.ArgumentParser( prog='p4-bisect', epilog='For help on CMD, use p4-bisect CMD -h') - parser.set_defaults(func=partial(help, parser)) subparsers = parser.add_subparsers() a = subparsers.add_parser From cbddbd5fac855c641693f0133a8cfb714f9561e5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 21:54:52 +0100 Subject: [PATCH 185/266] Only link the testthr* module with test cases that use it. Copied from Perforce Change: 186055 ServerID: perforce.ravenbrook.com --- mps/code/comm.gmk | 15 +++++++++------ mps/code/commpost.nmk | 10 +++++----- mps/code/commpre.nmk | 7 ++++++- mps/code/w3i3mv.nmk | 6 ++++++ 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index 589b6db40ba..4fb69b9ea1e 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -156,7 +156,8 @@ SNC = poolsnc.c POOLN = pooln.c MV2 = poolmv2.c MVFF = poolmvff.c -TESTLIB = testlib.c testthrix.c +TESTLIB = testlib.c +TESTTHR = testthrix.c FMTDY = fmtdy.c fmtno.c FMTDYTST = fmtdy.c fmtno.c fmtdytst.c FMTHETST = fmthe.c fmtdy.c fmtno.c fmtdytst.c @@ -201,6 +202,8 @@ MVFFDEP = $(MVFF:%.c=$(PFM)/$(VARIETY)/%.d) TESTLIBOBJ = $(TESTLIB:%.c=$(PFM)/$(VARIETY)/%.o) TESTLIBDEP = $(TESTLIB:%.c=$(PFM)/$(VARIETY)/%.d) +TESTTHROBJ = $(TESTTHR:%.c=$(PFM)/$(VARIETY)/%.o) +TESTTHRDEP = $(TESTTHR:%.c=$(PFM)/$(VARIETY)/%.d) FMTDYOBJ = $(FMTDY:%.c=$(PFM)/$(VARIETY)/%.o) FMTDYDEP = $(FMTDY:%.c=$(PFM)/$(VARIETY)/%.d) FMTDYTSTOBJ = $(FMTDYTST:%.c=$(PFM)/$(VARIETY)/%.o) @@ -390,7 +393,7 @@ $(PFM)/$(VARIETY)/amcsshe: $(PFM)/$(VARIETY)/amcsshe.o \ $(FMTHETSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a $(PFM)/$(VARIETY)/amcssth: $(PFM)/$(VARIETY)/amcssth.o \ - $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a + $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)/$(VARIETY)/mps.a $(PFM)/$(VARIETY)/amsss: $(PFM)/$(VARIETY)/amsss.o \ $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a @@ -411,7 +414,7 @@ $(PFM)/$(VARIETY)/awluthe: $(PFM)/$(VARIETY)/awluthe.o \ $(FMTHETSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a $(PFM)/$(VARIETY)/awlutth: $(PFM)/$(VARIETY)/awlutth.o \ - $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a + $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)/$(VARIETY)/mps.a $(PFM)/$(VARIETY)/btcv: $(PFM)/$(VARIETY)/btcv.o \ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a @@ -420,7 +423,7 @@ $(PFM)/$(VARIETY)/bttest: $(PFM)/$(VARIETY)/bttest.o \ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a $(PFM)/$(VARIETY)/djbench: $(PFM)/$(VARIETY)/djbench.o \ - $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a + $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)/$(VARIETY)/mps.a $(PFM)/$(VARIETY)/exposet0: $(PFM)/$(VARIETY)/exposet0.o \ $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a @@ -441,7 +444,7 @@ $(PFM)/$(VARIETY)/fotest: $(PFM)/$(VARIETY)/fotest.o \ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a $(PFM)/$(VARIETY)/gcbench: $(PFM)/$(VARIETY)/gcbench.o \ - $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a + $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)/$(VARIETY)/mps.a $(PFM)/$(VARIETY)/locbwcss: $(PFM)/$(VARIETY)/locbwcss.o \ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a @@ -450,7 +453,7 @@ $(PFM)/$(VARIETY)/lockcov: $(PFM)/$(VARIETY)/lockcov.o \ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a $(PFM)/$(VARIETY)/lockut: $(PFM)/$(VARIETY)/lockut.o \ - $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a + $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)/$(VARIETY)/mps.a $(PFM)/$(VARIETY)/locusss: $(PFM)/$(VARIETY)/locusss.o \ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk index ca44c8a7db2..47139017626 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/commpost.nmk @@ -124,7 +124,7 @@ $(PFM)\$(VARIETY)\amcsshe.exe: $(PFM)\$(VARIETY)\amcsshe.obj \ $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) $(PFM)\$(VARIETY)\amcssth.exe: $(PFM)\$(VARIETY)\amcssth.obj \ - $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) + $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)\$(VARIETY)\amsss.exe: $(PFM)\$(VARIETY)\amsss.obj \ $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) @@ -148,7 +148,7 @@ $(PFM)\$(VARIETY)\awluthe.exe: $(PFM)\$(VARIETY)\awluthe.obj \ $(PFM)\$(VARIETY)\awlutth.exe: $(PFM)\$(VARIETY)\awlutth.obj \ $(FMTTESTOBJ) \ - $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) + $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)\$(VARIETY)\btcv.exe: $(PFM)\$(VARIETY)\btcv.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) @@ -160,7 +160,7 @@ $(PFM)\$(VARIETY)\cvmicv.exe: $(PFM)\$(VARIETY)\cvmicv.obj \ $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) $(PFM)\$(VARIETY)\djbench.exe: $(PFM)\$(VARIETY)\djbench.obj \ - $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) + $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)\$(VARIETY)\exposet0.exe: $(PFM)\$(VARIETY)\exposet0.obj \ $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) @@ -181,7 +181,7 @@ $(PFM)\$(VARIETY)\fotest.exe: $(PFM)\$(VARIETY)\fotest.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) $(PFM)\$(VARIETY)\gcbench.exe: $(PFM)\$(VARIETY)\gcbench.obj \ - $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) + $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)\$(VARIETY)\locbwcss.exe: $(PFM)\$(VARIETY)\locbwcss.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) @@ -190,7 +190,7 @@ $(PFM)\$(VARIETY)\lockcov.exe: $(PFM)\$(VARIETY)\lockcov.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) $(PFM)\$(VARIETY)\lockut.exe: $(PFM)\$(VARIETY)\lockut.obj \ - $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) + $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)\$(VARIETY)\locusss.exe: $(PFM)\$(VARIETY)\locusss.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index 09f4f165207..336bb788d82 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -32,6 +32,7 @@ # 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 # # @@ -180,7 +181,8 @@ SNC = DW = FMTTEST = FMTSCHEME = -TESTLIB = +TESTLIB = +TESTTHR = # CHECK PARAMETERS @@ -228,6 +230,9 @@ TESTLIB = !IFNDEF TESTLIB !ERROR commpre.nmk: TESTLIB not defined !ENDIF +!IFNDEF TESTTHR +!ERROR commpre.nmk: TESTTHR not defined +!ENDIF # DECLARATIONS diff --git a/mps/code/w3i3mv.nmk b/mps/code/w3i3mv.nmk index 97a669700cc..870b520cba0 100644 --- a/mps/code/w3i3mv.nmk +++ b/mps/code/w3i3mv.nmk @@ -44,6 +44,7 @@ FMTTESTOBJ0 = $(FMTTEST:<=w3i3mv\hot\) FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i3mv\hot\) POOLNOBJ0 = $(POOLN:<=w3i3mv\hot\) TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\hot\) +TESTTHROBJ0 = $(TESTTHR:<=w3i3mv\hot\) !ELSEIF "$(VARIETY)" == "cool" CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST) @@ -63,6 +64,7 @@ FMTTESTOBJ0 = $(FMTTEST:<=w3i3mv\cool\) FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i3mv\cool\) POOLNOBJ0 = $(POOLN:<=w3i3mv\cool\) TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\cool\) +TESTTHROBJ0 = $(TESTTHR:<=w3i3mv\cool\) !ELSEIF "$(VARIETY)" == "rash" CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST) @@ -82,6 +84,7 @@ FMTTESTOBJ0 = $(FMTTEST:<=w3i3mv\rash\) FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i3mv\rash\) POOLNOBJ0 = $(POOLN:<=w3i3mv\rash\) TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\rash\) +TESTTHROBJ0 = $(TESTTHR:<=w3i3mv\rash\) #!ELSEIF "$(VARIETY)" == "cv" #CFLAGS=$(CFLAGSCOMMON) $(CFCV) @@ -107,6 +110,8 @@ TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\rash\) #POOLNOBJ = $(POOLNOBJ0:>=.obj) #TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\cv\) #TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) +#TESTTHROBJ0 = $(TESTTHR:<=w3i3mv\cv\) +#TESTTHROBJ = $(TESTTHROBJ0:>=.obj) !ENDIF @@ -126,6 +131,7 @@ FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj) FMTSCHEMEOBJ = $(FMTSCHEMEOBJ0:>=.obj) POOLNOBJ = $(POOLNOBJ0:>=.obj) TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) +TESTTHROBJ = $(TESTTHROBJ0:>=.obj) !INCLUDE commpost.nmk From ce16681f03baeb037cf5f2213e9a2218678cb723 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 12 May 2014 22:18:09 +0100 Subject: [PATCH 186/266] Need -lpthread so that we can compile the threading test cases, even though we aren't going to be able to run them. Copied from Perforce Change: 186057 ServerID: perforce.ravenbrook.com --- mps/code/anangc.gmk | 2 +- mps/code/ananll.gmk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/code/anangc.gmk b/mps/code/anangc.gmk index 7ebccd8b72e..f0a7d2ff515 100644 --- a/mps/code/anangc.gmk +++ b/mps/code/anangc.gmk @@ -16,7 +16,7 @@ MPMPF = \ than.c \ vman.c -LIBS = -lm +LIBS = -lm -lpthread include gc.gmk diff --git a/mps/code/ananll.gmk b/mps/code/ananll.gmk index cdfda39b300..cc95645f212 100644 --- a/mps/code/ananll.gmk +++ b/mps/code/ananll.gmk @@ -16,7 +16,7 @@ MPMPF = \ than.c \ vman.c -LIBS = -lm +LIBS = -lm -lpthread include ll.gmk From ac79e9110f07545d78106febb441a92ec1c2bf70 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 13 May 2014 09:32:06 +0100 Subject: [PATCH 187/266] Windows doesn't have setenv, so use _putenv_s. Copied from Perforce Change: 186060 ServerID: perforce.ravenbrook.com --- mps/code/testlib.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mps/code/testlib.h b/mps/code/testlib.h index 9c197cae839..38a4c94bdab 100644 --- a/mps/code/testlib.h +++ b/mps/code/testlib.h @@ -68,6 +68,22 @@ #endif +/* setenv -- set environment variable + * + * Windows lacks setenv(), but _putenv_s() has similar functionality. + * + * + * This macro version may evaluate the name argument twice. + */ + +#if defined(MPS_OS_W3) + +#define setenv(name, value, overwrite) \ + (((overwrite) || !getenv(name)) ? _putenv_s(name, value) : 0) + +#endif + + /* ulongest_t -- longest unsigned integer type * * Define a longest unsigned integer type for testing, scanning, and From a6ce57cb0e998979c50c62ecc0021811ad5ec39d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 13 May 2014 09:33:26 +0100 Subject: [PATCH 188/266] Compile testthrw3.c on all windows build configurations. Copied from Perforce Change: 186061 ServerID: perforce.ravenbrook.com --- mps/code/w3i3pc.nmk | 6 ++++++ mps/code/w3i6mv.nmk | 6 ++++++ mps/code/w3i6pc.nmk | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/mps/code/w3i3pc.nmk b/mps/code/w3i3pc.nmk index d6d424b669d..f9c7bef7e19 100644 --- a/mps/code/w3i3pc.nmk +++ b/mps/code/w3i3pc.nmk @@ -43,6 +43,7 @@ DWOBJ0 = $(DW:<=w3i3pc\hot\) FMTTESTOBJ0 = $(FMTTEST:<=w3i3pc\hot\) POOLNOBJ0 = $(POOLN:<=w3i3pc\hot\) TESTLIBOBJ0 = $(TESTLIB:<=w3i3pc\hot\) +TESTTHROBJ0 = $(TESTTHR:<=w3i3pc\hot\) !ELSEIF "$(VARIETY)" == "cool" CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST) @@ -61,6 +62,7 @@ DWOBJ0 = $(DW:<=w3i3pc\cool\) FMTTESTOBJ0 = $(FMTTEST:<=w3i3pc\cool\) POOLNOBJ0 = $(POOLN:<=w3i3pc\cool\) TESTLIBOBJ0 = $(TESTLIB:<=w3i3pc\cool\) +TESTTHROBJ0 = $(TESTTHR:<=w3i3pc\cool\) !ELSEIF "$(VARIETY)" == "rash" CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST) @@ -79,6 +81,7 @@ DWOBJ0 = $(DW:<=w3i3pc\rash\) FMTTESTOBJ0 = $(FMTTEST:<=w3i3pc\rash\) POOLNOBJ0 = $(POOLN:<=w3i3pc\rash\) TESTLIBOBJ0 = $(TESTLIB:<=w3i3pc\rash\) +TESTTHROBJ0 = $(TESTTHR:<=w3i3pc\rash\) #!ELSEIF "$(VARIETY)" == "cv" #CFLAGS=$(CFLAGSCOMMON) $(CFCV) @@ -104,6 +107,8 @@ TESTLIBOBJ0 = $(TESTLIB:<=w3i3pc\rash\) #POOLNOBJ = $(POOLNOBJ0:>=.obj) #TESTLIBOBJ0 = $(TESTLIB:<=w3i3pc\cv\) #TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) +#TESTTHROBJ0 = $(TESTTHR:<=w3i3pc\cv\) +#TESTTHROBJ = $(TESTTHROBJ0:>=.obj) !ENDIF @@ -122,6 +127,7 @@ DWOBJ = $(DWOBJ0:>=.obj) FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj) POOLNOBJ = $(POOLNOBJ0:>=.obj) TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) +TESTTHROBJ = $(TESTTHROBJ0:>=.obj) !INCLUDE commpost.nmk diff --git a/mps/code/w3i6mv.nmk b/mps/code/w3i6mv.nmk index 6d31a81452d..67aab4ea57d 100644 --- a/mps/code/w3i6mv.nmk +++ b/mps/code/w3i6mv.nmk @@ -44,6 +44,7 @@ FMTTESTOBJ0 = $(FMTTEST:<=w3i6mv\hot\) FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i6mv\hot\) POOLNOBJ0 = $(POOLN:<=w3i6mv\hot\) TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\hot\) +TESTTHROBJ0 = $(TESTTHR:<=w3i6mv\hot\) !ELSEIF "$(VARIETY)" == "cool" CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST) @@ -63,6 +64,7 @@ FMTTESTOBJ0 = $(FMTTEST:<=w3i6mv\cool\) FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i6mv\cool\) POOLNOBJ0 = $(POOLN:<=w3i6mv\cool\) TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\cool\) +TESTTHROBJ0 = $(TESTTHR:<=w3i6mv\cool\) !ELSEIF "$(VARIETY)" == "rash" CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST) @@ -82,6 +84,7 @@ FMTTESTOBJ0 = $(FMTTEST:<=w3i6mv\rash\) FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i6mv\rash\) POOLNOBJ0 = $(POOLN:<=w3i6mv\rash\) TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\rash\) +TESTTHROBJ0 = $(TESTTHR:<=w3i6mv\rash\) #!ELSEIF "$(VARIETY)" == "cv" #CFLAGS=$(CFLAGSCOMMON) $(CFCV) @@ -107,6 +110,8 @@ TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\rash\) #POOLNOBJ = $(POOLNOBJ0:>=.obj) #TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\cv\) #TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) +#TESTTHROBJ0 = $(TESTTHR:<=w3i6mv\cv\) +#TESTTHROBJ = $(TESTTHROBJ0:>=.obj) !ENDIF @@ -126,6 +131,7 @@ FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj) FMTSCHEMEOBJ = $(FMTSCHEMEOBJ0:>=.obj) POOLNOBJ = $(POOLNOBJ0:>=.obj) TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) +TESTTHROBJ = $(TESTTHROBJ0:>=.obj) !INCLUDE commpost.nmk diff --git a/mps/code/w3i6pc.nmk b/mps/code/w3i6pc.nmk index 1decdde0083..a7d571257b0 100644 --- a/mps/code/w3i6pc.nmk +++ b/mps/code/w3i6pc.nmk @@ -47,6 +47,7 @@ DWOBJ0 = $(DW:<=w3i6pc\hot\) FMTTESTOBJ0 = $(FMTTEST:<=w3i6pc\hot\) POOLNOBJ0 = $(POOLN:<=w3i6pc\hot\) TESTLIBOBJ0 = $(TESTLIB:<=w3i6pc\hot\) +TESTTHROBJ0 = $(TESTTHR:<=w3i6pc\hot\) !ELSEIF "$(VARIETY)" == "cool" CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST) @@ -65,6 +66,7 @@ DWOBJ0 = $(DW:<=w3i6pc\cool\) FMTTESTOBJ0 = $(FMTTEST:<=w3i6pc\cool\) POOLNOBJ0 = $(POOLN:<=w3i6pc\cool\) TESTLIBOBJ0 = $(TESTLIB:<=w3i6pc\cool\) +TESTTHROBJ0 = $(TESTTHR:<=w3i6pc\cool\) !ELSEIF "$(VARIETY)" == "rash" CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST) @@ -83,6 +85,7 @@ DWOBJ0 = $(DW:<=w3i6pc\rash\) FMTTESTOBJ0 = $(FMTTEST:<=w3i6pc\rash\) POOLNOBJ0 = $(POOLN:<=w3i6pc\rash\) TESTLIBOBJ0 = $(TESTLIB:<=w3i6pc\rash\) +TESTTHROBJ0 = $(TESTTHR:<=w3i6pc\rash\) #!ELSEIF "$(VARIETY)" == "cv" #CFLAGS=$(CFLAGSCOMMON) $(CFCV) @@ -108,6 +111,8 @@ TESTLIBOBJ0 = $(TESTLIB:<=w3i6pc\rash\) #POOLNOBJ = $(POOLNOBJ0:>=.obj) #TESTLIBOBJ0 = $(TESTLIB:<=w3i6pc\cv\) #TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) +#TESTTHROBJ0 = $(TESTTHR:<=w3i6pc\cv\) +#TESTTHROBJ = $(TESTTHROBJ0:>=.obj) !ENDIF @@ -126,6 +131,7 @@ DWOBJ = $(DWOBJ0:>=.obj) FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj) POOLNOBJ = $(POOLNOBJ0:>=.obj) TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) +TESTTHROBJ = $(TESTTHROBJ0:>=.obj) !INCLUDE commpost.nmk From 9aecea10df4e49f47a500bdce87b2768e0e21246 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 13 May 2014 10:12:56 +0100 Subject: [PATCH 189/266] Ansi platform compiles and passes tests on windows. in detail: * Move Windows-specific modules like vmw3.c out of commpre.nmk and into the platform-specific Nmake files. * Set StackProbeDEPTH to 0 on the ANSI platform. * New Nmake file ananmv.nmk builds the MPS for the ANSI platform using Microsoft Visual C/C++. Copied from Perforce Change: 186063 ServerID: perforce.ravenbrook.com --- mps/code/ananmv.nmk | 184 +++++++++++++++++++++++++++++++++++++++++++ mps/code/commpre.nmk | 5 -- mps/code/config.h | 4 +- mps/code/w3i3mv.nmk | 13 ++- mps/code/w3i3pc.nmk | 13 ++- mps/code/w3i6mv.nmk | 22 ++++-- mps/code/w3i6pc.nmk | 13 ++- 7 files changed, 236 insertions(+), 18 deletions(-) create mode 100644 mps/code/ananmv.nmk diff --git a/mps/code/ananmv.nmk b/mps/code/ananmv.nmk new file mode 100644 index 00000000000..ecf97540ece --- /dev/null +++ b/mps/code/ananmv.nmk @@ -0,0 +1,184 @@ +# ananmv.nmk: ANSI/ANSI/MICROSOFT VISUAL C/C++ NMAKE FILE -*- makefile -*- +# +# $Id$ +# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + +PFM = ananmv + +PFMDEFS = /DCONFIG_PF_ANSI /DCONFIG_THREAD_SINGLE + +!INCLUDE commpre.nmk +!INCLUDE mv.nmk + +# MPM sources: core plus platform-specific. +MPM = $(MPMCOMMON) \ + \ + \ + \ + \ + \ + \ + + + +# Source to object file mappings and CFLAGS amalgamation +# +# %%VARIETY %%PART: When adding a new variety or part, add new macros which +# expand to the files included in the part for each variety +# +# %%VARIETY: When adding a new variety, add a CFLAGS macro which expands to +# the flags that that variety should use when compiling C. And a LINKFLAGS +# macro which expands to the flags that the variety should use when building +# executables. And a LIBFLAGS macro which expands to the flags that the +# variety should use when building libraries + +!IF "$(VARIETY)" == "hot" +CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST) +CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST) +LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT) +LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT) +MPMOBJ0 = $(MPM:<=ananmv\hot\) +PLINTHOBJ0 = $(PLINTH:<=ananmv\hot\) +AMSOBJ0 = $(AMS:<=ananmv\hot\) +AMCOBJ0 = $(AMC:<=ananmv\hot\) +AWLOBJ0 = $(AWL:<=ananmv\hot\) +LOOBJ0 = $(LO:<=ananmv\hot\) +SNCOBJ0 = $(SNC:<=ananmv\hot\) +MVFFOBJ0 = $(MVFF:<=ananmv\hot\) +DWOBJ0 = $(DW:<=ananmv\hot\) +FMTTESTOBJ0 = $(FMTTEST:<=ananmv\hot\) +FMTSCHEMEOBJ0 = $(FMTSCHEME:<=ananmv\hot\) +POOLNOBJ0 = $(POOLN:<=ananmv\hot\) +TESTLIBOBJ0 = $(TESTLIB:<=ananmv\hot\) +TESTTHROBJ0 = $(TESTTHR:<=ananmv\hot\) + +!ELSEIF "$(VARIETY)" == "cool" +CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST) +CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST) +LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL) +LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL) +MPMOBJ0 = $(MPM:<=ananmv\cool\) +PLINTHOBJ0 = $(PLINTH:<=ananmv\cool\) +AMSOBJ0 = $(AMS:<=ananmv\cool\) +AMCOBJ0 = $(AMC:<=ananmv\cool\) +AWLOBJ0 = $(AWL:<=ananmv\cool\) +LOOBJ0 = $(LO:<=ananmv\cool\) +SNCOBJ0 = $(SNC:<=ananmv\cool\) +MVFFOBJ0 = $(MVFF:<=ananmv\cool\) +DWOBJ0 = $(DW:<=ananmv\cool\) +FMTTESTOBJ0 = $(FMTTEST:<=ananmv\cool\) +FMTSCHEMEOBJ0 = $(FMTSCHEME:<=ananmv\cool\) +POOLNOBJ0 = $(POOLN:<=ananmv\cool\) +TESTLIBOBJ0 = $(TESTLIB:<=ananmv\cool\) +TESTTHROBJ0 = $(TESTTHR:<=ananmv\cool\) + +!ELSEIF "$(VARIETY)" == "rash" +CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST) +CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST) +LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH) +LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH) +MPMOBJ0 = $(MPM:<=ananmv\rash\) +PLINTHOBJ0 = $(PLINTH:<=ananmv\rash\) +AMSOBJ0 = $(AMS:<=ananmv\rash\) +AMCOBJ0 = $(AMC:<=ananmv\rash\) +AWLOBJ0 = $(AWL:<=ananmv\rash\) +LOOBJ0 = $(LO:<=ananmv\rash\) +SNCOBJ0 = $(SNC:<=ananmv\rash\) +MVFFOBJ0 = $(MVFF:<=ananmv\rash\) +DWOBJ0 = $(DW:<=ananmv\rash\) +FMTTESTOBJ0 = $(FMTTEST:<=ananmv\rash\) +FMTSCHEMEOBJ0 = $(FMTSCHEME:<=ananmv\rash\) +POOLNOBJ0 = $(POOLN:<=ananmv\rash\) +TESTLIBOBJ0 = $(TESTLIB:<=ananmv\rash\) +TESTTHROBJ0 = $(TESTTHR:<=ananmv\rash\) + +#!ELSEIF "$(VARIETY)" == "cv" +#CFLAGS=$(CFLAGSCOMMON) $(CFCV) +#LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCV) +#LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCV) +#MPMOBJ0 = $(MPM:<=ananmv\cv\) +#MPMOBJ = $(MPMOBJ0:>=.obj) +#PLINTHOBJ0 = $(PLINTH:<=ananmv\cv\) +#PLINTHOBJ = $(PLINTHOBJ0:>=.obj) +#AMSOBJ0 = $(AMS:<=ananmv\cv\) +#AMSOBJ = $(AMSOBJ0:>=.obj) +#AMCOBJ0 = $(AMC:<=ananmv\cv\) +#AMCOBJ = $(AMCOBJ0:>=.obj) +#AWLOBJ0 = $(AWL:<=ananmv\cv\) +#AWLOBJ = $(AWLOBJ0:>=.obj) +#LOOBJ0 = $(LO:<=ananmv\cv\) +#LOOBJ = $(LOOBJ0:>=.obj) +#SNCOBJ0 = $(SNC:<=ananmv\cv\) +#SNCOBJ = $(SNCOBJ0:>=.obj) +#DWOBJ0 = $(DW:<=ananmv\cv\) +#DWOBJ = $(DWOBJ0:>=.obj) +#POOLNOBJ0 = $(POOLN:<=ananmv\cv\) +#POOLNOBJ = $(POOLNOBJ0:>=.obj) +#TESTLIBOBJ0 = $(TESTLIB:<=ananmv\cv\) +#TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) +#TESTTHROBJ0 = $(TESTTHR:<=ananmv\cv\) +#TESTTHROBJ = $(TESTTHROBJ0:>=.obj) + +!ENDIF + +# %%PART: When adding a new part, add new macros which expand to the object +# files included in the part + +MPMOBJ = $(MPMOBJ0:>=.obj) +PLINTHOBJ = $(PLINTHOBJ0:>=.obj) +AMSOBJ = $(AMSOBJ0:>=.obj) +AMCOBJ = $(AMCOBJ0:>=.obj) +AWLOBJ = $(AWLOBJ0:>=.obj) +LOOBJ = $(LOOBJ0:>=.obj) +SNCOBJ = $(SNCOBJ0:>=.obj) +MVFFOBJ = $(MVFFOBJ0:>=.obj) +DWOBJ = $(DWOBJ0:>=.obj) +FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj) +FMTSCHEMEOBJ = $(FMTSCHEMEOBJ0:>=.obj) +POOLNOBJ = $(POOLNOBJ0:>=.obj) +TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) +TESTTHROBJ = $(TESTTHROBJ0:>=.obj) + + +!INCLUDE commpost.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. diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index 336bb788d82..88ed5565270 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -135,13 +135,11 @@ MPMCOMMON=\ \ \ \ - \ \ \ \ \ \ - \ \ \ \ @@ -150,7 +148,6 @@ MPMCOMMON=\ \ \ \ - \ \ \ \ @@ -163,12 +160,10 @@ MPMCOMMON=\ \ \ \ - \ \ \ \ \ - \ PLINTH = AMC = diff --git a/mps/code/config.h b/mps/code/config.h index 1792e8cbaba..0a1eb1a862b 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -425,7 +425,9 @@ /* Stack configuration */ /* Currently StackProbe has a useful implementation only on Windows. */ -#if defined(MPS_OS_W3) && defined(MPS_ARCH_I3) +#if defined(PLATFORM_ANSI) +#define StackProbeDEPTH ((Size)0) +#elif defined(MPS_OS_W3) && defined(MPS_ARCH_I3) #define StackProbeDEPTH ((Size)500) #elif defined(MPS_OS_W3) && defined(MPS_ARCH_I6) #define StackProbeDEPTH ((Size)500) diff --git a/mps/code/w3i3mv.nmk b/mps/code/w3i3mv.nmk index 870b520cba0..a0f919335b1 100644 --- a/mps/code/w3i3mv.nmk +++ b/mps/code/w3i3mv.nmk @@ -11,8 +11,17 @@ PFMDEFS = /DCONFIG_PF_STRING="w3i3mv" /DCONFIG_PF_W3I3MV /DWIN32 /D_WINDOWS !INCLUDE mv.nmk # MPM sources: core plus platform-specific. -MPM = $(MPMCOMMON) - +MPM = $(MPMCOMMON) \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + # Source to object file mappings and CFLAGS amalgamation diff --git a/mps/code/w3i3pc.nmk b/mps/code/w3i3pc.nmk index f9c7bef7e19..ad56deca83a 100644 --- a/mps/code/w3i3pc.nmk +++ b/mps/code/w3i3pc.nmk @@ -11,8 +11,17 @@ PFMDEFS = /DCONFIG_PF_STRING="w3i3pc" /DCONFIG_PF_W3I3PC /DWIN32 /D_WINDOWS !INCLUDE pc.nmk # MPM sources: core plus platform-specific. -MPM = $(MPMCOMMON) - +MPM = $(MPMCOMMON) \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + # Source to object file mappings and CFLAGS amalgamation diff --git a/mps/code/w3i6mv.nmk b/mps/code/w3i6mv.nmk index 67aab4ea57d..9d20b498525 100644 --- a/mps/code/w3i6mv.nmk +++ b/mps/code/w3i6mv.nmk @@ -1,18 +1,28 @@ # w3i6mv.nmk: WINDOWS (x86-64) NMAKE FILE -*- makefile -*- # # $Id$ -# Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. +# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. PFM = w3i6mv PFMDEFS = /DCONFIG_PF_STRING="w3i6mv" /DCONFIG_PF_W3I6MV /DWIN32 /D_WINDOWS MASM = ml64 -# MPM sources: core plus platform-specific. -MPM = $(MPMCOMMON) - - !INCLUDE commpre.nmk +!INCLUDE mv.nmk + +# MPM sources: core plus platform-specific. +MPM = $(MPMCOMMON) \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + # Source to object file mappings and CFLAGS amalgamation @@ -139,7 +149,7 @@ TESTTHROBJ = $(TESTTHROBJ0:>=.obj) # C. COPYRIGHT AND LICENSE # -# Copyright (C) 2001-2013 Ravenbrook Limited . +# Copyright (C) 2001-2014 Ravenbrook Limited . # All rights reserved. This is an open source license. Contact # Ravenbrook for commercial licensing options. # diff --git a/mps/code/w3i6pc.nmk b/mps/code/w3i6pc.nmk index a7d571257b0..687a0a6f204 100644 --- a/mps/code/w3i6pc.nmk +++ b/mps/code/w3i6pc.nmk @@ -15,8 +15,17 @@ PFMDEFS = /DCONFIG_PF_STRING="w3i6pc" /DCONFIG_PF_W3I6PC /DWIN32 /D_WINDOWS CFLAGSCOMMONPRE = $(CFLAGSCOMMONPRE) /Tamd64-coff # MPM sources: core plus platform-specific. -MPM = $(MPMCOMMON) - +MPM = $(MPMCOMMON) \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + # Source to object file mappings and CFLAGS amalgamation From e58b421e1b9de64f25dba7aac6bbe2ad2172b8c8 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 13 May 2014 10:48:51 +0100 Subject: [PATCH 190/266] Fix typo: the general root scanning function type is mps_root_scan_t, not mps_reg_scan_t. Copied from Perforce Change: 186065 ServerID: perforce.ravenbrook.com --- mps/manual/source/guide/lang.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/manual/source/guide/lang.rst b/mps/manual/source/guide/lang.rst index 916782424d5..ca57e81a2ec 100644 --- a/mps/manual/source/guide/lang.rst +++ b/mps/manual/source/guide/lang.rst @@ -748,7 +748,7 @@ And third, the global symbol table:: static size_t symtab_size; You tell the MPS how to scan these by writing root scanning functions -of type :c:type:`mps_reg_scan_t`. These functions are similar to the +of type :c:type:`mps_root_scan_t`. These functions are similar to the :ref:`scan method ` in an :term:`object format`, described above. @@ -823,7 +823,7 @@ after the rehash has completed, de-registering the old root by calling :c:func:`mps_root_destroy`. It would be possible to write a root scanning function of type -:c:type:`mps_reg_scan_t`, as described above, to fix the references in +:c:type:`mps_root_scan_t`, as described above, to fix the references in the global symbol table, but the case of a table of references is sufficiently common that the MPS provides a convenient (and optimized) function, :c:func:`mps_root_create_table`, for registering it:: From 814612113433bcbfc6fb642cba0120da5b3843ab Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 13 May 2014 10:57:35 +0100 Subject: [PATCH 191/266] Strength the tear-down advice: you "should" park the arena (not just "good practice"). Copied from Perforce Change: 186066 ServerID: perforce.ravenbrook.com --- mps/manual/source/guide/debug.rst | 7 ++++--- mps/manual/source/guide/lang.rst | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/mps/manual/source/guide/debug.rst b/mps/manual/source/guide/debug.rst index 678cc398593..daf3fb63ae5 100644 --- a/mps/manual/source/guide/debug.rst +++ b/mps/manual/source/guide/debug.rst @@ -86,10 +86,11 @@ General debugging advice handle SIGSEGV pass nostop noprint - On OS X barrier hits do not use signals and so do not enter the debugger. + On these operating systems, you can add this commands to your + ``.gdbinit`` if you always want them to be run. - (On these operating systems, you can add these commands to your - ``.gdbinit`` if you always want them to be run.) + On OS X barrier hits do not use signals and so do not enter the + debugger. .. index:: diff --git a/mps/manual/source/guide/lang.rst b/mps/manual/source/guide/lang.rst index ca57e81a2ec..68473613ba2 100644 --- a/mps/manual/source/guide/lang.rst +++ b/mps/manual/source/guide/lang.rst @@ -1142,28 +1142,28 @@ tracking down the causes, appear in the chapter :ref:`guide-debug`. Tidying up ---------- -When your program is done with the MPS, it's good practice to -:term:`park ` the arena (by calling -:c:func:`mps_arena_park`) and then tear down all the MPS data -structures. This causes the MPS to check the consistency of its data -structures and report any problems it detects. It also causes the MPS -to flush its :term:`telemetry stream`. +When your program is done with the MPS, you should :term:`park ` the arena (by calling :c:func:`mps_arena_park`) to ensure that +no incremental garbage collection is in progress, and then tear down +all the MPS data structures. This causes the MPS to check the +consistency of its data structures and report any problems it detects. +It also causes the MPS to flush its :term:`telemetry stream`. MPS data structures must be destroyed or deregistered in the reverse order to that in which they were registered or created. So you must -destroy all :term:`allocation points` created in a -:term:`pool` before destroying the pool; destroy all :term:`roots` and pools, and deregister all :term:`threads`, that -were created in an :term:`arena` before destroying the arena, and so -on. +destroy all :term:`allocation points` created in a :term:`pool` before +destroying the pool; destroy all :term:`roots` and pools, and +deregister all :term:`threads`, that were created in an :term:`arena` +before destroying the arena, and so on. For example:: mps_arena_park(arena); /* ensure no collection is running */ mps_ap_destroy(obj_ap); /* destroy ap before pool */ mps_pool_destroy(obj_pool); /* destroy pool before fmt */ - mps_fmt_destroy(obj_fmt); /* destroy fmt before arena */ - mps_root_destroy(reg_root); /* destroy root before arena */ + mps_root_destroy(reg_root); /* destroy root before thread */ mps_thread_dereg(thread); /* deregister thread before arena */ + mps_fmt_destroy(obj_fmt); /* destroy fmt before arena */ mps_arena_destroy(arena); /* last of all */ From 0bbc3befd8c94042a1cef9d9db46f14bd6c326ff Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 15 May 2014 17:35:27 +0100 Subject: [PATCH 192/266] Remove unused macros ("unless" and "when"). Copied from Perforce Change: 186120 ServerID: perforce.ravenbrook.com --- mps/code/poolmv2.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index b4ac6913fdf..72774063ed2 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -149,12 +149,6 @@ DEFINE_POOL_CLASS(MVTPoolClass, this) /* Macros */ - -/* .trans.something: the C language sucks */ -#define unless(cond) if (!(cond)) -#define when(cond) if (cond) - - #define Pool2MVT(pool) PARENT(MVTStruct, poolStruct, pool) #define MVT2Pool(mvt) (&(mvt)->poolStruct) From 6080a23791f4ae8b6eb84a2f9490315ecd1e06e9 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 16 May 2014 11:06:24 +0100 Subject: [PATCH 193/266] Update release notes with job003772 and job003773. Copied from Perforce Change: 186126 ServerID: perforce.ravenbrook.com --- mps/manual/source/release.rst | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 0ac53f9020a..9af9d523fe8 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -83,13 +83,26 @@ Other changes .. _job003756: https://www.ravenbrook.com/project/mps/issue/job003756/ -#. :ref:`pool-ams` pools get reliably collected, even in the case - where an AMS pool is the only pool on its generation chain and is - allocating into some generation other than the nursery. See - job003771_. +#. :ref:`pool-ams`, :ref:`pool-awl` and :ref:`pool-lo` pools get + reliably collected, even in the case where the pool is the only + pool on its generation chain and is allocating into some generation + other than the nursery. See job003771_. .. _job003771: https://www.ravenbrook.com/project/mps/issue/job003771/ +#. 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_. + + .. _job003772: https://www.ravenbrook.com/project/mps/issue/job003772/ + +#. All unreachable objects in :ref:`pool-lo` pools are finalized. + (Previously, objects on a segment attached to an allocation point + were not finalized until the allocation point was full.) See + job003773_. + + .. _job003773: https://www.ravenbrook.com/project/mps/issue/job003773/ .. _release-notes-1.113: From 971b4fbdaac593429e80efbd4a48cd6a151701d3 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 16 May 2014 11:17:29 +0100 Subject: [PATCH 194/266] Check for performance regressions before making a release. Copied from Perforce Change: 186127 ServerID: perforce.ravenbrook.com --- mps/procedure/release-build.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mps/procedure/release-build.rst b/mps/procedure/release-build.rst index ee65b5f645d..6624e0b8341 100644 --- a/mps/procedure/release-build.rst +++ b/mps/procedure/release-build.rst @@ -102,6 +102,10 @@ All relative paths are relative to On other platforms they are as shown above. +#. Check that there are no performance regressions by comparing the + benchmarks (``djbench`` and ``gcbench``) for the last release and + this one. + 5. Making the release (automated procedure) ------------------------------------------- From 62eafbbb475a7fc8ba41fed0248506d41381d6ec Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 16 May 2014 12:31:47 +0100 Subject: [PATCH 195/266] Add note about consequences of running frequent collections. Copied from Perforce Change: 186134 ServerID: perforce.ravenbrook.com --- mps/manual/source/guide/debug.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mps/manual/source/guide/debug.rst b/mps/manual/source/guide/debug.rst index daf3fb63ae5..ddc46244c09 100644 --- a/mps/manual/source/guide/debug.rst +++ b/mps/manual/source/guide/debug.rst @@ -66,7 +66,10 @@ General debugging advice result, by having a mode for testing in which you run frequent collections (by calling :c:func:`mps_arena_collect` followed by :c:func:`mps_arena_release`), perhaps as frequently as every - allocation. + allocation. (This will of course make the system run very slowly, + but it ensures that if there are roots or references that are not + being scanned then the failure will occur close in time to the cause, + making it easier to diagnose.) #. .. index:: single: debugger From ca839741cb55598e69053502998dff2ade771512 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 16 May 2014 13:36:52 +0100 Subject: [PATCH 196/266] Be more forceful about the requirement to update the fixed reference. Copied from Perforce Change: 186136 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/scanning.rst | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst index 474ec637dd8..a36da60bf0c 100644 --- a/mps/manual/source/topic/scanning.rst +++ b/mps/manual/source/topic/scanning.rst @@ -60,8 +60,8 @@ region to be scanned. They must carry out the following steps: function as soon as practicable. #. 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. + updated the reference. Make sure that the updated reference is + stored back into the region being scanned. #. Call the macro :c:func:`MPS_SCAN_END` on the scan state. @@ -463,15 +463,18 @@ Fixing interface :term:`Fix` a :term:`reference`. - ``ss`` is the :term:`scan state` that was passed to the scan method. + ``ss`` is the :term:`scan state` that was passed to the + :term:`scan method`. ``ref_io`` points to the reference. - Returns :c:macro:`MPS_RES_OK` if successful: in this case the - reference may have been updated, and the scan method must continue - to scan the :term:`block`. If it returns any other result, the - :term:`scan method` must return that result as soon as possible, - without fixing any further references. + Returns :c:macro:`MPS_RES_OK` if successful. In this case the + reference may have been updated, and so the scan method must store + the updated reference back to the region being scanned. The scan + method must continue to scan the :term:`block`. + + If it returns any other result, the scan method must return that + result as soon as possible, without fixing any further references. This macro must only be used within a :term:`scan method`, between :c:func:`MPS_SCAN_BEGIN` and :c:func:`MPS_SCAN_END`. From b5fa39ff3900b4a8d57d0347a720537ff7d30446 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 17 May 2014 00:26:34 +0100 Subject: [PATCH 197/266] Check meaning of extend_by and remove fixme. Copied from Perforce Change: 186148 ServerID: perforce.ravenbrook.com --- mps/code/dbgpool.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mps/code/dbgpool.c b/mps/code/dbgpool.c index 77c1d6eaf40..75cd14feddc 100644 --- a/mps/code/dbgpool.c +++ b/mps/code/dbgpool.c @@ -190,7 +190,10 @@ static Res DebugPoolInit(Pool pool, ArgList args) /* This pool has to be like the arena control pool: the blocks */ /* allocated must be accessible using void*. */ MPS_ARGS_BEGIN(pcArgs) { - MPS_ARGS_ADD(pcArgs, MPS_KEY_EXTEND_BY, debug->tagSize); /* FIXME: Check this */ + /* By setting EXTEND_BY to debug->tagSize we get the smallest + possible extensions compatible with the tags, and so the + least amount of wasted space. */ + MPS_ARGS_ADD(pcArgs, MPS_KEY_EXTEND_BY, debug->tagSize); MPS_ARGS_ADD(pcArgs, MPS_KEY_MFS_UNIT_SIZE, debug->tagSize); res = PoolCreate(&debug->tagPool, PoolArena(pool), PoolClassMFS(), pcArgs); } MPS_ARGS_END(pcArgs); From f39c3d27ff9efffa7aa2d9b8c2f1890b4a093b00 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 17 May 2014 09:30:45 +0100 Subject: [PATCH 198/266] Documentation improvements suggests by bruce mitchener: * Fix cross-references to mps_pool_debug_option_s * Link pool classes in the header of the table of pool class properties Copied from Perforce Change: 186150 ServerID: perforce.ravenbrook.com --- mps/manual/source/pool/ams.rst | 8 ++--- mps/manual/source/pool/intro.rst | 58 ++++++++++++++++---------------- mps/manual/source/pool/mv.rst | 9 ++--- mps/manual/source/pool/mvff.rst | 8 ++--- 4 files changed, 42 insertions(+), 41 deletions(-) diff --git a/mps/manual/source/pool/ams.rst b/mps/manual/source/pool/ams.rst index ae1d43f8bed..9fb1f9a9103 100644 --- a/mps/manual/source/pool/ams.rst +++ b/mps/manual/source/pool/ams.rst @@ -183,16 +183,16 @@ AMS interface takes three keyword arguments: :c:macro:`MPS_KEY_FORMAT` and :c:macro:`MPS_KEY_CHAIN` are as described above, and :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging - options. See :c:type:`mps_debug_option_s`. + options. See :c:type:`mps_pool_debug_option_s`. .. deprecated:: starting with version 1.112. - When using :c:func:`mps_pool_create`, pass the format, - chain, and debugging options like this:: + 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_class_t mps_class_ams_debug(), - mps_debug_option_s debug_option, + 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/intro.rst b/mps/manual/source/pool/intro.rst index ed8f83b8d4a..7abe7480e9b 100644 --- a/mps/manual/source/pool/intro.rst +++ b/mps/manual/source/pool/intro.rst @@ -100,35 +100,35 @@ it makes no sense to ask whether they may contain :term:`weak references (1)`. -============================================= ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== -Property AMC AMCZ AMS AWL LO MFS MV MVFF MVT SNC -============================================= ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== -Supports :c:func:`mps_alloc`? no no no no no yes yes yes no no -Supports :c:func:`mps_free`? no no no no no yes yes yes yes no -Supports allocation points? yes yes yes yes yes no yes yes yes yes -Supports allocation frames? yes yes yes yes yes no no yes yes yes -Supports segregated allocation caches? no no no no no yes yes yes no no -Timing of collections? [2]_ auto auto auto auto auto --- --- --- --- --- -May contain references? [3]_ yes no yes yes no no no no no yes -May contain exact references? [4]_ yes --- yes yes --- --- --- --- --- yes -May contain ambiguous references? [4]_ no --- no no --- --- --- --- --- no -May contain weak references? [4]_ no --- no yes --- --- --- --- --- no -Allocations fixed or variable in size? var var var var var fixed var var var var -Alignment? [5]_ conf conf conf conf conf [6]_ [6]_ [7]_ [7]_ conf -Dependent objects? [8]_ no --- no yes --- --- --- --- --- no -May use remote references? [9]_ no --- no no --- --- --- --- --- no -Blocks are automatically managed? [10]_ yes yes yes yes yes no no no no no -Blocks are promoted between generations yes yes no no no --- --- --- --- --- -Blocks are manually managed? [10]_ no no no no no yes yes yes yes yes -Blocks are scanned? [11]_ yes no yes yes no no no no no yes -Blocks support base pointers only? [12]_ no no yes yes yes --- --- --- --- yes -Blocks support internal pointers? [12]_ yes yes no no no --- --- --- --- no -Blocks may be protected by barriers? yes no yes yes yes no no no no yes -Blocks may move? yes yes no no no no no no no no -Blocks may be finalized? yes yes yes yes yes no no no no no -Blocks must be formatted? [11]_ yes yes yes yes yes no no no no yes -Blocks may use :term:`in-band headers`? yes yes yes yes yes --- --- --- --- no -============================================= ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== +.. csv-table:: + :header: "Property", ":ref:`AMC `", ":ref:`AMCZ `", ":ref:`AMS `", ":ref:`AWL `", ":ref:`LO `", ":ref:`MFS `", ":ref:`MV `", ":ref:`MVFF `", ":ref:`MVT `", ":ref:`SNC `" + :widths: 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + + Supports :c:func:`mps_alloc`?, no, no, no, no, no, yes, yes, yes, no, no + Supports :c:func:`mps_free`?, no, no, no, no, no, yes, yes, yes, yes, no + Supports allocation points?, yes, yes, yes, yes, yes, no, yes, yes, yes, yes + Supports allocation frames?, yes, yes, yes, yes, yes, no, no, yes, yes, yes + Supports segregated allocation caches?, no, no, no, no, no, yes, yes, yes, no, no + Timing of collections? [2]_, auto, auto, auto, auto, auto, ---, ---, ---, ---, --- + May contain references? [3]_, yes, no, yes, yes, no, no, no, no, no, yes + May contain exact references? [4]_, yes, ---, yes, yes, ---, ---, ---, ---, ---, yes + May contain ambiguous references? [4]_, no, ---, no, no, ---, ---, ---, ---, ---, no + May contain weak references? [4]_, no, ---, no, yes, ---, ---, ---, ---, ---, no + Allocations fixed or variable in size?, var, var, var, var, var, fixed, var, var, var, var + Alignment? [5]_, conf, conf, conf, conf, conf, [6]_, [6]_, [7]_, [7]_, conf + Dependent objects? [8]_, no, ---, no, yes, ---, ---, ---, ---, ---, no + May use remote references? [9]_, no, ---, no, no, ---, ---, ---, ---, ---, no + Blocks are automatically managed? [10]_, yes, yes, yes, yes, yes, no, no, no, no, no + Blocks are promoted between generations, yes, yes, no, no, no, ---, ---, ---, ---, --- + Blocks are manually managed? [10]_, no, no, no, no, no, yes, yes, yes, yes, yes + Blocks are scanned? [11]_, yes, no, yes, yes, no, no, no, no, no, yes + Blocks support base pointers only? [12]_, no, no, yes, yes, yes, ---, ---, ---, ---, yes + Blocks support internal pointers? [12]_, yes, yes, no, no, no, ---, ---, ---, ---, no + Blocks may be protected by barriers?, yes, no, yes, yes, yes, no, no, no, no, yes + Blocks may move?, yes, yes, no, no, no, no, no, no, no, no + Blocks may be finalized?, yes, yes, yes, yes, yes, no, no, no, no, no + Blocks must be formatted? [11]_, yes, yes, yes, yes, yes, no, no, no, no, yes + Blocks may use :term:`in-band headers`?, yes, yes, yes, yes, yes, ---, ---, ---, ---, no .. note:: diff --git a/mps/manual/source/pool/mv.rst b/mps/manual/source/pool/mv.rst index 361cd41c0b5..d24ce3f273f 100644 --- a/mps/manual/source/pool/mv.rst +++ b/mps/manual/source/pool/mv.rst @@ -122,16 +122,17 @@ MV interface takes four keyword arguments: :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`. + 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 debugging - options, segment size, mean size, and maximum size like this:: + 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_class_t mps_class_mv_debug(), - mps_debug_option_s debug_option, + mps_pool_debug_option_s debug_option, mps_size_t extend_size, mps_size_t average_size, mps_size_t maximum_size) diff --git a/mps/manual/source/pool/mvff.rst b/mps/manual/source/pool/mvff.rst index e688a00d09d..954a860fc63 100644 --- a/mps/manual/source/pool/mvff.rst +++ b/mps/manual/source/pool/mvff.rst @@ -201,16 +201,16 @@ MVFF interface :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_debug_option_s`. + options. See :c:type:`mps_pool_debug_option_s`. .. deprecated:: starting with version 1.112. - When using :c:func:`mps_pool_create`, pass the debugging - options, and other arguments like this:: + 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_class_t mps_class_mvff_debug(), - mps_debug_option_s debug_option, + mps_pool_debug_option_s debug_option, size_t extend_size, size_t average_size, mps_align_t alignment, From 9c3eb68f97a0cf2f14fa2ffbf95cb6d04afca8c7 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 18 May 2014 22:46:16 +0100 Subject: [PATCH 199/266] Landiterate now returns a bool indicating whether all visitor calls returned true. Copied from Perforce Change: 186165 ServerID: perforce.ravenbrook.com --- mps/code/cbs.c | 6 +++--- mps/code/failover.c | 6 +++--- mps/code/freelist.c | 5 +++-- mps/code/land.c | 10 ++++++---- mps/code/mpm.h | 2 +- mps/code/mpmtypes.h | 2 +- mps/design/land.txt | 6 ++++-- 7 files changed, 21 insertions(+), 16 deletions(-) diff --git a/mps/code/cbs.c b/mps/code/cbs.c index 383ac47c472..c7b4478ce4c 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -748,7 +748,7 @@ static Bool cbsIterateVisit(Tree tree, void *closureP, Size closureS) return TRUE; } -static void cbsIterate(Land land, LandVisitor visitor, +static Bool cbsIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) { CBS cbs; @@ -769,8 +769,8 @@ static void cbsIterate(Land land, LandVisitor visitor, closure.visitor = visitor; closure.closureP = closureP; closure.closureS = closureS; - (void)TreeTraverse(SplayTreeRoot(splay), splay->compare, splay->nodeKey, - cbsIterateVisit, &closure, 0); + return TreeTraverse(SplayTreeRoot(splay), splay->compare, splay->nodeKey, + cbsIterateVisit, &closure, 0); } diff --git a/mps/code/failover.c b/mps/code/failover.c index e8a0dbc7dae..80ecb0a6210 100644 --- a/mps/code/failover.c +++ b/mps/code/failover.c @@ -164,7 +164,7 @@ static Res failoverDelete(Range rangeReturn, Land land, Range range) } -static void failoverIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) +static Bool failoverIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) { Failover fo; @@ -173,8 +173,8 @@ static void failoverIterate(Land land, LandVisitor visitor, void *closureP, Size AVERT(Failover, fo); AVER(visitor != NULL); - LandIterate(fo->primary, visitor, closureP, closureS); - LandIterate(fo->secondary, visitor, closureP, closureS); + return LandIterate(fo->primary, visitor, closureP, closureS) + && LandIterate(fo->secondary, visitor, closureP, closureS); } diff --git a/mps/code/freelist.c b/mps/code/freelist.c index 1e071e06763..241f08ff190 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -438,7 +438,7 @@ static Res freelistDelete(Range rangeReturn, Land land, Range range) } -static void freelistIterate(Land land, LandVisitor visitor, +static Bool freelistIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) { Freelist fl; @@ -468,8 +468,9 @@ static void freelistIterate(Land land, LandVisitor visitor, } cur = next; if (!cont) - break; + return FALSE; } + return TRUE; } diff --git a/mps/code/land.c b/mps/code/land.c index 9ff8257151c..7221514fff3 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -233,15 +233,17 @@ Res LandDelete(Range rangeReturn, Land land, Range range) * See */ -void LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) +Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) { + Bool res; AVERT(Land, land); AVER(FUNCHECK(visitor)); landEnter(land); - (*land->class->iterate)(land, visitor, closureP, closureS); + res = (*land->class->iterate)(land, visitor, closureP, closureS); landLeave(land); + return res; } @@ -503,13 +505,13 @@ static Res landNoDelete(Range rangeReturn, Land land, Range range) return ResUNIMPL; } -static void landNoIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) +static Bool landNoIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) { AVERT(Land, land); AVER(visitor != NULL); UNUSED(closureP); UNUSED(closureS); - NOOP; + return FALSE; } static Bool landNoFind(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 9d5854b8cf6..0a87b8fc81d 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -1014,7 +1014,7 @@ 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 void LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS); +extern Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS); 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 04f73a7e42d..d81255c974d 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -272,7 +272,7 @@ 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)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS); -typedef void (*LandIterateMethod)(Land land, LandVisitor visitor, void *closureP, Size closureS); +typedef Bool (*LandIterateMethod)(Land land, LandVisitor visitor, void *closureP, Size closureS); typedef Bool (*LandFindMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete); typedef Res (*LandFindInZonesMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high); typedef Res (*LandDescribeMethod)(Land land, mps_lib_FILE *stream); diff --git a/mps/design/land.txt b/mps/design/land.txt index 11f192fa6ff..3ed8b466b0d 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -164,13 +164,15 @@ strategy. _`.function.delete.alias`: It is acceptable for ``rangeReturn`` and ``range`` to share storage. -``void LandIterate(Land land, LandIterateMethod iterate, void *closureP, Size closureS)`` +``Bool LandIterate(Land land, LandIterateMethod iterate, void *closureP, Size closureS)`` _`.function.iterate`: ``LandIterate()`` is the function used to iterate all isolated contiguous ranges in a land. It receives a pointer, ``Size`` closure pair to pass on to the iterator method, and an iterator method to invoke on every range. If the iterator method -returns ``FALSE``, then the iteration is terminated. +returns ``FALSE``, then the iteration is terminated and +``LandIterate()`` returns ``FALSE``. If all iterator method calls +return ``TRUE``, then ``LandIterate()`` returns ``TRUE`` ``Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)`` From ac89be651905f27d24902c3281643076242cc453 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 18 May 2014 22:50:22 +0100 Subject: [PATCH 200/266] Ignore or use the result of landiterate. Copied from Perforce Change: 186166 ServerID: perforce.ravenbrook.com --- mps/code/freelist.c | 2 +- mps/code/land.c | 4 ++-- mps/code/landtest.c | 2 +- mps/code/poolmv2.c | 9 ++------- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/mps/code/freelist.c b/mps/code/freelist.c index 241f08ff190..4040630b1c0 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -749,7 +749,7 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream) " listSize = $U\n", (WriteFU)fl->listSize, NULL); - LandIterate(land, freelistDescribeVisitor, stream, 0); + (void)LandIterate(land, freelistDescribeVisitor, stream, 0); res = WriteF(stream, "}\n", NULL); return res; diff --git a/mps/code/land.c b/mps/code/land.c index 7221514fff3..c0f5f2c1cbc 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -416,7 +416,7 @@ void LandFlush(Land dest, Land src) AVERT(Land, dest); AVERT(Land, src); - LandIterate(src, landFlushVisitor, dest, 0); + (void)LandIterate(src, landFlushVisitor, dest, 0); } @@ -485,7 +485,7 @@ static Bool landSizeVisitor(Bool *deleteReturn, Land land, Range range, Size LandSlowSize(Land land) { Size size = 0; - LandIterate(land, landSizeVisitor, &size, 0); + (void)LandIterate(land, landSizeVisitor, &size, 0); return size; } diff --git a/mps/code/landtest.c b/mps/code/landtest.c index ef13e196600..988b4be9391 100644 --- a/mps/code/landtest.c +++ b/mps/code/landtest.c @@ -115,7 +115,7 @@ static void check(TestState state) closure.limit = addrOfIndex(state, ArraySize); closure.oldLimit = state->block; - LandIterate(state->land, checkVisitor, (void *)&closure, 0); + (void)LandIterate(state->land, checkVisitor, (void *)&closure, 0); if (closure.oldLimit == state->block) Insist(BTIsSetRange(state->allocTable, 0, diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index 45a38592946..e8b38489253 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -1240,7 +1240,7 @@ static void MVTRefillABQIfEmpty(MVT mvt, Size size) if (mvt->abqOverflow && ABQIsEmpty(MVTABQ(mvt))) { mvt->abqOverflow = FALSE; METER_ACC(mvt->refills, size); - LandIterate(MVTFailover(mvt), &MVTRefillVisitor, mvt, 0); + (void)LandIterate(MVTFailover(mvt), &MVTRefillVisitor, mvt, 0); } } @@ -1250,7 +1250,6 @@ static void MVTRefillABQIfEmpty(MVT mvt, Size size) typedef struct MVTContigencyClosureStruct { MVT mvt; - Bool found; RangeStruct range; Arena arena; Size min; @@ -1287,7 +1286,6 @@ static Bool MVTContingencyVisitor(Bool *deleteReturn, Land land, Range range, /* verify that min will fit when seg-aligned */ if (size >= 2 * cl->min) { RangeInit(&cl->range, base, limit); - cl->found = TRUE; return FALSE; } @@ -1295,7 +1293,6 @@ static Bool MVTContingencyVisitor(Bool *deleteReturn, Land land, Range range, cl->hardSteps++; if (MVTCheckFit(base, limit, cl->min, cl->arena)) { RangeInit(&cl->range, base, limit); - cl->found = TRUE; return FALSE; } @@ -1309,14 +1306,12 @@ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn, MVTContigencyClosureStruct cls; cls.mvt = mvt; - cls.found = FALSE; cls.arena = PoolArena(MVT2Pool(mvt)); cls.min = min; cls.steps = 0; cls.hardSteps = 0; - LandIterate(MVTFailover(mvt), MVTContingencyVisitor, (void *)&cls, 0); - if (!cls.found) + if (LandIterate(MVTFailover(mvt), MVTContingencyVisitor, (void *)&cls, 0)) return FALSE; AVER(RangeSize(&cls.range) >= min); From 6dec3e4cec46c39b9b8518772318d3a84f1b6474 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 19 May 2014 10:55:48 +0100 Subject: [PATCH 201/266] Correct dependencies for benchmarks and event tools. Copied from Perforce Change: 186171 ServerID: perforce.ravenbrook.com --- mps/code/comm.gmk | 60 ++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index 4fb69b9ea1e..c90473c5eb8 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -163,12 +163,11 @@ FMTDYTST = fmtdy.c fmtno.c fmtdytst.c FMTHETST = fmthe.c fmtdy.c fmtno.c fmtdytst.c FMTSCM = fmtscheme.c PLINTH = mpsliban.c mpsioan.c -EVENTPROC = eventcnv.c table.c MPMCOMMON = abq.c arena.c arenacl.c arenavm.c arg.c boot.c bt.c \ buffer.c cbs.c dbgpool.c dbgpooli.c event.c format.c freelist.c \ global.c ld.c locus.c message.c meter.c mpm.c mpsi.c nailboard.c \ pool.c poolabs.c poolmfs.c poolmrg.c poolmv.c protocol.c range.c \ - ref.c reserv.c ring.c root.c sa.c sac.c seg.c shield.c splay.c ss.c \ + ref.c reserv.c ring.c root.c sa.c sac.c seg.c shield.c splay.c ss.c \ table.c trace.c traceanc.c tract.c tree.c walk.c MPM = $(MPMCOMMON) $(MPMPF) @@ -182,40 +181,22 @@ MPM = $(MPMCOMMON) $(MPMPF) ifdef VARIETY MPMOBJ = $(MPM:%.c=$(PFM)/$(VARIETY)/%.o) \ $(MPMS:%.s=$(PFM)/$(VARIETY)/%.o) -MPMDEP = $(MPM:%.c=$(PFM)/$(VARIETY)/%.d) AMCOBJ = $(AMC:%.c=$(PFM)/$(VARIETY)/%.o) -AMCDEP = $(AMC:%.c=$(PFM)/$(VARIETY)/%.d) AMSOBJ = $(AMS:%.c=$(PFM)/$(VARIETY)/%.o) -AMSDEP = $(AMS:%.c=$(PFM)/$(VARIETY)/%.d) AWLOBJ = $(AWL:%.c=$(PFM)/$(VARIETY)/%.o) -AWLDEP = $(AWL:%.c=$(PFM)/$(VARIETY)/%.d) LOOBJ = $(LO:%.c=$(PFM)/$(VARIETY)/%.o) -LODEP = $(LO:%.c=$(PFM)/$(VARIETY)/%.d) SNCOBJ = $(SNC:%.c=$(PFM)/$(VARIETY)/%.o) -SNCDEP = $(SNC:%.c=$(PFM)/$(VARIETY)/%.d) POOLNOBJ = $(POOLN:%.c=$(PFM)/$(VARIETY)/%.o) -POOLNDEP = $(POOLN:%.c=$(PFM)/$(VARIETY)/%.d) MV2OBJ = $(MV2:%.c=$(PFM)/$(VARIETY)/%.o) -MV2DEP = $(MV2:%.c=$(PFM)/$(VARIETY)/%.d) MVFFOBJ = $(MVFF:%.c=$(PFM)/$(VARIETY)/%.o) -MVFFDEP = $(MVFF:%.c=$(PFM)/$(VARIETY)/%.d) TESTLIBOBJ = $(TESTLIB:%.c=$(PFM)/$(VARIETY)/%.o) -TESTLIBDEP = $(TESTLIB:%.c=$(PFM)/$(VARIETY)/%.d) TESTTHROBJ = $(TESTTHR:%.c=$(PFM)/$(VARIETY)/%.o) -TESTTHRDEP = $(TESTTHR:%.c=$(PFM)/$(VARIETY)/%.d) FMTDYOBJ = $(FMTDY:%.c=$(PFM)/$(VARIETY)/%.o) -FMTDYDEP = $(FMTDY:%.c=$(PFM)/$(VARIETY)/%.d) FMTDYTSTOBJ = $(FMTDYTST:%.c=$(PFM)/$(VARIETY)/%.o) -FMTDYTSTDEP = $(FMTDYTST:%.c=$(PFM)/$(VARIETY)/%.d) FMTHETSTOBJ = $(FMTHETST:%.c=$(PFM)/$(VARIETY)/%.o) -FMTHETSTDEP = $(FMTHETST:%.c=$(PFM)/$(VARIETY)/%.d) FMTSCMOBJ = $(FMTSCM:%.c=$(PFM)/$(VARIETY)/%.o) -FMTSCMDEP = $(FMTSCM:%.c=$(PFM)/$(VARIETY)/%.d) PLINTHOBJ = $(PLINTH:%.c=$(PFM)/$(VARIETY)/%.o) -PLINTHDEP = $(PLINTH:%.c=$(PFM)/$(VARIETY)/%.d) -EVENTPROCOBJ = $(EVENTPROC:%.c=$(PFM)/$(VARIETY)/%.o) -EVENTPROCDEP = $(EVENTPROC:%.c=$(PFM)/$(VARIETY)/%.d) endif @@ -423,7 +404,7 @@ $(PFM)/$(VARIETY)/bttest: $(PFM)/$(VARIETY)/bttest.o \ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a $(PFM)/$(VARIETY)/djbench: $(PFM)/$(VARIETY)/djbench.o \ - $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)/$(VARIETY)/mps.a + $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)/$(VARIETY)/exposet0: $(PFM)/$(VARIETY)/exposet0.o \ $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a @@ -444,7 +425,7 @@ $(PFM)/$(VARIETY)/fotest: $(PFM)/$(VARIETY)/fotest.o \ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a $(PFM)/$(VARIETY)/gcbench: $(PFM)/$(VARIETY)/gcbench.o \ - $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)/$(VARIETY)/mps.a + $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)/$(VARIETY)/locbwcss: $(PFM)/$(VARIETY)/locbwcss.o \ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a @@ -580,22 +561,27 @@ else ifeq ($(VARIETY),hot) include $(PFM)/$(VARIETY)/mps.d else -# %%PART: When adding a new part, add the dependency file macro for the new -# part here. +# %%PART: When adding a new part, add the dependencies file for the +# new part here. include \ - $(MPMDEP) \ - $(AMCDEP) \ - $(AMSDEP) \ - $(AWLDEP) \ - $(EVENTPROCDEP) \ - $(FMTDYDEP) \ - $(FMTDYTSTDEP) \ - $(FMTHETSTDEP) \ - $(FMTSCMDEP) \ - $(LODEP) \ - $(PLINTHDEP) \ - $(POOLNDEP) \ - $(TESTLIBDEP) + $(AMC:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(AMS:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(AWL:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(FMTDY:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(FMTDYTST:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(FMTHETST:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(FMTSCM:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(LO:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(MPM:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(MV2:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(MVFF:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(PLINTH:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(POOLN:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(SNC:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(TESTLIB:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(TESTTHR:%.c=$(PFM)/$(VARIETY)/%.d) \ + $(EXTRA_TARGETS:mps%=$(PFM)/$(VARIETY)/%.d) \ + $(TEST_TARGETS:%=$(PFM)/$(VARIETY)/%.d) endif endif From f5547fb7388f896ef1f068931458589119f44b60 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 19 May 2014 11:39:05 +0100 Subject: [PATCH 202/266] Don't include pooln.c in mps.c -- only used by test case poolncv. Include dependencies in all varieties, not just in COOL. Copied from Perforce Change: 186174 ServerID: perforce.ravenbrook.com --- mps/code/comm.gmk | 45 +++++++++++++++------------------------------ mps/code/mps.c | 1 - 2 files changed, 15 insertions(+), 31 deletions(-) diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index c90473c5eb8..af5718c6caf 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -169,7 +169,7 @@ MPMCOMMON = abq.c arena.c arenacl.c arenavm.c arg.c boot.c bt.c \ pool.c poolabs.c poolmfs.c poolmrg.c poolmv.c protocol.c range.c \ ref.c reserv.c ring.c root.c sa.c sac.c seg.c shield.c splay.c ss.c \ table.c trace.c traceanc.c tract.c tree.c walk.c -MPM = $(MPMCOMMON) $(MPMPF) +MPM = $(MPMCOMMON) $(MPMPF) $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(PLINTH) # These map the source file lists onto object files and dependency files @@ -181,22 +181,16 @@ MPM = $(MPMCOMMON) $(MPMPF) ifdef VARIETY MPMOBJ = $(MPM:%.c=$(PFM)/$(VARIETY)/%.o) \ $(MPMS:%.s=$(PFM)/$(VARIETY)/%.o) -AMCOBJ = $(AMC:%.c=$(PFM)/$(VARIETY)/%.o) -AMSOBJ = $(AMS:%.c=$(PFM)/$(VARIETY)/%.o) -AWLOBJ = $(AWL:%.c=$(PFM)/$(VARIETY)/%.o) -LOOBJ = $(LO:%.c=$(PFM)/$(VARIETY)/%.o) -SNCOBJ = $(SNC:%.c=$(PFM)/$(VARIETY)/%.o) -POOLNOBJ = $(POOLN:%.c=$(PFM)/$(VARIETY)/%.o) -MV2OBJ = $(MV2:%.c=$(PFM)/$(VARIETY)/%.o) -MVFFOBJ = $(MVFF:%.c=$(PFM)/$(VARIETY)/%.o) - -TESTLIBOBJ = $(TESTLIB:%.c=$(PFM)/$(VARIETY)/%.o) -TESTTHROBJ = $(TESTTHR:%.c=$(PFM)/$(VARIETY)/%.o) FMTDYOBJ = $(FMTDY:%.c=$(PFM)/$(VARIETY)/%.o) FMTDYTSTOBJ = $(FMTDYTST:%.c=$(PFM)/$(VARIETY)/%.o) FMTHETSTOBJ = $(FMTHETST:%.c=$(PFM)/$(VARIETY)/%.o) FMTSCMOBJ = $(FMTSCM:%.c=$(PFM)/$(VARIETY)/%.o) +MV2OBJ = $(MV2:%.c=$(PFM)/$(VARIETY)/%.o) +MVFFOBJ = $(MVFF:%.c=$(PFM)/$(VARIETY)/%.o) PLINTHOBJ = $(PLINTH:%.c=$(PFM)/$(VARIETY)/%.o) +POOLNOBJ = $(POOLN:%.c=$(PFM)/$(VARIETY)/%.o) +TESTLIBOBJ = $(TESTLIB:%.c=$(PFM)/$(VARIETY)/%.o) +TESTTHROBJ = $(TESTTHR:%.c=$(PFM)/$(VARIETY)/%.o) endif @@ -344,10 +338,7 @@ endif $(PFM)/rash/mps.a: $(PFM)/rash/mps.o $(PFM)/hot/mps.a: $(PFM)/hot/mps.o - -$(PFM)/cool/mps.a: \ - $(MPMOBJ) $(AMCOBJ) $(AMSOBJ) $(AWLOBJ) $(LOOBJ) $(SNCOBJ) \ - $(MV2OBJ) $(MVFFOBJ) $(PLINTHOBJ) $(POOLNOBJ) +$(PFM)/cool/mps.a: $(MPMOBJ) # OTHER GENUINE TARGETS @@ -458,7 +449,7 @@ $(PFM)/$(VARIETY)/nailboardtest: $(PFM)/$(VARIETY)/nailboardtest.o \ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a $(PFM)/$(VARIETY)/poolncv: $(PFM)/$(VARIETY)/poolncv.o \ - $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a + $(POOLNOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a $(PFM)/$(VARIETY)/qs: $(PFM)/$(VARIETY)/qs.o \ $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a @@ -561,34 +552,28 @@ else ifeq ($(VARIETY),hot) include $(PFM)/$(VARIETY)/mps.d else +include $(MPM:%.c=$(PFM)/$(VARIETY)/%.d) +endif # VARIETY != hot +endif # VARIETY != rash + # %%PART: When adding a new part, add the dependencies file for the # new part here. include \ - $(AMC:%.c=$(PFM)/$(VARIETY)/%.d) \ - $(AMS:%.c=$(PFM)/$(VARIETY)/%.d) \ - $(AWL:%.c=$(PFM)/$(VARIETY)/%.d) \ $(FMTDY:%.c=$(PFM)/$(VARIETY)/%.d) \ $(FMTDYTST:%.c=$(PFM)/$(VARIETY)/%.d) \ $(FMTHETST:%.c=$(PFM)/$(VARIETY)/%.d) \ $(FMTSCM:%.c=$(PFM)/$(VARIETY)/%.d) \ - $(LO:%.c=$(PFM)/$(VARIETY)/%.d) \ - $(MPM:%.c=$(PFM)/$(VARIETY)/%.d) \ - $(MV2:%.c=$(PFM)/$(VARIETY)/%.d) \ - $(MVFF:%.c=$(PFM)/$(VARIETY)/%.d) \ $(PLINTH:%.c=$(PFM)/$(VARIETY)/%.d) \ $(POOLN:%.c=$(PFM)/$(VARIETY)/%.d) \ - $(SNC:%.c=$(PFM)/$(VARIETY)/%.d) \ $(TESTLIB:%.c=$(PFM)/$(VARIETY)/%.d) \ $(TESTTHR:%.c=$(PFM)/$(VARIETY)/%.d) \ $(EXTRA_TARGETS:mps%=$(PFM)/$(VARIETY)/%.d) \ $(TEST_TARGETS:%=$(PFM)/$(VARIETY)/%.d) -endif -endif -endif -endif +endif # !defined TARGET +endif # !defined VARIETY -endif +endif # !defined gendep # Library diff --git a/mps/code/mps.c b/mps/code/mps.c index 200f63e894c..9f217c15791 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -85,7 +85,6 @@ #include "poolawl.c" #include "poollo.c" #include "poolsnc.c" -#include "pooln.c" #include "poolmv2.c" #include "poolmvff.c" From c381033485fd95f05ff9d1f2eae47be436df1cac Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 19 May 2014 15:39:18 +0100 Subject: [PATCH 203/266] Add test suite support to xcode project. Copied from Perforce Change: 186186 ServerID: perforce.ravenbrook.com --- mps/code/mps.xcodeproj/project.pbxproj | 286 ++++++++++++++++++++++++- 1 file changed, 284 insertions(+), 2 deletions(-) diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index 29e47139571..60bd70789ac 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -7,6 +7,54 @@ objects = { /* Begin PBXAggregateTarget section */ + 2215A9A9192A47BB00E9E2CE /* testci */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 2215A9AD192A47BB00E9E2CE /* Build configuration list for PBXAggregateTarget "testci" */; + buildPhases = ( + 2215A9AC192A47BB00E9E2CE /* ShellScript */, + ); + dependencies = ( + 2215A9AA192A47BB00E9E2CE /* PBXTargetDependency */, + ); + name = testci; + productName = testrun; + }; + 2215A9B1192A47C500E9E2CE /* testansi */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 2215A9B5192A47C500E9E2CE /* Build configuration list for PBXAggregateTarget "testansi" */; + buildPhases = ( + 2215A9B4192A47C500E9E2CE /* ShellScript */, + ); + dependencies = ( + 2215A9B2192A47C500E9E2CE /* PBXTargetDependency */, + ); + name = testansi; + productName = testrun; + }; + 2215A9B9192A47CE00E9E2CE /* testall */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 2215A9BD192A47CE00E9E2CE /* Build configuration list for PBXAggregateTarget "testall" */; + buildPhases = ( + 2215A9BC192A47CE00E9E2CE /* ShellScript */, + ); + dependencies = ( + 2215A9BA192A47CE00E9E2CE /* PBXTargetDependency */, + ); + name = testall; + productName = testrun; + }; + 2215A9C1192A47D500E9E2CE /* testpoll */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpoll" */; + buildPhases = ( + 2215A9C4192A47D500E9E2CE /* ShellScript */, + ); + dependencies = ( + 2215A9C2192A47D500E9E2CE /* PBXTargetDependency */, + ); + name = testpoll; + productName = testrun; + }; 22CDE8EF16E9E97D00366D0A /* testrun */ = { isa = PBXAggregateTarget; buildConfigurationList = 22CDE8F016E9E97E00366D0A /* Build configuration list for PBXAggregateTarget "testrun" */; @@ -79,6 +127,7 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 2215A9C9192A495F00E9E2CE /* pooln.c in Sources */ = {isa = PBXBuildFile; fileRef = 22FACEDE18880933000FDBC1 /* pooln.c */; }; 2231BB5118CA97D8002D6322 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; 2231BB5318CA97D8002D6322 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; 2231BB5F18CA97DC002D6322 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; @@ -287,6 +336,34 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 2215A9AB192A47BB00E9E2CE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3104AFF1156D37A0000A585A; + remoteInfo = all; + }; + 2215A9B3192A47C500E9E2CE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3104AFF1156D37A0000A585A; + remoteInfo = all; + }; + 2215A9BB192A47CE00E9E2CE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3104AFF1156D37A0000A585A; + remoteInfo = all; + }; + 2215A9C3192A47D500E9E2CE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3104AFF1156D37A0000A585A; + remoteInfo = all; + }; 2231BB4E18CA97D8002D6322 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; @@ -3311,6 +3388,10 @@ projectRoot = ""; targets = ( 3104AFF1156D37A0000A585A /* all */, + 2215A9B9192A47CE00E9E2CE /* testall */, + 2215A9B1192A47C500E9E2CE /* testansi */, + 2215A9A9192A47BB00E9E2CE /* testci */, + 2215A9C1192A47D500E9E2CE /* testpoll */, 22CDE8EF16E9E97D00366D0A /* testrun */, 31EEABFA156AAF9D00714D05 /* mps */, 3114A632156E94DB001E0AA3 /* abqtest */, @@ -3364,6 +3445,62 @@ /* End PBXProject section */ /* Begin PBXShellScriptBuildPhase section */ + 2215A9AC192A47BB00E9E2CE /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + showEnvVarsInLog = 0; + }; + 2215A9B4192A47C500E9E2CE /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + showEnvVarsInLog = 0; + }; + 2215A9BC192A47CE00E9E2CE /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + showEnvVarsInLog = 0; + }; + 2215A9C4192A47D500E9E2CE /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + showEnvVarsInLog = 0; + }; 22CDE8F416E9E9D400366D0A /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -3375,7 +3512,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\"\n"; + shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -3791,8 +3928,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 31D60048156D3ECF00337B26 /* testlib.c in Sources */, + 2215A9C9192A495F00E9E2CE /* pooln.c in Sources */, 31D6004B156D3EE600337B26 /* poolncv.c in Sources */, + 31D60048156D3ECF00337B26 /* testlib.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3876,6 +4014,26 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 2215A9AA192A47BB00E9E2CE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3104AFF1156D37A0000A585A /* all */; + targetProxy = 2215A9AB192A47BB00E9E2CE /* PBXContainerItemProxy */; + }; + 2215A9B2192A47C500E9E2CE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3104AFF1156D37A0000A585A /* all */; + targetProxy = 2215A9B3192A47C500E9E2CE /* PBXContainerItemProxy */; + }; + 2215A9BA192A47CE00E9E2CE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3104AFF1156D37A0000A585A /* all */; + targetProxy = 2215A9BB192A47CE00E9E2CE /* PBXContainerItemProxy */; + }; + 2215A9C2192A47D500E9E2CE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3104AFF1156D37A0000A585A /* all */; + targetProxy = 2215A9C3192A47D500E9E2CE /* PBXContainerItemProxy */; + }; 2231BB4D18CA97D8002D6322 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 31EEABFA156AAF9D00714D05 /* mps */; @@ -4319,6 +4477,90 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ + 2215A9AE192A47BB00E9E2CE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testrun copy"; + }; + name = Debug; + }; + 2215A9AF192A47BB00E9E2CE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testrun copy"; + }; + name = Release; + }; + 2215A9B0192A47BB00E9E2CE /* RASH */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testrun copy"; + }; + name = RASH; + }; + 2215A9B6192A47C500E9E2CE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testci copy"; + }; + name = Debug; + }; + 2215A9B7192A47C500E9E2CE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testci copy"; + }; + name = Release; + }; + 2215A9B8192A47C500E9E2CE /* RASH */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testci copy"; + }; + name = RASH; + }; + 2215A9BE192A47CE00E9E2CE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testansi copy"; + }; + name = Debug; + }; + 2215A9BF192A47CE00E9E2CE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testansi copy"; + }; + name = Release; + }; + 2215A9C0192A47CE00E9E2CE /* RASH */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testansi copy"; + }; + name = RASH; + }; + 2215A9C6192A47D500E9E2CE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testall copy"; + }; + name = Debug; + }; + 2215A9C7192A47D500E9E2CE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testall copy"; + }; + name = Release; + }; + 2215A9C8192A47D500E9E2CE /* RASH */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "testall copy"; + }; + name = RASH; + }; 2231BB5618CA97D8002D6322 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5532,6 +5774,46 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 2215A9AD192A47BB00E9E2CE /* Build configuration list for PBXAggregateTarget "testci" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2215A9AE192A47BB00E9E2CE /* Debug */, + 2215A9AF192A47BB00E9E2CE /* Release */, + 2215A9B0192A47BB00E9E2CE /* RASH */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2215A9B5192A47C500E9E2CE /* Build configuration list for PBXAggregateTarget "testansi" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2215A9B6192A47C500E9E2CE /* Debug */, + 2215A9B7192A47C500E9E2CE /* Release */, + 2215A9B8192A47C500E9E2CE /* RASH */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2215A9BD192A47CE00E9E2CE /* Build configuration list for PBXAggregateTarget "testall" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2215A9BE192A47CE00E9E2CE /* Debug */, + 2215A9BF192A47CE00E9E2CE /* Release */, + 2215A9C0192A47CE00E9E2CE /* RASH */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpoll" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2215A9C6192A47D500E9E2CE /* Debug */, + 2215A9C7192A47D500E9E2CE /* Release */, + 2215A9C8192A47D500E9E2CE /* RASH */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 2231BB5518CA97D8002D6322 /* Build configuration list for PBXNativeTarget "locbwcss" */ = { isa = XCConfigurationList; buildConfigurations = ( From c974c43840c00403a113cc50ec6cabf3194507e1 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 19 May 2014 15:40:31 +0100 Subject: [PATCH 204/266] New tool noaslr disables address space layout randomization on os x. Copied from Perforce Change: 186187 ServerID: perforce.ravenbrook.com --- mps/tool/noaslr.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 mps/tool/noaslr.c diff --git a/mps/tool/noaslr.c b/mps/tool/noaslr.c new file mode 100644 index 00000000000..2a174941882 --- /dev/null +++ b/mps/tool/noaslr.c @@ -0,0 +1,97 @@ +/* noaslr.c: Disable ASLR on OS X Mavericks + * + * $Id: //info.ravenbrook.com/project/mps/master/code/eventcnv.c#26 $ + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * + * This is a command-line tool that runs another program with address + * space layout randomization (ASLR) disabled. + * + * The technique is taken from GDB via "How gdb disables ASLR in Mac + * OS X Lion" + * + * + * On OS X Mavericks, the _POSIX_SPAWN_DISABLE_ASLR constant is not + * defined in any header, but the LLDB sources reveal its value, and + * experimentally this value works. + * + */ + +#include +#include +#include +#include + +#ifndef _POSIX_SPAWN_DISABLE_ASLR +#define _POSIX_SPAWN_DISABLE_ASLR 0x100 +#endif + +int main(int argc, char **argv) +{ + extern char **environ; + pid_t pid; + posix_spawnattr_t attr; + int res, status = 1; + char *default_argv[] = {"/bin/sh", NULL}; + + if (argc >= 2) + ++ argv; + else + argv = default_argv; + + res = posix_spawnattr_init(&attr); + if (res != 0) + return res; + + res = posix_spawnattr_setflags(&attr, _POSIX_SPAWN_DISABLE_ASLR); + if (res != 0) + return res; + + res = posix_spawn(&pid, argv[0], NULL, &attr, argv, environ); + if (res != 0) + return res; + + (void)waitpid(pid, &status, 0); + return status; +} + + +/* 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 43d30e9ca38529dd86b91384f0ad153458af014b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 19 May 2014 15:41:20 +0100 Subject: [PATCH 205/266] Gcbench now reports the number of chunks. Copied from Perforce Change: 186188 ServerID: perforce.ravenbrook.com --- mps/code/gcbench.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c index c958128ce4f..733dc0a925b 100644 --- a/mps/code/gcbench.c +++ b/mps/code/gcbench.c @@ -12,6 +12,7 @@ #include "testthr.h" #include "fmtdy.h" #include "fmtdytst.h" +#include "mpm.h" #include /* fprintf, printf, putchars, sscanf, stderr, stdout */ #include /* alloca, exit, EXIT_FAILURE, EXIT_SUCCESS, strtoul */ @@ -244,6 +245,7 @@ static void arena_setup(gcthread_fn_t fn, } MPS_ARGS_END(args); watch(fn, name); mps_arena_park(arena); + printf("%u chunks\n", (unsigned)RingLength(&arena->chunkRing)); mps_pool_destroy(pool); mps_fmt_destroy(format); if (ngen > 0) From 0801758b6f57483a37b23e5d19320be17acde586 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 19 May 2014 16:07:24 +0100 Subject: [PATCH 206/266] Fix typo. Copied from Perforce Change: 186192 ServerID: perforce.ravenbrook.com --- mps/design/land.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/design/land.txt b/mps/design/land.txt index 3ed8b466b0d..b9f80b29d23 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -225,7 +225,7 @@ _`.function.find.zones`: Locate a block at least as big as ``size`` that lies entirely within the ``zoneSet``, return its range via the ``rangeReturn`` argument, and return ``ResOK``. (The first such block, if ``high`` is ``FALSE``, or the last, if ``high`` is ``TRUE``.) If -there is no such block, , return ``ResFAIL``. +there is no such block, return ``ResFAIL``. Delete the range as for ``LandFindFirst()`` and ``LastFindLast()`` (with the effect of ``FindDeleteLOW`` if ``high`` is ``FALSE`` and the From a3e6d214fa548756eb15d21fb93c070f9e0e90ca Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 19 May 2014 16:23:42 +0100 Subject: [PATCH 207/266] Fix status-handling defect noted by nb in review. Make indentation consistent with rest of MPS code. Fix copyright date. Copied from Perforce Change: 186193 ServerID: perforce.ravenbrook.com --- mps/tool/noaslr.c | 49 ++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/mps/tool/noaslr.c b/mps/tool/noaslr.c index 2a174941882..3ae73dc9362 100644 --- a/mps/tool/noaslr.c +++ b/mps/tool/noaslr.c @@ -1,7 +1,7 @@ /* noaslr.c: Disable ASLR on OS X Mavericks * * $Id: //info.ravenbrook.com/project/mps/master/code/eventcnv.c#26 $ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. * * This is a command-line tool that runs another program with address * space layout randomization (ASLR) disabled. @@ -27,37 +27,42 @@ int main(int argc, char **argv) { - extern char **environ; - pid_t pid; - posix_spawnattr_t attr; - int res, status = 1; - char *default_argv[] = {"/bin/sh", NULL}; + extern char **environ; + pid_t pid; + posix_spawnattr_t attr; + int res, status = 1; + char *default_argv[] = {"/bin/sh", NULL}; - if (argc >= 2) - ++ argv; - else - argv = default_argv; + if (argc >= 2) + ++ argv; + else + argv = default_argv; - res = posix_spawnattr_init(&attr); - if (res != 0) - return res; + res = posix_spawnattr_init(&attr); + if (res != 0) + return res; - res = posix_spawnattr_setflags(&attr, _POSIX_SPAWN_DISABLE_ASLR); - if (res != 0) - return res; + res = posix_spawnattr_setflags(&attr, _POSIX_SPAWN_DISABLE_ASLR); + if (res != 0) + return res; - res = posix_spawn(&pid, argv[0], NULL, &attr, argv, environ); - if (res != 0) - return res; + res = posix_spawn(&pid, argv[0], NULL, &attr, argv, environ); + if (res != 0) + return res; - (void)waitpid(pid, &status, 0); - return status; + if (waitpid(pid, &status, 0) == -1) + return 1; + + if (!WIFEXITED(status)) + return 1; + + return WEXITSTATUS(status); } /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From 2f6c8cb9c8d91e92702f56611848072619b8c06e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 19 May 2014 17:11:36 +0100 Subject: [PATCH 208/266] Update design.mps.strategy to describe the current relationship between chains, generations and pool generations; bring the description of the condemn logic up to date. Copied from Perforce Change: 186196 ServerID: perforce.ravenbrook.com --- mps/design/strategy.txt | 173 +++++++++++++++++++--------------------- 1 file changed, 82 insertions(+), 91 deletions(-) diff --git a/mps/design/strategy.txt b/mps/design/strategy.txt index 4b09c3cc004..7d04687c5d3 100644 --- a/mps/design/strategy.txt +++ b/mps/design/strategy.txt @@ -81,100 +81,107 @@ the client to specify preferred relative object locations ("this object should be kept in the same cache line as that one"), to improve cache locality. + Generations ----------- The largest part of the current MPS strategy implementation is the -support for generational GC. Generations are only fully supported for -AMC (and AMCZ) pools. See under "Non-AMC Pools", below, for more -information. +support for generational garbage collections. -Data Structures -............... -The fundamental structure of generational GC is the ``Chain``, -which describes a set of generations. A chain is created by client -code calling ``mps_chain_create()``, specifying the "size" and -"mortality" for each generation. When creating an AMC pool, the -client code must specify the chain which will control collections for -that pool. The same chain may be used for multiple pools. +General data structures +....................... -Each generation in a chain has a ``GenDesc`` structure, -allocated in an array pointed to from the chain. Each AMC pool has a -set of ``PoolGen`` structures, one per generation. The PoolGens -for each generation point to the GenDesc and are linked together in a -ring on the GenDesc. These structures are (solely?) used to gather +The fundamental structure of generational garbage collection is the +``Chain``, which describes a sequence of generations. + +A chain specifies the "capacity" and "mortality" for each generation. +When creating an automatically collected pool, the client code may +specify the chain which will control collections for that pool. The +same chain may be used for multiple pools. If no chain is specified, +the pool uses the arena's default generation chain. + +Each generation in a chain has a ``GenDesc`` structure, allocated in +an array pointed to from the chain. In addition to the generations in +the chains, the arena has a unique ``GenDesc`` structure, named +``topGen`` and described in comments as "the dynamic generation" +(misleadingly: in fact it is the *least* dynamic generation). + +Each automatically collected pool has a set of ``PoolGen`` structures, +one for each generation that it can allocate or promote into. The +``PoolGen`` structures for each generation point to the ``GenDesc`` +for that generation, and are linked together in a ring on the +``GenDesc``. These structures are used to gather accounting information for strategy decisions. -The arena has a unique ``GenDesc`` structure, named -``topGen`` and described in comments as "the dynamic generation" -(although in fact it is the *least* dynamic generation). Each AMC -pool has one more PoolGen than there are GenDescs in the chain. The -extra PoolGen refers to this topGen. +The non-moving automatic pool classes (AMS, AWL and LO) do not support +generational collection, so they allocate into a single generation. +The moving automatic pool classes (AMC and AMCZ) have one pool +generations for each generation in the chain, plus one pool generation +for the arena's "top generation". -AMC segments have a segment descriptor ``amcSegStruct`` which is -a ``GCSegStruct`` with two additional fields. One field -``segTypeP`` is a pointer either to the per-generation per-pool -``amcGen`` structure (a subclass of ``PoolGen``), or to a -nailboard (which then points to an amcGen). The other field -``new`` is a boolean used for keeping track of memory usage for -strategy reasons (see below under 'Accounting'). The ``amcGen`` -is used for statistics (``->segs``) and forwarding buffers -(``->forward``). -The AMC pool class only ever allocates a segment in order to fill a -buffer: either the buffer for a client Allocation Point, or a -forwarding buffer. In order to support generational collection, there -is a subclass ``amcBuf`` of ``SegBuf``, with a -``gen`` field (pointing to a ``amcGen``). So in -``AMCBufferFill()`` the generation of the new segment can be -determined. +AMC data structures +................... -When an AMC pool is created, these ``amcGen`` and -``amcBuf`` structures are all created, and the -``amcBuf->gen`` fields initialized so that the forwarding buffer -of each amcGen knows that it belongs to the next "older" amcGen (apart -from the "oldest" amcGen - that which refers to the topGen - whose -forwarding buffer belongs to itself). +An AMC pool creates an array of pool generation structures of type +``amcGen`` (a subclass of ``PoolGen``). Each pool generation points to +the *forwarding buffer* for that generation: this is the buffer that +surviving objects are copied into. -When copying an object in ``AMCFix()``, the object's current -generation is determined (``amcSegGen()``), and the object is -copied to that amcGen's forwarding buffer, using the buffer protocol. -Thus, objects are "promoted" up the chain of generations until they -end up in the topGen, which is shared between all chains and all -pools. +AMC segments point to the AMC pool generation that the segment belongs +to, and AMC buffers point to the AMC pool generation that the buffer +will be allocating into. -For statistics and reporting purposes, when ``STATISTICS`` is -on, each AMC pool has an array of ``PageRetStruct``s, one per -trace. This structure has many ``Count`` fields, and is -intended to help to assess AMC page retention code. See job001811. +The forwarding buffers are set up during AMC pool creation. Each +generation forwards into the next higher generation in the chain, +except for the top generation, which forwards to itself. Thus, objects +are "promoted" up the chain of generations until they end up in the +top generations, which is shared between all generational pools. + + +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. + +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 + ``ChainCondemnAuto()``. + + 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. + Zones ..... -All collections in the MPS start with condemnation of a complete -``ZoneSet``. Each generation in each chain has a zoneset -associated with it (``chain->gen[N].zones``); the condemned -zoneset is the union of some number of generation's zonesets. It is -condemned by code in the chain system calling -``TraceCondemnZones()``. This is either for all chains -(``ChainCondemnAll()`` called for every chain from -``traceCondemnAll()``) or for some number of generations in a -single chain (``ChainCondemnAuto()`` called from -``TracePoll()``). Note that the condemnation is of every -automatic-pool segment in any zone in the zoneset. It is not limited -to the segments actually associated with the condemned generation(s). +Each generation in each chain has a zoneset associated with it +(``gen->zones``); the condemned zoneset is the union of some number of +generation's zonesets. An attempt is made to use distinct zonesets for different generations. -Segments are allocated from ``AMCBufferFill()`` using ``ChainAlloc()`` +Segments in automatic pools are allocated using ``PoolGenAlloc()`` which creates a ``SegPref`` using the zoneset from the generation's -``GenDesc``. The zoneset for each generation number starts out -empty. If the zoneset is empty, an attempt is made to allocate from a -free zone. The ``GenDesc`` zoneset is augmented with whichever zones the -new segment occupies. +``GenDesc``. The zoneset for each generation starts out empty. If the +zoneset is empty, an attempt is made to allocate from a free zone. The +``GenDesc`` zoneset is augmented with whichever zones the new segment +occupies. Note that this zoneset can never shrink. + Accounting .......... @@ -349,25 +356,6 @@ other uses of that: - in ``AMCWhiten()``, if new is TRUE, the segment size is deducted from ``poolGen.newSize`` and new is set to FALSE. -Non-AMC Pools -............. - -The implementations of AMS, AWL, and LO pool classes are all aware of -generations (this is necessary because all tracing is driven by the -generational data structures described above), but do not make use of -them. For LO and AWL, when a pool is created, a chain with a single -generation is also created, with size and mortality parameters -hard-wired into the pool-creation function (LOInit, AWLInit). For -AMS, a chain is passed as a pool creation parameter into -``mps_pool_create()``, but this chain must also have only a -single generation (otherwise ``ResPARAM`` is returned). - -Note that these chains are separate from any chain used by an AMC pool -(except in the trivial case when a single-generation chain is used for -both AMC and AMS). Note also that these pools do not use or point to -the ``arena->topGen``, which applies only to AMC. - -Non-AMC pools have no support for ramps. Starting a Trace ................ @@ -378,15 +366,18 @@ Trace Progress .............. TODO: When do we do some tracing work? How much tracing work do we do? + Document History ---------------- - 2013-06-04 NB_ Checked this in although it's far from complete. Pasted in my 'ramping notes' from email, which mention some bugs which I may have fixed (TODO: check this). -- 2014-01-29 RB_ The arena no longer manages generation zonesets. +- 2014-01-29 RB_ The arena no longer manages generation zonesets. +- 2014-05-17 GDR_ Bring data structures and condemn logic up to date. -.. _RB: http://www.ravenbrook.com/consultants/rb +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ .. _NB: http://www.ravenbrook.com/consultants/nb/ +.. _RB: http://www.ravenbrook.com/consultants/rb Copyright and License From c92970302ef9b8cf41c3a841e560b3796e3d0d9b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 19 May 2014 17:12:03 +0100 Subject: [PATCH 209/266] Add gendesc and poolgen to the list of types. Copied from Perforce Change: 186197 ServerID: perforce.ravenbrook.com --- mps/manual/source/extensions/mps/designs.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mps/manual/source/extensions/mps/designs.py b/mps/manual/source/extensions/mps/designs.py index 230594e9392..83eb78c7115 100644 --- a/mps/manual/source/extensions/mps/designs.py +++ b/mps/manual/source/extensions/mps/designs.py @@ -20,12 +20,12 @@ 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 Globals - Index Land LD Lock Message MessageType MutatorFaultContext Page - Pointer Pool PThreadext Range Rank RankSet Ref RefSet Res - Reservoir Ring Root RootMode RootVar ScanState Seg SegBuf SegPref - SegPrefKind Serial Shift Sig Size Space SplayNode SplayTree - StackContext Thread Trace TraceId TraceSet TraceStartWhy + Clock Compare Count Epoch FindDelete Format FrameState Fun GenDesc + Globals Index Land LD Lock Message MessageType MutatorFaultContext + Page Pointer Pool PoolGen PThreadext Range Rank RankSet Ref RefSet + Res Reservoir Ring Root RootMode RootVar ScanState Seg SegBuf + SegPref SegPrefKind Serial Shift Sig Size Space SplayNode + SplayTree StackContext Thread Trace TraceId TraceSet TraceStartWhy TraceState ULongest VM Word ZoneSet ''' From 68f9a3cd5c7c0142bc7e830a6173ffcbe2bd0159 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 20 May 2014 12:44:36 +0100 Subject: [PATCH 210/266] Fix assertion in bootblockcheck. Copied from Perforce Change: 186204 ServerID: perforce.ravenbrook.com --- mps/code/boot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/boot.c b/mps/code/boot.c index eff8409fc1e..af365d3b4f1 100644 --- a/mps/code/boot.c +++ b/mps/code/boot.c @@ -30,7 +30,7 @@ Bool BootBlockCheck(BootBlock boot) CHECKL(boot->limit != NULL); CHECKL(boot->base <= boot->alloc); CHECKL(boot->alloc <= boot->limit); - CHECKL(boot->alloc < boot->limit); + CHECKL(boot->base < boot->limit); return TRUE; } From f4f23676ce816d04ab1d15b5a104d18e55c4a620 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 20 May 2014 19:01:26 +0100 Subject: [PATCH 211/266] Fix the build on windows. Copied from Perforce Change: 186213 ServerID: perforce.ravenbrook.com --- mps/code/ananmv.nmk | 73 ++++++------------------------------------- mps/code/commpost.nmk | 11 +++---- mps/code/commpre.nmk | 14 +++++++-- mps/code/w3i3mv.nmk | 73 ++++++------------------------------------- mps/code/w3i3pc.nmk | 73 ++++++------------------------------------- mps/code/w3i6mv.nmk | 73 ++++++------------------------------------- mps/code/w3i6pc.nmk | 73 ++++++------------------------------------- 7 files changed, 60 insertions(+), 330 deletions(-) diff --git a/mps/code/ananmv.nmk b/mps/code/ananmv.nmk index ecf97540ece..ea68b19ee68 100644 --- a/mps/code/ananmv.nmk +++ b/mps/code/ananmv.nmk @@ -7,11 +7,8 @@ PFM = ananmv PFMDEFS = /DCONFIG_PF_ANSI /DCONFIG_THREAD_SINGLE -!INCLUDE commpre.nmk -!INCLUDE mv.nmk - -# MPM sources: core plus platform-specific. -MPM = $(MPMCOMMON) \ +# MPM platform-specific sources. +MPMPF = \ \ \ \ @@ -20,6 +17,9 @@ MPM = $(MPMCOMMON) \ \ +!INCLUDE commpre.nmk +!INCLUDE mv.nmk + # Source to object file mappings and CFLAGS amalgamation # @@ -38,14 +38,7 @@ CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST) LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT) LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT) MPMOBJ0 = $(MPM:<=ananmv\hot\) -PLINTHOBJ0 = $(PLINTH:<=ananmv\hot\) -AMSOBJ0 = $(AMS:<=ananmv\hot\) -AMCOBJ0 = $(AMC:<=ananmv\hot\) -AWLOBJ0 = $(AWL:<=ananmv\hot\) -LOOBJ0 = $(LO:<=ananmv\hot\) -SNCOBJ0 = $(SNC:<=ananmv\hot\) -MVFFOBJ0 = $(MVFF:<=ananmv\hot\) -DWOBJ0 = $(DW:<=ananmv\hot\) +FMTDYOBJ0 = $(FMTDY:<=ananmv\hot\) FMTTESTOBJ0 = $(FMTTEST:<=ananmv\hot\) FMTSCHEMEOBJ0 = $(FMTSCHEME:<=ananmv\hot\) POOLNOBJ0 = $(POOLN:<=ananmv\hot\) @@ -58,14 +51,7 @@ CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST) LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL) LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL) MPMOBJ0 = $(MPM:<=ananmv\cool\) -PLINTHOBJ0 = $(PLINTH:<=ananmv\cool\) -AMSOBJ0 = $(AMS:<=ananmv\cool\) -AMCOBJ0 = $(AMC:<=ananmv\cool\) -AWLOBJ0 = $(AWL:<=ananmv\cool\) -LOOBJ0 = $(LO:<=ananmv\cool\) -SNCOBJ0 = $(SNC:<=ananmv\cool\) -MVFFOBJ0 = $(MVFF:<=ananmv\cool\) -DWOBJ0 = $(DW:<=ananmv\cool\) +FMTDYOBJ0 = $(FMTDY:<=ananmv\cool\) FMTTESTOBJ0 = $(FMTTEST:<=ananmv\cool\) FMTSCHEMEOBJ0 = $(FMTSCHEME:<=ananmv\cool\) POOLNOBJ0 = $(POOLN:<=ananmv\cool\) @@ -78,61 +64,20 @@ CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST) LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH) LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH) MPMOBJ0 = $(MPM:<=ananmv\rash\) -PLINTHOBJ0 = $(PLINTH:<=ananmv\rash\) -AMSOBJ0 = $(AMS:<=ananmv\rash\) -AMCOBJ0 = $(AMC:<=ananmv\rash\) -AWLOBJ0 = $(AWL:<=ananmv\rash\) -LOOBJ0 = $(LO:<=ananmv\rash\) -SNCOBJ0 = $(SNC:<=ananmv\rash\) -MVFFOBJ0 = $(MVFF:<=ananmv\rash\) -DWOBJ0 = $(DW:<=ananmv\rash\) +FMTDYOBJ0 = $(FMTDY:<=ananmv\rash\) FMTTESTOBJ0 = $(FMTTEST:<=ananmv\rash\) FMTSCHEMEOBJ0 = $(FMTSCHEME:<=ananmv\rash\) POOLNOBJ0 = $(POOLN:<=ananmv\rash\) TESTLIBOBJ0 = $(TESTLIB:<=ananmv\rash\) TESTTHROBJ0 = $(TESTTHR:<=ananmv\rash\) -#!ELSEIF "$(VARIETY)" == "cv" -#CFLAGS=$(CFLAGSCOMMON) $(CFCV) -#LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCV) -#LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCV) -#MPMOBJ0 = $(MPM:<=ananmv\cv\) -#MPMOBJ = $(MPMOBJ0:>=.obj) -#PLINTHOBJ0 = $(PLINTH:<=ananmv\cv\) -#PLINTHOBJ = $(PLINTHOBJ0:>=.obj) -#AMSOBJ0 = $(AMS:<=ananmv\cv\) -#AMSOBJ = $(AMSOBJ0:>=.obj) -#AMCOBJ0 = $(AMC:<=ananmv\cv\) -#AMCOBJ = $(AMCOBJ0:>=.obj) -#AWLOBJ0 = $(AWL:<=ananmv\cv\) -#AWLOBJ = $(AWLOBJ0:>=.obj) -#LOOBJ0 = $(LO:<=ananmv\cv\) -#LOOBJ = $(LOOBJ0:>=.obj) -#SNCOBJ0 = $(SNC:<=ananmv\cv\) -#SNCOBJ = $(SNCOBJ0:>=.obj) -#DWOBJ0 = $(DW:<=ananmv\cv\) -#DWOBJ = $(DWOBJ0:>=.obj) -#POOLNOBJ0 = $(POOLN:<=ananmv\cv\) -#POOLNOBJ = $(POOLNOBJ0:>=.obj) -#TESTLIBOBJ0 = $(TESTLIB:<=ananmv\cv\) -#TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) -#TESTTHROBJ0 = $(TESTTHR:<=ananmv\cv\) -#TESTTHROBJ = $(TESTTHROBJ0:>=.obj) - !ENDIF # %%PART: When adding a new part, add new macros which expand to the object # files included in the part MPMOBJ = $(MPMOBJ0:>=.obj) -PLINTHOBJ = $(PLINTHOBJ0:>=.obj) -AMSOBJ = $(AMSOBJ0:>=.obj) -AMCOBJ = $(AMCOBJ0:>=.obj) -AWLOBJ = $(AWLOBJ0:>=.obj) -LOOBJ = $(LOOBJ0:>=.obj) -SNCOBJ = $(SNCOBJ0:>=.obj) -MVFFOBJ = $(MVFFOBJ0:>=.obj) -DWOBJ = $(DWOBJ0:>=.obj) +FMTDYOBJ = $(FMTDYOBJ0:>=.obj) FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj) FMTSCHEMEOBJ = $(FMTSCHEMEOBJ0:>=.obj) POOLNOBJ = $(POOLNOBJ0:>=.obj) diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk index 47139017626..c4e7d8d7f1a 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/commpost.nmk @@ -92,12 +92,9 @@ $(PFM)\hot\mps.lib: $(PFM)\hot\mps.obj $(ECHO) $@ $(LIBMAN) $(LIBFLAGS) /OUT:$@ $** -$(PFM)\cool\mps.lib: \ - $(MPMOBJ) $(AMCOBJ) $(AMSOBJ) $(AWLOBJ) $(LOOBJ) $(SNCOBJ) \ - $(MVFFOBJ) $(PLINTHOBJ) $(POOLNOBJ) +$(PFM)\cool\mps.lib: $(MPMOBJ) $(ECHO) $@ - $(CC) /c $(CFLAGS) /Fo$(PFM)\$(VARIETY)\version.obj version.c - $(LIBMAN) $(LIBFLAGS) /OUT:$@ $** $(PFM)\$(VARIETY)\version.obj + $(LIBMAN) $(LIBFLAGS) /OUT:$@ $** # OTHER GENUINE TARGETS @@ -213,8 +210,8 @@ $(PFM)\$(VARIETY)\mv2test.exe: $(PFM)\$(VARIETY)\mv2test.obj \ $(PFM)\$(VARIETY)\nailboardtest.exe: $(PFM)\$(VARIETY)\nailboardtest.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) -$(PFM)\$(VARIETY)\poolncv.exe: $(PFM)\$(VARIETY)\poolncv.obj \ - $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) +$(PFM)\$(VARIETY)\poolncv.exe: $(PFM)\$(VARIETY)\poolncv.obj \ + $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) $(POOLNOBJ) $(PFM)\$(VARIETY)\qs.exe: $(PFM)\$(VARIETY)\qs.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index 88ed5565270..7aa82b4eb79 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -164,6 +164,7 @@ MPMCOMMON=\ \ \ \ + \ PLINTH = AMC = @@ -173,11 +174,12 @@ LO = MVFF = POOLN = SNC = -DW = +FMTDY = FMTTEST = FMTSCHEME = TESTLIB = TESTTHR = +MPM = $(MPMCOMMON) $(MPMPF) $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(PLINTH) # CHECK PARAMETERS @@ -192,9 +194,15 @@ TESTTHR = !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 @@ -213,8 +221,8 @@ TESTTHR = !IFNDEF SNC !ERROR commpre.nmk: SNC not defined !ENDIF -!IFNDEF DW -!ERROR commpre.nmk: DW not defined +!IFNDEF FMTDY +!ERROR commpre.nmk: FMTDY not defined !ENDIF !IFNDEF FMTTEST !ERROR commpre.nmk: FMTTEST not defined diff --git a/mps/code/w3i3mv.nmk b/mps/code/w3i3mv.nmk index a0f919335b1..458fd033484 100644 --- a/mps/code/w3i3mv.nmk +++ b/mps/code/w3i3mv.nmk @@ -7,11 +7,8 @@ PFM = w3i3mv PFMDEFS = /DCONFIG_PF_STRING="w3i3mv" /DCONFIG_PF_W3I3MV /DWIN32 /D_WINDOWS -!INCLUDE commpre.nmk -!INCLUDE mv.nmk - -# MPM sources: core plus platform-specific. -MPM = $(MPMCOMMON) \ +# MPM platform-specific sources. +MPMPF = \ \ \ \ @@ -23,6 +20,9 @@ MPM = $(MPMCOMMON) \ \ +!INCLUDE commpre.nmk +!INCLUDE mv.nmk + # Source to object file mappings and CFLAGS amalgamation # @@ -41,14 +41,7 @@ CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST) LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT) LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT) MPMOBJ0 = $(MPM:<=w3i3mv\hot\) -PLINTHOBJ0 = $(PLINTH:<=w3i3mv\hot\) -AMSOBJ0 = $(AMS:<=w3i3mv\hot\) -AMCOBJ0 = $(AMC:<=w3i3mv\hot\) -AWLOBJ0 = $(AWL:<=w3i3mv\hot\) -LOOBJ0 = $(LO:<=w3i3mv\hot\) -SNCOBJ0 = $(SNC:<=w3i3mv\hot\) -MVFFOBJ0 = $(MVFF:<=w3i3mv\hot\) -DWOBJ0 = $(DW:<=w3i3mv\hot\) +FMTDYOBJ0 = $(FMTDY:<=w3i3mv\hot\) FMTTESTOBJ0 = $(FMTTEST:<=w3i3mv\hot\) FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i3mv\hot\) POOLNOBJ0 = $(POOLN:<=w3i3mv\hot\) @@ -61,14 +54,7 @@ CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST) LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL) LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL) MPMOBJ0 = $(MPM:<=w3i3mv\cool\) -PLINTHOBJ0 = $(PLINTH:<=w3i3mv\cool\) -AMSOBJ0 = $(AMS:<=w3i3mv\cool\) -AMCOBJ0 = $(AMC:<=w3i3mv\cool\) -AWLOBJ0 = $(AWL:<=w3i3mv\cool\) -LOOBJ0 = $(LO:<=w3i3mv\cool\) -SNCOBJ0 = $(SNC:<=w3i3mv\cool\) -MVFFOBJ0 = $(MVFF:<=w3i3mv\cool\) -DWOBJ0 = $(DW:<=w3i3mv\cool\) +FMTDYOBJ0 = $(FMTDY:<=w3i3mv\cool\) FMTTESTOBJ0 = $(FMTTEST:<=w3i3mv\cool\) FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i3mv\cool\) POOLNOBJ0 = $(POOLN:<=w3i3mv\cool\) @@ -81,61 +67,20 @@ CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST) LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH) LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH) MPMOBJ0 = $(MPM:<=w3i3mv\rash\) -PLINTHOBJ0 = $(PLINTH:<=w3i3mv\rash\) -AMSOBJ0 = $(AMS:<=w3i3mv\rash\) -AMCOBJ0 = $(AMC:<=w3i3mv\rash\) -AWLOBJ0 = $(AWL:<=w3i3mv\rash\) -LOOBJ0 = $(LO:<=w3i3mv\rash\) -SNCOBJ0 = $(SNC:<=w3i3mv\rash\) -MVFFOBJ0 = $(MVFF:<=w3i3mv\rash\) -DWOBJ0 = $(DW:<=w3i3mv\rash\) +FMTDYOBJ0 = $(FMTDY:<=w3i3mv\rash\) FMTTESTOBJ0 = $(FMTTEST:<=w3i3mv\rash\) FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i3mv\rash\) POOLNOBJ0 = $(POOLN:<=w3i3mv\rash\) TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\rash\) TESTTHROBJ0 = $(TESTTHR:<=w3i3mv\rash\) -#!ELSEIF "$(VARIETY)" == "cv" -#CFLAGS=$(CFLAGSCOMMON) $(CFCV) -#LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCV) -#LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCV) -#MPMOBJ0 = $(MPM:<=w3i3mv\cv\) -#MPMOBJ = $(MPMOBJ0:>=.obj) -#PLINTHOBJ0 = $(PLINTH:<=w3i3mv\cv\) -#PLINTHOBJ = $(PLINTHOBJ0:>=.obj) -#AMSOBJ0 = $(AMS:<=w3i3mv\cv\) -#AMSOBJ = $(AMSOBJ0:>=.obj) -#AMCOBJ0 = $(AMC:<=w3i3mv\cv\) -#AMCOBJ = $(AMCOBJ0:>=.obj) -#AWLOBJ0 = $(AWL:<=w3i3mv\cv\) -#AWLOBJ = $(AWLOBJ0:>=.obj) -#LOOBJ0 = $(LO:<=w3i3mv\cv\) -#LOOBJ = $(LOOBJ0:>=.obj) -#SNCOBJ0 = $(SNC:<=w3i3mv\cv\) -#SNCOBJ = $(SNCOBJ0:>=.obj) -#DWOBJ0 = $(DW:<=w3i3mv\cv\) -#DWOBJ = $(DWOBJ0:>=.obj) -#POOLNOBJ0 = $(POOLN:<=w3i3mv\cv\) -#POOLNOBJ = $(POOLNOBJ0:>=.obj) -#TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\cv\) -#TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) -#TESTTHROBJ0 = $(TESTTHR:<=w3i3mv\cv\) -#TESTTHROBJ = $(TESTTHROBJ0:>=.obj) - !ENDIF # %%PART: When adding a new part, add new macros which expand to the object # files included in the part MPMOBJ = $(MPMOBJ0:>=.obj) -PLINTHOBJ = $(PLINTHOBJ0:>=.obj) -AMSOBJ = $(AMSOBJ0:>=.obj) -AMCOBJ = $(AMCOBJ0:>=.obj) -AWLOBJ = $(AWLOBJ0:>=.obj) -LOOBJ = $(LOOBJ0:>=.obj) -SNCOBJ = $(SNCOBJ0:>=.obj) -MVFFOBJ = $(MVFFOBJ0:>=.obj) -DWOBJ = $(DWOBJ0:>=.obj) +FMTDYOBJ = $(FMTDYOBJ0:>=.obj) FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj) FMTSCHEMEOBJ = $(FMTSCHEMEOBJ0:>=.obj) POOLNOBJ = $(POOLNOBJ0:>=.obj) diff --git a/mps/code/w3i3pc.nmk b/mps/code/w3i3pc.nmk index ad56deca83a..f3e848a94dd 100644 --- a/mps/code/w3i3pc.nmk +++ b/mps/code/w3i3pc.nmk @@ -7,11 +7,8 @@ PFM = w3i3pc PFMDEFS = /DCONFIG_PF_STRING="w3i3pc" /DCONFIG_PF_W3I3PC /DWIN32 /D_WINDOWS -!INCLUDE commpre.nmk -!INCLUDE pc.nmk - -# MPM sources: core plus platform-specific. -MPM = $(MPMCOMMON) \ +# MPM platform-specific sources. +MPMPF = \ \ \ \ @@ -23,6 +20,9 @@ MPM = $(MPMCOMMON) \ \ +!INCLUDE commpre.nmk +!INCLUDE pc.nmk + # Source to object file mappings and CFLAGS amalgamation # @@ -41,14 +41,7 @@ CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST) LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT) LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT) MPMOBJ0 = $(MPM:<=w3i3pc\hot\) -PLINTHOBJ0 = $(PLINTH:<=w3i3pc\hot\) -AMSOBJ0 = $(AMS:<=w3i3pc\hot\) -AMCOBJ0 = $(AMC:<=w3i3pc\hot\) -AWLOBJ0 = $(AWL:<=w3i3pc\hot\) -LOOBJ0 = $(LO:<=w3i3pc\hot\) -SNCOBJ0 = $(SNC:<=w3i3pc\hot\) -MVFFOBJ0 = $(MVFF:<=w3i3pc\hot\) -DWOBJ0 = $(DW:<=w3i3pc\hot\) +FMTDYOBJ0 = $(FMTDY:<=w3i3pc\hot\) FMTTESTOBJ0 = $(FMTTEST:<=w3i3pc\hot\) POOLNOBJ0 = $(POOLN:<=w3i3pc\hot\) TESTLIBOBJ0 = $(TESTLIB:<=w3i3pc\hot\) @@ -60,14 +53,7 @@ CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST) LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL) LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL) MPMOBJ0 = $(MPM:<=w3i3pc\cool\) -PLINTHOBJ0 = $(PLINTH:<=w3i3pc\cool\) -AMSOBJ0 = $(AMS:<=w3i3pc\cool\) -AMCOBJ0 = $(AMC:<=w3i3pc\cool\) -AWLOBJ0 = $(AWL:<=w3i3pc\cool\) -LOOBJ0 = $(LO:<=w3i3pc\cool\) -SNCOBJ0 = $(SNC:<=w3i3pc\cool\) -MVFFOBJ0 = $(MVFF:<=w3i3pc\cool\) -DWOBJ0 = $(DW:<=w3i3pc\cool\) +FMTDYOBJ0 = $(FMTDY:<=w3i3pc\cool\) FMTTESTOBJ0 = $(FMTTEST:<=w3i3pc\cool\) POOLNOBJ0 = $(POOLN:<=w3i3pc\cool\) TESTLIBOBJ0 = $(TESTLIB:<=w3i3pc\cool\) @@ -79,60 +65,19 @@ CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST) LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH) LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH) MPMOBJ0 = $(MPM:<=w3i3pc\rash\) -PLINTHOBJ0 = $(PLINTH:<=w3i3pc\rash\) -AMSOBJ0 = $(AMS:<=w3i3pc\rash\) -AMCOBJ0 = $(AMC:<=w3i3pc\rash\) -AWLOBJ0 = $(AWL:<=w3i3pc\rash\) -LOOBJ0 = $(LO:<=w3i3pc\rash\) -SNCOBJ0 = $(SNC:<=w3i3pc\rash\) -MVFFOBJ0 = $(MVFF:<=w3i3pc\rash\) -DWOBJ0 = $(DW:<=w3i3pc\rash\) +FMTDYOBJ0 = $(FMTDY:<=w3i3pc\rash\) FMTTESTOBJ0 = $(FMTTEST:<=w3i3pc\rash\) POOLNOBJ0 = $(POOLN:<=w3i3pc\rash\) TESTLIBOBJ0 = $(TESTLIB:<=w3i3pc\rash\) TESTTHROBJ0 = $(TESTTHR:<=w3i3pc\rash\) -#!ELSEIF "$(VARIETY)" == "cv" -#CFLAGS=$(CFLAGSCOMMON) $(CFCV) -#LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCV) -#LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCV) -#MPMOBJ0 = $(MPM:<=w3i3pc\cv\) -#MPMOBJ = $(MPMOBJ0:>=.obj) -#PLINTHOBJ0 = $(PLINTH:<=w3i3pc\cv\) -#PLINTHOBJ = $(PLINTHOBJ0:>=.obj) -#AMSOBJ0 = $(AMS:<=w3i3pc\cv\) -#AMSOBJ = $(AMSOBJ0:>=.obj) -#AMCOBJ0 = $(AMC:<=w3i3pc\cv\) -#AMCOBJ = $(AMCOBJ0:>=.obj) -#AWLOBJ0 = $(AWL:<=w3i3pc\cv\) -#AWLOBJ = $(AWLOBJ0:>=.obj) -#LOOBJ0 = $(LO:<=w3i3pc\cv\) -#LOOBJ = $(LOOBJ0:>=.obj) -#SNCOBJ0 = $(SNC:<=w3i3pc\cv\) -#SNCOBJ = $(SNCOBJ0:>=.obj) -#DWOBJ0 = $(DW:<=w3i3pc\cv\) -#DWOBJ = $(DWOBJ0:>=.obj) -#POOLNOBJ0 = $(POOLN:<=w3i3pc\cv\) -#POOLNOBJ = $(POOLNOBJ0:>=.obj) -#TESTLIBOBJ0 = $(TESTLIB:<=w3i3pc\cv\) -#TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) -#TESTTHROBJ0 = $(TESTTHR:<=w3i3pc\cv\) -#TESTTHROBJ = $(TESTTHROBJ0:>=.obj) - !ENDIF # %%PART: When adding a new part, add new macros which expand to the object # files included in the part MPMOBJ = $(MPMOBJ0:>=.obj) -PLINTHOBJ = $(PLINTHOBJ0:>=.obj) -AMSOBJ = $(AMSOBJ0:>=.obj) -AMCOBJ = $(AMCOBJ0:>=.obj) -AWLOBJ = $(AWLOBJ0:>=.obj) -LOOBJ = $(LOOBJ0:>=.obj) -SNCOBJ = $(SNCOBJ0:>=.obj) -MVFFOBJ = $(MVFFOBJ0:>=.obj) -DWOBJ = $(DWOBJ0:>=.obj) +FMTDYOBJ = $(FMTDYOBJ0:>=.obj) FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj) POOLNOBJ = $(POOLNOBJ0:>=.obj) TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) diff --git a/mps/code/w3i6mv.nmk b/mps/code/w3i6mv.nmk index 9d20b498525..5cfa511db91 100644 --- a/mps/code/w3i6mv.nmk +++ b/mps/code/w3i6mv.nmk @@ -8,11 +8,8 @@ PFM = w3i6mv PFMDEFS = /DCONFIG_PF_STRING="w3i6mv" /DCONFIG_PF_W3I6MV /DWIN32 /D_WINDOWS MASM = ml64 -!INCLUDE commpre.nmk -!INCLUDE mv.nmk - -# MPM sources: core plus platform-specific. -MPM = $(MPMCOMMON) \ +# MPM platform-specific sources. +MPMPF = \ \ \ \ @@ -24,6 +21,9 @@ MPM = $(MPMCOMMON) \ \ +!INCLUDE commpre.nmk +!INCLUDE mv.nmk + # Source to object file mappings and CFLAGS amalgamation # @@ -42,14 +42,7 @@ CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST) LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT) LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT) MPMOBJ0 = $(MPM:<=w3i6mv\hot\) -PLINTHOBJ0 = $(PLINTH:<=w3i6mv\hot\) -AMSOBJ0 = $(AMS:<=w3i6mv\hot\) -AMCOBJ0 = $(AMC:<=w3i6mv\hot\) -AWLOBJ0 = $(AWL:<=w3i6mv\hot\) -LOOBJ0 = $(LO:<=w3i6mv\hot\) -SNCOBJ0 = $(SNC:<=w3i6mv\hot\) -MVFFOBJ0 = $(MVFF:<=w3i6mv\hot\) -DWOBJ0 = $(DW:<=w3i6mv\hot\) +FMTDYOBJ0 = $(FMTDY:<=w3i6mv\hot\) FMTTESTOBJ0 = $(FMTTEST:<=w3i6mv\hot\) FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i6mv\hot\) POOLNOBJ0 = $(POOLN:<=w3i6mv\hot\) @@ -62,14 +55,7 @@ CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST) LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL) LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL) MPMOBJ0 = $(MPM:<=w3i6mv\cool\) -PLINTHOBJ0 = $(PLINTH:<=w3i6mv\cool\) -AMSOBJ0 = $(AMS:<=w3i6mv\cool\) -AMCOBJ0 = $(AMC:<=w3i6mv\cool\) -AWLOBJ0 = $(AWL:<=w3i6mv\cool\) -LOOBJ0 = $(LO:<=w3i6mv\cool\) -SNCOBJ0 = $(SNC:<=w3i6mv\cool\) -MVFFOBJ0 = $(MVFF:<=w3i6mv\cool\) -DWOBJ0 = $(DW:<=w3i6mv\cool\) +FMTDYOBJ0 = $(FMTDY:<=w3i6mv\cool\) FMTTESTOBJ0 = $(FMTTEST:<=w3i6mv\cool\) FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i6mv\cool\) POOLNOBJ0 = $(POOLN:<=w3i6mv\cool\) @@ -82,61 +68,20 @@ CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST) LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH) LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH) MPMOBJ0 = $(MPM:<=w3i6mv\rash\) -PLINTHOBJ0 = $(PLINTH:<=w3i6mv\rash\) -AMSOBJ0 = $(AMS:<=w3i6mv\rash\) -AMCOBJ0 = $(AMC:<=w3i6mv\rash\) -AWLOBJ0 = $(AWL:<=w3i6mv\rash\) -LOOBJ0 = $(LO:<=w3i6mv\rash\) -SNCOBJ0 = $(SNC:<=w3i6mv\rash\) -MVFFOBJ0 = $(MVFF:<=w3i6mv\rash\) -DWOBJ0 = $(DW:<=w3i6mv\rash\) +FMTDYOBJ0 = $(FMTDY:<=w3i6mv\rash\) FMTTESTOBJ0 = $(FMTTEST:<=w3i6mv\rash\) FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i6mv\rash\) POOLNOBJ0 = $(POOLN:<=w3i6mv\rash\) TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\rash\) TESTTHROBJ0 = $(TESTTHR:<=w3i6mv\rash\) -#!ELSEIF "$(VARIETY)" == "cv" -#CFLAGS=$(CFLAGSCOMMON) $(CFCV) -#LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCV) -#LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCV) -#MPMOBJ0 = $(MPM:<=w3i6mv\cv\) -#MPMOBJ = $(MPMOBJ0:>=.obj) -#PLINTHOBJ0 = $(PLINTH:<=w3i6mv\cv\) -#PLINTHOBJ = $(PLINTHOBJ0:>=.obj) -#AMSOBJ0 = $(AMS:<=w3i6mv\cv\) -#AMSOBJ = $(AMSOBJ0:>=.obj) -#AMCOBJ0 = $(AMC:<=w3i6mv\cv\) -#AMCOBJ = $(AMCOBJ0:>=.obj) -#AWLOBJ0 = $(AWL:<=w3i6mv\cv\) -#AWLOBJ = $(AWLOBJ0:>=.obj) -#LOOBJ0 = $(LO:<=w3i6mv\cv\) -#LOOBJ = $(LOOBJ0:>=.obj) -#SNCOBJ0 = $(SNC:<=w3i6mv\cv\) -#SNCOBJ = $(SNCOBJ0:>=.obj) -#DWOBJ0 = $(DW:<=w3i6mv\cv\) -#DWOBJ = $(DWOBJ0:>=.obj) -#POOLNOBJ0 = $(POOLN:<=w3i6mv\cv\) -#POOLNOBJ = $(POOLNOBJ0:>=.obj) -#TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\cv\) -#TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) -#TESTTHROBJ0 = $(TESTTHR:<=w3i6mv\cv\) -#TESTTHROBJ = $(TESTTHROBJ0:>=.obj) - !ENDIF # %%PART: When adding a new part, add new macros which expand to the object # files included in the part MPMOBJ = $(MPMOBJ0:>=.obj) -PLINTHOBJ = $(PLINTHOBJ0:>=.obj) -AMSOBJ = $(AMSOBJ0:>=.obj) -AMCOBJ = $(AMCOBJ0:>=.obj) -AWLOBJ = $(AWLOBJ0:>=.obj) -LOOBJ = $(LOOBJ0:>=.obj) -SNCOBJ = $(SNCOBJ0:>=.obj) -MVFFOBJ = $(MVFFOBJ0:>=.obj) -DWOBJ = $(DWOBJ0:>=.obj) +FMTDYOBJ = $(FMTDYOBJ0:>=.obj) FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj) FMTSCHEMEOBJ = $(FMTSCHEMEOBJ0:>=.obj) POOLNOBJ = $(POOLNOBJ0:>=.obj) diff --git a/mps/code/w3i6pc.nmk b/mps/code/w3i6pc.nmk index 687a0a6f204..58488b757f7 100644 --- a/mps/code/w3i6pc.nmk +++ b/mps/code/w3i6pc.nmk @@ -9,13 +9,10 @@ PFM = w3i6pc PFMDEFS = /DCONFIG_PF_STRING="w3i6pc" /DCONFIG_PF_W3I6PC /DWIN32 /D_WINDOWS -!INCLUDE commpre.nmk -!INCLUDE pc.nmk - CFLAGSCOMMONPRE = $(CFLAGSCOMMONPRE) /Tamd64-coff -# MPM sources: core plus platform-specific. -MPM = $(MPMCOMMON) \ +# MPM platform-specific sources. +MPMPF = \ \ \ \ @@ -27,6 +24,9 @@ MPM = $(MPMCOMMON) \ \ +!INCLUDE commpre.nmk +!INCLUDE pc.nmk + # Source to object file mappings and CFLAGS amalgamation # @@ -45,14 +45,7 @@ CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST) LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT) LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT) MPMOBJ0 = $(MPM:<=w3i6pc\hot\) -PLINTHOBJ0 = $(PLINTH:<=w3i6pc\hot\) -AMSOBJ0 = $(AMS:<=w3i6pc\hot\) -AMCOBJ0 = $(AMC:<=w3i6pc\hot\) -AWLOBJ0 = $(AWL:<=w3i6pc\hot\) -LOOBJ0 = $(LO:<=w3i6pc\hot\) -SNCOBJ0 = $(SNC:<=w3i6pc\hot\) -MVFFOBJ0 = $(MVFF:<=w3i6pc\hot\) -DWOBJ0 = $(DW:<=w3i6pc\hot\) +FMTDYOBJ0 = $(FMTDY:<=w3i6pc\hot\) FMTTESTOBJ0 = $(FMTTEST:<=w3i6pc\hot\) POOLNOBJ0 = $(POOLN:<=w3i6pc\hot\) TESTLIBOBJ0 = $(TESTLIB:<=w3i6pc\hot\) @@ -64,14 +57,7 @@ CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST) LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL) LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL) MPMOBJ0 = $(MPM:<=w3i6pc\cool\) -PLINTHOBJ0 = $(PLINTH:<=w3i6pc\cool\) -AMSOBJ0 = $(AMS:<=w3i6pc\cool\) -AMCOBJ0 = $(AMC:<=w3i6pc\cool\) -AWLOBJ0 = $(AWL:<=w3i6pc\cool\) -LOOBJ0 = $(LO:<=w3i6pc\cool\) -SNCOBJ0 = $(SNC:<=w3i6pc\cool\) -MVFFOBJ0 = $(MVFF:<=w3i6pc\cool\) -DWOBJ0 = $(DW:<=w3i6pc\cool\) +FMTDYOBJ0 = $(FMTDY:<=w3i6pc\cool\) FMTTESTOBJ0 = $(FMTTEST:<=w3i6pc\cool\) POOLNOBJ0 = $(POOLN:<=w3i6pc\cool\) TESTLIBOBJ0 = $(TESTLIB:<=w3i6pc\cool\) @@ -83,60 +69,19 @@ CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST) LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH) LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH) MPMOBJ0 = $(MPM:<=w3i6pc\rash\) -PLINTHOBJ0 = $(PLINTH:<=w3i6pc\rash\) -AMSOBJ0 = $(AMS:<=w3i6pc\rash\) -AMCOBJ0 = $(AMC:<=w3i6pc\rash\) -AWLOBJ0 = $(AWL:<=w3i6pc\rash\) -LOOBJ0 = $(LO:<=w3i6pc\rash\) -SNCOBJ0 = $(SNC:<=w3i6pc\rash\) -MVFFOBJ0 = $(MVFF:<=w3i6pc\rash\) -DWOBJ0 = $(DW:<=w3i6pc\rash\) +FMTDYOBJ0 = $(FMTDY:<=w3i6pc\rash\) FMTTESTOBJ0 = $(FMTTEST:<=w3i6pc\rash\) POOLNOBJ0 = $(POOLN:<=w3i6pc\rash\) TESTLIBOBJ0 = $(TESTLIB:<=w3i6pc\rash\) TESTTHROBJ0 = $(TESTTHR:<=w3i6pc\rash\) -#!ELSEIF "$(VARIETY)" == "cv" -#CFLAGS=$(CFLAGSCOMMON) $(CFCV) -#LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCV) -#LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCV) -#MPMOBJ0 = $(MPM:<=w3i6pc\cv\) -#MPMOBJ = $(MPMOBJ0:>=.obj) -#PLINTHOBJ0 = $(PLINTH:<=w3i6pc\cv\) -#PLINTHOBJ = $(PLINTHOBJ0:>=.obj) -#AMSOBJ0 = $(AMS:<=w3i6pc\cv\) -#AMSOBJ = $(AMSOBJ0:>=.obj) -#AMCOBJ0 = $(AMC:<=w3i6pc\cv\) -#AMCOBJ = $(AMCOBJ0:>=.obj) -#AWLOBJ0 = $(AWL:<=w3i6pc\cv\) -#AWLOBJ = $(AWLOBJ0:>=.obj) -#LOOBJ0 = $(LO:<=w3i6pc\cv\) -#LOOBJ = $(LOOBJ0:>=.obj) -#SNCOBJ0 = $(SNC:<=w3i6pc\cv\) -#SNCOBJ = $(SNCOBJ0:>=.obj) -#DWOBJ0 = $(DW:<=w3i6pc\cv\) -#DWOBJ = $(DWOBJ0:>=.obj) -#POOLNOBJ0 = $(POOLN:<=w3i6pc\cv\) -#POOLNOBJ = $(POOLNOBJ0:>=.obj) -#TESTLIBOBJ0 = $(TESTLIB:<=w3i6pc\cv\) -#TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) -#TESTTHROBJ0 = $(TESTTHR:<=w3i6pc\cv\) -#TESTTHROBJ = $(TESTTHROBJ0:>=.obj) - !ENDIF # %%PART: When adding a new part, add new macros which expand to the object # files included in the part MPMOBJ = $(MPMOBJ0:>=.obj) -PLINTHOBJ = $(PLINTHOBJ0:>=.obj) -AMSOBJ = $(AMSOBJ0:>=.obj) -AMCOBJ = $(AMCOBJ0:>=.obj) -AWLOBJ = $(AWLOBJ0:>=.obj) -LOOBJ = $(LOOBJ0:>=.obj) -SNCOBJ = $(SNCOBJ0:>=.obj) -MVFFOBJ = $(MVFFOBJ0:>=.obj) -DWOBJ = $(DWOBJ0:>=.obj) +FMTDYOBJ = $(FMTDYOBJ0:>=.obj) FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj) POOLNOBJ = $(POOLNOBJ0:>=.obj) TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) From 38670ee8fccaa7b66a01a336107565bb832a5634 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 20 May 2014 19:36:04 +0100 Subject: [PATCH 212/266] Fix the build on w3i6mv. Copied from Perforce Change: 186217 ServerID: perforce.ravenbrook.com --- mps/code/amcssth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c index b96df985028..7c7bbf2ecb1 100644 --- a/mps/code/amcssth.c +++ b/mps/code/amcssth.c @@ -237,7 +237,7 @@ static void test_pool(mps_pool_t pool, size_t roots_count, int mode) die(mps_ap_alloc_pattern_begin(busy_ap, ramp), "pattern begin (busy_ap)"); ramping = 1; while (collections < collectionsCOUNT) { - unsigned long c; + mps_word_t c; size_t r; c = mps_collections(arena); @@ -245,7 +245,7 @@ static void test_pool(mps_pool_t pool, size_t roots_count, int mode) if (collections != c) { collections = c; printf("\nCollection %lu started, %lu objects, committed=%lu.\n", - c, objs, (unsigned long)mps_arena_committed(arena)); + (unsigned long)c, objs, (unsigned long)mps_arena_committed(arena)); report(arena); for (i = 0; i < exactRootsCOUNT; ++i) From c639055f7bb0d4ced1006f5fd56706033ec6b258 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 20 May 2014 23:25:03 +0100 Subject: [PATCH 213/266] In light of performance findings, boost the default arena size to 256 mb. add a -m option to djbench so that we can test the effect of setting the initial arena size on the manual pool classes. Copied from Perforce Change: 186224 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 2 +- mps/code/djbench.c | 20 ++++++++++++++++++-- mps/manual/source/topic/arena.rst | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index 0a1eb1a862b..081b3ffaeeb 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -419,7 +419,7 @@ pool to be very heavily used. */ #define CONTROL_EXTEND_BY 4096 -#define VM_ARENA_SIZE_DEFAULT ((Size)1 << 20) +#define VM_ARENA_SIZE_DEFAULT ((Size)1 << 28) /* Stack configuration */ diff --git a/mps/code/djbench.c b/mps/code/djbench.c index c1f37f412b2..00bb5d3f954 100644 --- a/mps/code/djbench.c +++ b/mps/code/djbench.c @@ -48,6 +48,7 @@ static double pact = 0.2; /* probability per pass of acting */ static unsigned rinter = 75; /* pass interval for recursion */ static unsigned rmax = 10; /* maximum recursion depth */ static mps_bool_t zoned = TRUE; /* arena allocates using zones */ +static size_t arenasize = 256ul * 1024 * 1024; /* arena size */ #define DJRUN(fname, alloc, free) \ static unsigned fname##_inner(mps_ap_t ap, unsigned depth, unsigned r) { \ @@ -177,7 +178,7 @@ static void wrap(dj_t dj, mps_class_t dummy, const char *name) static void arena_wrap(dj_t dj, mps_class_t pool_class, const char *name) { MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 256ul * 1024 * 1024); /* FIXME: Why is there no default? */ + MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, arenasize); MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, zoned); DJMUST(mps_arena_create_k(&arena, mps_arena_class_vm(), args)); } MPS_ARGS_END(args); @@ -201,6 +202,7 @@ static struct option longopts[] = { {"rinter", required_argument, NULL, 'r'}, {"rmax", required_argument, NULL, 'd'}, {"seed", required_argument, NULL, 'x'}, + {"arena-size", required_argument, NULL, 'm'}, {"arena-unzoned", no_argument, NULL, 'z'}, {NULL, 0, NULL, 0} }; @@ -235,7 +237,7 @@ int main(int argc, char *argv[]) { seed = rnd_seed(); - while ((ch = getopt_long(argc, argv, "ht:i:p:b:s:a:r:d:x:z", longopts, NULL)) != -1) + while ((ch = getopt_long(argc, argv, "ht:i:p:b:s:a:r:d:m:x:z", longopts, NULL)) != -1) switch (ch) { case 't': nthreads = (unsigned)strtoul(optarg, NULL, 10); @@ -267,6 +269,20 @@ int main(int argc, char *argv[]) { case 'z': zoned = FALSE; break; + case 'm': { + char *p; + arenasize = (unsigned)strtoul(optarg, &p, 10); + switch(toupper(*p)) { + case 'G': arenasize <<= 30; break; + case 'M': arenasize <<= 20; break; + case 'K': arenasize <<= 10; break; + case '\0': break; + default: + fprintf(stderr, "Bad arena size %s\n", optarg); + return EXIT_FAILURE; + } + } + break; default: fprintf(stderr, "Usage: %s [option...] [test...]\n" diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index 86e0a39550f..8fd61fed6bf 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -236,7 +236,7 @@ Virtual memory arenas accepts one :term:`keyword argument` on all platforms: * :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type:`size_t`, default - 2\ :superscript:`20`) is the initial amount of virtual address + 256\ :term:`megabytes`) is the initial amount of virtual address space, in :term:`bytes (1)`, that the arena will reserve (this space is initially reserved so that the arena can subsequently use it without interference from other parts of the program, but From e4dd74448df10ea996d8a7171e643a4afc7b6612 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 20 May 2014 23:27:06 +0100 Subject: [PATCH 214/266] Update release notes. Copied from Perforce Change: 186225 ServerID: perforce.ravenbrook.com --- mps/manual/source/release.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 07dd03eef70..49713d5e303 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -44,8 +44,8 @@ New features Interface changes ................. -#. There is now a default value (currently 1 \ :term:`megabyte`) for - the :c:macro:`MPS_KEY_ARENA_SIZE` keyword argument to +#. There is now a default value (currently 256 \ :term:`megabytes`) + for the :c:macro:`MPS_KEY_ARENA_SIZE` keyword argument to :c:func:`mps_arena_create_k` when creating a virtual memory arena. See :c:func:`mps_arena_class_vm`. From 11f082b849e7fb86940411143a43756b2fbf88a5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 21 May 2014 12:13:21 +0100 Subject: [PATCH 215/266] Add bufferisready(buffer) assertion to "common assertions and their causes". found by christian schafmeister . Copied from Perforce Change: 186229 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 200c20af8bb..e65f6eafebd 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -233,6 +233,13 @@ cause), please :ref:`let us know ` so that we can improve this documentation. +``buffer.c: BufferIsReady(buffer)`` + + The client program called :c:func:`mps_reserve` twice on the same + :term:`allocation point` without calling :c:func:`mps_commit`. See + :ref:`topic-allocation-point-protocol`. + + ``dbgpool.c: fencepost check on free`` The client program wrote to a location after the end, or before From 4cb51f1bd3ca370aa8b9dd76ed8a01b3fa81d6e8 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 21 May 2014 12:14:29 +0100 Subject: [PATCH 216/266] Fix typo. Copied from Perforce Change: 186230 ServerID: perforce.ravenbrook.com --- mps/code/mps.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/mps.h b/mps/code/mps.h index 049a489f96d..56c0c06061e 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -13,7 +13,7 @@ * `MPS_` or `_mps_` and may use any identifiers with these prefixes in * future. * - * .naming.internal: Any idenfitier beginning with underscore is for + * .naming.internal: Any identifier beginning with an underscore is for * internal use within the interface and may change or be withdrawn without * warning. * From b0f1837ea989e3ff4d391c443615757101863545 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 21 May 2014 12:20:40 +0100 Subject: [PATCH 217/266] Cross-reference from debugging chapter of the guide to "common assertions and their causes". Copied from Perforce Change: 186232 ServerID: perforce.ravenbrook.com --- mps/manual/source/guide/debug.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mps/manual/source/guide/debug.rst b/mps/manual/source/guide/debug.rst index ddc46244c09..8f64ec66ab1 100644 --- a/mps/manual/source/guide/debug.rst +++ b/mps/manual/source/guide/debug.rst @@ -42,6 +42,9 @@ General debugging advice in production), and can generate profiling output in the form of the :term:`telemetry stream`. +#. If your program triggers an assertion failure in the MPS, consult + :ref:`topic-error-cause` for suggestions as to the possible cause. + #. .. index:: single: ASLR single: address space layout randomization From 85bb536fa550e93e6e13f9bbaa71f919dc6a59e7 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 21 May 2014 14:47:11 +0100 Subject: [PATCH 218/266] Glossary entry and guide to address space layout randomization. Copied from Perforce Change: 186234 ServerID: perforce.ravenbrook.com --- mps/manual/source/glossary/a.rst | 24 +++++++ mps/manual/source/guide/debug.rst | 116 ++++++++++++++++++++++++++---- 2 files changed, 125 insertions(+), 15 deletions(-) diff --git a/mps/manual/source/glossary/a.rst b/mps/manual/source/glossary/a.rst index a7ab2de1bda..e7c6afe4d4f 100644 --- a/mps/manual/source/glossary/a.rst +++ b/mps/manual/source/glossary/a.rst @@ -103,6 +103,26 @@ Memory Management Glossary: A .. seealso:: :term:`virtual address space`, :term:`physical address space`. + address space layout randomization + + .. aka:: *ASLR*. + + The random placement in :term:`address space` of the + :term:`stack`, data segment, :term:`heap`, and so on, of a + process. + + The purpose of ASLR is to make it harder for an attacker to + exploit buffer overflow bugs, by making it harder to determine + the addresses of data structures. + + .. mps:specific:: + + ASLR also makes it hard to prepare a repeatable test case + for a program that performs computation based on the + addresses of objects, for example, hashing objects by + their address. See :ref:`guide-debug-aslr` for techniques + to deal with this. + address translation cache .. see:: :term:`translation lookaside buffer`. @@ -389,6 +409,10 @@ Memory Management Glossary: A class of :term:`arenas`. Arena classes include :term:`client arenas` and :term:`virtual memory arenas`. + ASLR + + .. see:: :term:`address space layout randomization`. + assertion A declaration in a program of a condition that is expected diff --git a/mps/manual/source/guide/debug.rst b/mps/manual/source/guide/debug.rst index 8f64ec66ab1..7dfca3bcbad 100644 --- a/mps/manual/source/guide/debug.rst +++ b/mps/manual/source/guide/debug.rst @@ -45,21 +45,17 @@ General debugging advice #. If your program triggers an assertion failure in the MPS, consult :ref:`topic-error-cause` for suggestions as to the possible cause. -#. .. index:: - single: ASLR - single: address space layout randomization - - Prepare a reproducible test case if possible. The MPS may be +#. Prepare a reproducible test case if possible. The MPS may be :term:`asynchronous `, but it is deterministic, so in single-threaded applications you should be - able to get consistent results. (But you need to beware of `address - space layout randomization`_: if you perform computation based on - the addresses of objects, for example, hashing objects by their - address, then ASLR will cause your hash tables to be laid out - differently on each run, which may affect the order of memory - management operations.) + able to get consistent results. - .. _address space layout randomization: http://en.wikipedia.org/wiki/Address_space_layout_randomization + However, you need to beware of :term:`address space layout + randomization`: if you perform computation based on the addresses + of objects, for example, hashing objects by their address, then + ASLR will cause your hash tables to be laid out differently on each + run, which may affect the order of memory management operations. + See :ref:`guide-debug-aslr` below. A fact that assists with reproducibility is that the more frequently the collector runs, the sooner and more reliably errors @@ -92,13 +88,103 @@ General debugging advice handle SIGSEGV pass nostop noprint - On these operating systems, you can add this commands to your - ``.gdbinit`` if you always want them to be run. + On these operating systems, you can add this command to your + ``.gdbinit`` if you always want it to be run. - On OS X barrier hits do not use signals and so do not enter the + On OS X, barrier hits do not use signals and so do not enter the debugger. +.. index:: + single: ASLR + single: address space layout randomization + +.. _guide-debug-aslr: + +Address space layout randomization +---------------------------------- + +:term:`Address space layout randomization` (ASLR) makes it hard to +prepare a repeatable test case for a program that performs computation +based on the addresses of objects, for example, hashing objects by +their address. If this is affecting you, you'll find it useful to +disable ASLR when testing. + +Here's a small program that you can use to check if ASLR is enabled on +your system. It outputs addresses from four key memory areas in a +program (data segment, text segment, stack and heap): + +.. code-block:: c + + #include + #include + + int data; + + int main() { + void *heap = malloc(4); + int stack = 0; + printf("data: %p text: %p stack: %p heap: %p\n", + &data, (void *)main, &stack, heap); + return 0; + } + +When ASLR is turned on, running this program outputs different +addresses on each run. For example, here are four runs on OS X +10.9.3:: + + data: 0x10a532020 text: 0x10a531ed0 stack: 0x7fff556ceb1c heap: 0x7f9f80c03980 + data: 0x10d781020 text: 0x10d780ed0 stack: 0x7fff5247fb1c heap: 0x7fe498c03980 + data: 0x10164b020 text: 0x10164aed0 stack: 0x7fff5e5b5b1c heap: 0x7fb783c03980 + data: 0x10c7f8020 text: 0x10c7f7ed0 stack: 0x7fff53408b1c heap: 0x7f9740403980 + +By contrast, here are four runs on FreeBSD 8.3:: + + data: 0x8049728 text: 0x8048470 stack: 0xbfbfebfc heap: 0x28201088 + data: 0x8049728 text: 0x8048470 stack: 0xbfbfebfc heap: 0x28201088 + data: 0x8049728 text: 0x8048470 stack: 0xbfbfebfc heap: 0x28201088 + data: 0x8049728 text: 0x8048470 stack: 0xbfbfebfc heap: 0x28201088 + +On many Linux systems, ASLR can be configured for all processes on the +system by writing one of the following values to +``/proc/sys/kernel/randomize_va_space``: + + 0 - Turn the process address space randomization off. + + 1 - Make the addresses of mmap base, stack and VDSO page randomized. + + 2 - Additionally enable heap randomization. + +For example, to turn randomization off:: + + $ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space + +See the `Linux kernel documentation`_ for details. + +.. _Linux kernel documentation: https://www.kernel.org/doc/Documentation/sysctl/kernel.txt + +On OS X 10.9, ASLR can be disabled for a single process by starting +the process using :c:func:`posix_spawn`, passing the undocumented +attribute ``0x100``, like this: + +.. code-block:: c + + #include + + pid_t pid; + posix_spawnattr_t attr; + + posix_spawnattr_init(&attr); + posix_spawnattr_setflags(&attr, 0x100); + posix_spawn(&pid, argv[0], NULL, &attr, argv, environ); + +The MPS provides the source code for a command-line tool implementing +this (``tool/noaslr.c``). We've confirmed that this works on OS X +10.9.3, but since the technique is undocumented, it may well break in +future releases. (If you know of a documented way to achieve this, +please :ref:`contact us `.) + + .. index:: single: underscanning single: bug; underscanning From cc43fd2a1cc4498e8278455389eacc7826f934d6 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 21 May 2014 16:08:15 +0100 Subject: [PATCH 219/266] Add aslr test program to the repository. Explain how to disable ASLR for a single process on Linux (better than disabling it for the whole system). Organize the ASLR documentation more clearly. Copied from Perforce Change: 186236 ServerID: perforce.ravenbrook.com --- mps/manual/source/guide/debug.rst | 58 ++++++++++++++++------------- mps/tool/testaslr.c | 62 +++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 25 deletions(-) create mode 100644 mps/tool/testaslr.c diff --git a/mps/manual/source/guide/debug.rst b/mps/manual/source/guide/debug.rst index 7dfca3bcbad..060928c2ba6 100644 --- a/mps/manual/source/guide/debug.rst +++ b/mps/manual/source/guide/debug.rst @@ -145,44 +145,52 @@ By contrast, here are four runs on FreeBSD 8.3:: data: 0x8049728 text: 0x8048470 stack: 0xbfbfebfc heap: 0x28201088 data: 0x8049728 text: 0x8048470 stack: 0xbfbfebfc heap: 0x28201088 -On many Linux systems, ASLR can be configured for all processes on the -system by writing one of the following values to -``/proc/sys/kernel/randomize_va_space``: +Here's the situation on each of the operating systems supported by the MPS: - 0 - Turn the process address space randomization off. +* **FreeBSD** (as of version 10.0) does not support ASLR, so there's + nothing to do. - 1 - Make the addresses of mmap base, stack and VDSO page randomized. +* On **Windows** (Vista or later), ASLR is a property of the + executable, and it can be turned off at link time using the + |DYNAMICBASE|_. - 2 - Additionally enable heap randomization. + .. |DYNAMICBASE| replace:: ``/DYNAMICBASE:NO`` linker option + .. _DYNAMICBASE: http://msdn.microsoft.com/en-us/library/bb384887.aspx -For example, to turn randomization off:: +* On **Linux** (kernel version 2.6.12 or later), ASLR can be turned + off for a single process by running |setarch|_ with the ``-R`` + option:: - $ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space + -R, --addr-no-randomize + Disables randomization of the virtual address space -See the `Linux kernel documentation`_ for details. + .. |setarch| replace:: ``setarch`` + .. _setarch: http://man7.org/linux/man-pages/man8/setarch.8.html -.. _Linux kernel documentation: https://www.kernel.org/doc/Documentation/sysctl/kernel.txt + For example:: -On OS X 10.9, ASLR can be disabled for a single process by starting -the process using :c:func:`posix_spawn`, passing the undocumented -attribute ``0x100``, like this: + $ setarch $(uname -m) -R ./myprogram -.. code-block:: c +* On **OS X** (10.7 or later), ASLR can be disabled for a single + process by starting the process using :c:func:`posix_spawn`, passing + the undocumented attribute ``0x100``, like this: - #include + .. code-block:: c - pid_t pid; - posix_spawnattr_t attr; + #include - posix_spawnattr_init(&attr); - posix_spawnattr_setflags(&attr, 0x100); - posix_spawn(&pid, argv[0], NULL, &attr, argv, environ); + pid_t pid; + posix_spawnattr_t attr; -The MPS provides the source code for a command-line tool implementing -this (``tool/noaslr.c``). We've confirmed that this works on OS X -10.9.3, but since the technique is undocumented, it may well break in -future releases. (If you know of a documented way to achieve this, -please :ref:`contact us `.) + posix_spawnattr_init(&attr); + posix_spawnattr_setflags(&attr, 0x100); + posix_spawn(&pid, argv[0], NULL, &attr, argv, environ); + + The MPS provides the source code for a command-line tool + implementing this (``tool/noaslr.c``). We've confirmed that this + works on OS X 10.9.3, but since the technique is undocumented, it + may well break in future releases. (If you know of a documented way + to achieve this, please :ref:`contact us `.) .. index:: diff --git a/mps/tool/testaslr.c b/mps/tool/testaslr.c new file mode 100644 index 00000000000..f421565b7be --- /dev/null +++ b/mps/tool/testaslr.c @@ -0,0 +1,62 @@ +/* testaslr.c: Simple test for ASLR + * + * $Id: //info.ravenbrook.com/project/mps/master/code/eventcnv.c#26 $ + * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * + * Run this program multiple times and see if gets different addresses. + */ + +#include +#include + +int data; + +int main() { + void *heap = malloc(4); + int stack = 0; + printf("data: %p text: %p stack: %p heap: %p\n", + &data, (void *)main, &stack, heap); + return 0; +} + + +/* 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. + */ From 77f08df1d54bf2f6976704f5636927016e7aa9fc Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 22 May 2014 17:05:24 +0100 Subject: [PATCH 220/266] Insert abstracts (from the memory management reference). commented out for now, but at least data is here now. Copied from Perforce Change: 186247 ServerID: perforce.ravenbrook.com --- mps/manual/source/mmref/bib.rst | 2036 +++++++++++++++++++++++++++++++ 1 file changed, 2036 insertions(+) diff --git a/mps/manual/source/mmref/bib.rst b/mps/manual/source/mmref/bib.rst index aba18413d6e..ade7ddaed60 100644 --- a/mps/manual/source/mmref/bib.rst +++ b/mps/manual/source/mmref/bib.rst @@ -9,126 +9,537 @@ Bibliography .. abstract: ad97.html + Exact garbage collection for the strongly-typed Java language may + seem straightforward. Unfortunately, a single pair of bytecodes in + the Java Virtual Machine instruction set presents an obstacle that + has thus far not been discussed in the literature. We explain the + problem, outline the space of possible solutions, and present a + solution utilizing bytecode-preprocessing to enable exact garbage + collection while maintaining compatibility with existing compiled + Java class files. + * .. _ADM98: Ole Agesen, David L. Detlefs, J. Eliot B. Moss. 1998. "`Garbage Collection and Local Variable Type-precision and Liveness in Java Virtual Machines `_". ACM. Proceedings of the ACM SIGPLAN '98 conference on Programming language design and implementation, pp. 269--279. .. abstract: adm98.html + Full precision in garbage collection implies retaining only those + heap allocated objects that will actually be used in the future. + Since full precision is not computable in general, garbage + collectors use safe (i.e., conservative) approximations such as + reachability from a set of root references. Ambiguous roots + collectors (commonly called "conservative") can be overly + conservative because they overestimate the root set, and thereby + retain unexpectedly large amounts of garbage. We consider two more + precise collection schemes for Java virtual machines (JVMs). One + uses a type analysis to obtain a type-precise root set (only those + variables that contain references); the other adds a live variable + analysis to reduce the root set to only the live reference + variables. Even with the Java programming language's strong + typing, it turns out that the JVM specification has a feature that + makes type-precise root sets difficult to compute. We explain the + problem and ways in which it can be solved. + + Our experimental results include measurements of the costs of the + type and liveness analyses at load time, of the incremental + benefits at run time of the liveness analysis over the + type-analysis alone, and of various map sixes and counts. We find + that the liveness analysis often produces little or no improvement + in heap size, sometimes modest improvements, and occasionally the + improvement is dramatic. While further study is in order, we + conclude that the main benefit of the liveness analysis is + preventing bad surprises. + * .. _AEL88: Andrew Appel, John R. Ellis, Kai Li. 1988. "`Real-time Concurrent Collection on Stock Multiprocessors `_". ACM, SIGPLAN. ACM PLDI 88, SIGPLAN Notices 23, 7 (July 88), pp. 11--20. .. abstract: ael88.html + We've designed and implemented a copying garbage-collection + algorithm that is efficient, real-time, concurrent, runs on + commercial uniprocessors and shared-memory multiprocessors, and + requires no change to compilers. The algorithm uses standard + virtual-memory hardware to detect references to "from space" + objects and to synchronize the collector and mutator threads. + We've implemented and measured a prototype running on SRC's + 5-processor Firefly. It will be straightforward to merge our + techniques with generational collection. An incremental, + non-concurrent version could be implemented easily on many + versions of Unix. + * .. _APPLE94: Apple Computer, Inc. 1994. *Inside Macintosh: Memory*. Addison-Wesley. ISBN 0-201-63240-3. .. abstract: apple94.html + Inside Macintosh: Memory describes the parts of the Macintosh® + Operating System that allow you to directly allocate, release, or + otherwise manipulate memory. Everyone who programs Macintosh + computers should read this book. + + Inside Macintosh: Memory shows in detail how your application can + manage the memory partition it is allocated and perform other + memory-related operations. It also provides a complete technical + reference for the Memory Manager, the Virtual Memory Manager, and + other memory-related utilities provided by the system software. + * .. _ATTARDI94: Giuseppe Attardi & Tito Flagella. 1994. "`A Customisable Memory Management Framework `_". TR-94-010. .. abstract: attardi94.html + Memory management is a critical issue for many large + object-oriented applications, but in C++ only explicit memory + reclamation through the delete operator is generally available. We + analyse different possibilities for memory management in C++ and + present a dynamic memory management framework which can be + customised to the need of specific applications. The framework + allows full integration and coexistence of different memory + management techniques. The Customisable Memory Management (CMM) is + based on a primary collector which exploits an evolution of + Bartlett's mostly copying garbage collector. Specialised + collectors can be built for separate memory heaps. A Heap class + encapsulates the allocation strategy for each heap. We show how to + emulate different garbage collection styles or user-specific + memory management techniques. The CMM is implemented in C++ + without any special support in the language or the compiler. The + techniques used in the CMM are general enough to be applicable + also to other languages. + * .. _AFI98: Giuseppe Attardi, Tito Flagella, Pietro Iglio. 1998. "`A customisable memory management framework for C++ `_". Software -- Practice and Experience. 28(11), 1143--1183. .. abstract: afi98.html + Automatic garbage collection relieves programmers from the burden + of managing memory themselves and several techniques have been + developed that make garbage collection feasible in many + situations, including real time applications or within traditional + programming languages. However optimal performance cannot always + be achieved by a uniform general purpose solution. Sometimes an + algorithm exhibits a predictable pattern of memory usage that + could be better handled specifically, delaying as much as possible + the intervention of the general purpose collector. This leads to + the requirement for algorithm specific customisation of the + collector strategies. We present a dynamic memory management + framework which can be customised to the needs of an algorithm, + while preserving the convenience of automatic collection in the + normal case. The Customisable Memory Manager (CMM) organises + memory in multiple heaps. Each heap is an instance of a C++ class + which abstracts and encapsulates a particular storage discipline. + The default heap for collectable objects uses the technique of + mostly copying garbage collection, providing good performance and + memory compaction. Customisation of the collector is achieved + exploiting object orientation by defining specialised versions of + the collector methods for each heap class. The object oriented + interface to the collector enables coexistence and coordination + among the various collectors as well as integration with + traditional code unaware of garbage collection. The CMM is + implemented in C++ without any special support in the language or + the compiler. The techniques used in the CMM are general enough to + be applicable also to other languages. The performance of the CMM + is analysed and compared to other conservative collectors for + C/C++ in various configurations. + * .. _AKPY98: Alain Azagury, Elliot K. Kolodner, Erez Petrank, Zvi Yehudai. 1998. "`Combining Card Marking with Remembered Sets: How to Save Scanning Time `_". ACM. ISMM'98 pp. 10--19. .. abstract: akpy98.html + We consider the combination of card marking with remembered sets + for generational garbage collection as suggested by Hosking and + Moss. When more than two generations are used, a naive + implementation may cause excessive and wasteful scanning of the + cards and thus increase the collection time. We offer a simple + data structure and a corresponding algorithm to keep track of + which cards need be scanned for which generation. We then extend + these ideas for the Train Algorithm of Hudson and Moss. Here, the + solution is more involved, and allows tracking of which card + should be scanned for which car-collection in the train. + * .. _BAKER77: Henry G. Baker, Carl Hewitt. 1977. "`The Incremental Garbage Collection of Processes `_". ACM. SIGPLAN Notices 12, 8 (August 1977), pp. 55--59. .. abstract: baker77.html + This paper investigates some problems associated with an argument + evaluation order that we call "future" order, which is different + from both call-by-name and call-by-value. In call-by-future, each + formal parameter of a function is bound to a separate process + (called a "future") dedicated to the evaluation of the + corresponding argument. This mechanism allows the fully parallel + evaluation of arguments to a function, and has been shown to + augment the expressive power of a language. + + We discuss an approach to a problem that arises in this context: + futures which were thought to be relevant when they were created + become irrelevant through being ignored in the body of the + expression where they were bound. The problem of irrelevant + processes also appears in multiprocessing problem-solving systems + which start several processors working on the same problem but + with different methods, and return with the solution which + finishes first. This "parallel method strategy" has the drawback + that the processes which are investigating the losing methods must + be identified, stopped, and reassigned to more useful tasks. + + The solution we propose is that of garbage collection. We propose + that the goal structure of the solution plan be explicitly + represented in memory as part of the graph memory (like Lisp's + heap) so that a garbage collection algorithm can discover which + processes are performing useful work, and which can be recycled + for a new task. An incremental algorithm for the unified garbage + collection of storage and processes is described. + * .. _BAKER78: Henry G. Baker. 1978. "`List Processing in Real Time on a Serial Computer `_". ACM. Communications of the ACM 21, 4 (April 1978), pp. 280--294. .. abstract: baker78.html + A real-time list processing system is one in which the time + required by the elementary list operations (e.g. CONS, CAR, CDR, + RPLACA, RPLACD, EQ, and ATOM in LISP) is bounded by a (small) + constant. Classical implementations of list processing systems + lack this property because allocating a list cell from the heap + may cause a garbage collection, which process requires time + proportional to the heap size to finish. A real-time list + processing system is presented which continuously reclaims + garbage, including directed cycles, while linearizing and + compacting the accessible cells into contiguous locations to avoid + fragmenting the free storage pool. The program is small and + requires no time-sharing interrupts, making it suitable for + microcode. Finally, the system requires the same average time, and + not more than twice the space, of a classical implementation, and + those space requirements can be reduced to approximately classical + proportions by compact list representation. Arrays of different + sizes, a program stack, and hash linking are simple extensions to + our system, and reference counting is found to be inferior for + many applications. + * .. _BAKER79: Henry G. Baker. 1979. "`Optimizing Allocation and Garbage Collection of Spaces `_". In Winston and Brown, eds. *Artificial Intelligence: An MIT Perspective.* MIT Press. .. abstract: baker79.html + MACLISP, unlike some other implementations of LISP, allocates + storage for different types of objects in noncontiguous areas + called "spaces". These spaces partition the active storage into + disjoint areas, each of which holds a different type of object. + For example, "list cells" are stored in one space, "full-word + integers" reside in another space, "full-word floating point + numbers" in another, and so on. + + Allocating space in this manner has several advantages. An + object's type can easily be computed from a pointer to it, without + any memory references to the object itself. Thus, the LISP + primitive ATOM(x) can easily compute its result without even + paging in x. Another advantage is that the type of an object does + not require any storage within the object, so that arithmetic with + hardware data types such as full-word integers can use hardware + instructions directly. + + There are problems associated with this method of storage and type + management, however. When all data types are allocated from the + same heap, there is no problem with varying demand for the + different data types; all data types require storage from the same + pool, so that only the total amount of storage is important. Once + different data types must be allocated from different spaces, + however, the relative sizes of the spaces becomes important. + * .. _BAKER91: Henry G. Baker. 1991. "`Cache-Conscious Copying Collectors `_". OOPSLA'91/GC'91 Workshop on Garbage Collection. .. abstract: baker91.html + Garbage collectors must minimize the scarce resources of cache + space and off-chip communications bandwidth to optimize + performance on modern single-chip computer architectures. + Strategies for achieving these goals in the context of copying + garbage collection are discussed. A multi-processor + mutator/collector system is analyzed. Finally, the Intel 80860XP + architecture is studied. + * .. _BAKER92A: Henry G. Baker. 1992. "`Lively Linear Lisp -- 'Look Ma, No Garbage!' `_". ACM. SIGPLAN Notices 27, 8 (August 1992), pp. 89--98. .. abstract: baker92a.html + Linear logic has been proposed as one solution to the problem of + garbage collection and providing efficient "update-in-place" + capabilities within a more functional language. Linear logic + conserves accessibility, and hence provides a "mechanical + metaphor" which is more appropriate for a distributed-memory + parallel processor in which copying is explicit. However, linear + logic's lack of sharing may introduce significant inefficiencies + of its own. + + We show an efficient implementation of linear logic called "Linear + Lisp" that runs within a constant factor of non-linear logic. This + Linear Lisp allows RPLACX operations, and manages storage as + safely as a non-linear Lisp, but does not need a garbage + collector. Since it offers assignments but no sharing, it occupies + a twilight zone between functional languages and imperative + languages. Our Linear Lisp Machine offers many of the same + capabilities as combinator/graph reduction machines, but without + their copying and garbage collection problems. + * .. _BAKER92C: Henry G. Baker. 1992. "`The Treadmill: Real-Time Garbage Collection Without Motion Sickness `_". ACM. SIGPLAN Notices 27, 3 (March 1992), pp. 66--70. .. abstract: baker92c.html + A simple real-time garbage collection algorithm is presented which + does not copy, thereby avoiding some of the problems caused by the + asynchronous motion of objects. This in-place "treadmill" garbage + collection scheme has approximately the same complexity as other + non-moving garbage collectors, thus making it usable in a + high-level language implementation where some pointers cannot be + traced. The treadmill is currently being used in a Lisp system + built in Ada. + * .. _BAKER92: Henry G. Baker. 1992. "`CONS Should not CONS its Arguments, or, a Lazy Alloc is a Smart Alloc `_". ACM. SIGPLAN Notices 27, 3 (March 1992), 24--34. .. abstract: baker92.html + "Lazy allocation" is a model for allocating objects on the + execution stack of a high-level language which does not create + dangling references. Our model provides safe transportation into + the heap for objects that may survive the deallocation of the + surrounding stack frame. Space for objects that do not survive the + deallocation of the surrounding stack frame is reclaimed without + additional effort when the stack is popped. Lazy allocation thus + performs a first-level garbage collection, and if the language + supports garbage collection of the heap, then our model can reduce + the amortized cost of allocation in such a heap by filtering out + the short-lived objects that can be more efficiently managed in + LIFO order. A run-time mechanism called "result expectation" + further filters out unneeded results from functions called only + for their effects. In a shared-memory multi-processor environment, + this filtering reduces contention for the allocation and + management of global memory. + + Our model performs simple local operations, and is therefore + suitable for an interpreter or a hardware implementation. Its + overheads for functional data are associated only with + *assignments*, making lazy allocation attractive for "mostly + functional" programming styles. Many existing stack allocation + optimizations can be seen as instances of this generic model, in + which some portion of these local operations have been optimized + away through static analysis techniques. + + Important applications of our model include the efficient + allocation of temporary data structures that are passed as + arguments to anonymous procedures which may or may not use these + data structures in a stack-like fashion. The most important of + these objects are functional arguments (funargs), which require + some run-time allocation to preserve the local environment. Since + a funarg is sometimes returned as a first-class value, its + lifetime can survive the stack frame in which it was created. + Arguments which are evaluated in a lazy fashion (Scheme "delays" + or "suspensions") are similarly handled. Variable-length argument + "lists" themselves can be allocated in this fashion, allowing + these objects to become "first-class". Finally, lazy allocation + correctly handles the allocation of a Scheme control stack, + allowing Scheme continuations to become first-class values. + * .. _BAKER92B: Henry G. Baker. 1992. "`NREVERSAL of Fortune -- The Thermodynamics of Garbage Collection `_". Springer-Verlag. LNCS Vol. 637. .. abstract: baker92b.html + The need to *reverse* a computation arises in many contexts -- + debugging, editor undoing, optimistic concurrency undoing, + speculative computation undoing, trace scheduling, exception + handling undoing, database recovery, optimistic discrete event + simulations, subjunctive computing, etc. The need to *analyze* a + reversed computation arises in the context of static analysis -- + liveness analysis, strictness analysis, type inference, etc. + Traditional means for restoring a computation to a previous state + involve checkpoints; checkpoints require time to copy, as well as + space to store, the copied material. Traditional reverse abstract + interpretation produces relatively poor information due to its + inability to guess the previous values of assigned-to variables. + + We propose an abstract computer model and a programming language + -- Psi-Lisp -- whose primitive operations are injective and hence + reversible, thus allowing arbitrary undoing without the overheads + of checkpointing. Such a computer can be built from reversible + conservative logic circuits, with the serendipitous advantage of + dissipating far less heat than traditional Boolean AND/OR/NOT + circuits. Unlike functional languages, which have one "state" for + all times, Psi-Lisp has at all times one "state", with unique + predecessor and successor states. + + Compiling into a reversible pseudocode can have benefits even when + targeting a traditional computer. Certain optimizations, e.g., + update-in-place, and compile-time garbage collection may be more + easily performed, because the information may be elicited without + the difficult and time-consuming iterative abstract interpretation + required for most non-reversible models. + + In a reversible machine, garbage collection for recycling storage + can always be performed by a reversed (sub)computation. While this + "collection is reversed mutation" insight does not reduce space + requirements when used for the computation as a whole, it does + save space when used to recycle at finer scales. This insight also + provides an explanation for the fundamental importance of the + push-down stack both for recognizing palindromes and for managing + storage. + + Reversible computers are related to *Prolog*, *linear logic* and + *chemical abstract machines*. + * .. _BAKER93: Henry G. Baker. 1993. "`'Infant Mortality' and Generational Garbage Collection `_". ACM. SIGPLAN Notices 28, 4 (April 1993), pp. 55--57. .. abstract: baker93.html + Generation-based garbage collection has been advocated by + appealing to the intuitive but vague notion that "young objects + are more likely to die than old objects". The intuition is, that + if a generation-based garbage collection scheme focuses its effort + on scanning recently created objects, then its scanning efforts + will pay off more in the form of more recovered garbage, than if + it scanned older objects. In this note, we show a counterexample + of a system in which "infant mortality" is as high as you please, + but for which generational garbage collection is ineffective for + improving the average mark/cons ratio. Other benefits, such as + better locality and a smaller number of large delays, may still + make generational garbage collection attractive for such a system, + however. + * .. _BAKER93A: Henry G. Baker. 1993. "`Equal Rights for Functional Objects or, The More Things Change, The More They Are the Same `_". ACM. OOPS Messenger 4, 4 (October 1993), pp. 2--27. .. abstract: baker93a.html + We argue that intensional object identity in object-oriented + programming languages and databases is best defined operationally + by side-effect semantics. A corollary is that "functional" objects + have extensional semantics. This model of object identity, which + is analogous to the normal forms of relational algebra, provides + cleaner semantics for the value-transmission operations and + built-in primitive equality predicate of a programming language, + and eliminates the confusion surrounding "call-by-value" and + "call-by-reference" as well as the confusion of multiple equality + predicates. + + Implementation issues are discussed, and this model is shown to + have significant performance advantages in persistent, parallel, + distributed and multilingual processing environments. This model + also provides insight into the "type equivalence" problem of + Algol-68, Pascal and Ada. + * .. _BAKER94: Henry G. Baker. 1994. "`Minimizing Reference Count Updating with Deferred and Anchored Pointers for Functional Data Structures `_". ACM. SIGPLAN Notices 29, 9 (September 1994), pp. 38--43. .. abstract: baker94.html + "Reference counting" can be an attractive form of dynamic storage + management. It recovers storage promptly and (with a garbage stack + instead of a free list) it can be made "real-time" -- i.e., all + accesses can be performed in constant time. Its major drawbacks + are its inability to reclaim cycles, its count storage, and its + count update overhead. Update overhead is especially irritating + for functional (read-only) data where updates may dirty pristine + cache lines and pages. + + We show how reference count updating can be largely eliminated for + functional data structures by using the "linear style" of + programming that is inspired by Girard's linear logic, and by + distinguishing normal pointers from "anchored pointers", which + indicate not only the object itself, but also the depth of the + stack frame that anchors the object. An "anchor" for a pointer is + essentially an enclosing data structure that is temporarily locked + from being collected for the duration of the anchored pointer's + existence by a deferred reference count. An "anchored pointer" + thus implies a reference count increment that has been deferred + until it is either cancelled or performed. + + Anchored pointers are generalizations of "borrowed" pointers and + "phantom" pointers. Anchored pointers can provide a solution to + the "derived pointer problem" in garbage collection. + * .. _BAKER94A: Henry G. Baker. 1994. "`Thermodynamics and Garbage Collection `_". ACM. SIGPLAN Notices 29, 4 (April 1994), pp. 58--63. .. abstract: baker94a.html + We discuss the principles of statistical thermodynamics and their + application to storage management problems. We point out problems + which result from imprecise usage of the terms "information", + "state", "reversible", "conservative", etc. + * .. _BAKER95A: Henry G. Baker. 1995. "`'Use-Once' Variables and Linear Objects -- Storage Management, Reflection and Multi-Threading `_". ACM. SIGPLAN Notices 30, 1 (January 1995), pp. 45--52. .. abstract: baker95a.html + Programming languages should have 'use-once' variables in addition + to the usual 'multiple-use' variables. 'Use-once' variables are + bound to linear (unshared, unaliased, or singly-referenced) + objects. Linear objects are cheap to access and manage, because + they require no synchronization or tracing garbage collection. + Linear objects can elegantly and efficiently solve otherwise + difficult problems of functional/mostly-functional systems -- + e.g., in-place updating and the efficient initialization of + functional objects. Use-once variables are ideal for directly + manipulating resources which are inherently linear such as + freelists and 'engine ticks' in reflective languages. + + A 'use-once' variable must be dynamically referenced exactly once + within its scope. Unreferenced use-once variables must be + explicitly killed, and multiply-referenced use-once variables must + be explicitly copied; this duplication and deletion is subject to + the constraint that some linear datatypes do not support + duplication and deletion methods. Use-once variables are bound + only to linear objects, which may reference other linear or + non-linear objects. Non-linear objects can reference other + non-linear objects, but can reference a linear object only in a + way that ensures mutual exclusion. + + Although implementations have long had implicit use-once variables + and linear objects, most languages do not provide the programmer + any help for their utilization. For example, use-once variables + allow for the safe/controlled use of reified language + implementation objects like single-use continuations. + + Linear objects and use-once variables map elegantly into dataflow + models of concurrent computation, and the graphical + representations of dataflow models make an appealing visual linear + programming language. + * .. _BAKER95: Henry G. Baker. 1995. *Memory Management: International Workshop IWMM'95*. Springer-Verlag. ISBN 3-540-60368-9. .. abstract: baker95.html + [from the preface] The International Workshop on Memory Management + 1995 (IWMM'95) is a continuation of the excellent series started + by Yves Bekkers and Jacques Cohen with IWMM'92. The present volume + assembles the refereed and invited technical papers which were + presented during this year's workshop. + * .. _BBW97: Nick Barnes, Richard Brooksby, David Jones, Gavin Matthews, Pekka P. Pirinen, Nick Dalton, P. Tucker Withington. 1997. "`A Proposal for a Standard Memory Management Interface `_". OOPSLA97 Workshop on Garbage Collection and Memory Management. @@ -139,24 +550,113 @@ Bibliography .. abstract: zorn93b.html + Dynamic storage allocation is used heavily in many application + areas including interpreters, simulators, optimizers, and + translators. We describe research that can improve all aspects of + the performance of dynamic storage allocation by predicting the + lifetimes of short-lived objects when they are allocated. Using + five significant, allocation-intensive C programs, we show that a + great fraction of all bytes allocated are short-lived (> 90% in + all cases). Furthermore, we describe an algorithm for lifetime + prediction that accurately predicts the lifetimes of 42-99% of all + objects allocated. We describe and simulate a storage allocator + that takes advantage of lifetime prediction of short-lived objects + and show that it can significantly improve a program's memory + overhead and reference locality, and even, at times, improve CPU + performance as well. + * .. _BARRETT93: David A. Barrett, Benjamin Zorn. 1995. "`Garbage Collection using a Dynamic Threatening Boundary `_". ACM. SIGPLAN'95 Conference on Programming Language Design and Implementation, pp. 301--314. .. abstract: barrett93.html + Generational techniques have been very successful in reducing the + impact of garbage collection algorithms upon the performance of + programs. However, it is impossible for designers of collection + algorithms to anticipate the memory allocation behavior of all + applications in advance. Existing generational collectors rely + upon the applications programmer to tune the behavior of the + collector to achieve maximum performance for each application. + Unfortunately, because the many tuning parameters require detailed + knowledge of both the collection algorithm and the program + allocation behavior in order to be used effectively, such tuning + is difficult and error prone. We propose a new garbage collection + algorithm that uses just two easily understood tuning parameters + that directly reflect the maximum memory and pause time + constraints familiar to application programmers and users. + + Like generational collectors, ours divides memory into two spaces, + one for short-lived, and another for long-lived objects. Unlike + previous work, our collector dynamically adjusts the boundary + between these two spaces in order to directly meet the resource + constraints specified by the user. We describe two methods for + adjusting this boundary, compare them with several existing + algorithms, and show how effectively ours meets the specified + constraints. Our pause time collector saved memory by holding + median pause times closer to the constraint than the other pause + time constrained algorithm and, when not over-constrained, our + memory constrained collector exhibited the lowest CPU overhead of + the algorithms we measured yet was capable of maintaining a + maximum memory constraint. + * .. _BARTLETT88: Joel F. Bartlett. 1988. "`Compacting Garbage Collection with Ambiguous Roots `_". Digital Equipment Corporation. .. abstract: bartlett88.html + This paper introduces a copying garbage collection algorithm which + is able to compact most of the accessible storage in the heap + without having an explicitly defined set of pointers that contain + all the roots of all accessible storage. Using "hints" found in + the processor's registers and stack, the algorithm is able to + divide heap allocated objects into two groups: those that might be + referenced by a pointer in the stack or registers, and those that + are not. The objects which might be referenced are left in place, + and the other objects are copied into a more compact + representation. + + A Lisp compiler and runtime system which uses such a collector + need not have complete control of the processor in order to force + a certain discipline on the stack and registers. A Scheme + implementation has been done for the Digital WRL Titan processor + which uses a garbage collector based on this "mostly copying" + algorithm. Like other languages for the Titan, it uses the Mahler + intermediate language as its target. This simplifies the compiler + and allows it to take advantage of the significant machine + dependent optimizations provided by Mahler. The common + intermediate language also simplifies call-outs from Scheme + programs to functions written in other languages and call-backs + from functions in other languages. + + Measurements of the Scheme implementation show that the algorithm + is efficient, as little unneeded storage is retained and only a + very small fraction of the heap is left in place. + + Simple pointer manipulation protocols also mean that compiler + support is not needed in order to correctly handle pointers. Thus + it is reasonable to provide garbage collected storage in languages + such as C. A collector written in C which uses this algorithm is + included in the Appendix. + * .. _BARTLETT89: Joel F. Bartlett. 1989. "`Mostly-Copying Garbage Collection Picks Up Generations and C++ `_". Digital Equipment Corporation. .. abstract: bartlett89.html + The "mostly-copying" garbage collection algorithm provides a way + to perform compacting garbage collection in spite of the presence + of ambiguous pointers in the root set. As originally defined, each + collection required almost all accessible objects to be moved. + While adequate for many applications, programs that retained a + large amount of storage spent a significant amount of time garbage + collecting. To improve performance of these applications, a + generational version of the algorithm has been designed. This note + reports on this extension of the algorithm, and its application in + collectors for Scheme and C++. + * .. _BC92: Yves Bekkers & Jacques Cohen. 1992. "`Memory Management, International Workshop IWMM 92 `_". Springer-Verlag. LNCS Vol. 637, ISBN 3-540-55940-X. @@ -167,6 +667,12 @@ Bibliography .. abstract: bb99.html + In this paper, we present Hoard, a memory allocator for + shared-memory multiprocessors. We prove that its worst-case memory + fragmentation is asymptotically equivalent to that of an optimal + uniprocessor allocator. We present experiments that demonstrate + its speed and scalability. + * .. _BERGER01: Emery D. Berger, Benjamin G. Zorn, Kathryn S. McKinley. 2001. "`Composing high-performance memory allocators `_" ACM SIGPLAN Conference on Programming Language Design and Implementation 2001, pp. 114--124. @@ -177,12 +683,33 @@ Bibliography .. abstract: bw88.html + We describe a technique for storage allocation and garbage + collection in the absence of significant co-operation from the + code using the allocator. This limits garbage collection overhead + to the time actually required for garbage collection. In + particular, application programs that rarely or never make use of + the collector no longer encounter a substantial performance + penalty. This approach greatly simplifies the implementation of + languages supporting garbage collection. It further allows + conventional compilers to be used with a garbage collector, either + as the primary means of storage reclamation, or as a debugging + tool. + * .. _BDS91: Hans-J. Boehm, Alan J. Demers, Scott Shenker. 1991. "`Mostly Parallel Garbage Collection `_". Xerox PARC. ACM PLDI 91, SIGPLAN Notices 26, 6 (June 1991), pp. 157--164. .. abstract: bds91.html + We present a method for adapting garbage collectors designed to + run sequentially with the client, so that they may run + concurrently with it. We rely on virtual memory hardware to + provide information about pages that have been updated or + "dirtied" during a given period of time. This method has been used + to construct a mostly parallel trace-and-sweep collector that + exhibits very short pause times. Performance measurements are + given. + * .. _BC92A: Hans-J. Boehm, David Chase. 1992. "A Proposal for Garbage-Collector-Safe C Compilation". *Journal of C Language Translation.* vol. 4, 2 (December 1992), pp. 126--141. @@ -193,12 +720,51 @@ Bibliography .. abstract: boehm93.html + We call a garbage collector conservative if it has only partial + information about the location of pointers, and is thus forced to + treat arbitrary bit patterns as though they might be pointers, in + at least some cases. We show that some very inexpensive, but + previously unused techniques can have dramatic impact on the + effectiveness of conservative garbage collectors in reclaiming + memory. Our most significant observation is that static data that + appears to point to the heap should not result in misidentified + reference to the heap. The garbage collector has enough + information to allocate around such references. We also observe + that programming style has a significantly impact on the amount of + spuriously retained storage, typically even if the collector is + not terribly conservative. Some fairly common C and C++ + programming styles significantly decrease the effectiveness of any + garbage collector. These observations suffice to explain some of + the different assessments of conservative collection that have + appeared in the literature. + * .. _BOEHM00: Hans-J. Boehm. 2000. "`Reducing Garbage Collector Cache Misses `_". ACM. ISMM'00 pp. 59--64. .. abstract: boehm00.html + Cache misses are currently a major factor in the cost of garbage + collection, and we expect them to dominate in the future. + Traditional garbage collection algorithms exhibit relatively litle + temporal locality; each live object in the heap is likely to be + touched exactly once during each garbage collection. We measure + two techniques for dealing with this issue: prefetch-on-grey, and + lazy sweeping. The first of these is new in this context. Lazy + sweeping has been in common use for a decade. It was introduced as + a mechanism for reducing paging and pause times; we argue that it + is also crucial for eliminating cache misses during the sweep + phase. + + Our measurements are obtained in the context of a non-moving + garbage collector. Fully copying garbage collection inherently + requires more traffic through the cache, and thus probably also + stands to benefit substantially from something like the + prefetch-on-grey technique. Generational garbage collection may + reduce the benefit of these techniques for some applications, but + experiments with a non-moving generational collector suggest that + they remain quite useful. + * .. _BOEHM02: Hans-J. Boehm. 2002. "`Destructors, Finalizers, and Synchronization `_". HP Labs technical report HPL-2002-335. @@ -229,6 +795,23 @@ Bibliography .. abstract: cgz94.html + Improving the performance of C programs has been a topic of great + interest for many years. Both hardware technology and compiler + optimization research has been applied in an effort to make C + programs execute faster. In many application domains, the C++ + language is replacing C as the programming language of choice. In + this paper, we measure the empirical behavior of a group of + significant C and C++ programs and attempt to identify and + quantify behavioral differences between them. Our goal is to + determine whether optimization technology that has been successful + for C programs will also be successful in C++ programs. We + furthermore identify behavioral characteristics of C++ programs + that suggest optimizations that should be applied in those + programs. Our results show that C++ programs exhibit behavior that + is significantly different than C programs. These results should + be of interest to compiler writers and architecture designers who + are designing systems to execute object-oriented programs. + * .. _CPC00: Dante J. Cannarozzi, Michael P. Plezbert, Ron K. Cytron. 2000. "`Contaminated garbage collection `_". ACM. Proceedings of the ACM SIGPLAN '00 conference on on Programming language design and implementation, pp. 264--273. @@ -251,30 +834,122 @@ Bibliography .. abstract: cl98.html + Processor and memory technology trends show a continual increase + in the cost of accessing main memory. Machine designers have tried + to mitigate the effect of this trend through a variety of + techniques that attempt to reduce or tolerate memory latency. + These techniques, unfortunately, have only been partially + successful for pointer-manipulating programs. Recent research has + demonstrated that these programs can benefit greatly from the + complementary approach of reorganizing pointer data structures to + improve cache locality. This paper describes how a generational + garbage collector can be used to achieve a cache-conscious data + layout, in which objects with high temporal affinity are placed + next to each other, so they are likely to reside in the same cache + block. The paper demonstrates the feasibility of collecting low + overhead, real-time profiling information about data access + patterns for object-oriented languages, and describes a new + copying algorithm that utilizes this information to produce a + cache-conscious object layout. Preliminary results indicate that + this technique reduces cache miss rates by 21-42\%, and improves + program performance by 14-37\%. + * .. _CH97: William D Clinger & Lars T Hansen. 1997. "`Generational Garbage Collection and the Radioactive Decay Model `_". ACM. Proceedings of PLDI 1997. .. abstract: ch97.html + If a fixed exponentially decreasing probability distribution + function is used to model every object's lifetime, then the age of + an object gives no information about its future life expectancy. + This *radioactive decay model* implies that there can be no + rational basis for deciding which live objects should be promoted + to another generation. Yet there remains a rational basis for + deciding how many objects to promote, when to collect garbage, and + which generations to collect. + + Analysis of the model leads to a new kind of generational garbage + collector whose effectiveness does not depend upon heuristics that + predict which objects will live longer than others. + + This result provides insight into the computational advantages of + generational garbage collection, with implications for the + management of objects whose life expectancies are difficult to + predict. + * .. _COHEN81: Jacques Cohen. 1981. "Garbage collection of linked data structures". Computing Surveys. Vol. 13, no. 3. .. abstract: cohen81.html + A concise and unified view of the numerous existing algorithms for + performing garbage collection of linked data structures is + presented. The emphasis is on garbage collection proper, rather + than on storage allocation. + + First, the classical garbage collection algorithms and their + marking and collecting phases, with and without compacting, are + discussed. + + Algorithms describing these phases are classified according to the + type of cells to be collected: those for collecting single-sized + cells are simpler than those for varisized cells. Recently + proposed algorithms are presented and compared with the classical + ones. Special topics in garbage collection are also covered. A + bibliography with topical annotations is included. + * .. _CCZ98: Dominique Colnet, Philippe Coucaud, Olivier Zendra. 1998. "`Compiler Support to Customize the Mark and Sweep Algorithm `_". ACM. ISMM'98 pp. 154--165. .. abstract: ccz98.html + Mark and sweep garbage collectors (GC) are classical but still + very efficient automatic memory management systems. Although + challenged by other kinds of systems, such as copying collectors, + mark and sweep collectors remain among the best in terms of + performance. + + This paper describes our implementation of an efficient mark and + sweep garbage collector tailored to each program. Compiler support + provides the type information required to statically and + automatically generate this customized garbage collector. The + segregation of object by type allows the production of a more + efficient GC code. This technique, implemented in SmallEiffel, our + compiler for the object-oriented language Eiffel, is applicable to + other languages and other garbage collection algorithms, be they + distributed or not. + + We present the results obtained on programs featuring a variety of + programming styles and compare our results to a well-known and + high-quality garbage collector. + * .. _CWZ93: Jonathan E. Cook, Alexander L. Wolf, Benjamin Zorn. 1994. "`Partition Selection Policies in Object Database Garbage Collection `_". ACM. SIGMOD. International Conference on the Management of Data (SIGMOD'94), pp. 371--382. .. abstract: cwz93.html + The automatic reclamation of storage for unreferenced objects is + very important in object databases. Existing language system + algorithms for automatic storage reclamation have been shown to be + inappropriate. In this paper, we investigate methods to improve + the performance of algorithms for automatic storage reclamation of + object databases. These algorithms are based on a technique called + partitioned garbage collection, in which a subset of the entire + database is collected independently of the rest. Specifically, we + investigate the policy that is used to select what partition in + the database should be collected. The new partition selection + policies that we propose and investigate are based on the + intuition that the values of overwritten pointers provide good + hints about where to find garbage. Using trace-driven simulation, + we show that one of our policies requires less I/O to collect more + garbage than any existing implementable policy and performs close + to an impractical-to-implement but near-optimal policy over a wide + range of database sizes and connectivities. + * .. _CKWZ96: Jonathan E. Cook, Artur Klauser, Alexander L. Wolf, Benjamin Zorn. 1996. "`Semi-automatic, Self-adaptive Control of Garbage Collection Rates in Object Databases `_". ACM, SIGMOD. International Conference on the Management of Data (SIGMOD'96), pp. 377--388. @@ -285,6 +960,12 @@ Bibliography .. abstract: cns92.html + We improved the performance of garbage collection in the Standard ML of + New Jersey system by using the virtual memory facilities provided by + the Mach kernel. We took advantage of Mach's support for large sparse + address spaces and user-defined paging servers. We decreased the + elapsed time for realistic applications by as much as a factor of 4. + * .. _DACONTA93: Michael C. Daconta. 1993. *C Pointers and Dynamic Memory Management.* Wiley. ISBN 0-471-56152-5. @@ -295,6 +976,18 @@ Bibliography .. abstract: daconta95.html + [from the back cover] Using techniques developed in the classroom + at America Online's Programmer's University, Michael Daconta + deftly pilots programmers through the intricacies of the two most + difficult aspects of C++ programming: pointers and dynamic memory + management. Written by a programmer for programmers, this + no-nonsense, nuts-and-bolts guide shows you how to fully exploit + advanced C++ programming features, such as creating class-specific + allocators, understanding references versus pointers, manipulating + multidimensional arrays with pointers, and how pointers and + dynamic memory are the core of object-oriented constructs like + inheritance, name-mangling, and virtual functions. + * .. _DAHL63: O.-J. Dahl. 1963. "The SIMULA Storage Allocation Scheme". Norsk Regnesentral. NCC Document no. 162. @@ -321,6 +1014,21 @@ Bibliography .. abstract: zorn93.html + Dynamic storage allocation is an important part of a large class + of computer programs written in C and C++. High-performance + algorithms for dynamic storage allocation have been, and will + continue to be, of considerable interest. This paper presents + detailed measurements of the cost of dynamic storage allocation in + 11 diverse C and C++ programs using five very different dynamic + storage allocation implementations, including a conservative + garbage collection algorithm. Four of the allocator + implementations measured are publicly-available on the Internet. A + number of the programs used in these measurements are also + available on the Internet to facilitate further research in + dynamic storage allocation. Finally, the data presented in this + paper is an abbreviated version of more extensive statistics that + are also publicly-available on the Internet. + * .. _DB76: L. Peter Deutsch, Daniel G. Bobrow. 1976. "`An Efficient, Incremental, Automatic Garbage Collector `_". CACM. vol. 19, no. 9, pp. 522--526. @@ -335,36 +1043,114 @@ Bibliography .. abstract: dmh92.html + We consider the problem of supporting compacting garbage + collection in the presence of modern compiler optimizations. Since + our collector may move any heap object, it must accurately locate, + follow, and update all pointers and values derived from pointers. + To assist the collector, we extend the compiler to emit tables + describing live pointers, and values derived from pointers, at + each program location where collection may occur. Significant + results include identification of a number of problems posed by + optimizations, solutions to those problems, a working compiler, + and experimental data concerning table sizes, table compression, + and time overhead of decoding tables during collection. While gc + support can affect the code produced, our sample programs show no + significant changes, the table sizes are a modest fraction of the + size of the optimized code, and stack tracing is a small fraction + of total gc time. Since the compiler enhancements are also modest, + we conclude that the approach is practical. + * .. _DTM93: Amer Diwan, David Tarditi, J. Eliot B. Moss. 1993. "`Memory Subsystem Performance of Programs with Intensive Heap Allocation `_". Carnegie Mellon University. CMU-CS-93-227. .. abstract: dtm93.html + Heap allocation with copying garbage collection is a general + storage management technique for modern programming languages. It + is believed to have poor memory subsystem performance. To + investigate this, we conducted an in-depth study of the memory + subsystem performance of heap allocation for memory subsystems + found on many machines. We studied the performance of + mostly-functional Standard ML programs which made heavy use of + heap allocation. We found that most machines support heap + allocation poorly. However, with the appropriate memory subsystem + organization, heap allocation can have good performance. The + memory subsystem property crucial for achieving good performance + was the ability to allocate and initialize a new object into the + cache without a penalty. This can be achieved by having subblock + placement with a subblock size of one word with a write allocate + policy, along with fast page-mode writes or a write buffer. For + caches with subblock placement, the data cache overhead was under + 9% for a 64k or larger data cache; without subblock placement the + overhead was often higher than 50%. + * .. _DTM93A: Amer Diwan, David Tarditi, J. Eliot B. Moss. 1994. "`Memory Subsystem Performance of Programs Using Copying Garbage Collection `_". ACM. CMU-CS-93-210, also in POPL '94. .. abstract: dtm93a.html + Heap allocation with copying garbage collection is believed to + have poor memory subsystem performance. We conducted a study of + the memory subsystem performance of heap allocation for memory + subsystems found on many machines. We found that many machines + support heap allocation poorly. However, with the appropriate + memory subsystem organization, heap allocation can have good + memory subsystem performance. + * .. _DOLIGEZ93: Damien Doligez & Xavier Leroy. 1993. "`A concurrent, generational garbage collector for a multithreaded implementation of ML `_". ACM. POPL '93, 113--123. .. abstract: doligez93.html + This paper presents the design and implementation of a "quasi + real-time" garbage collector for Concurrent Caml Light, an + implementation of ML with threads. This two-generation system + combines a fast, asynchronous copying collector on the young + generation with a non-disruptive concurrent marking collector on + the old generation. This design crucially relies on the ML + compile-time distinction between mutable and immutable objects. + * .. _DOLIGEZ94: Damien Doligez & Georges Gonthier. 1994. "`Portable, unobtrusive garbage collection for multiprocessor systems `_". ACM. POPL '94, 70--83. .. abstract: doligez94.html + We describe and prove the correctness of a new concurrent + mark-and-sweep garbage collection algorithm. This algorithm + derives from the classical on-the-fly algorithm from Dijkstra et + al. A distinguishing feature of our algorithm is that it supports + multiprocessor environments where the registers of running + processes are not readily accessible, without imposing any + overhead on the elementary operations of loading a register or + reading or initializing a field. Furthermore our collector never + blocks running mutator processes except possibly on requests for + free memory; in particular, updating a field or creating or + marking or sweeping a heap object does not involve + system-dependent synchronization primitives such as locks. We also + provide support for process creation and deletion, and for + managing an extensible heap of variable-sized objects. + * .. _DBE93: R. Kent Dybvig, Carl Bruggeman, David Eby. 1993. "`Guardians in a Generation-Based Garbage Collector `_". SIGPLAN. Proceedings of the ACM SIGPLAN '93 Conference on Programming Language Design and Implementation, June 1993. .. abstract: dbe93.html + This paper describes a new language feature that allows + dynamically allocated objects to be saved from deallocation by an + automatic storage management system so that clean-up or other + actions can be performed using the data stored within the objects. + The program has full control over the timing of clean-up actions, + which eliminates several potential problems and often eliminates + the need for critical sections in code that interacts with + clean-up actions. Our implementation is "generation-friendly" in + the sense that the additional overhead within the mutator is + proportional to the number of clean-up actions actually performed. + * .. _EDELSON92A: Daniel R. Edelson. 1992. "`Smart pointers: They're smart, but they're not pointers `_". USENIX C++ Conference. @@ -379,18 +1165,66 @@ Bibliography .. abstract: edwards.html + (This short memo doesn't have an abstract. Basically, it describes + the plan for the LISP II Relocating Garbage Collector. It has four + phases: marking, collection, relocation and moving. Marking is by + recursive descent using a bit table. The remaining phases are + linear sweeps through the bit table. The collection phase + calculates how much everything needs to move, storing this + information in the free blocks. The relocation phase updates all + relocatable addresses. The moving phase moves the surviving + objects into one contiguous block.) + * .. _ELLIS93: John R. Ellis, David L. Detlefs. 1993. "`Safe, Efficient Garbage Collection for C++ `_". Xerox PARC. .. abstract: ellis93.html + We propose adding safe, efficient garbage collection to C++, + eliminating the possibility of storage-management bugs and making + the design of complex, object-oriented systems much easier. This + can be accomplished with almost no change to the language itself + and only small changes to existing implementations, while + retaining compatibility with existing class libraries. + * .. _FERREIRA96: Paulo Ferreira. 1996. "`Larchant: garbage collection in a cached distributed shared store with persistence by reachability `_". Université Paris VI. Thése de doctorat. .. abstract: ferreira96.html + The model of Larchant is that of a *Shared Address Space* + (spanning every site in a network including secondary storage) + with *Persistence By Reachability*. To provide the illusion of a + shared address space across the network, despite the fact that + site memories are disjoint, Larchant implements a *distributed + shared memory* mechanism. Reachability is accessed by tracing the + pointer graph, starting from the persistent root, and reclaiming + unreachable objects. This is the task of *Garbage Collection* + (GC). + + GC was until recently thought to be intractable in a large-scale + system, due to problems of scale, incoherence, asynchrony, and + performance. This thesis presents the solutions that Larchant + proposes to these problems. + + The GC algorithm in Larchant combines tracing and + reference-listing. It traces whenever economically feasible, i.e., + as long as the memory subset being collected remains local to a + site, and counts references that would cost I/O traffic to trace. + GC is orthogonal to coherence, i.e., makes progress even if only + incoherent replicas are locally available. The garbage collector + runs concurrently and asynchronously to applications. The + reference-listing boundary changes dynamically and seamlessly, and + independently at each site, in order to collect cycles of + unreachable objects. + + We prove formally that our GC algorithm is correct, i.e., it is + safe and live. The performance results from our Larchant prototype + show that our design goals (scalability, coherence orthogonality, + and good performance) are fulfilled. + * .. _FS98: Paulo Ferreira & Marc Shapiro. 1998. "`Modelling a Distributed Cached Store for Garbage Collection `_". Springer-Verlag. Proceedings of 12th European Conference on Object-Oriented Programming, ECOOP98, LNCS 1445. @@ -405,6 +1239,21 @@ Bibliography .. abstract: fw77.html + Deutsch and Bobrow propose a storage reclamation scheme for a heap + which is a hybrid of garbage collection and reference counting. + The point of the hybrid scheme is to keep track of very low + reference counts between necessary invocation of garbage + collection so that nodes which are allocated and rather quickly + abandoned can be returned to available space, delaying necessity + for garbage collection. We show how such a scheme may be + implemented using the mark bit already required in every node by + the garbage collector. Between garbage collections that bit is + used to distinguish nodes with a reference count known to be one. + A significant feature of our scheme is a small cache of references + to nodes whose implemented counts "ought to be higher" which + prevents the loss of logical count information in simple + manipulations of uniquely referenced structures. + * .. _FW79: Daniel P Friedman, David S. Wise. 1979. "`Reference counting can manage the circular environments of mutual recursion `_". *Information Processing Letters.* 8, 1 (January 1979): 41--45. @@ -415,42 +1264,169 @@ Bibliography .. abstract: gzh93.html + The allocation and disposal of memory is a ubiquitous operation in + most programs. Rarely do programmers concern themselves with + details of memory allocators; most assume that memory allocators + provided by the system perform well. This paper presents a + performance evaluation of the reference locality of dynamic + storage allocation algorithms based on trace-driven simulation of + five large allocation-intensive C programs. In this paper, we show + how the design of a memory allocator can significantly affect the + reference locality for various applications. Our measurements show + that poor locality in sequential-fit algorithms reduces program + performance, both by increasing paging and cache miss rates. While + increased paging can be debilitating on any architecture, cache + misses rates are also important for modern computer architectures. + We show that algorithms attempting to be space-efficient, by + coalescing adjacent free objects show poor reference locality, + possibly negating the benefits of space efficiency. At the other + extreme, algorithms can expend considerable effort to increase + reference locality yet gain little in total execution performance. + Our measurements suggest an allocator design that is both very + fast and has good locality of reference. + * .. _GRUN92: Dirk Grunwald & Benjamin Zorn. 1993. "`CustoMalloc: Efficient Synthesized Memory Allocators `_". Software -- Practice and Experience. 23(8):851--869. .. abstract: grun92.html + The allocation and disposal of memory is a ubiquitous operation in + most programs. Rarely do programmers concern themselves with + details of memory allocators; most assume that memory allocators + provided by the system perform well. Yet, in some applications, + programmers use domain-specific knowledge in an attempt to improve + the speed or memory utilization of memory allocators. In this + paper, we describe a program (CustoMalloc) that synthesizes a + memory allocator customized for a specific application. Our + experiments show that the synthesized allocators are uniformly + faster than the common binary-buddy (BSD) allocator, and are more + space efficient. Constructing a custom allocator requires little + programmer effort. The process can usually be accomplished in a + few minutes, and yields results superior even to domain-specific + allocators designed by programmers. Our measurements show the + synthesized allocators are from two to ten times faster than + widely used allocators. + * .. _GUDEMAN93: David Gudeman. 1993. "`Representing Type Information in Dynamically Typed Languages `_". University of Arizona at Tucson. Technical Report TR 93-27. .. abstract: gudeman93.html + This report is a discussion of various techniques for representing + type information in dynamically typed languages, as implemented on + general-purpose machines (and costs are discussed in terms of + modern RISC machines). It is intended to make readily available a + large body of knowledge that currently has to be absorbed + piecemeal from the literature or re-invented by each language + implementor. This discussion covers not only tagging schemes but + other forms of representation as well, although the discussion is + strictly limited to the representation of type information. It + should also be noted that this report does not purport to contain + a survey of the relevant literature. Instead, this report gathers + together a body of folklore, organizes it into a logical + structure, makes some generalizations, and then discusses the + results in terms of modern hardware. + * .. _HARRIS99: Timothy Harris. 1999. "`Early storage reclamation in a tracing garbage collector `_". ACM. ACM SIG-PLAN Notices 34:4, pp. 46--53. .. abstract: harris99.html + This article presents a technique for allowing the early recovery + of storage space occupied by garbage data. The idea is similar to + that of generational garbage collection, except that the heap is + partitioned based on a static analysis of data type definitions + rather than on the approximate age of allocated objects. A + prototype implementation is presented, along with initial results + and ideas for future work. + * .. _HENRIK94: Roger Henriksson. 1994. "Scheduling Real Time Garbage Collection". Department of Computer Science at Lund University. LU-CS-TR:94-129. .. abstract: henrik94.html + This paper presents a new model for scheduling the work of an + incremental garbage collector in a system with hard real time + requirements. The method utilizes the fact that just some of the + processes in the system have to meet hard real time requirements + and that these processes typically run periodically, a fact that + we can make use of when scheduling the garbage collection. The + work of the collector is scheduled to be performed in the pauses + between the critical processes and is suspended when the processes + with hard real time requirements run. It is shown that this + approach is feasible for many real time systems and that it leaves + the time-critical parts of the system undisturbed from garbage + collection induced delays. + * .. _HENRIK96: Roger Henriksson. 1996. "`Adaptive Scheduling of Incremental Copying Garbage Collection for Interactive Applications `_". NWPER96. .. abstract: henrik96.html + Incremental algorithms are often used to interleave the work of a + garbage collector with the execution of an application program, + the intention being to avoid long pauses. However, overestimating + the worst-case storage needs of the program often causes all the + garbage collection work to be performed in the beginning of the + garbage collection cycles, slowing down the application program to + an unwanted degree. This paper explores an approach to + distributing the work more evenly over the garbage collection + cycle. + * .. _HENRIKSSON98: Roger Henriksson. 1998. "`Scheduling Garbage Collection in Embedded Systems `_". Department of Computer Science at Lund University. Ph.D. thesis. .. abstract: henriksson98.html + The complexity of systems for automatic control and other + safety-critical applications grows rapidly. Computer software + represents an increasing part of the complexity. As larger systems + are developed, we need to find scalable techniques to manage the + complexity in order to guarantee high product quality. Memory + management is a key quality factor for these systems. Automatic + memory management, or garbage collection, is a technique that + significantly reduces the complex problem of correct memory + management. The risk of software errors decreases and development + time is reduced. + + Garbage collection techniques suitable for interactive and soft + real-time systems exist, but few approaches are suitable for + systems with hard real-time requirements, such as control systems + (embedded systems). One part of the problem is solved by + incremental garbage collection algorithms, which have been + presented before. We focus on the scheduling problem which forms + the second part of the problem, i.e. how the work of a garbage + collector should be scheduled in order to disturb the application + program as little as possible. It is studied how a priori + scheduling analysis of systems with automatic memory management + can be made. The field of garbage collection research is thus + joined with the field of scheduling analysis in order to produce a + practical synthesis of the two fields. + + A scheduling strategy is presented that employs the properties of + control systems to ensure that no garbage collection work is + performed during the execution of critical processes. The hard + real-time part of the system is thus never disturbed by garbage + collection work. Existing incremental garbage collection + algorithms are adapted to the presented strategy. Necessary + modifications of the algorithms and the real-time kernel are + discussed. A standard scheduling analysis technique, rate + monotonic analysis, is extended in order to make a priori analysis + of the schedulability of the garbage collector possible. + + The scheduling algorithm has been implemented in an industrially + relevant real-time environment in order to show that the strategy + is feasible in practice. The experimental evaluation shows that + predictable behaviour and sub-millisecond worst-case delays can be + achieved on standard hardware even by a non-optimized prototype + garbage collector. + * .. _HOSKING91: Antony L. Hosking. 1991. "`Main memory management for persistence `_". ACM. Proceedings of the ACM OOPSLA'91 Workshop on Garbage Collection. @@ -473,18 +1449,50 @@ Bibliography .. abstract: hmdw91.html + We describe a memory management toolkit for language implementors. + It offers efficient and flexible generation scavenging garbage + collection. In addition to providing a core of + language-independent algorithms and data structures, the toolkit + includes auxiliary components that ease implementation of garbage + collection for programming languages. We have detailed designs for + Smalltalk and Modula-3 and are confident the toolkit can be used + with a wide variety of languages. The toolkit approach is itself + novel, and our design includes a number of additional innovations + in flexibility, efficiency, accuracy, and cooperation between the + compiler and the collector. + * .. _HM92: Richard L. Hudson, J. Eliot B. Moss. 1992. "`Incremental Collection of Mature Objects `_". Springer-Verlag. LNCS #637 International Workshop on Memory Management, St. Malo, France, Sept. 1992, pp. 388--403. .. abstract: hm92.html + We present a garbage collection algorithm that extends + generational scavenging to collect large older generations (mature + objects) non-disruptively. The algorithm's approach is to process + bounded-size pieces of mature object space at each collection; the + subtleties lie in guaranteeing that it eventually collects any and + all garbage. The algorithm does not assume any special hardware or + operating system support, e.g., for forwarding pointers or + protection traps. The algorithm copies objects, so it naturally + supports compaction and reclustering. + * .. _HMMM97: Richard L. Hudson, Ron Morrison, J. Eliot B. Moss, David S. Munro. 1997. "`Garbage Collecting the World: One Car at a Time `_". ACM. Proc. OOPSLA 97, pp. 162--175. .. abstract: hmmm97.html + A new garbage collection algorithm for distributed object systems, + called DMOS (Distributed Mature Object Space), is presented. It is + derived from two previous algorithms, MOS (Mature Object Space), + sometimes called the train algorithm, and PMOS (Persistent Mature + Object Space). The contribution of DMOS is that it provides the + following unique combination of properties for a distributed + collector: safety, completeness, non-disruptiveness, + incrementality, and scalability. Furthermore, the DMOS collector + is non-blocking and does not use global tracing. + * .. _ISO90: "International Standard ISO/IEC 9899:1990 Programming languages — C". @@ -495,12 +1503,68 @@ Bibliography .. abstract: johnstone97.html + Dynamic memory use has been widely recognized to have profound + effects on program performance, and has been the topic of many + research studies over the last forty years. In spite of years of + research, there is considerable confusion about the effects of + dynamic memory allocation. Worse, this confusion is often + unrecognized, and memory allocators are widely thought to be + fairly well understood. + + In this research, we attempt to clarify many issues for both + manual and automatic non-moving memory management. We show that + the traditional approaches to studying dynamic memory allocation + are unsound, and develop a sound methodology for studying this + problem. We present experimental evidence that fragmentation costs + are much lower than previously recognized for most programs, and + develop a framework for understanding these results and enabling + further research in this area. For a large class of programs using + well-known allocation policies, we show that fragmentation costs + are near zero. We also study the locality effects of memory + allocation on programs, a research area that has been almost + completely ignored. We show that these effects can be quite + dramatic, and that the best allocation policies in terms of + fragmentation are also among the best in terms of locality at both + the cache and virtual memory levels of the memory hierarchy. + + We extend these fragmentation and locality results to real-time + garbage collection. We have developed a hard real-time, + non-copying generational garbage collector which uses a + write-barrier to coordinate collection work only with + modifications of pointers, therefore making coordination costs + cheaper and more predictable than previous approaches. We combine + this write-barrier approach with implicit non-copying reclamation, + which has most of the advantages of copying collection (notably + avoiding both the sweep phase required by mark-sweep collectors, + and the referencing of garbage objects when reclaiming their + space), without the disadvantage of having to actually copy the + objects. In addition, we present a model for non-copying + implicit-reclamation garbage collection. We use this model to + compare and contrast our work with that of others, and to discuss + the tradeoffs that must be made when developing such a garbage + collector. + * .. _JW98: Mark S. Johnstone, Paul R. Wilson. 1998. "`The Memory Fragmentation Problem: Solved? `_". ACM. ISMM'98 pp. 26--36. .. abstract: jw98.html + We show that for 8 real and varied C and C++ programs, several + conventional dynamic storage allocators provide near-zero + fragmentation, once overheads due to implementation details + (headers, alignment, etc.) are properly accounted for. This + substantially strengthens our previous results showing that the + memory fragmentation problem has generally been misunderstood, and + that good allocator policies can provide good memory usage for + most programs. The new results indicate that for most programs, + excellent allocator policies are readily available, and efficiency + of implementation is the major challenge. While we believe that + our experimental results are state-of-the-art and our methodology + is superior to most previous work, more work should be done to + identify and study unusual problematic program behaviors not + represented in our sample. + * .. _JONES92: Richard E. Jones. 1992. "`Tail recursion without space leaks `_". *Journal of Functional Programming.* 2(1):73--79. @@ -511,18 +1575,77 @@ Bibliography .. abstract: jl92.html + Weighted Reference Counting is a low-communication distributed + storage reclamation scheme for loosely-coupled multiprocessors. + The algorithm we present herein extends weighted reference + counting to allow the collection of cyclic data structures. To do + so, the algorithm identifies candidate objects that may be part of + cycles and performs a tricolour mark-scan on their subgraph in a + lazy manner to discover whether the subgraph is still in use. The + algorithm is concurrent in the sense that multiple useful + computation processes and garbage collection processes can be + performed simultaneously. + * .. _JONES96: Richard E. Jones, Rafael Lins. 1996. "`Garbage Collection: Algorithms for Automatic Dynamic Memory Management `_". Wiley. ISBN 0-471-94148-4. .. abstract: jones96.html + [from the back cover] The memory storage requirements of complex + programs are extremely difficult to manage correctly by hand. A + single error may lead to indeterminate and inexplicable program + crashes. Worse still, failures are often unrepeatable and may + surface only long after the program has been delivered to the + customer. The eradication of memory errors typically consumes a + substantial amount of development time. And yet the answer is + relatively easy -- garbage collection; removing the clutter of + memory management from module interfaces, which then frees the + programmer to concentrate on the problem at hand rather than + low-level book-keeping details. For this reason, most modern + object-oriented languages such as Smalltalk, Eiffel, Java and + Dylan, are supported by garbage collection. Garbage collecting + libraries are even available for such uncooperative languages as C + and C++. + + This book considers how dynamic memory can be recycled + automatically to guarantee error-free memory management. There is + an abundant but disparate literature on the subject, largely + confined to research papers. This book sets out to pool this + experience in a single accessible and unified framework. + + Each of the important algorithms is explained in detail, often + with illustrations of its characteristic features and animations + of its use. Techniques are described and compared for declarative + and imperative programming styles, for sequential, concurrent and + distributed architectures. + + For professionals developing programs from simple software tools + to complex systems, as well as for researchers and students + working in compiler construction, functional, logic and + object-oriented programming design, this book will provide not + only a clear introduction but also a convenient reference source + for modern garbage collection techniques. + * .. _ACM98: Richard E. Jones. 1998. "`ISMM'98 International Symposium on Memory Management `_". ACM. ISBN 1-58113-114-3. .. abstract: acm98.html + (From the preface:) The International Symposium on Memory + Management is a forum for research in several related areas of + memory management, especially garbage collectors and dynamic + storage allocators. [...] The nineteen papers selected for + publication in this volume cover a remarkably broad range of + memory management topics from explicit malloc-style allocation to + automatic memory management, from cache-conscious data layout to + efficient management of distributed references, from conservative + to type-accurate garbage collection, for applications ranging from + user application to long-running servers, supporting languages as + different as C, C++, Modula-3, Java, Eiffel, Erlang, Scheme, ML, + Haskell and Prolog. + * .. _JONES12: Richard E. Jones, Antony Hosking, and Eliot Moss. 2012. "`The Garbage Collection Handbook `_". Chapman & Hall. @@ -541,6 +1664,29 @@ Bibliography .. abstract: kqh98.html + This paper studies a representative of an important class of + emerging applications, a parallel data mining workload. The + application, extracted from the IBM Intelligent Miner, identifies + groups of records that are mathematically similar based on a + neural network model called self-organizing map. We examine and + compare in details two implementations of the application: (1) + temporal locality or working set sizes; (2) spatial locality and + memory block utilization; (3) communication characteristics and + scalability; and (4) TLB performance. + + First, we find that the working set hierarchy of the application + is governed by two parameters, namely the size of an input record + and the size of prototype array; it is independent of the number + of input records. Second, the application shows good spatial + locality, with the implementation optimized for sparse data sets + having slightly worse spatial locality. Third, due to the batch + update scheme, the application bears very low communication. + Finally, a 2-way set associative TLB may result in severely skewed + TLB performance in a multiprocessor environment caused by the + large discrepancy in the amount of conflict misses. Increasing the + set associativity is more effective in mitigating the problem than + increasing the TLB size. + * .. _KH00: Jin-Soo Kim & Yarsun Hsu. 2000. "Memory system behavior of Java programs: methodology and analysis". ACM. Proc. International conference on measurements and modeling of computer systems, pp. 264--274. @@ -551,12 +1697,53 @@ Bibliography .. abstract: kolodner92.html + A stable heap is a storage that is managed automatically using + garbage collection, manipulated using atomic transactions, and + accessed using a uniform storage model. These features enhance + reliability and simplify programming by preventing errors due to + explicit deallocation, by masking failures and concurrency using + transactions, and by eliminating the distinction between accessing + temporary storage and permanent storage. Stable heap management is + useful for programming language for reliable distributed + computing, programming languages with persistent storage, and + object-oriented database systems. Many applications that could + benefit from a stable heap (e.g., computer-aided design, + computer-aided software engineering, and office information + systems) require large amounts of storage, timely responses for + transactions, and high availability. We present garbage collection + and recovery algorithms for a stable heap implementation that meet + these goals and are appropriate for stock hardware. The collector + is incremental: it does not attempt to collect the whole heap at + once. The collector is also atomic: it is coordinated with the + recovery system to prevent problems when it moves and modifies + objects . The time for recovery is independent of heap size, and + can be shortened using checkpoints. + * .. _LK98: Per-Åke Larson & Murali Krishnan. 1998. "`Memory Allocation for Long-Running Server Applications `_". ACM. ISMM'98 pp. 176--185. .. abstract: lk98.html + Prior work on dynamic memory allocation has largely neglected + long-running server applications, for example, web servers and + mail servers. Their requirements differ from those of one-shot + applications like compilers or text editors. We investigated how + to build an allocator that is not only fast and memory efficient + but also scales well on SMP machines. We found that it is not + sufficient to focus on reducing lock contention. Only limited + improvement can be achieved this way; higher speedups require a + reduction in cache misses and cache invalidation traffic. We then + designed and prototyped a new allocator, called Lkmalloc, targeted + for both traditional applications and server applications. + LKmalloc uses several subheaps, each one with a separate set of + free lists and memory arena. A thread always allocates from the + same subheap but can free a block belonging to any subheap. A + thread is assigned to a subheap by hashing on its thread ID. We + compared its performance with several other allocators on a + server-like, simulated workload and found that it indeed scales + well and is quite fast but could use memory more efficiently. + * .. _LH83: Henry Lieberman & Carl Hewitt. 1983. "`A real-time garbage collector based on the lifetimes of objects `_". ACM. 26(6):419--429. @@ -571,6 +1758,18 @@ Bibliography .. abstract: mccarthy60.html + A programming system called LISP (for LISt Processor) has been + developed for the IBM 704 computer by the Artificial Intelligence + group at M.I.T. The system was designed to facilitate experiments + with a proposed system called the Advice Taker, whereby a machine + could be instructed to handle declarative as well as imperative + sentences and could exhibit "common sense" in carrying out its + instructions. The original proposal for the Advice Taker was made + in November 1958. The main requirement was a programming system + for manipulating expressions representing formalized declarative + and imperative sentences so that the Advice Taker could make + deductions. + * .. _MCCARTHY79: John McCarthy. 1979. "`History of Lisp `_". In *History of programming languages I*, pp. 173–185. ACM. @@ -581,6 +1780,23 @@ Bibliography .. abstract: ptm98.html + [introduction from the catalog] Presents a survey of both + distributed shared memory (DSM) efforts and commercial DSM + systems. The book discusses relevant issues that make the concept + of DSM one of the most attractive approaches for building + large-scale, high-performance multiprocessor systems. Its text + provides a general introduction to the DSM field as well as a + broad survey of the basic DSM concepts, mechanisms, design issues, + and systems. + + Distributed Shared Memory concentrates on basic DSM algorithms, + their enhancements, and their performance evaluation. In addition, + it details implementations that employ DSM solutions at the + software and the hardware level. The book is a research and + development reference that provides state-of-the art information + that will be useful to architects, designers, and programmers of + DSM systems. + * .. _MINSKY63: M. L. Minsky. 1963. "A LISP Garbage Collector Algorithm Using Serial Secondary Storage". MIT. Memorandum MAC-M-129, Artificial Intelligence Project, Memo 58 (revised). @@ -615,78 +1831,318 @@ Bibliography .. abstract: mfh95.html + Most specifications of garbage collectors concentrate on the + low-level algorithmic details of how to find and preserve + accessible objects. Often, they focus on bit-level manipulations + such as "scanning stack frames," "marking objects," "tagging + data," etc. While these details are important in some contexts, + they often obscure the more fundamental aspects of memory + management: what objects are garbage and why? + + We develop a series of calculi that are just low-level enough that + we can express allocation and garbage collection, yet are + sufficiently abstract that we may formally prove the correctness + of various memory management strategies. By making the heap of a + program syntactically apparent, we can specify memory actions as + rewriting rules that allocate values on the heap and automatically + dereference pointers to such objects when needed. This formulation + permits the specification of garbage collection as a relation that + removes portions of the heap without affecting the outcome of + evaluation. + + Our high-level approach allows us to specify in a compact manner a + wide variety of memory management techniques, including standard + trace-based garbage collection (i.e., the family of copying and + mark/sweep collection algorithms), generational collection, and + type-based, tag-free collection. Furthermore, since the definition + of garbage is based on the semantics of the underlying language + instead of the conservative approximation of inaccessibility, we + are able to specify and prove the idea that type inference can be + used to collect some objects that are accessible but never used. + * .. _MBMM99: David S. Munro, Alfred Brown, Ron Morrison, J. Eliot B. Moss. 1999. "`Incremental Garbage Collection of a Persistent Object Store using PMOS `_". Morgan Kaufmann. in Advances in Persistent Object Systems, pp. 78--91. .. abstract: mbmm99.html + PMOS is an incremental garbage collector designed specifically to + reclaim space in a persistent object store. It is complete in that + it will, after a finite number of invocations, reclaim all + unreachable storage. PMOS imposes minimum constraints on the order + of collection and offers techniques to reduce the I/O traffic + induced by the collector. Here we present the first implementation + of the PMOS collector called PMOS#1. The collector has been + incorporated into the stable heap layer of the generic persistent + object store used to support a number of languages including + Napier88. Our main design goals are to maintain the independence + of the language from the store and to retain the existing store + interface. The implementation has been completed and tested using + a Napier88 system. The main results of this work show that the + PMOS collector is implementable in a persistent store and that it + can be built without requiring changes to the language + interpreter. Initial performance measurements are reported. These + results suggest however, that effective use of PMOS requires + greater co-operation between language and store. + * .. _NOPH92: Scott Nettles, James O'Toole, David Pierce, Nickolas Haines. 1992. "`Replication-Based Incremental Copying Collection `_". IWMM'92. .. abstract: noph92.html + We introduce a new replication-based copying garbage collection + technique. We have implemented one simple variation of this method + to provide incremental garbage collection on stock hardware with + no special operating system or virtual memory support. The + performance of the prototype implementation is excellent: major + garbage collection pauses are completely eliminated with only a + slight increase in minor collection pause times. + + Unlike the standard copying algorithm, the replication-based + method does not destroy the original replica when a copy is + created. Instead, multiple copies may exist, and various standard + strategies for maintaining consistency may be applied. In our + implementation for Standard ML of New Jersey, the mutator + continues to use the from-space replicas until the collector has + achieved a consistent replica of all live data in to-space. + + We present a design for a concurrent garbage collector using the + replication-based technique. We also expect replication-based GC + methods to be useful in providing services for persistence and + distribution, and briefly discuss these possibilities. + * .. _NETTLES92: Scott Nettles. 1992. "`A Larch Specification of Copying Garbage Collection `_". Carnegie Mellon University. CMU-CS-92-219. .. abstract: nettles92.html + Garbage collection (GC) is an important part of many language + implementations. One of the most important garbage collection + techniques is copying GC. This paper consists of an informal but + abstract description of copying collection, a formal specification + of copying collection written in the Larch Shared Language and the + Larch/C Interface Language, a simple implementation of a copying + collector written in C, an informal proof that the implementation + satisfies the specification, and a discussion of how the + specification applies to other types of copying GC such as + generational copying collectors. Limited familiarity with copying + GC or Larch is needed to read the specification. + * .. _NO93A: Scott Nettles & James O'Toole. 1993. "Implementing Orthogonal Persistence: A Simple Optimization Using Replicating Collection". USENIX. IWOOOS'93. .. abstract: no93a.html + Orthogonal persistence provides a safe and convenient model of + object persistence. We have implemented a transaction system which + supports orthogonal persistence in a garbage-collected heap. In + our system, replicating collection provides efficient concurrent + garbage collection of the heap. In this paper, we show how + replicating garbage collection can also be used to reduce commit + operation latencies in our implementation. + + We describe how our system implements transaction commit. We + explain why the presence of non-persistent objects can add to the + cost of this operation. We show how to eliminate these additional + costs by using replicating garbage collection. The resulting + implementation of orthogonal persistence should provide + transaction performance that is independent of the quantity of + non-persistent data in use. We expect efficient support for + orthogonal persistence to be valuable in operating systems + applications which use persistent data. + * .. _NO93: Scott Nettles & James O'Toole. 1993. "`Real-Time Replication Garbage Collection `_". ACM. PLDI'93. .. abstract: no93.html + We have implemented the first copying garbage collector that + permits continuous unimpeded mutator access to the original + objects during copying. The garbage collector incrementally + replicates all accessible objects and uses a mutation log to bring + the replicas up-to-date with changes made by the mutator. An + experimental implementation demonstrates that the costs of using + our algorithm are small and that bounded pause times of 50 + milliseconds can be readily achieved. + * .. _NIELSEN77: Norman R. Nielsen. 1977. "Dynamic Memory Allocation in Computer Simulation". ACM. CACM 20:11. .. abstract: nielsen77.html + This paper investigates the performance of 35 dynamic memory + allocation algorithms when used to service simulation programs as + represented by 18 test cases. Algorithm performance was measured + in terms of processing time, memory usage, and external memory + fragmentation. Algorithms maintaining separate free space lists + for each size of memory block used tended to perform quite well + compared with other algorithms. Simple algorithms operating on + memory ordered lists (without any free list) performed + surprisingly well. Algorithms employing power-of-two block sizes + had favorable processing requirements but generally unfavorable + memory usage. Algorithms employing LIFO, FIFO, or memory ordered + free lists generally performed poorly compared with others. + * .. _OTOOLE90: James O'Toole. 1990. "Garbage Collecting Locally". .. abstract: otoole90.html + Generational garbage collection is a simple technique for + automatic partial memory reclamation. In this paper, I present the + basic mechanics of generational collection and discuss its + characteristics. I compare several published algorithms and argue + that fundamental considerations of locality, as reflected in the + changing relative speeds of processors, memories, and disks, + strongly favor a focus on explicit optimization of I/O + requirements during garbage collection. I show that this focus on + I/O costs due to memory hierarchy debunks a well-known claim about + the relative costs of garbage collection and stack allocation. I + suggest two directions for future research in this area and + discuss some simple architectural changes in virtual memory + interfaces which may enable efficient garbage collector + utilization of standard virtual memory hardware. + * .. _ON94: James O'Toole & Scott Nettles. 1994. "`Concurrent Replicating Garbage Collection `_". ACM. LFP'94. .. abstract: on94.html + We have implemented a concurrent copying garbage collector that + uses replicating garbage collection. In our design, the client can + continuously access the heap during garbage collection. No + low-level synchronization between the client and the garbage + collector is required on individual object operations. The garbage + collector replicates live heap objects and periodically + synchronizes with the client to obtain the client's current root + set and mutation log. An experimental implementation using the + Standard ML of New Jersey system on a shared-memory multiprocessor + demonstrates excellent pause time performance and moderate + execution time speedups. + * .. _JRR99: Simon Peyton Jones, Norman Ramsey, Fermin Reig. 1999. "`C--: a portable assembly language that supports garbage collection `_". Springer-Verlag. International Conference on Principles and Practice of Declarative Programming 1999, LNCS 1702, pp. 1--28. .. abstract: jrr99.html + For a compiler writer, generating good machine code for a variety + of platforms is hard work. One might try to reuse a retargetable + code generator, but code generators are complex and difficult to + use, and they limit one's choice of implementation language. One + might try to use C as a portable assembly language, but C limits + the compiler writer's flexibility and the performance of the + resulting code. The wide use of C, despite these drawbacks, argues + for a portable assembly language. C-- is a new language designed + expressly for this purpose. The use of a portable assembly + language introduces new problems in the support of such high-level + run-time services as garbage collection, exception handling, + concurrency, profiling, and debugging. We address these problems + by combining the C-- language with a C-- run-time interface. The + combination is designed to allow the compiler writer a choice of + source-language semantics and implementation techniques, while + still providing good performance. + * .. _PIEPER93: John S. Pieper. 1993. "Compiler Techniques for Managing Data Motion". Carnegie Mellon University. Technical report number CMU-CS-93-217. .. abstract: pieper93.html + Software caching, automatic algorithm blocking, and data overlays + are different names for the same problem: compiler management of + data movement throughout the memory hierarchy. Modern + high-performance architectures often omit hardware support for + moving data between levels of the memory hierarchy: iWarp does not + include a data cache, and Cray supercomputers do not have virtual + memory. These systems have effectively traded a more complicated + programming model for performance by replacing a + hardware-controlled memory hierarchy with a simple fast memory. + The simpler memories have less logic in the critical path, so the + cycle time of the memories is improved. + + For programs which fit in the resulting memory, the extra + performance is great. Unfortunately, the driving force behind + supercomputing today is a class of very large scientific problems, + both in terms of computation time and in terms of the amount of + data used. Many of these programs do not fit in the memory of the + machines available. When architects trade hardware support for + data migration to gain performance, control of the memory + hierarchy is left to the programmer. Either the program size must + be cut down to fit into the machine, or every loop which accesses + more data than will fit into memory must be restructured by hand. + This thesis describes how a compiler can relieve the programmer of + this burden, and automate data motion throughout the memory + hierarchy without direct hardware support. + + This works develops a model of how data is accessed within a + nested loop by typical scientific programs. It describes + techniques which can be used by compilers faced with the task of + managing data motion. The concentration is on nested loops which + process large data arrays using linear array subscripts. Because + the array subscripts are linear functions of the loop indices and + the loop indices form an integer lattice, linear algebra can be + applied to solve many compilation problems. + + The approach it to tile the iteration space of the loop nest. + Tiling allows the compiler to improve locality of reference. The + tiling basis matrix is chosen from a set of candidate vectors + which neatly divide the data set. The execution order of the tiles + is selected to maximize locality between tiles. Finally, the tile + sizes are chosen to minimize execution time. + + The approach has been applied to several common scientific loop + nests: matrix-matrix multiplication, QR-decomposition, and + LU-decomposition. In addition, an illustrative example from the + Livermore Loop benchmark set is examined. Although more compiler + time can be required in some cases, this technique produces better + code at no cost for most programs. + * .. _PIRINEN98: Pekka P. Pirinen. 1998. "Barrier techniques for incremental tracing". ACM. ISMM'98 pp. 20--25. .. abstract: pirinen98.html + This paper presents a classification of barrier techniques for + interleaving tracing with mutator operation during an incremental + garbage collection. The two useful tricolour invariants are + derived from more elementary considerations of graph traversal. + Barrier techniques for maintaining these invariants are classified + according to the action taken at the barrier (such as scanning an + object or changing its colour), and it is shown that the + algorithms described in the literature cover all the possibilities + except one. Unfortunately, the new technique is impractical. Ways + of combining barrier techniques are also discussed. + * .. _PRINTEZIS96: Tony Printezis. 1996. "Disk Garbage Collection Strategies for Persistent Java". Proceedings of the First International Workshop on Persistence and Java. .. abstract: printezis96.html + This paper presents work currently in progress on Disk Garbage + Collection issues for PJava, an orthogonally persistent version of + Java. In particular, it concentrates on the initial Prototype of + the Disk Garbage Collector of PJava0 which has already been + implemented. This Prototype was designed to be very simple and + modular in order to be easily changed, evolved, improved, and + allow experimentation. Several experiments were performed in order + to test possible optimisations; these experiments concentrated on + the following four areas: a) efficient access to the store; b) + page-replacement algorithms; c) efficient discovery of live + objects during compaction; and d) dealing with forward references. + The paper presents a description of the Prototype's architecture, + the results of these experiments and related discussion, and some + future directions based on the experience gained from this work. + * .. _PC96: Tony Printezis & Quentin Cutts. 1996. "Measuring the Allocation Rate of Napier88". Department of Computing Science at University of Glasgow. TR ?. @@ -697,6 +2153,40 @@ Bibliography .. abstract: reinhold93.html + As processor speeds continue to improve relative to main-memory + access times, cache performance is becoming an increasingly + important component of program performance. Prior work on the + cache performance of garbage-collected programming languages has + either assumed or argued that conventional garbage-collection + methods will yield poor performance, and has therefore + concentrated on new collection algorithms designed specifically to + improve cache-level reference locality. This dissertation argues + to the contrary: Many programs written in garbage-collected + languages are naturally well-suited to the direct-mapped caches + typically found in modern computer systems. + + Using a trace-driven cache simulator and other analysis tools, + five nontrivial, long-running Scheme programs are studied. A + control experiment shows that the programs have excellent cache + performance without any garbage collection at all. A second + experiment indicates that the programs will perform well with a + simple and infrequently-run generational compacting collector. + + An analysis of the test programs' memory usage patterns reveals + that the mostly-functional programming style typically used in + Scheme programs, in combination with simple linear storage + allocation, causes most data objects to be dispersed in time and + space so that references to them cause little cache interference. + From this it follows that other Scheme programs, and programs + written in similar styles in different languages, should perform + well with a simple generational compacting collector; + sophisticated collectors intended to improve cache performance are + unlikely to be effective. The analysis also suggests that, as + locality becomes ever more important to program performance, + programs written in garbage-collected languages may turn out to + have significant performance advantage over programs written in + more conventional languages. + * .. _ROBSON77: J. M. Robson. 1977. "Worst case fragmentation of first fit and best fit storage allocation strategies". ACM. ACM Computer Journal, 20(3):242--244. @@ -707,12 +2197,66 @@ Bibliography .. abstract: rr97.html + It is well accepted that automatic garbage collection simplifies + programming, promotes modularity, and reduces development effort. + However it is commonly believed that these advantages do not + counteract the perceived price: excessive overheads, possible long + pause times while garbage collections occur, and the need to + modify existing code. Even though there are publically available + garbage collector implementations that can be used in existing + programs, they do not guarantee short pauses, and some + modification of the application using them is still required. In + this paper we describe a snapshot-at-beginning concurrent garbage + collector algorithm and its implementation. This algorithm + guarantees short pauses, and can be easily implemented on stock + UNIX-like operating systems. Our results show that our collector + performs comparable to other garbage collection implementations on + uniprocessor machines and outperforms similar collectors on + multiprocessor machines. We also show our collector to be + competitive in performance with explicit deallocation. Our + collector has the added advantage of being non-intrusive. Using a + dynamic linking technique and effective root set inferencing, we + have been able to successfully run our collector even in + commercial programs where only the binary executable and no source + code is available. In this paper we describe our algorithm, its + implementation, and provide both an algorithmic and a performance + comparison between our collector and other similar garbage + collectors. + * .. _ROJEMO95: Niklas Röjemo. 1995. "Highlights from nhc -- a space-efficient Haskell compiler". Chalmers University of Technology. .. abstract: rojemo95.html + Self-compiling implementations of Haskell, i.e., those written in + Haskell, have been and, except one, are still space consuming + monsters. Object code size for the compilers themselves are 3-8Mb, + and they need 12-20Mb to recompile themselves. One reason for the + huge demands for memory is that the main goal for these compilers + is to produce fast code. However, the compiler described in this + paper, called "nhc" for "Nearly a Haskell Compiler", is the one + above mentioned exception. This compiler concentrates on keeping + memory usage down, even at a cost in time. The code produced is + not fast, but nhc is usable, and the resulting programs can be run + on computers with small memory. + + This paper describes some of the implementation choices done, in + the Haskell part of the source code, to reduce memory consumption + in nhc. It is possible to use these also in other Haskell + compilers with no, or very small, changes to their run-time + systems. + + Time is neither the main focus of nhc nor of this paper, but there + is nevertheless a small section about the speed of nhc. The most + notable observation concerning speed is that nhc spends + approximately half the time processing interface files, which is + much more than needed in the type checker. Processing interface + files is also the most space consuming part of nhc in most cases. + It is only when compiling source files with large sets of mutually + recursive functions that more memory is needed to type check than + to process interface files. + * .. _ROJEMO95A: Niklas Röjemo. 1995. "Generational garbage collection for lazy functional languages without temporary space leaks". Chalmers University of Technology. @@ -723,12 +2267,40 @@ Bibliography .. abstract: rr96.html + The context for this paper is functional computation by graph + reduction. Our overall aim is more efficient use of memory. The + specific topic is the detection of dormant cells in the live graph + -- those retained in heap memory though not actually playing a + useful role in computation. We describe a profiler that can + identify heap consumption by such 'useless' cells. Unlike heap + profilers based on traversals of the live heap, this profiler + works by examining cells post-mortem. The new profiler has + revealed a surprisingly large proportion of 'useless' cells, even + in some programs that previously seemed space-efficient such as + the bootstrapping Haskell compiler "nhc". + * .. _RW99: David J. Roth, David S. Wise. 1999. "`One-bit counts between unique and sticky `_". ACM. ISMM'98, pp. 49--56. .. abstract: rw99.html + Stoye's one-bit reference tagging scheme can be extended to local + counts of two or more via two strategies. The first, suited to + pure register transactions, is a cache of referents to two shared + references. The analog of Deutch's and Bobrow's multiple-reference + table, this cache is sufficient to manage small counts across + successive assignment statements. Thus, accurate reference counts + above one can be tracked for short intervals, like that bridging + one function's environment to its successor's. + + The second, motivated by runtime stacks that duplicate references, + avoids counting any references from the stack. It requires a local + pointer-inversion protocol in the mutator, but one still local to + the referent and the stack frame. Thus, an accurate reference + count of one can be maintained regardless of references from the + recursion stack. + * .. _ROVNER85: Paul Rovner. 1985. "`On Adding Garbage Collection and Runtime Types to a Strongly-Typed, Statically-Checked, Concurrent Language `_". Xerox PARC. TR CSL-84-7. @@ -739,12 +2311,40 @@ Bibliography .. abstract: runciman92.html + We describe the design, implementation, and use of a new kind of + profiling tool that yields valuable information about the memory + use of lazy functional programs. The tool has two parts: a + modified functional language implementation which generated + profiling implementation during the execution of programs, and a + separate program which converts this information to graphical + form. With the aid of profile graphs, one can make alterations to + a functional program which dramatically reduce its space + consumption. We demonstrate that this is the case of a genuine + example -- the first to which the tool has been applied -- for + which the results are strikingly successful. + * .. _RR94: Colin Runciman & Niklas Röjemo. 1994. "`New dimensions in heap profiling `_". University of York. .. abstract: rr94.html + First-generation heap profilers for lazy functional languages have + proved to be effective tools for locating some kinds of space + faults, but in other cases they cannot provide sufficient + information to solve the problem. This paper describes the design, + implementation and use of a new profiler that goes beyond the + two-dimensional "who produces what" view of heap cells to provide + information about their more dynamic and structural attributes. + Specifically, the new profiler can distinguish between cells + according to their *eventual lifetime*, or on the basis of the + *closure retainers* by virtue of which they remain part of the + live heap. A bootstrapping Haskell compiler (nhc) hosts the + implementation: among examples of the profiler's use we include + self-application to nhc. Another example is the original + heap-profiling case study "clausify", which now consumes even less + memory and is much faster. + * .. _RR96A: Colin Runciman & Niklas Röjemo. 1996. "Two-pass heap profiling: a matter of life and death". Department of Computer Science, University of York. @@ -755,6 +2355,16 @@ Bibliography .. abstract: sg95.html + We present an implementation of the Train Algorithm, an + incremental collection scheme for reclamation of mature garbage in + generation-based memory management systems. To the best of our + knowledge, this is the first Train Algorithm implementation ever. + Using the algorithm, the traditional mark-sweep garbage collector + employed by the Mjølner run-time system for the + object-oriented BETA programming language was replaced by a + non-disruptive one, with only negligible time and storage + overheads. + * .. _SB00: Manuel Serrano, Hans-J. Boehm. 2000. "`Understanding memory allocation of Scheme programs `_". ACM. Proceedings of International Conference on Functional Programming 2000. @@ -765,6 +2375,22 @@ Bibliography .. abstract: shapiro94.html + Larchant-RDOSS is a distributed shared memory that persists on + reliable storage across process lifetimes. Memory management is + automatic: including consistent caching of data and of locks, + collecting objects unreachable from the persistent root, writing + reachable objects to disk, and reducing store fragmentation. + Memory management is based on a novel garbage collection + algorithm, that approximates a global trace by a series of local + traces, with no induced I/O or locking traffic, and no + synchronization between the collector and the application + processes. This results in a simple programming model, and + expected minimal added application latency. The algorithm is + designed for the most unfavorable environment (uncontrolled + programming language, reference by pointers, distributed system, + non-coherent shared memory) and should work well also in more + favorable settings. + * .. _SHAW87: Robert A. Shaw. 1987. "Improving Garbage Collector Performance in Virtual Memory". Stanford University. CSL-TR-87-323. @@ -779,12 +2405,51 @@ Bibliography .. abstract: singhal92.html + Texas is a persistent storage system for C++, providing high + performance while emphasizing simplicity, modularity and + portability. A key component of the design is the use of pointer + swizzling at page fault time, which exploits existing virtual + memory features to implement large address spaces efficiently on + stock hardware, with little or no change to existing compilers. + Long pointers are used to implement an enormous address space, but + are transparently converted to the hardware-supported pointer + format when pages are loaded into virtual memory. + + Runtime type descriptors and slightly modified heap allocation + routines support pagewise pointer swizzling by allowing objects + and their pointer fields to be identified within pages. If + compiler support for runtime type identification is not available, + a simple preprocessor can be used to generate type descriptors. + + This address translation is largely independent of issues of data + caching, sharing, and checkpointing; it employs operating systems' + existing virtual memories for caching, and a simple and flexible + log-structured storage manager to improve checkpointing + performance. + + Pagewise virtual memory protections are also used to detect writes + for logging purposes, without requiring any changes to compiled + code. This may degrade checkpointing performance for small + transactions with poor locality of writes, but page diffing and + sub-page logging promise to keep performance competitive with + finer-grained checkpointing schemes. + + Texas presents a simple programming interface; an application + creates persistent objects by simply allocating them on the + persistent heap. In addition, the implementation is relatively + small, and is easy to incorporate into existing applications. The + log-structured storage module easily supports advanced extensions + such as compressed storage, versioning, and adaptive + reorganization. + * .. _SOBALVARRO88: P. G. Sobalvarro. 1988. "`A Lifetime-based Garbage Collector for LISP Systems on General-Purpose Computers `_". MIT. AITR-1417. .. abstract: sobalvarro88.html + Garbage collector performance in LISP systems on custom hardware has been substantially improved by the adoption of lifetime-based garbage collection techniques. To date, however, successful lifetime-based garbage collectors have required special-purpose hardware, or at least privileged access to data structures maintained by the virtual memory system. I present here a lifetime-based garbage collector requiring no special-purpose hardware or virtual memory system support, and discuss its performance. + * .. _STEELE75: Guy L. Steele. 1975. "`Multiprocessing Compactifying Garbage Collection `_". CACM. 18:9 pp. 495--508. @@ -811,12 +2476,40 @@ Bibliography .. abstract: td95.html + We study the cost of storage management for garbage-collected + programs compiled with the Standard ML of New Jersey compiler. We + show that the cost of storage management is not the same as the + time spent garbage collecting. For many of the programs, the time + spent garbage collecting is less than the time spent doing other + storage-management tasks. + * .. _TJ94: Stephen Thomas, Richard E. Jones. 1994. "Garbage Collection for Shared Environment Closure Reducers". Computing Laboratory, The University of Kent at Canterbury. Technical Report 31-94. .. abstract: tj94.html + Shared environment closure reducers such as Fairbairn and Wray's + TIM incur a comparatively low cost when creating a suspension, and + so provide an elegant method for implementing lazy functional + evaluation. However, comparatively little attention has been given + to the problems involved in identifying which portions of a shared + environment are needed (and ignoring those which are not) during a + garbage collection. Proper consideration of this issue has subtle + consequences when implementing a storage manager in a TIM-like + system. We describe the problem and illustrate the negative + consequences of ignoring it. + + We go on to describe a solution in which the compiler determines + statically which portions of that code's environment are required + for each piece of code it generates, and emits information to + assist the run-time storage manager to scavenge environments + selectively. We also describe a technique for expressing this + information directly as executable code, and demonstrate that a + garbage collector implemented in this way can perform + significantly better than an equivalent, table-driven interpretive + collector. + * .. _THOMAS95: Stephen Thomas. 1995. "Garbage Collection in Shared-Environment Closure Reducers: Space-Efficient Depth First Copying using a Tailored Approach". *Information Processing Letters.* 56:1, pp. 1--7. @@ -827,6 +2520,29 @@ Bibliography .. abstract: tt97.html + This paper describes a memory management discipline for programs + that perform dynamic memory allocation and de-allocation. At + runtime, all values are put into regions. The store consists of a + stack of regions. All points of region allocation and + de-allocation are inferred automatically, using a type and effect + based program analysis. The scheme does not assume the presence of + a garbage collector. The scheme was first presented in 1994 (M. + Tofte and J.-P. Talpin, in *Proceedings of the 21st ACM + SIGPLAN-SIGACT Symposium on Principles of Programming Languages,* + pp. 188--201); subsequently, it has been tested in the ML Kit with + Regions, a region-based, garbage-collection free implementation of + the Standard ML Core Language, which includes recursive datatypes, + higher-order functions and updatable references (L. Birkedal, M. + Tofte, and M. Vejlstrup, (1996), in *Proceedings of the 23rd ACM + SIGPLAN-SIGACT Symposium on Principles of Programming Languages,* + pp. 171--183). This paper defines a region-based dynamic semantics + for a skeletal programming language extracted from Standard ML. We + present the inference system which specifies where regions can be + allocated and de-allocated and a detailed proof that the system is + sound with respect to a standard semantics. We conclude by giving + some advice on how to write programs that run well on a stack of + regions, based on practical experience with the ML Kit. + * .. _UNGAR84: Dave Ungar. 1984. "`Generation Scavenging: A Non-disruptive High Performance Storage Reclamation Algorithm `_". ACM, SIGSOFT, SIGPLAN. Practical Programming Environments Conference. @@ -837,12 +2553,47 @@ Bibliography .. abstract: ungar88.html + One of the most promising automatic storage reclamation + techniques, generation-based storage reclamation, suffers poor + performance if many objects live for a fairly long time and then + die. We have investigated the severity of the problem by + simulating Generation Scavenging automatic storage reclamation + from traces of actual four-hour sessions. There was a wide + variation in the sample runs, with garbage-collection overhead + ranging from insignificant, during interactive runs, to sever, + during a single non-interactive run. All runs demonstrated that + performance could be improved with two techniques: segregating + large bitmaps and strings, and mediating tenuring with demographic + feedback. These two improvements deserve consideration for any + generation-based storage reclamation strategy. + * .. _VO96: Kiem-Phong Vo. 1996. "Vmalloc: A General and Efficient Memory Allocator". Software -- Practice and Experience. 26(3): 357--374 (1996). .. abstract: vo96.html + On C/Unix systems, the malloc interface is standard for dynamic + memory allocation. Despite its popularity, malloc's shortcomings + frequently cause programmers to code around it. The new library + Vmalloc generalizes malloc to give programmers more control over + memory allocation. Vmalloc introduces the idea of organizing + memory into separate regions, each with a discipline to get raw + memory and a method to manage allocation. Applications can write + their own disciplines to manipulate arbitrary type of memory or + just to better organize memory in a region by creating new regions + out of its memory. The provided set of allocation methods include + general purpose allocations, fast special cases and aids for + memory debugging or profiling. A compatible malloc interface + enables current applications to select allocation methods using + environment variables so they can tune for performance or perform + other tasks such as profiling memory usage, generating traces of + allocation calls or debugging memory errors. A performance study + comparing Vmalloc and currently popular malloc implementations + shows that Vmalloc is competitive to the best of these allocators. + Applications can gain further performance improvement by using the + right mixture of regions with different Vmalloc methods. + * .. _WW76: Daniel C. Watson, David S. Wise. 1976. "Tuning Garwick's algorithm for repacking sequential storage". *BIT.* 16, 4 (December 1976): 442--450. @@ -853,24 +2604,100 @@ Bibliography .. abstract: wlm92.html + GC systems allocate and reuse memory cyclically; this imposes a + cyclic pattern on memory accesses that has its own distinctive + locality characteristics. The cyclic reuse of memory tends to + defeat caching strategies if the reuse cycle is too large to fit + in fast memory. Generational GCs allow a smaller amount of memory + to be reused more often. This improves VM performance, because the + frequently-reused area stays in main memory. The same principle + can be applied at the level of high-speed cache memories, if the + cache is larger than the youngest generation. Because of the + repeated cycling through a fixed amount of memory, however, + generational GC interacts with cache design in unusual ways, and + modestly set-associative caches can significantly outperform + direct-mapped caches. + + While our measurements do not show very high miss rates for GCed + systems, they indicate that performance problems are likely in + faster next-generation systems, where second-level cache misses + may cost scores of cycles. Software techniques can improve cache + performance of garbage-collected systems, by decreasing the cache + "footprint" of the youngest generation; compiler techniques that + reduce the amount of heap allocation also improve locality. Still, + garbage-collected systems with a high rate of heap allocation + require somewhat more cache capacity and/or main memory bandwidth + than conventional systems. + * .. _WIL92A: Paul R. Wilson, Sheetal V. Kakkad. 1992. "`Pointer Swizzling at Page Fault Time `_". University of Texas at Austin. .. abstract: wil92a.html + Pointer swizzling at page fault time is a novel address + translation mechanism that exploits conventional address + translation hardware. It can support huge address spaces + efficiently without long hardware addresses; such large address + spaces are attractive for persistent object stores, distributed + shared memories, and shared address space operating systems. This + swizzling scheme can be used to provide data compatibility across + machines with different word sizes, and even to provide binary + code compatibility across machines with different hardware address + sizes. + + Pointers are translated ("swizzled") from a long format to a + shorter hardware-supported format at page fault time. No extra + hardware is required, and no continual software overhead is + incurred by presence checks of indirection of pointers. This + pagewise technique exploits temporal and spatial locality in much + the same way as normal virtual memory; this gives it many + desirable performance characteristics, especially given the trend + toward larger main memories. It is easy to implement using common + compilers and operating systems. + * .. _WIL94: Paul R. Wilson. 1994. "`Uniprocessor Garbage Collection Techniques `_". University of Texas. .. abstract: wil94.html + We survey basic garbage collection algorithms, and variations such + as incremental and generational collection; we then discuss + low-level implementation considerations and the relationships + between storage management systems, languages, and compilers. + Throughout, we attempt to present a unified view based on abstract + traversal strategies, addressing issues of conservatism, + opportunism, and immediacy of reclamation; we also point out a + variety of implementation details that are likely to have a + significant impact on performance. + * .. _WIL95: Paul R. Wilson, Mark S. Johnstone, Michael Neely, David Boles. 1995. "`Dynamic Storage Allocation: A Survey and Critical Review `_". University of Texas at Austin. .. abstract: wil95.html + Dynamic memory allocation has been a fundamental part of most + computer systems since roughly 1960, and memory allocation is + widely considered to be either a solved problem or an insoluble + one. In this survey, we describe a variety of memory allocator + designs and point out issues relevant to their design and + evaluation. We then chronologically survey most of the literature + on allocators between 1961 and 1995. (Scores of papers are + discussed, in varying detail, and over 150 references are given.) + + We argue that allocator designs have been unduly restricted by an + emphasis on mechanism, rather than policy, while the latter is + more important; higher-level strategic issues are still more + important, but have not been given much attention. + + Most theoretical analyses and empirical allocator evaluations to + date have relied on very strong assumptions of randomness and + independence, but real program behavior exhibits important + regularities that must be exploited if allocators are to perform + well in practice. + * .. _WISE78: David S. Wise. 1978. "`The double buddy system `_". Department of Computer Science at Indiana University. Technical Report 79. @@ -891,6 +2718,18 @@ Bibliography .. abstract: wise92.html + A stop-and-copy garbage collector updates one-bit reference + counting with essentially no extra space and minimal memory cycles + beyond the conventional collection algorithm. Any object that is + uniquely referenced during a collection becomes a candidate for + cheap recovery before the next one, or faster recopying then if it + remains uniquely referenced. Since most objects stay uniquely + referenced, subsequent collections run faster even if none are + recycled between garbage collections. This algorithm extends to + generation scavenging, it admits uncounted references from roots, + and it corrects conservatively stuck counters, that result from + earlier uncertainty whether references were unique. + * .. _WW95: David S. Wise, Joshua Walgenbach. 1996. "`Static and Dynamic Partitioning of Pointers as Links and Threads `_". SIGPLAN. Proc. 1996 ACM SIGPLAN Intl. Conf. on Functional Programming, SIGPLAN Not. 31, 6 (June 1996), pp. 42--49. @@ -905,12 +2744,51 @@ Bibliography .. abstract: withington91.html + A group at Symbolics is developing a Lisp runtime kernel, derived + from its Genera operating system, to support real-time control + applications. The first candidate application has strict + response-time requirements (so strict that it does not permit the + use of paged virtual memory). Traditionally, Lisp's automatic + storage-management mechanism has made it unsuitable to real-time + systems of this nature. A number of garbage collector designs and + implementations exist (including the Genera garbage collector) + that purport to be "real-time", but which actually have only + mitigated the impact of garbage collection sufficiently that it + usually goes unnoticed by humans. Unfortunately, + electro-mechanical systems are not so forgiving. This paper + examines the limitations of existing real-time garbage collectors + and describes the avenues that we are exploring in our work to + develop a CLOS-based garbage collector that can meet the real-time + requirements of real real-time systems. + * .. _YIP91: G. May Yip. 1991. "`Incremental, Generational Mostly-Copying Garbage Collection in Uncooperative Environments `_". Digital Equipment Corporation. .. abstract: yip91.html + The thesis of this project is that incremental collection can be + done feasibly and efficiently in an architecture and compiler + independent manner. The design and implementation of an + incremental, generational mostly-copying garbage collector for C++ + is presented. The collector achieves, simultaneously, real-time + performance (from incremental collection), low total garbage + collection delay (from generational collection), and the ability + to function without hardware and compiler support (from + mostly-copying collection). + + The incremental collector runs on commercially-available + uniprocessors, such as the DECStation 3100, without any special + hardware support. It uses UNIX's user controllable page protection + facility (mprotect) to synchronize between the scanner (of the + collector) and the mutator (of the application program). Its + implementation does not require any modification to the C++ + compiler. The maximum garbage collection pause is well within the + 100-millisecond limit imposed by real-time applications executing + on interactive workstations. Compared to its non-incremental + version, the total execution time of the incremental collector is + not adversely affected. + * .. _YUASA90: Taiichi Yuasa. 1990. "Real-Time Garbage Collection on General-Purpose Machines". Journal of Software and Systems. 11:3 pp. 181--198. @@ -921,45 +2799,203 @@ Bibliography .. abstract: zorn88.html + This paper describes inprof, a tool used to study the memory + allocation behavior of programs. mprof records the amount of + memory each function allocates, breaks down allocation information + by type and size, and displays a program's dynamic cal graph so + that functions indirectly responsible for memory allocation are + easy to identify. mprof is a two-phase tool. The monitor phase is + linked into executing programs and records information each time + memory is allocated. The display phase reduces the data generated + by the monitor and displays the information to the user in several + tables. mprof has been implemented for C and Kyoto Common Lisp. + Measurements of these implementations are presented. + * .. _ZORN89: Benjamin Zorn. 1989. "`Comparative Performance Evaluation of Garbage Collection Algorithms `_". Computer Science Division (EECS) of University of California at Berkeley. Technical Report UCB/CSD 89/544 and PhD thesis. .. abstract: zorn89.html + This thesis shows that object-level, trace-driven simulation can + facilitate evaluation of language runtime systems and reaches new + conclusions about the relative performance of important garbage + collection algorithms. In particular, I reach the unexpected + conclusion that mark-and-sweep garbage collection, when augmented + with generations, shows comparable CPU performance and much better + reference locality than the more widely used copying algorithms. + In the past, evaluation of garbage collection algorithms has been + limited by the high cost of implementing the algorithms. + Substantially different algorithms have rarely been compared in a + systematic way. + + With the availability of high-performance, low-cost workstations, + trace-driven performance evaluation of these algorithms is now + economical. This thesis describes MARS, a runtime system simulator + that is driven by operations on program objects, and not memory + addresses. MARS has been attached to a commercial Common Lisp + system and eight large Lisp applications are used in the thesis as + test programs. To illustrate the advantages of the object-level + tracing technique used by MARS, this thesis compares the relative + performance of stop-and-copy, incremental, and mark-and-sweep + collection algorithms, all organized with multiple generations. + The comparative evaluation is based on several metrics: CPU + overhead, reference locality, and interactive availability. + + Mark-and-sweep collection shows slightly higher CPU overhead than + stop-and-copy ability (5 percent), but requires significantly less + physical memory to achieve the same page fault rate (30-40 + percent). Incremental collection has very good interactive + availability, but implementing the read barrier on stock hardware + incurs a substantial CPU overhead (30-60 percent). In the future, + I will use MARS to investigate other performance aspects of + sophisticated runtime systems. + * .. _ZORN90B: Benjamin Zorn. 1990. "Comparing Mark-and-sweep and Stop-and-copy Garbage Collection". ACM. Conference on Lisp and Functional Programming, pp. 87--98. .. abstract: zorn90b.html + Stop-and-copy garbage collection has been preferred to + mark-and-sweep collection in the last decade because its + collection time is proportional to the size of reachable data and + not to the memory size. This paper compares the CPU overhead and + the memory requirements of the two collection algorithms extended + with generations, and finds that mark-and-sweep collection + requires at most a small amount of additional CPU overhead (3-6%) + but requires an average of 20% (and up to 40%) less memory to + achieve the same page fault rate. The comparison is based on + results obtained using trace-driven simulation with large Common + Lisp programs. + * .. _ZORN90: Benjamin Zorn. 1990. "`Barrier Methods for Garbage Collection `_". University of Colorado at Boulder. Technical Report CU-CS-494-90. .. abstract: zorn90.html + Garbage collection algorithms have been enhanced in recent years + with two methods: generation-based collection and Baker + incremental copying collection. Generation-based collection + requires special actions during certain store operations to + implement the "write barrier". Incremental collection requires + special actions on certain load operations to implement the "read + barrier". This paper evaluates the performance of different + implementations of the read and write barriers and reaches several + important conclusions. First, the inlining of barrier checks + results in surprisingly low overheads, both for the write barrier + (2%-6%) and the read barrier (< 20%). Contrary to previous + belief, these results suggest that a Baker-style read barrier can + be implemented efficiently without hardware support. Second, the + use of operating system traps to implement garbage collection + methods results in extremely high overheads because the cost of + trap handling is so high. Since this large overhead is completely + unnecessary, operating system memory protection traps should be + reimplemented to be as fast as possible. Finally, the performance + of these approaches on several machine architectures is compared + to show that the results are generally applicable. + * .. _ZORN91: Benjamin Zorn. 1991. "`The Effect of Garbage Collection on Cache Performance `_". University of Colorado at Boulder. Technical Report CU-CS-528-91. .. abstract: zorn91.html + Cache performance is an important part of total performance in + modern computer systems. This paper describes the use of + trace-driven simulation to estimate the effect of garbage + collection algorithms on cache performance. Traces from four large + Common Lisp programs have been collected and analyzed with an + all-associativity cache simulator. While previous work has focused + on the effect of garbage collection on page reference locality, + this evaluation unambiguously shows that garbage collection + algorithms can have a profound effect on cache performance as + well. On processors with a direct-mapped cache, a generation + stop-and-copy algorithm exhibits a miss rate up to four times + higher than a comparable generation mark-and-sweep algorithm. + Furthermore, two-way set-associative caches are shown to reduce + the miss rate in stop-and-copy algorithms often by a factor of two + and sometimes by a factor of almost five over direct-mapped + caches. As processor speeds increase, cache performance will play + an increasing role in total performance. These results suggest + that garbage collection algorithms will play an important part in + improving that performance. + * .. _ZORN92B: Benjamin Zorn & Dirk Grunwald. 1992. "`Empirical Measurements of Six Allocation-intensive C Programs `_". ACM, SIGPLAN. SIGPLAN notices, 27(12):71--80. .. abstract: zorn92b.html + Dynamic memory management is an important part of a large class of + computer programs and high-performance algorithms for dynamic + memory management have been, and will continue to be, of + considerable interest. This paper presents empirical data from a + collection of six allocation-intensive C programs. Extensive + statistics about the allocation behavior of the programs measured, + including the distributions of object sizes, lifetimes, and + interarrival times, are presented. This data is valuable for the + following reasons: first, the data from these programs can be used + to design high-performance algorithms for dynamic memory + management. Second, these programs can be used as a benchmark test + suite for evaluating and comparing the performance of different + dynamic memory management algorithms. Finally, the data presented + gives readers greater insight into the storage allocation patterns + of a broad range of programs. The data presented in this paper is + an abbreviated version of more extensive statistics that are + publicly available on the internet. + * .. _ZORN92: Benjamin Zorn. 1993. "`The Measured Cost of Conservative Garbage Collection `_". Software -- Practice and Experience. 23(7):733--756. .. abstract: zorn92.html + Because dynamic memory management is an important part of a large + class of computer programs, high-performance algorithms for + dynamic memory management have been, and will continue to be, of + considerable interest. Experience indicates that for many + programs, dynamic storage allocation is so important that + programmers feel compelled to write and use their own + domain-specific allocators to avoid the overhead of system + libraries. Conservative garbage collection has been suggested as + an important algorithm for dynamic storage management in C + programs. In this paper, I evaluate the costs of different dynamic + storage management algorithms, including domain-specific + allocators; widely-used general-purpose allocators; and a publicly + available conservative garbage collection algorithm. Surprisingly, + I find that programmer enhancements often have little effect on + program performance. I also find that the true cost of + conservative garbage collection is not the CPU overhead, but the + memory system overhead of the algorithm. I conclude that + conservative garbage collection is a promising alternative to + explicit storage management and that the performance of + conservative collection is likely to be improved in the future. C + programmers should now seriously consider using conservative + garbage collection instead of malloc/free in programs they write. + * .. _ZORN92A: Benjamin Zorn & Dirk Grunwald. 1994. "`Evaluating Models of Memory Allocation `_". ACM. Transactions on Modeling and Computer Simulation 4(1):107--131. .. abstract: zorn92a.html + Because dynamic memory management is an important part of a large + class of computer programs, high-performance algorithms for + dynamic memory management have been, and will continue to be, of + considerable interest. We evaluate and compare models of the + memory allocation behavior in actual programs and investigate how + these models can be used to explore the performance of memory + management algorithms. These models, if accurate enough, provide + an attractive alternative to algorithm evaluation based on + trace-driven simulation using actual traces. We explore a range of + models of increasing complexity including models that have been + used by other researchers. Based on our analysis, we draw three + important conclusions. First, a very simple model, which generates + a uniform distribution around the mean of observed values, is + often quite accurate. Second, two new models we propose show + greater accuracy than those previously described in the + literature. Finally, none of the models investigated appear + adequate for generating an operating system workload. + From 8a5e8c5a919fec63800d066187ab40833f5d9d64 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 22 May 2014 17:53:56 +0100 Subject: [PATCH 221/266] Manual formatting improvements: * Hide the glossary table of contents: just show the alphabet * Don't use hanging indent for glossary entries * Cross-ref link to license now works Copied from Perforce Change: 186249 ServerID: perforce.ravenbrook.com --- mps/manual/source/copyright.rst | 4 ++-- mps/manual/source/glossary/index.rst | 1 + mps/manual/source/themes/mps/static/mps.css_t | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/mps/manual/source/copyright.rst b/mps/manual/source/copyright.rst index 98b2dea1b42..234ae604da6 100644 --- a/mps/manual/source/copyright.rst +++ b/mps/manual/source/copyright.rst @@ -1,7 +1,7 @@ -.. _license: - .. index:: single: copyright single: license +.. _license: + .. include:: ../../license.txt diff --git a/mps/manual/source/glossary/index.rst b/mps/manual/source/glossary/index.rst index bb55975bf97..91e022df5ad 100644 --- a/mps/manual/source/glossary/index.rst +++ b/mps/manual/source/glossary/index.rst @@ -7,6 +7,7 @@ Memory Management Glossary .. toctree:: :maxdepth: 1 + :hidden: a b diff --git a/mps/manual/source/themes/mps/static/mps.css_t b/mps/manual/source/themes/mps/static/mps.css_t index b21939b7af6..6b0e20d0eb4 100644 --- a/mps/manual/source/themes/mps/static/mps.css_t +++ b/mps/manual/source/themes/mps/static/mps.css_t @@ -139,6 +139,9 @@ dl.glossary dt, dl.type dt, dl.function dt, dl.macro dt { margin-top: 2em; margin-bottom: 1em; font-size: 120%; +} + +dl.type dt, dl.function dt, dl.macro dt { /* Use a hanging indent so that long wrapped prototypes are easier to read. */ padding-left: 4em; text-indent: -4em; From b6a0ce5f65ef83aef58306c128f1700b2246f091 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 22 May 2014 18:03:05 +0100 Subject: [PATCH 222/266] Hans boehm's web pages have moved to http://hboehm.info/ Copied from Perforce Change: 186251 ServerID: perforce.ravenbrook.com --- mps/manual/source/mmref/bib.rst | 6 +++--- mps/manual/source/mmref/faq.rst | 10 +++++----- mps/manual/source/mmref/lang.rst | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mps/manual/source/mmref/bib.rst b/mps/manual/source/mmref/bib.rst index ade7ddaed60..e330ad8a568 100644 --- a/mps/manual/source/mmref/bib.rst +++ b/mps/manual/source/mmref/bib.rst @@ -679,7 +679,7 @@ Bibliography * .. _BW88: - Hans-J. Boehm, Mark Weiser. 1988. "`Garbage collection in an uncooperative environment `_". Software -- Practice and Experience. 18(9):807--820. + Hans-J. Boehm, Mark Weiser. 1988. "`Garbage collection in an uncooperative environment `_". Software -- Practice and Experience. 18(9):807--820. .. abstract: bw88.html @@ -697,7 +697,7 @@ Bibliography * .. _BDS91: - Hans-J. Boehm, Alan J. Demers, Scott Shenker. 1991. "`Mostly Parallel Garbage Collection `_". Xerox PARC. ACM PLDI 91, SIGPLAN Notices 26, 6 (June 1991), pp. 157--164. + Hans-J. Boehm, Alan J. Demers, Scott Shenker. 1991. "`Mostly Parallel Garbage Collection `_". Xerox PARC. ACM PLDI 91, SIGPLAN Notices 26, 6 (June 1991), pp. 157--164. .. abstract: bds91.html @@ -716,7 +716,7 @@ Bibliography * .. _BOEHM93: - Hans-J. Boehm. 1993. "`Space Efficient Conservative Garbage Collection `_". ACM, SIGPLAN. Proceedings of the ACM SIGPLAN '91 Conference on Programming Language Design and Implementation, SIGPLAN Notices 28, 6, pp 197--206. + Hans-J. Boehm. 1993. "`Space Efficient Conservative Garbage Collection `_". ACM, SIGPLAN. Proceedings of the ACM SIGPLAN '91 Conference on Programming Language Design and Implementation, SIGPLAN Notices 28, 6, pp 197--206. .. abstract: boehm93.html diff --git a/mps/manual/source/mmref/faq.rst b/mps/manual/source/mmref/faq.rst index 190ecaecdb4..7203ff27288 100644 --- a/mps/manual/source/mmref/faq.rst +++ b/mps/manual/source/mmref/faq.rst @@ -22,7 +22,7 @@ garbage collection>` for :term:`C` exist as add-on libraries. .. link:: - `Boehm–Weiser collector `_. + `Boehm–Weiser collector `_. Why do I need to test the return value from ``malloc``? Surely it always succeeds? @@ -130,7 +130,7 @@ semi-conservative garbage collectors for C++. .. link:: - `Boehm–Weiser collector `_. + `Boehm–Weiser collector `_. Why is ``delete`` so slow? @@ -168,7 +168,7 @@ collector will work with C++. .. link:: - `Boehm–Weiser collector `_. + `Boehm–Weiser collector `_. Can't I get all the benefits of garbage collection using C++ constructors and destructors? @@ -408,7 +408,7 @@ Boehm–Weiser collector. .. link:: - `Boehm–Weiser collector `_, + `Boehm–Weiser collector `_, `GC-LIST FAQ `_. @@ -423,7 +423,7 @@ provides garbage collection. .. link:: - `Boehm–Weiser collector `_. + `Boehm–Weiser collector `_. Why does my program use so much memory? diff --git a/mps/manual/source/mmref/lang.rst b/mps/manual/source/mmref/lang.rst index 0d081b82a30..4860089f580 100644 --- a/mps/manual/source/mmref/lang.rst +++ b/mps/manual/source/mmref/lang.rst @@ -86,7 +86,7 @@ Memory management in various languages .. link:: - `Boehm-Weiser collector `_, + `Boehm-Weiser collector `_, `C standardization `_, `comp.lang.c Frequently Asked Questions `_. From d21c318794cb66c46b5e3a5a29b210cc48def4db Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 22 May 2014 18:09:00 +0100 Subject: [PATCH 223/266] =?UTF-8?q?Prefer=20"boehm=E2=80=93demers=E2=80=93?= =?UTF-8?q?weiser"=20following=20http://hboehm.info/gc/.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copied from Perforce Change: 186252 ServerID: perforce.ravenbrook.com --- mps/manual/source/mmref/faq.rst | 16 ++++++++-------- mps/manual/source/mmref/lang.rst | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mps/manual/source/mmref/faq.rst b/mps/manual/source/mmref/faq.rst index 7203ff27288..a484fdcf3bd 100644 --- a/mps/manual/source/mmref/faq.rst +++ b/mps/manual/source/mmref/faq.rst @@ -22,7 +22,7 @@ garbage collection>` for :term:`C` exist as add-on libraries. .. link:: - `Boehm–Weiser collector `_. + `Boehm–Demers–Weiser collector `_. Why do I need to test the return value from ``malloc``? Surely it always succeeds? @@ -130,7 +130,7 @@ semi-conservative garbage collectors for C++. .. link:: - `Boehm–Weiser collector `_. + `Boehm–Demers–Weiser collector `_. Why is ``delete`` so slow? @@ -163,12 +163,12 @@ In :term:`C++`, it may be that class libraries expect you to call Failing this, if there is a genuine :term:`memory leak` in a class library for which you don't have the source, then the only thing you -can try is to add a :term:`garbage collector`. The Boehm–Weiser +can try is to add a :term:`garbage collector`. The Boehm–Demers–Weiser collector will work with C++. .. link:: - `Boehm–Weiser collector `_. + `Boehm–Demers–Weiser collector `_. Can't I get all the benefits of garbage collection using C++ constructors and destructors? @@ -400,7 +400,7 @@ Where can I find out more about garbage collection? Many modern languages have :term:`garbage collection` built in, and the language documentation should give details. For some other languages, garbage collection can be added, for example via the -Boehm–Weiser collector. +Boehm–Demers–Weiser collector. .. seealso:: :term:`garbage collection` @@ -408,14 +408,14 @@ Boehm–Weiser collector. .. link:: - `Boehm–Weiser collector `_, + `Boehm–Demers–Weiser collector `_, `GC-LIST FAQ `_. Where can I get a garbage collector? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The Boehm–Weiser collector is suitable for C or C++. The best way to +The Boehm–Demers–Weiser collector is suitable for C or C++. The best way to get a garbage collector, however, is to program in a language that provides garbage collection. @@ -423,7 +423,7 @@ provides garbage collection. .. link:: - `Boehm–Weiser collector `_. + `Boehm–Demers–Weiser collector `_. Why does my program use so much memory? diff --git a/mps/manual/source/mmref/lang.rst b/mps/manual/source/mmref/lang.rst index 4860089f580..31a22cc0717 100644 --- a/mps/manual/source/mmref/lang.rst +++ b/mps/manual/source/mmref/lang.rst @@ -53,7 +53,7 @@ Memory management in various languages library functions for :term:`memory (2)` management in C, :term:`malloc` and :term:`free (2)`, have become almost synonymous with :term:`manual memory management`), although - with the Boehm-Weiser :term:`collector (1)`, it is now + with the Boehm–Demers–Weiser :term:`collector (1)`, it is now possible to use :term:`garbage collection`. The language is notorious for fostering memory management @@ -86,7 +86,7 @@ Memory management in various languages .. link:: - `Boehm-Weiser collector `_, + `Boehm–Demers–Weiser collector `_, `C standardization `_, `comp.lang.c Frequently Asked Questions `_. @@ -173,7 +173,7 @@ Memory management in various languages abstraction level of C++ makes the bookkeeping required for :term:`manual memory management` even harder. Although the standard library provides only manual memory management, with - the Boehm-Weiser :term:`collector (1)`, it is now possible to + the Boehm–Demers–Weiser :term:`collector (1)`, it is now possible to use :term:`garbage collection`. :term:`Smart pointers` are another popular solution. From 64ad925abe1578c6c606ef1bf28ef497cdc3045d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 22 May 2014 18:19:09 +0100 Subject: [PATCH 224/266] Fix broken link. Copied from Perforce Change: 186253 ServerID: perforce.ravenbrook.com --- mps/manual/source/mmref/credit.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/manual/source/mmref/credit.rst b/mps/manual/source/mmref/credit.rst index 816cfb0c870..0ce0bd0c8b3 100644 --- a/mps/manual/source/mmref/credit.rst +++ b/mps/manual/source/mmref/credit.rst @@ -27,7 +27,7 @@ Reference. The Adaptive Memory Management Group no longer exists, and Harlequin has become a part of `Global Graphics `_. However, most of the group's work -has been aquired by `Ravenbrook Limited`, whose directors are Richard +has been aquired by `Ravenbrook Limited`_, whose directors are Richard Brooksby, the group's chief architect and manager, and Nick Barnes, a senior group member. From 2dd5cc0e7b51853499f754290a70801e15ba4255 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 22 May 2014 19:27:56 +0100 Subject: [PATCH 225/266] Initial support for building the memory management reference out of the memory pool system manual. Copied from Perforce Change: 186255 ServerID: perforce.ravenbrook.com --- mps/manual/source/conf.py | 55 ++++++------ .../source/{diagrams => images}/logo.png | Bin mps/manual/source/mmref/faq.rst | 22 ++--- .../source/themes/mmref/static/mmref.css_t | 78 ++++++++++++++++++ mps/manual/source/themes/mmref/theme.conf | 18 ++++ 5 files changed, 136 insertions(+), 37 deletions(-) rename mps/manual/source/{diagrams => images}/logo.png (100%) create mode 100644 mps/manual/source/themes/mmref/static/mmref.css_t create mode 100644 mps/manual/source/themes/mmref/theme.conf diff --git a/mps/manual/source/conf.py b/mps/manual/source/conf.py index b3c561d615f..d9daac312ea 100644 --- a/mps/manual/source/conf.py +++ b/mps/manual/source/conf.py @@ -22,6 +22,33 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('.')) +# -- Project configuration ----------------------------------------------------- + +# The same set of sources builds the Memory Pool System documentation +# and the Memory Management Reference. + +if True: + project = u'Memory Pool System' + master_doc = 'index' + html_theme = 'mps' + html_sidebars = { + '**': ['localtoc.html', 'relations.html', 'links.html', 'contact.html'], + } + with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), + '../../code/version.c')) as f: + for line in f: + m = re.match(r'#define MPS_RELEASE "release/((\d+\.\d+)\.\d+)"', line) + if m: + release, version = m.groups() + break +else: + project = u'Memory Management Reference' + master_doc = 'index' + html_theme = 'mmref' + version = '4' + release = '4.0' + + # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. @@ -40,24 +67,9 @@ # The encoding of source files. #source_encoding = 'utf-8-sig' -# The master toctree document. -master_doc = 'index' - # General information about the project. -project = u'Memory Pool System' copyright = date.today().strftime(u'%Y, Ravenbrook Limited') -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), - '../../code/version.c')) as f: - for line in f: - m = re.match(r'#define MPS_RELEASE "release/((\d+\.\d+)\.\d+)"', line) - if m: - release, version = m.groups() - break - # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None @@ -98,10 +110,6 @@ # -- Options for HTML output --------------------------------------------------- -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'mps' - # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. @@ -119,7 +127,7 @@ # The name of an image file (relative to this directory) to place at the top # of the sidebar. -html_logo = 'diagrams/logo.png' +html_logo = 'images/logo.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 @@ -129,7 +137,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = [] +html_static_path = ['images'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. @@ -139,11 +147,6 @@ # typographically correct entities. html_use_smartypants = True -# Custom sidebar templates, maps document names to template names. -html_sidebars = { - '**': ['localtoc.html', 'relations.html', 'links.html', 'contact.html'], -} - # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} diff --git a/mps/manual/source/diagrams/logo.png b/mps/manual/source/images/logo.png similarity index 100% rename from mps/manual/source/diagrams/logo.png rename to mps/manual/source/images/logo.png diff --git a/mps/manual/source/mmref/faq.rst b/mps/manual/source/mmref/faq.rst index a484fdcf3bd..c45ba810d64 100644 --- a/mps/manual/source/mmref/faq.rst +++ b/mps/manual/source/mmref/faq.rst @@ -25,8 +25,8 @@ garbage collection>` for :term:`C` exist as add-on libraries. `Boehm–Demers–Weiser collector `_. -Why do I need to test the return value from ``malloc``? Surely it always succeeds? -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Why do I need to test the return value from malloc? Surely it always succeeds? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For small programs, and during light testing, it is true that :term:`malloc` usually succeeds. Unfortunately, there are all sorts of @@ -73,8 +73,8 @@ when out of memory, wrap :term:`malloc` in something like this:: Undefined behavior is worth eliminating even in small programs. -What's the point of having a garbage collector? Why not use ``malloc`` and ``free``? -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +What's the point of having a garbage collector? Why not use malloc and free? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :term:`Manual memory management`, such as :term:`malloc` and :term:`free (2)`, forces the programmer to keep track of which memory @@ -90,12 +90,12 @@ problem, rather than the tedious details of the implementation. .. seealso:: :term:`garbage collection` -What's wrong with ANSI ``malloc`` in the C library? -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +What's wrong with ANSI malloc in the C library? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -:term:`Malloc` provides a very basic :term:`manual memory management` -service. However, it does not provide the following things, which may -be desirable in your memory manager: +The :term:`malloc` function provides a very basic :term:`manual memory +management` service. However, it does not provide the following +things, which may be desirable in your memory manager: * high performance for specified block sizes; * :term:`tagged references`; @@ -133,8 +133,8 @@ semi-conservative garbage collectors for C++. `Boehm–Demers–Weiser collector `_. -Why is ``delete`` so slow? -^^^^^^^^^^^^^^^^^^^^^^^^^^ +Why is delete so slow? +^^^^^^^^^^^^^^^^^^^^^^ Often ``delete`` must perform a more complex task than simply freeing the memory associated with an object; this is known as diff --git a/mps/manual/source/themes/mmref/static/mmref.css_t b/mps/manual/source/themes/mmref/static/mmref.css_t new file mode 100644 index 00000000000..69a3be290b0 --- /dev/null +++ b/mps/manual/source/themes/mmref/static/mmref.css_t @@ -0,0 +1,78 @@ +/* -*- css -*- */ + +@import url('scrolls.css'); + +h1, h2, h3, h4, h5, h6, dl.glossary dt { + font-family: {{ theme_headfont }}; +} + +dl.glossary dt { + font-size: 120%; +} + +div.header { + background-image: none; + background-color: {{ theme_headerbg }}; + border-top: none; +} + +h1.heading a { + background-image: url(logo.png); + background-size: auto 100%; + background-position: center; + background-repeat: no-repeat; + display: block; + width: 100%; + height: 80px; +} + +a, a:visited, a.reference.internal { + text-decoration: none; +} + +a.reference em { + font-style: normal; +} + +a.reference.internal:hover { + text-decoration: none; + border-bottom: 1px solid {{ theme_underlinecolor }}; +} + +.xref.std-term { + font-style: normal; + color: {{ theme_textcolor }}; + border-bottom: 1px dotted {{ theme_underlinecolor }}; +} + +div.seealso, div.admonition { + background: url(metal.png); + border: none; +} + +p.admonition_title:after { + content: ":"; +} + +div.admonition p.admonition-title + p + p { + margin-top: 1em; +} + +div.figure { + margin-top: 1em; + margin-bottom: 1em; +} + +div.figure img { + max-width: 100%; +} + +.align-center { + text-align: center; +} + +img.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} \ No newline at end of file diff --git a/mps/manual/source/themes/mmref/theme.conf b/mps/manual/source/themes/mmref/theme.conf new file mode 100644 index 00000000000..0977e252b47 --- /dev/null +++ b/mps/manual/source/themes/mmref/theme.conf @@ -0,0 +1,18 @@ +# Colour scheme: + +[theme] +inherit = scrolls +stylesheet = mmref.css + + +[options] +headerbg = #B38184 +subheadlinecolor = #000000 +linkcolor = #73626E +visitedlinkcolor = #73626E +admonitioncolor = #aaa +textcolor = #000000 +underlinecolor = #aaa + +bodyfont = 'Optima', sans-serif +headfont = 'Verdana', sans-serif From 3c037431eda012b85d96e0102cd5643d12314dad Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 22 May 2014 22:10:29 +0100 Subject: [PATCH 226/266] Control project selection via the environment. MMRef uses own layout, not scrolls layout. Put title at the top and improve formatting. Don't generate next/prev links to different directories. Copied from Perforce Change: 186257 ServerID: perforce.ravenbrook.com --- mps/manual/source/conf.py | 17 ++++---- mps/manual/source/themes/mmref/layout.html | 42 +++++++++++++++++++ .../source/themes/mmref/static/mmref.css_t | 42 ++++++++++++++----- 3 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 mps/manual/source/themes/mmref/layout.html diff --git a/mps/manual/source/conf.py b/mps/manual/source/conf.py index d9daac312ea..733438fc253 100644 --- a/mps/manual/source/conf.py +++ b/mps/manual/source/conf.py @@ -25,9 +25,16 @@ # -- Project configuration ----------------------------------------------------- # The same set of sources builds the Memory Pool System documentation -# and the Memory Management Reference. +# and the Memory Management Reference, depending on whether the MMREF +# environment variable is set. -if True: +if os.environ.get('MMREF'): + project = u'Memory Management Reference' + master_doc = 'index' + html_theme = 'mmref' + version = '4' + release = '4.0' +else: project = u'Memory Pool System' master_doc = 'index' html_theme = 'mps' @@ -41,12 +48,6 @@ if m: release, version = m.groups() break -else: - project = u'Memory Management Reference' - master_doc = 'index' - html_theme = 'mmref' - version = '4' - release = '4.0' # -- General configuration ----------------------------------------------------- diff --git a/mps/manual/source/themes/mmref/layout.html b/mps/manual/source/themes/mmref/layout.html new file mode 100644 index 00000000000..0597e1ca7ef --- /dev/null +++ b/mps/manual/source/themes/mmref/layout.html @@ -0,0 +1,42 @@ +{# + scrolls/layout.html + ~~~~~~~~~~~~~~~~~~~ + + Sphinx layout template for the scrolls theme, originally written + by Armin Ronacher. + + :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +#} +{%- extends "basic/layout.html" %} +{% set script_files = script_files + ['_static/theme_extras.js'] %} +{% set css_files = css_files + ['_static/print.css'] %} +{# do not display relbars #} +{% block relbar1 %}{% endblock %} +{% block relbar2 %}{% endblock %} +{% block content %} +
+ +
+ {%- if prev and '../' not in prev.link %} + « {{ prev.title }} | + {%- endif %} + {{ title }} + {%- if next and '../' not in next.link %} + | {{ next.title }} » + {%- endif %} +
+
+ {%- if display_toc %} +
+

{{ _('Table Of Contents') }}

+ {{ toc }} +
+ {%- endif %} + {% block body %}{% endblock %} +
+
+{% endblock %} diff --git a/mps/manual/source/themes/mmref/static/mmref.css_t b/mps/manual/source/themes/mmref/static/mmref.css_t index 69a3be290b0..cd77bc91aed 100644 --- a/mps/manual/source/themes/mmref/static/mmref.css_t +++ b/mps/manual/source/themes/mmref/static/mmref.css_t @@ -2,28 +2,38 @@ @import url('scrolls.css'); -h1, h2, h3, h4, h5, h6, dl.glossary dt { +h2, h3, h4, h5, h6, dl.glossary dt { font-family: {{ theme_headfont }}; } -dl.glossary dt { - font-size: 120%; -} - div.header { background-image: none; background-color: {{ theme_headerbg }}; border-top: none; } +h1.heading { + height: auto; + text-align: center; + padding-top: 10px; + padding-bottom: 10px; +} + +h1.heading:hover { + background: #73626E; +} + h1.heading a { - background-image: url(logo.png); - background-size: auto 100%; - background-position: center; - background-repeat: no-repeat; + background-image: none; display: block; width: 100%; - height: 80px; + height: auto; + font-size: 150%; +} + +h1.heading span { + display: block; + color: {{ theme_textcolor }}; } a, a:visited, a.reference.internal { @@ -75,4 +85,14 @@ img.align-center { display: block; margin-left: auto; margin-right: auto; -} \ No newline at end of file +} + +dl.glossary dt { + font-size: 120%; + margin-top: 1em; +} + +p.glossary-alphabet { + font-weight: bold; + text-align: center; +} From aae21e035377c53e662816550ae02295a0fdf67c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 23 May 2014 14:06:26 +0100 Subject: [PATCH 227/266] Fix bug in poollo: forgot to change losegbits to loseggrains in one place. Copied from Perforce Change: 186262 ServerID: perforce.ravenbrook.com --- mps/code/poollo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/poollo.c b/mps/code/poollo.c index e022963c14b..06d3e68160f 100644 --- a/mps/code/poollo.c +++ b/mps/code/poollo.c @@ -189,7 +189,7 @@ static void loSegFinish(Seg seg) ATTRIBUTE_UNUSED -static Count loSegBits(LOSeg loseg) +static Count loSegGrains(LOSeg loseg) { LO lo; Size size; From 062275fdf772d993c6aa3da6a12c30d3c885451f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 23 May 2014 15:58:51 +0100 Subject: [PATCH 228/266] Memory management reference progress. Copied from Perforce Change: 186264 ServerID: perforce.ravenbrook.com --- mps/manual/source/index.rst | 6 + mps/manual/source/make-mmref.py | 168 +++++++++++++ mps/manual/source/mmref-copyright.rst | 26 ++ mps/manual/source/mmref/index.rst | 2 + mps/manual/source/themes/mmref/layout.html | 7 +- .../source/themes/mmref/static/metal.png | Bin 0 -> 43694 bytes .../source/themes/mmref/static/mmref.css_t | 34 ++- .../source/themes/mmref/static/watermark.png | Bin 0 -> 75141 bytes .../source/themes/mmref/static/watermark.svg | 237 ++++++++++++++++++ mps/manual/source/themes/mmref/theme.conf | 14 +- 10 files changed, 481 insertions(+), 13 deletions(-) create mode 100755 mps/manual/source/make-mmref.py create mode 100644 mps/manual/source/mmref-copyright.rst create mode 100644 mps/manual/source/themes/mmref/static/metal.png create mode 100644 mps/manual/source/themes/mmref/static/watermark.png create mode 100644 mps/manual/source/themes/mmref/static/watermark.svg diff --git a/mps/manual/source/index.rst b/mps/manual/source/index.rst index 161a13ad3b3..91d27f7a8a8 100644 --- a/mps/manual/source/index.rst +++ b/mps/manual/source/index.rst @@ -18,6 +18,12 @@ Memory Pool System Memory Management Reference ########################### +.. toctree:: + :hidden: + + mmref-index + mmref-copyright + .. toctree:: :maxdepth: 2 diff --git a/mps/manual/source/make-mmref.py b/mps/manual/source/make-mmref.py new file mode 100755 index 00000000000..92add8bbbea --- /dev/null +++ b/mps/manual/source/make-mmref.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python +# +# Ravenbrook +# +# +# MAKE THE MEMORY MANAGEMENT REFERENCE +# +# Gareth Rees, Ravenbrook Limited, 2014-05-23 +# +# +# 1. INTRODUCTION +# +# This script builds the Memory Management Reference website from the +# Memory Pool System manual. +# +# The whole build procedure is as follows: +# +# 1. Sync //info.ravenbrook.com/project/mps/master/manual/... +# 2. make html MMREF=1 +# 3. Run this script +# +# +# 2. DESIGN +# +# We build the Memory Management Reference out of the Memory Pool +# System manual because: +# +# 1. having a single set of sources makes it easier to work on; +# 2. the glossary is a vital tool in organizing the MPS manual; +# 3. cross-references from the MMRef to the MPS are an opportunity +# for advertising the latter to readers of the former. +# +# +# 3. DEPENDENCIES +# +# html5lib +# six + +import html5lib +import html5lib.serializer +import html5lib.treewalkers +from io import open +import os +import re +from shutil import copyfile +import sys +from six.moves.urllib.parse import urljoin + + +# 4. CONFIGURATION + +# Subdirectories of the MPS manual that belong in the MMRef. +mmref_dirs = ('glossary', 'mmref', '_images', '_static') + +# Top-level files that belong in the MMRef. +mmref_files = ('index', 'copyright') + +# Regular expression matching files to be included in the MMRef. +url_filter_re = re.compile(r'^/html/(?:(?:{})\.html)?(?:#.*)?$|/(?:{})/'.format( + '|'.join(mmref_files), '|'.join(mmref_dirs))) + +# Root URL for the MPS manual. +rewrite_url = 'http://www.ravenbrook.com/project/mps/master/manual/html/' + + +def rewrite_links(src, src_base, url_filter, rewrite_base, + url_attributes = (('a', 'href'),)): + """Rewrite URLs in src and return the result. + + First, src is parsed as HTML. Second, all URLs found in the + document are resolved relative to src_base and the result passed to + the functions url_filter. If this returns False, the URL is resolved + again, this time relative to rewrite_base, and the result stored + back to the document. Finally, the updated document is serialized + as HTML and returned. + + The keyword argument url_attributes is a sequence of (tag, + attribute) pairs that contain URLs to be rewritten. + + """ + tree_builder = html5lib.treebuilders.getTreeBuilder('dom') + parser = html5lib.html5parser.HTMLParser(tree = tree_builder) + dom = parser.parse(src) + + for tag, attr in url_attributes: + for e in dom.getElementsByTagName(tag): + u = e.getAttribute(attr) + if u and not url_filter(urljoin(src_base, u)): + rewritten = urljoin(rewrite_base, u) + if u != rewritten: + print(" {} -> {}".format(u, rewritten)) + e.setAttribute(attr, rewritten) + + tree_walker = html5lib.treewalkers.getTreeWalker('dom') + html_serializer = html5lib.serializer.htmlserializer.HTMLSerializer() + return u''.join(html_serializer.serialize(tree_walker(dom))) + +def rewrite_file(src_dir, src_filename, target_path, rewrite_url): + src_path = os.path.join(src_dir, src_filename) + if (os.path.exists(target_path) + and os.stat(src_path).st_mtime <= os.stat(target_path).st_mtime): + return + print("Converting {} -> {}".format(src_path, target_path)) + src = open(os.path.join(src_dir, src_filename), encoding='utf-8').read() + src_base = '/{}/'.format(src_dir) + url_filter = url_filter_re.search + rewrite_base = urljoin(rewrite_url, src_dir) + result = rewrite_links(src, src_base, url_filter, rewrite_base) + open(target_path, 'w', encoding='utf-8').write(result) + +def main(argv): + src_root = 'html' + target_root = 'mmref' + for d in mmref_dirs: + src_dir = os.path.join(src_root, d) + target_dir = os.path.join(target_root, d) + os.makedirs(target_dir, exist_ok=True) + for f in os.listdir(src_dir): + target_path = os.path.join(target_dir, f) + if os.path.splitext(f)[1] == '.html': + rewrite_file(src_dir, f, target_path, rewrite_url) + else: + copyfile(os.path.join(src_dir, f), target_path) + for f in mmref_files: + rewrite_file(src_root, 'mmref-{}.html'.format(f), + os.path.join(target_root, '{}.html'.format(f)), + rewrite_url) + + +if __name__ == '__main__': + main(sys.argv) + + +# B. DOCUMENT HISTORY +# +# 2014-05-23 GDR Created. +# +# +# C. COPYRIGHT AND LICENCE +# +# Copyright (c) 2014 Ravenbrook Ltd. All rights reserved. +# +# 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. +# +# 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 AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +# 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. +# +# +# $Id: //info.ravenbrook.com/project/mps/master/tool/branch#9 $ diff --git a/mps/manual/source/mmref-copyright.rst b/mps/manual/source/mmref-copyright.rst new file mode 100644 index 00000000000..b2e95ecd3a7 --- /dev/null +++ b/mps/manual/source/mmref-copyright.rst @@ -0,0 +1,26 @@ +Copyright +********* + + +Use subject to copyright restrictions +===================================== + +The copyright in The Memory Management Reference is owned by +`Ravenbrook Limited`_. + +.. _Ravenbrook Limited: http://www.ravenbrook.com/ + +Permission to copy part or all of The Memory Management Reference for +personal or classroom use is granted without fee, provided that copies +are not made or distributed for profit or commercial advantage; that +the copyright notice, the title of the publication, and its date +appear; and that notice is given that copying is by permission of +Ravenbrook Limited. To copy otherwise, to republish, to post on +servers, or to redistribute to lists requires prior specific +permission. + + +Warranty disclaimer +=================== + +The Memory Management Reference is provided "as is" without warranty of any kind, express or implied, including, but not limited to, the implied warranties of merchantability, fitness for a particular purpose, and non-infringement. diff --git a/mps/manual/source/mmref/index.rst b/mps/manual/source/mmref/index.rst index eb6ef48257e..6ca51d1fb39 100644 --- a/mps/manual/source/mmref/index.rst +++ b/mps/manual/source/mmref/index.rst @@ -1,3 +1,5 @@ +.. _mmref-intro: + Introduction to memory management ################################# diff --git a/mps/manual/source/themes/mmref/layout.html b/mps/manual/source/themes/mmref/layout.html index 0597e1ca7ef..961baeda428 100644 --- a/mps/manual/source/themes/mmref/layout.html +++ b/mps/manual/source/themes/mmref/layout.html @@ -17,15 +17,14 @@ {% block content %}
- {%- if prev and '../' not in prev.link %} + {%- if prev and '/' not in prev.link and 'mmref-' not in prev.link %} « {{ prev.title }} | {%- endif %} {{ title }} - {%- if next and '../' not in next.link %} + {%- if next and '/' not in next.link and 'mmref-' not in next.link %} | {{ next.title }} » {%- endif %}
diff --git a/mps/manual/source/themes/mmref/static/metal.png b/mps/manual/source/themes/mmref/static/metal.png new file mode 100644 index 0000000000000000000000000000000000000000..2f9f1ad08473dcf728044895fd7809749e38eb9e GIT binary patch literal 43694 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
C!Jx` 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⪙&q=#tG>6de17c{BTQQMXN{V(0X&DK0cOGJ zEOs)g7nJR`wy4=pr>;5EV6y=F`}vkL<O7(<{Rth3!_Cm+aI~7=Lkt+mz|Fm-g1qO3K0=rK{Q@U)sqs%OfGkdk%8OikgXr|cSY37kQ&!SUWTRQw z&n;h?V!E$7joL041iJQ4j!Tg++Ej5d7+8S-E|2~EdcscpuE6lm;_@30Di8$AC$_jq zJwrit#k|G&r>^tav!e0%~fdfY`Cgzev&|x2UK2^+(&H zWd{M-q{X6=r^mQ0uHlo}FnR(idaUK-FAC~7EDY^4tB7^Hc?C#dxXx-Un3L(x%#_0HuLyTSQRIkSRCDR??yS`{xpisiwvj z73%#aMkEa^nj$9f3?5$g9dL3^{NWtlu@jqY7K1cMndJA!rRn(YVI2PgoP4RA;jXzA z$%*N&26D*5g;kt^E1S{Yg_G*$koJt75oM(Elf|0F^WB& znxR11>ow!!v0p8Yu=)E!@3fP@ZDpiXPC-xp$_eId4mTE%GnL&f*6G`hVS9e&L4B%Q zWYqgB|8_zw3tJ;SHGTft_tbfpM!&CV%8MLfF^5fS3A@ApR#Mz z*fG=BgQ`J_@&F^4qtdFghj|5$PK(Xm5%>bd*7X~~l4-Nf{2HlrquM+=f)ve7E(drZ z39N@Af$Z8qZDp)PI(rFB_TL5VYPJcG4GYQ^s4g4^17=L6Sk|en7`8^l zRGg3W<-m_hNB*zoRycE8ug4M1bQ`N;>MDefQNR@BEt?AKeyx9(g6latGPJkubQwrZ z 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 literal 0 HcmV?d00001 diff --git a/mps/manual/source/themes/mmref/static/watermark.svg b/mps/manual/source/themes/mmref/static/watermark.svg new file mode 100644 index 00000000000..ca9159234e1 --- /dev/null +++ b/mps/manual/source/themes/mmref/static/watermark.svg @@ -0,0 +1,237 @@ + + + + + + + + + + image/svg+xml + + + + + + + + 2e2f 6d70 7369 2e63 0073 697a 6520 3e203000 6d70 735f 6172 656e 615f 6f20 213d204e 554c 4c00 6d70 735f 706f 6f6c 5f6f2021 3d20 4e55 4c4c 006d 7073 5f66 6d745f6f 2021 3d20 4e55 4c4c 006d 7073 5f666d74 5f41 2021 3d20 4e55 4c4c 006d 70735f66 6d74 5f42 2021 3d20 4e55 4c4c 006d7073 5f66 6d74 2021 3d20 4e55 4c4c 006d7073 5f66 6d74 5f66 6978 6564 2021 3d204e55 4c4c 0054 4553 5454 2846 6f72 6d61742c 2066 6f72 6d61 7429 0054 4553 54542850 6f6f 6c2c 2070 6f6f 6c29 0070 5f6f2021 3d20 4e55 4c4c 006d 7073 5f61 705f6f20 213d 204e 554c 4c00 6d70 735f 61702021 3d20 4e55 4c4c 0054 4553 5454 28427566 6665 722c 2062 7566 2900 5445 53545428 4275 6666 6572 2c20 4275 6666 65724f66 4150 286d 7073 5f61 7029 2900 6d70735f 6170 2d3e 696e 6974 203d 3d20 6d70735f 6170 2d3e 616c 6c6f 6300 7020 213d204e 554c 4c00 7020 3d3d 206d 7073 5f61702d 3e69 6e69 7400 2876 6f69 6420 2a292828 6368 6172 202a 296d 7073 5f61 702d3e69 6e69 7420 2b20 7369 7a65 2920 3d3d206d 7073 5f61 702d 3e61 6c6c 6f63 00667261 6d65 5f6f 2021 3d20 4e55 4c4c 0053697a 6549 7341 6c69 676e 6564 2873 697a652c 2042 7566 6665 7250 6f6f 6c28 62756629 2d3e 616c 6967 6e6d 656e 7429 006d7073 5f73 6163 5f6f 2021 3d20 4e55 4c4c0054 4553 5454 2853 4143 2c20 7361 63290054 4553 5454 2853 4143 2c20 5341 434f6645 7874 6572 6e61 6c53 4143 286d 7073 + + diff --git a/mps/manual/source/themes/mmref/theme.conf b/mps/manual/source/themes/mmref/theme.conf index 0977e252b47..e0ef30ece1b 100644 --- a/mps/manual/source/themes/mmref/theme.conf +++ b/mps/manual/source/themes/mmref/theme.conf @@ -1,18 +1,18 @@ -# Colour scheme: +# Colour scheme: [theme] inherit = scrolls stylesheet = mmref.css - [options] -headerbg = #B38184 +headerbg = transparent +headerhover = #81A8B8 subheadlinecolor = #000000 -linkcolor = #73626E -visitedlinkcolor = #73626E -admonitioncolor = #aaa +linkcolor = #5D7985 +visitedlinkcolor = #5D7985 +admonitioncolor = #A4BCC2 textcolor = #000000 -underlinecolor = #aaa +underlinecolor = #A4BCC2 bodyfont = 'Optima', sans-serif headfont = 'Verdana', sans-serif From 1d08c3ef535460b8fb32ebc26c53c2959ce24346 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 23 May 2014 21:23:47 +0100 Subject: [PATCH 229/266] Don't copy diagrams unless they are newer. Copied from Perforce Change: 186266 ServerID: perforce.ravenbrook.com --- mps/manual/source/extensions/mps/designs.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/mps/manual/source/extensions/mps/designs.py b/mps/manual/source/extensions/mps/designs.py index 83eb78c7115..ceaee15a256 100644 --- a/mps/manual/source/extensions/mps/designs.py +++ b/mps/manual/source/extensions/mps/designs.py @@ -124,6 +124,15 @@ def convert_file(name, source, dest): with open(dest, 'wb') as out: out.write(s.encode('utf-8')) +def newer(src, target): + """Return True if src is newer (that is, modified more recently) than + target, False otherwise. + + """ + return (not os.path.isfile(target) + or os.path.getmtime(target) < os.path.getmtime(src) + or os.path.getmtime(target) < os.path.getmtime(__file__)) + # Mini-make def convert_updated(app): app.info(bold('converting MPS design documents')) @@ -131,11 +140,11 @@ def convert_updated(app): name = os.path.splitext(os.path.basename(design))[0] if name == 'index': continue converted = 'source/design/%s.rst' % name - if (not os.path.isfile(converted) - or os.path.getmtime(converted) < os.path.getmtime(design) - or os.path.getmtime(converted) < os.path.getmtime(__file__)): + if newer(design, converted): app.info('converting design %s' % name) convert_file(name, design, converted) for diagram in glob.iglob('../design/*.svg'): - shutil.copyfile(diagram, 'source/design/%s' % os.path.basename(diagram)) - + target = os.path.join('source/design/', os.path.basename(diagram)) + if newer(diagram, target): + shutil.copyfile(diagram, target) + From f36a2e5164477fe6c5d97f7332825f4b7fc30d72 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 23 May 2014 21:24:23 +0100 Subject: [PATCH 230/266] Big up the memory pool system. Copied from Perforce Change: 186267 ServerID: perforce.ravenbrook.com --- mps/manual/source/mmref/faq.rst | 17 +++++++++++------ mps/manual/source/mmref/lang.rst | 24 ++++++++++++++---------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/mps/manual/source/mmref/faq.rst b/mps/manual/source/mmref/faq.rst index c45ba810d64..594f1656b97 100644 --- a/mps/manual/source/mmref/faq.rst +++ b/mps/manual/source/mmref/faq.rst @@ -22,6 +22,7 @@ garbage collection>` for :term:`C` exist as add-on libraries. .. link:: + `Memory Pool System `_, `Boehm–Demers–Weiser collector `_. @@ -130,6 +131,7 @@ semi-conservative garbage collectors for C++. .. link:: + `Memory Pool System `_, `Boehm–Demers–Weiser collector `_. @@ -163,11 +165,11 @@ In :term:`C++`, it may be that class libraries expect you to call Failing this, if there is a genuine :term:`memory leak` in a class library for which you don't have the source, then the only thing you -can try is to add a :term:`garbage collector`. The Boehm–Demers–Weiser -collector will work with C++. +can try is to add a :term:`garbage collector`. .. link:: + `Memory Pool System `_, `Boehm–Demers–Weiser collector `_. @@ -400,7 +402,7 @@ Where can I find out more about garbage collection? Many modern languages have :term:`garbage collection` built in, and the language documentation should give details. For some other languages, garbage collection can be added, for example via the -Boehm–Demers–Weiser collector. +Memory Pool System, or the Boehm–Demers–Weiser collector. .. seealso:: :term:`garbage collection` @@ -408,6 +410,7 @@ Boehm–Demers–Weiser collector. .. link:: + `Memory Pool System `_, `Boehm–Demers–Weiser collector `_, `GC-LIST FAQ `_. @@ -415,14 +418,16 @@ Boehm–Demers–Weiser collector. Where can I get a garbage collector? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The Boehm–Demers–Weiser collector is suitable for C or C++. The best way to -get a garbage collector, however, is to program in a language that -provides garbage collection. +The Memory Pool System and the Boehm–Demers–Weiser collector are +suitable for C or C++. The best way to get a garbage collector, +however, is to program in a language that provides garbage collection +natively. .. seealso:: :term:`garbage collection` .. link:: + `Memory Pool System `_, `Boehm–Demers–Weiser collector `_. diff --git a/mps/manual/source/mmref/lang.rst b/mps/manual/source/mmref/lang.rst index 31a22cc0717..247eb7c6c25 100644 --- a/mps/manual/source/mmref/lang.rst +++ b/mps/manual/source/mmref/lang.rst @@ -53,8 +53,9 @@ Memory management in various languages library functions for :term:`memory (2)` management in C, :term:`malloc` and :term:`free (2)`, have become almost synonymous with :term:`manual memory management`), although - with the Boehm–Demers–Weiser :term:`collector (1)`, it is now - possible to use :term:`garbage collection`. + with the Memory Pool System, or the Boehm–Demers–Weiser + collector, it is now possible to use :term:`garbage + collection`. The language is notorious for fostering memory management bugs, including: @@ -86,6 +87,7 @@ Memory management in various languages .. link:: + `Memory Pool System `_, `Boehm–Demers–Weiser collector `_, `C standardization `_, `comp.lang.c Frequently Asked Questions `_. @@ -148,11 +150,11 @@ Memory management in various languages 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–Weiser - :term:`conservative collector `, and a :term:`generational ` :term:`copying collector `. + The Mono runtime comes with two collectors: the + Boehm–Demers–Weiser :term:`conservative collector + `, and a :term:`generational + ` :term:`copying collector + `. .. link:: @@ -173,9 +175,9 @@ Memory management in various languages abstraction level of C++ makes the bookkeeping required for :term:`manual memory management` even harder. Although the standard library provides only manual memory management, with - the Boehm–Demers–Weiser :term:`collector (1)`, it is now possible to - use :term:`garbage collection`. :term:`Smart pointers` are - another popular solution. + the Memory Pool System, or the Boehm–Demers–Weiser collector, + it is now possible to use :term:`garbage collection`. + :term:`Smart pointers` are another popular solution. The language is notorious for fostering memory management bugs, including: @@ -222,6 +224,8 @@ Memory management in various languages .. link:: + `Memory Pool System `_, + `Boehm–Demers–Weiser collector `_, `comp.lang.c++ FAQ `_, `C++ standardization `_. From 52d707784694df8ba2fbd712c3114ac63dcd5577 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 23 May 2014 21:25:08 +0100 Subject: [PATCH 231/266] Add home page. Copied from Perforce Change: 186268 ServerID: perforce.ravenbrook.com --- mps/manual/source/make-mmref.py | 24 +++++--- mps/manual/source/mmref-index.rst | 56 +++++++++++++++++++ .../source/themes/mmref/static/mmref.css_t | 8 +++ 3 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 mps/manual/source/mmref-index.rst diff --git a/mps/manual/source/make-mmref.py b/mps/manual/source/make-mmref.py index 92add8bbbea..31c12b9a6ba 100755 --- a/mps/manual/source/make-mmref.py +++ b/mps/manual/source/make-mmref.py @@ -88,19 +88,25 @@ def rewrite_links(src, src_base, url_filter, rewrite_base, if u and not url_filter(urljoin(src_base, u)): rewritten = urljoin(rewrite_base, u) if u != rewritten: - print(" {} -> {}".format(u, rewritten)) e.setAttribute(attr, rewritten) tree_walker = html5lib.treewalkers.getTreeWalker('dom') html_serializer = html5lib.serializer.htmlserializer.HTMLSerializer() return u''.join(html_serializer.serialize(tree_walker(dom))) +def newer(src, target): + """Return True if src is newer (that is, modified more recently) than + target, False otherwise. + + """ + return (not os.path.isfile(target) + or os.path.getmtime(target) < os.path.getmtime(src)) + def rewrite_file(src_dir, src_filename, target_path, rewrite_url): src_path = os.path.join(src_dir, src_filename) - if (os.path.exists(target_path) - and os.stat(src_path).st_mtime <= os.stat(target_path).st_mtime): + if not newer(src_path, target_path): return - print("Converting {} -> {}".format(src_path, target_path)) + print("Rewriting links in {} -> {}".format(src_path, target_path)) src = open(os.path.join(src_dir, src_filename), encoding='utf-8').read() src_base = '/{}/'.format(src_dir) url_filter = url_filter_re.search @@ -108,19 +114,19 @@ def rewrite_file(src_dir, src_filename, target_path, rewrite_url): result = rewrite_links(src, src_base, url_filter, rewrite_base) open(target_path, 'w', encoding='utf-8').write(result) -def main(argv): +def main(target_root='mmref'): src_root = 'html' - target_root = 'mmref' for d in mmref_dirs: src_dir = os.path.join(src_root, d) target_dir = os.path.join(target_root, d) os.makedirs(target_dir, exist_ok=True) for f in os.listdir(src_dir): + src_path = os.path.join(src_dir, f) target_path = os.path.join(target_dir, f) if os.path.splitext(f)[1] == '.html': rewrite_file(src_dir, f, target_path, rewrite_url) - else: - copyfile(os.path.join(src_dir, f), target_path) + elif os.path.isfile(src_path): + copyfile(src_path, target_path) for f in mmref_files: rewrite_file(src_root, 'mmref-{}.html'.format(f), os.path.join(target_root, '{}.html'.format(f)), @@ -128,7 +134,7 @@ def main(argv): if __name__ == '__main__': - main(sys.argv) + main(*sys.argv[1:]) # B. DOCUMENT HISTORY diff --git a/mps/manual/source/mmref-index.rst b/mps/manual/source/mmref-index.rst new file mode 100644 index 00000000000..264fa5c3e4a --- /dev/null +++ b/mps/manual/source/mmref-index.rst @@ -0,0 +1,56 @@ +Home +**** + +Welcome to the **Memory Management Reference**! This is a resource for programmers and computer scientists interested in :term:`memory management` and :term:`garbage collection`. + + +.. admonition:: :ref:`glossary` + + A glossary of more than 500 memory management terms, from + :term:`absolute address` to :term:`zero count table`. + + .. image:: diagrams/treadmill.svg + :target: glossary_ + + .. _glossary: glossary/index.html#glossary + + +.. admonition:: :ref:`mmref-intro` + + Articles giving a beginner's overview of memory management. + + .. image:: diagrams/address.svg + :target: intro_ + + .. _intro: mmref/index.html#mmref-intro + + +.. admonition:: :ref:`bibliography` + + Books and research papers related to memory management. + + .. image:: diagrams/copying.svg + :target: bib_ + + .. _bib: mmref/bib.html#bibliography + + +.. admonition:: :ref:`mmref-faq` + + Frequently asked questions about memory management. + + .. image:: diagrams/snap-out.svg + :target: faq_ + + .. _faq: mmref/faq.html#mmref-faq + +The Memory Management Reference is maintained by `Ravenbrook +Limited`_. We also maintain the `Memory Pool System`_ (an open-source, +thread-safe, :term:`incremental ` +garbage collector), and we are happy to provide advanced memory +management solutions to language and application developers through +our `consulting service`_. + +.. _Ravenbrook Limited: http://www.ravenbrook.com/ +.. _consulting service: http://www.ravenbrook.com/services/mm/ +.. _Memory Pool System: http://www.ravenbrook.com/project/mps/ diff --git a/mps/manual/source/themes/mmref/static/mmref.css_t b/mps/manual/source/themes/mmref/static/mmref.css_t index df9d26b1cf0..c24e7eb67a1 100644 --- a/mps/manual/source/themes/mmref/static/mmref.css_t +++ b/mps/manual/source/themes/mmref/static/mmref.css_t @@ -104,6 +104,14 @@ div.admonition-ref-glossary, div.admonition-ref-bibliography, div.admonition-ref vertical-align: top; } +div.admonition-ref-glossary, div.admonition-ref-mmref-intro { + height:400px; +} + +div.admonition-ref-bibliography, div.admonition-ref-mmref-faq { + height:230px; +} + div.admonition-ref-glossary, div.admonition-ref-bibliography { margin-right: 1%; } From 8f16d41cd3f5f4398571c71efa5b42d3a5bb1be6 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 23 May 2014 22:06:12 +0100 Subject: [PATCH 232/266] New memory management reference, using the memory pool systsem manual sources. Copied from Perforce Change: 186271 ServerID: perforce.ravenbrook.com --- mps/manual/source/make-mmref.py | 174 -------------------------------- 1 file changed, 174 deletions(-) delete mode 100755 mps/manual/source/make-mmref.py diff --git a/mps/manual/source/make-mmref.py b/mps/manual/source/make-mmref.py deleted file mode 100755 index 31c12b9a6ba..00000000000 --- a/mps/manual/source/make-mmref.py +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/env python -# -# Ravenbrook -# -# -# MAKE THE MEMORY MANAGEMENT REFERENCE -# -# Gareth Rees, Ravenbrook Limited, 2014-05-23 -# -# -# 1. INTRODUCTION -# -# This script builds the Memory Management Reference website from the -# Memory Pool System manual. -# -# The whole build procedure is as follows: -# -# 1. Sync //info.ravenbrook.com/project/mps/master/manual/... -# 2. make html MMREF=1 -# 3. Run this script -# -# -# 2. DESIGN -# -# We build the Memory Management Reference out of the Memory Pool -# System manual because: -# -# 1. having a single set of sources makes it easier to work on; -# 2. the glossary is a vital tool in organizing the MPS manual; -# 3. cross-references from the MMRef to the MPS are an opportunity -# for advertising the latter to readers of the former. -# -# -# 3. DEPENDENCIES -# -# html5lib -# six - -import html5lib -import html5lib.serializer -import html5lib.treewalkers -from io import open -import os -import re -from shutil import copyfile -import sys -from six.moves.urllib.parse import urljoin - - -# 4. CONFIGURATION - -# Subdirectories of the MPS manual that belong in the MMRef. -mmref_dirs = ('glossary', 'mmref', '_images', '_static') - -# Top-level files that belong in the MMRef. -mmref_files = ('index', 'copyright') - -# Regular expression matching files to be included in the MMRef. -url_filter_re = re.compile(r'^/html/(?:(?:{})\.html)?(?:#.*)?$|/(?:{})/'.format( - '|'.join(mmref_files), '|'.join(mmref_dirs))) - -# Root URL for the MPS manual. -rewrite_url = 'http://www.ravenbrook.com/project/mps/master/manual/html/' - - -def rewrite_links(src, src_base, url_filter, rewrite_base, - url_attributes = (('a', 'href'),)): - """Rewrite URLs in src and return the result. - - First, src is parsed as HTML. Second, all URLs found in the - document are resolved relative to src_base and the result passed to - the functions url_filter. If this returns False, the URL is resolved - again, this time relative to rewrite_base, and the result stored - back to the document. Finally, the updated document is serialized - as HTML and returned. - - The keyword argument url_attributes is a sequence of (tag, - attribute) pairs that contain URLs to be rewritten. - - """ - tree_builder = html5lib.treebuilders.getTreeBuilder('dom') - parser = html5lib.html5parser.HTMLParser(tree = tree_builder) - dom = parser.parse(src) - - for tag, attr in url_attributes: - for e in dom.getElementsByTagName(tag): - u = e.getAttribute(attr) - if u and not url_filter(urljoin(src_base, u)): - rewritten = urljoin(rewrite_base, u) - if u != rewritten: - e.setAttribute(attr, rewritten) - - tree_walker = html5lib.treewalkers.getTreeWalker('dom') - html_serializer = html5lib.serializer.htmlserializer.HTMLSerializer() - return u''.join(html_serializer.serialize(tree_walker(dom))) - -def newer(src, target): - """Return True if src is newer (that is, modified more recently) than - target, False otherwise. - - """ - return (not os.path.isfile(target) - or os.path.getmtime(target) < os.path.getmtime(src)) - -def rewrite_file(src_dir, src_filename, target_path, rewrite_url): - src_path = os.path.join(src_dir, src_filename) - if not newer(src_path, target_path): - return - print("Rewriting links in {} -> {}".format(src_path, target_path)) - src = open(os.path.join(src_dir, src_filename), encoding='utf-8').read() - src_base = '/{}/'.format(src_dir) - url_filter = url_filter_re.search - rewrite_base = urljoin(rewrite_url, src_dir) - result = rewrite_links(src, src_base, url_filter, rewrite_base) - open(target_path, 'w', encoding='utf-8').write(result) - -def main(target_root='mmref'): - src_root = 'html' - for d in mmref_dirs: - src_dir = os.path.join(src_root, d) - target_dir = os.path.join(target_root, d) - os.makedirs(target_dir, exist_ok=True) - for f in os.listdir(src_dir): - src_path = os.path.join(src_dir, f) - target_path = os.path.join(target_dir, f) - if os.path.splitext(f)[1] == '.html': - rewrite_file(src_dir, f, target_path, rewrite_url) - elif os.path.isfile(src_path): - copyfile(src_path, target_path) - for f in mmref_files: - rewrite_file(src_root, 'mmref-{}.html'.format(f), - os.path.join(target_root, '{}.html'.format(f)), - rewrite_url) - - -if __name__ == '__main__': - main(*sys.argv[1:]) - - -# B. DOCUMENT HISTORY -# -# 2014-05-23 GDR Created. -# -# -# C. COPYRIGHT AND LICENCE -# -# Copyright (c) 2014 Ravenbrook Ltd. All rights reserved. -# -# 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. -# -# 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 AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR -# 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. -# -# -# $Id: //info.ravenbrook.com/project/mps/master/tool/branch#9 $ From 9644d0b8c4e8598b4fe9fecfd3cfeec190b1ac8a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 24 May 2014 10:15:45 +0100 Subject: [PATCH 233/266] Add $id$ and copyright lines to various scripts. Copied from Perforce Change: 186276 ServerID: perforce.ravenbrook.com --- mps/tool/branch | 7 +++---- mps/tool/release | 7 +++---- mps/tool/testcoverage | 7 +++---- mps/tool/testemscripten | 7 +++---- mps/tool/testopendylan | 7 +++---- 5 files changed, 15 insertions(+), 20 deletions(-) diff --git a/mps/tool/branch b/mps/tool/branch index bb54f0d4527..981735d4360 100755 --- a/mps/tool/branch +++ b/mps/tool/branch @@ -1,11 +1,10 @@ #!/usr/bin/env python # -# Ravenbrook -# -# # BRANCH -- CREATE VERSION OR TASK BRANCH -# # Gareth Rees, Ravenbrook Limited, 2014-03-18 +# +# $Id$ +# Copyright (c) 2014 Ravenbrook Limited. See end of file for license. # # # 1. INTRODUCTION diff --git a/mps/tool/release b/mps/tool/release index 6daf82bed1c..d47fc36e788 100755 --- a/mps/tool/release +++ b/mps/tool/release @@ -1,11 +1,10 @@ #!/usr/bin/env python # -# Ravenbrook -# -# # RELEASE -- MAKE A RELEASE -# # Gareth Rees, Ravenbrook Limited, 2014-03-18 +# +# $Id$ +# Copyright (c) 2014 Ravenbrook Limited. See end of file for license. # # # 1. INTRODUCTION diff --git a/mps/tool/testcoverage b/mps/tool/testcoverage index cf4c62ae703..56ee5789bbf 100755 --- a/mps/tool/testcoverage +++ b/mps/tool/testcoverage @@ -1,11 +1,10 @@ #!/bin/sh # -# Ravenbrook -# -# # TESTCOVERAGE -- TEST COVERAGE REPORT FOR THE MPS -# # Gareth Rees, Ravenbrook Limited, 2014-03-21 +# +# $Id$ +# Copyright (c) 2014 Ravenbrook Limited. See end of file for license. # # # 1. INTRODUCTION diff --git a/mps/tool/testemscripten b/mps/tool/testemscripten index 4639e9e69a4..b4c565440db 100755 --- a/mps/tool/testemscripten +++ b/mps/tool/testemscripten @@ -1,11 +1,10 @@ #!/bin/sh # -# Ravenbrook -# -# # TESTEMSCRIPTEN -- TEST THE MPS WITH EMSCRIPTEN -# # Gareth Rees, Ravenbrook Limited, 2014-04-17 +# +# $Id$ +# Copyright (c) 2014 Ravenbrook Limited. See end of file for license. # # # 1. INTRODUCTION diff --git a/mps/tool/testopendylan b/mps/tool/testopendylan index 0c185ff2fd0..4bd1488261c 100755 --- a/mps/tool/testopendylan +++ b/mps/tool/testopendylan @@ -1,11 +1,10 @@ #!/bin/sh # -# Ravenbrook -# -# # TESTOPENDYLAN -- TEST THE MPS WITH OPENDYLAN -# # Gareth Rees, Ravenbrook Limited, 2014-03-20 +# +# $Id$ +# Copyright (c) 2014 Ravenbrook Limited. See end of file for license. # # # 1. INTRODUCTION From 86265c073469bc7b56303fe2132d4e99acfcad96 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 24 May 2014 15:40:22 +0100 Subject: [PATCH 234/266] Move bibliography to top level. Add many missing abstracts and fix some links. Just one bibliography entry for the C90 standard. Copied from Perforce Change: 186278 ServerID: perforce.ravenbrook.com --- mps/manual/source/{mmref => }/bib.rst | 1268 +++++++++++++++++++++---- mps/manual/source/index.rst | 32 +- mps/manual/source/mmref/index.rst | 2 - mps/manual/source/topic/interface.rst | 6 +- mps/manual/source/topic/plinth.rst | 10 +- 5 files changed, 1091 insertions(+), 227 deletions(-) rename mps/manual/source/{mmref => }/bib.rst (72%) diff --git a/mps/manual/source/mmref/bib.rst b/mps/manual/source/bib.rst similarity index 72% rename from mps/manual/source/mmref/bib.rst rename to mps/manual/source/bib.rst index e330ad8a568..00ef030f527 100644 --- a/mps/manual/source/mmref/bib.rst +++ b/mps/manual/source/bib.rst @@ -7,7 +7,7 @@ Bibliography Ole Agesen, David L. Detlefs. 1997. "`Finding References in Java Stacks `_". Sun Labs. OOPSLA97 Workshop on Garbage Collection and Memory Management. - .. abstract: ad97.html + .. admonition:: Abstract Exact garbage collection for the strongly-typed Java language may seem straightforward. Unfortunately, a single pair of bytecodes in @@ -22,7 +22,7 @@ Bibliography Ole Agesen, David L. Detlefs, J. Eliot B. Moss. 1998. "`Garbage Collection and Local Variable Type-precision and Liveness in Java Virtual Machines `_". ACM. Proceedings of the ACM SIGPLAN '98 conference on Programming language design and implementation, pp. 269--279. - .. abstract: adm98.html + .. admonition:: Abstract Full precision in garbage collection implies retaining only those heap allocated objects that will actually be used in the future. @@ -55,7 +55,7 @@ Bibliography Andrew Appel, John R. Ellis, Kai Li. 1988. "`Real-time Concurrent Collection on Stock Multiprocessors `_". ACM, SIGPLAN. ACM PLDI 88, SIGPLAN Notices 23, 7 (July 88), pp. 11--20. - .. abstract: ael88.html + .. admonition:: Abstract We've designed and implemented a copying garbage-collection algorithm that is efficient, real-time, concurrent, runs on @@ -73,9 +73,9 @@ Bibliography Apple Computer, Inc. 1994. *Inside Macintosh: Memory*. Addison-Wesley. ISBN 0-201-63240-3. - .. abstract: apple94.html + .. admonition:: Abstract - Inside Macintosh: Memory describes the parts of the Macintosh® + Inside Macintosh: Memory describes the parts of the Macintosh® Operating System that allow you to directly allocate, release, or otherwise manipulate memory. Everyone who programs Macintosh computers should read this book. @@ -90,7 +90,7 @@ Bibliography Giuseppe Attardi & Tito Flagella. 1994. "`A Customisable Memory Management Framework `_". TR-94-010. - .. abstract: attardi94.html + .. admonition:: Abstract Memory management is a critical issue for many large object-oriented applications, but in C++ only explicit memory @@ -114,7 +114,7 @@ Bibliography Giuseppe Attardi, Tito Flagella, Pietro Iglio. 1998. "`A customisable memory management framework for C++ `_". Software -- Practice and Experience. 28(11), 1143--1183. - .. abstract: afi98.html + .. admonition:: Abstract Automatic garbage collection relieves programmers from the burden of managing memory themselves and several techniques have been @@ -150,7 +150,7 @@ Bibliography Alain Azagury, Elliot K. Kolodner, Erez Petrank, Zvi Yehudai. 1998. "`Combining Card Marking with Remembered Sets: How to Save Scanning Time `_". ACM. ISMM'98 pp. 10--19. - .. abstract: akpy98.html + .. admonition:: Abstract We consider the combination of card marking with remembered sets for generational garbage collection as suggested by Hosking and @@ -167,7 +167,7 @@ Bibliography Henry G. Baker, Carl Hewitt. 1977. "`The Incremental Garbage Collection of Processes `_". ACM. SIGPLAN Notices 12, 8 (August 1977), pp. 55--59. - .. abstract: baker77.html + .. admonition:: Abstract This paper investigates some problems associated with an argument evaluation order that we call "future" order, which is different @@ -201,7 +201,7 @@ Bibliography Henry G. Baker. 1978. "`List Processing in Real Time on a Serial Computer `_". ACM. Communications of the ACM 21, 4 (April 1978), pp. 280--294. - .. abstract: baker78.html + .. admonition:: Abstract A real-time list processing system is one in which the time required by the elementary list operations (e.g. CONS, CAR, CDR, @@ -227,7 +227,7 @@ Bibliography Henry G. Baker. 1979. "`Optimizing Allocation and Garbage Collection of Spaces `_". In Winston and Brown, eds. *Artificial Intelligence: An MIT Perspective.* MIT Press. - .. abstract: baker79.html + .. admonition:: Abstract MACLISP, unlike some other implementations of LISP, allocates storage for different types of objects in noncontiguous areas @@ -258,7 +258,7 @@ Bibliography Henry G. Baker. 1991. "`Cache-Conscious Copying Collectors `_". OOPSLA'91/GC'91 Workshop on Garbage Collection. - .. abstract: baker91.html + .. admonition:: Abstract Garbage collectors must minimize the scarce resources of cache space and off-chip communications bandwidth to optimize @@ -272,7 +272,7 @@ Bibliography Henry G. Baker. 1992. "`Lively Linear Lisp -- 'Look Ma, No Garbage!' `_". ACM. SIGPLAN Notices 27, 8 (August 1992), pp. 89--98. - .. abstract: baker92a.html + .. admonition:: Abstract Linear logic has been proposed as one solution to the problem of garbage collection and providing efficient "update-in-place" @@ -297,7 +297,7 @@ Bibliography Henry G. Baker. 1992. "`The Treadmill: Real-Time Garbage Collection Without Motion Sickness `_". ACM. SIGPLAN Notices 27, 3 (March 1992), pp. 66--70. - .. abstract: baker92c.html + .. admonition:: Abstract A simple real-time garbage collection algorithm is presented which does not copy, thereby avoiding some of the problems caused by the @@ -312,7 +312,7 @@ Bibliography Henry G. Baker. 1992. "`CONS Should not CONS its Arguments, or, a Lazy Alloc is a Smart Alloc `_". ACM. SIGPLAN Notices 27, 3 (March 1992), 24--34. - .. abstract: baker92.html + .. admonition:: Abstract "Lazy allocation" is a model for allocating objects on the execution stack of a high-level language which does not create @@ -359,7 +359,7 @@ Bibliography Henry G. Baker. 1992. "`NREVERSAL of Fortune -- The Thermodynamics of Garbage Collection `_". Springer-Verlag. LNCS Vol. 637. - .. abstract: baker92b.html + .. admonition:: Abstract The need to *reverse* a computation arises in many contexts -- debugging, editor undoing, optimistic concurrency undoing, @@ -407,7 +407,7 @@ Bibliography Henry G. Baker. 1993. "`'Infant Mortality' and Generational Garbage Collection `_". ACM. SIGPLAN Notices 28, 4 (April 1993), pp. 55--57. - .. abstract: baker93.html + .. admonition:: Abstract Generation-based garbage collection has been advocated by appealing to the intuitive but vague notion that "young objects @@ -427,7 +427,7 @@ Bibliography Henry G. Baker. 1993. "`Equal Rights for Functional Objects or, The More Things Change, The More They Are the Same `_". ACM. OOPS Messenger 4, 4 (October 1993), pp. 2--27. - .. abstract: baker93a.html + .. admonition:: Abstract We argue that intensional object identity in object-oriented programming languages and databases is best defined operationally @@ -450,7 +450,7 @@ Bibliography Henry G. Baker. 1994. "`Minimizing Reference Count Updating with Deferred and Anchored Pointers for Functional Data Structures `_". ACM. SIGPLAN Notices 29, 9 (September 1994), pp. 38--43. - .. abstract: baker94.html + .. admonition:: Abstract "Reference counting" can be an attractive form of dynamic storage management. It recovers storage promptly and (with a garbage stack @@ -481,7 +481,7 @@ Bibliography Henry G. Baker. 1994. "`Thermodynamics and Garbage Collection `_". ACM. SIGPLAN Notices 29, 4 (April 1994), pp. 58--63. - .. abstract: baker94a.html + .. admonition:: Abstract We discuss the principles of statistical thermodynamics and their application to storage management problems. We point out problems @@ -492,7 +492,7 @@ Bibliography Henry G. Baker. 1995. "`'Use-Once' Variables and Linear Objects -- Storage Management, Reflection and Multi-Threading `_". ACM. SIGPLAN Notices 30, 1 (January 1995), pp. 45--52. - .. abstract: baker95a.html + .. admonition:: Abstract Programming languages should have 'use-once' variables in addition to the usual 'multiple-use' variables. 'Use-once' variables are @@ -532,23 +532,44 @@ Bibliography Henry G. Baker. 1995. *Memory Management: International Workshop IWMM'95*. Springer-Verlag. ISBN 3-540-60368-9. - .. abstract: baker95.html + .. admonition:: From the Preface - [from the preface] The International Workshop on Memory Management - 1995 (IWMM'95) is a continuation of the excellent series started - by Yves Bekkers and Jacques Cohen with IWMM'92. The present volume - assembles the refereed and invited technical papers which were - presented during this year's workshop. + The International Workshop on Memory Management 1995 (IWMM'95) is + a continuation of the excellent series started by Yves Bekkers and + Jacques Cohen with IWMM'92. The present volume assembles the + refereed and invited technical papers which were presented during + this year's workshop. * .. _BBW97: - Nick Barnes, Richard Brooksby, David Jones, Gavin Matthews, Pekka P. Pirinen, Nick Dalton, P. Tucker Withington. 1997. "`A Proposal for a Standard Memory Management Interface `_". OOPSLA97 Workshop on Garbage Collection and Memory Management. + Nick Barnes, Richard Brooksby, David Jones, Gavin Matthews, Pekka P. Pirinen, Nick Dalton, P. Tucker Withington. 1997. "`A Proposal for a Standard Memory Management Interface `_". OOPSLA97 Workshop on Garbage Collection and Memory Management. + + .. admonition:: From the notes + + There is no well-defined memory-management library API which would + allow programmers to easily choose the best memory management + implementation for their application. + + Some languages allow replacement of their memory management + functions, but usually only the program API is specified, hence + replacement of the entire program interface is required. + + Few languages support multiple memory management policies within a + single program. Those that do use proprietary memory management + policies. + + We believe that the design of an abstract program API is a + prerequisite to the design of a “server” API and eventually an API + that would permit multiple cooperating memory “servers”. If the + interface is simple yet powerful enough to encompass most memory + management systems, it stands a good chance of being widely + adopted. * .. _ZORN93B: David A. Barrett, Benjamin Zorn. 1993. "`Using Lifetime Predictors to Improve Memory Allocation Performance `_". ACM. SIGPLAN'93 Conference on Programming Language Design and Implementation, pp. 187--196. - .. abstract: zorn93b.html + .. admonition:: Abstract Dynamic storage allocation is used heavily in many application areas including interpreters, simulators, optimizers, and @@ -556,9 +577,9 @@ Bibliography the performance of dynamic storage allocation by predicting the lifetimes of short-lived objects when they are allocated. Using five significant, allocation-intensive C programs, we show that a - great fraction of all bytes allocated are short-lived (> 90% in + great fraction of all bytes allocated are short-lived (> 90% in all cases). Furthermore, we describe an algorithm for lifetime - prediction that accurately predicts the lifetimes of 42-99% of all + prediction that accurately predicts the lifetimes of 42--99% of all objects allocated. We describe and simulate a storage allocator that takes advantage of lifetime prediction of short-lived objects and show that it can significantly improve a program's memory @@ -569,7 +590,7 @@ Bibliography David A. Barrett, Benjamin Zorn. 1995. "`Garbage Collection using a Dynamic Threatening Boundary `_". ACM. SIGPLAN'95 Conference on Programming Language Design and Implementation, pp. 301--314. - .. abstract: barrett93.html + .. admonition:: Abstract Generational techniques have been very successful in reducing the impact of garbage collection algorithms upon the performance of @@ -604,7 +625,7 @@ Bibliography Joel F. Bartlett. 1988. "`Compacting Garbage Collection with Ambiguous Roots `_". Digital Equipment Corporation. - .. abstract: bartlett88.html + .. admonition:: Abstract This paper introduces a copying garbage collection algorithm which is able to compact most of the accessible storage in the heap @@ -644,7 +665,7 @@ Bibliography Joel F. Bartlett. 1989. "`Mostly-Copying Garbage Collection Picks Up Generations and C++ `_". Digital Equipment Corporation. - .. abstract: bartlett89.html + .. admonition:: Abstract The "mostly-copying" garbage collection algorithm provides a way to perform compacting garbage collection in spite of the presence @@ -665,7 +686,7 @@ Bibliography Emery D. Berger, Robert D. Blumofe. 1999. "`Hoard: A Fast, Scalable, and Memory-Efficient Allocator for Shared-Memory Multiprocessors `_". University of Texas at Austin. UTCS TR99-22. - .. abstract: bb99.html + .. admonition:: Abstract In this paper, we present Hoard, a memory allocator for shared-memory multiprocessors. We prove that its worst-case memory @@ -677,11 +698,39 @@ Bibliography Emery D. Berger, Benjamin G. Zorn, Kathryn S. McKinley. 2001. "`Composing high-performance memory allocators `_" ACM SIGPLAN Conference on Programming Language Design and Implementation 2001, pp. 114--124. + .. admonition:: Abstract + + Current general-purpose memory allocators do not provide + sufficient speed or flexibility for modern high-performance + applications. Highly-tuned general purpose allocators have + per-operation costs around one hundred cycles, while the cost of + an operation in a custom memory allocator can be just a handful of + cycles. To achieve high performance, programmers often write + custom memory allocators from scratch -- a difficult and + error-prone process. + + In this paper, we present a flexible and efficient infrastructure + for building memory allocators that is based on C++ templates and + inheritance. This novel approach allows programmers to build + custom and general-purpose allocators as “heap layers” that can be + composed without incurring any additional runtime overhead or + additional programming cost. We show that this infrastructure + simplifies allocator construction and results in allocators that + either match or improve the performance of heavily-tuned + allocators written in C, including the Kingsley allocator and the + GNU obstack library. We further show this infrastructure can be + used to rapidly build a general-purpose allocator that has + performance comparable to the Lea allocator, one of the best + uniprocessor allocators available. We thus demonstrate a clean, + easy-to-use allocator interface that seamlessly combines the power + and efficiency of any number of general and custom allocators + within a single application. + * .. _BW88: Hans-J. Boehm, Mark Weiser. 1988. "`Garbage collection in an uncooperative environment `_". Software -- Practice and Experience. 18(9):807--820. - .. abstract: bw88.html + .. admonition:: Abstract We describe a technique for storage allocation and garbage collection in the absence of significant co-operation from the @@ -699,7 +748,7 @@ Bibliography Hans-J. Boehm, Alan J. Demers, Scott Shenker. 1991. "`Mostly Parallel Garbage Collection `_". Xerox PARC. ACM PLDI 91, SIGPLAN Notices 26, 6 (June 1991), pp. 157--164. - .. abstract: bds91.html + .. admonition:: Abstract We present a method for adapting garbage collectors designed to run sequentially with the client, so that they may run @@ -712,13 +761,26 @@ Bibliography * .. _BC92A: - Hans-J. Boehm, David Chase. 1992. "A Proposal for Garbage-Collector-Safe C Compilation". *Journal of C Language Translation.* vol. 4, 2 (December 1992), pp. 126--141. + Hans-J. Boehm, David Chase. 1992. "`A Proposal for Garbage-Collector-Safe C Compilation `_". *Journal of C Language Translation.* vol. 4, 2 (December 1992), pp. 126--141. + + .. admonition:: Abstract + + Conservative garbage collectors are commonly used in combination + with conventional C programs. Empirically, this usually works + well. However, there are no guarantees that this is safe in the + presence of "improved" compiler optimization. We propose that C + compilers provide a facility to suppress optimizations that are + unsafe in the presence of conservative garbage collection. Such a + facility can be added to an existing compiler at very minimal + cost, provided the additional analysis is done in a + machine-independent source-to-source prepass. Such a prepass may + also check the source code for garbage-collector-safety. * .. _BOEHM93: Hans-J. Boehm. 1993. "`Space Efficient Conservative Garbage Collection `_". ACM, SIGPLAN. Proceedings of the ACM SIGPLAN '91 Conference on Programming Language Design and Implementation, SIGPLAN Notices 28, 6, pp 197--206. - .. abstract: boehm93.html + .. admonition:: Abstract We call a garbage collector conservative if it has only partial information about the location of pointers, and is thus forced to @@ -742,7 +804,7 @@ Bibliography Hans-J. Boehm. 2000. "`Reducing Garbage Collector Cache Misses `_". ACM. ISMM'00 pp. 59--64. - .. abstract: boehm00.html + .. admonition:: Abstract Cache misses are currently a major factor in the cost of garbage collection, and we expect them to dominate in the future. @@ -769,10 +831,57 @@ Bibliography Hans-J. Boehm. 2002. "`Destructors, Finalizers, and Synchronization `_". HP Labs technical report HPL-2002-335. + .. admonition:: Abstract + + We compare two different facilities for running cleanup actions + for objects that are about to reach the end of their life. + Destructors, such as we find in C++, are invoked synchronously + when an object goes out of scope. They make it easier to implement + cleanup actions for objects of well-known lifetime, especially in + the presence of exceptions. Languages like Java, Modula-3, and C# + provide a different kind of "finalization" facility: Cleanup + methods may be run when the garbage collector discovers a heap + object to be otherwise inaccessible. Unlike C++ destructors, such + methods run in a separate thread at some much less well-defined + time. We argue that these are fundamentally different, and + potentially complementary, language facilities. We also try to + resolve some common misunderstandings about finalization in the + process. In particular: 1. The asynchronous nature of finalizers + is not just an accident of implementation or a shortcoming of + tracing collectors; it is necessary for correctness of client + code, fundamentally affects how finalizers must be written, and + how finalization facilities should be presented to the user. 2. An + object may legitimately be finalized while one of its methods are + still running. This should and can be addressed by the language + specification and client code. + * .. _BM77: Robert S. Boyer and J. Strother Moore. 1977. "`A Fast String Searching Algorithm `_". *Communications of the ACM* 20(10):762--772. + .. admonition:: Abstract + + An algorithm is presented that searches for the location, "*i*," + of the first occurrence of a character string, "*pat*," in another + string, "*string*." During the search operation, the characters of + *pat* are matched starting with the last character of *pat*. The + information gained by starting the match at the end of the pattern + often allows the algorithm to proceed in large jumps through the + text being searched. Thus the algorithm has the unusual property + that, in most cases, not all of the first *i* characters of + *string* are inspected. The number of characters actually + inspected (on the average) decreases as a function of the length + of *pat*. For a random English pattern of length 5, the algorithm + will typically inspect *i*/4 characters of string before finding a + match at *i*. Furthermore, the algorithm has been implemented so + that (on the average) fewer than *i* + *patlen* machine + instructions are executed. These conclusions are supported with + empirical evidence and a theoretical analysis of the average + behavior of the algorithm. The worst case behavior of the + algorithm is linear in *i* + *patlen*, assuming the availability + of array space for tables linear in *patlen* plus the size of the + alphabet. + * .. _BL72: P. Branquart, J. Lewi. 1972. "A scheme of storage allocation and garbage collection for ALGOL 68". Elsevier/North-Holland. ALGOL 68 Implementation -- Proceedings of the IFIP Working Conference on ALGOL 68 Implementation, July 1970. @@ -781,6 +890,28 @@ Bibliography Richard Brooksby. 2002. "`The Memory Pool System: Thirty person-years of memory management development goes Open Source `_". ISMM'02. + .. admonition:: Abstract + + The Memory Pool System (MPS) is a very general, adaptable, + flexible, reliable, and efficient memory management system. It + permits the flexible combination of memory management techniques, + supporting manual and automatic memory management, in-line + allocation, finalization, weakness, and multiple simultaneous + co-operating incremental generational garbage collections. It also + includes a library of memory pool classes implementing specialized + memory management policies. + + Between 1994 and 2001, Harlequin (now part of Global Graphics) + invested about thirty person-years of effort developing the MPS. + The system contained many innovative techniques and abstractions + which were kept secret. In 1997 Richard Brooksby, the manager and + chief architect of the project, and Nicholas Barnes, a senior + developer, left Harlequin to form their own consultancy company, + Ravenbrook, and in 2001, Ravenbrook acquired the MPS technology + from Global Graphics. We are happy to announce that we are + publishing the source code and documentation under an open source + licence. This paper gives an overview of the system. + * .. _C1990: International Standard ISO/IEC 9899:1990. "Programming languages — C". @@ -793,7 +924,7 @@ Bibliography Brad Calder, Dirk Grunwald, Benjamin Zorn. 1994. "`Quantifying Behavioral Differences Between C and C++ Programs `_". *Journal of Programming Languages.* 2(4):313--351. - .. abstract: cgz94.html + .. admonition:: Abstract Improving the performance of C programs has been a topic of great interest for many years. Both hardware technology and compiler @@ -816,23 +947,89 @@ Bibliography Dante J. Cannarozzi, Michael P. Plezbert, Ron K. Cytron. 2000. "`Contaminated garbage collection `_". ACM. Proceedings of the ACM SIGPLAN '00 conference on on Programming language design and implementation, pp. 264--273. + .. admonition:: Abstract + + We describe a new method for determining when an objct can be + garbage collected. The method does not require marking live + objects. Instead, each object *X* is *dynamically* associated with + a stack frame *M*, such that *X* is collectable when *M* pops. + Because *X* could have been dead earlier, our method is + conservative. Our results demonstrate that the methos nonetheless + idenitifies a large percentage of collectable objects. The method + has been implemented in Sun's Java™ Virtual Machine interpreter, + and results are presented based on this implementation. + * .. _CW86: Patrick J. Caudill, Allen Wirfs-Brock. 1986. "A Third-Generation Smalltalk-80 Implementation". ACM. SIGPLAN Notices. 21(11), OOPSLA'86 ACM Conference on Object-Oriented Systems, Languages and Applications. + .. admonition:: Abstract + + A new, high performance Smalltalk-80™ implementation is described + which builds directly upon two previous implementation efforts. + This implementation supports a large object space while retaining + compatibility with previous Smalltalk-80™ images. The + implementation utilizes a interpreter which incorporates a + generation based garbage collector and which does not have an + object table. This paper describes the design decisions which lead + to this implementation and reports preliminary performance + results. + * .. _CHENEY70: - C. J. Cheney. 1970. "A non-recursive list compacting algorithm". CACM. 13-11 pp. 677--678. + C. J. Cheney. 1970. "`A non-recursive list compacting algorithm `_". CACM. 13-11 pp. 677--678. + + .. admonition:: Abstract + + A simple nonrecursive list structure compacting scheme or garbage + collector suitable for both compact and LISP-like list structures + is presented. The algorithm avoids the need for recursion by using + the partial structure as it is built up to keep track of those + lists that have been copied. * .. _CHL98: Perry Cheng, Robert Harper, Peter Lee. 1998. "`Generational stack collection and profile-driven pretenuring `_". ACM. Proceedings of SIGPLAN'98 Conference on Programming Language Design and Implementation, pp. 162--173. + .. admonition:: Abstract + + This paper presents two techniques for improving garbage + collection performance: generational stack collection and + profile-driven pretenuring. The first is applicable to stack-based + implementations of functional languages while the second is useful + for any generational collector. We have implemented both + techniques in a generational collector used by the TIL compiler, + and have observed decreases in garbage collection times of as much + as 70% and 30%, respectively. + + Functional languages encourage the use of recursion which can lead + to a long chain of activation records. When a collection occurs, + these activation records must be scanned for roots. We show that + scanning many activation records can take so long as to become the + dominant cost of garbage collection. However, most deep stacks + unwind very infrequently, so most of the root information obtained + from the stack remains unchanged across successive garbage + collections. *Generational stack collection* greatly reduces the + stack scan cost by reusing information from previous scans. + + Generational techniques have been successful in reducing the cost + of garbage collection. Various complex heap arrangements and + tenuring policies have been proposed to increase the effectiveness + of generational techniques by reducing the cost and frequency of + scanning and copying. In contrast, we show that by using profile + information to make lifetime predictions, *pretenuring* can avoid + copying data altogether. In essence, this technique uses a + refinement of the generational hypothesis (most data die young) + with a locality principle concerning the age of data: most + allocations sites produce data that immediately dies, while a few + allocation sites consistently produce data that survives many + collections. + * .. _CL98: Trishul M. Chilimbi, James R. Larus. 1998. "`Using Generational Garbage Collection To Implement Cache-Conscious Data Placement `_". ACM. ISMM'98 pp. 37--48. - .. abstract: cl98.html + .. admonition:: Abstract Processor and memory technology trends show a continual increase in the cost of accessing main memory. Machine designers have tried @@ -858,7 +1055,7 @@ Bibliography William D Clinger & Lars T Hansen. 1997. "`Generational Garbage Collection and the Radioactive Decay Model `_". ACM. Proceedings of PLDI 1997. - .. abstract: ch97.html + .. admonition:: Abstract If a fixed exponentially decreasing probability distribution function is used to model every object's lifetime, then the age of @@ -882,7 +1079,7 @@ Bibliography Jacques Cohen. 1981. "Garbage collection of linked data structures". Computing Surveys. Vol. 13, no. 3. - .. abstract: cohen81.html + .. admonition:: Abstract A concise and unified view of the numerous existing algorithms for performing garbage collection of linked data structures is @@ -904,7 +1101,7 @@ Bibliography Dominique Colnet, Philippe Coucaud, Olivier Zendra. 1998. "`Compiler Support to Customize the Mark and Sweep Algorithm `_". ACM. ISMM'98 pp. 154--165. - .. abstract: ccz98.html + .. admonition:: Abstract Mark and sweep garbage collectors (GC) are classical but still very efficient automatic memory management systems. Although @@ -930,7 +1127,7 @@ Bibliography Jonathan E. Cook, Alexander L. Wolf, Benjamin Zorn. 1994. "`Partition Selection Policies in Object Database Garbage Collection `_". ACM. SIGMOD. International Conference on the Management of Data (SIGMOD'94), pp. 371--382. - .. abstract: cwz93.html + .. admonition:: Abstract The automatic reclamation of storage for unreferenced objects is very important in object databases. Existing language system @@ -954,11 +1151,31 @@ Bibliography Jonathan E. Cook, Artur Klauser, Alexander L. Wolf, Benjamin Zorn. 1996. "`Semi-automatic, Self-adaptive Control of Garbage Collection Rates in Object Databases `_". ACM, SIGMOD. International Conference on the Management of Data (SIGMOD'96), pp. 377--388. + .. admonition:: Abstract + + A fundamental problem in automating object database storage + reclamation is determining how often to perform garbage + collection. We show that the choice of collection rate can have a + significant impact on application performance and that the "best" + rate depends on the dynamic behavior of the application, tempered + by the particular performance goals of the user. We describe two + semi-automatic, self-adaptive policies for controlling collection + rate that we have developed to address the problem. Using + trace-driven simulations, we evaluate the performance of the + policies on a test database application that demonstrates two + distinct reclustering behaviors. Our results show that the + policies are effective at achieving user-specified levels of I/O + operations and database garbage percentage. We also investigate + the sensitivity of the policies over a range of object + connectivities. The evaluation demonstrates that semi-automatic, + self-adaptive policies are a practical means for flexibly + controlling garbage collection rate. + * .. _CNS92: Eric Cooper, Scott Nettles, Indira Subramanian. 1992. "Improving the Performance of SML Garbage Collection using Application-Specific Virtual Memory Management". ACM Conference on LISP and Functional Programming, pp. 43--52. - .. abstract: cns92.html + .. admonition:: Abstract We improved the performance of garbage collection in the Standard ML of New Jersey system by using the virtual memory facilities provided by @@ -974,19 +1191,19 @@ Bibliography Michael C. Daconta. 1995. *C++ Pointers and Dynamic Memory Management.* Wiley. ISBN 0-471-04998-0. - .. abstract: daconta95.html + .. admonition:: From the back cover - [from the back cover] Using techniques developed in the classroom - at America Online's Programmer's University, Michael Daconta - deftly pilots programmers through the intricacies of the two most - difficult aspects of C++ programming: pointers and dynamic memory - management. Written by a programmer for programmers, this - no-nonsense, nuts-and-bolts guide shows you how to fully exploit - advanced C++ programming features, such as creating class-specific - allocators, understanding references versus pointers, manipulating - multidimensional arrays with pointers, and how pointers and - dynamic memory are the core of object-oriented constructs like - inheritance, name-mangling, and virtual functions. + Using techniques developed in the classroom at America Online's + Programmer's University, Michael Daconta deftly pilots programmers + through the intricacies of the two most difficult aspects of C++ + programming: pointers and dynamic memory management. Written by a + programmer for programmers, this no-nonsense, nuts-and-bolts guide + shows you how to fully exploit advanced C++ programming features, + such as creating class-specific allocators, understanding + references versus pointers, manipulating multidimensional arrays + with pointers, and how pointers and dynamic memory are the core of + object-oriented constructs like inheritance, name-mangling, and + virtual functions. * .. _DAHL63: @@ -994,25 +1211,91 @@ Bibliography * .. _DENNING68: - P. J. Denning. 1968. "Thrashing: Its Causes and Prevention". Proceedings AFIPS,1968 Fall Joint Computer Conference, vol. 33, pp. 915--922. + P. J. Denning. 1968. "`Thrashing: Its Causes and Prevention `_". Proceedings AFIPS,1968 Fall Joint Computer Conference, vol. 33, pp. 915--922. + + .. admonition:: From the introduction + + A particularly troublesome phenomenon, thrashing, may seriously + interfere with the performance of paged memory systems, reducing + computing giants (Multics, IBM System 360, and others not + necessarily excepted) to computing dwarfs. The term thrashing + denotes excessive overhead and severe performance degradation or + collapse caused by too much paging. Thrashing inevitably turns a + shortage of memory space into a surplus of processor time. * .. _DENNING70: P. J. Denning. 1970. "`Virtual Memory `_". ACM. ACM Computing Surveys, vol. 2, no. 3, pp. 153--190, Sept. 1970. + .. admonition:: Abstract + + The need for automatic storage allocation arises from desires for + program modularity, machine independence, and resource sharing. + Virtual memory is an elegant way of achieving these objectives. In + a virtual memory, the addresses a program may use to identify + information are distinguished from the addresses the memory system + uses to identify physical storage sites, and program-generated + addresses are translated automatically to the corresponding + machine addresses. Two principal methods for implementing virtual + memory, segmentation and paging, are compared and contrasted. Many + contemporary implementations have experienced one or more of these + problems: poor utilization of storage, thrashing, and high costs + associated with loading information into memory. These and + subsidiary problems are studied from a theoretic view, and are + shown to be controllable by a proper combination of hardware and + memory management policies. + * .. _DS72: P. J. Denning, S. C. Schwartz. 1972. "`Properties of the Working-set Model `_". CACM. vol. 15, no. 3, pp. 191--198. + .. admonition:: Abstract + + A program's working set *W*\ (*t*, *T*) at time *t* is the set of + distinct pages among the *T* most recently referenced pages. + Relations between the average working-set size, the missing-page + rate, and the interreference-interval distribution may be derived + both from time-average definitions and from ensemble-average + (statistical) definitions. An efficient algorithm for estimating + these quantities is given. The relation to LRU (least recently + used) paging is characterized. The independent-reference model, in + which page references are statistically independent, is used to + assess the effects of interpage dependencies on working-set size + observations. Under general assumptions, working-set size is shown + to be normally distributed. + * .. _DETLEFS92: David L. Detlefs. 1992. "`Garbage collection and runtime typing as a C++ library `_". USENIX C++ Conference. + .. admonition:: From the introduction + + Automatic storage management, or *garbage collection*, is a + feature that can ease program development and enhance program + reliability. Many high-level languages other than C++ provide + garbage collection. This paper proposes the use of "smart pointer" + template classes as an interface for the use of garbage collection + in C++. Template classes and operator overloading are techniques + allowing language extension at the level of user code; I claim + that using these techniques to create smart pointer classes + provdes a syntax for manipulating garbage-collected storage safely + and conveniently. Further, the use of a smart-pointer template + class offers the possibility of implementing the collector at the + user-level, without requiring support from the compiler. If such a + compiler-independent implementation is possible with adequate + performance, then programmers can start to write code using + garbage collection without waiting for language and compiler + modifications. If the use of such a garbage collection interface + becomes widespread, then C++ compilation systems can be built to + specially support tht garbage collection interface, thereby + allowing the use of collection algorithms with enhanced + performance. + * .. _ZORN93: David L. Detlefs, Al Dosser, Benjamin Zorn. 1994. "`Memory Allocation Costs in Large C and C++ Programs `_". Software -- Practice and Experience. 24(6):527--542. - .. abstract: zorn93.html + .. admonition:: Abstract Dynamic storage allocation is an important part of a large class of computer programs written in C and C++. High-performance @@ -1033,15 +1316,44 @@ Bibliography L. Peter Deutsch, Daniel G. Bobrow. 1976. "`An Efficient, Incremental, Automatic Garbage Collector `_". CACM. vol. 19, no. 9, pp. 522--526. + .. admonition:: Abstract + + This paper describes a new way of solving the storage reclamation + problem for a system such as Lisp that allocates storage + automatically from a heap, and does not require the programmer to + give any indication that particular items are no longer useful or + accessible. A reference count scheme for reclaiming + non-self-referential structures, and a linearizing, compacting, + copying scheme to reorganize all storage at the users discretion + are proposed. The algorithms are designed to work well in systems + which use multiple levels of storage, and large virtual address + space. They depend on the fact that most cells are referenced + exactly once, and that reference counts need only be accurate when + storage is about to be reclaimed. A transaction file stores + changes to reference counts, and a multiple reference table stores + the count for items which are referenced more than once. + * .. _DLMSS76: E. W. Dijkstra, Leslie Lamport, A. J. Martin, C. S. Scholten, E. F. M. Steffens. 1976. "`On-the-fly Garbage Collection: An Exercise in Cooperation `_". Springer-Verlag. Lecture Notes in Computer Science, Vol. 46. + .. admonition:: Abstract + + As an example of cooperation between sequential processes with + very little mutual interference despite frequent manipulations of + a large shared data space, a technique is developed which allows + nearly all of the activity needed for garbage detection and + collection to be performed by an additional processor operating + con- currently with the processor devoted to the computation + proper. Exclusion and synchronization constraints have been kept + as weak as could be achieved; the severe complexities engendered + by doing so are illustrated. + * .. _DMH92: Amer Diwan, Richard L. Hudson, J. Eliot B. Moss. 1992. "`Compiler Support for Garbage Collection in a Statically Typed Language `_". ACM. Proceedings of the 5th ACM SIGPLAN conference on Programming language design and implementation, pp. 273--282. - .. abstract: dmh92.html + .. admonition:: Abstract We consider the problem of supporting compacting garbage collection in the presence of modern compiler optimizations. Since @@ -1064,7 +1376,7 @@ Bibliography Amer Diwan, David Tarditi, J. Eliot B. Moss. 1993. "`Memory Subsystem Performance of Programs with Intensive Heap Allocation `_". Carnegie Mellon University. CMU-CS-93-227. - .. abstract: dtm93.html + .. admonition:: Abstract Heap allocation with copying garbage collection is a general storage management technique for modern programming languages. It @@ -1089,7 +1401,7 @@ Bibliography Amer Diwan, David Tarditi, J. Eliot B. Moss. 1994. "`Memory Subsystem Performance of Programs Using Copying Garbage Collection `_". ACM. CMU-CS-93-210, also in POPL '94. - .. abstract: dtm93a.html + .. admonition:: Abstract Heap allocation with copying garbage collection is believed to have poor memory subsystem performance. We conducted a study of @@ -1103,7 +1415,7 @@ Bibliography Damien Doligez & Xavier Leroy. 1993. "`A concurrent, generational garbage collector for a multithreaded implementation of ML `_". ACM. POPL '93, 113--123. - .. abstract: doligez93.html + .. admonition:: Abstract This paper presents the design and implementation of a "quasi real-time" garbage collector for Concurrent Caml Light, an @@ -1117,7 +1429,7 @@ Bibliography Damien Doligez & Georges Gonthier. 1994. "`Portable, unobtrusive garbage collection for multiprocessor systems `_". ACM. POPL '94, 70--83. - .. abstract: doligez94.html + .. admonition:: Abstract We describe and prove the correctness of a new concurrent mark-and-sweep garbage collection algorithm. This algorithm @@ -1138,7 +1450,7 @@ Bibliography R. Kent Dybvig, Carl Bruggeman, David Eby. 1993. "`Guardians in a Generation-Based Garbage Collector `_". SIGPLAN. Proceedings of the ACM SIGPLAN '93 Conference on Programming Language Design and Implementation, June 1993. - .. abstract: dbe93.html + .. admonition:: Abstract This paper describes a new language feature that allows dynamically allocated objects to be saved from deallocation by an @@ -1155,15 +1467,49 @@ Bibliography Daniel R. Edelson. 1992. "`Smart pointers: They're smart, but they're not pointers `_". USENIX C++ Conference. + .. admonition:: From the introduction + + This paper shows hhow the behaviour of smart pointers diverges + from that of pointers in certain common C++ constructs. Given + this, we conclude that the C++ programming language does not + support seamless smart pointers: smart pointers cannot + transparently replace raw pointers in all ways except declaration + syntax. We show that this conclusion also applies to *accessors*. + * .. _EDELSON92: - Daniel R. Edelson. 1992. "Comparing Two Garbage Collectors for C++". University of California at Santa Cruz. Technical Report UCSC-CRL-93-20. + Daniel R. Edelson. 1992. "`Comparing Two Garbage Collectors for C++ `_". University of California at Santa Cruz. Technical Report UCSC-CRL-93-20. + + .. admonition:: Abstract + + Our research is concerned with compiler- independent, tag-free + garbage collection for the C++ programming language. This paper + presents a mark-and-sweep collector, and explains how it + ameliorates shortcomings of a previous copy collector. The new + collector, like the old, uses C++'s facilities for creating + abstract data types to define a *tracked reference* type, called + *roots*, at the level of the application program. A programmer + wishing to utilize the garbage collection service uses these roots + in place of normal, raw pointers. We present a detailed study of + the cost of using roots, as compared to both normal pointers and + reference counted pointers, in terms of instruction counts. We + examine the efficiency of a small C++ application using roots, + reference counting, manual reclamation, and conservative + collection. Coding the application to use garbage collection, and + analyzing the resulting efficiency, helped us identify a number of + memory leaks and inefficiencies in the original, manually + reclaimed version. We find that for this program, garbage + collection using roots is much more efficient than reference + counting, though less efficient than manual reclamation. It is + hard to directly compare our collector to the conservative + collector because of the differing efficiencies of their + respective memory allocators. * .. _EDWARDS: Daniel J. Edwards. n.d. "`Lisp II Garbage Collector `_". MIT. AI Memo 19 (AIM-19). - .. abstract: edwards.html + .. admonition:: Our summary (This short memo doesn't have an abstract. Basically, it describes the plan for the LISP II Relocating Garbage Collector. It has four @@ -1179,7 +1525,7 @@ Bibliography John R. Ellis, David L. Detlefs. 1993. "`Safe, Efficient Garbage Collection for C++ `_". Xerox PARC. - .. abstract: ellis93.html + .. admonition:: Abstract We propose adding safe, efficient garbage collection to C++, eliminating the possibility of storage-management bugs and making @@ -1192,7 +1538,7 @@ Bibliography Paulo Ferreira. 1996. "`Larchant: garbage collection in a cached distributed shared store with persistence by reachability `_". Université Paris VI. Thése de doctorat. - .. abstract: ferreira96.html + .. admonition:: Abstract The model of Larchant is that of a *Shared Address Space* (spanning every site in a network including secondary storage) @@ -1229,15 +1575,53 @@ Bibliography Paulo Ferreira & Marc Shapiro. 1998. "`Modelling a Distributed Cached Store for Garbage Collection `_". Springer-Verlag. Proceedings of 12th European Conference on Object-Oriented Programming, ECOOP98, LNCS 1445. + .. admonition:: Abstract + + Caching and persistence support efficient, convenient and + transparent distributed data sharing. The most natural model of + persistence is persistence by reachability, managed automatically + by a garbage collector (GC). We propose a very general model of + such a system (based on distributed shared memory) and a scalable, + asynchronous distributed GC algorithm. Within this model, we show + sufficient and widely applicable correctness conditions for the + interactions between applications, store, memory, coherence, and + GC. + + The GC runs as a set of processes (local to each participating + machine) communicating by asynchronous messages. Collection does + not interfere with applications by setting locks, polluting + caches, or causing I/O; this requirement raised some novel and + interesting challenges which we address in this article. The + algorithm is safe and live; it is not complete, i.e. it collects + some distributed cycles of garbage but not necessarily all. + * .. _FW76: Daniel P Friedman, David S. Wise. 1976. "`Garbage collecting a heap which includes a scatter table `_". *Information Processing Letters.* 5, 6 (December 1976): 161--164. + .. admonition:: Abstract + + A new algorithm is introduced for garbage collecting a heap which + contains shared data structures accessed from a scatter table. The + scheme provides for the purging of useless entries from the + scatter table with no traverslas beyond the two required by + classic collection schemes. For languages which use scatter tables + to sustain unique existence of complex structures, like natural + variables of SNOBOL, it indirectly allows liberal use of a single + scatter table by ensuring efficient deletion of useless entries. + Since the scatter table is completely restructured during the + course of execution, the hashing scheme itself is easily altered + during garbage collection whenever skewed loading of the scatter + table warrants abandonment of the old hashing. This procedure is + applicable to the maintenance of dynamic structures such as those + in information retrieval schemes or in languages like LISP and + SNOBOL. + * .. _FW77: Daniel P Friedman, David S. Wise. 1977. "`The One Bit Reference Count `_". *BIT.* (17)3: 351--359. - .. abstract: fw77.html + .. admonition:: Abstract Deutsch and Bobrow propose a storage reclamation scheme for a heap which is a hybrid of garbage collection and reference counting. @@ -1258,11 +1642,23 @@ Bibliography Daniel P Friedman, David S. Wise. 1979. "`Reference counting can manage the circular environments of mutual recursion `_". *Information Processing Letters.* 8, 1 (January 1979): 41--45. + .. admonition:: From the introduction + + In this note we advance reference counting as a storage management + technique viable for implementing recursive languages like ISWIM + or pure LISP with the ``labels`` construct for implementing mutual + recursion from SCHEME. ``Labels`` is derived from ``letrec`` and + displaces the ``label`` operator, a version of the paradoxical + Y-combinator. The key observation is that the requisite circular + structure (which ordinarily cripples reference counts) occurs only + within the language--rather than the user--structure, and that the + references into this structure are well-controlled. + * .. _GZH93: Dirk Grunwald, Benjamin Zorn, R. Henderson. 1993. "`Improving the Cache Locality of Memory Allocation `_". SIGPLAN. SIGPLAN '93, Conference on PLDI, June 1993, Albuquerque, New Mexico. - .. abstract: gzh93.html + .. admonition:: Abstract The allocation and disposal of memory is a ubiquitous operation in most programs. Rarely do programmers concern themselves with @@ -1289,7 +1685,7 @@ Bibliography Dirk Grunwald & Benjamin Zorn. 1993. "`CustoMalloc: Efficient Synthesized Memory Allocators `_". Software -- Practice and Experience. 23(8):851--869. - .. abstract: grun92.html + .. admonition:: Abstract The allocation and disposal of memory is a ubiquitous operation in most programs. Rarely do programmers concern themselves with @@ -1312,7 +1708,7 @@ Bibliography David Gudeman. 1993. "`Representing Type Information in Dynamically Typed Languages `_". University of Arizona at Tucson. Technical Report TR 93-27. - .. abstract: gudeman93.html + .. admonition:: Abstract This report is a discussion of various techniques for representing type information in dynamically typed languages, as implemented on @@ -1333,7 +1729,7 @@ Bibliography Timothy Harris. 1999. "`Early storage reclamation in a tracing garbage collector `_". ACM. ACM SIG-PLAN Notices 34:4, pp. 46--53. - .. abstract: harris99.html + .. admonition:: Abstract This article presents a technique for allowing the early recovery of storage space occupied by garbage data. The idea is similar to @@ -1347,7 +1743,7 @@ Bibliography Roger Henriksson. 1994. "Scheduling Real Time Garbage Collection". Department of Computer Science at Lund University. LU-CS-TR:94-129. - .. abstract: henrik94.html + .. admonition:: Abstract This paper presents a new model for scheduling the work of an incremental garbage collector in a system with hard real time @@ -1366,7 +1762,7 @@ Bibliography Roger Henriksson. 1996. "`Adaptive Scheduling of Incremental Copying Garbage Collection for Interactive Applications `_". NWPER96. - .. abstract: henrik96.html + .. admonition:: Abstract Incremental algorithms are often used to interleave the work of a garbage collector with the execution of an application program, @@ -1382,7 +1778,7 @@ Bibliography Roger Henriksson. 1998. "`Scheduling Garbage Collection in Embedded Systems `_". Department of Computer Science at Lund University. Ph.D. thesis. - .. abstract: henriksson98.html + .. admonition:: Abstract The complexity of systems for automatic control and other safety-critical applications grows rapidly. Computer software @@ -1431,23 +1827,78 @@ Bibliography Antony L. Hosking. 1991. "`Main memory management for persistence `_". ACM. Proceedings of the ACM OOPSLA'91 Workshop on Garbage Collection. + .. admonition:: Abstract + + Reachability-based persistence imposes new requirements for main + memory management in general, and garbage collection in + particular. After a brief introduction to the characteristics and + requirements of reachability-based persistence, we present the + design of a run-time storage manager for Persistent Smalltalk and + Persistent Modula-3, which allows the reclamation of storage from + both temporary objects and buffered persistent objects. + * .. _HMS92: Antony L. Hosking, J. Eliot B. Moss, Darko Stefanovic. 1992. "`A comparative performance evaluation of write barrier implementations `_". ACM. OOPSLA'92 Conference Proceedings, ACM SIGPLAN Notices 27(10), pp 92--109. + .. admonition:: Abstract + + Generational garbage collectors are able to achieve very small + pause times by concentrating on the youngest (most recently + allocated) objects when collecting, since objects have been + observed to die young in many systems. Generational collectors + must keep track of all pointers from older to younger generations, + by “monitoring” all stores into the heap. This *write barrier* has + been implemented in a number of ways, varying essentially in the + granularity of the information observed and stored. Here we + examine a range of write barrier implementations and evaluate + their relative performance within a generation scavenging garbage + collector for Smalltalk. + * .. _HH93: Antony L. Hosking, Richard L. Hudson. 1993. "`Remembered sets can also play cards `_". ACM. Proceedings of the ACM OOPSLA'93 Workshop on Memory Management and Garbage Collection. + .. admonition:: Abstract + + Remembered sets and dirty bits have been proposed as alternative + implementations of the write barrier for garbage collection. There + are advantages to both approaches. Dirty bits can be efficiently + maintained with minimal, bounded overhead per store operation, + while remembered sets concisely, and accurately record the + necessary information. Here we present evidence to show that + hybrids can combine the virtues of both schemes and offer + competitive performance. Moreover, we argue that a hybrid can + better avoid the devils that are the downfall of the separate + alternatives. + * .. _HM93: Antony L. Hosking, J. Eliot B. Moss. 1993. "`Protection traps and alternatives for memory management of an object-oriented language `_". ACM. Proceedings of the Fourteenth ACM Symposium on Operating Systems Principles, ACM Operating Systems Review 27(5), pp 106--119. + .. admonition:: Abstract + + Many operating systems allow user programs to specify the + protection level (inaccessible, read-only, read-write) of pages in + their virtual memory address space, and to handle any protection + violations that may occur. Such page-protection techniques have + been exploited by several user-level algorithms for applications + including generational garbage collection and persistent stores. + Unfortunately, modern hardware has made efficient handling of page + protection faults more difficult. Moreover, page-sized granularity + may not match the natural granularity of a given application. In + light of these problems, we reevaluate the usefulness of + page-protection primitives in such applications, by comparing the + performance of implementations that make use of the primitives + with others that do not. Our results show that for certain + applications software solutions outperform solutions that rely on + page-protection or other related virtual memory primitives. + * .. _HMDW91: Richard L. Hudson, J. Eliot B. Moss, Amer Diwan, Christopher F. Weight. 1991. "`A Language-Independent Garbage Collector Toolkit `_". University of Massachusetts at Amherst. COINS Technical Report 91--47. - .. abstract: hmdw91.html + .. admonition:: Abstract We describe a memory management toolkit for language implementors. It offers efficient and flexible generation scavenging garbage @@ -1465,7 +1916,7 @@ Bibliography Richard L. Hudson, J. Eliot B. Moss. 1992. "`Incremental Collection of Mature Objects `_". Springer-Verlag. LNCS #637 International Workshop on Memory Management, St. Malo, France, Sept. 1992, pp. 388--403. - .. abstract: hm92.html + .. admonition:: Abstract We present a garbage collection algorithm that extends generational scavenging to collect large older generations (mature @@ -1481,7 +1932,7 @@ Bibliography Richard L. Hudson, Ron Morrison, J. Eliot B. Moss, David S. Munro. 1997. "`Garbage Collecting the World: One Car at a Time `_". ACM. Proc. OOPSLA 97, pp. 162--175. - .. abstract: hmmm97.html + .. admonition:: Abstract A new garbage collection algorithm for distributed object systems, called DMOS (Distributed Mature Object Space), is presented. It is @@ -1493,15 +1944,11 @@ Bibliography incrementality, and scalability. Furthermore, the DMOS collector is non-blocking and does not use global tracing. -* .. _ISO90: - - "International Standard ISO/IEC 9899:1990 Programming languages — C". - * .. _JOHNSTONE97: Mark S. Johnstone. 1997. "`Non-Compacting Memory Allocation and Real-Time Garbage Collection `_". University of Texas at Austin. - .. abstract: johnstone97.html + .. admonition:: Abstract Dynamic memory use has been widely recognized to have profound effects on program performance, and has been the topic of many @@ -1548,7 +1995,7 @@ Bibliography Mark S. Johnstone, Paul R. Wilson. 1998. "`The Memory Fragmentation Problem: Solved? `_". ACM. ISMM'98 pp. 26--36. - .. abstract: jw98.html + .. admonition:: Abstract We show that for 8 real and varied C and C++ programs, several conventional dynamic storage allocators provide near-zero @@ -1569,11 +2016,26 @@ Bibliography Richard E. Jones. 1992. "`Tail recursion without space leaks `_". *Journal of Functional Programming.* 2(1):73--79. + .. admonition:: Abstract + + The G-machine is a compiled graph reduction machine for lazy + functional languages. The G-machine compiler contains many + optimisations to improve performance. One set of such + optimisations is designed to improve the performance of tail + recursive functions. Unfortunately the abstract machine is subject + to a space leak--objects are unnecessarily preserved by the + garbage collector. + + This paper analyses why a particular form of space leak occurs in + the G-machine, and presents some ideas for fixing this problem. + This phenomena in other abstract machines is also examined + briefly. + * .. _JL92: Richard E. Jones, Rafael Lins. 1992. "`Cyclic weighted reference counting without delay `_". Computing Laboratory, The University of Kent at Canterbury. Technical Report 28-92. - .. abstract: jl92.html + .. admonition:: Abstract Weighted Reference Counting is a low-communication distributed storage reclamation scheme for loosely-coupled multiprocessors. @@ -1590,23 +2052,22 @@ Bibliography Richard E. Jones, Rafael Lins. 1996. "`Garbage Collection: Algorithms for Automatic Dynamic Memory Management `_". Wiley. ISBN 0-471-94148-4. - .. abstract: jones96.html + .. admonition:: From the back cover - [from the back cover] The memory storage requirements of complex - programs are extremely difficult to manage correctly by hand. A - single error may lead to indeterminate and inexplicable program - crashes. Worse still, failures are often unrepeatable and may - surface only long after the program has been delivered to the - customer. The eradication of memory errors typically consumes a - substantial amount of development time. And yet the answer is - relatively easy -- garbage collection; removing the clutter of - memory management from module interfaces, which then frees the - programmer to concentrate on the problem at hand rather than - low-level book-keeping details. For this reason, most modern - object-oriented languages such as Smalltalk, Eiffel, Java and - Dylan, are supported by garbage collection. Garbage collecting - libraries are even available for such uncooperative languages as C - and C++. + The memory storage requirements of complex programs are extremely + difficult to manage correctly by hand. A single error may lead to + indeterminate and inexplicable program crashes. Worse still, + failures are often unrepeatable and may surface only long after + the program has been delivered to the customer. The eradication of + memory errors typically consumes a substantial amount of + development time. And yet the answer is relatively easy -- garbage + collection; removing the clutter of memory management from module + interfaces, which then frees the programmer to concentrate on the + problem at hand rather than low-level book-keeping details. For + this reason, most modern object-oriented languages such as + Smalltalk, Eiffel, Java and Dylan, are supported by garbage + collection. Garbage collecting libraries are even available for + such uncooperative languages as C and C++. This book considers how dynamic memory can be recycled automatically to guarantee error-free memory management. There is @@ -1631,20 +2092,19 @@ Bibliography Richard E. Jones. 1998. "`ISMM'98 International Symposium on Memory Management `_". ACM. ISBN 1-58113-114-3. - .. abstract: acm98.html + .. admonition:: From the Preface - (From the preface:) The International Symposium on Memory - Management is a forum for research in several related areas of - memory management, especially garbage collectors and dynamic - storage allocators. [...] The nineteen papers selected for - publication in this volume cover a remarkably broad range of - memory management topics from explicit malloc-style allocation to - automatic memory management, from cache-conscious data layout to - efficient management of distributed references, from conservative - to type-accurate garbage collection, for applications ranging from - user application to long-running servers, supporting languages as - different as C, C++, Modula-3, Java, Eiffel, Erlang, Scheme, ML, - Haskell and Prolog. + The International Symposium on Memory Management is a forum for + research in several related areas of memory management, especially + garbage collectors and dynamic storage allocators. [...] The + nineteen papers selected for publication in this volume cover a + remarkably broad range of memory management topics from explicit + malloc-style allocation to automatic memory management, from + cache-conscious data layout to efficient management of distributed + references, from conservative to type-accurate garbage collection, + for applications ranging from user application to long-running + servers, supporting languages as different as C, C++, Modula-3, + Java, Eiffel, Erlang, Scheme, ML, Haskell and Prolog. * .. _JONES12: @@ -1654,6 +2114,32 @@ Bibliography Ian Joyner. 1996. "`C++??: A Critique of C++ `_.". + .. admonition:: Abstract + + The C++?? Critique is an analysis of some of the flaws of C++. It + is by no means exhaustive, nor does it attempt to document every + little niggle with C++, rather concentrating on main themes. The + critique uses Java and Eiffel as comparisons to C++ to give a more + concrete feel to the criticisms, viewing conceptual differences + rather than syntactic ones as being more important. Some C++ + authors realising there are glaring deficiencies in C++ have + chosen to defend C++ by also being critical within their own work. + Most notable are Bjarne Stroustup's "Design and Evolution of C++," + and Scott Meyers' "Effective" and "More Effective C++." These warn + of many traps and pitfalls, but reach the curious conclusion that + since "good" C++ programmers are aware of these problems and know + how to avoid them, C++ is alright. + + The C++ critique makes many of the same criticisms, but comes to + the different conclusion that these pitfalls are not acceptable, + and should not be in a language used for modern large scale + software engineering. Clean design is more important than after + the fact warnings, and it is inconceivable that purchasers of end + user software would tolerate this tactic on the part of vendors. + The critique also takes a look at C, and concludes that many of + the features of C should be left out of modern languages, and that + C is a flawed base for a language. + * .. _KANEFSKY89: Bob Kanefsky. 1989. "`Recursive Memory Allocation `_". Bob Kanefsky. Songworm 3, p.?. @@ -1662,7 +2148,7 @@ Bibliography Jin-Soo Kim, Xiaohan Qin, Yarsun Hsu. 1998. "`Memory Characterization of a Parallel Data Mining Workload `_". IEEE. Proc. Workload Characterization: Methodology and Case Studies, pp. . - .. abstract: kqh98.html + .. admonition:: Abstract This paper studies a representative of an important class of emerging applications, a parallel data mining workload. The @@ -1691,11 +2177,34 @@ Bibliography Jin-Soo Kim & Yarsun Hsu. 2000. "Memory system behavior of Java programs: methodology and analysis". ACM. Proc. International conference on measurements and modeling of computer systems, pp. 264--274. + .. admonition:: Abstract + + This paper studies the memory system behavior of Java programs by + analyzing memory reference traces of several SPECjvm98 + applications running with a Just-In-Time (JIT) compiler. Trace + information is collected by an exception-based tracing tool called + JTRACE, without any instrumentation to the Java programs or the + JIT compiler.First, we find that the overall cache miss ratio is + increased due to garbage collection, which suffers from higher + cache misses compared to the application. We also note that going + beyond 2-way cache associativity improves the cache miss ratio + marginally. Second, we observe that Java programs generate a + substantial amount of short-lived objects. However, the size of + frequently-referenced long-lived objects is more important to the + cache performance, because it tends to determine the application's + working set size. Finally, we note that the default heap + configuration which starts from a small initial heap size is very + inefficient since it invokes a garbage collector frequently. + Although the direct costs of garbage collection decrease as we + increase the available heap size, there exists an optimal heap + size which minimizes the total execution time due to the + interaction with the virtual memory performance. + * .. _KOLODNER92: Elliot K. Kolodner. 1992. "Atomic Incremental Garbage Collection and Recovery for a Large Stable Heap". Laboratory for Computer Science at MIT. MIT-LCS-TR-534. - .. abstract: kolodner92.html + .. admonition:: Abstract A stable heap is a storage that is managed automatically using garbage collection, manipulated using atomic transactions, and @@ -1723,7 +2232,7 @@ Bibliography Per-Åke Larson & Murali Krishnan. 1998. "`Memory Allocation for Long-Running Server Applications `_". ACM. ISMM'98 pp. 176--185. - .. abstract: lk98.html + .. admonition:: Abstract Prior work on dynamic memory allocation has largely neglected long-running server applications, for example, web servers and @@ -1748,46 +2257,69 @@ Bibliography Henry Lieberman & Carl Hewitt. 1983. "`A real-time garbage collector based on the lifetimes of objects `_". ACM. 26(6):419--429. + .. admonition:: Abstract + + In previous heap storage systems, the cost of creating objects and + garbage collection is independent of the lifetime of the object. + Since objects with short lifetimes account for a large portion of + storage use, it is worth optimizing a garbage collector to reclaim + storage for these objects more quickly. The garbage collector + should spend proportionately less effort reclaiming objects with + longer lifetimes. We present a garbage collection algorithm that + (1) makes storage for short-lived objects cheaper than storage for + long-lived objects, (2) that operates in real-time--object + creation and access times are bounded, (3) increases locality of + reference, for better virtual memory performance, (4) works well + with multiple processors and a large address space. + * .. _MM59: - J. McCarthy, M. L. Minsky. 1959. "Artificial Intelligence, Quarterly Progress Report no. 53". Research Laboratory of Electronics at MIT. + J. McCarthy, M. L. Minsky. 1959. "`Artificial Intelligence, Quarterly Progress Report no. 53 `_". Research Laboratory of Electronics at MIT. * .. _MCCARTHY60: J. McCarthy. 1960. "`Recursive Functions of Symbolic Expressions and Their Computation by Machine `_". CACM. - .. abstract: mccarthy60.html + .. admonition:: Abstract - A programming system called LISP (for LISt Processor) has been - developed for the IBM 704 computer by the Artificial Intelligence - group at M.I.T. The system was designed to facilitate experiments - with a proposed system called the Advice Taker, whereby a machine - could be instructed to handle declarative as well as imperative - sentences and could exhibit "common sense" in carrying out its - instructions. The original proposal for the Advice Taker was made - in November 1958. The main requirement was a programming system - for manipulating expressions representing formalized declarative - and imperative sentences so that the Advice Taker could make - deductions. + A programming system called LISP (for LISt Processor) has been + developed for the IBM 704 computer by the Artificial Intelligence + group at M.I.T. The system was designed to facilitate experiments + with a proposed system called the Advice Taker, whereby a machine + could be instructed to handle declarative as well as imperative + sentences and could exhibit "common sense" in carrying out its + instructions. The original proposal for the Advice Taker was made + in November 1958. The main requirement was a programming system + for manipulating expressions representing formalized declarative + and imperative sentences so that the Advice Taker could make + deductions. + + In the course of its development the LISP system went through + several stages of simplification and eventually came to be based + on a scheme for representing the partial recursive functions of a + certain class of symbolic expressions. This representation is + independent of the IBM 704 computer, or of any other electronic + computer, and it now seems expedient to expound the system by + starting with the class of expressions called S-expressions and + the functions called S-functions. * .. _MCCARTHY79: - John McCarthy. 1979. "`History of Lisp `_". In *History of programming languages I*, pp. 173–185. ACM. + John McCarthy. 1979. "`History of Lisp `_". In *History of programming languages I*, pp. 173--185. ACM. * .. _PTM98: Veljko Milutinovic, Jelica Protic, Milo Tomasevic. 1997. "`Distributed shared memory: concepts and systems `_". IEEE Computer Society Press. ISBN 0-8186-7737-6. - .. abstract: ptm98.html + .. admonition:: From the publisher's catalog - [introduction from the catalog] Presents a survey of both - distributed shared memory (DSM) efforts and commercial DSM - systems. The book discusses relevant issues that make the concept - of DSM one of the most attractive approaches for building - large-scale, high-performance multiprocessor systems. Its text - provides a general introduction to the DSM field as well as a - broad survey of the basic DSM concepts, mechanisms, design issues, - and systems. + Presents a survey of both distributed shared memory (DSM) efforts + and commercial DSM systems. The book discusses relevant issues + that make the concept of DSM one of the most attractive approaches + for building large-scale, high-performance multiprocessor systems. + Its text provides a general introduction to the DSM field as well + as a broad survey of the basic DSM concepts, mechanisms, design + issues, and systems. Distributed Shared Memory concentrates on basic DSM algorithms, their enhancements, and their performance evaluation. In addition, @@ -1799,12 +2331,45 @@ Bibliography * .. _MINSKY63: - M. L. Minsky. 1963. "A LISP Garbage Collector Algorithm Using Serial Secondary Storage". MIT. Memorandum MAC-M-129, Artificial Intelligence Project, Memo 58 (revised). + M. L. Minsky. 1963. "`A LISP Garbage Collector Algorithm Using Serial Secondary Storage `_". MIT. Memorandum MAC-M-129, Artificial Intelligence Project, Memo 58 (revised). + + .. admonition:: Abstract + + This paper presents an algorithm for reclaiming unused free + storage memory cells is LISP. It depends on availability of a fast + secondary storage device, or a large block of available temporary + storage. For this price, we get 1. Packing of free-storage into a + solidly packed block. 2. Smooth packing of arbitrary linear blocks + and arrays. 3. The collector will handle arbitrarily complex + re-entrant list structure with no introduction of spurious copies. + 4. The algorithm is quite efficient; the marking pass visits words + at most twice and usually once, and the loading pass is linear. + 5. The system is easily modified to allow for increase in size of + already fixed consecutive blocks, provide one can afford to + initiate a collection pass or use a modified array while waiting + for such a pass to occur. * .. _MOON84: David Moon. 1984. "`Garbage Collection in a Large Lisp System `_". ACM. Symposium on Lisp and Functional Programming, August 1984. + .. admonition:: Abstract + + This paper discusses garbage collection techniques used in a + high-performance Lisp implementation with a large virtual memory, + the Symbolics 3600. Particular attention is paid to practical + issues and experience. In a large system problems of scale appear + and the most straightforward garbage-collection techniques do not + work well. Many of these problems involve the interaction of the + garbage collector with demand-paged virtual memory. Some of the + solutions adopted in the 3600 are presented, including incremental + copying garbage collection, approximately depth-first copying, + ephemeral objects, tagged architecture, and hardware assists. We + discuss techniques for improving the efficiency of garbage + collection by recognizing that objects in the Lisp world have a + variety of lifetimes. The importance of designing the architecture + and the hardware to facilitate garbage collection is stressed. + * .. _MOON85: David Moon. 1985. "Architecture of the Symbolics 3600". IEEE. 12th International Symposium on Computer Architecture, pp. 76--83. @@ -1825,11 +2390,30 @@ Bibliography Luc Moreau. 1998. "`Hierarchical Distributed Reference Counting `_". ACM. ISMM'98 pp. 57--67. + .. admonition:: Abstract + + Massively distributed computing is a challenging problem for + garbage collection algorithm designers as it raises the issue of + scalability. The high number of hosts involved in a computation + can require large tables for reference listing, whereas the lack + of information sharing between hosts in a same locality can entail + redundant GC traffic. In this paper, we argue that a conceptual + hierarchical organisation of massive distributed computations can + solve this problem. By conceptual hierarchical organisation, we + mean that processors are still able to communicate in a peer to + peer manner using their usual communication mechanism, but GC + messages will be routed as if processors were organised in + hierarchy. We present an extension of a distributed reference + counting algorithm that uses such a hierarchical organisation. It + allows us to bound table sizes by the number of hosts in a domain, + and it allows us to share GC information between hosts in a same + locality in order to reduce cross-network GC traffic. + * .. _MFH95: Greg Morrisett, Matthias Felleisen, Robert Harper. 1995. "`Abstract Models of Memory Management `_". Carnegie Mellon University. CMU-CS-FOX-95-01. - .. abstract: mfh95.html + .. admonition:: Abstract Most specifications of garbage collectors concentrate on the low-level algorithmic details of how to find and preserve @@ -1864,7 +2448,7 @@ Bibliography David S. Munro, Alfred Brown, Ron Morrison, J. Eliot B. Moss. 1999. "`Incremental Garbage Collection of a Persistent Object Store using PMOS `_". Morgan Kaufmann. in Advances in Persistent Object Systems, pp. 78--91. - .. abstract: mbmm99.html + .. admonition:: Abstract PMOS is an incremental garbage collector designed specifically to reclaim space in a persistent object store. It is complete in that @@ -1889,7 +2473,7 @@ Bibliography Scott Nettles, James O'Toole, David Pierce, Nickolas Haines. 1992. "`Replication-Based Incremental Copying Collection `_". IWMM'92. - .. abstract: noph92.html + .. admonition:: Abstract We introduce a new replication-based copying garbage collection technique. We have implemented one simple variation of this method @@ -1916,7 +2500,7 @@ Bibliography Scott Nettles. 1992. "`A Larch Specification of Copying Garbage Collection `_". Carnegie Mellon University. CMU-CS-92-219. - .. abstract: nettles92.html + .. admonition:: Abstract Garbage collection (GC) is an important part of many language implementations. One of the most important garbage collection @@ -1934,7 +2518,7 @@ Bibliography Scott Nettles & James O'Toole. 1993. "Implementing Orthogonal Persistence: A Simple Optimization Using Replicating Collection". USENIX. IWOOOS'93. - .. abstract: no93a.html + .. admonition:: Abstract Orthogonal persistence provides a safe and convenient model of object persistence. We have implemented a transaction system which @@ -1958,7 +2542,7 @@ Bibliography Scott Nettles & James O'Toole. 1993. "`Real-Time Replication Garbage Collection `_". ACM. PLDI'93. - .. abstract: no93.html + .. admonition:: Abstract We have implemented the first copying garbage collector that permits continuous unimpeded mutator access to the original @@ -1973,7 +2557,7 @@ Bibliography Norman R. Nielsen. 1977. "Dynamic Memory Allocation in Computer Simulation". ACM. CACM 20:11. - .. abstract: nielsen77.html + .. admonition:: Abstract This paper investigates the performance of 35 dynamic memory allocation algorithms when used to service simulation programs as @@ -1992,7 +2576,7 @@ Bibliography James O'Toole. 1990. "Garbage Collecting Locally". - .. abstract: otoole90.html + .. admonition:: Abstract Generational garbage collection is a simple technique for automatic partial memory reclamation. In this paper, I present the @@ -2013,7 +2597,7 @@ Bibliography James O'Toole & Scott Nettles. 1994. "`Concurrent Replicating Garbage Collection `_". ACM. LFP'94. - .. abstract: on94.html + .. admonition:: Abstract We have implemented a concurrent copying garbage collector that uses replicating garbage collection. In our design, the client can @@ -2031,7 +2615,7 @@ Bibliography Simon Peyton Jones, Norman Ramsey, Fermin Reig. 1999. "`C--: a portable assembly language that supports garbage collection `_". Springer-Verlag. International Conference on Principles and Practice of Declarative Programming 1999, LNCS 1702, pp. 1--28. - .. abstract: jrr99.html + .. admonition:: Abstract For a compiler writer, generating good machine code for a variety of platforms is hard work. One might try to reuse a retargetable @@ -2054,7 +2638,7 @@ Bibliography John S. Pieper. 1993. "Compiler Techniques for Managing Data Motion". Carnegie Mellon University. Technical report number CMU-CS-93-217. - .. abstract: pieper93.html + .. admonition:: Abstract Software caching, automatic algorithm blocking, and data overlays are different names for the same problem: compiler management of @@ -2109,7 +2693,7 @@ Bibliography Pekka P. Pirinen. 1998. "Barrier techniques for incremental tracing". ACM. ISMM'98 pp. 20--25. - .. abstract: pirinen98.html + .. admonition:: Abstract This paper presents a classification of barrier techniques for interleaving tracing with mutator operation during an incremental @@ -2126,7 +2710,7 @@ Bibliography Tony Printezis. 1996. "Disk Garbage Collection Strategies for Persistent Java". Proceedings of the First International Workshop on Persistence and Java. - .. abstract: printezis96.html + .. admonition:: Abstract This paper presents work currently in progress on Disk Garbage Collection issues for PJava, an orthogonally persistent version of @@ -2151,7 +2735,7 @@ Bibliography M. B. Reinhold. 1993. "`Cache Performance of Garbage Collected Programming Languages `_". Laboratory for Computer Science at MIT. MIT/LCS/TR-581. - .. abstract: reinhold93.html + .. admonition:: Abstract As processor speeds continue to improve relative to main-memory access times, cache performance is becoming an increasingly @@ -2195,7 +2779,7 @@ Bibliography Gustavo Rodriguez-Rivera & Vince Russo. 1997. "Non-intrusive Cloning Garbage Collection with Stock Operating System Support". Software -- Practice and Experience. 27:8. - .. abstract: rr97.html + .. admonition:: Abstract It is well accepted that automatic garbage collection simplifies programming, promotes modularity, and reduces development effort. @@ -2227,7 +2811,7 @@ Bibliography Niklas Röjemo. 1995. "Highlights from nhc -- a space-efficient Haskell compiler". Chalmers University of Technology. - .. abstract: rojemo95.html + .. admonition:: Abstract Self-compiling implementations of Haskell, i.e., those written in Haskell, have been and, except one, are still space consuming @@ -2261,11 +2845,28 @@ Bibliography Niklas Röjemo. 1995. "Generational garbage collection for lazy functional languages without temporary space leaks". Chalmers University of Technology. + .. admonition:: Abstract + + Generational garbage collection is an established method for + creating efficient garbage collectors. Even a simple + implementation where all nodes that survive one garbage collection + are *tenured*, i.e., moved to an old generation, works well in + strict languages. In lazy languages, however, such an + implementation can create severe *temporary space leaks*. The + temporary space leaks appear in programs that traverse large + lazily built data structures, e.g., a lazy list representing a + large file, where only a small part is needed at any time. A + simple generational garbage collector cannot reclaim the memory, + used by the lazily built list, at minor collections. The reason is + that at least one of the nodes in the list belongs to the old + generation, after the first minor collection, and will hold on to + the rest of the nodes in the list until the next major collection. + * .. _RR96: Niklas Röjemo & Colin Runciman. 1996. "Lag, drag, void and use -- heap profiling and space-efficient compilation revisited". ACM, SIGPLAN. ICFP'96, ACM SIGPLAN Notices 31:6, ISBN 0-89791-770-7, pp. 34--41. - .. abstract: rr96.html + .. admonition:: Abstract The context for this paper is functional computation by graph reduction. Our overall aim is more efficient use of memory. The @@ -2283,7 +2884,7 @@ Bibliography David J. Roth, David S. Wise. 1999. "`One-bit counts between unique and sticky `_". ACM. ISMM'98, pp. 49--56. - .. abstract: rw99.html + .. admonition:: Abstract Stoye's one-bit reference tagging scheme can be extended to local counts of two or more via two strategies. The first, suited to @@ -2303,13 +2904,37 @@ Bibliography * .. _ROVNER85: - Paul Rovner. 1985. "`On Adding Garbage Collection and Runtime Types to a Strongly-Typed, Statically-Checked, Concurrent Language `_". Xerox PARC. TR CSL-84-7. + Paul Rovner. 1985. "`On Adding Garbage Collection and Runtime Types to a Strongly-Typed, Statically-Checked, Concurrent Language `_". Xerox PARC. TR CSL-84-7. + + .. admonition:: Abstract + + Enough is known now about garbage collection, runtime types, + strong-typing, static-checking and concurrency that it is possible + to explore what happens when they are combined in a real + programming system. + + Storage management is one of a few central issues through which + one can get a good view of the design of an entire system. + Tensions between ease of integration and the need for protection; + between generality, simplicity, flexibility, extensibility and + efficiency are all manifest when assumptions and attitudes about + managing storage are studied. And deep understanding follows best + from the analysis of systems that people use to get real work + done. + + This paper is not for those who seek arguments pro or con about + the need for these features in programming systems; such issues + are for other papers. This one assumes these features to be good + and describes how they combine and interact in Cedar, a + programming language and environment designed to help programmers + build moderate-sized experimental systems for moderate numbers of + people to test and use. * .. _RUNCIMAN92: Colin Runciman & David Wakeling. 1992. "`Heap Profiling of Lazy Functional Programs `_". University of York. - .. abstract: runciman92.html + .. admonition:: Abstract We describe the design, implementation, and use of a new kind of profiling tool that yields valuable information about the memory @@ -2327,7 +2952,7 @@ Bibliography Colin Runciman & Niklas Röjemo. 1994. "`New dimensions in heap profiling `_". University of York. - .. abstract: rr94.html + .. admonition:: Abstract First-generation heap profilers for lazy functional languages have proved to be effective tools for locating some kinds of space @@ -2349,11 +2974,45 @@ Bibliography Colin Runciman & Niklas Röjemo. 1996. "Two-pass heap profiling: a matter of life and death". Department of Computer Science, University of York. + .. admonition:: Abstract + + A heap profile is a chart showing the contents of heap memory + throughout a computation. Contents are depicted abstractly by + showing how much space is occupied by memory cells in each of + several classes. A good heap profiler can use a variety of + attributes of memory cells to de-fine a classification. Effective + profiling usually involves a combination of attributes. The ideal + profiler gives full support for combination in two ways. First, a + section of the heap of interest to the programmer can be specified + by constraining the values of any combination of cell attributes. + Secondly, no matter what attributes are used to specify such a + section, a heap profile can be obtained for that section only, and + any other attribute can be used to define the classification. + + Achieving this ideal is not simple For some combinations of + attributes. A heap profile is derived by interpolation of a series + of censuses of heap contents at different stages. The obvious way + to obtain census data is to traverse the live heap at intervals + throughout the computation. This is fine for static attributes + (e.g. What type of value does this memory cell represent?), and + for dynamic attributes that can be determined for each cell by + examining the heap at any given moment (e.g. From which function + closures can this cell be reached?). But some attributes of cells + can only be determined retrospectively by post-mortem inspection + asa cell is overwritten or garbage-collected (e.g. Is this cell + ever used again?). Now we see the problem: if a profiler supports + both live and pose-mortem attributes, how can we implement the + ideal of unrestricted combinations? That is the problem me solve + in this paper. We give techniques for profiling a. heap section + specified in terms of both live and post-mortem attributes. We + show how to generate live-attribute profiles of a section of the + heal, specified using post-mortem attributes, and vice versa. + * .. _SG95: Jacob Seligmann & Steffen Grarup. 1995. "`Incremental Mature Garbage Collection Using the Train Algorithm `_". Springer-Verlag. ECOOP'95, Lecture Notes in Computer Science, Vol. 952, pp. 235--252, ISBN 3-540-60160-0. - .. abstract: sg95.html + .. admonition:: Abstract We present an implementation of the Train Algorithm, an incremental collection scheme for reclamation of mature garbage in @@ -2369,11 +3028,32 @@ Bibliography Manuel Serrano, Hans-J. Boehm. 2000. "`Understanding memory allocation of Scheme programs `_". ACM. Proceedings of International Conference on Functional Programming 2000. + .. admonition:: Abstract + + Memory is the performance bottleneck of modern architectures. + Keeping memory consumption as low as possible enables fast and + unobtrusive applications. But it is not easy to estimate the + memory use of programs implemented in functional languages, due to + both the complex translations of some high level constructs, and + the use of automatic memory managers. To help understand memory + allocation behavior of Scheme programs, we have designed two + complementary tools. The first one reports on frequency of + allocation, heap configurations and on memory reclamation. The + second tracks down memory leaks. We have applied these tools to + our Scheme compiler, the largest Scheme program we have been + developing. This has allowed us to drastically reduce the amount + of memory consumed during its bootstrap process, without requiring + much development time. Development tools will be neglected unless + they are both conveniently accessible and easy to use. In order to + avoid this pitfall, we have carefully designed the user interface + of these two tools. Their integration into a real programming + environment for Scheme is detailed in the paper. + * .. _SHAPIRO94: Marc Shapiro & Paulo Ferreira. 1994. "`Larchant-RDOSS: a distributed shared persistent memory and its garbage collector `_". INRIA. INRIA Rapport de Recherche no. 2399; Cornell Computer Science TR94-1466. - .. abstract: shapiro94.html + .. admonition:: Abstract Larchant-RDOSS is a distributed shared memory that persists on reliable storage across process lifetimes. Memory management is @@ -2403,7 +3083,7 @@ Bibliography Vivek Singhal, Sheetal V. Kakkad, Paul R. Wilson. 1992. "`Texas: An Efficient, Portable Persistent Store `_". University of Texas at Austin. - .. abstract: singhal92.html + .. admonition:: Abstract Texas is a persistent storage system for C++, providing high performance while emphasizing simplicity, modularity and @@ -2446,13 +3126,30 @@ Bibliography P. G. Sobalvarro. 1988. "`A Lifetime-based Garbage Collector for LISP Systems on General-Purpose Computers `_". MIT. AITR-1417. - .. abstract: sobalvarro88.html + .. admonition:: Abstract Garbage collector performance in LISP systems on custom hardware has been substantially improved by the adoption of lifetime-based garbage collection techniques. To date, however, successful lifetime-based garbage collectors have required special-purpose hardware, or at least privileged access to data structures maintained by the virtual memory system. I present here a lifetime-based garbage collector requiring no special-purpose hardware or virtual memory system support, and discuss its performance. * .. _STEELE75: - Guy L. Steele. 1975. "`Multiprocessing Compactifying Garbage Collection `_". CACM. 18:9 pp. 495--508. + Guy L. Steele. 1975. "Multiprocessing Compactifying Garbage Collection". CACM. 18:9 pp. 495--508. + + .. admonition:: Abstract + + Algorithms for a multiprocessing compactifying garbage collector + are presented and discussed. The simple case of two processors, + one performing LISP-like list operations and the other performing + garbage collection continuously, is thoroughly examined. The + necessary capabilities of each processor are defined, as well as + interprocessor communication and interlocks. Complete procedures + for garbage collection and for standard list processing primitives + are presented and thoroughly explained. Particular attention is + given to the problems of marking and relocating list cells while + another processor may be operating on them. The primary aim + throughout is to allow the list processor to run unimpeded while + the other processor reclaims list storage The more complex case + involving several list processors and one or more garbage + collection processors are also briefly discussed. * .. _STEELE76: @@ -2460,21 +3157,68 @@ Bibliography * .. _STEELE77: - Guy L. Steele. 1977. "Data Representation in PDP-10 MACLISP". MIT. AI Memo 421. + Guy L. Steele. 1977. "`Data Representation in PDP-10 MACLISP `_". MIT. AI Memo 420. + + .. admonition:: Abstract + + The internal representations of the various MacLISP data types are + presented and discussed. Certain implementation tradeoffs are + considered. The ultimate decisions on these tradeoffs are + discussed in the light of MacLISP's prime objective of being an + efficient high-level language for the implementation of large + systems such as MACSYMA. The basic strategy of garbage collection + is outlined, with reference to the specific representations + involved. Certain "clever tricks" are explained and justified. The + "address space crunch" is explained and some alternative solutions + explored. * .. _SLC99: - James M. Stichnoth, Guei-Yuan Lueh, Michal Cierniak. 1999. "`Support for Garbage Collection at Every Instruction in a Java Compiler `_". SIGPLAN. Proceedings of the 1999 ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI). SIGPLAN Notices 34(5). pp. 118--127. + James M. Stichnoth, Guei-Yuan Lueh, Michal Cierniak. 1999. "`Support for Garbage Collection at Every Instruction in a Java Compiler `_". SIGPLAN. Proceedings of the 1999 ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI). SIGPLAN Notices 34(5). pp. 118--127. + + .. admonition:: Abstract + + A high-performance implementation of a Java Virtual Machine + requires a compiler to translate Java bytecodes into native + instructions, as well as an advanced garbage collector (e.g., + copying or generational). When the Java heap is exhausted and the + garbage collector executes, the compiler must report to the + garbage collector all live object references contained in physical + registers and stack locations. Typical compilers only allow + certain instructions (e.g., call instructions and backward + branches) to be GC-safe; if GC happens at some other instruction, + the compiler may need to advance execution to the next GC-safe + point. Until now, no one has ever attempted to make every + compiler-generated instruction GC-safe, due to the perception that + recording this information would require too much space. This kind + of support could improve the GC performance in multithreaded + applications. We show how to use simple compression techniques to + reduce the size of the GC map to about 20% of the generated code + size, a result that is competitive with the best previously + published results. In addition, we extend the work of Agesen, + Detlefs, and Moss, regarding the so-called “JSR Problem” (the + single exception to Java’s type safety property), in a way that + eliminates the need for extra runtime overhead in the generated + code. * .. _SCN84: Will R Stoye, T J W Clarke, Arthur C Norman. 1984. "Some Practical Methods for Rapid Combinator Reduction". In LFP 1984, 159--166. + .. admonition:: Abstract + + The SKIM II processor is a microcoded hardware machine for the + rapid evaluation of functional languages. This paper gives details + of some of the more novel methods employed by SKIM II, and + resulting performance measurements. The authors conclude that + combinator reduction can still form the basis for the efficient + implementation of a functional language. + * .. _TD95: David Tarditi & Amer Diwan. 1995. "`Measuring the Cost of Storage Management `_". Carnegie Mellon University. CMU-CS-94-201. - .. abstract: td95.html + .. admonition:: Abstract We study the cost of storage management for garbage-collected programs compiled with the Standard ML of New Jersey compiler. We @@ -2487,7 +3231,7 @@ Bibliography Stephen Thomas, Richard E. Jones. 1994. "Garbage Collection for Shared Environment Closure Reducers". Computing Laboratory, The University of Kent at Canterbury. Technical Report 31-94. - .. abstract: tj94.html + .. admonition:: Abstract Shared environment closure reducers such as Fairbairn and Wray's TIM incur a comparatively low cost when creating a suspension, and @@ -2514,11 +3258,22 @@ Bibliography Stephen Thomas. 1995. "Garbage Collection in Shared-Environment Closure Reducers: Space-Efficient Depth First Copying using a Tailored Approach". *Information Processing Letters.* 56:1, pp. 1--7. + .. admonition:: Abstract + + Implementations of abstract machines such as the OP-TIM and the + PG-TIM need to use a tailored garbage collector which seems to + require an auxiliary stack,with a potential maximum size that is + directly proportional to the amount of live data in the heap. + However, it turns out that it is possible to build a recursive + copying collector that does not require additional space by + reusing already-scavenged space. This paper is a description of + this technique. + * .. _TT97: Mads Tofte & Jean-Pierre Talpin. 1997. "`Region-Based Memory Management `_". Information and Computation 132(2), pp. 109--176. - .. abstract: tt97.html + .. admonition:: Abstract This paper describes a memory management discipline for programs that perform dynamic memory allocation and de-allocation. At @@ -2547,11 +3302,22 @@ Bibliography Dave Ungar. 1984. "`Generation Scavenging: A Non-disruptive High Performance Storage Reclamation Algorithm `_". ACM, SIGSOFT, SIGPLAN. Practical Programming Environments Conference. + .. admonition:: Abstract + + Many interactive computing environments provide automatic storage + reclamation and virtual memory to ease the burden of managing + storage. Unfortunately, many storage reclamation algorithms impede + interaction with distracting pauses. *Generation Scavenging* is a + reclamation algorithm that has no noticeable pauses, eliminates + page faults for transient objects, compacts objects without + resorting to indirection, and reclaims circular structures, in one + third the time of traditional approaches. + * .. _UNGAR88: Dave Ungar & Frank Jackson. 1988. "`Tenuring Policies for Generation-Based Storage Reclamation `_". SIGPLAN. OOPSLA '88 Conference Proceedings, ACM SIGPLAN Notices, Vol. 23, No. 11, pp. 1--17. - .. abstract: ungar88.html + .. admonition:: Abstract One of the most promising automatic storage reclamation techniques, generation-based storage reclamation, suffers poor @@ -2571,7 +3337,7 @@ Bibliography Kiem-Phong Vo. 1996. "Vmalloc: A General and Efficient Memory Allocator". Software -- Practice and Experience. 26(3): 357--374 (1996). - .. abstract: vo96.html + .. admonition:: Abstract On C/Unix systems, the malloc interface is standard for dynamic memory allocation. Despite its popularity, malloc's shortcomings @@ -2598,11 +3364,24 @@ Bibliography Daniel C. Watson, David S. Wise. 1976. "Tuning Garwick's algorithm for repacking sequential storage". *BIT.* 16, 4 (December 1976): 442--450. + .. admonition:: Abstract + + Garwick's algorithm, for repacking LIFO lists stored in a + contiguous block of memory, bases the allocation of remaining + space upon both sharing and previous stack growth. A system + whereby the weight applied to each method can be adjusted + according to the current behaviour of the stacks is discussed. + + We also investigate the problem of determining during memory + repacking that the memory is used to saturation and the driving + program should therefore be aborted. The tuning parameters studied + here seem to offer no new grasp on this problem. + * .. _WLM92: Paul R. Wilson, Michael S. Lam, Thomas G. Moher. 1992. "Caching Considerations for Generational Garbage Collection". ACM. L&FP 92. - .. abstract: wlm92.html + .. admonition:: Abstract GC systems allocate and reuse memory cyclically; this imposes a cyclic pattern on memory accesses that has its own distinctive @@ -2633,7 +3412,7 @@ Bibliography Paul R. Wilson, Sheetal V. Kakkad. 1992. "`Pointer Swizzling at Page Fault Time `_". University of Texas at Austin. - .. abstract: wil92a.html + .. admonition:: Abstract Pointer swizzling at page fault time is a novel address translation mechanism that exploits conventional address @@ -2660,7 +3439,7 @@ Bibliography Paul R. Wilson. 1994. "`Uniprocessor Garbage Collection Techniques `_". University of Texas. - .. abstract: wil94.html + .. admonition:: Abstract We survey basic garbage collection algorithms, and variations such as incremental and generational collection; we then discuss @@ -2676,7 +3455,7 @@ Bibliography Paul R. Wilson, Mark S. Johnstone, Michael Neely, David Boles. 1995. "`Dynamic Storage Allocation: A Survey and Critical Review `_". University of Texas at Austin. - .. abstract: wil95.html + .. admonition:: Abstract Dynamic memory allocation has been a fundamental part of most computer systems since roughly 1960, and memory allocation is @@ -2700,23 +3479,69 @@ Bibliography * .. _WISE78: - David S. Wise. 1978. "`The double buddy system `_". Department of Computer Science at Indiana University. Technical Report 79. + David S. Wise. 1978. "`The double buddy system `_". Department of Computer Science at Indiana University. Technical Report 79. + + .. admonition:: Abstract + + A new buddy system is described in which the region of storage + being managed is partitioned into two sub-regions, each managed by + a fairly standard "binary" buddy system. Like the weighted buddy + systems of Shen and Peterson, the block sizes are of sizes 2\ + :superscript:`n+1` or 3·2\ :superscript:`n`, but unlike theirs + there is no extra overhead for typing information or for buddy + calculation, and an allocation which requires splitting an extant + available block only rarely creates a block smaller than the one + being allocated. Such smaller blocks are carved out only when the + boundary between the two subregions floats; the most interesting + property of this system is that the procedures for allocation and + deallocation are designed to keep blocks immediately adjacent to + the subregion boundary free, so that the boundary may be moved + within a range of unused space without disturbing blocks in use. + This option is attained with a minimum of extra computation beyond + that of a binary buddy system, and provides this scheme with a new + approach to the problem of external fragmentation. * .. _WISE79: - David S. Wise. 1979. "`Morris's garbage compaction algorithm restores reference counts `_". TOPLAS. 1, 1 (July l979): 115--120. + David S. Wise. 1979. "`Morris's garbage compaction algorithm restores reference counts `_". TOPLAS. 1, 1 (July 1979): 115--120. + + .. admonition:: Abstract + + The two-pass compaction algorithm of F.L. Morris, which follows + upon the mark phase in a garbage collector, may be modified to + recover reference counts for a hybrid storage management system. + By counting the executions of two loops in that algorithm where + upward and downward references, respectively, are forwarded to the + relocation address of one node, we can initialize a count of + active references and then update it but once. The reference count + may share space with the mark bit in each node, but it may not + share the additional space required in each pointer by Morris's + algorithm, space which remains unused outside the garbage + collector. * .. _WISE85: David S. Wise. 1985. "`Design for a multiprocessing heap with on-board reference counting `_". Springer-Verlag. In J.-P. Jouannaud (ed.), Functional Programming Languages and Computer Architecture, Lecture Notes in Computer Science 201: 289--304. + .. admonition:: Abstract + + A project to design a pair of memory chips with a modicum of + intelligence is described. Together, the two allow simple + fabrication of a small memory bank, a heap of binary (LISP-like) + nodes that offers the following features: 64-bit nodes; two + pointer fields per node up to 29 bits each; reference counts + implicitly maintained on writes; 2 bits per node for marking + (uncounted) circular references; 4 bits per node for + conditional-store testing at the memory; provision for + processor-driven, recounting garbage collection. + * .. _WISE92: .. _WISE93: David S. Wise. 1993. "`Stop-and-copy and one-bit reference counting `_". *Information Processing Letters.* 46, 5 (July 1993): 243--249. - .. abstract: wise92.html + .. admonition:: Abstract A stop-and-copy garbage collector updates one-bit reference counting with essentially no extra space and minimal memory cycles @@ -2734,15 +3559,50 @@ Bibliography David S. Wise, Joshua Walgenbach. 1996. "`Static and Dynamic Partitioning of Pointers as Links and Threads `_". SIGPLAN. Proc. 1996 ACM SIGPLAN Intl. Conf. on Functional Programming, SIGPLAN Not. 31, 6 (June 1996), pp. 42--49. + .. admonition:: Abstract + + Identifying some pointers as invisible threads, for the purposes + of storage management, is a generalization from several widely + used programming conventions, like threaded trees. The necessary + invariant is that nodes that are accessible (without threads) emit + threads only to other accessible nodes. Dynamic tagging or static + typing of threads ameliorates storage recycling both in functional + and imperative languages. + + We have seen the distinction between threads and links sharpen + both hardware- and software-supported storage management in + SCHEME, and also in C. Certainly, therefore, implementations of + languages that already have abstract management and concrete + typing, should detect and use this as a new static type. + * .. _WHHHO94: David S. Wise, Brian Heck, Caleb Hess, Willie Hunt, Eric Ost. 1997. "`Uniprocessor Performance of a Reference-Counting Hardware Heap `_". *LISP and Symbolic Computation.* 10, 2 (July 1997), pp. 159--181. + .. admonition:: Abstract + + A hardware self-managing heap memory (RCM) for languages like + LISP, SMALLTALK, and JAVA has been designed, built, tested and + benchmarked. On every pointer write from the processor, + reference-counting transactions are performed in real time within + this memory, and garbage cells are reused without processor + cycles. A processor allocates new nodes simply by reading from a + distinguished location in its address space. The memory hardware + also incorporates support for off-line, multiprocessing, + mark-sweep garbage collection. + + Performance statistics are presented from a partial implementation + of SCHEME over five different memory models and two garbage + collection strategies, from main memory (no access to RCM) to a + fully operational RCM installed on an external bus. The + performance of the RCM memory is more than competitive with main + memory. + * .. _WITHINGTON91: P. Tucker Withington. 1991. "`How Real is 'Real-Time' Garbage Collection? `_". ACM. OOPSLA/ECOOP '91 Workshop on Garbage Collection in Object-Oriented Systems. - .. abstract: withington91.html + .. admonition:: Abstract A group at Symbolics is developing a Lisp runtime kernel, derived from its Genera operating system, to support real-time control @@ -2765,7 +3625,7 @@ Bibliography G. May Yip. 1991. "`Incremental, Generational Mostly-Copying Garbage Collection in Uncooperative Environments `_". Digital Equipment Corporation. - .. abstract: yip91.html + .. admonition:: Abstract The thesis of this project is that incremental collection can be done feasibly and efficiently in an architecture and compiler @@ -2793,11 +3653,27 @@ Bibliography Taiichi Yuasa. 1990. "Real-Time Garbage Collection on General-Purpose Machines". Journal of Software and Systems. 11:3 pp. 181--198. + .. admonition:: Abstract + + An algorithm for real-time garbage collection is presented, proved + correct, and evaluated. This algorithm is intended for + list-processing systems on general-purpose machines, i.e., Von + Neumann style serial computers with a single processor. On these + machines, real-time garbage collection inevitably causes some + overhead on the overall execution of the list-processing system, + because some of the primitive list-processing operations must + check the status of garbage collection. By removing such overhead + from frequently used primitives such as pointer references (e.g., + Lisp car and cdr) and stack manipulations, the presented algorithm + reduces the execution overhead to a great extent. Although the + algorithm does not support compaction of the whole data space, it + efficiently supports partial compaction such as array relocation. + * .. _ZORN88: Benjamin Zorn & Paul Hilfinger. 1988. "`A Memory Allocation Profiler for C and Lisp Programs `_". USENIX. Proceedings for the Summer 1988 USENIX Conference, pp. 223--237. - .. abstract: zorn88.html + .. admonition:: Abstract This paper describes inprof, a tool used to study the memory allocation behavior of programs. mprof records the amount of @@ -2815,7 +3691,7 @@ Bibliography Benjamin Zorn. 1989. "`Comparative Performance Evaluation of Garbage Collection Algorithms `_". Computer Science Division (EECS) of University of California at Berkeley. Technical Report UCB/CSD 89/544 and PhD thesis. - .. abstract: zorn89.html + .. admonition:: Abstract This thesis shows that object-level, trace-driven simulation can facilitate evaluation of language runtime systems and reaches new @@ -2855,7 +3731,7 @@ Bibliography Benjamin Zorn. 1990. "Comparing Mark-and-sweep and Stop-and-copy Garbage Collection". ACM. Conference on Lisp and Functional Programming, pp. 87--98. - .. abstract: zorn90b.html + .. admonition:: Abstract Stop-and-copy garbage collection has been preferred to mark-and-sweep collection in the last decade because its @@ -2873,7 +3749,7 @@ Bibliography Benjamin Zorn. 1990. "`Barrier Methods for Garbage Collection `_". University of Colorado at Boulder. Technical Report CU-CS-494-90. - .. abstract: zorn90.html + .. admonition:: Abstract Garbage collection algorithms have been enhanced in recent years with two methods: generation-based collection and Baker @@ -2900,7 +3776,7 @@ Bibliography Benjamin Zorn. 1991. "`The Effect of Garbage Collection on Cache Performance `_". University of Colorado at Boulder. Technical Report CU-CS-528-91. - .. abstract: zorn91.html + .. admonition:: Abstract Cache performance is an important part of total performance in modern computer systems. This paper describes the use of @@ -2926,7 +3802,7 @@ Bibliography Benjamin Zorn & Dirk Grunwald. 1992. "`Empirical Measurements of Six Allocation-intensive C Programs `_". ACM, SIGPLAN. SIGPLAN notices, 27(12):71--80. - .. abstract: zorn92b.html + .. admonition:: Abstract Dynamic memory management is an important part of a large class of computer programs and high-performance algorithms for dynamic @@ -2950,7 +3826,7 @@ Bibliography Benjamin Zorn. 1993. "`The Measured Cost of Conservative Garbage Collection `_". Software -- Practice and Experience. 23(7):733--756. - .. abstract: zorn92.html + .. admonition:: Abstract Because dynamic memory management is an important part of a large class of computer programs, high-performance algorithms for @@ -2979,7 +3855,7 @@ Bibliography Benjamin Zorn & Dirk Grunwald. 1994. "`Evaluating Models of Memory Allocation `_". ACM. Transactions on Modeling and Computer Simulation 4(1):107--131. - .. abstract: zorn92a.html + .. admonition:: Abstract Because dynamic memory management is an important part of a large class of computer programs, high-performance algorithms for diff --git a/mps/manual/source/index.rst b/mps/manual/source/index.rst index 91d27f7a8a8..4edc69bbf60 100644 --- a/mps/manual/source/index.rst +++ b/mps/manual/source/index.rst @@ -1,7 +1,3 @@ -.. Memory Pool System documentation master file, created by - sphinx-quickstart on Tue Oct 9 11:21:17 2012. - - Memory Pool System ################## @@ -15,32 +11,26 @@ Memory Pool System design/old -Memory Management Reference -########################### - -.. toctree:: - :hidden: - - mmref-index - mmref-copyright - -.. toctree:: - :maxdepth: 2 - - mmref/index - mmref/bib - mmref/credit - - Appendices ########## .. toctree:: :maxdepth: 1 + bib glossary/index copyright contact release * :ref:`genindex` + + +.. toctree:: + :hidden: + + mmref/index + mmref-index + mmref/faq + mmref-copyright + mmref/credit diff --git a/mps/manual/source/mmref/index.rst b/mps/manual/source/mmref/index.rst index 6ca51d1fb39..d87db74339d 100644 --- a/mps/manual/source/mmref/index.rst +++ b/mps/manual/source/mmref/index.rst @@ -11,5 +11,3 @@ Introduction to memory management alloc recycle lang - faq - diff --git a/mps/manual/source/topic/interface.rst b/mps/manual/source/topic/interface.rst index a939ddf302b..54637557f60 100644 --- a/mps/manual/source/topic/interface.rst +++ b/mps/manual/source/topic/interface.rst @@ -194,7 +194,7 @@ out parameter, like this:: res = mps_alloc((mps_addr_t *)&fp, pool, sizeof(struct foo)); This is known as :term:`type punning`, and its behaviour is not -defined in ANSI/ISO Standard C. See :ref:`ISO/IEC 9899:1990 ` +defined in ANSI/ISO Standard C. See :ref:`ISO/IEC 9899:1990 ` §6.3.2.3, which defines the conversion of a pointer from one type to another: the behaviour of this cast is not covered by any of the cases in the standard. @@ -209,7 +209,7 @@ Instead, we recommend this approach:: This has defined behaviour because conversion from ``void *`` to any other :term:`object pointer` type is defined by :ref:`ISO/IEC -9899:1990 ` §6.3.2.3.1. +9899:1990 ` §6.3.2.3.1. .. index:: @@ -219,7 +219,7 @@ Macros ------ #. For function-like macros, the MPS follows the same convention as - the Standard C library. To quote :ref:`ISO/IEC 9899:1990 ` + the Standard C library. To quote :ref:`ISO/IEC 9899:1990 ` §7.1.7: Any function declared in a header may additionally be diff --git a/mps/manual/source/topic/plinth.rst b/mps/manual/source/topic/plinth.rst index a7e94d21a0b..daba2ad62de 100644 --- a/mps/manual/source/topic/plinth.rst +++ b/mps/manual/source/topic/plinth.rst @@ -296,7 +296,7 @@ Library module This function is intended to have the same semantics as the :c:func:`fputc` function of the ANSI C Standard (:ref:`ISO/IEC - 9899:1990 ` §7.11.7.3). + 9899:1990 ` §7.11.7.3). .. note:: @@ -314,7 +314,7 @@ Library module This function is intended to have the same semantics as the :c:func:`fputs` function of the ANSI C Standard (:ref:`ISO/IEC - 9899:1990 ` §7.11.7.4). + 9899:1990 ` §7.11.7.4). Return a non-negative integer if successful, or :c:func:`mps_lib_get_EOF` if not. @@ -383,7 +383,7 @@ Library module This function is intended to have the same semantics as the :c:func:`memcmp` function of the ANSI C Standard (:ref:`ISO/IEC - 9899:1990 ` §7.11.4.1). + 9899:1990 ` §7.11.4.1). .. note:: @@ -406,7 +406,7 @@ Library module This function is intended to have the same semantics as the :c:func:`memcpy` function of the ANSI C Standard (:ref:`ISO/IEC - 9899:1990 ` §7.11.2.1). + 9899:1990 ` §7.11.2.1). The MPS never passes overlapping blocks to :c:func:`mps_lib_memcpy`. @@ -432,7 +432,7 @@ Library module This function is intended to have the same semantics as the :c:func:`memset` function of the ANSI C Standard (:ref:`ISO/IEC - 9899:1990 ` §7.11.6.1). + 9899:1990 ` §7.11.6.1). .. note:: From 4feb525191181ba07a32920b1fd891d2fcdfa36c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 24 May 2014 15:48:57 +0100 Subject: [PATCH 235/266] Bibliography was moved to top level. Copied from Perforce Change: 186279 ServerID: perforce.ravenbrook.com --- mps/manual/source/mmref-index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/manual/source/mmref-index.rst b/mps/manual/source/mmref-index.rst index 264fa5c3e4a..c645899bb49 100644 --- a/mps/manual/source/mmref-index.rst +++ b/mps/manual/source/mmref-index.rst @@ -32,7 +32,7 @@ Welcome to the **Memory Management Reference**! This is a resource for programm .. image:: diagrams/copying.svg :target: bib_ - .. _bib: mmref/bib.html#bibliography + .. _bib: bib.html#bibliography .. admonition:: :ref:`mmref-faq` From b2ee9221e88e3895d92fa38597b85990a43b9da0 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 24 May 2014 16:55:02 +0100 Subject: [PATCH 236/266] List all the glossary entries. Copied from Perforce Change: 186282 ServerID: perforce.ravenbrook.com --- mps/manual/source/glossary/index.rst | 587 ++++++++++++++++++ .../source/themes/mmref/static/mmref.css_t | 5 + 2 files changed, 592 insertions(+) diff --git a/mps/manual/source/glossary/index.rst b/mps/manual/source/glossary/index.rst index 91e022df5ad..f3f3ed154c0 100644 --- a/mps/manual/source/glossary/index.rst +++ b/mps/manual/source/glossary/index.rst @@ -32,3 +32,590 @@ Memory Management Glossary v w z + +:term:`absolute address ` +:term:`activation frame ` +:term:`activation record` +:term:`activation stack ` +:term:`active ` +:term:`address` +:term:`address space` +:term:`address space layout randomization` +:term:`address translation cache ` +:term:`address-ordered first fit` +:term:`aging space` +:term:`algebraic data type` +:term:`alignment` +:term:`alive ` +:term:`allocate` +:term:`allocation frame` +:term:`allocation mechanism` +:term:`allocation pattern` +:term:`allocation point` +:term:`allocation point protocol` +:term:`allocation policy` +:term:`allocation strategy` +:term:`allocator` +:term:`ambiguous reference` +:term:`ambiguous root` +:term:`arena` +:term:`arena class` +:term:`ASLR
` +:term:`assertion` +:term:`asynchronous garbage collector` +:term:`ATC ` +:term:`atomic object ` +:term:`automatic memory management` +:term:`automatic storage duration` + +:term:`backing store` +:term:`barrier (1)` +:term:`barrier (2)` +:term:`barrier hit ` +:term:`base pointer` +:term:`best fit` +:term:`BIBOP` +:term:`big bag of pages ` +:term:`binary buddies` +:term:`bit array ` +:term:`bit table ` +:term:`bit vector ` +:term:`bitmap` +:term:`bitmapped fit` +:term:`bitmask` +:term:`bitset ` +:term:`black` +:term:`blacklisting` +:term:`black-listing` +:term:`block` +:term:`bounds error ` +:term:`boxed` +:term:`break-table` +:term:`brk` +:term:`broken heart` +:term:`bucket` +:term:`buddy system` +:term:`buffer` +:term:`bus error` +:term:`byte (1)` +:term:`byte (2)` +:term:`byte (3)` +:term:`byte (4)` + +:term:`C89 ` +:term:`C90` +:term:`C99` +:term:`cache (1)` +:term:`cache (2)` +:term:`cache memory ` +:term:`cache policy` +:term:`caching (3)` +:term:`cactus stack` +:term:`card` +:term:`card marking` +:term:`cell ` +:term:`Cheney collector` +:term:`Cheney scan ` +:term:`clamped state` +:term:`client arena` +:term:`client object` +:term:`client pointer` +:term:`client program ` +:term:`closure` +:term:`coalesce` +:term:`collect` +:term:`collection ` +:term:`collection cycle` +:term:`collector (1) ` +:term:`collector (2)` +:term:`color` +:term:`colour` +:term:`commit limit` +:term:`committed (1) ` +:term:`committed (2)` +:term:`compactifying ` +:term:`compaction` +:term:`composite object` +:term:`comprehensive` +:term:`concurrent garbage collection ` +:term:`condemned set` +:term:`connected` +:term:`cons (1)` +:term:`cons (2) ` +:term:`conservative garbage collection` +:term:`constant root` +:term:`constructor (1)` +:term:`constructor (2)` +:term:`continuation` +:term:`control stack` +:term:`cool` +:term:`copy method` +:term:`copying garbage collection` +:term:`core` +:term:`creation space` +:term:`critical path` +:term:`crossing map` +:term:`cyclic data structure` + +:term:`dangling pointer` +:term:`data stack` +:term:`dead` +:term:`deallocate ` +:term:`debugging pool` +:term:`deferred coalescing` +:term:`deferred reference counting` +:term:`dependent object` +:term:`derived pointer ` +:term:`derived type` +:term:`destructor (1)` +:term:`destructor (2)` +:term:`DGC ` +:term:`direct method` +:term:`dirty bit` +:term:`distributed garbage collection` +:term:`double buddies` +:term:`double free` +:term:`doubleword` +:term:`doubly weak hash table` +:term:`DRAM ` +:term:`dynamic allocation ` +:term:`dynamic extent` +:term:`dynamic memory` +:term:`dynamic RAM ` + +:term:`ecru ` +:term:`edge` +:term:`entry table (1)` +:term:`entry table (2)` +:term:`exact garbage collection` +:term:`exact reference` +:term:`exact root` +:term:`exact segregated fit` +:term:`execution stack ` +:term:`exit table` +:term:`extent ` +:term:`external fragmentation` + +:term:`fencepost` +:term:`fence post` +:term:`fencepost error` +:term:`fence post error` +:term:`Fibonacci buddies` +:term:`FIFO-ordered first fit` +:term:`file mapping ` +:term:`finalization` +:term:`finalized block` +:term:`first fit` +:term:`fix` +:term:`flip` +:term:`floating garbage` +:term:`foreign code` +:term:`format` +:term:`format method` +:term:`formatted object` +:term:`forward method` +:term:`forwarding marker` +:term:`forwarding object` +:term:`forwarding pointer` +:term:`fragmentation` +:term:`frame ` +:term:`free (1)` +:term:`free (2)` +:term:`free (3)` +:term:`free (4) ` +:term:`free block` +:term:`free block chain` +:term:`free list` +:term:`free store ` +:term:`freestore ` +:term:`from space` +:term:`fromspace` +:term:`function pointer` +:term:`function record ` + +:term:`garbage` +:term:`garbage collection` +:term:`garbage collector` +:term:`GB ` +:term:`GC ` +:term:`General Protection Fault` +:term:`generation` +:term:`generation chain` +:term:`generation scavenging ` +:term:`generational garbage collection` +:term:`generational hypothesis` +:term:`gigabyte` +:term:`good fit` +:term:`GPF ` +:term:`grain` +:term:`graph` +:term:`gray` +:term:`grey` +:term:`gray list` +:term:`grey list` + +:term:`handle` +:term:`header ` +:term:`heap` +:term:`heap allocation` +:term:`hit` +:term:`hit rate` +:term:`hot` +:term:`huge page` + +:term:`immediate data` +:term:`immune set` +:term:`immutable` +:term:`immutable object ` +:term:`in-band header` +:term:`in parameter` +:term:`in/out parameter` +:term:`incremental garbage collection` +:term:`incremental update` +:term:`indefinite extent` +:term:`indexed fit` +:term:`indirect method` +:term:`infant mortality ` +:term:`inline allocation (1)` +:term:`inline allocation (2)` +:term:`inter-generational pointer` +:term:`interior pointer` +:term:`internal fragmentation` +:term:`invalid page fault` +:term:`inverted page table` +:term:`inverted page-table` +:term:`is-forwarded method` + +:term:`kB ` +:term:`keyword argument` +:term:`kilobyte` + +:term:`large object area` +:term:`large page ` +:term:`leaf object` +:term:`leak ` +:term:`life ` +:term:`lifetime` +:term:`LIFO-ordered first fit` +:term:`limited-field reference count` +:term:`linear addressing` +:term:`live` +:term:`load` +:term:`locality of reference` +:term:`location ` +:term:`location dependency` +:term:`lock free` +:term:`logical address ` +:term:`longword ` + +:term:`machine word ` +:term:`main memory` +:term:`malloc` +:term:`manual memory management` +:term:`mapped` +:term:`mapping` +:term:`mark-compact` +:term:`mark-sweep` +:term:`mark-and-sweep` +:term:`marking` +:term:`MB ` +:term:`megabyte` +:term:`memoization ` +:term:`memory (1)` +:term:`memory (2)` +:term:`memory (3)
` +:term:`memory (4)` +:term:`memory bandwidth` +:term:`memory cache ` +:term:`memory hierarchy ` +:term:`memory leak` +:term:`memory location` +:term:`memory management` +:term:`Memory Management Unit ` +:term:`memory manager` +:term:`memory mapping` +:term:`memory protection ` +:term:`message` +:term:`message queue` +:term:`message type` +:term:`misaligned ` +:term:`miss` +:term:`miss rate` +:term:`mmap` +:term:`MMU` +:term:`mostly-copying garbage collection` +:term:`mostly-exact garbage collection ` +:term:`mostly-precise garbage collection ` +:term:`moving garbage collector` +:term:`moving memory manager` +:term:`mutable` +:term:`mutator` + +:term:`nailing ` +:term:`natural alignment` +:term:`nepotism` +:term:`next fit` +:term:`new space` +:term:`newspace ` +:term:`node` +:term:`non-moving garbage collector` +:term:`non-moving memory manager` +:term:`nursery generation ` +:term:`nursery space` + +:term:`object` +:term:`object format` +:term:`object pointer` +:term:`off-white` +:term:`old space ` +:term:`oldspace ` +:term:`one-bit reference count` +:term:`opaque type` +:term:`out parameter` +:term:`out-of-band header` +:term:`overcommit` +:term:`overwriting error` + +:term:`padding` +:term:`padding method` +:term:`padding object` +:term:`page` +:term:`page fault` +:term:`page marking` +:term:`page protection ` +:term:`page table` +:term:`paged in` +:term:`paged out` +:term:`paging` +:term:`palimpsest` +:term:`parallel garbage collection` +:term:`parked state` +:term:`perfect fit` +:term:`phantom reachable` +:term:`phantomly reachable` +:term:`phantom reference` +:term:`physical address` +:term:`physical address space` +:term:`physical memory (1)` +:term:`physical memory (2)` +:term:`physical storage ` +:term:`pig in the python` +:term:`pig in the snake ` +:term:`pinning` +:term:`placement policy ` +:term:`platform` +:term:`plinth` +:term:`pointer` +:term:`pool` +:term:`pool class` +:term:`precise garbage collection ` +:term:`precise reference ` +:term:`precise root ` +:term:`premature free` +:term:`premature promotion ` +:term:`premature tenuring` +:term:`primary storage
` +:term:`promotion` +:term:`protectable root` +:term:`protection` +:term:`protection exception ` +:term:`protection fault` +:term:`protection violation ` + +:term:`quadword` + +:term:`RAM` +:term:`random access memory ` +:term:`ramp allocation` +:term:`rank` +:term:`rash` +:term:`raw ` +:term:`reachable` +:term:`read barrier` +:term:`read fault` +:term:`read-only memory ` +:term:`real memory (1)` +:term:`real memory (2) ` +:term:`reclaim` +:term:`recycle` +:term:`reference` +:term:`reference counting` +:term:`reference object` +:term:`region inference` +:term:`register` +:term:`register set partitioning` +:term:`relocation` +:term:`remembered set` +:term:`remote reference` +:term:`replicating garbage collector` +:term:`reserved` +:term:`resident` +:term:`resident set` +:term:`result code` +:term:`resurrection` +:term:`ROM` +:term:`root` +:term:`root description` +:term:`root mode` +:term:`root set` + +:term:`sbrk` +:term:`scalar data type` +:term:`scan` +:term:`scan method` +:term:`scan state` +:term:`scavenging garbage collection ` +:term:`SDRAM` +:term:`segmentation violation` +:term:`segmented addressing` +:term:`segregated allocation cache` +:term:`segregated fit` +:term:`segregated free list` +:term:`segregated free-list` +:term:`semi-conservative garbage collection` +:term:`semi-space` +:term:`semi-space collector ` +:term:`sequential fit` +:term:`sequential store buffer` +:term:`shared memory` +:term:`simple object` +:term:`simple segregated storage` +:term:`size` +:term:`size class` +:term:`skip method` +:term:`smart pointer` +:term:`snap-out` +:term:`snapshot at the beginning` +:term:`soft reference` +:term:`softly reachable` +:term:`space leak ` +:term:`spare commit limit` +:term:`spare committed memory` +:term:`spaghetti stack ` +:term:`splat` +:term:`split` +:term:`SRAM ` +:term:`SSB ` +:term:`stack` +:term:`stack allocation` +:term:`stack frame` +:term:`stack record ` +:term:`static allocation` +:term:`static memory (1)` +:term:`static memory (2)` +:term:`static object` +:term:`static RAM ` +:term:`static storage duration` +:term:`stepper function` +:term:`sticky reference count ` +:term:`stop-and-copy collection` +:term:`storage ` +:term:`storage hierarchy` +:term:`storage level` +:term:`storage management ` +:term:`store (1)` +:term:`store (2) ` +:term:`strict segregated fit` +:term:`strong reference` +:term:`strong root` +:term:`strong tri-color invariant` +:term:`strong tri-colour invariant` +:term:`strong tricolor invariant` +:term:`strong tricolour invariant` +:term:`strongly reachable` +:term:`suballocator` +:term:`subgraph` +:term:`superpage ` +:term:`sure reference ` +:term:`swap space` +:term:`swapped in` +:term:`swapped out` +:term:`swapping` +:term:`sweeping` +:term:`synchronous garbage collector` + +:term:`tabling ` +:term:`tag` +:term:`tagged architecture` +:term:`tagged reference` +:term:`TB (1) ` +:term:`TB (2) ` +:term:`telemetry filter` +:term:`telemetry label` +:term:`telemetry stream` +:term:`tenuring ` +:term:`terabyte` +:term:`termination ` +:term:`thrash` +:term:`thread` +:term:`threatened set ` +:term:`TLB ` +:term:`to space` +:term:`tospace` +:term:`trace` +:term:`tracing garbage collection` +:term:`translation buffer` +:term:`translation lookaside buffer` +:term:`transparent alias` +:term:`transparent type` +:term:`transport` +:term:`transport snap-out ` +:term:`treadmill` +:term:`tri-color invariant` +:term:`tri-colour invariant` +:term:`tricolor invariant` +:term:`tricolour invariant` +:term:`tri-color marking` +:term:`tri-colour marking` +:term:`tricolor marking` +:term:`tricolour marking` +:term:`two-space collector` +:term:`two space collector` +:term:`type-accurate garbage collection ` +:term:`type punning` + +:term:`unaligned` +:term:`unboxed` +:term:`unclamped state` +:term:`undead` +:term:`unmapped` +:term:`unreachable` +:term:`unsure reference ` +:term:`unwrapped` +:term:`use after free ` + +:term:`value object` +:term:`variety` +:term:`vector data type` +:term:`virtual address` +:term:`virtual address space` +:term:`virtual memory` +:term:`virtual memory arena` +:term:`visitor function ` +:term:`VM (1) ` +:term:`VM (2)` + +:term:`weak-key hash table` +:term:`weak-value hash table` +:term:`weak hash table` +:term:`weak reference (1)` +:term:`weak reference (2)` +:term:`weak root` +:term:`weak tri-color invariant` +:term:`weak tri-colour invariant` +:term:`weak tricolor invariant` +:term:`weak tricolour invariant` +:term:`weakly reachable` +:term:`weighted buddies` +:term:`weighted reference counting` +:term:`white` +:term:`word` +:term:`working set` +:term:`worst fit` +:term:`wrapped` +:term:`wrapper` +:term:`write barrier` +:term:`write fault` + +:term:`ZCT ` +:term:`zero count table` diff --git a/mps/manual/source/themes/mmref/static/mmref.css_t b/mps/manual/source/themes/mmref/static/mmref.css_t index c24e7eb67a1..54523e04e54 100644 --- a/mps/manual/source/themes/mmref/static/mmref.css_t +++ b/mps/manual/source/themes/mmref/static/mmref.css_t @@ -134,3 +134,8 @@ div#home h1 + p { margin-top: 0; padding-top: 15px; } + +div#memory-management-glossary em.xref.std-term { + white-space: no-wrap; + margin-right: 1em; +} From 23d389b5c694995322f42b8da3e99e96b89c7060 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 24 May 2014 16:56:14 +0100 Subject: [PATCH 237/266] Correct spelling of "nowrap". Copied from Perforce Change: 186283 ServerID: perforce.ravenbrook.com --- mps/manual/source/themes/mmref/static/mmref.css_t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/manual/source/themes/mmref/static/mmref.css_t b/mps/manual/source/themes/mmref/static/mmref.css_t index 54523e04e54..ceab4faddef 100644 --- a/mps/manual/source/themes/mmref/static/mmref.css_t +++ b/mps/manual/source/themes/mmref/static/mmref.css_t @@ -136,6 +136,6 @@ div#home h1 + p { } div#memory-management-glossary em.xref.std-term { - white-space: no-wrap; + white-space: nowrap; margin-right: 1em; } From 43f92f9864b05b43edd9861c8bd6aa8400ad34e7 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 25 May 2014 16:49:52 +0100 Subject: [PATCH 238/266] Fix typo. Copied from Perforce Change: 186293 ServerID: perforce.ravenbrook.com --- mps/manual/source/bib.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mps/manual/source/bib.rst b/mps/manual/source/bib.rst index 00ef030f527..f32b6d33422 100644 --- a/mps/manual/source/bib.rst +++ b/mps/manual/source/bib.rst @@ -949,7 +949,7 @@ Bibliography .. admonition:: Abstract - We describe a new method for determining when an objct can be + We describe a new method for determining when an object can be garbage collected. The method does not require marking live objects. Instead, each object *X* is *dynamically* associated with a stack frame *M*, such that *X* is collectable when *M* pops. @@ -2155,10 +2155,10 @@ Bibliography application, extracted from the IBM Intelligent Miner, identifies groups of records that are mathematically similar based on a neural network model called self-organizing map. We examine and - compare in details two implementations of the application: (1) - temporal locality or working set sizes; (2) spatial locality and - memory block utilization; (3) communication characteristics and - scalability; and (4) TLB performance. + compare in details two implementations of the application: + (1) temporal locality or working set sizes; (2) spatial locality + and memory block utilization; (3) communication characteristics + and scalability; and (4) TLB performance. First, we find that the working set hierarchy of the application is governed by two parameters, namely the size of an input record From 060394b167b16e000f1ee857c674ee6d4d654ba2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 25 May 2014 16:50:21 +0100 Subject: [PATCH 239/266] Fix typo, clarify cautions. Copied from Perforce Change: 186294 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/finalization.rst | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/mps/manual/source/topic/finalization.rst b/mps/manual/source/topic/finalization.rst index 745feefed16..5b65d9945dd 100644 --- a/mps/manual/source/topic/finalization.rst +++ b/mps/manual/source/topic/finalization.rst @@ -51,7 +51,7 @@ the block was allocated. to do the finalization. In such an implementation, the client program's finalization code may end up running concurrently with other code that accesses the underlying resource, and so access to - the resource need to be guarded with a lock, but then an unlucky + the resource needs to be guarded with a lock, but then an unlucky scheduling of finalization can result in deadlock. See :ref:`Boehm (2002) ` for a detailed discussion of this issue. @@ -170,8 +170,9 @@ Cautions #. The MPS does not finalize objects in the context of :c:func:`mps_arena_destroy` or :c:func:`mps_pool_destroy`. - :c:func:`mps_pool_destroy` should therefore not be invoked on pools - containing objects registered for finalization. + Moreover, if you have pools containing objects registered for + finalization, you must destroy these pools by following the “safe + tear-down” procedure described under :c:func:`mps_pool_destroy`. .. note:: @@ -189,11 +190,6 @@ Cautions .. note:: - You can safely destroy pools containing objects registered for - finalization if you follow the "safe tear-down" procedure - described under :c:func:`mps_pool_destroy`, but the objects do - not get finalized. - The only reliable way to ensure that all finalizable objects are finalized is to maintain a table of :term:`weak references (1)` to all such objects. The weak references don't From 5f848d04048b6c3e21c71abc81f7fffd26004c12 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 25 May 2014 19:26:48 +0100 Subject: [PATCH 240/266] Split land iteration into two functions, one which deletes ranges, the other which does not. Copied from Perforce Change: 186298 ServerID: perforce.ravenbrook.com --- mps/code/cbs.c | 14 +------------- mps/code/freelist.c | 29 +++++++++++++++++++++++++++-- mps/code/land.c | 41 +++++++++++++++++++++++++++++++++++------ mps/code/landtest.c | 4 +--- mps/code/mpm.h | 1 + mps/code/mpmst.h | 1 + mps/code/mpmtypes.h | 4 +++- mps/code/poolmv2.c | 6 ++---- mps/design/cbs.txt | 12 +++++++++--- mps/design/land.txt | 25 +++++++++++++++++++------ 10 files changed, 99 insertions(+), 38 deletions(-) diff --git a/mps/code/cbs.c b/mps/code/cbs.c index c7b4478ce4c..de6c25ff08c 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -705,16 +705,6 @@ static Res cbsZonedSplayNodeDescribe(Tree tree, mps_lib_FILE *stream) /* cbsIterate -- iterate over all blocks in CBS - * - * Applies a visitor to all isolated contiguous ranges in a CBS. - * It receives a pointer, ``Size`` closure pair to pass on to the - * visitor function, and an visitor function to invoke on every range - * in address order. If the visitor returns ``FALSE``, then the iteration - * is terminated. - * - * The visitor function may not modify the CBS during the iteration. - * This is because CBSIterate uses TreeTraverse, which does not permit - * modification, for speed and to avoid perturbing the splay tree balance. * * See . */ @@ -733,15 +723,13 @@ static Bool cbsIterateVisit(Tree tree, void *closureP, Size closureS) CBSBlock cbsBlock; Land land = closure->land; CBS cbs = cbsOfLand(land); - Bool delete = FALSE; Bool cont = TRUE; UNUSED(closureS); cbsBlock = cbsBlockOfTree(tree); RangeInit(&range, CBSBlockBase(cbsBlock), CBSBlockLimit(cbsBlock)); - cont = (*closure->visitor)(&delete, land, &range, closure->closureP, closure->closureS); - AVER(!delete); /* */ + cont = (*closure->visitor)(land, &range, closure->closureP, closure->closureS); if (!cont) return FALSE; METER_ACC(cbs->treeSearch, cbs->treeSize); diff --git a/mps/code/freelist.c b/mps/code/freelist.c index 4040630b1c0..0abf766a9f3 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -440,6 +440,30 @@ static Res freelistDelete(Range rangeReturn, Land land, Range range) static Bool freelistIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) +{ + Freelist fl; + FreelistBlock cur; + + AVERT(Land, land); + fl = freelistOfLand(land); + AVERT(Freelist, fl); + AVER(FUNCHECK(visitor)); + /* closureP and closureS are arbitrary */ + + for (cur = fl->list; cur != freelistEND; cur = FreelistBlockNext(cur)) { + RangeStruct range; + Bool cont; + RangeInit(&range, FreelistBlockBase(cur), FreelistBlockLimit(fl, cur)); + cont = (*visitor)(land, &range, closureP, closureS); + if (!cont) + return FALSE; + } + return TRUE; +} + + +static Bool freelistIterateAndDelete(Land land, LandDeleteVisitor visitor, + void *closureP, Size closureS) { Freelist fl; FreelistBlock prev, cur, next; @@ -448,6 +472,7 @@ static Bool freelistIterate(Land land, LandVisitor visitor, fl = freelistOfLand(land); AVERT(Freelist, fl); AVER(FUNCHECK(visitor)); + /* closureP and closureS are arbitrary */ prev = freelistEND; cur = fl->list; @@ -712,13 +737,12 @@ static Res freelistFindInZones(Range rangeReturn, Range oldRangeReturn, * closureP. */ -static Bool freelistDescribeVisitor(Bool *deleteReturn, Land land, Range range, +static Bool freelistDescribeVisitor(Land land, Range range, void *closureP, Size closureS) { Res res; mps_lib_FILE *stream = closureP; - if (deleteReturn == NULL) return FALSE; if (!TESTT(Land, land)) return FALSE; if (!RangeCheck(range)) return FALSE; if (stream == NULL) return FALSE; @@ -767,6 +791,7 @@ DEFINE_LAND_CLASS(FreelistLandClass, class) class->insert = freelistInsert; class->delete = freelistDelete; class->iterate = freelistIterate; + class->iterateAndDelete = freelistIterateAndDelete; class->findFirst = freelistFindFirst; class->findLast = freelistFindLast; class->findLargest = freelistFindLargest; diff --git a/mps/code/land.c b/mps/code/land.c index c0f5f2c1cbc..b7f4ebf8386 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -28,8 +28,9 @@ Bool FindDeleteCheck(FindDelete findDelete) /* landEnter, landLeave -- Avoid re-entrance * - * .enter-leave: The visitor function passed to LandIterate is not - * allowed to call methods of that land. These functions enforce this. + * .enter-leave: The visitor functions passed to LandIterate and + * LandIterateAndDelete are not allowed to call methods of that land. + * These functions enforce this. * * .enter-leave.simple: Some simple queries are fine to call from * visitor functions. These are marked with the tag of this comment. @@ -247,6 +248,26 @@ Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) } +/* LandIterateAndDelete -- iterate over isolated ranges of addresses + * in land, deleting some of them + * + * See + */ + +Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS) +{ + Bool res; + AVERT(Land, land); + AVER(FUNCHECK(visitor)); + landEnter(land); + + res = (*land->class->iterateAndDelete)(land, visitor, closureP, closureS); + + landLeave(land); + return res; +} + + /* LandFindFirst -- find first range of given size * * See @@ -416,7 +437,7 @@ void LandFlush(Land dest, Land src) AVERT(Land, dest); AVERT(Land, src); - (void)LandIterate(src, landFlushVisitor, dest, 0); + (void)LandIterateAndDelete(src, landFlushVisitor, dest, 0); } @@ -464,12 +485,11 @@ static Size landNoSize(Land land) /* LandSlowSize -- generic size method but slow */ -static Bool landSizeVisitor(Bool *deleteReturn, Land land, Range range, +static Bool landSizeVisitor(Land land, Range range, void *closureP, Size closureS) { Size *size; - AVER(deleteReturn != NULL); AVERT(Land, land); AVERT(Range, range); AVER(closureP != NULL); @@ -477,7 +497,6 @@ static Bool landSizeVisitor(Bool *deleteReturn, Land land, Range range, size = closureP; *size += RangeSize(range); - *deleteReturn = FALSE; return TRUE; } @@ -514,6 +533,15 @@ static Bool landNoIterate(Land land, LandVisitor visitor, void *closureP, Size c return FALSE; } +static Bool landNoIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS) +{ + AVERT(Land, land); + AVER(visitor != NULL); + UNUSED(closureP); + UNUSED(closureS); + return FALSE; +} + static Bool landNoFind(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) { AVER(rangeReturn != NULL); @@ -556,6 +584,7 @@ DEFINE_CLASS(LandClass, class) class->insert = landNoInsert; class->delete = landNoDelete; class->iterate = landNoIterate; + class->iterateAndDelete = landNoIterateAndDelete; class->findFirst = landNoFind; class->findLast = landNoFind; class->findLargest = landNoFind; diff --git a/mps/code/landtest.c b/mps/code/landtest.c index 988b4be9391..195f9758656 100644 --- a/mps/code/landtest.c +++ b/mps/code/landtest.c @@ -75,13 +75,11 @@ static void describe(TestState state) { } -static Bool checkVisitor(Bool *deleteReturn, Land land, Range range, - void *closureP, Size closureS) +static Bool checkVisitor(Land land, Range range, void *closureP, Size closureS) { Addr base, limit; CheckTestClosure cl = closureP; - Insist(deleteReturn != NULL); testlib_unused(land); testlib_unused(closureS); Insist(cl != NULL); diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 0a87b8fc81d..28373eadc69 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -1015,6 +1015,7 @@ 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 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/mpmst.h b/mps/code/mpmst.h index 8ce4d14f01a..86087a31102 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -621,6 +621,7 @@ typedef struct LandClassStruct { LandInsertMethod insert; /* insert a range into the land */ LandDeleteMethod delete; /* delete a range from the land */ LandIterateMethod iterate; /* iterate over ranges in the land */ + LandIterateAndDeleteMethod iterateAndDelete; /* iterate and maybe delete */ LandFindMethod findFirst; /* find first range of given size */ LandFindMethod findLast; /* find last range of given size */ LandFindMethod findLargest; /* find largest range */ diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index d81255c974d..c79c049ca5f 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -271,8 +271,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)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS); +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 (*LandFindMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete); typedef Res (*LandFindInZonesMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high); typedef Res (*LandDescribeMethod)(Land land, mps_lib_FILE *stream); diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index e8b38489253..4f36884ab79 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -1209,12 +1209,11 @@ static Bool MVTReturnSegs(MVT mvt, Range range, Arena arena) * empty. */ -static Bool MVTRefillVisitor(Bool *deleteReturn, Land land, Range range, +static Bool MVTRefillVisitor(Land land, Range range, void *closureP, Size closureS) { MVT mvt; - AVER(deleteReturn != NULL); AVERT(Land, land); mvt = closureP; AVERT(MVT, mvt); @@ -1258,7 +1257,7 @@ typedef struct MVTContigencyClosureStruct Count hardSteps; } MVTContigencyClosureStruct, *MVTContigencyClosure; -static Bool MVTContingencyVisitor(Bool *deleteReturn, Land land, Range range, +static Bool MVTContingencyVisitor(Land land, Range range, void *closureP, Size closureS) { MVT mvt; @@ -1266,7 +1265,6 @@ static Bool MVTContingencyVisitor(Bool *deleteReturn, Land land, Range range, Addr base, limit; MVTContigencyClosure cl; - AVER(deleteReturn != NULL); AVERT(Land, land); AVERT(Range, range); AVER(closureP != NULL); diff --git a/mps/design/cbs.txt b/mps/design/cbs.txt index c0661f2f792..496cc5ea246 100644 --- a/mps/design/cbs.txt +++ b/mps/design/cbs.txt @@ -124,9 +124,10 @@ _`.limit.zones`: ``CBSLandClass`` and ``CBSFastLandClass`` do not support the ``LandFindInZones()`` generic function (the subclass ``CBSZonedLandClass`` does support this operation). -_`.limit.iterate`: CBS does not support visitors setting -``deleteReturn`` to ``TRUE`` when iterating over ranges with -``LandIterate()``. +_`.limit.iterate`: CBS does not provide an implementation for the +``LandIterateAndDelete()`` generic function. This is because +``TreeTraverse()`` does not permit modification, for speed and to +avoid perturbing the splay tree balance. _`.limit.flush`: CBS cannot be used as the source in a call to ``LandFlush()``. (Because of `.limit.iterate`_.) @@ -221,6 +222,11 @@ converting them when they reach all free in the bit set. Note that this would make coalescence slightly less eager, by up to ``(word-width - 1)``. +_`.future.iterate.and.delete`: It would be possible to provide an +implementation for the ``LandIterateAndDelete()`` generic function by +calling ``TreeToVine()`` first, and then iterating over the vine +(where deletion is straightforward). + Risks ----- diff --git a/mps/design/land.txt b/mps/design/land.txt index b9f80b29d23..a4b79dec937 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -77,15 +77,22 @@ Types _`.type.land`: The type of a generic land instance. -``typedef Bool (*LandVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS);`` +``typedef Bool (*LandVisitor)(Land land, Range range, void *closureP, Size closureS);`` _`.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);`` + +_`.type.visitor`: 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 update ``*deleteReturn`` to ``TRUE`` if the range must be deleted from the land, or ``FALSE`` if the range must be kept. (The default is to -keep the range, and not all land classes support deletion.) +keep the range.) Generic functions @@ -164,16 +171,22 @@ strategy. _`.function.delete.alias`: It is acceptable for ``rangeReturn`` and ``range`` to share storage. -``Bool LandIterate(Land land, LandIterateMethod iterate, void *closureP, Size closureS)`` +``Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)`` _`.function.iterate`: ``LandIterate()`` is the function used to iterate all isolated contiguous ranges in a land. It receives a -pointer, ``Size`` closure pair to pass on to the iterator method, and -an iterator method to invoke on every range. If the iterator method -returns ``FALSE``, then the iteration is terminated and +visitor function to invoke on every range, and a pointer, ``Size`` +closure pair 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`` +``Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS)`` + +_`.function.iterate.and.delete`: As ``LandIterate()``, but the visitor +function additionally returns a Boolean indicating whether the range +should be deleted from the land. + ``Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)`` _`.function.find.first`: Locate the first block (in address order) From e35f3b1b6c1b4897524b9b25e809fc6d5ead59dc Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 25 May 2014 20:49:22 +0100 Subject: [PATCH 241/266] Fix problems identified by dl in review . Copied from Perforce Change: 186300 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 16 +++++------ mps/code/cbs.c | 64 +++++++++++++++++++++++--------------------- mps/code/failover.c | 39 ++++++++++++++++++--------- mps/code/freelist.c | 27 +++++++++++-------- mps/code/land.c | 53 +++++++++++++++++++----------------- mps/code/landtest.c | 4 ++- mps/code/mpm.h | 4 +-- mps/code/mpmtypes.h | 2 +- mps/code/poolmv2.c | 3 ++- mps/design/index.txt | 6 ++--- mps/design/land.txt | 11 ++++---- 11 files changed, 129 insertions(+), 100 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index bd631e2ac49..be3137fd9bd 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -843,7 +843,7 @@ static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high, Arena arena; RangeStruct range, oldRange; Chunk chunk; - Bool b; + Bool found, b; Index baseIndex; Count pages; Res res; @@ -860,8 +860,8 @@ static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high, /* Step 1. Find a range of address space. */ - res = LandFindInZones(&range, &oldRange, ArenaFreeLand(arena), - size, zones, high); + res = LandFindInZones(&found, &range, &oldRange, ArenaFreeLand(arena), + size, zones, high); if (res == ResLIMIT) { /* found block, but couldn't store info */ RangeStruct pageRange; @@ -869,17 +869,17 @@ static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high, if (res != ResOK) /* disastrously short on memory */ return res; arenaExcludePage(arena, &pageRange); - res = LandFindInZones(&range, &oldRange, ArenaFreeLand(arena), - size, zones, high); + res = LandFindInZones(&found, &range, &oldRange, ArenaFreeLand(arena), + size, zones, high); AVER(res != ResLIMIT); } - if (res == ResFAIL) /* out of address space */ - return ResRESOURCE; - AVER(res == ResOK); /* unexpected error from ZoneCBS */ if (res != ResOK) /* defensive return */ return res; + + if (!found) /* out of address space */ + return ResRESOURCE; /* Step 2. Make memory available in the address space range. */ diff --git a/mps/code/cbs.c b/mps/code/cbs.c index de6c25ff08c..caad67aba71 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -989,17 +989,20 @@ static Bool cbsFindLargest(Range rangeReturn, Range oldRangeReturn, } -static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn, - Land land, Size size, +static Res cbsFindInZones(Bool *foundReturn, Range rangeReturn, + Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high) { CBS cbs; + CBSBlock block; Tree tree; cbsTestNodeInZonesClosureStruct closure; Res res; LandFindMethod landFind; SplayFindMethod splayFind; + RangeStruct rangeStruct, oldRangeStruct; + AVER(foundReturn != NULL); AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); AVERT(Land, land); @@ -1013,16 +1016,14 @@ static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn, splayFind = high ? SplayFindLast : SplayFindFirst; if (zoneSet == ZoneSetEMPTY) - return ResFAIL; + goto fail; if (zoneSet == ZoneSetUNIV) { FindDelete fd = high ? FindDeleteHIGH : FindDeleteLOW; - if ((*landFind)(rangeReturn, oldRangeReturn, land, size, fd)) - return ResOK; - else - return ResFAIL; + *foundReturn = (*landFind)(rangeReturn, oldRangeReturn, land, size, fd); + return ResOK; } if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(LandArena(land))) - return ResFAIL; + goto fail; /* It would be nice if there were a neat way to eliminate all runs of zones in zoneSet too small for size.*/ @@ -1031,31 +1032,34 @@ static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn, closure.zoneSet = zoneSet; closure.size = size; closure.high = high; - if (splayFind(&tree, cbsSplay(cbs), - cbsTestNodeInZones, - cbsTestTreeInZones, - &closure, sizeof(closure))) { - CBSBlock block = cbsBlockOfTree(tree); - RangeStruct rangeStruct, oldRangeStruct; + if (!(*splayFind)(&tree, cbsSplay(cbs), + cbsTestNodeInZones, cbsTestTreeInZones, + &closure, sizeof(closure))) + goto fail; - AVER(CBSBlockBase(block) <= closure.base); - AVER(AddrOffset(closure.base, closure.limit) >= size); - AVER(ZoneSetSub(ZoneSetOfRange(LandArena(land), closure.base, closure.limit), zoneSet)); - AVER(closure.limit <= CBSBlockLimit(block)); + block = cbsBlockOfTree(tree); - if (!high) - RangeInit(&rangeStruct, closure.base, AddrAdd(closure.base, size)); - else - RangeInit(&rangeStruct, AddrSub(closure.limit, size), closure.limit); - res = cbsDelete(&oldRangeStruct, land, &rangeStruct); - if (res == ResOK) { /* enough memory to split block */ - RangeCopy(rangeReturn, &rangeStruct); - RangeCopy(oldRangeReturn, &oldRangeStruct); - } - } else - res = ResFAIL; + AVER(CBSBlockBase(block) <= closure.base); + AVER(AddrOffset(closure.base, closure.limit) >= size); + AVER(ZoneSetSub(ZoneSetOfRange(LandArena(land), closure.base, closure.limit), zoneSet)); + AVER(closure.limit <= CBSBlockLimit(block)); - return res; + if (!high) + RangeInit(&rangeStruct, closure.base, AddrAdd(closure.base, size)); + else + RangeInit(&rangeStruct, AddrSub(closure.limit, size), closure.limit); + res = cbsDelete(&oldRangeStruct, land, &rangeStruct); + if (res != ResOK) + /* not enough memory to split block */ + return res; + RangeCopy(rangeReturn, &rangeStruct); + RangeCopy(oldRangeReturn, &oldRangeStruct); + *foundReturn = TRUE; + return ResOK; + +fail: + *foundReturn = FALSE; + return ResOK; } diff --git a/mps/code/failover.c b/mps/code/failover.c index 80ecb0a6210..8032cfe55d0 100644 --- a/mps/code/failover.c +++ b/mps/code/failover.c @@ -96,7 +96,7 @@ static Res failoverInsert(Range rangeReturn, Land land, Range range) /* Provide more opportunities for coalescence. See * . */ - LandFlush(fo->primary, fo->secondary); + (void)LandFlush(fo->primary, fo->secondary); res = LandInsert(rangeReturn, fo->primary, range); if (res != ResOK && res != ResFAIL) @@ -121,7 +121,7 @@ static Res failoverDelete(Range rangeReturn, Land land, Range range) /* Prefer efficient search in the primary. See * . */ - LandFlush(fo->primary, fo->secondary); + (void)LandFlush(fo->primary, fo->secondary); res = LandDelete(&oldRange, fo->primary, range); @@ -144,16 +144,22 @@ static Res failoverDelete(Range rangeReturn, Land land, Range range) /* Don't call LandInsert(..., land, ...) here: that would be * re-entrant and fail the landEnter check. */ res = LandInsert(&dummyRange, fo->primary, &left); - if (res != ResOK && res != ResFAIL) + if (res != ResOK) { + /* The range was successful deleted from the primary above. */ + AVER(res != ResFAIL); res = LandInsert(&dummyRange, fo->secondary, &left); - AVER(res == ResOK); + AVER(res == ResOK); + } } RangeInit(&right, RangeLimit(range), RangeLimit(&oldRange)); if (!RangeIsEmpty(&right)) { res = LandInsert(&dummyRange, fo->primary, &right); - if (res != ResOK && res != ResFAIL) + if (res != ResOK) { + /* The range was successful deleted from the primary above. */ + AVER(res != ResFAIL); res = LandInsert(&dummyRange, fo->secondary, &right); - AVER(res == ResOK); + AVER(res == ResOK); + } } } if (res == ResOK) { @@ -190,7 +196,7 @@ static Bool failoverFindFirst(Range rangeReturn, Range oldRangeReturn, Land land AVERT(FindDelete, findDelete); /* See . */ - LandFlush(fo->primary, fo->secondary); + (void)LandFlush(fo->primary, fo->secondary); return LandFindFirst(rangeReturn, oldRangeReturn, fo->primary, size, findDelete) || LandFindFirst(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete); @@ -209,7 +215,7 @@ static Bool failoverFindLast(Range rangeReturn, Range oldRangeReturn, Land land, AVERT(FindDelete, findDelete); /* See . */ - LandFlush(fo->primary, fo->secondary); + (void)LandFlush(fo->primary, fo->secondary); return LandFindLast(rangeReturn, oldRangeReturn, fo->primary, size, findDelete) || LandFindLast(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete); @@ -228,17 +234,20 @@ static Bool failoverFindLargest(Range rangeReturn, Range oldRangeReturn, Land la AVERT(FindDelete, findDelete); /* See . */ - LandFlush(fo->primary, fo->secondary); + (void)LandFlush(fo->primary, fo->secondary); return LandFindLargest(rangeReturn, oldRangeReturn, fo->primary, size, findDelete) || LandFindLargest(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete); } -static Bool failoverFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high) +static Bool failoverFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high) { Failover fo; + Bool found = FALSE; + Res res; + AVER(foundReturn != NULL); AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); AVERT(Land, land); @@ -248,10 +257,14 @@ static Bool failoverFindInZones(Range rangeReturn, Range oldRangeReturn, Land la AVERT(Bool, high); /* See . */ - LandFlush(fo->primary, fo->secondary); + (void)LandFlush(fo->primary, fo->secondary); - return LandFindInZones(rangeReturn, oldRangeReturn, fo->primary, size, zoneSet, high) - || LandFindInZones(rangeReturn, oldRangeReturn, fo->secondary, size, zoneSet, high); + res = LandFindInZones(&found, rangeReturn, oldRangeReturn, fo->primary, size, zoneSet, high); + if (res != ResOK || !found) + res = LandFindInZones(&found, rangeReturn, oldRangeReturn, fo->secondary, size, zoneSet, high); + + *foundReturn = found; + return res; } diff --git a/mps/code/freelist.c b/mps/code/freelist.c index 0abf766a9f3..a1f4803906e 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -32,7 +32,7 @@ typedef union FreelistBlockUnion { /* freelistEND -- the end of a list * * The end of a list should not be represented with NULL, as this is - * ambiguous. However, freelistEND in fact a null pointer for + * ambiguous. However, freelistEND is in fact a null pointer, for * performance. To check whether you have it right, try temporarily * defining freelistEND as ((FreelistBlock)2) or similar (it must be * an even number because of the use of a tag). @@ -666,8 +666,8 @@ static Bool freelistFindLargest(Range rangeReturn, Range oldRangeReturn, } -static Res freelistFindInZones(Range rangeReturn, Range oldRangeReturn, - Land land, Size size, +static Res freelistFindInZones(Bool *foundReturn, Range rangeReturn, + Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high) { Freelist fl; @@ -691,16 +691,14 @@ static Res freelistFindInZones(Range rangeReturn, Range oldRangeReturn, search = high ? RangeInZoneSetLast : RangeInZoneSetFirst; if (zoneSet == ZoneSetEMPTY) - return ResFAIL; + goto fail; if (zoneSet == ZoneSetUNIV) { FindDelete fd = high ? FindDeleteHIGH : FindDeleteLOW; - if ((*landFind)(rangeReturn, oldRangeReturn, land, size, fd)) - return ResOK; - else - return ResFAIL; + *foundReturn = (*landFind)(rangeReturn, oldRangeReturn, land, size, fd); + return ResOK; } if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(LandArena(land))) - return ResFAIL; + goto fail; prev = freelistEND; cur = fl->list; @@ -723,10 +721,15 @@ static Res freelistFindInZones(Range rangeReturn, Range oldRangeReturn, } if (!found) - return ResFAIL; + goto fail; freelistDeleteFromBlock(oldRangeReturn, fl, &foundRange, foundPrev, foundCur); RangeCopy(rangeReturn, &foundRange); + *foundReturn = TRUE; + return ResOK; + +fail: + *foundReturn = FALSE; return ResOK; } @@ -762,6 +765,7 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream) { Freelist fl; Res res; + Bool b; if (!TESTT(Land, land)) return ResFAIL; fl = freelistOfLand(land); @@ -773,7 +777,8 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream) " listSize = $U\n", (WriteFU)fl->listSize, NULL); - (void)LandIterate(land, freelistDescribeVisitor, stream, 0); + b = LandIterate(land, freelistDescribeVisitor, stream, 0); + if (!b) return ResFAIL; res = WriteF(stream, "}\n", NULL); return res; diff --git a/mps/code/land.c b/mps/code/land.c index b7f4ebf8386..78dc7f0b324 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -236,15 +236,15 @@ Res LandDelete(Range rangeReturn, Land land, Range range) Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) { - Bool res; + Bool b; AVERT(Land, land); AVER(FUNCHECK(visitor)); landEnter(land); - res = (*land->class->iterate)(land, visitor, closureP, closureS); + b = (*land->class->iterate)(land, visitor, closureP, closureS); landLeave(land); - return res; + return b; } @@ -256,15 +256,15 @@ Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS) { - Bool res; + Bool b; AVERT(Land, land); AVER(FUNCHECK(visitor)); landEnter(land); - res = (*land->class->iterateAndDelete)(land, visitor, closureP, closureS); + b = (*land->class->iterateAndDelete)(land, visitor, closureP, closureS); landLeave(land); - return res; + return b; } @@ -275,7 +275,7 @@ Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) { - Bool res; + Bool b; AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); @@ -284,11 +284,11 @@ Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size AVER(FindDeleteCheck(findDelete)); landEnter(land); - res = (*land->class->findFirst)(rangeReturn, oldRangeReturn, land, size, - findDelete); + b = (*land->class->findFirst)(rangeReturn, oldRangeReturn, land, size, + findDelete); landLeave(land); - return res; + return b; } @@ -299,7 +299,7 @@ Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) { - Bool res; + Bool b; AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); @@ -308,11 +308,11 @@ Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, AVER(FindDeleteCheck(findDelete)); landEnter(land); - res = (*land->class->findLast)(rangeReturn, oldRangeReturn, land, size, - findDelete); + b = (*land->class->findLast)(rangeReturn, oldRangeReturn, land, size, + findDelete); landLeave(land); - return res; + return b; } @@ -323,7 +323,7 @@ Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete) { - Bool res; + Bool b; AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); @@ -332,11 +332,11 @@ Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size si AVER(FindDeleteCheck(findDelete)); landEnter(land); - res = (*land->class->findLargest)(rangeReturn, oldRangeReturn, land, size, - findDelete); + b = (*land->class->findLargest)(rangeReturn, oldRangeReturn, land, size, + findDelete); landLeave(land); - return res; + return b; } @@ -345,10 +345,11 @@ Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size si * See */ -Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high) +Res LandFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high) { Res res; + AVER(foundReturn != NULL); AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); AVERT(Land, land); @@ -357,8 +358,8 @@ Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size siz AVERT(Bool, high); landEnter(land); - res = (*land->class->findInZones)(rangeReturn, oldRangeReturn, land, size, - zoneSet, high); + res = (*land->class->findInZones)(foundReturn, rangeReturn, oldRangeReturn, + land, size, zoneSet, high); landLeave(land); return res; @@ -432,12 +433,12 @@ static Bool landFlushVisitor(Bool *deleteReturn, Land land, Range range, * See */ -void LandFlush(Land dest, Land src) +Bool LandFlush(Land dest, Land src) { AVERT(Land, dest); AVERT(Land, src); - (void)LandIterateAndDelete(src, landFlushVisitor, dest, 0); + return LandIterateAndDelete(src, landFlushVisitor, dest, 0); } @@ -504,7 +505,8 @@ static Bool landSizeVisitor(Land land, Range range, Size LandSlowSize(Land land) { Size size = 0; - (void)LandIterate(land, landSizeVisitor, &size, 0); + Bool b = LandIterate(land, landSizeVisitor, &size, 0); + AVER(b); return size; } @@ -552,8 +554,9 @@ static Bool landNoFind(Range rangeReturn, Range oldRangeReturn, Land land, Size return ResUNIMPL; } -static Res landNoFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high) +static Res landNoFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high) { + AVER(foundReturn != NULL); AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); AVERT(Land, land); diff --git a/mps/code/landtest.c b/mps/code/landtest.c index 195f9758656..a4eb9b369e1 100644 --- a/mps/code/landtest.c +++ b/mps/code/landtest.c @@ -108,12 +108,14 @@ static Bool checkVisitor(Land land, Range range, void *closureP, Size closureS) static void check(TestState state) { CheckTestClosureStruct closure; + Bool b; closure.state = state; closure.limit = addrOfIndex(state, ArraySize); closure.oldLimit = state->block; - (void)LandIterate(state->land, checkVisitor, (void *)&closure, 0); + b = LandIterate(state->land, checkVisitor, (void *)&closure, 0); + Insist(b); if (closure.oldLimit == state->block) Insist(BTIsSetRange(state->allocTable, 0, diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 28373eadc69..43110467be2 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -1019,9 +1019,9 @@ extern Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *clo 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); -extern Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high); +extern Res LandFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high); extern Res LandDescribe(Land land, mps_lib_FILE *stream); -extern void LandFlush(Land dest, Land src); +extern Bool LandFlush(Land dest, Land src); extern Size LandSlowSize(Land land); extern Bool LandClassCheck(LandClass class); diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index c79c049ca5f..c9c5b029c4a 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -276,7 +276,7 @@ typedef Bool (*LandDeleteVisitor)(Bool *deleteReturn, Land land, Range range, vo typedef Bool (*LandIterateMethod)(Land land, LandVisitor visitor, void *closureP, Size closureS); typedef Bool (*LandIterateAndDeleteMethod)(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS); typedef Bool (*LandFindMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete); -typedef Res (*LandFindInZonesMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high); +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); diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index 4f36884ab79..b0636a3d467 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -1239,7 +1239,8 @@ static void MVTRefillABQIfEmpty(MVT mvt, Size size) if (mvt->abqOverflow && ABQIsEmpty(MVTABQ(mvt))) { mvt->abqOverflow = FALSE; METER_ACC(mvt->refills, size); - (void)LandIterate(MVTFailover(mvt), &MVTRefillVisitor, mvt, 0); + /* The iteration stops if the ABQ overflows, so may finish or not. */ + (void)LandIterate(MVTFailover(mvt), MVTRefillVisitor, mvt, 0); } } diff --git a/mps/design/index.txt b/mps/design/index.txt index d5fe0a7658f..39594723074 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -45,17 +45,17 @@ arena_ The design of the MPS arena arenavm_ Virtual memory arena bt_ Bit tables buffer_ Allocation buffers and allocation points -cbs_ Coalescing Block Structure allocator +cbs_ Coalescing Block Structure land implementation check_ Design of checking in MPS class-interface_ Design of the pool class interface collection_ The collection framework config_ The design of MPS configuration critical-path_ The critical path through the MPS diag_ The design of MPS diagnostic feedback -failover_ Fail-over allocator +failover_ Fail-over land implementation finalize_ Finalization fix_ The Design of the Generic Fix Function -freelist_ Free list allocator +freelist_ Free list land implementation guide.hex.trans_ Guide to transliterating the alphabet into hexadecimal guide.impl.c.format_ Coding standard: conventions for the general format of C source code in the MPS interface-c_ The design of the Memory Pool System interface to C diff --git a/mps/design/land.txt b/mps/design/land.txt index a4b79dec937..b4b8bd212a1 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -232,13 +232,14 @@ Like ``LandFindFirst()``, optionally delete the range (specifying range in which the range was found via the ``oldRangeReturn`` argument. -``Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high)`` +``Res LandFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high)`` _`.function.find.zones`: Locate a block at least as big as ``size`` that lies entirely within the ``zoneSet``, return its range via the -``rangeReturn`` argument, and return ``ResOK``. (The first such block, -if ``high`` is ``FALSE``, or the last, if ``high`` is ``TRUE``.) If -there is no such block, return ``ResFAIL``. +``rangeReturn`` argument, set ``*foundReturn`` to ``TRUE``, and return +``ResOK``. (The first such block, if ``high`` is ``FALSE``, or the +last, if ``high`` is ``TRUE``.) If there is no such block, set +``*foundReturn`` to ``TRUE``, and return ``ResOK``. Delete the range as for ``LandFindFirst()`` and ``LastFindLast()`` (with the effect of ``FindDeleteLOW`` if ``high`` is ``FALSE`` and the @@ -248,7 +249,7 @@ the ``oldRangeReturn`` argument. _`.function.find.zones.fail`: It's possible that the range can't be deleted from the land because that would require allocation, in which -case the result code will indicate the cause of the failure. +case the result code indicates the cause of the failure. ``Res LandDescribe(Land land, mps_lib_FILE *stream)`` From e9dddf19de5b9545ced5a721e426606ba6dd5cbc Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 26 May 2014 12:39:38 +0100 Subject: [PATCH 242/266] New chapter of the guide discusses the "stretchy vector" problem. Copied from Perforce Change: 186305 ServerID: perforce.ravenbrook.com --- mps/manual/source/glossary/index.rst | 1 + mps/manual/source/glossary/s.rst | 24 ++++- mps/manual/source/guide/index.rst | 1 + mps/manual/source/guide/vector.rst | 152 +++++++++++++++++++++++++++ 4 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 mps/manual/source/guide/vector.rst diff --git a/mps/manual/source/glossary/index.rst b/mps/manual/source/glossary/index.rst index f3f3ed154c0..9a426a5e742 100644 --- a/mps/manual/source/glossary/index.rst +++ b/mps/manual/source/glossary/index.rst @@ -515,6 +515,7 @@ Memory Management Glossary :term:`storage management ` :term:`store (1)` :term:`store (2) ` +:term:`stretchy vector` :term:`strict segregated fit` :term:`strong reference` :term:`strong root` diff --git a/mps/manual/source/glossary/s.rst b/mps/manual/source/glossary/s.rst index 41389cb2103..f244ad79b62 100644 --- a/mps/manual/source/glossary/s.rst +++ b/mps/manual/source/glossary/s.rst @@ -785,6 +785,26 @@ Memory Management Glossary: S .. see:: :term:`memory (1)`. + stretchy vector + + A data structure consisting of a vector that may grow or + shrink to accommodate adding or removing elements. Named after + the ```` abstract class in Dylan). + + .. relevance:: + + In the presence of an :term:`asynchronous garbage + collector`, the vector and its size may need to be updated + atomically. + + .. link:: + + `Dylan Reference Manual: Collections `_. + + .. mps:specific:: + + See :ref:`guide-stretchy-vector`. + strict segregated fit A :term:`segregated fit` :term:`allocation mechanism` which @@ -806,7 +826,7 @@ Memory Management Glossary: S collection>`, a strong reference is a :term:`reference` that keeps the :term:`object` it refers to :term:`alive `. - A strong reference is the usual sort of reference; The term is + A strong reference is the usual sort of reference: the term is usually used to draw a contrast with :term:`weak reference (1)`. @@ -819,7 +839,7 @@ Memory Management Glossary: S A strong root is a :term:`root` such that all :term:`references` in it are :term:`strong references`. - A strong root is the usual sort of root. The term is usually + A strong root is the usual sort of root: the term is usually used to draw a contrast with :term:`weak root`. .. opposite:: :term:`weak root`. diff --git a/mps/manual/source/guide/index.rst b/mps/manual/source/guide/index.rst index abd9ef242ca..a7218dd2ba5 100644 --- a/mps/manual/source/guide/index.rst +++ b/mps/manual/source/guide/index.rst @@ -9,6 +9,7 @@ Guide overview build lang + vector debug perf advanced diff --git a/mps/manual/source/guide/vector.rst b/mps/manual/source/guide/vector.rst new file mode 100644 index 00000000000..8b9452ac1f6 --- /dev/null +++ b/mps/manual/source/guide/vector.rst @@ -0,0 +1,152 @@ +.. index:: + single: stretchy vectors + single: atomic updates + +.. _guide-stretchy-vector: + +The stretchy vector problem +============================ + +The :ref:`previous chapter ` pointed out that: + + Because the MPS is :term:`asynchronous `, it might be scanning, moving, or collecting, at any + point in time. + +The consequences of this can take a while to sink in, so this chapter +discusses a particular instance that catches people out: the *stretchy +vector* problem (named after the |stretchy-vector|_ abstract class in +Dylan). + +.. |stretchy-vector| replace:: ```` +.. _stretchy-vector: http://opendylan.org/books/drm/Collection_Classes#stretchy-vector + +A *stretchy vector* is a vector that can change length dynamically. +Such a vector is often implemented using two objects: an array, and a +header object that stores the length and a pointer to an array. +Stretching (or shrinking) such a vector involves five steps: + +1. allocate a new array; +2. copy elements from the old array to the new array; +3. clear unused elements in the new array (if stretching); +4. update the pointer to the array in the header; +5. update the length in the header. + +For example: + +.. code-block:: c + + typedef struct vector_s { + type_t type; /* TYPE_VECTOR */ + size_t length; /* number of elements */ + obj_t *array; /* array of elements */ + } vector_s, *vector_t; + + void resize_vector(vector_t vector, size_t new_length) { + obj_t *new_array = realloc(vector->array, new_length * sizeof(obj_t)); + if (new_array == NULL) + error("out of memory in resize_vector"); + if (vector->length < new_length) { + memset(&vector->array[vector->length], 0, + (new_length - vector->length) * sizeof(obj_t)); + } + vector->array = new_array; + vector->length = new_length; + } + +When adapting this code to the MPS, the following problems must be +solved: + +1. During step 2, the new array must be :term:`reachable` from the + roots, and :term:`scannable `. (If it's not reachable, then + it may be collected; if it's not scannable, then references it + contains will not be updated when they are moved by the collector.) + + 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. + +2. References in the new array must not be scanned until they have been + copied or cleared. (Otherwise they will be invalid.) + + This can be solved by clearing the new array before calling + :c:func:`mps_commit`. + +3. The old array must be scanned at the old length (otherwise the scan + may run off the end of the old array when the vector grows), and + the new array must be scanned at the new length (otherwise the scan + may run off the end of the old array when the vector shrinks). + +4. The array object must be scannable without referring to the header + object. (Because the header object may have been protected by the + MPS: see :ref:`topic-format-cautions`.) + +Problems 3 and 4 can be solved by storing the length in the array. The +revised data structures and resizing code might look like this: + +.. code-block:: c + + typedef struct vector_s { + type_t type; /* TYPE_VECTOR */ + obj_t array; /* TYPE_ARRAY object */ + } vector_s, *vector_t; + + typedef struct array_s { + type_t type; /* TYPE_ARRAY */ + size_t length; /* number of elements */ + obj_t array[0]; /* array of elements */ + } array_s, *array_t; + + void resize_vector(vector_t vector, size_t new_length) { + size_t size = ALIGN_OBJ(offsetof(array_s, array) + new_length * sizeof(obj_t)); + mps_addr_t addr; + array_t array; + + do { + mps_res_t res = mps_reserve(&addr, ap, size); + if (res != MPS_RES_OK) error("out of memory in resize_vector"); + array = addr; + array->type = TYPE_ARRAY; + array->length = new_length; + memset(array->array, 0, new_length * sizeof(obj_t)); + /* Now the new array is scannable, and it is reachable via the + * local variable 'array', so it is safe to commit it. */ + } while(!mps_commit(ap, addr, size)); + + /* Copy elements after committing, so that the collector will + * update them if they move. */ + memcpy(array->array, vector->array->array, + min(vector->array->length, new_length) * sizeof(obj_t)); + vector->array = array; + } + +Similar difficulties can arise even when adapting code written for +other garbage collectors. For example, here's the function +|setarrayvector|_ from Lua_: + +.. |setarrayvector| replace:: ``setarrayvector()`` +.. _setarrayvector: http://www.lua.org/source/5.2/ltable.c.html#setarrayvector +.. _Lua: http://www.lua.org + +.. code-block:: c + + static void setarrayvector (lua_State *L, Table *t, int size) { + int i; + luaM_reallocvector(L, t->array, t->sizearray, size, TValue); + for (i=t->sizearray; iarray[i]); + t->sizearray = size; + } + +Lua's garbage collector is :term:`synchronous `, so it can be assumed that there cannot be a garbage +collection between the assignment to ``t->array`` (resulting from the +expansion of the |luaM_reallocvector|_ macro) and the assignment to +``t->sizearray``, and so the collector will always consistently see +either the old array or the new array, with the correct size. This +assumption will no longer be correct if this code is adapted to the +MPS. + +.. |luaM_reallocvector| replace:: ``luaM_reallocvector()`` +.. _luaM_reallocvector: http://www.lua.org/source/5.2/lmem.h.html#luaM_reallocvector From f5cd9029f9a64fbf80399ebf663123fe3ce4cdc8 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 26 May 2014 13:46:10 +0100 Subject: [PATCH 243/266] The java reference pages have moved to oracle.com. Add more cross-references to the MPS documentation. Copied from Perforce Change: 186307 ServerID: perforce.ravenbrook.com --- mps/manual/source/glossary/a.rst | 6 +++++- mps/manual/source/glossary/c.rst | 8 +++++++- mps/manual/source/glossary/f.rst | 5 +++++ mps/manual/source/glossary/g.rst | 15 ++++++++++----- mps/manual/source/glossary/i.rst | 6 ++++++ mps/manual/source/glossary/l.rst | 7 ++++++- mps/manual/source/glossary/m.rst | 5 +++++ mps/manual/source/glossary/n.rst | 6 ++++++ mps/manual/source/glossary/p.rst | 12 ++++++++++-- mps/manual/source/glossary/r.rst | 9 +++++++-- mps/manual/source/glossary/s.rst | 12 ++++++------ mps/manual/source/glossary/w.rst | 4 ++-- 12 files changed, 75 insertions(+), 20 deletions(-) diff --git a/mps/manual/source/glossary/a.rst b/mps/manual/source/glossary/a.rst index e7c6afe4d4f..e5c2693a71c 100644 --- a/mps/manual/source/glossary/a.rst +++ b/mps/manual/source/glossary/a.rst @@ -202,7 +202,11 @@ Memory Management Glossary: A .. mps:specific:: An alignment is represented by the unsigned integral type - :c:type:`mps_align_t`. It must be a positive power of 2. + :c:type:`mps_align_t`. It must be a power of 2. The + alignment of objects allocated in a :term:`pool` may be + specified by passing the :c:macro:`MPS_KEY_ALIGN` + :term:`keyword argument` when calling + :c:func:`mps_pool_create`. alive diff --git a/mps/manual/source/glossary/c.rst b/mps/manual/source/glossary/c.rst index b2d8f2b1400..2449ce9f82a 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`. @@ -615,6 +615,12 @@ Memory Management Glossary: C .. seealso:: :term:`broken heart`, :term:`forwarding pointer`, :term:`two-space collector`. + .. mps:specific:: + + The :ref:`pool-amc` pool class implements copying garbage + collection (more precisely, :term:`mostly-copying garbage + collection`). + core A historical synonym for :term:`main memory`, deriving from diff --git a/mps/manual/source/glossary/f.rst b/mps/manual/source/glossary/f.rst index 540cc048d46..eedbd00a9da 100644 --- a/mps/manual/source/glossary/f.rst +++ b/mps/manual/source/glossary/f.rst @@ -26,6 +26,11 @@ Memory Management Glossary: F .. similar:: :term:`in-band header`. + .. mps:specific:: + + :term:`Debugging pools` use fenceposts. See + :ref:`topic-debugging`. + fencepost error fence post error diff --git a/mps/manual/source/glossary/g.rst b/mps/manual/source/glossary/g.rst index 25feb894906..4dc74e66221 100644 --- a/mps/manual/source/glossary/g.rst +++ b/mps/manual/source/glossary/g.rst @@ -89,7 +89,7 @@ Memory Management Glossary: G This term is often used when referring to particular implementations or algorithms, for example, "the - Boehm-Demers-Weiser *collector*". + Boehm--Demers--Weiser *collector*". GB @@ -132,16 +132,16 @@ Memory Management Glossary: G .. mps:specific:: The :term:`client program` specifies the generational - structure of a :term:`pool` using a :term:`generation - chain`. See :ref:`topic-collection`. + structure of a :term:`pool` (or group of pools) using a + :term:`generation chain`. See :ref:`topic-collection`. generation chain .. mps:specific:: A data structure that specifies the structure of the - :term:`generations` in a :term:`pool`. See - :ref:`topic-collection`. + :term:`generations` in a :term:`pool` (or group of pools). + See :ref:`topic-collection`. generation scavenging @@ -174,6 +174,11 @@ Memory Management Glossary: G .. seealso:: :term:`remembered set`. + .. mps:specific:: + + The :ref:`pool-amc` and :ref:`pool-amcz` pool classes + support generational garbage collection. + generational hypothesis .. aka:: *infant mortality*. diff --git a/mps/manual/source/glossary/i.rst b/mps/manual/source/glossary/i.rst index 9ce2a3f9cea..b174241959c 100644 --- a/mps/manual/source/glossary/i.rst +++ b/mps/manual/source/glossary/i.rst @@ -133,6 +133,12 @@ Memory Management Glossary: I .. bibref:: :ref:`Appel et al. (1988) `, :ref:`Boehm et al. (1991) `. + .. mps:specific:: + + The MPS uses incremental collection, except for + collections started by calling + :c:func:`mps_arena_collect`. + incremental update Incremental-update algorithms for :term:`tracing `, diff --git a/mps/manual/source/glossary/l.rst b/mps/manual/source/glossary/l.rst index 5a143e55f69..3e4f0db4270 100644 --- a/mps/manual/source/glossary/l.rst +++ b/mps/manual/source/glossary/l.rst @@ -81,9 +81,14 @@ Memory Management Glossary: L If leaf objects can be identified, a :term:`garbage collector` can make certain optimizations: leaf objects do not have to be :term:`scanned ` for references nor - are :term:`barrier (1)` needed to detect + are :term:`barriers (1)` needed to detect and maintain references in the object. + .. mps:specific:: + + The :ref:`pool-amcz` and :ref:`pool-lo` pool classes are + designed for the storage of leaf objects. + leak .. see:: :term:`memory leak`. diff --git a/mps/manual/source/glossary/m.rst b/mps/manual/source/glossary/m.rst index 4562d30d7b6..db4d8b88a59 100644 --- a/mps/manual/source/glossary/m.rst +++ b/mps/manual/source/glossary/m.rst @@ -535,6 +535,11 @@ Memory Management Glossary: M .. bibref:: :ref:`Bartlett (1989) `, :ref:`Yip (1991) `. + .. mps:specific:: + + The :ref:`pool-amc` pool class implements mostly-copying + garbage collection. + mostly-exact garbage collection .. see:: :term:`semi-conservative garbage collection`. diff --git a/mps/manual/source/glossary/n.rst b/mps/manual/source/glossary/n.rst index 24ddcf66cea..792ad32b251 100644 --- a/mps/manual/source/glossary/n.rst +++ b/mps/manual/source/glossary/n.rst @@ -117,4 +117,10 @@ Memory Management Glossary: N The size of the nursery space must be chosen carefully. Often it is related to the size of :term:`physical memory (1)`. + .. mps:specific:: + By default, a garbage-collected :term:`pool` allocates + into the first :term:`generation` in its :term:`generation + chain`, but this can be altered by setting the + :c:macro:`MPS_KEY_GEN` :term:`keyword argument` when + calling :c:func:`mps_pool_create`. diff --git a/mps/manual/source/glossary/p.rst b/mps/manual/source/glossary/p.rst index fc08d9c2abb..e0259978d8b 100644 --- a/mps/manual/source/glossary/p.rst +++ b/mps/manual/source/glossary/p.rst @@ -222,7 +222,7 @@ Memory Management Glossary: P .. link:: - `Class java.lang.ref.PhantomReference `_, `Reference Objects and Garbage Collection `_. + `Class java.lang.ref.PhantomReference `_, `Reference Objects and Garbage Collection `_. phantom reference @@ -239,7 +239,7 @@ Memory Management Glossary: P .. link:: - `Class java.lang.ref.PhantomReference `_, `Reference Objects and Garbage Collection `_. + `Class java.lang.ref.PhantomReference `_, `Reference Objects and Garbage Collection `_. physical address @@ -321,6 +321,14 @@ Memory Management Glossary: P .. seealso:: :term:`generational garbage collection`. + .. mps:specific:: + + A :term:`pool` can be configured to allocate into a + specific :term:`generation` in its :term:`generation + chain` by setting the :c:macro:`MPS_KEY_GEN` + :term:`keyword argument` when calling + :c:func:`mps_pool_create`. + pig in the snake .. see:: :term:`pig in the python`. diff --git a/mps/manual/source/glossary/r.rst b/mps/manual/source/glossary/r.rst index a521c1d7bd4..2c8a9ef70ad 100644 --- a/mps/manual/source/glossary/r.rst +++ b/mps/manual/source/glossary/r.rst @@ -93,7 +93,7 @@ Memory Management Glossary: R .. link:: - `Package java.lang.ref `_, `Reference Objects and Garbage Collection `_. + `Package java.lang.ref `_, `Reference Objects and Garbage Collection `_. read barrier @@ -317,7 +317,7 @@ Memory Management Glossary: R .. link:: - `Package java.lang.ref `_, `Reference Objects and Garbage Collection `_. + `Package java.lang.ref `_, `Reference Objects and Garbage Collection `_. .. bibref:: :ref:`Dybvig et al. (1993) `. @@ -471,6 +471,11 @@ Memory Management Glossary: R .. seealso:: :term:`mapping`, :term:`mmap`. + .. mps:specific:: + + The function :c:func:`mps_arena_reserved` returns the + total address space reserved by an arena. + resident In a :term:`cache (2)` system, that part of the cached storage diff --git a/mps/manual/source/glossary/s.rst b/mps/manual/source/glossary/s.rst index f244ad79b62..dc9355f2a0f 100644 --- a/mps/manual/source/glossary/s.rst +++ b/mps/manual/source/glossary/s.rst @@ -333,7 +333,7 @@ Memory Management Glossary: S By overloading certain operators it is possible for the class to present the illusion of being a pointer, so that - ``operator\*``, ``operator-\>``, etc. can be used as normal. + ``operator*``, ``operator->``, etc. can be used as normal. Reference counting allows the objects that are referred to using the smart pointer class to have their :term:`memory (1)` automatically :term:`reclaimed` when they are no longer @@ -429,7 +429,7 @@ Memory Management Glossary: S .. link:: - `Class java.lang.ref.SoftReference `_, `Reference Objects and Garbage Collection `_. + `Class java.lang.ref.SoftReference `_, `Reference Objects and Garbage Collection `_. softly reachable @@ -453,7 +453,7 @@ Memory Management Glossary: S .. link:: - `Class java.lang.ref.SoftReference `_, `Reference Objects and Garbage Collection `_. + `Class java.lang.ref.SoftReference `_, `Reference Objects and Garbage Collection `_. space leak @@ -787,9 +787,9 @@ Memory Management Glossary: S stretchy vector - A data structure consisting of a vector that may grow or - shrink to accommodate adding or removing elements. Named after - the ```` abstract class in Dylan). + A :term:`vector ` that may grow or shrink to + accommodate adding or removing elements. Named after the + ```` abstract class in Dylan. .. relevance:: diff --git a/mps/manual/source/glossary/w.rst b/mps/manual/source/glossary/w.rst index 7d061294ce6..46d8d9edd06 100644 --- a/mps/manual/source/glossary/w.rst +++ b/mps/manual/source/glossary/w.rst @@ -70,7 +70,7 @@ Memory Management Glossary: W .. link:: - `Class java.lang.ref.WeakReference `_, `Reference Objects and Garbage Collection `_. + `Class java.lang.ref.WeakReference `_, `Reference Objects and Garbage Collection `_. weak root @@ -134,7 +134,7 @@ Memory Management Glossary: W .. link:: - `Class java.lang.ref.WeakReference `_, `Reference Objects and Garbage Collection `_. + `Class java.lang.ref.WeakReference `_, `Reference Objects and Garbage Collection `_. weighted buddies From 244f8987788d3b5e271fd82b7371b8928f1e3f06 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 26 May 2014 14:10:37 +0100 Subject: [PATCH 244/266] Reference mps_pool_create_k, not the deprecated function mps_pool_create. Copied from Perforce Change: 186309 ServerID: perforce.ravenbrook.com --- mps/manual/source/glossary/a.rst | 2 +- mps/manual/source/glossary/n.rst | 2 +- mps/manual/source/glossary/p.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mps/manual/source/glossary/a.rst b/mps/manual/source/glossary/a.rst index e5c2693a71c..746b5c0cf49 100644 --- a/mps/manual/source/glossary/a.rst +++ b/mps/manual/source/glossary/a.rst @@ -206,7 +206,7 @@ Memory Management Glossary: A alignment of objects allocated in a :term:`pool` may be specified by passing the :c:macro:`MPS_KEY_ALIGN` :term:`keyword argument` when calling - :c:func:`mps_pool_create`. + :c:func:`mps_pool_create_k`. alive diff --git a/mps/manual/source/glossary/n.rst b/mps/manual/source/glossary/n.rst index 792ad32b251..67fbd65a371 100644 --- a/mps/manual/source/glossary/n.rst +++ b/mps/manual/source/glossary/n.rst @@ -123,4 +123,4 @@ Memory Management Glossary: N into the first :term:`generation` in its :term:`generation chain`, but this can be altered by setting the :c:macro:`MPS_KEY_GEN` :term:`keyword argument` when - calling :c:func:`mps_pool_create`. + calling :c:func:`mps_pool_create_k`. diff --git a/mps/manual/source/glossary/p.rst b/mps/manual/source/glossary/p.rst index e0259978d8b..8909d6fb964 100644 --- a/mps/manual/source/glossary/p.rst +++ b/mps/manual/source/glossary/p.rst @@ -327,7 +327,7 @@ Memory Management Glossary: P specific :term:`generation` in its :term:`generation chain` by setting the :c:macro:`MPS_KEY_GEN` :term:`keyword argument` when calling - :c:func:`mps_pool_create`. + :c:func:`mps_pool_create_k`. pig in the snake From c1c09530b33e3f163b8bb1bf48a8fa28cc358f41 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 27 May 2014 15:53:55 +0100 Subject: [PATCH 245/266] Fix problems in design/splay: "Node" structure now called "Tree", so fix cross-reference. .future.reverse was removed, so remove cross-reference to it. Copied from Perforce Change: 186315 ServerID: perforce.ravenbrook.com --- mps/design/splay.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mps/design/splay.txt b/mps/design/splay.txt index 4290b703ac1..fefb40fe8a9 100644 --- a/mps/design/splay.txt +++ b/mps/design/splay.txt @@ -51,7 +51,7 @@ _`.def.splay-tree`: A *splay tree* is a self-adjusting binary tree as described in [ST85]_ and [Sleator96]_. _`.def.node`: A *node* is used in the typical data structure sense to -mean an element of a tree (see also `.type.splay.node`_). +mean an element of a tree (see also `.type.tree`_). _`.def.key`: A *key* is a value associated with each node; the keys are totally ordered by a client provided comparator. @@ -442,8 +442,7 @@ right trees. For the left tree, we traverse the right child line, reversing pointers, until we reach the node that was the last node prior to the transplantation of the root's children. Then we update from that node back to the left tree's root, restoring pointers. -Updating the right tree is the same, mutatis mutandis. (See -`.future.reverse`_ for an alternative approach). +Updating the right tree is the same, mutatis mutandis. Usage From 3c95447dfc6e6e83b5a11978c11537ccb11aac29 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 27 May 2014 19:34:02 +0100 Subject: [PATCH 246/266] Test "make install" as well as "make test". Copied from Perforce Change: 186317 ServerID: perforce.ravenbrook.com --- mps/.travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mps/.travis.yml b/mps/.travis.yml index 07a0dd66528..bc1dfd5bfb1 100644 --- a/mps/.travis.yml +++ b/mps/.travis.yml @@ -9,3 +9,5 @@ notifications: email: - mps-travis@ravenbrook.com irc: "irc.freenode.net#memorypoolsystem" +script: + - ./configure --prefix=$PWD/prefix && make install && make test From 56875865821cb0ba15a1b8e1139be306f00f3b11 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 27 May 2014 20:26:25 +0100 Subject: [PATCH 247/266] Fix typo; add cross-ref from "automatic memory management". Copied from Perforce Change: 186319 ServerID: perforce.ravenbrook.com --- mps/manual/source/glossary/a.rst | 6 ++++++ mps/manual/source/glossary/p.rst | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mps/manual/source/glossary/a.rst b/mps/manual/source/glossary/a.rst index 746b5c0cf49..ec4da5f86d2 100644 --- a/mps/manual/source/glossary/a.rst +++ b/mps/manual/source/glossary/a.rst @@ -480,6 +480,12 @@ Memory Management Glossary: A .. opposite:: :term:`manual memory management`. + .. mps:specific:: + + The MPS provides automatic memory management through + :term:`pool classes` such as :ref:`pool-amc`, + :ref:`pool-ams`, and :ref:`pool-awl`. + automatic storage duration In :term:`C`, :term:`objects` that are declared with diff --git a/mps/manual/source/glossary/p.rst b/mps/manual/source/glossary/p.rst index 8909d6fb964..5fdba129d77 100644 --- a/mps/manual/source/glossary/p.rst +++ b/mps/manual/source/glossary/p.rst @@ -167,7 +167,7 @@ Memory Management Glossary: P mutator changing :term:`objects` while collection occurs. The problem is similar to that of :term:`incremental GC `, but harder. The solution - typically involves :term:`barrier (1)`. + typically involves :term:`barriers (1)`. .. similar:: :term:`incremental `. From 29d6c2b70ea0d97f382ba131f5accce28aeaa009 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 27 May 2014 21:52:25 +0100 Subject: [PATCH 248/266] Format the glossary index in two colummns. Copied from Perforce Change: 186321 ServerID: perforce.ravenbrook.com --- mps/manual/source/glossary/index.rst | 3 +++ .../source/themes/mmref/static/mmref.css_t | 26 ++++++++++++++++--- mps/manual/source/themes/mps/static/mps.css_t | 21 ++++++++++++++- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/mps/manual/source/glossary/index.rst b/mps/manual/source/glossary/index.rst index 9a426a5e742..40656261350 100644 --- a/mps/manual/source/glossary/index.rst +++ b/mps/manual/source/glossary/index.rst @@ -33,6 +33,9 @@ Memory Management Glossary w z +All +=== + :term:`absolute address ` :term:`activation frame ` :term:`activation record` diff --git a/mps/manual/source/themes/mmref/static/mmref.css_t b/mps/manual/source/themes/mmref/static/mmref.css_t index ceab4faddef..f16758a7391 100644 --- a/mps/manual/source/themes/mmref/static/mmref.css_t +++ b/mps/manual/source/themes/mmref/static/mmref.css_t @@ -2,6 +2,11 @@ @import url('scrolls.css'); +sup { + vertical-align: top; + font-size: 80%; +} + dl.glossary dt { font-family: {{ theme_headfont }}; } @@ -135,7 +140,22 @@ div#home h1 + p { padding-top: 15px; } -div#memory-management-glossary em.xref.std-term { - white-space: nowrap; - margin-right: 1em; +/* Format the glossary index in two columns. */ + +div#memory-management-glossary div#all { + -webkit-columns: 2; + -moz-columns: 2; + -o-columns: 2; + -ms-columns: 2; + columns: 2; + padding-top: 1em; +} + +div#memory-management-glossary div#all h2 { + display: none; +} + +div#memory-management-glossary div#all a.reference.internal:after { + content: "\A"; + white-space: pre; } diff --git a/mps/manual/source/themes/mps/static/mps.css_t b/mps/manual/source/themes/mps/static/mps.css_t index 6b0e20d0eb4..5904c165580 100644 --- a/mps/manual/source/themes/mps/static/mps.css_t +++ b/mps/manual/source/themes/mps/static/mps.css_t @@ -188,7 +188,7 @@ p.glossary-alphabet { } sup { - vertical-align: 20%; + vertical-align: top; font-size: 80%; } @@ -220,3 +220,22 @@ li.toctree-l1, li.toctree-l2, li.toctree-l3 { padding-top: 0 !important; } +/* Format the glossary index in two columns. */ + +div#memory-management-glossary div#all { + -webkit-columns: 2; + -moz-columns: 2; + -o-columns: 2; + -ms-columns: 2; + columns: 2; + padding-top: 1em; +} + +div#memory-management-glossary div#all h2 { + display: none; +} + +div#memory-management-glossary div#all a.reference.internal:after { + content: "\A"; + white-space: pre; +} From 16ba7af3cb8d646d80d32b234a047953bed89bf3 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 28 May 2014 11:09:14 +0100 Subject: [PATCH 249/266] Failoverfindinzones is untested. Copied from Perforce Change: 186327 ServerID: perforce.ravenbrook.com --- mps/code/failover.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mps/code/failover.c b/mps/code/failover.c index 8032cfe55d0..1129c627590 100644 --- a/mps/code/failover.c +++ b/mps/code/failover.c @@ -247,6 +247,7 @@ static Bool failoverFindInZones(Bool *foundReturn, Range rangeReturn, Range oldR Bool found = FALSE; Res res; + AVER(FALSE); /* TODO: this code is completely untested! */ AVER(foundReturn != NULL); AVER(rangeReturn != NULL); AVER(oldRangeReturn != NULL); From d1c5dfc2d26472d3595bd9fc4193ba6d4df9b849 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 28 May 2014 17:24:46 +0100 Subject: [PATCH 250/266] Add comment explaining purpose of attribute_unused. Copied from Perforce Change: 186335 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mps/code/config.h b/mps/code/config.h index 081b3ffaeeb..e4db1be6423 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -292,6 +292,11 @@ /* Attribute for functions that may be unused in some build configurations. * GCC: + * + * This attribute must be applied to all Check functions, otherwise + * the RASH variety fails to compile with -Wunused-function. (It + * should not be applied to functions that are unused in all build + * configurations: these functions should not be compiled.) */ #if defined(MPS_BUILD_GC) || defined(MPS_BUILD_LL) #define ATTRIBUTE_UNUSED __attribute__((__unused__)) From e0c1ed0734a0fabdd8f38c7f6d5fcaeac556f814 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 28 May 2014 17:42:11 +0100 Subject: [PATCH 251/266] Clarifying a couple of comments most likely messed up by search-and-replace edits. Copied from Perforce Change: 186344 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 be3137fd9bd..ecfcb029e05 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -386,7 +386,7 @@ void ArenaDestroy(Arena arena) LandFinish(ArenaFreeLand(arena)); /* The CBS block pool can't free its own memory via ArenaFree because - that would use the CBSZoned. */ + that would use the freeLand. */ MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor, NULL, 0); PoolFinish(ArenaCBSBlockPool(arena)); @@ -687,7 +687,7 @@ static Res arenaExtendCBSBlockPool(Range pageRangeReturn, Arena arena) return ResOK; } -/* arenaExcludePage -- exclude CBS block pool's page from Land +/* arenaExcludePage -- exclude CBS block pool's page from free land * * Exclude the page we specially allocated for the CBS block pool * so that it doesn't get reallocated. From 4f3f12c3db58651c38b0a827c6689c58fc307a7f Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 29 May 2014 14:07:24 +0100 Subject: [PATCH 252/266] Fixing unbracketed macro parameter. Copied from Perforce Change: 186345 ServerID: perforce.ravenbrook.com --- mps/code/freelist.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mps/code/freelist.c b/mps/code/freelist.c index a1f4803906e..87f34384f27 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -14,7 +14,7 @@ SRCID(freelist, "$Id$"); #define freelistOfLand(land) PARENT(FreelistStruct, landStruct, land) -#define freelistAlignment(fl) LandAlignment(&fl->landStruct) +#define freelistAlignment(fl) LandAlignment(&(fl)->landStruct) typedef union FreelistBlockUnion { @@ -246,6 +246,9 @@ 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'. + * + * TODO: Consider using a sentinel FreelistBlockUnion in the FreeListStruct + * as the end marker and see if that simplifies. */ static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev, From 224afa61a8ae10a40540e9045b6ce5c38a62c873 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 29 May 2014 14:50:36 +0100 Subject: [PATCH 253/266] Fix problems identified by rb in review . Copied from Perforce Change: 186347 ServerID: perforce.ravenbrook.com --- mps/code/cbs.c | 6 +----- mps/code/failover.c | 15 +++++++++++---- mps/code/fotest.c | 4 +--- mps/code/freelist.c | 9 ++++++--- mps/code/poolmvff.c | 5 ++--- mps/code/splay.c | 4 ++-- mps/code/splay.h | 2 +- 7 files changed, 24 insertions(+), 21 deletions(-) diff --git a/mps/code/cbs.c b/mps/code/cbs.c index caad67aba71..6e30d77daa8 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -132,12 +132,8 @@ static Bool cbsTestTree(SplayTree splay, Tree tree, AVERT(SplayTree, splay); AVERT(Tree, tree); -#if 0 AVER(closureP == NULL); AVER(size > 0); -#endif - UNUSED(closureP); - UNUSED(size); AVER(IsLandSubclass(cbsLand(cbsOfSplay(splay)), CBSFastLandClass)); block = cbsFastBlockOfTree(tree); @@ -397,7 +393,7 @@ static Res cbsBlockAlloc(CBSBlock *blockReturn, CBS cbs, Range range) block->base = RangeBase(range); block->limit = RangeLimit(range); - SplayNodeUpdate(cbsSplay(cbs), cbsBlockTree(block)); + SplayNodeInit(cbsSplay(cbs), cbsBlockTree(block)); AVERT(CBSBlock, block); *blockReturn = block; diff --git a/mps/code/failover.c b/mps/code/failover.c index 1129c627590..7e9f07d7b8c 100644 --- a/mps/code/failover.c +++ b/mps/code/failover.c @@ -129,10 +129,17 @@ static Res failoverDelete(Range rangeReturn, Land land, Range range) /* Range not found in primary: try secondary. */ return LandDelete(rangeReturn, fo->secondary, range); } else if (res != ResOK) { - /* Range was found in primary, but couldn't be deleted, perhaps - * because the primary is out of memory. Delete the whole of - * oldRange, and re-insert the fragments (which might end up in - * the secondary). See . + /* Range was found in primary, but couldn't be deleted. The only + * case we expect to encounter here is the case where the primary + * is out of memory. (In particular, we don't handle the case of a + * CBS returning ResLIMIT because its block pool has been + * configured not to automatically extend itself.) + */ + AVER(ResIsAllocFailure(res)); + + /* Delete the whole of oldRange, and re-insert the fragments + * (which might end up in the secondary). See + * . */ res = LandDelete(&dummyRange, fo->primary, &oldRange); if (res != ResOK) diff --git a/mps/code/fotest.c b/mps/code/fotest.c index 2729395c0df..788253b570d 100644 --- a/mps/code/fotest.c +++ b/mps/code/fotest.c @@ -52,13 +52,11 @@ static Res oomAlloc(Addr *pReturn, Pool pool, Size size, UNUSED(pool); UNUSED(size); UNUSED(withReservoirPermit); - switch (rnd() % 4) { + switch (rnd() % 3) { case 0: return ResRESOURCE; case 1: return ResMEMORY; - case 2: - return ResLIMIT; default: return ResCOMMIT_LIMIT; } diff --git a/mps/code/freelist.c b/mps/code/freelist.c index 87f34384f27..ca66a0b273d 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -246,9 +246,12 @@ 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'. - * - * TODO: Consider using a sentinel FreelistBlockUnion in the FreeListStruct - * as the end marker and see if that simplifies. + + * 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. */ static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev, diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 8eb177434b1..7b1f435944c 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -82,9 +82,8 @@ typedef MVFFDebugStruct *MVFFDebug; /* MVFFInsert -- add given range to free lists * - * Updates MVFF counters for additional free space. Returns maximally - * coalesced range containing given range. Does not attempt to free - * segments (see MVFFFreeSegs). + * Updates rangeIO to be maximally coalesced range containing given + * range. Does not attempt to free segments (see MVFFFreeSegs). */ static Res MVFFInsert(Range rangeIO, MVFF mvff) { AVERT(Range, rangeIO); diff --git a/mps/code/splay.c b/mps/code/splay.c index 278f038b9b5..1b0e8afb8fd 100644 --- a/mps/code/splay.c +++ b/mps/code/splay.c @@ -1317,9 +1317,9 @@ void SplayNodeRefresh(SplayTree splay, Tree node) } -/* SplayNodeUpdate -- update the client property without splaying */ +/* SplayNodeInit -- initialize client property without splaying */ -void SplayNodeUpdate(SplayTree splay, Tree node) +void SplayNodeInit(SplayTree splay, Tree node) { AVERT(SplayTree, splay); AVERT(Tree, node); diff --git a/mps/code/splay.h b/mps/code/splay.h index d6496ff9977..24b97c4b055 100644 --- a/mps/code/splay.h +++ b/mps/code/splay.h @@ -69,7 +69,7 @@ extern Bool SplayFindLast(Tree *nodeReturn, SplayTree splay, void *closureP, Size closureS); extern void SplayNodeRefresh(SplayTree splay, Tree node); -extern void SplayNodeUpdate(SplayTree splay, Tree node); +extern void SplayNodeInit(SplayTree splay, Tree node); extern Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, TreeDescribeMethod nodeDescribe); From b8c39883eaf3a0b58ebff70cebc40a39f005f6d4 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 29 May 2014 15:28:33 +0100 Subject: [PATCH 254/266] Pass and check special closure values unused_pointer, unused_size instead of null, 0. Copied from Perforce Change: 186352 ServerID: perforce.ravenbrook.com --- mps/code/abqtest.c | 3 ++- mps/code/arena.c | 6 ++++-- mps/code/cbs.c | 17 +++++++++-------- mps/code/fbmtest.c | 5 +++-- mps/code/freelist.c | 4 ++-- mps/code/land.c | 6 ++++-- mps/code/landtest.c | 4 ++-- mps/code/misc.h | 9 +++++++++ mps/code/poolmfs.c | 4 +++- mps/code/poolmv2.c | 11 +++++++---- 10 files changed, 45 insertions(+), 24 deletions(-) diff --git a/mps/code/abqtest.c b/mps/code/abqtest.c index 367bafe730b..9aad3351cb6 100644 --- a/mps/code/abqtest.c +++ b/mps/code/abqtest.c @@ -96,6 +96,7 @@ static Bool TestDeleteCallback(Bool *deleteReturn, void *element, { TestBlock *a = (TestBlock *)element; TestClosure cl = (TestClosure)closureP; + AVER(closureS == UNUSED_SIZE); UNUSED(closureS); if (*a == cl->b) { *deleteReturn = TRUE; @@ -144,7 +145,7 @@ static void step(void) cdie(b != NULL, "found to delete"); cl.b = b; cl.res = ResFAIL; - ABQIterate(&abq, TestDeleteCallback, &cl, 0); + ABQIterate(&abq, TestDeleteCallback, &cl, UNUSED_SIZE); cdie(cl.res == ResOK, "ABQIterate"); } } diff --git a/mps/code/arena.c b/mps/code/arena.c index ecfcb029e05..d270adf7499 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -360,6 +360,8 @@ static void arenaMFSPageFreeVisitor(Pool pool, Addr base, Size size, void *closureP, Size closureS) { AVERT(Pool, pool); + AVER(closureP == UNUSED_POINTER); + AVER(closureS == UNUSED_SIZE); UNUSED(closureP); UNUSED(closureS); UNUSED(size); @@ -387,8 +389,8 @@ void ArenaDestroy(Arena arena) /* The CBS block pool can't free its own memory via ArenaFree because that would use the freeLand. */ - MFSFinishTracts(ArenaCBSBlockPool(arena), - arenaMFSPageFreeVisitor, NULL, 0); + MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor, + UNUSED_POINTER, UNUSED_SIZE); PoolFinish(ArenaCBSBlockPool(arena)); /* Call class-specific finishing. This will call ArenaFinish. */ diff --git a/mps/code/cbs.c b/mps/code/cbs.c index 6e30d77daa8..6f0350d0519 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -721,6 +721,7 @@ static Bool cbsIterateVisit(Tree tree, void *closureP, Size closureS) CBS cbs = cbsOfLand(land); Bool cont = TRUE; + AVER(closureS == UNUSED_SIZE); UNUSED(closureS); cbsBlock = cbsBlockOfTree(tree); @@ -754,7 +755,7 @@ static Bool cbsIterate(Land land, LandVisitor visitor, closure.closureP = closureP; closure.closureS = closureS; return TreeTraverse(SplayTreeRoot(splay), splay->compare, splay->nodeKey, - cbsIterateVisit, &closure, 0); + cbsIterateVisit, &closure, UNUSED_SIZE); } @@ -871,15 +872,15 @@ typedef struct cbsTestNodeInZonesClosureStruct { } cbsTestNodeInZonesClosureStruct, *cbsTestNodeInZonesClosure; static Bool cbsTestNodeInZones(SplayTree splay, Tree tree, - void *closureP, Size closureSize) + void *closureP, Size closureS) { CBSBlock block = cbsBlockOfTree(tree); cbsTestNodeInZonesClosure closure = closureP; RangeInZoneSet search; UNUSED(splay); - AVER(closureSize == sizeof(cbsTestNodeInZonesClosureStruct)); - UNUSED(closureSize); + AVER(closureS == UNUSED_SIZE); + UNUSED(closureS); search = closure->high ? RangeInZoneSetLast : RangeInZoneSetFirst; @@ -889,15 +890,15 @@ static Bool cbsTestNodeInZones(SplayTree splay, Tree tree, } static Bool cbsTestTreeInZones(SplayTree splay, Tree tree, - void *closureP, Size closureSize) + void *closureP, Size closureS) { CBSFastBlock fastBlock = cbsFastBlockOfTree(tree); CBSZonedBlock zonedBlock = cbsZonedBlockOfTree(tree); cbsTestNodeInZonesClosure closure = closureP; UNUSED(splay); - AVER(closureSize == sizeof(cbsTestNodeInZonesClosureStruct)); - UNUSED(closureSize); + AVER(closureS == UNUSED_SIZE); + UNUSED(closureS); return fastBlock->maxSize >= closure->size && ZoneSetInter(zonedBlock->zones, closure->zoneSet) != ZoneSetEMPTY; @@ -1030,7 +1031,7 @@ static Res cbsFindInZones(Bool *foundReturn, Range rangeReturn, closure.high = high; if (!(*splayFind)(&tree, cbsSplay(cbs), cbsTestNodeInZones, cbsTestTreeInZones, - &closure, sizeof(closure))) + &closure, UNUSED_SIZE)) goto fail; block = cbsBlockOfTree(tree); diff --git a/mps/code/fbmtest.c b/mps/code/fbmtest.c index 231d02482a7..e24fcc564ee 100644 --- a/mps/code/fbmtest.c +++ b/mps/code/fbmtest.c @@ -98,6 +98,7 @@ static Bool checkCallback(Range range, void *closureP, Size closureS) Addr base, limit; CheckFBMClosure cl = (CheckFBMClosure)closureP; + AVER(closureS == UNUSED_SIZE); UNUSED(closureS); Insist(cl != NULL); @@ -149,10 +150,10 @@ static void check(FBMState state) switch (state->type) { case FBMTypeCBS: - CBSIterate(state->the.cbs, checkCBSCallback, (void *)&closure, 0); + CBSIterate(state->the.cbs, checkCBSCallback, &closure, UNUSED_SIZE); break; case FBMTypeFreelist: - FreelistIterate(state->the.fl, checkFLCallback, (void *)&closure, 0); + FreelistIterate(state->the.fl, checkFLCallback, &closure, UNUSED_SIZE); break; default: cdie(0, "invalid state->type"); diff --git a/mps/code/freelist.c b/mps/code/freelist.c index ca66a0b273d..2be00189aa8 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -755,7 +755,7 @@ static Bool freelistDescribeVisitor(Land land, Range range, if (!TESTT(Land, land)) return FALSE; if (!RangeCheck(range)) return FALSE; if (stream == NULL) return FALSE; - UNUSED(closureS); + if (closureS != UNUSED_SIZE) return FALSE; res = WriteF(stream, " [$P,", (WriteFP)RangeBase(range), @@ -783,7 +783,7 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream) " listSize = $U\n", (WriteFU)fl->listSize, NULL); - b = LandIterate(land, freelistDescribeVisitor, stream, 0); + b = LandIterate(land, freelistDescribeVisitor, stream, UNUSED_SIZE); if (!b) return ResFAIL; res = WriteF(stream, "}\n", NULL); diff --git a/mps/code/land.c b/mps/code/land.c index 78dc7f0b324..19f26057623 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -414,6 +414,7 @@ static Bool landFlushVisitor(Bool *deleteReturn, Land land, Range range, AVERT(Land, land); AVERT(Range, range); AVER(closureP != NULL); + AVER(closureS == UNUSED_SIZE); UNUSED(closureS); dest = closureP; @@ -438,7 +439,7 @@ Bool LandFlush(Land dest, Land src) AVERT(Land, dest); AVERT(Land, src); - return LandIterateAndDelete(src, landFlushVisitor, dest, 0); + return LandIterateAndDelete(src, landFlushVisitor, dest, UNUSED_SIZE); } @@ -494,6 +495,7 @@ static Bool landSizeVisitor(Land land, Range range, AVERT(Land, land); AVERT(Range, range); AVER(closureP != NULL); + AVER(closureS == UNUSED_SIZE); UNUSED(closureS); size = closureP; @@ -505,7 +507,7 @@ static Bool landSizeVisitor(Land land, Range range, Size LandSlowSize(Land land) { Size size = 0; - Bool b = LandIterate(land, landSizeVisitor, &size, 0); + Bool b = LandIterate(land, landSizeVisitor, &size, UNUSED_SIZE); AVER(b); return size; } diff --git a/mps/code/landtest.c b/mps/code/landtest.c index a4eb9b369e1..af6beff29ac 100644 --- a/mps/code/landtest.c +++ b/mps/code/landtest.c @@ -81,7 +81,7 @@ static Bool checkVisitor(Land land, Range range, void *closureP, Size closureS) CheckTestClosure cl = closureP; testlib_unused(land); - testlib_unused(closureS); + Insist(closureS == UNUSED_SIZE); Insist(cl != NULL); base = RangeBase(range); @@ -114,7 +114,7 @@ static void check(TestState state) closure.limit = addrOfIndex(state, ArraySize); closure.oldLimit = state->block; - b = LandIterate(state->land, checkVisitor, (void *)&closure, 0); + b = LandIterate(state->land, checkVisitor, &closure, UNUSED_SIZE); Insist(b); if (closure.oldLimit == state->block) diff --git a/mps/code/misc.h b/mps/code/misc.h index 7380421d5c5..853903b58fa 100644 --- a/mps/code/misc.h +++ b/mps/code/misc.h @@ -152,6 +152,15 @@ typedef const struct SrcIdStruct { #define UNUSED(param) ((void)param) +/* UNUSED_POINTER, UNUSED_SIZE -- values for unused arguments + * + * Use these values for unused pointer, size closure arguments and + * check them in the callback or visitor. + */ +#define UNUSED_POINTER ((Pointer)0xB60405ED) /* PointeR UNUSED */ +#define UNUSED_SIZE ((Size)0x520405ED) /* SiZe UNUSED */ + + /* PARENT -- parent structure * * Given a pointer to a field of a structure this returns a pointer to diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c index b40094d839c..c203c5697b6 100644 --- a/mps/code/poolmfs.c +++ b/mps/code/poolmfs.c @@ -151,6 +151,8 @@ void MFSFinishTracts(Pool pool, MFSTractVisitor visitor, static void MFSTractFreeVisitor(Pool pool, Addr base, Size size, void *closureP, Size closureS) { + AVER(closureP == UNUSED_POINTER); + AVER(closureS == UNUSED_SIZE); UNUSED(closureP); UNUSED(closureS); ArenaFree(base, size, pool); @@ -165,7 +167,7 @@ static void MFSFinish(Pool pool) mfs = PoolPoolMFS(pool); AVERT(MFS, mfs); - MFSFinishTracts(pool, MFSTractFreeVisitor, NULL, 0); + MFSFinishTracts(pool, MFSTractFreeVisitor, UNUSED_POINTER, UNUSED_SIZE); mfs->sig = SigInvalid; } diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index fcffea6f129..4dd85c184e5 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -754,6 +754,7 @@ static Bool MVTDeleteOverlapping(Bool *deleteReturn, void *element, AVER(deleteReturn != NULL); AVER(element != NULL); AVER(closureP != NULL); + AVER(closureS == UNUSED_SIZE); UNUSED(closureS); oldRange = element; @@ -820,7 +821,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, 0); + ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &newRange, UNUSED_SIZE); (void)MVTReserve(mvt, &newRange); } @@ -849,7 +850,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, 0); + ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &rangeOld, UNUSED_SIZE); /* 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. @@ -1211,6 +1212,7 @@ static Bool MVTRefillVisitor(Land land, Range range, AVERT(Land, land); mvt = closureP; AVERT(MVT, mvt); + AVER(closureS == UNUSED_SIZE); UNUSED(closureS); if (RangeSize(range) < mvt->reuseSize) @@ -1234,7 +1236,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(MVTFailover(mvt), MVTRefillVisitor, mvt, 0); + (void)LandIterate(MVTFailover(mvt), MVTRefillVisitor, mvt, UNUSED_SIZE); } } @@ -1266,6 +1268,7 @@ static Bool MVTContingencyVisitor(Land land, Range range, cl = closureP; mvt = cl->mvt; AVERT(MVT, mvt); + AVER(closureS == UNUSED_SIZE); UNUSED(closureS); base = RangeBase(range); @@ -1304,7 +1307,7 @@ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn, cls.steps = 0; cls.hardSteps = 0; - if (LandIterate(MVTFailover(mvt), MVTContingencyVisitor, (void *)&cls, 0)) + if (LandIterate(MVTFailover(mvt), MVTContingencyVisitor, &cls, UNUSED_SIZE)) return FALSE; AVER(RangeSize(&cls.range) >= min); From 2828487364a419ebfb809f1e14fc3dc1f537328e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 29 May 2014 17:14:32 +0100 Subject: [PATCH 255/266] Fix off-by-one error. Copied from Perforce Change: 186357 ServerID: perforce.ravenbrook.com --- mps/code/poolamc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 313e6a9dde0..fe419f1ef0c 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -877,7 +877,7 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args) if(res != ResOK) goto failGensAlloc; amc->gen = p; - for (i = 0; i <= genCount; ++i) { + for (i = 0; i < genCount; ++i) { res = amcGenCreate(&amc->gen[i], amc, ChainGen(chain, i)); if (res != ResOK) goto failGenAlloc; From 7e345e486f53b2d0cfe956b6e80146257c9a8e31 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 29 May 2014 17:21:51 +0100 Subject: [PATCH 256/266] Better fix for the off-by-one error (chaingen already has the topgen logic). Copied from Perforce Change: 186358 ServerID: perforce.ravenbrook.com --- mps/code/poolamc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index fe419f1ef0c..7470ea70934 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -877,14 +877,11 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args) if(res != ResOK) goto failGensAlloc; amc->gen = p; - for (i = 0; i < genCount; ++i) { + for (i = 0; i <= genCount; ++i) { res = amcGenCreate(&amc->gen[i], amc, ChainGen(chain, i)); if (res != ResOK) goto failGenAlloc; } - res = amcGenCreate(&amc->gen[genCount], amc, &arena->topGen); - if (res != ResOK) - goto failGenAlloc; /* Set up forwarding buffers. */ for(i = 0; i < genCount; ++i) { amcBufSetGen(amc->gen[i]->forward, amc->gen[i+1]); From d59108f214a998e8617ab888126e9e4054ef2f6e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 30 May 2014 10:56:12 +0100 Subject: [PATCH 257/266] Fix problems noted by rb in review . Copied from Perforce Change: 186361 ServerID: perforce.ravenbrook.com --- mps/code/locus.c | 43 ++++++++++++++++++++++++++++++++++--------- mps/code/misc.h | 13 +++++++++++++ mps/code/poolamc.c | 7 +++++-- mps/code/tract.h | 5 +---- mps/design/arena.txt | 11 +++++------ mps/design/type.txt | 9 ++++++--- 6 files changed, 64 insertions(+), 24 deletions(-) diff --git a/mps/code/locus.c b/mps/code/locus.c index 6c0b7776ee4..e6ba0af02d9 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -250,7 +250,9 @@ GenDesc ChainGen(Chain chain, Index gen) } -/* PoolGenAlloc -- allocate a segment in a pool generation */ +/* PoolGenAlloc -- allocate a segment in a pool generation and update + * accounting + */ Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size, Bool withReservoirPermit, ArgList args) @@ -479,7 +481,12 @@ Bool PoolGenCheck(PoolGen pgen) /* PoolGenFill -- accounting for allocation * - * The memory was free, is now new (or newDeferred). + * Call this when the pool allocates memory to the client program via + * BufferFill. The deferred flag indicates whether the accounting of + * this memory (for the purpose of scheduling collections) should be + * deferred until later. + * + * See */ void PoolGenFill(PoolGen pgen, Size size, Bool deferred) @@ -500,7 +507,11 @@ void PoolGenFill(PoolGen pgen, Size size, Bool deferred) /* PoolGenEmpty -- accounting for emptying a buffer * - * The unused part of the buffer was new (or newDeferred) and is now free. + * Call this when the client program returns memory (that was never + * condemned) to the pool via BufferEmpty. The deferred flag is as for + * PoolGenFill. + * + * See */ void PoolGenEmpty(PoolGen pgen, Size unused, Bool deferred) @@ -519,9 +530,13 @@ void PoolGenEmpty(PoolGen pgen, Size unused, Bool deferred) } -/* PoolGenAge -- accounting for condemning a segment +/* PoolGenAge -- accounting for condemning * - * The memory was new (or newDeferred), is now old (or oldDeferred) + * Call this when memory is condemned via PoolWhiten. The size + * parameter should be the amount of memory that is being condemned + * for the first time. The deferred flag is as for PoolGenFill. + * + * See */ void PoolGenAge(PoolGen pgen, Size size, Bool deferred) @@ -542,7 +557,10 @@ void PoolGenAge(PoolGen pgen, Size size, Bool deferred) /* PoolGenReclaim -- accounting for reclaiming * - * The reclaimed memory was old, and is now free. + * Call this when reclaiming memory, passing the amount of memory that + * was reclaimed. The deferred flag is as for PoolGenFill. + * + * See */ void PoolGenReclaim(PoolGen pgen, Size reclaimed, Bool deferred) @@ -563,9 +581,13 @@ void PoolGenReclaim(PoolGen pgen, Size reclaimed, Bool deferred) } -/* PoolGenUndefer -- accounting for end of ramp mode +/* PoolGenUndefer -- finish deferring accounting * - * The memory was oldDeferred or newDeferred, is now old or new. + * Call this when exiting ramp mode, passing the amount of old + * (condemned at least once) and new (never condemned) memory whose + * accounting was deferred (for example, during a ramp). + * + * See */ void PoolGenUndefer(PoolGen pgen, Size oldSize, Size newSize) @@ -605,7 +627,10 @@ void PoolGenSegMerge(PoolGen pgen) /* PoolGenFree -- free a segment and update accounting * - * The segment is assumed to finish free. + * Call this when all the memory is the segment is accounted as free. + * (If not, call PoolGenAge and then PoolGenReclaim first.) + * + * See */ void PoolGenFree(PoolGen pgen, Seg seg) diff --git a/mps/code/misc.h b/mps/code/misc.h index 853903b58fa..7b080fe9863 100644 --- a/mps/code/misc.h +++ b/mps/code/misc.h @@ -178,6 +178,19 @@ typedef const struct SrcIdStruct { ((type *)(void *)((char *)(p) - offsetof(type, field))) + +/* BOOLFIELD -- declare a Boolean bitfield + * + * A Boolean bitfield needs to be unsigned (not Bool), so that its + * values are 0 and 1 (not 0 and -1), in order to avoid a sign + * conversion (which would be a compiler error) when assigning TRUE to + * the field. + * + * See + */ +#define BOOLFIELD(name) unsigned name : 1 + + /* BITFIELD -- coerce a value into a bitfield * * This coerces value to the given width and type in a way that avoids diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 7470ea70934..1377d15ddb5 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -94,8 +94,8 @@ typedef struct amcSegStruct { GCSegStruct gcSegStruct; /* superclass fields must come first */ amcGen gen; /* generation this segment belongs to */ Nailboard board; /* nailboard for this segment or NULL if none */ - unsigned old : 1; /* .seg.old */ - unsigned deferred : 1; /* .seg.deferred */ + BOOLFIELD(old); /* .seg.old */ + BOOLFIELD(deferred); /* .seg.deferred */ Sig sig; /* */ } amcSegStruct; @@ -1111,6 +1111,9 @@ static void AMCBufferEmpty(Pool pool, Buffer buffer, ShieldCover(arena, seg); } + /* The unused part of the buffer is not reused by AMC, so we pass 0 + * for the unused argument. This call therefore has no effect on the + * accounting, but we call it anyway for consistency. */ PoolGenEmpty(&amcSegGen(seg)->pgen, 0, Seg2amcSeg(seg)->deferred); } diff --git a/mps/code/tract.h b/mps/code/tract.h index c359032feee..b957e024fd1 100644 --- a/mps/code/tract.h +++ b/mps/code/tract.h @@ -37,9 +37,6 @@ typedef union PagePoolUnion { * * .tract: Tracts represent the grains of memory allocation from * the arena. See . - * - * .bool: The hasSeg field is a boolean, but can't be represented - * as type Bool. See . */ typedef struct TractStruct { /* Tract structure */ @@ -47,7 +44,7 @@ typedef struct TractStruct { /* Tract structure */ void *p; /* pointer for use of owning pool */ Addr base; /* Base address of the tract */ TraceSet white : TraceLIMIT; /* traces for which tract is white */ - unsigned hasSeg : 1; /* does tract have a seg in p? See .bool */ + BOOLFIELD(hasSeg); /* does tract have a seg in p? */ } TractStruct; diff --git a/mps/design/arena.txt b/mps/design/arena.txt index a1fae81ce5e..0532213c294 100644 --- a/mps/design/arena.txt +++ b/mps/design/arena.txt @@ -237,7 +237,7 @@ _`.tract.structure`: The tract structure definition looks like this:: void *p; /* pointer for use of owning pool */ Addr base; /* Base address of the tract */ TraceSet white : TRACE_MAX; /* traces for which tract is white */ - unsigned int hasSeg : 1; /* does tract have a seg in p? */ + BOOLFIELD(hasSeg); /* does tract have a seg in p? */ } TractStruct; _`.tract.field.pool`: The pool.pool field indicates to which pool the tract @@ -262,10 +262,9 @@ use it for any purpose. _`.tract.field.hasSeg`: The ``hasSeg`` bit-field is a Boolean which indicates whether the ``p`` field is being used by the segment module. -If this field is ``TRUE``, then the value of ``p`` is a ``Seg``. -``hasSeg`` is typed as an ``unsigned int``, rather than a ``Bool``. -This ensures that there won't be sign conversion problems when -converting the bit-field value. +If this field is ``TRUE``, then the value of ``p`` is a ``Seg``. See +design.mps.type.bool.bitfield for why this is declared using the +``BOOLFIELD`` macro. _`.tract.field.base`: The base field contains the base address of the memory represented by the tract. @@ -273,7 +272,7 @@ memory represented by the tract. _`.tract.field.white`: The white bit-field indicates for which traces the tract is white (`.req.fun.trans.white`_). This information is also stored in the segment, but is duplicated here for efficiency during a -call to ``TraceFix`` (see design.mps.trace.fix). +call to ``TraceFix()`` (see design.mps.trace.fix). _`.tract.limit`: The limit of the tract's memory may be determined by adding the arena alignment to the base address. diff --git a/mps/design/type.txt b/mps/design/type.txt index baee04ef3d2..1bf254e581d 100644 --- a/mps/design/type.txt +++ b/mps/design/type.txt @@ -155,9 +155,12 @@ _`.bool.bitfield`: When a Boolean needs to be stored in a bitfield, the type of the bitfield must be ``unsigned:1``, not ``Bool:1``. (That's because the two values of the type ``Bool:1`` are ``0`` and ``-1``, which means that assigning ``TRUE`` would require a sign -conversion.) To avoid warnings about loss of data from GCC with the -``-Wconversion`` option, ``misc.h`` provides the ``BOOLOF`` macro for -coercing a value to an unsigned single-bit field. +conversion.) To make it clear why this is done, ``misc.h`` provides +the ``BOOLFIELD`` macro. + +_`.bool.bitfield.assign`: To avoid warnings about loss of data from +GCC with the ``-Wconversion`` option, ``misc.h`` provides the +``BOOLOF`` macro for coercing a value to an unsigned single-bit field. ``typedef unsigned BufferMode`` From e5903c950a79ed9e1d41176770cff7e073a834e1 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 30 May 2014 10:58:10 +0100 Subject: [PATCH 258/266] Fix typo. Copied from Perforce Change: 186362 ServerID: perforce.ravenbrook.com --- mps/code/locus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/locus.c b/mps/code/locus.c index e6ba0af02d9..5b98d768e1b 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -627,7 +627,7 @@ void PoolGenSegMerge(PoolGen pgen) /* PoolGenFree -- free a segment and update accounting * - * Call this when all the memory is the segment is accounted as free. + * Call this when all the memory in the segment is accounted as free. * (If not, call PoolGenAge and then PoolGenReclaim first.) * * See From 0449a44337e3e1c68ca2084684cd6f783c7cf87e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 30 May 2014 11:36:52 +0100 Subject: [PATCH 259/266] Amc supports interior pointers. Copied from Perforce Change: 186364 ServerID: perforce.ravenbrook.com --- mps/manual/source/pool/amc.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mps/manual/source/pool/amc.rst b/mps/manual/source/pool/amc.rst index 4f326b9f78f..e09cef8cb14 100644 --- a/mps/manual/source/pool/amc.rst +++ b/mps/manual/source/pool/amc.rst @@ -24,8 +24,8 @@ except for blocks that are :term:`pinned ` by It uses :term:`generational garbage collection`. That is, it exploits assumptions about object lifetimes and inter-connection variously -referred to as "the generational hypothesis". In particular, the -following tendencies will be efficiently exploited by an AMC pool: +referred to as "the :term:`generational hypothesis`". In particular, +the following tendencies will be efficiently exploited by an AMC pool: - most objects die young; @@ -72,8 +72,10 @@ AMC properties * Blocks are :term:`scanned `. -* Blocks may only be referenced by :term:`base pointers` (unless they - have :term:`in-band headers`). +* Blocks may be referenced by :term:`interior pointers` (unless + :c:macro:`MPS_KEY_INTERIOR` is set to ``FALSE``, in which case only + :term:`base pointers`, or :term:`client pointers` if the blocks + have :term:`in-band headers`, are supported). * Blocks may be protected by :term:`barriers (1)`. From 7c71849813b7668c80075612b149bbe677676dc2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 30 May 2014 12:17:02 +0100 Subject: [PATCH 260/266] Defend against the visitor function modifying the block. Copied from Perforce Change: 186367 ServerID: perforce.ravenbrook.com --- mps/code/freelist.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/mps/code/freelist.c b/mps/code/freelist.c index 2be00189aa8..d022338a113 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -448,7 +448,7 @@ static Bool freelistIterate(Land land, LandVisitor visitor, void *closureP, Size closureS) { Freelist fl; - FreelistBlock cur; + FreelistBlock cur, next; AVERT(Land, land); fl = freelistOfLand(land); @@ -456,9 +456,12 @@ static Bool freelistIterate(Land land, LandVisitor visitor, AVER(FUNCHECK(visitor)); /* closureP and closureS are arbitrary */ - for (cur = fl->list; cur != freelistEND; cur = FreelistBlockNext(cur)) { + for (cur = fl->list; cur != freelistEND; cur = next) { RangeStruct range; Bool cont; + /* .next.first: Take next before calling the visitor, in case the + * visitor touches the block. */ + next = FreelistBlockNext(cur); RangeInit(&range, FreelistBlockBase(cur), FreelistBlockLimit(fl, cur)); cont = (*visitor)(land, &range, closureP, closureS); if (!cont) @@ -486,20 +489,21 @@ static Bool freelistIterateAndDelete(Land land, LandDeleteVisitor visitor, Bool delete = FALSE; RangeStruct range; Bool cont; + Size size; + next = FreelistBlockNext(cur); /* See .next.first. */ + size = FreelistBlockSize(fl, cur); RangeInit(&range, FreelistBlockBase(cur), FreelistBlockLimit(fl, cur)); cont = (*visitor)(&delete, land, &range, closureP, closureS); - next = FreelistBlockNext(cur); if (delete) { - Size size = FreelistBlockSize(fl, cur); freelistBlockSetPrevNext(fl, prev, next, -1); AVER(fl->size >= size); fl->size -= size; } else { prev = cur; } - cur = next; if (!cont) return FALSE; + cur = next; } return TRUE; } From 9fb9c2f319593a6b192c38b5da08555fd19bfd6e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 30 May 2014 12:29:42 +0100 Subject: [PATCH 261/266] Rename poolgen functions to make it clear that they only handle accounting. Copied from Perforce Change: 186368 ServerID: perforce.ravenbrook.com --- mps/code/chain.h | 12 ++++++------ mps/code/locus.c | 32 ++++++++++++++++---------------- mps/code/poolamc.c | 14 +++++++------- mps/code/poolams.c | 16 ++++++++-------- mps/code/poolawl.c | 12 ++++++------ mps/code/poollo.c | 12 ++++++------ mps/code/segsmss.c | 4 ++-- 7 files changed, 51 insertions(+), 51 deletions(-) diff --git a/mps/code/chain.h b/mps/code/chain.h index 706838610ec..bd2dd650dbe 100644 --- a/mps/code/chain.h +++ b/mps/code/chain.h @@ -91,13 +91,13 @@ extern void PoolGenFinish(PoolGen pgen); extern Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size, Bool withReservoirPermit, ArgList args); extern void PoolGenFree(PoolGen pgen, Seg seg); -extern void PoolGenFill(PoolGen pgen, Size size, Bool deferred); -extern void PoolGenEmpty(PoolGen pgen, Size unused, Bool deferred); -extern void PoolGenAge(PoolGen pgen, Size aged, Bool deferred); -extern void PoolGenReclaim(PoolGen pgen, Size reclaimed, Bool deferred); +extern void PoolGenAccountForFill(PoolGen pgen, Size size, Bool deferred); +extern void PoolGenAccountForEmpty(PoolGen pgen, Size unused, Bool deferred); +extern void PoolGenAccountForAge(PoolGen pgen, Size aged, Bool deferred); +extern void PoolGenAccountForReclaim(PoolGen pgen, Size reclaimed, Bool deferred); extern void PoolGenUndefer(PoolGen pgen, Size oldSize, Size newSize); -extern void PoolGenSegSplit(PoolGen pgen); -extern void PoolGenSegMerge(PoolGen pgen); +extern void PoolGenAccountForSegSplit(PoolGen pgen); +extern void PoolGenAccountForSegMerge(PoolGen pgen); #endif /* chain_h */ diff --git a/mps/code/locus.c b/mps/code/locus.c index 5b98d768e1b..9eb0fd152ac 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -479,7 +479,7 @@ Bool PoolGenCheck(PoolGen pgen) } -/* PoolGenFill -- accounting for allocation +/* PoolGenAccountForFill -- accounting for allocation * * Call this when the pool allocates memory to the client program via * BufferFill. The deferred flag indicates whether the accounting of @@ -489,7 +489,7 @@ Bool PoolGenCheck(PoolGen pgen) * See */ -void PoolGenFill(PoolGen pgen, Size size, Bool deferred) +void PoolGenAccountForFill(PoolGen pgen, Size size, Bool deferred) { AVERT(PoolGen, pgen); AVERT(Bool, deferred); @@ -505,16 +505,16 @@ void PoolGenFill(PoolGen pgen, Size size, Bool deferred) } -/* PoolGenEmpty -- accounting for emptying a buffer +/* PoolGenAccountForEmpty -- accounting for emptying a buffer * * Call this when the client program returns memory (that was never * condemned) to the pool via BufferEmpty. The deferred flag is as for - * PoolGenFill. + * PoolGenAccountForFill. * * See */ -void PoolGenEmpty(PoolGen pgen, Size unused, Bool deferred) +void PoolGenAccountForEmpty(PoolGen pgen, Size unused, Bool deferred) { AVERT(PoolGen, pgen); AVERT(Bool, deferred); @@ -530,16 +530,16 @@ void PoolGenEmpty(PoolGen pgen, Size unused, Bool deferred) } -/* PoolGenAge -- accounting for condemning +/* PoolGenAccountForAge -- accounting for condemning * * Call this when memory is condemned via PoolWhiten. The size * parameter should be the amount of memory that is being condemned - * for the first time. The deferred flag is as for PoolGenFill. + * for the first time. The deferred flag is as for PoolGenAccountForFill. * * See */ -void PoolGenAge(PoolGen pgen, Size size, Bool deferred) +void PoolGenAccountForAge(PoolGen pgen, Size size, Bool deferred) { AVERT(PoolGen, pgen); @@ -555,15 +555,15 @@ void PoolGenAge(PoolGen pgen, Size size, Bool deferred) } -/* PoolGenReclaim -- accounting for reclaiming +/* PoolGenAccountForReclaim -- accounting for reclaiming * * Call this when reclaiming memory, passing the amount of memory that - * was reclaimed. The deferred flag is as for PoolGenFill. + * was reclaimed. The deferred flag is as for PoolGenAccountForFill. * * See */ -void PoolGenReclaim(PoolGen pgen, Size reclaimed, Bool deferred) +void PoolGenAccountForReclaim(PoolGen pgen, Size reclaimed, Bool deferred) { AVERT(PoolGen, pgen); AVERT(Bool, deferred); @@ -604,18 +604,18 @@ void PoolGenUndefer(PoolGen pgen, Size oldSize, Size newSize) } -/* PoolGenSegSplit -- accounting for splitting a segment */ +/* PoolGenAccountForSegSplit -- accounting for splitting a segment */ -void PoolGenSegSplit(PoolGen pgen) +void PoolGenAccountForSegSplit(PoolGen pgen) { AVERT(PoolGen, pgen); STATISTIC(++ pgen->segs); } -/* PoolGenSegMerge -- accounting for merging a segment */ +/* PoolGenAccountForSegMerge -- accounting for merging a segment */ -void PoolGenSegMerge(PoolGen pgen) +void PoolGenAccountForSegMerge(PoolGen pgen) { AVERT(PoolGen, pgen); STATISTIC_STAT ({ @@ -628,7 +628,7 @@ void PoolGenSegMerge(PoolGen pgen) /* PoolGenFree -- free a segment and update accounting * * Call this when all the memory in the segment is accounted as free. - * (If not, call PoolGenAge and then PoolGenReclaim first.) + * (If not, call PoolGenAccountForAge and then PoolGenAccountForReclaim first.) * * See */ diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 1377d15ddb5..1f2cad0314f 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -955,10 +955,10 @@ static void AMCFinish(Pool pool) amcSeg amcseg = Seg2amcSeg(seg); if (!amcseg->old) { - PoolGenAge(&gen->pgen, SegSize(seg), amcseg->deferred); + PoolGenAccountForAge(&gen->pgen, SegSize(seg), amcseg->deferred); amcseg->old = TRUE; } - PoolGenReclaim(&gen->pgen, SegSize(seg), amcseg->deferred); + PoolGenAccountForReclaim(&gen->pgen, SegSize(seg), amcseg->deferred); PoolGenFree(&gen->pgen, seg); } @@ -1066,7 +1066,7 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn, } } - PoolGenFill(pgen, SegSize(seg), Seg2amcSeg(seg)->deferred); + PoolGenAccountForFill(pgen, SegSize(seg), Seg2amcSeg(seg)->deferred); *baseReturn = base; *limitReturn = limit; return ResOK; @@ -1114,7 +1114,7 @@ static void AMCBufferEmpty(Pool pool, Buffer buffer, /* The unused part of the buffer is not reused by AMC, so we pass 0 * for the unused argument. This call therefore has no effect on the * accounting, but we call it anyway for consistency. */ - PoolGenEmpty(&amcSegGen(seg)->pgen, 0, Seg2amcSeg(seg)->deferred); + PoolGenAccountForEmpty(&amcSegGen(seg)->pgen, 0, Seg2amcSeg(seg)->deferred); } @@ -1302,7 +1302,7 @@ static Res AMCWhiten(Pool pool, Trace trace, Seg seg) gen = amcSegGen(seg); AVERT(amcGen, gen); if (!amcseg->old) { - PoolGenAge(&gen->pgen, SegSize(seg), amcseg->deferred); + PoolGenAccountForAge(&gen->pgen, SegSize(seg), amcseg->deferred); amcseg->old = TRUE; } @@ -2004,7 +2004,7 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg) /* We may not free a buffered seg. */ AVER(SegBuffer(seg) == NULL); - PoolGenReclaim(&gen->pgen, SegSize(seg), Seg2amcSeg(seg)->deferred); + PoolGenAccountForReclaim(&gen->pgen, SegSize(seg), Seg2amcSeg(seg)->deferred); PoolGenFree(&gen->pgen, seg); } else { /* Seg retained */ @@ -2083,7 +2083,7 @@ static void AMCReclaim(Pool pool, Trace trace, Seg seg) trace->reclaimSize += SegSize(seg); - PoolGenReclaim(&gen->pgen, SegSize(seg), Seg2amcSeg(seg)->deferred); + PoolGenAccountForReclaim(&gen->pgen, SegSize(seg), Seg2amcSeg(seg)->deferred); PoolGenFree(&gen->pgen, seg); } diff --git a/mps/code/poolams.c b/mps/code/poolams.c index e6c4e7d4837..cd85651a4fe 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -399,7 +399,7 @@ static Res AMSSegMerge(Seg seg, Seg segHi, amssegHi->sig = SigInvalid; AVERT(AMSSeg, amsseg); - PoolGenSegMerge(&ams->pgen); + PoolGenAccountForSegMerge(&ams->pgen); return ResOK; failSuper: @@ -505,7 +505,7 @@ static Res AMSSegSplit(Seg seg, Seg segHi, amssegHi->sig = AMSSegSig; AVERT(AMSSeg, amsseg); AVERT(AMSSeg, amssegHi); - PoolGenSegSplit(&ams->pgen); + PoolGenAccountForSegSplit(&ams->pgen); return ResOK; failSuper: @@ -738,10 +738,10 @@ static void AMSSegsDestroy(AMS ams) AMSSeg amsseg = Seg2AMSSeg(seg); AVER(amsseg->ams == ams); AMSSegFreeCheck(amsseg); - PoolGenAge(&ams->pgen, AMSGrainsSize(ams, amsseg->newGrains), FALSE); + PoolGenAccountForAge(&ams->pgen, AMSGrainsSize(ams, amsseg->newGrains), FALSE); amsseg->oldGrains += amsseg->newGrains; amsseg->newGrains = 0; - PoolGenReclaim(&ams->pgen, AMSGrainsSize(ams, amsseg->oldGrains), FALSE); + PoolGenAccountForReclaim(&ams->pgen, AMSGrainsSize(ams, amsseg->oldGrains), FALSE); amsseg->freeGrains += amsseg->oldGrains; amsseg->oldGrains = 0; AVER(amsseg->freeGrains == amsseg->grains); @@ -999,7 +999,7 @@ static Res AMSBufferFill(Addr *baseReturn, Addr *limitReturn, DebugPoolFreeCheck(pool, baseAddr, limitAddr); allocatedSize = AddrOffset(baseAddr, limitAddr); - PoolGenFill(&ams->pgen, allocatedSize, FALSE); + PoolGenAccountForFill(&ams->pgen, allocatedSize, FALSE); *baseReturn = baseAddr; *limitReturn = limitAddr; return ResOK; @@ -1081,7 +1081,7 @@ static void AMSBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit) AVER(amsseg->newGrains >= limitIndex - initIndex); amsseg->newGrains -= limitIndex - initIndex; size = AddrOffset(init, limit); - PoolGenEmpty(&ams->pgen, size, FALSE); + PoolGenAccountForEmpty(&ams->pgen, size, FALSE); } @@ -1165,7 +1165,7 @@ static Res AMSWhiten(Pool pool, Trace trace, Seg seg) } /* The unused part of the buffer remains new: the rest becomes old. */ - PoolGenAge(&ams->pgen, AMSGrainsSize(ams, amsseg->newGrains - uncondemned), FALSE); + PoolGenAccountForAge(&ams->pgen, AMSGrainsSize(ams, amsseg->newGrains - uncondemned), FALSE); amsseg->oldGrains += amsseg->newGrains - uncondemned; amsseg->newGrains = uncondemned; amsseg->marksChanged = FALSE; /* */ @@ -1625,7 +1625,7 @@ static void AMSReclaim(Pool pool, Trace trace, Seg seg) AVER(amsseg->oldGrains >= reclaimedGrains); amsseg->oldGrains -= reclaimedGrains; amsseg->freeGrains += reclaimedGrains; - PoolGenReclaim(&ams->pgen, AMSGrainsSize(ams, reclaimedGrains), FALSE); + PoolGenAccountForReclaim(&ams->pgen, AMSGrainsSize(ams, reclaimedGrains), FALSE); trace->reclaimSize += AMSGrainsSize(ams, reclaimedGrains); /* preservedInPlaceCount is updated on fix */ trace->preservedInPlaceSize += AMSGrainsSize(ams, amsseg->oldGrains); diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 775d29d2018..ffd95c15b4d 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -609,10 +609,10 @@ static void AWLFinish(Pool pool) RING_FOR(node, ring, nextNode) { Seg seg = SegOfPoolRing(node); AWLSeg awlseg = Seg2AWLSeg(seg); - PoolGenAge(&awl->pgen, AWLGrainsSize(awl, awlseg->newGrains), FALSE); + PoolGenAccountForAge(&awl->pgen, AWLGrainsSize(awl, awlseg->newGrains), FALSE); awlseg->oldGrains += awlseg->newGrains; awlseg->newGrains = 0; - PoolGenReclaim(&awl->pgen, AWLGrainsSize(awl, awlseg->oldGrains), FALSE); + PoolGenAccountForReclaim(&awl->pgen, AWLGrainsSize(awl, awlseg->oldGrains), FALSE); awlseg->freeGrains += awlseg->oldGrains; awlseg->oldGrains = 0; AVER(awlseg->freeGrains == awlseg->grains); @@ -686,7 +686,7 @@ static Res AWLBufferFill(Addr *baseReturn, Addr *limitReturn, AVER(awlseg->freeGrains >= j - i); awlseg->freeGrains -= j - i; awlseg->newGrains += j - i; - PoolGenFill(&awl->pgen, AddrOffset(base, limit), FALSE); + PoolGenAccountForFill(&awl->pgen, AddrOffset(base, limit), FALSE); } *baseReturn = base; *limitReturn = limit; @@ -725,7 +725,7 @@ static void AWLBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit) AVER(awlseg->newGrains >= j - i); awlseg->newGrains -= j - i; awlseg->freeGrains += j - i; - PoolGenEmpty(&awl->pgen, AddrOffset(init, limit), FALSE); + PoolGenAccountForEmpty(&awl->pgen, AddrOffset(init, limit), FALSE); } } @@ -786,7 +786,7 @@ static Res AWLWhiten(Pool pool, Trace trace, Seg seg) } } - PoolGenAge(&awl->pgen, AWLGrainsSize(awl, awlseg->newGrains - uncondemned), FALSE); + PoolGenAccountForAge(&awl->pgen, AWLGrainsSize(awl, awlseg->newGrains - uncondemned), FALSE); awlseg->oldGrains += awlseg->newGrains - uncondemned; awlseg->newGrains = uncondemned; trace->condemned += AWLGrainsSize(awl, awlseg->oldGrains); @@ -1166,7 +1166,7 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg) AVER(awlseg->oldGrains >= reclaimedGrains); awlseg->oldGrains -= reclaimedGrains; awlseg->freeGrains += reclaimedGrains; - PoolGenReclaim(&awl->pgen, AWLGrainsSize(awl, reclaimedGrains), FALSE); + PoolGenAccountForReclaim(&awl->pgen, AWLGrainsSize(awl, reclaimedGrains), FALSE); trace->reclaimSize += AWLGrainsSize(awl, reclaimedGrains); trace->preservedInPlaceCount += preservedInPlaceCount; diff --git a/mps/code/poollo.c b/mps/code/poollo.c index 06d3e68160f..a75fc0b5ba3 100644 --- a/mps/code/poollo.c +++ b/mps/code/poollo.c @@ -382,7 +382,7 @@ static void loSegReclaim(LOSeg loseg, Trace trace) AVER(loseg->oldGrains >= reclaimedGrains); loseg->oldGrains -= reclaimedGrains; loseg->freeGrains += reclaimedGrains; - PoolGenReclaim(&lo->pgen, LOGrainsSize(lo, reclaimedGrains), FALSE); + PoolGenAccountForReclaim(&lo->pgen, LOGrainsSize(lo, reclaimedGrains), FALSE); trace->reclaimSize += LOGrainsSize(lo, reclaimedGrains); trace->preservedInPlaceCount += preservedInPlaceCount; @@ -540,10 +540,10 @@ static void LOFinish(Pool pool) AVERT(LOSeg, loseg); UNUSED(loseg); /* */ - PoolGenAge(&lo->pgen, LOGrainsSize(lo, loseg->newGrains), FALSE); + PoolGenAccountForAge(&lo->pgen, LOGrainsSize(lo, loseg->newGrains), FALSE); loseg->oldGrains += loseg->newGrains; loseg->newGrains = 0; - PoolGenReclaim(&lo->pgen, LOGrainsSize(lo, loseg->oldGrains), FALSE); + PoolGenAccountForReclaim(&lo->pgen, LOGrainsSize(lo, loseg->oldGrains), FALSE); loseg->freeGrains += loseg->oldGrains; loseg->oldGrains = 0; AVER(loseg->freeGrains == loSegGrains(loseg)); @@ -612,7 +612,7 @@ static Res LOBufferFill(Addr *baseReturn, Addr *limitReturn, loseg->newGrains += limitIndex - baseIndex; } - PoolGenFill(&lo->pgen, AddrOffset(base, limit), FALSE); + PoolGenAccountForFill(&lo->pgen, AddrOffset(base, limit), FALSE); *baseReturn = base; *limitReturn = limit; @@ -667,7 +667,7 @@ static void LOBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit) AVER(loseg->newGrains >= limitIndex - initIndex); loseg->newGrains -= limitIndex - initIndex; loseg->freeGrains += limitIndex - initIndex; - PoolGenEmpty(&lo->pgen, AddrOffset(init, limit), FALSE); + PoolGenAccountForEmpty(&lo->pgen, AddrOffset(init, limit), FALSE); } } @@ -709,7 +709,7 @@ static Res LOWhiten(Pool pool, Trace trace, Seg seg) BTCopyInvertRange(loseg->alloc, loseg->mark, 0, grains); } - PoolGenAge(&lo->pgen, LOGrainsSize(lo, loseg->newGrains - uncondemned), FALSE); + PoolGenAccountForAge(&lo->pgen, LOGrainsSize(lo, loseg->newGrains - uncondemned), FALSE); loseg->oldGrains += loseg->newGrains - uncondemned; loseg->newGrains = uncondemned; trace->condemned += LOGrainsSize(lo, loseg->oldGrains); diff --git a/mps/code/segsmss.c b/mps/code/segsmss.c index 1db6c98d8f2..20cedf67dd2 100644 --- a/mps/code/segsmss.c +++ b/mps/code/segsmss.c @@ -467,7 +467,7 @@ static void AMSUnallocateRange(AMS ams, Seg seg, Addr base, Addr limit) amsseg->freeGrains += limitIndex - baseIndex; AVER(amsseg->newGrains >= limitIndex - baseIndex); amsseg->newGrains -= limitIndex - baseIndex; - PoolGenEmpty(&ams->pgen, AddrOffset(base, limit), FALSE); + PoolGenAccountForEmpty(&ams->pgen, AddrOffset(base, limit), FALSE); } @@ -507,7 +507,7 @@ static void AMSAllocateRange(AMS ams, Seg seg, Addr base, Addr limit) AVER(amsseg->freeGrains >= limitIndex - baseIndex); amsseg->freeGrains -= limitIndex - baseIndex; amsseg->newGrains += limitIndex - baseIndex; - PoolGenFill(&ams->pgen, AddrOffset(base, limit), FALSE); + PoolGenAccountForFill(&ams->pgen, AddrOffset(base, limit), FALSE); } From d6e27d318345c1dde22be4a0e2784d14d80bc815 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 30 May 2014 13:41:59 +0100 Subject: [PATCH 262/266] Gcbench and djbench don't need to link against mps.lib (they include mps.c instead). Copied from Perforce Change: 186377 ServerID: perforce.ravenbrook.com --- mps/code/commpost.nmk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk index 40beeb7fc58..96fca59e250 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/commpost.nmk @@ -157,7 +157,7 @@ $(PFM)\$(VARIETY)\cvmicv.exe: $(PFM)\$(VARIETY)\cvmicv.obj \ $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) $(PFM)\$(VARIETY)\djbench.exe: $(PFM)\$(VARIETY)\djbench.obj \ - $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) $(TESTTHROBJ) + $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)\$(VARIETY)\exposet0.exe: $(PFM)\$(VARIETY)\exposet0.obj \ $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) @@ -175,7 +175,7 @@ $(PFM)\$(VARIETY)\fotest.exe: $(PFM)\$(VARIETY)\fotest.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) $(PFM)\$(VARIETY)\gcbench.exe: $(PFM)\$(VARIETY)\gcbench.obj \ - $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ) + $(FMTTESTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)\$(VARIETY)\landtest.exe: $(PFM)\$(VARIETY)\landtest.obj \ $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) From 66f67b0681abb9dbe5c4c833dc3c5ddce4dfc597 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 30 May 2014 13:42:22 +0100 Subject: [PATCH 263/266] Avoid "warning c4306: 'type cast' : conversion from 'unsigned int' to 'pointer' of greater size" on w3i6mv. Copied from Perforce Change: 186378 ServerID: perforce.ravenbrook.com --- mps/code/misc.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mps/code/misc.h b/mps/code/misc.h index 853903b58fa..a5fca0f0f42 100644 --- a/mps/code/misc.h +++ b/mps/code/misc.h @@ -156,8 +156,12 @@ typedef const struct SrcIdStruct { * * Use these values for unused pointer, size closure arguments and * check them in the callback or visitor. + * + * We use PointerAdd rather than a cast to avoid "warning C4306: 'type + * cast' : conversion from 'unsigned int' to 'Pointer' of greater + * size" on platform w3i6mv. */ -#define UNUSED_POINTER ((Pointer)0xB60405ED) /* PointeR UNUSED */ +#define UNUSED_POINTER PointerAdd(0, 0xB60405ED) /* PointeR UNUSED */ #define UNUSED_SIZE ((Size)0x520405ED) /* SiZe UNUSED */ From f7b6693641931ec247ea07aedd807b442804109b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 8 Jun 2014 12:42:17 +0100 Subject: [PATCH 264/266] More stringent checking in poolgenaccountforseg{split,merge}, as suggested by dl in . Copied from Perforce Change: 186426 ServerID: perforce.ravenbrook.com --- mps/code/locus.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mps/code/locus.c b/mps/code/locus.c index 9eb0fd152ac..d7fb4f038f6 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -609,7 +609,10 @@ void PoolGenUndefer(PoolGen pgen, Size oldSize, Size newSize) void PoolGenAccountForSegSplit(PoolGen pgen) { AVERT(PoolGen, pgen); - STATISTIC(++ pgen->segs); + STATISTIC_STAT ({ + AVER(pgen->segs >= 1); /* must be at least one segment to split */ + ++ pgen->segs; + }); } @@ -619,7 +622,7 @@ void PoolGenAccountForSegMerge(PoolGen pgen) { AVERT(PoolGen, pgen); STATISTIC_STAT ({ - AVER(pgen->segs > 0); + AVER(pgen->segs >= 2); /* must be at least two segments to merge */ -- pgen->segs; }); } From e8bb8ecedb993fa364df45924e794264ea7e1ce5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 8 Jun 2014 13:12:12 +0100 Subject: [PATCH 265/266] Encapsulate the artifical ageing and reclaiming that's need to ensure that all the memory in a segment is accounted as free. addresses point made by rb in Copied from Perforce Change: 186428 ServerID: perforce.ravenbrook.com --- mps/code/chain.h | 7 ++++--- mps/code/locus.c | 15 ++++++++++++--- mps/code/poolamc.c | 19 ++++++++----------- mps/code/poolams.c | 20 +++++++++++--------- mps/code/poolawl.c | 20 +++++++++++--------- mps/code/poollo.c | 22 ++++++++++------------ mps/design/strategy.txt | 9 +++++++-- 7 files changed, 63 insertions(+), 49 deletions(-) diff --git a/mps/code/chain.h b/mps/code/chain.h index bd2dd650dbe..87cfa08dd71 100644 --- a/mps/code/chain.h +++ b/mps/code/chain.h @@ -1,7 +1,7 @@ /* chain.h: GENERATION CHAINS * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. */ #ifndef chain_h @@ -90,7 +90,8 @@ 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); -extern void PoolGenFree(PoolGen pgen, Seg seg); +extern void PoolGenFree(PoolGen pgen, Seg seg, Size freeSize, Size oldSize, + Size newSize, Bool deferred); extern void PoolGenAccountForFill(PoolGen pgen, Size size, Bool deferred); extern void PoolGenAccountForEmpty(PoolGen pgen, Size unused, Bool deferred); extern void PoolGenAccountForAge(PoolGen pgen, Size aged, Bool deferred); @@ -104,7 +105,7 @@ extern void PoolGenAccountForSegMerge(PoolGen pgen); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/locus.c b/mps/code/locus.c index d7fb4f038f6..537eea666e8 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -630,13 +630,15 @@ void PoolGenAccountForSegMerge(PoolGen pgen) /* PoolGenFree -- free a segment and update accounting * - * Call this when all the memory in the segment is accounted as free. - * (If not, call PoolGenAccountForAge and then PoolGenAccountForReclaim first.) + * Pass the amount of memory in the segment that is accounted as free, + * old, or new, respectively. The deferred flag is as for + * PoolGenAccountForFill. * * See */ -void PoolGenFree(PoolGen pgen, Seg seg) +void PoolGenFree(PoolGen pgen, Seg seg, Size freeSize, Size oldSize, + Size newSize, Bool deferred) { Size size; @@ -644,6 +646,13 @@ void PoolGenFree(PoolGen pgen, Seg seg) AVERT(Seg, seg); size = SegSize(seg); + AVER(freeSize + oldSize + newSize == size); + + /* Pretend to age and reclaim the contents of the segment to ensure + * that the entire segment is accounted as free. */ + PoolGenAccountForAge(pgen, newSize, deferred); + PoolGenAccountForReclaim(pgen, oldSize + newSize, deferred); + AVER(pgen->totalSize >= size); pgen->totalSize -= size; STATISTIC_STAT ({ diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 1f2cad0314f..20c5a168cdd 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -953,13 +953,12 @@ static void AMCFinish(Pool pool) Seg seg = SegOfPoolRing(node); amcGen gen = amcSegGen(seg); amcSeg amcseg = Seg2amcSeg(seg); - - if (!amcseg->old) { - PoolGenAccountForAge(&gen->pgen, SegSize(seg), amcseg->deferred); - amcseg->old = TRUE; - } - PoolGenAccountForReclaim(&gen->pgen, SegSize(seg), amcseg->deferred); - PoolGenFree(&gen->pgen, seg); + AVERT(amcSeg, amcseg); + PoolGenFree(&gen->pgen, seg, + 0, + amcseg->old ? SegSize(seg) : 0, + amcseg->old ? 0 : SegSize(seg), + amcseg->deferred); } /* Disassociate forwarding buffers from gens before they are */ @@ -2004,8 +2003,7 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg) /* We may not free a buffered seg. */ AVER(SegBuffer(seg) == NULL); - PoolGenAccountForReclaim(&gen->pgen, SegSize(seg), Seg2amcSeg(seg)->deferred); - PoolGenFree(&gen->pgen, seg); + PoolGenFree(&gen->pgen, seg, 0, SegSize(seg), 0, Seg2amcSeg(seg)->deferred); } else { /* Seg retained */ STATISTIC_STAT( { @@ -2083,8 +2081,7 @@ static void AMCReclaim(Pool pool, Trace trace, Seg seg) trace->reclaimSize += SegSize(seg); - PoolGenAccountForReclaim(&gen->pgen, SegSize(seg), Seg2amcSeg(seg)->deferred); - PoolGenFree(&gen->pgen, seg); + PoolGenFree(&gen->pgen, seg, 0, SegSize(seg), 0, Seg2amcSeg(seg)->deferred); } diff --git a/mps/code/poolams.c b/mps/code/poolams.c index cd85651a4fe..b5e942c7e84 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -736,16 +736,14 @@ static void AMSSegsDestroy(AMS ams) RING_FOR(node, ring, next) { Seg seg = SegOfPoolRing(node); AMSSeg amsseg = Seg2AMSSeg(seg); + AVERT(AMSSeg, amsseg); AVER(amsseg->ams == ams); AMSSegFreeCheck(amsseg); - PoolGenAccountForAge(&ams->pgen, AMSGrainsSize(ams, amsseg->newGrains), FALSE); - amsseg->oldGrains += amsseg->newGrains; - amsseg->newGrains = 0; - PoolGenAccountForReclaim(&ams->pgen, AMSGrainsSize(ams, amsseg->oldGrains), FALSE); - amsseg->freeGrains += amsseg->oldGrains; - amsseg->oldGrains = 0; - AVER(amsseg->freeGrains == amsseg->grains); - PoolGenFree(&ams->pgen, seg); + PoolGenFree(&ams->pgen, seg, + AMSGrainsSize(ams, amsseg->freeGrains), + AMSGrainsSize(ams, amsseg->oldGrains), + AMSGrainsSize(ams, amsseg->newGrains), + FALSE); } } @@ -1636,7 +1634,11 @@ static void AMSReclaim(Pool pool, Trace trace, Seg seg) if (amsseg->freeGrains == grains && SegBuffer(seg) == NULL) /* No survivors */ - PoolGenFree(&ams->pgen, seg); + PoolGenFree(&ams->pgen, seg, + AMSGrainsSize(ams, amsseg->freeGrains), + AMSGrainsSize(ams, amsseg->oldGrains), + AMSGrainsSize(ams, amsseg->newGrains), + FALSE); } diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index ffd95c15b4d..31af1dcd160 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -609,14 +609,12 @@ static void AWLFinish(Pool pool) RING_FOR(node, ring, nextNode) { Seg seg = SegOfPoolRing(node); AWLSeg awlseg = Seg2AWLSeg(seg); - PoolGenAccountForAge(&awl->pgen, AWLGrainsSize(awl, awlseg->newGrains), FALSE); - awlseg->oldGrains += awlseg->newGrains; - awlseg->newGrains = 0; - PoolGenAccountForReclaim(&awl->pgen, AWLGrainsSize(awl, awlseg->oldGrains), FALSE); - awlseg->freeGrains += awlseg->oldGrains; - awlseg->oldGrains = 0; - AVER(awlseg->freeGrains == awlseg->grains); - PoolGenFree(&awl->pgen, seg); + AVERT(AWLSeg, awlseg); + PoolGenFree(&awl->pgen, seg, + AWLGrainsSize(awl, awlseg->freeGrains), + AWLGrainsSize(awl, awlseg->oldGrains), + AWLGrainsSize(awl, awlseg->newGrains), + FALSE); } awl->sig = SigInvalid; PoolGenFinish(&awl->pgen); @@ -1175,7 +1173,11 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg) if (awlseg->freeGrains == awlseg->grains && buffer == NULL) /* No survivors */ - PoolGenFree(&awl->pgen, seg); + PoolGenFree(&awl->pgen, seg, + AWLGrainsSize(awl, awlseg->freeGrains), + AWLGrainsSize(awl, awlseg->oldGrains), + AWLGrainsSize(awl, awlseg->newGrains), + FALSE); } diff --git a/mps/code/poollo.c b/mps/code/poollo.c index a75fc0b5ba3..af93c12bd13 100644 --- a/mps/code/poollo.c +++ b/mps/code/poollo.c @@ -391,7 +391,11 @@ static void loSegReclaim(LOSeg loseg, Trace trace) SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace)); if (!marked) - PoolGenFree(&lo->pgen, seg); + PoolGenFree(&lo->pgen, seg, + LOGrainsSize(lo, loseg->freeGrains), + LOGrainsSize(lo, loseg->oldGrains), + LOGrainsSize(lo, loseg->newGrains), + FALSE); } /* This walks over _all_ objects in the heap, whether they are */ @@ -536,18 +540,12 @@ static void LOFinish(Pool pool) RING_FOR(node, &pool->segRing, nextNode) { Seg seg = SegOfPoolRing(node); LOSeg loseg = SegLOSeg(seg); - AVERT(LOSeg, loseg); - UNUSED(loseg); /* */ - - PoolGenAccountForAge(&lo->pgen, LOGrainsSize(lo, loseg->newGrains), FALSE); - loseg->oldGrains += loseg->newGrains; - loseg->newGrains = 0; - PoolGenAccountForReclaim(&lo->pgen, LOGrainsSize(lo, loseg->oldGrains), FALSE); - loseg->freeGrains += loseg->oldGrains; - loseg->oldGrains = 0; - AVER(loseg->freeGrains == loSegGrains(loseg)); - PoolGenFree(&lo->pgen, seg); + PoolGenFree(&lo->pgen, seg, + LOGrainsSize(lo, loseg->freeGrains), + LOGrainsSize(lo, loseg->oldGrains), + LOGrainsSize(lo, loseg->newGrains), + FALSE); } PoolGenFinish(&lo->pgen); diff --git a/mps/design/strategy.txt b/mps/design/strategy.txt index 3ab1402d8dd..40b88863af9 100644 --- a/mps/design/strategy.txt +++ b/mps/design/strategy.txt @@ -270,8 +270,13 @@ _`.accounting.op`: The following operations are provided: _`.accounting.op.alloc`: Allocate a segment in a pool generation. Debit *total*, credit *free*. (But see `.account.total.negated`_.) -_`.accounting.op.free`: Free a segment. Debit *free*, credit *total*. -(But see `.account.total.negated`_.) +_`.accounting.op.free`: Free a segment. First, ensure that the +contents of the segment are accounted as free, by artificially ageing +any memory accounted as *new* or *newDeferred* (see +`.accounting.op.age`_) and then artifically reclaiming any memory +accounted as *old* or *oldDeferred* (see `.accounting.op.reclaim`_). +Finally, debit *free*, credit *total*. (But see +`.account.total.negated`_.) _`.accounting.op.fill`: Allocate memory, for example by filling a buffer. Debit *free*, credit *new* or *newDeferred*. From f2447e74fd0956d9573f09fa42589a7bd64f636a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 8 Jun 2014 15:20:50 +0100 Subject: [PATCH 266/266] Fix the build on fri3gc. Copied from Perforce Change: 186436 ServerID: perforce.ravenbrook.com --- mps/code/poolamc.c | 4 ++-- mps/code/poolawl.c | 2 +- mps/code/poollo.c | 2 +- mps/design/type.txt | 5 +++++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 20c5a168cdd..82e7998a2db 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -113,8 +113,8 @@ static Bool amcSegCheck(amcSeg amcseg) CHECKD(Nailboard, amcseg->board); CHECKL(SegNailed(amcSeg2Seg(amcseg)) != TraceSetEMPTY); } - CHECKL(BoolCheck(amcseg->old)); - CHECKL(BoolCheck(amcseg->deferred)); + /* CHECKL(BoolCheck(amcseg->old)); */ + /* CHECKL(BoolCheck(amcseg->deferred)); */ return TRUE; } diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 31af1dcd160..eb2b561eb4b 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -1325,7 +1325,7 @@ static Bool AWLCheck(AWL awl) CHECKS(AWL, awl); CHECKD(Pool, &awl->poolStruct); CHECKL(awl->poolStruct.class == AWLPoolClassGet()); - CHECKL(AWLGrainsSize(awl, 1) == awl->poolStruct.alignment); + CHECKL(AWLGrainsSize(awl, (Count)1) == awl->poolStruct.alignment); /* Nothing to check about succAccesses. */ CHECKL(FUNCHECK(awl->findDependent)); /* Don't bother to check stats. */ diff --git a/mps/code/poollo.c b/mps/code/poollo.c index af93c12bd13..c9b093c960e 100644 --- a/mps/code/poollo.c +++ b/mps/code/poollo.c @@ -836,7 +836,7 @@ static Bool LOCheck(LO lo) CHECKD(Pool, &lo->poolStruct); CHECKL(lo->poolStruct.class == EnsureLOPoolClass()); CHECKL(ShiftCheck(lo->alignShift)); - CHECKL(LOGrainsSize(lo, 1) == PoolAlignment(&lo->poolStruct)); + CHECKL(LOGrainsSize(lo, (Count)1) == PoolAlignment(&lo->poolStruct)); CHECKD(PoolGen, &lo->pgen); return TRUE; } diff --git a/mps/design/type.txt b/mps/design/type.txt index 1bf254e581d..9197c4b36ac 100644 --- a/mps/design/type.txt +++ b/mps/design/type.txt @@ -162,6 +162,11 @@ _`.bool.bitfield.assign`: To avoid warnings about loss of data from GCC with the ``-Wconversion`` option, ``misc.h`` provides the ``BOOLOF`` macro for coercing a value to an unsigned single-bit field. +_`.bool.bitfield.check`: A Boolean bitfield cannot have an incorrect +value, and if you call ``BoolCheck()`` on such a bitfield then GCC 4.2 +issues the warning "comparison is always true due to limited range of +data type". When avoiding such a warning, reference this tag. + ``typedef unsigned BufferMode``