diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 928696b4298..f12749a44d5 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -77,7 +77,8 @@ typedef struct VMArenaStruct { /* VM arena structure */ ZoneSet blacklist; /* zones to use last */ ZoneSet genZoneSet[VMArenaGenCount]; /* .gencount.const */ ZoneSet freeSet; /* unassigned zones */ - Size extendBy; + Size extendBy; /* desired arena increment */ + Size extendMin; /* minimum arena increment */ Sig sig; /* */ } VMArenaStruct; @@ -179,6 +180,7 @@ static Bool VMArenaCheck(VMArena vmArena) } CHECKL(ZoneSetInter(allocSet, vmArena->freeSet) == ZoneSetEMPTY); CHECKL(vmArena->extendBy > 0); + CHECKL(vmArena->extendMin <= vmArena->extendBy); if (arena->primary != NULL) { primary = Chunk2VMChunk(arena->primary); @@ -489,6 +491,7 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, va_list args) vmArena->freeSet = ZoneSetUNIV; /* includes blacklist */ /* */ vmArena->extendBy = userSize; + vmArena->extendMin = 0; /* have to have a valid arena before calling ChunkCreate */ vmArena->sig = VMArenaSig; @@ -1086,14 +1089,42 @@ static Res vmArenaExtend(VMArena vmArena, Size size) VMArenaReserved(VMArena2Arena(vmArena)), NULL )); /* .chunk-create.fail: If we fail, try again with a smaller size */ - for(;; chunkSize /= 2) { - res = VMChunkCreate(&newChunk, vmArena, chunkSize); - if(res == ResOK) - break; + { + int fidelity = 8; /* max fraction of addr-space we may 'waste' */ + Size chunkHalf; + Size chunkMin = 4 * 1024; /* typical single page */ + Size sliceSize; + + if (vmArena->extendMin > chunkMin) + chunkMin = vmArena->extendMin; + if (chunkSize < chunkMin) + chunkSize = chunkMin; + + for(;; chunkSize = chunkHalf) { + chunkHalf = chunkSize / 2; + sliceSize = chunkHalf / fidelity; + AVER(sliceSize > 0); + + /* remove slices, down to chunkHalf but no further */ + for(; chunkSize > chunkHalf; chunkSize -= sliceSize) { + if(chunkSize < chunkMin) { + DIAG_SINGLEF(( "vmArenaExtend_FailMin", + "no remaining address-space chunk >= min($W)", chunkMin, + " (so VMArenaReserved remains $W bytes)\n", + VMArenaReserved(VMArena2Arena(vmArena)), NULL )); + return ResRESOURCE; + } + res = VMChunkCreate(&newChunk, vmArena, chunkSize); + if(res == ResOK) + goto vmArenaExtend_Done; + } + } } +vmArenaExtend_Done: + DIAG_SINGLEF(( "vmArenaExtend_Done", - "Reserved new chunk of VM $W bytes", chunkSize, + "Request for new chunk of VM $W bytes succeeded", chunkSize, " (VMArenaReserved now $W bytes)\n", VMArenaReserved(VMArena2Arena(vmArena)), NULL )); @@ -1586,6 +1617,29 @@ static void VMFree(Addr base, Size size, Pool pool) } +mps_res_t mps_arena_vm_growth(mps_arena_t mps_arena, + size_t mps_desired, size_t mps_minimum) +{ + Arena arena = (Arena)mps_arena; + Size desired = (Size)mps_desired; + Size minimum = (Size)mps_minimum; + VMArena vmArena; + + ArenaEnter(arena); + + AVERT(Arena, arena); + vmArena = Arena2VMArena(arena); + AVERT(VMArena, vmArena); + + vmArena->extendBy = desired; + vmArena->extendMin = minimum; + + ArenaLeave(arena); + + return MPS_RES_OK; +} + + /* VMArenaClass -- The VM arena class definition */ DEFINE_ARENA_CLASS(VMArenaClass, this) diff --git a/mps/code/mpsavm.h b/mps/code/mpsavm.h index a2789365fb7..5eae2ef201b 100644 --- a/mps/code/mpsavm.h +++ b/mps/code/mpsavm.h @@ -14,12 +14,16 @@ extern mps_arena_class_t mps_arena_class_vm(void); extern mps_arena_class_t mps_arena_class_vmnz(void); +/* The vm arena class supports extensions to the arena protocol: */ +extern mps_res_t mps_arena_vm_growth(mps_arena_t, size_t, size_t); + + #endif /* mpsavm_h */ /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2002,2007 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. *