diff --git a/mps/code/arena.c b/mps/code/arena.c
index a5ca9dbb19f..dc2f008303c 100644
--- a/mps/code/arena.c
+++ b/mps/code/arena.c
@@ -461,6 +461,21 @@ void ControlFree(Arena arena, void* base, size_t size)
}
+/* ControlDescribe -- describe the arena's control pool */
+
+Res ControlDescribe(Arena arena, mps_lib_FILE *stream)
+{
+ Res res;
+
+ if (!CHECKT(Arena, arena)) return ResFAIL;
+ if (stream == NULL) return ResFAIL;
+
+ res = PoolDescribe(ArenaControlPool(arena), stream);
+
+ return res;
+}
+
+
/* ArenaAlloc -- allocate some tracts from the arena */
Res ArenaAlloc(Addr *baseReturn, SegPref pref, Size size, Pool pool,
diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk
index bbc9ecbb619..e8e5bb6383b 100644
--- a/mps/code/comm.gmk
+++ b/mps/code/comm.gmk
@@ -393,7 +393,7 @@ $(PFM)/$(VARIETY)/lockcov: $(PFM)/$(VARIETY)/lockcov.o \
$(MPMOBJ) $(PLINTHOBJ) $(TESTLIBOBJ)
$(PFM)/$(VARIETY)/mpsicv: $(PFM)/$(VARIETY)/mpsicv.o \
- $(FMTDYTSTOBJ) $(MPMOBJ) $(PLINTHOBJ) $(AMCOBJ) $(TESTLIBOBJ)
+ $(FMTDYTSTOBJ) $(FMTHETSTOBJ) $(MPMOBJ) $(PLINTHOBJ) $(AMCOBJ) $(TESTLIBOBJ)
$(PFM)/$(VARIETY)/amcss: $(PFM)/$(VARIETY)/amcss.o \
$(FMTDYTSTOBJ) $(MPMOBJ) $(PLINTHOBJ) $(AMCOBJ) $(TESTLIBOBJ)
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index fc56e1e5062..467bf9f7d67 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -501,6 +501,7 @@ extern void ControlFinish(Arena arena);
extern Res ControlAlloc(void **baseReturn, Arena arena, size_t size,
Bool withReservoirPermit);
extern void ControlFree(Arena arena, void *base, size_t size);
+extern Res ControlDescribe(Arena arena, mps_lib_FILE *stream);
/* Peek/Poke
diff --git a/mps/code/mpsicv.c b/mps/code/mpsicv.c
index dbc8c1484b1..dea398b4097 100644
--- a/mps/code/mpsicv.c
+++ b/mps/code/mpsicv.c
@@ -9,6 +9,7 @@
#include "mpscamc.h"
#include "mpsavm.h"
#include "mpscmv.h"
+#include "fmthe.h"
#include "fmtdy.h"
#include "fmtdytst.h"
#include "mps.h"
@@ -38,6 +39,29 @@ static mps_gen_param_s testChain[genCOUNT] = {
static mps_pool_t amcpool;
static mps_ap_t ap;
+static size_t ap_headerSIZE = 0;
+/* For this ap.... */
+/* Auto_header format
+ *
+ * [ auto_header ][===object===]
+ * ^pMps ^pCli
+ * <-----------sizeMps--------->
+ * <---sizeCli-->
+ *
+ * Note: pMps < pCli; sizeMps > sizeCli.
+ */
+#define PtrMps2Cli(n) ((char*)n + ap_headerSIZE)
+#define PtrCli2Mps(n) ((char*)n - ap_headerSIZE)
+#define SizeMps2Cli(n) (n - ap_headerSIZE)
+#define SizeCli2Mps(n) (n + ap_headerSIZE)
+#define HeaderInit(pMps) do { \
+ if(ap_headerSIZE != 0) { \
+ mps_addr_t pMps_MACROCOPY = (pMps); /* macro hygiene */ \
+ ((int*)pMps_MACROCOPY)[0] = realHeader; \
+ ((int*)pMps_MACROCOPY)[1] = 0xED0ED; \
+ } \
+ } while(0)
+
static mps_addr_t exactRoots[exactRootsCOUNT];
static mps_addr_t ambigRoots[ambigRootsCOUNT];
@@ -103,18 +127,22 @@ static void alignmentTest(mps_arena_t arena)
static mps_addr_t make(void)
{
- size_t length = rnd() % 20, size = (length+2)*sizeof(mps_word_t);
- mps_addr_t p;
+ size_t length = rnd() % 20;
+ size_t sizeCli = (length+2)*sizeof(mps_word_t);
+ size_t sizeMps = SizeCli2Mps(sizeCli);
+ mps_addr_t pMps, pCli;
mps_res_t res;
do {
- MPS_RESERVE_BLOCK(res, p, ap, size);
+ MPS_RESERVE_BLOCK(res, pMps, ap, sizeMps);
if (res != MPS_RES_OK) die(res, "MPS_RESERVE_BLOCK");
- res = dylan_init(p, size, exactRoots, exactRootsCOUNT);
+ HeaderInit(pMps);
+ pCli = PtrMps2Cli(pMps);
+ res = dylan_init(pCli, sizeCli, exactRoots, exactRootsCOUNT);
if (res != MPS_RES_OK) die(res, "dylan_init");
- } while(!mps_commit(ap, p, size));
+ } while(!mps_commit(ap, pMps, sizeMps));
- return p;
+ return pCli;
}
@@ -122,18 +150,22 @@ static mps_addr_t make(void)
static mps_addr_t make_with_permit(void)
{
- size_t length = rnd() % 20, size = (length+2)*sizeof(mps_word_t);
- mps_addr_t p;
+ size_t length = rnd() % 20;
+ size_t sizeCli = (length+2)*sizeof(mps_word_t);
+ size_t sizeMps = SizeCli2Mps(sizeCli);
+ mps_addr_t pMps, pCli;
mps_res_t res;
do {
- MPS_RESERVE_WITH_RESERVOIR_PERMIT_BLOCK(res, p, ap, size);
+ MPS_RESERVE_WITH_RESERVOIR_PERMIT_BLOCK(res, pMps, ap, sizeMps);
if (res != MPS_RES_OK) die(res, "MPS_RESERVE_WITH_RESERVOIR_PERMIT_BLOCK");
- res = dylan_init(p, size, exactRoots, exactRootsCOUNT);
+ HeaderInit(pMps);
+ pCli = PtrMps2Cli(pMps);
+ res = dylan_init(pCli, sizeCli, exactRoots, exactRootsCOUNT);
if (res != MPS_RES_OK) die(res, "dylan_init");
- } while(!mps_commit(ap, p, size));
+ } while(!mps_commit(ap, pMps, sizeMps));
- return p;
+ return pCli;
}
@@ -141,18 +173,22 @@ static mps_addr_t make_with_permit(void)
static mps_addr_t make_no_inline(void)
{
- size_t length = rnd() % 20, size = (length+2)*sizeof(mps_word_t);
- mps_addr_t p;
+ size_t length = rnd() % 20;
+ size_t sizeCli = (length+2)*sizeof(mps_word_t);
+ size_t sizeMps = SizeCli2Mps(sizeCli);
+ mps_addr_t pMps, pCli;
mps_res_t res;
do {
- res = (mps_reserve)(&p, ap, size);
+ res = (mps_reserve)(&pMps, ap, sizeMps);
if (res != MPS_RES_OK) die(res, "(mps_reserve)");
- res = dylan_init(p, size, exactRoots, exactRootsCOUNT);
+ HeaderInit(pMps);
+ pCli = PtrMps2Cli(pMps);
+ res = dylan_init(pCli, sizeCli, exactRoots, exactRootsCOUNT);
if (res != MPS_RES_OK) die(res, "dylan_init");
- } while(!(mps_commit)(ap, p, size));
+ } while(!(mps_commit)(ap, pMps, sizeMps));
- return p;
+ return pCli;
}
@@ -290,7 +326,16 @@ static void *test(void *arg, size_t s)
arena = (mps_arena_t)arg;
testlib_unused(s);
- die(dylan_fmt(&format, arena), "fmt_create");
+ if (rnd() & 1) {
+ printf("Using auto_header format.\n");
+ EnsureHeaderFormat(&format, arena);
+ ap_headerSIZE = headerSIZE; /* from fmthe.h */
+ } else {
+ printf("Using normal format (no implicit object header: client pointers point at start of storage).\n");
+ die(dylan_fmt(&format, arena), "fmt_create");
+ ap_headerSIZE = 0;
+ }
+
die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
die(mps_pool_create(&mv, arena, mps_class_mv(), 0x10000, 32, 0x10000),
@@ -402,8 +447,8 @@ static void *test(void *arg, size_t s)
cdie(rampCount > 0 ? res == MPS_RES_OK : res == MPS_RES_FAIL,
"alloc_pattern_end");
if (rampCount > 0) {
- --rampCount;
- }
+ --rampCount;
+ }
break;
case 3:
die(mps_ap_alloc_pattern_reset(ap), "alloc_pattern_reset");
@@ -483,7 +528,7 @@ int main(int argc, char **argv)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2002, 2008 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c
index 7ab6e5b9875..de524d53803 100644
--- a/mps/code/poolamc.c
+++ b/mps/code/poolamc.c
@@ -736,7 +736,8 @@ static void amcSegDestroyNailboard(Seg seg, Pool pool)
AVERT(amcNailboard, board);
arena = PoolArena(pool);
- bits = SegSize(seg) >> board->markShift;
+ /* See d.m.p.Nailboard.size. */
+ bits = (SegSize(seg) + pool->format->headerSize) >> board->markShift;
ControlFree(arena, board->mark, BTSize(bits));
board->sig = SigInvalid;
ControlFree(arena, board, sizeof(amcNailboardStruct));
@@ -2280,7 +2281,7 @@ static Bool AMCCheck(AMC amc)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2002, 2008 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/readme.txt b/mps/readme.txt
index e6a7af65bf5..61e09d5736f 100644
--- a/mps/readme.txt
+++ b/mps/readme.txt
@@ -53,13 +53,32 @@ record of changes. In a release of the MPS-Kit, this section becomes
the summary of what is new for that release.)
[
-......Post 1.108.0 changes:
+......Post 1.108.1 changes:
This is release A.BBB.C, made on YYYY-MM-DD.
Changes from release A.BBB.C-1:
Functional changes to MPS code:
+
+Defect discovered:
+ - when using an auto_header format (mps_fmt_create_auto_header)
+ with AMC pools (mps_class_amc), the MPS leaks a small amount of
+ memory on each collection.
+Impact:
+ - the leak is likely to be a few bytes per collection, and at most
+ one byte per page (typically 2^12 bytes) of the address-space
+ currently in use for objects in AMC pools;
+ - the leak is of temporary memory that the MPS uses to process
+ ambiguous references (typically references on the stack and in
+ registers), so a larger stack when a collection starts will
+ tend to cause a larger leak;
+ - the leaked bytes are widely-spaced single bytes which therefore
+ also cause fragmentation;
+ - the leaked bytes are not reclaimed until the client calls
+ mps_arena_destroy().
+Fixed: correctly release all of this temporary memory.
+
Other changes:
]
@@ -449,7 +468,7 @@ B. DOCUMENT HISTORY
C. COPYRIGHT AND LICENSE
-Copyright (C) 2001-2002, 2006-2007 Ravenbrook Limited.
+Copyright (C) 2001-2002, 2006-2007, 2008 Ravenbrook Limited.
All rights reserved. .
This is an open source license.
Contact Ravenbrook for commercial licensing options.