diff --git a/mps/code/amsss.c b/mps/code/amsss.c index d87ebe95c02..d6a4265d182 100644 --- a/mps/code/amsss.c +++ b/mps/code/amsss.c @@ -105,7 +105,7 @@ static mps_addr_t make(void) /* test -- the actual stress test */ static mps_pool_debug_option_s freecheckOptions = - { NULL, 0, (const void *)"Dead", 4 }; + { NULL, 0, (void *)"Dead", 4 }; static void test_pool(mps_class_t pool_class, mps_arg_s args[], mps_bool_t haveAmbiguous) diff --git a/mps/code/apss.c b/mps/code/apss.c index 8c90536fa00..81edbe7d04d 100644 --- a/mps/code/apss.c +++ b/mps/code/apss.c @@ -43,28 +43,25 @@ static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size) /* stress -- create a pool of the requested type and allocate in it */ -static mps_res_t stress(mps_class_t class, size_t (*size)(size_t i), - mps_arena_t arena, ...) +static mps_res_t stress(mps_arena_t arena, mps_align_t align, + size_t (*size)(size_t i, mps_align_t align), + const char *name, mps_class_t class, mps_arg_s args[]) { mps_res_t res = MPS_RES_OK; mps_pool_t pool; mps_ap_t ap; - va_list arg; size_t i, k; int *ps[testSetSIZE]; size_t ss[testSetSIZE]; - va_start(arg, arena); - res = mps_pool_create_v(&pool, arena, class, arg); - va_end(arg); - if (res != MPS_RES_OK) - return res; + printf("stress %s\n", name); + die(mps_pool_create_k(&pool, arena, class, args), "pool_create"); die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate"); /* allocate a load of objects */ for (i=0; i> (i / 10)), 2) + 1, MPS_PF_ALIGN); + return alignUp(rnd() % max((maxSize >> (i / 10)), 2) + 1, align); } static mps_pool_debug_option_s bothOptions = { - /* .fence_template = */ (const void *)"postpostpostpost", - /* .fence_size = */ MPS_PF_ALIGN, - /* .free_template = */ (const void *)"DEAD", + /* .fence_template = */ (void *)"post", + /* .fence_size = */ 4, + /* .free_template = */ (void *)"DEAD", /* .free_size = */ 4 }; static mps_pool_debug_option_s fenceOptions = { - /* .fence_template = */ (const void *)"\0XXX ''\"\"'' XXX\0", - /* .fence_size = */ 16, + /* .fence_template = */ (void *)"123456789abcdef", + /* .fence_size = */ 15, /* .free_template = */ NULL, /* .free_size = */ 0 }; + /* testInArena -- test all the pool classes in the given arena */ static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options) { - mps_res_t res; + MPS_ARGS_BEGIN(args) { + mps_align_t align = sizeof(void *) << (rnd() % 4); + MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE); + die(stress(arena, align, randomSizeAligned, "MVFF", mps_class_mvff(), args), + "stress MVFF"); + } MPS_ARGS_END(args); /* IWBN to test MVFFDebug, but the MPS doesn't support debugging APs, */ /* yet (MV Debug works here, because it fakes it through PoolAlloc). */ - printf("MVFF\n"); - res = stress(mps_class_mvff(), randomSizeAligned, arena, - (size_t)65536, (size_t)32, (mps_align_t)MPS_PF_ALIGN, TRUE, TRUE, TRUE); - if (res == MPS_RES_COMMIT_LIMIT) return; - die(res, "stress MVFF"); - printf("MV debug\n"); - res = stress(mps_class_mv_debug(), randomSizeAligned, arena, - options, (size_t)65536, (size_t)32, (size_t)65536); - if (res == MPS_RES_COMMIT_LIMIT) return; - die(res, "stress MV debug"); + MPS_ARGS_BEGIN(args) { + mps_align_t align = 1 << (rnd() % 6); + MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); + die(stress(arena, align, randomSizeAligned, "MV", mps_class_mv(), args), + "stress MV"); + } MPS_ARGS_END(args); - printf("MV\n"); - res = stress(mps_class_mv(), randomSizeAligned, arena, - (size_t)65536, (size_t)32, (size_t)65536); - if (res == MPS_RES_COMMIT_LIMIT) return; - die(res, "stress MV"); + MPS_ARGS_BEGIN(args) { + mps_align_t align = 1 << (rnd() % 6); + MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); + MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options); + die(stress(arena, align, randomSizeAligned, "MV debug", + mps_class_mv_debug(), args), + "stress MV debug"); + } MPS_ARGS_END(args); - printf("MVT\n"); - res = stress(mps_class_mvt(), randomSizeAligned, arena, - (size_t)8, (size_t)32, (size_t)65536, (mps_word_t)4, - (mps_word_t)50); - if (res == MPS_RES_COMMIT_LIMIT) return; - die(res, "stress MVT"); + MPS_ARGS_BEGIN(args) { + mps_align_t align = sizeof(void *) << (rnd() % 4); + MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); + die(stress(arena, align, randomSizeAligned, "MVT", mps_class_mvt(), args), + "stress MVT"); + } MPS_ARGS_END(args); } diff --git a/mps/code/config.h b/mps/code/config.h index bf9731c5875..cf4e4c27ade 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -354,6 +354,7 @@ /* Pool MV Configuration -- see */ +#define MV_ALIGN_DEFAULT MPS_PF_ALIGN #define MV_EXTEND_BY_DEFAULT ((Size)65536) #define MV_AVG_SIZE_DEFAULT ((Size)32) #define MV_MAX_SIZE_DEFAULT ((Size)65536) diff --git a/mps/code/dbgpool.c b/mps/code/dbgpool.c index 77c1d6eaf40..79e34c603ac 100644 --- a/mps/code/dbgpool.c +++ b/mps/code/dbgpool.c @@ -123,10 +123,17 @@ Bool PoolDebugOptionsCheck(PoolDebugOptions opt) ARG_DEFINE_KEY(pool_debug_options, PoolDebugOptions); +static char debugFencepostTemplate[4] = {'P', 'O', 'S', 'T'}; +static char debugFreeTemplate[4] = {'D', 'E', 'A', 'D'}; + +static PoolDebugOptionsStruct debugPoolOptionsDefault = { + debugFencepostTemplate, 4, debugFreeTemplate, 4, +}; + static Res DebugPoolInit(Pool pool, ArgList args) { Res res; - PoolDebugOptions options; + PoolDebugOptions options = &debugPoolOptionsDefault; PoolDebugMixin debug; TagInitMethod tagInit; Size tagSize; @@ -134,10 +141,8 @@ static Res DebugPoolInit(Pool pool, ArgList args) AVERT(Pool, pool); - /* TODO: Split this structure into separate keyword arguments, - now that we can support them. */ - ArgRequire(&arg, args, MPS_KEY_POOL_DEBUG_OPTIONS); - options = (PoolDebugOptions)arg.val.pool_debug_options; + if (ArgPick(&arg, args, MPS_KEY_POOL_DEBUG_OPTIONS)) + options = (PoolDebugOptions)arg.val.pool_debug_options; AVERT(PoolDebugOptions, options); @@ -158,10 +163,6 @@ static Res DebugPoolInit(Pool pool, ArgList args) /* into Addr memory, to avoid breaking . */ debug->fenceSize = options->fenceSize; if (debug->fenceSize != 0) { - if (debug->fenceSize % PoolAlignment(pool) != 0) { - res = ResPARAM; - goto alignFail; - } /* Fenceposting turns on tagging */ if (tagInit == NULL) { tagSize = 0; @@ -176,10 +177,6 @@ static Res DebugPoolInit(Pool pool, ArgList args) /* into Addr memory, to avoid breaking . */ debug->freeSize = options->freeSize; if (debug->freeSize != 0) { - if (PoolAlignment(pool) % debug->freeSize != 0) { - res = ResPARAM; - goto alignFail; - } debug->freeTemplate = options->freeTemplate; } @@ -205,7 +202,6 @@ static Res DebugPoolInit(Pool pool, ArgList args) return ResOK; tagFail: -alignFail: SuperclassOfPool(pool)->finish(pool); AVER(res != ResOK); return res; @@ -231,38 +227,119 @@ static void DebugPoolFinish(Pool pool) } -/* freeSplat -- splat free block with splat pattern +/* patternCopy -- copy pattern to fill a range * - * If base is in a segment, the whole block has to be in it. + * Fill the range of addresses from base (inclusive) to limit + * (exclusive) with copies of pattern (which is size bytes long). + * + * Keep in sync with patternCheck. */ +static void patternCopy(Addr pattern, Size size, Addr base, Addr limit) +{ + Addr p; + + AVER(pattern != NULL); + AVER(0 < size); + AVER(base != NULL); + AVER(base <= limit); + + p = base; + while (p < limit) { + Addr end = AddrAdd(p, size); + Addr rounded = AddrRoundUp(p, size); + Size offset = (Word)p % size; + if (end < p || rounded < p) { + /* Address range overflow */ + break; + } else if (p == rounded && end <= limit) { + /* Room for a whole copy */ + (void)AddrCopy(p, pattern, size); + p = end; + } else if (p < rounded && rounded <= end && rounded <= limit) { + /* Copy up to rounded */ + (void)AddrCopy(p, (char *)pattern + offset, AddrOffset(p, rounded)); + p = rounded; + } else { + /* Copy up to limit */ + AVER(limit <= end && (p == rounded || limit <= rounded)); + (void)AddrCopy(p, (char *)pattern + offset, AddrOffset(p, limit)); + p = limit; + } + } +} + +/* patternCheck -- check pattern against a range + * + * Compare the range of addresses from base (inclusive) to limit + * (exclusive) with copies of pattern (which is size bytes long). The + * copies of pattern must be arranged so that fresh copies start at + * aligned addresses wherever possible. + * + * Keep in sync with patternCopy. + */ + +static Bool patternCheck(Addr pattern, Size size, Addr base, Addr limit) +{ + Addr p; + + AVER(pattern != NULL); + AVER(0 < size); + AVER(base != NULL); + AVER(base <= limit); + + p = base; + while (p < limit) { + Addr end = AddrAdd(p, size); + Addr rounded = AddrRoundUp(p, size); + Size offset = (Word)p % size; + if (end < p || rounded < p) { + /* Address range overflow */ + break; + } else if (p == rounded && end <= limit) { + /* Room for a whole copy */ + if (AddrComp(p, pattern, size) != 0) + return FALSE; + p = end; + } else if (p < rounded && rounded <= end && rounded <= limit) { + /* Copy up to rounded */ + if (AddrComp(p, (char *)pattern + offset, AddrOffset(p, rounded)) != 0) + return FALSE; + p = rounded; + } else { + /* Copy up to limit */ + AVER(limit <= end && (p == rounded || limit <= rounded)); + if (AddrComp(p, (char *)pattern + offset, AddrOffset(p, limit)) != 0) + return FALSE; + p = limit; + } + } + + return TRUE; +} + + +/* freeSplat -- splat free block with splat pattern */ + static void freeSplat(PoolDebugMixin debug, Pool pool, Addr base, Addr limit) { - Addr p, next; - Size freeSize = debug->freeSize; Arena arena; - Seg seg = NULL; /* suppress "may be used uninitialized" */ - Bool inSeg; + Seg seg; AVER(base < limit); /* If the block is in a segment, make sure any shield is up. */ arena = PoolArena(pool); - inSeg = SegOfAddr(&seg, arena, base); - if (inSeg) { - AVER(limit <= SegLimit(seg)); - ShieldExpose(arena, seg); + if (SegOfAddr(&seg, arena, base)) { + do { + ShieldExpose(arena, seg); + } while (SegLimit(seg) < limit && SegNext(&seg, arena, seg)); } - /* Write as many copies of the template as fit in the block. */ - for (p = base, next = AddrAdd(p, freeSize); - next <= limit && p < next /* watch out for overflow in next */; - p = next, next = AddrAdd(next, freeSize)) - (void)AddrCopy(p, debug->freeTemplate, freeSize); - /* Fill the tail of the block with a partial copy of the template. */ - if (next > limit || next < p) - (void)AddrCopy(p, debug->freeTemplate, AddrOffset(p, limit)); - if (inSeg) { - ShieldCover(arena, seg); + patternCopy(debug->freeTemplate, debug->freeSize, base, limit); + if (SegOfAddr(&seg, arena, base)) { + do { + ShieldCover(arena, seg); + } while (SegLimit(seg) < limit && SegNext(&seg, arena, seg)); } } @@ -271,40 +348,24 @@ static void freeSplat(PoolDebugMixin debug, Pool pool, Addr base, Addr limit) static Bool freeCheck(PoolDebugMixin debug, Pool pool, Addr base, Addr limit) { - Addr p, next; - Size freeSize = debug->freeSize; - Res res; + Bool res; Arena arena; - Seg seg = NULL; /* suppress "may be used uninitialized" */ - Bool inSeg; + Seg seg; AVER(base < limit); /* If the block is in a segment, make sure any shield is up. */ arena = PoolArena(pool); - inSeg = SegOfAddr(&seg, arena, base); - if (inSeg) { - AVER(limit <= SegLimit(seg)); - ShieldExpose(arena, seg); + if (SegOfAddr(&seg, arena, base)) { + do { + ShieldExpose(arena, seg); + } while (SegLimit(seg) < limit && SegNext(&seg, arena, seg)); } - /* Compare this to the AddrCopys in freeSplat. */ - /* Check the complete copies of the template in the block. */ - for (p = base, next = AddrAdd(p, freeSize); - next <= limit && p < next /* watch out for overflow in next */; - p = next, next = AddrAdd(next, freeSize)) - if (AddrComp(p, debug->freeTemplate, freeSize) != 0) { - res = FALSE; goto done; - } - /* Check the partial copy of the template at the tail of the block. */ - if (next > limit || next < p) - if (AddrComp(p, debug->freeTemplate, AddrOffset(p, limit)) != 0) { - res = FALSE; goto done; - } - res = TRUE; - -done: - if (inSeg) { - ShieldCover(arena, seg); + res = patternCheck(debug->freeTemplate, debug->freeSize, base, limit); + if (SegOfAddr(&seg, arena, base)) { + do { + ShieldCover(arena, seg); + } while (SegLimit(seg) < limit && SegNext(&seg, arena, seg)); } return res; } @@ -351,63 +412,75 @@ static void freeCheckFree(PoolDebugMixin debug, * start fp client object slop end fp * * slop is the extra allocation from rounding up the client request to - * the pool's alignment. The fenceposting code does this, so there's a - * better chance of the end fencepost being flush with the next object - * (can't be guaranteed, since the underlying pool could have allocated - * an even larger block). The alignment slop is filled from the - * fencepost template as well (as much as fits, .fence.size guarantees - * the template is larger). + * the pool's alignment. The fenceposting code adds this slop so that + * there's a better chance of the end fencepost being flush with the + * next object (though it can't be guaranteed, since the underlying + * pool could have allocated an even larger block). The alignment slop + * is filled from the fencepost template as well. + * + * Keep in sync with fenceCheck. */ static Res fenceAlloc(Addr *aReturn, PoolDebugMixin debug, Pool pool, Size size, Bool withReservoir) { Res res; - Addr new, clientNew; - Size alignedSize; + Addr obj, startFence, clientNew, clientLimit, limit; + Size alignedFenceSize, alignedSize; AVER(aReturn != NULL); + AVERT(PoolDebugMixin, debug); + AVERT(Pool, pool); + alignedFenceSize = SizeAlignUp(debug->fenceSize, PoolAlignment(pool)); alignedSize = SizeAlignUp(size, PoolAlignment(pool)); - res = freeCheckAlloc(&new, debug, pool, alignedSize + 2*debug->fenceSize, + res = freeCheckAlloc(&obj, debug, pool, + alignedSize + 2 * alignedFenceSize, withReservoir); if (res != ResOK) return res; - clientNew = AddrAdd(new, debug->fenceSize); + + startFence = obj; + clientNew = AddrAdd(startFence, alignedFenceSize); + clientLimit = AddrAdd(clientNew, size); + limit = AddrAdd(clientNew, alignedSize + alignedFenceSize); + /* @@@@ shields? */ - /* start fencepost */ - (void)AddrCopy(new, debug->fenceTemplate, debug->fenceSize); - /* alignment slop */ - (void)AddrCopy(AddrAdd(clientNew, size), - debug->fenceTemplate, alignedSize - size); - /* end fencepost */ - (void)AddrCopy(AddrAdd(clientNew, alignedSize), - debug->fenceTemplate, debug->fenceSize); + patternCopy(debug->fenceTemplate, debug->fenceSize, startFence, clientNew); + patternCopy(debug->fenceTemplate, debug->fenceSize, clientLimit, limit); *aReturn = clientNew; - return res; + return ResOK; } -/* fenceCheck -- check fences of an object */ +/* fenceCheck -- check fences of an object + * + * Keep in sync with fenceAlloc. + */ static Bool fenceCheck(PoolDebugMixin debug, Pool pool, Addr obj, Size size) { - Size alignedSize; + Addr startFence, clientNew, clientLimit, limit; + Size alignedFenceSize, alignedSize; AVERT_CRITICAL(PoolDebugMixin, debug); AVERT_CRITICAL(Pool, pool); /* Can't check obj */ + alignedFenceSize = SizeAlignUp(debug->fenceSize, PoolAlignment(pool)); alignedSize = SizeAlignUp(size, PoolAlignment(pool)); + + startFence = AddrSub(obj, alignedFenceSize); + clientNew = obj; + clientLimit = AddrAdd(clientNew, size); + limit = AddrAdd(clientNew, alignedSize + alignedFenceSize); + /* @@@@ shields? */ - /* Compare this to the AddrCopys in fenceAlloc */ - return (AddrComp(AddrSub(obj, debug->fenceSize), debug->fenceTemplate, - debug->fenceSize) == 0 - && AddrComp(AddrAdd(obj, size), debug->fenceTemplate, - alignedSize - size) == 0 - && AddrComp(AddrAdd(obj, alignedSize), debug->fenceTemplate, - debug->fenceSize) == 0); + return patternCheck(debug->fenceTemplate, debug->fenceSize, + startFence, clientNew) + && patternCheck(debug->fenceTemplate, debug->fenceSize, + clientLimit, limit); } @@ -416,13 +489,14 @@ static Bool fenceCheck(PoolDebugMixin debug, Pool pool, Addr obj, Size size) static void fenceFree(PoolDebugMixin debug, Pool pool, Addr old, Size size) { - Size alignedSize; + Size alignedFenceSize, alignedSize; ASSERT(fenceCheck(debug, pool, old, size), "fencepost check on free"); + alignedFenceSize = SizeAlignUp(debug->fenceSize, PoolAlignment(pool)); alignedSize = SizeAlignUp(size, PoolAlignment(pool)); - freeCheckFree(debug, pool, AddrSub(old, debug->fenceSize), - alignedSize + 2*debug->fenceSize); + freeCheckFree(debug, pool, AddrSub(old, alignedFenceSize), + alignedSize + 2 * alignedFenceSize); } diff --git a/mps/code/freelist.h b/mps/code/freelist.h index c46ab57bc15..900b10e28f5 100644 --- a/mps/code/freelist.h +++ b/mps/code/freelist.h @@ -1,7 +1,7 @@ /* freelist.h: FREE LIST ALLOCATOR INTERFACE * * $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: . */ @@ -13,6 +13,8 @@ typedef struct FreelistStruct *Freelist; +#define FreelistMinimumAlignment ((Align)sizeof(FreelistBlock)) + extern Bool FreelistCheck(Freelist freelist); extern LandClass FreelistLandClassGet(void); @@ -22,7 +24,7 @@ extern LandClass FreelistLandClassGet(void); /* 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/gc.gmk b/mps/code/gc.gmk index 76716dc0785..d0ea64d404f 100644 --- a/mps/code/gc.gmk +++ b/mps/code/gc.gmk @@ -25,8 +25,7 @@ CFLAGSCOMPILER := \ -Wshadow \ -Wstrict-aliasing=2 \ -Wstrict-prototypes \ - -Wswitch-default \ - -Wwrite-strings + -Wswitch-default CFLAGSCOMPILERSTRICT := -ansi -pedantic # A different set of compiler flags for less strict compilation, for diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 9d5854b8cf6..e141edb2bc5 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -87,6 +87,7 @@ extern Addr (AddrAlignDown)(Addr addr, Align align); #define AddrIsAligned(p, a) WordIsAligned((Word)(p), a) #define AddrAlignUp(p, a) ((Addr)WordAlignUp((Word)(p), a)) +#define AddrRoundUp(p, r) ((Addr)WordRoundUp((Word)(p), r)) #define SizeIsAligned(s, a) WordIsAligned((Word)(s), a) #define SizeAlignUp(s, a) ((Size)WordAlignUp((Word)(s), a)) diff --git a/mps/code/mpmss.c b/mps/code/mpmss.c index 339ae5b54f4..a2019bca0f5 100644 --- a/mps/code/mpmss.c +++ b/mps/code/mpmss.c @@ -25,19 +25,19 @@ /* stress -- create a pool of the requested type and allocate in it */ -static mps_res_t stress(mps_class_t class, size_t (*size)(size_t i), - mps_arena_t arena, ...) +static mps_res_t stress(mps_arena_t arena, size_t (*size)(size_t i), + const char *name, mps_class_t pool_class, + mps_arg_s *args) { mps_res_t res; mps_pool_t pool; - va_list arg; size_t i, k; int *ps[testSetSIZE]; size_t ss[testSetSIZE]; - va_start(arg, arena); - res = mps_pool_create_v(&pool, arena, class, arg); - va_end(arg); + printf("%s\n", name); + + res = mps_pool_create_k(&pool, arena, pool_class, args); if (res != MPS_RES_OK) return res; @@ -87,7 +87,7 @@ static mps_res_t stress(mps_class_t class, size_t (*size)(size_t i), } -/* randomSize -- produce sizes both latge and small */ +/* randomSize -- produce sizes both large and small */ static size_t randomSize(size_t i) { @@ -99,7 +99,7 @@ static size_t randomSize(size_t i) } -/* randomSize8 -- produce sizes both latge and small, 8-byte aligned */ +/* randomSize8 -- produce sizes both large and small, 8-byte aligned */ static size_t randomSize8(size_t i) { @@ -121,61 +121,90 @@ static size_t fixedSize(size_t i) static mps_pool_debug_option_s bothOptions = { - /* .fence_template = */ (const void *)"postpostpostpost", - /* .fence_size = */ MPS_PF_ALIGN, - /* .free_template = */ (const void *)"DEAD", + /* .fence_template = */ (void *)"post", + /* .fence_size = */ 4, + /* .free_template = */ (void *)"DEAD", /* .free_size = */ 4 }; static mps_pool_debug_option_s fenceOptions = { - /* .fence_template = */ (const void *)"\0XXX ''\"\"'' XXX\0", - /* .fence_size = */ 16, + /* .fence_template = */ (void *)"123456789abcdef", + /* .fence_size = */ 15, /* .free_template = */ NULL, /* .free_size = */ 0 }; /* testInArena -- test all the pool classes in the given arena */ -static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options) +static void testInArena(mps_arena_class_t arena_class, mps_arg_s *arena_args, + mps_pool_debug_option_s *options) { - /* IWBN to test MVFFDebug, but the MPS doesn't support debugging */ - /* cross-segment allocation (possibly MVFF ought not to). */ - printf("MVFF\n"); - die(stress(mps_class_mvff(), randomSize8, arena, - (size_t)65536, (size_t)32, (mps_align_t)MPS_PF_ALIGN, TRUE, TRUE, TRUE), - "stress MVFF"); - printf("MV debug\n"); - die(stress(mps_class_mv_debug(), randomSize, arena, - options, (size_t)65536, (size_t)32, (size_t)65536), - "stress MV debug"); + mps_arena_t arena; - printf("MFS\n"); - fixedSizeSize = 13; - die(stress(mps_class_mfs(), fixedSize, arena, (size_t)100000, fixedSizeSize), + die(mps_arena_create_k(&arena, arena_class, arena_args), + "mps_arena_create"); + + MPS_ARGS_BEGIN(args) { + mps_align_t align = sizeof(void *) << (rnd() % 4); + MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE); + die(stress(arena, randomSize8, "MVFF", mps_class_mvff(), args), + "stress MVFF"); + } MPS_ARGS_END(args); + + MPS_ARGS_BEGIN(args) { + mps_align_t align = sizeof(void *) << (rnd() % 4); + MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE); + MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options); + die(stress(arena, randomSize8, "MVFF debug", mps_class_mvff_debug(), args), + "stress MVFF debug"); + } MPS_ARGS_END(args); + + MPS_ARGS_BEGIN(args) { + mps_align_t align = 1 << (rnd() % 6); + MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); + die(stress(arena, randomSize, "MV", mps_class_mv(), args), + "stress MV"); + } MPS_ARGS_END(args); + + MPS_ARGS_BEGIN(args) { + mps_align_t align = 1 << (rnd() % 6); + MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); + MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options); + die(stress(arena, randomSize, "MV debug", mps_class_mv_debug(), args), + "stress MV debug"); + } MPS_ARGS_END(args); + + MPS_ARGS_BEGIN(args) { + fixedSizeSize = 1 + rnd() % 64; + MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, fixedSizeSize); + MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, 100000); + die(stress(arena, fixedSize, "MFS", mps_class_mfs(), args), "stress MFS"); + } MPS_ARGS_END(args); - printf("MV\n"); - die(stress(mps_class_mv(), randomSize, arena, - (size_t)65536, (size_t)32, (size_t)65536), - "stress MV"); + mps_arena_destroy(arena); } int main(int argc, char *argv[]) { - mps_arena_t arena; - testlib_init(argc, argv); - die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), - "mps_arena_create"); - testInArena(arena, &bothOptions); - mps_arena_destroy(arena); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE); + testInArena(mps_arena_class_vm(), args, &bothOptions); + } MPS_ARGS_END(args); - die(mps_arena_create(&arena, mps_arena_class_vm(), smallArenaSIZE), - "mps_arena_create"); - testInArena(arena, &fenceOptions); - mps_arena_destroy(arena); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, smallArenaSIZE); + testInArena(mps_arena_class_vm(), args, &fenceOptions); + } MPS_ARGS_END(args); printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); return 0; diff --git a/mps/code/mps.h b/mps/code/mps.h index 9f56309d81e..f927ea48b30 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -326,9 +326,9 @@ typedef struct _mps_sac_s { /* .sacc: Keep in sync with . */ typedef struct mps_sac_class_s { - size_t _block_size; - size_t _cached_count; - unsigned _frequency; + size_t mps_block_size; + size_t mps_cached_count; + unsigned mps_frequency; } mps_sac_class_s; #define mps_sac_classes_s mps_sac_class_s @@ -754,9 +754,9 @@ extern void mps_arena_roots_walk(mps_arena_t, typedef struct mps_pool_debug_option_s { - const void *fence_template; + void *fence_template; size_t fence_size; - const void *free_template; + void *free_template; size_t free_size; } mps_pool_debug_option_s; diff --git a/mps/code/mpscmv2.h b/mps/code/mpscmv2.h index 8490b8f311a..8586a639901 100644 --- a/mps/code/mpscmv2.h +++ b/mps/code/mpscmv2.h @@ -9,22 +9,6 @@ #include "mps.h" -/* The mvt pool class has five extra parameters to mps_pool_create: - * mps_res_t mps_pool_create(mps_pool_t * pool, mps_arena_t arena, - * mps_class_t mvt_class, - * size_t minimum_size, - * size_t mean_size, - * size_t maximum_size, - * mps_count_t reserve_depth - * mps_count_t fragmentation_limit); - * minimum_, mean_, and maximum_size are the mimimum, mean, and - * maximum (typical) size of objects expected to be allocated in the - * pool. reserve_depth is a measure of the expected hysteresis of the - * object population. fragmentation_limit is a percentage (between 0 - * and 100): if the free space managed by the pool exceeds the - * specified percentage, the pool will resort to a "first fit" - * allocation policy. - */ extern mps_class_t mps_class_mvt(void); /* The mvt pool class supports two extensions to the pool protocol: diff --git a/mps/code/mpsw3.h b/mps/code/mpsw3.h new file mode 100644 index 00000000000..f32b7a09831 --- /dev/null +++ b/mps/code/mpsw3.h @@ -0,0 +1,79 @@ +/* mpsw3.h: RAVENBROOK MEMORY POOL SYSTEM C INTERFACE, WINDOWS PART + * + * $Id$ + * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * + * .readership: customers, MPS developers. + * .sources: . + */ + +#ifndef mpsw3_h +#define mpsw3_h + +#include "mps.h" /* needed for mps_tramp_t */ +#include "mpswin.h" /* needed for SEH filter */ + + +extern LONG mps_SEH_filter(LPEXCEPTION_POINTERS, void **, size_t *); +extern void mps_SEH_handler(void *, size_t); + + +#define mps_tramp(r_o, f, p, s) \ + MPS_BEGIN \ + void **_r_o = (r_o); \ + mps_tramp_t _f = (f); \ + void *_p = (p); \ + size_t _s = (s); \ + void *_hp = NULL; size_t _hs = 0; \ + __try { \ + *_r_o = (*_f)(_p, _s); \ + } __except(mps_SEH_filter(GetExceptionInformation(), \ + &_hp, &_hs)) { \ + mps_SEH_handler(_hp, _hs); \ + } \ + MPS_END + + +#endif /* mpsw3_h */ + + +/* C. COPYRIGHT AND LICENSE + * + * Copyright (C) 2001-2002 Ravenbrook Limited . + * All rights reserved. This is an open source license. Contact + * Ravenbrook for commercial licensing options. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Redistributions in any form must be accompanied by information on how + * to obtain complete source code for this software and any accompanying + * software that uses this software. The source code must either be + * included in the distribution or be available for no more than the cost + * of distribution plus a nominal fee, and must be freely redistributable + * under reasonable conditions. For an executable file, complete source + * code means the source code for all modules it contains. It does not + * include source code for modules or files that typically accompany the + * major components of the operating system on which the executable file + * runs. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/mps/code/mv2test.c b/mps/code/mv2test.c index 40d53d0589f..bf29f61981f 100644 --- a/mps/code/mv2test.c +++ b/mps/code/mv2test.c @@ -6,14 +6,10 @@ #include #include -#include "mpstd.h" #include #include "mpscmvt.h" #include "mps.h" - -typedef mps_word_t mps_count_t; /* machine word (target dep.) */ - #include "mpslib.h" #include "mpsavm.h" #include "testlib.h" @@ -71,11 +67,11 @@ static size_t randomSize(unsigned long i) #define TEST_SET_SIZE 1234 #define TEST_LOOPS 27 -static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size) +static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size, mps_align_t align) { mps_res_t res; - size = alignUp(size, MPS_PF_ALIGN); + size = alignUp(size, align); do { MPS_RESERVE_BLOCK(res, *p, ap, size); @@ -87,8 +83,9 @@ static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size) } -static mps_res_t stress(mps_class_t class, mps_arena_t arena, - size_t (*size)(unsigned long i), mps_arg_s args[]) +static mps_res_t stress(mps_arena_t arena, mps_align_t align, + size_t (*size)(unsigned long i), + mps_class_t class, mps_arg_s args[]) { mps_res_t res; mps_ap_t ap; @@ -105,7 +102,7 @@ static mps_res_t stress(mps_class_t class, mps_arena_t arena, for(i=0; i 0); AVER(avgSize > 0); AVER(avgSize <= extendBy); AVER(maxSize > 0); AVER(extendBy <= maxSize); + pool->alignment = align; mv = Pool2MV(pool); arena = PoolArena(pool); @@ -626,6 +631,7 @@ static void MVFree(Pool pool, Addr old, Size size) AVERT(MV, mv); AVER(old != (Addr)0); + AVER(AddrIsAligned(old, pool->alignment)); AVER(size > 0); size = SizeAlignUp(size, pool->alignment); diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index 45a38592946..a149178a8ef 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -261,7 +261,12 @@ static Res MVTInit(Pool pool, ArgList args) fragLimit = (Count)(arg.val.d * 100); } - AVER(SizeIsAligned(align, MPS_PF_ALIGN)); + AVERT(Align, align); + /* This restriction on the alignment is necessary because of the use + * of a Freelist to store the free address ranges in low-memory + * situations. See . + */ + AVER(AlignIsAligned(align, FreelistMinimumAlignment)); AVER(0 < minSize); AVER(minSize <= meanSize); AVER(meanSize <= maxSize); diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index c3e18df5aec..2e38c25aa3d 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -456,7 +456,7 @@ static Res MVFFInit(Pool pool, ArgList args) { Size extendBy = MVFF_EXTEND_BY_DEFAULT; Size avgSize = MVFF_AVG_SIZE_DEFAULT; - Size align = MVFF_ALIGN_DEFAULT; + Align align = MVFF_ALIGN_DEFAULT; Bool slotHigh = MVFF_SLOT_HIGH_DEFAULT; Bool arenaHigh = MVFF_ARENA_HIGH_DEFAULT; Bool firstFit = MVFF_FIRST_FIT_DEFAULT; @@ -500,7 +500,12 @@ static Res MVFFInit(Pool pool, ArgList args) AVER(avgSize <= extendBy); /* .arg.check */ AVER(spare >= 0.0); /* .arg.check */ AVER(spare <= 1.0); /* .arg.check */ - AVER(SizeIsAligned(align, MPS_PF_ALIGN)); + AVERT(Align, align); + /* This restriction on the alignment is necessary because of the use + * of a Freelist to store the free address ranges in low-memory + * situations. . + */ + AVER(AlignIsAligned(align, FreelistMinimumAlignment)); AVERT(Bool, slotHigh); AVERT(Bool, arenaHigh); AVERT(Bool, firstFit); diff --git a/mps/code/sac.c b/mps/code/sac.c index c85956c8f82..58fca2b33c3 100644 --- a/mps/code/sac.c +++ b/mps/code/sac.c @@ -117,10 +117,10 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount, /* to be large enough, but that gets complicated, if you have to */ /* merge classes because of the adjustment. */ for (i = 0; i < classesCount; ++i) { - AVER(classes[i]._block_size > 0); - AVER(SizeIsAligned(classes[i]._block_size, PoolAlignment(pool))); - AVER(prevSize < classes[i]._block_size); - prevSize = classes[i]._block_size; + AVER(classes[i].mps_block_size > 0); + AVER(SizeIsAligned(classes[i].mps_block_size, PoolAlignment(pool))); + AVER(prevSize < classes[i].mps_block_size); + prevSize = classes[i].mps_block_size; /* no restrictions on count */ /* no restrictions on frequency */ } @@ -128,7 +128,7 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount, /* Calculate frequency scale */ for (i = 0; i < classesCount; ++i) { unsigned oldFreq = totalFreq; - totalFreq += classes[i]._frequency; + totalFreq += classes[i].mps_frequency; AVER(oldFreq <= totalFreq); /* check for overflow */ UNUSED(oldFreq); /* */ } @@ -136,10 +136,10 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount, /* Find middle one */ totalFreq /= 2; for (i = 0; i < classesCount; ++i) { - if (totalFreq < classes[i]._frequency) break; - totalFreq -= classes[i]._frequency; + if (totalFreq < classes[i].mps_frequency) break; + totalFreq -= classes[i].mps_frequency; } - if (totalFreq <= classes[i]._frequency / 2) + if (totalFreq <= classes[i].mps_frequency / 2) middleIndex = i; else middleIndex = i + 1; /* there must exist another class at i+1 */ @@ -155,9 +155,9 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount, /* It's important this matches SACFind. */ esac = ExternalSACOfSAC(sac); for (j = middleIndex + 1, i = 0; j < classesCount; ++j, i += 2) { - esac->_freelists[i]._size = classes[j]._block_size; + esac->_freelists[i]._size = classes[j].mps_block_size; esac->_freelists[i]._count = 0; - esac->_freelists[i]._count_max = classes[j]._cached_count; + esac->_freelists[i]._count_max = classes[j].mps_cached_count; esac->_freelists[i]._blocks = NULL; } esac->_freelists[i]._size = SizeMAX; @@ -165,19 +165,19 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount, esac->_freelists[i]._count_max = 0; esac->_freelists[i]._blocks = NULL; for (j = middleIndex, i = 1; j > 0; --j, i += 2) { - esac->_freelists[i]._size = classes[j-1]._block_size; + esac->_freelists[i]._size = classes[j-1].mps_block_size; esac->_freelists[i]._count = 0; - esac->_freelists[i]._count_max = classes[j]._cached_count; + esac->_freelists[i]._count_max = classes[j].mps_cached_count; esac->_freelists[i]._blocks = NULL; } esac->_freelists[i]._size = 0; esac->_freelists[i]._count = 0; - esac->_freelists[i]._count_max = classes[j]._cached_count; + esac->_freelists[i]._count_max = classes[j].mps_cached_count; esac->_freelists[i]._blocks = NULL; /* finish init */ esac->_trapped = FALSE; - esac->_middle = classes[middleIndex]._block_size; + esac->_middle = classes[middleIndex].mps_block_size; sac->pool = pool; sac->classesCount = classesCount; sac->middleIndex = middleIndex; diff --git a/mps/code/sacss.c b/mps/code/sacss.c index ee86c83989d..7148338584d 100644 --- a/mps/code/sacss.c +++ b/mps/code/sacss.c @@ -7,6 +7,7 @@ #include "mpscmv.h" #include "mpscmvff.h" +#include "mpscmfs.h" #include "mpslib.h" #include "mpsavm.h" #include "mps.h" @@ -15,9 +16,7 @@ #include "mpslib.h" #include -#include "mpstd.h" #include -#include #include @@ -28,9 +27,6 @@ #define testSetSIZE 200 #define testLOOPS 10 -#define topClassSIZE 0xA00 -#define classCOUNT 4 - /* make -- allocate an object */ @@ -45,25 +41,36 @@ static mps_res_t make(mps_addr_t *p, mps_sac_t sac, size_t size) /* stress -- create a pool of the requested type and allocate in it */ -static mps_res_t stress(mps_class_t class, - size_t classes_count, mps_sac_classes_s *classes, - size_t (*size)(size_t i), mps_arena_t arena, ...) +static mps_res_t stress(mps_arena_t arena, mps_align_t align, + size_t (*size)(size_t i), + const char *name, mps_class_t pool_class, + mps_arg_s *args) { mps_res_t res; mps_pool_t pool; mps_sac_t sac; - va_list arg; size_t i, k; int *ps[testSetSIZE]; size_t ss[testSetSIZE]; + mps_sac_classes_s classes[4] = { + {1, 1, 1}, + {2, 1, 2}, + {16, 9, 5}, + {100, 9, 4} + }; + size_t classes_count = sizeof classes / sizeof *classes; + for (i = 0; i < classes_count; ++i) { + classes[i].mps_block_size *= alignUp(align, sizeof(void *)); + } - va_start(arg, arena); - res = mps_pool_create_v(&pool, arena, class, arg); - va_end(arg); + printf("%s\n", name); + + res = mps_pool_create_k(&pool, arena, pool_class, args); if (res != MPS_RES_OK) return res; - die(mps_sac_create(&sac, pool, classes_count, classes), "SACCreate"); + die(mps_sac_create(&sac, pool, classes_count, classes), + "SACCreate"); /* allocate a load of objects */ for (i = 0; i < testSetSIZE; ++i) { @@ -125,9 +132,9 @@ static mps_res_t stress(mps_class_t class, } -/* randomSize8 -- produce sizes both latge and small */ +/* randomSize -- produce sizes both large and small */ -static size_t randomSize8(size_t i) +static size_t randomSize(size_t i) { size_t maxSize = 2 * 160 * 0x2000; size_t size; @@ -138,58 +145,97 @@ static size_t randomSize8(size_t i) } -/* testInArena -- test all the pool classes in the given arena */ +/* fixedSize -- produce always the same size */ + +static size_t fixedSizeSize = 0; + +static size_t fixedSize(size_t i) +{ + testlib_unused(i); + return fixedSizeSize; +} + static mps_pool_debug_option_s debugOptions = { - /* .fence_template = */ (const void *)"postpostpostpost", - /* .fence_size = */ MPS_PF_ALIGN, - /* .free_template = */ (const void *)"DEAD", + /* .fence_template = */ (void *)"post", + /* .fence_size = */ 4, + /* .free_template = */ (void *)"DEAD", /* .free_size = */ 4 }; -static mps_sac_classes_s classes[4] = { - {MPS_PF_ALIGN, 1, 1}, - {MPS_PF_ALIGN * 2, 1, 2}, - {128 + MPS_PF_ALIGN, 9, 5}, - {topClassSIZE, 9, 4} -}; -static void testInArena(mps_arena_t arena) +/* testInArena -- test all the pool classes in the given arena */ + +static void testInArena(mps_arena_class_t arena_class, mps_arg_s *arena_args) { - printf("MVFF\n\n"); - die(stress(mps_class_mvff(), classCOUNT, classes, randomSize8, arena, - (size_t)65536, (size_t)32, (mps_align_t)MPS_PF_ALIGN, TRUE, TRUE, TRUE), - "stress MVFF"); - printf("MV debug\n\n"); - die(stress(mps_class_mv_debug(), classCOUNT, classes, randomSize8, arena, - &debugOptions, (size_t)65536, (size_t)32, (size_t)65536), - "stress MV debug"); - printf("MV\n\n"); - die(stress(mps_class_mv(), classCOUNT, classes, randomSize8, arena, - (size_t)65536, (size_t)32, (size_t)65536), - "stress MV"); + mps_arena_t arena; + + die(mps_arena_create_k(&arena, arena_class, arena_args), + "mps_arena_create"); + + MPS_ARGS_BEGIN(args) { + mps_align_t align = sizeof(void *) << (rnd() % 4); + MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE); + die(stress(arena, align, randomSize, "MVFF", mps_class_mvff(), args), + "stress MVFF"); + } MPS_ARGS_END(args); + + MPS_ARGS_BEGIN(args) { + mps_align_t align = sizeof(void *) << (rnd() % 4); + MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE); + MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &debugOptions); + die(stress(arena, align, randomSize, "MVFF debug", + mps_class_mvff_debug(), args), + "stress MVFF debug"); + } MPS_ARGS_END(args); + + MPS_ARGS_BEGIN(args) { + mps_align_t align = 1 << (rnd() % 6); + MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); + die(stress(arena, align, randomSize, "MV", mps_class_mv(), args), + "stress MV"); + } MPS_ARGS_END(args); + + MPS_ARGS_BEGIN(args) { + mps_align_t align = 1 << (rnd() % 6); + MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); + MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &debugOptions); + die(stress(arena, align, randomSize, "MV debug", + mps_class_mv_debug(), args), + "stress MV debug"); + } MPS_ARGS_END(args); + + MPS_ARGS_BEGIN(args) { + fixedSizeSize = sizeof(void *) * (1 + rnd() % 100); + MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, fixedSizeSize); + die(stress(arena, fixedSizeSize, fixedSize, "MFS", mps_class_mfs(), args), + "stress MFS"); + } MPS_ARGS_END(args); + + mps_arena_destroy(arena); } int main(int argc, char *argv[]) { - mps_arena_t arena; - testlib_init(argc, argv); - die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), - "mps_arena_create"); - testInArena(arena); - mps_arena_destroy(arena); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE); + testInArena(mps_arena_class_vm(), args); + } MPS_ARGS_END(args); MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE); MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, FALSE); - die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), - "mps_arena_create"); + testInArena(mps_arena_class_vm(), args); } MPS_ARGS_END(args); - testInArena(arena); - mps_arena_destroy(arena); printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); return 0; diff --git a/mps/design/object-debug.txt b/mps/design/object-debug.txt index 300a4e261a8..b99049a9d1d 100644 --- a/mps/design/object-debug.txt +++ b/mps/design/object-debug.txt @@ -70,6 +70,11 @@ an ``AVER()`` has fired. Naturally, if the information required for the dump has been corrupted, it will fail, as softly as possible (source @@@@). +_`.req.portable`: Client code that uses these features must be easily +portable to all the supported platforms. (Source: job003749_.) + +.. _job003749: http://www.ravenbrook.com/project/mps/issue/job003749/ + .. note:: There are more requirements, especially about memory dumps and @@ -90,6 +95,11 @@ specified as a byte/word which used repeatedly to fill the fencepost. _`.fence.content.template`: The content could be given as a template which is of the right size and is simply copied onto the fencepost. +_`.fence.content.template.repeat`: The content could be given as a +template which is copied repeatedly until the fencepost is full. (This +would avoid the need to specify different templates on different +architectures, and so help meet `.req.portable`_.) + _`.fence.walk`: `.req.fencepost.check`_ requires the ability to find all the allocated objects. In formatted pools, this is not a problem. In unformatted pools, we could use the walker. It's a feasible @@ -233,14 +243,14 @@ to pools. In particular, clients will be able to use tagging and fenceposting separately on each pool. _`.fence.size`: Having fenceposts of adjustable size and pattern is -quite useful. We feel that restricting the size to an integral -multiple of the [pool or format?] alignment is harmless and simplifies -the implementation enormously. +useful. Restricting the size to an integral multiple of the [pool or +format?] alignment would simplify the implementation but breaks +`.req.portable`_. _`.fence.template`: We use templates (`.fence.content.template`_) to fill in the fenceposts, but we do not give any guarantees about the -location of the fenceposts, only that they're properly aligned. This -leaves us the opportunity to do tail-only fenceposting, if we choose. +location of the fenceposts. This leaves us the opportunity to do +tail-only fenceposting, if we choose. _`.fence.slop`: [see impl.c.dbgpool.FenceAlloc @@@@] @@ -416,6 +426,8 @@ Document History - 2013-04-14 GDR_ Converted to reStructuredText. +- 2014-04-09 GDR_ Added newly discovered requirement `.req.portable`_. + .. _RB: http://www.ravenbrook.com/consultants/rb/ .. _GDR: http://www.ravenbrook.com/consultants/gdr/ diff --git a/mps/manual/source/pool/intro.rst b/mps/manual/source/pool/intro.rst index ed8f83b8d4a..53caa616c59 100644 --- a/mps/manual/source/pool/intro.rst +++ b/mps/manual/source/pool/intro.rst @@ -114,7 +114,7 @@ May contain exact references? [4]_ 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 +Alignment? [5]_ conf conf conf conf conf [6]_ conf [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 @@ -151,13 +151,13 @@ Blocks may use :term:`in-band headers`? yes yes yes yes yes .. [5] "Alignment" is "conf" if the client program may specify :term:`alignment` for each pool. - .. [6] The alignment of blocks allocated from :ref:`pool-mv` pools - is platform-dependent. + .. [6] The alignment of blocks allocated from :ref:`pool-mfs` + pools is the platform's :term:`natural alignment`, + :c:macro:`MPS_PF_ALIGN`. .. [7] :ref:`pool-mvt` and :ref:`pool-mvff` pools have - configurable alignment, but it may not be smaller than the - :term:`natural alignment` for the :term:`platform` (see - :c:macro:`MPS_PF_ALIGN`). + configurable alignment, but it may not be smaller than + ``sizeof(void *)``. .. [8] In pools with this property, each object may specify an :term:`dependent object` which the client program diff --git a/mps/manual/source/pool/mv.rst b/mps/manual/source/pool/mv.rst index 361cd41c0b5..3432a642fa9 100644 --- a/mps/manual/source/pool/mv.rst +++ b/mps/manual/source/pool/mv.rst @@ -38,9 +38,7 @@ MV properties * Allocations may be variable in size. -* The :term:`alignment` of blocks is not configurable: it is the - :term:`natural alignment` of the platform (see - :c:macro:`MPS_PF_ALIGN`). +* The :term:`alignment` of blocks is configurable. * Blocks do not have :term:`dependent objects`. @@ -73,7 +71,13 @@ MV interface :term:`pool`. When creating an MV pool, :c:func:`mps_pool_create_k` may take - three :term:`keyword arguments`: + the following :term:`keyword arguments`: + + * :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is + :c:macro:`MPS_PF_ALIGN`) is the + :term:`alignment` of addresses for allocation (and freeing) in + the pool. If an unaligned size is passed to :c:func:`mps_alloc` or + :c:func:`mps_free`, it will be rounded up to the pool's alignment. * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default 65536) is the :term:`size` of segment that the pool will @@ -119,10 +123,11 @@ MV interface class. When creating a debugging MV pool, :c:func:`mps_pool_create_k` - 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`. + takes the following keyword arguments: :c:macro:`MPS_KEY_ALIGN`, + :c:macro:`MPS_KEY_EXTEND_SIZE`, :c:macro:`MPS_KEY_MEAN_SIZE`, + :c:macro:`MPS_KEY_MAX_SIZE` are as described above, and + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging + options. See :c:type:`mps_debug_option_s`. .. deprecated:: starting with version 1.112. diff --git a/mps/manual/source/pool/mvff.rst b/mps/manual/source/pool/mvff.rst index 64c220e9506..b3eb511ea02 100644 --- a/mps/manual/source/pool/mvff.rst +++ b/mps/manual/source/pool/mvff.rst @@ -80,7 +80,7 @@ MVFF properties * Allocations may be variable in size. * The :term:`alignment` of blocks is configurable, but may not be - smaller than the :term:`natural alignment` of the platform. + smaller than ``sizeof(void *)``. * Blocks do not have :term:`dependent objects`. @@ -127,10 +127,10 @@ MVFF interface * :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is :c:macro:`MPS_PF_ALIGN`) is the :term:`alignment` of addresses for allocation (and freeing) in - the pool. If an unaligned size is passed to :c:func:`mps_alloc` or - :c:func:`mps_free`, it will be rounded up to the pool's alignment. - The minimum alignment supported by pools of this class is - ``sizeof(void *)``. + the pool. If an unaligned size is passed to :c:func:`mps_alloc` + or :c:func:`mps_free`, it will be rounded up to the pool's + alignment. The minimum alignment supported by pools of this + class is ``sizeof(void *)``. * :c:macro:`MPS_KEY_SPARE` (type :c:type:`double`, default 0.75) is the maximum proportion of memory that the pool will keep diff --git a/mps/manual/source/pool/mvt.rst b/mps/manual/source/pool/mvt.rst index f3bbba705a0..4f89b8d5178 100644 --- a/mps/manual/source/pool/mvt.rst +++ b/mps/manual/source/pool/mvt.rst @@ -78,6 +78,9 @@ MVT properties * Allocations may be variable in size. +* The :term:`alignment` of blocks is configurable, but may not be + smaller than ``sizeof(void *)``. + * Blocks do not have :term:`dependent objects`. * Blocks are not automatically :term:`reclaimed`. @@ -117,7 +120,7 @@ MVT interface the pool. If an unaligned size is passed to :c:func:`mps_alloc` or :c:func:`mps_free`, it will be rounded up to the pool's alignment. The minimum alignment supported by pools of this class is - ``sizeof(void *)``. + ``sizeof(void *)``. * :c:macro:`MPS_KEY_MIN_SIZE` (type :c:type:`size_t`, default is :c:macro:`MPS_PF_ALIGN`) is the diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 21d6ca6c13e..d3b657cd6a5 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -40,10 +40,23 @@ New features the lowest generation whose new size was within its capacity.) - Interface changes ................. +#. It is now possible to configure the alignment of objects allocated + in a :ref:`pool-mv` pool, by passing the :c:macro:`MPS_KEY_ALIGN` + keyword argument to :c:func:`mps_pool_create_k`. + +#. The alignment requirements for :ref:`pool-mvff` and :ref:`pool-mvt` + pools have been relaxed on the platforms ``w3i3mv`` and ``w3i6mv``. + On all platforms it is now possible to specify alignments down to + ``sizeof(void *)`` as the alignment for pools of these classes. + +#. The sizes of the templates in a :c:type:`mps_pool_debug_option_s` + structure no longer have to be related to the alignment of the + pools that they are used with. This makes it easier to reuse these + structures. + #. 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. @@ -81,6 +94,12 @@ Other changes .. _job003745: https://www.ravenbrook.com/project/mps/issue/job003745/ +#. The debugging version of the :ref:`pool-mvff` pool class, + :c:func:`mps_class_mvff_debug`, no longer triggers an assertion + failure if you allocate a large object. See job003751_. + + .. _job003751: https://www.ravenbrook.com/project/mps/issue/job003751/ + #. :program:`mpseventtxt` now successfully processes a telemetry log containing multiple labels associated with the same address. See job003756_. diff --git a/mps/manual/source/topic/cache.rst b/mps/manual/source/topic/cache.rst index fc523161a21..589e5e86db0 100644 --- a/mps/manual/source/topic/cache.rst +++ b/mps/manual/source/topic/cache.rst @@ -170,9 +170,9 @@ Cache interface The size classes are described by an array of element type :c:type:`mps_sac_class_s`. This array is used to initialize the - segregated allocation cache, and is not needed - after:c:func:`mps_sac_create` returns. The following constraints - apply to the array: + segregated allocation cache, and is not needed after + :c:func:`mps_sac_create` returns. The following constraints apply + to the array: * You must specify at least one size class. diff --git a/mps/manual/source/topic/debugging.rst b/mps/manual/source/topic/debugging.rst index 70494aa20cf..1f2cb498cf4 100644 --- a/mps/manual/source/topic/debugging.rst +++ b/mps/manual/source/topic/debugging.rst @@ -50,7 +50,7 @@ debugging: for the pattern at any time by calling :c:func:`mps_pool_check_free_space`. -The :term:`client program` specifies templates for both of these +The :term:`client program` may specify templates for both of these features via the :c:type:`mps_pool_debug_option_s` structure. This allows it to specify patterns: @@ -66,8 +66,8 @@ allows it to specify patterns: For example:: mps_pool_debug_option_s debug_options = { - (const void *)"postpost", 8, - (const void *)"freefree", 8, + "fencepost", 9, + "free", 4, }; mps_pool_t pool; mps_res_t res; @@ -87,9 +87,9 @@ For example:: class`. :: typedef struct mps_pool_debug_option_s { - const void *fence_template; + void *fence_template; size_t fence_size; - const void *free_template; + void *free_template; size_t free_size; } mps_pool_debug_option_s; @@ -104,10 +104,6 @@ For example:: ``free_size`` is the :term:`size` of ``free_template`` in bytes, or zero if the debugging pool should not splat free space. - Both ``fence_size`` and ``free_size`` must be a multiple of the - :term:`alignment` of the :term:`pool`, and also a multiple of the - alignment of the pool's :term:`object format` if it has one. - The debugging pool will copy the ``fence_size`` bytes pointed to by ``fence_template`` in a repeating pattern onto each fencepost during allocation, and it will copy the bytes pointed to by diff --git a/mps/manual/source/topic/keyword.rst b/mps/manual/source/topic/keyword.rst index 459f703e35f..936aedc0394 100644 --- a/mps/manual/source/topic/keyword.rst +++ b/mps/manual/source/topic/keyword.rst @@ -86,7 +86,7 @@ now :c:macro:`MPS_KEY_ARGS_END`. Keyword Type & field in ``arg.val`` See ======================================== ====================================================== ========================================================== :c:macro:`MPS_KEY_ARGS_END` *none* *see above* - :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt` :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams` :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl` :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`