static void MVFFFree(Pool pool, Addr old, Size size) { Res res; Addr base, limit; MVFF mvff; AVERT(Pool, pool); mvff = Pool2MVFF(pool); AVERT(MVFF, mvff); AVER(old != (Addr)0); AVER(AddrIsAligned(old, PoolAlignment(pool))); AVER(size > 0); size = SizeAlignUp(size, PoolAlignment(pool)); base = old; limit = AddrAdd(base, size); res = MVFFAddToFreeList(&base, &limit, mvff); AVER(res == ResOK); if (res == ResOK) MVFFFreeSegs(mvff, base, limit); return; }
/* 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. */ static Res MVFFAddSeg(Seg *segReturn, MVFF mvff, Size size, Bool withReservoirPermit) { Pool pool; Arena arena; Size segSize; Seg seg; Res res; Align align; Addr base, limit; AVERT(MVFF, mvff); AVER(size > 0); AVERT(Bool, withReservoirPermit); pool = MVFF2Pool(mvff); arena = PoolArena(pool); align = ArenaAlign(arena); AVER(SizeIsAligned(size, PoolAlignment(pool))); /* Use extendBy unless it's too small (see */ /* <design/poolmvff/#design.seg-size>). */ if (size <= mvff->extendBy) segSize = mvff->extendBy; else segSize = size; segSize = SizeAlignUp(segSize, align); res = SegAlloc(&seg, SegClassGet(), mvff->segPref, segSize, pool, withReservoirPermit, argsNone); if (res != ResOK) { /* try again for a seg just large enough for object */ /* see <design/poolmvff/#design.seg-fail> */ segSize = SizeAlignUp(size, align); res = SegAlloc(&seg, SegClassGet(), mvff->segPref, segSize, pool, withReservoirPermit, argsNone); if (res != ResOK) { return res; } } mvff->total += segSize; base = SegBase(seg); limit = AddrAdd(base, segSize); DebugPoolFreeSplat(pool, base, limit); res = MVFFAddToFreeList(&base, &limit, mvff); AVER(res == ResOK); AVER(base <= SegBase(seg)); if (mvff->minSegSize > segSize) mvff->minSegSize = segSize; /* Don't call MVFFFreeSegs; that would be silly. */ *segReturn = seg; return ResOK; }
static Res BufferAbsInit(Buffer buffer, Pool pool, Bool isMutator, ArgList args) { Arena arena; AVER(buffer != NULL); AVERT(Pool, pool); AVER(BoolCheck(isMutator)); AVERT(ArgList, args); /* Superclass init */ InstInit(CouldBeA(Inst, buffer)); arena = PoolArena(pool); /* Initialize the buffer. See <code/mpmst.h> for a definition of the structure. sig and serial comes later .init.sig-serial */ buffer->arena = arena; buffer->pool = pool; RingInit(&buffer->poolRing); buffer->isMutator = isMutator; if (ArenaGlobals(arena)->bufferLogging) { buffer->mode = BufferModeLOGGED; } else { buffer->mode = 0; } buffer->fillSize = 0.0; buffer->emptySize = 0.0; buffer->alignment = PoolAlignment(pool); buffer->base = (Addr)0; buffer->initAtFlip = (Addr)0; /* In the next three assignments we really mean zero, not NULL, because the bit pattern is compared. It's pretty unlikely we'll encounter a platform where this makes a difference. */ buffer->ap_s.init = (mps_addr_t)0; buffer->ap_s.alloc = (mps_addr_t)0; buffer->ap_s.limit = (mps_addr_t)0; buffer->poolLimit = (Addr)0; buffer->rampCount = 0; /* .init.sig-serial: Now the vanilla stuff is initialized, sign the buffer and give it a serial number. It can then be safely checked in subclass methods. */ buffer->serial = pool->bufferSerial; /* .trans.mod */ ++pool->bufferSerial; SetClassOfPoly(buffer, CLASS(Buffer)); buffer->sig = BufferSig; AVERT(Buffer, buffer); /* Attach the initialized buffer to the pool. */ RingAppend(&pool->bufferRing, &buffer->poolRing); EVENT3(BufferInit, buffer, pool, BOOLOF(buffer->isMutator)); return ResOK; }
static void MVFFFree(Pool pool, Addr old, Size size) { Addr base, limit; MVFF mvff; AVERT(Pool, pool); mvff = Pool2MVFF(pool); AVERT(MVFF, mvff); AVER(old != (Addr)0); AVER(size > 0); base = AddrAlignUp(old, PoolAlignment(pool)); size = size - AddrOffset(old, base); size = SizeAlignUp(size, PoolAlignment(pool)); limit = AddrAdd(base, size); MVFFAddToFreeList(&base, &limit, mvff); MVFFFreeSegs(mvff, base, limit); }
Res SACFill(Addr *p_o, SAC sac, Size size, Bool hasReservoirPermit) { Index i; Count blockCount, j; Size blockSize; Addr p, fl; Res res = ResOK; /* stop compiler complaining */ mps_sac_t esac; AVER(p_o != NULL); AVERT(SAC, sac); AVER(size != 0); AVERT(Bool, hasReservoirPermit); esac = ExternalSACOfSAC(sac); sacFind(&i, &blockSize, sac, size); /* Check it's empty (in the future, there will be other cases). */ AVER(esac->_freelists[i]._count == 0); /* Fill 1/3 of the cache for this class. */ blockCount = esac->_freelists[i]._count_max / 3; /* Adjust size for the overlarge class. */ if (blockSize == SizeMAX) /* .align: align 'cause some classes don't accept unaligned. */ blockSize = SizeAlignUp(size, PoolAlignment(sac->pool)); for (j = 0, fl = esac->_freelists[i]._blocks; j <= blockCount; ++j) { res = PoolAlloc(&p, sac->pool, blockSize, hasReservoirPermit); if (res != ResOK) break; /* @@@@ ignoring shields for now */ *ADDR_PTR(Addr, p) = fl; fl = p; } /* If didn't get any, just return. */ if (j == 0) { AVER(res != ResOK); return res; } /* Take the last one off, and return it. */ esac->_freelists[i]._count = j - 1; *p_o = fl; /* @@@@ ignoring shields for now */ esac->_freelists[i]._blocks = *ADDR_PTR(Addr, fl); return ResOK; }
static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size, Bool withReservoirPermit, DebugInfo info) { Res res; MVFF mvff; Addr base, limit; Bool foundBlock; AVERT(Pool, pool); mvff = Pool2MVFF(pool); AVERT(MVFF, mvff); AVER(aReturn != NULL); AVER(size > 0); AVER(BoolCheck(withReservoirPermit)); UNUSED(info); size = SizeAlignUp(size, PoolAlignment(pool)); foundBlock = MVFFFindFirstFree(&base, &limit, mvff, size); if (!foundBlock) { Seg seg; res = MVFFAddSeg(&seg, mvff, size, withReservoirPermit); if (res != ResOK) return res; foundBlock = MVFFFindFirstFree(&base, &limit, 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); /* We also know that the found range is no larger than the segment. */ AVER(SegSize(seg) >= AddrOffset(base, limit)); } AVER(foundBlock); AVER(AddrOffset(base, limit) == size); *aReturn = base; return ResOK; }
/* MVFFBufferFill -- Fill the buffer * * Fill it with the largest block we can find. */ static Res MVFFBufferFill(Addr *baseReturn, Addr *limitReturn, Pool pool, Buffer buffer, Size size, Bool withReservoirPermit) { Res res; MVFF mvff; Addr base, limit; Bool foundBlock; Seg seg = NULL; AVER(baseReturn != NULL); AVER(limitReturn != NULL); AVERT(Pool, pool); mvff = Pool2MVFF(pool); AVERT(MVFF, mvff); AVERT(Buffer, buffer); AVER(size > 0); AVER(SizeIsAligned(size, PoolAlignment(pool))); AVERT(Bool, withReservoirPermit); /* Hoping the largest is big enough, delete it and return if small. */ foundBlock = CBSFindLargest(&base, &limit, CBSOfMVFF(mvff), CBSFindDeleteENTIRE); if (foundBlock && AddrOffset(base, limit) < size) { foundBlock = FALSE; res = CBSInsert(CBSOfMVFF(mvff), base, limit); AVER(res == ResOK); } if (!foundBlock) { res = MVFFAddSeg(&seg, mvff, size, withReservoirPermit); if (res != ResOK) return res; foundBlock = CBSFindLargest(&base, &limit, CBSOfMVFF(mvff), CBSFindDeleteENTIRE); AVER(foundBlock); /* We will find the new segment. */ } AVER(AddrOffset(base, limit) >= size); mvff->free -= AddrOffset(base, limit); *baseReturn = base; *limitReturn = limit; return ResOK; }
Bool MFSCheck(MFS mfs) { Arena arena; CHECKS(MFS, mfs); CHECKC(MFSPool, mfs); CHECKD(Pool, MFSPool(mfs)); CHECKC(MFSPool, mfs); CHECKL(mfs->unitSize >= UNIT_MIN); CHECKL(mfs->extendBy >= UNIT_MIN); CHECKL(BoolCheck(mfs->extendSelf)); arena = PoolArena(MFSPool(mfs)); CHECKL(SizeIsArenaGrains(mfs->extendBy, arena)); CHECKL(SizeAlignUp(mfs->unroundedUnitSize, PoolAlignment(MFSPool(mfs))) == mfs->unitSize); if(mfs->tractList != NULL) { CHECKD_NOSIG(Tract, mfs->tractList); } CHECKL(mfs->free <= mfs->total); CHECKL((mfs->total - mfs->free) % mfs->unitSize == 0); return TRUE; }
void SACEmpty(SAC sac, Addr p, Size size) { Index i; Size blockSize; mps_sac_t esac; AVERT(SAC, sac); AVER(p != NULL); AVER(PoolHasAddr(sac->pool, p)); AVER(size > 0); esac = ExternalSACOfSAC(sac); sacFind(&i, &blockSize, sac, size); /* Check it's full (in the future, there will be other cases). */ AVER(esac->_freelists[i]._count == esac->_freelists[i]._count_max); /* Adjust size for the overlarge class. */ if (blockSize == SizeMAX) /* see .align */ blockSize = SizeAlignUp(size, PoolAlignment(sac->pool)); if (esac->_freelists[i]._count_max > 0) { Count blockCount; /* Flush 2/3 of the cache for this class. */ /* Computed as count - count/3, so that the rounding works out right. */ blockCount = esac->_freelists[i]._count; blockCount -= esac->_freelists[i]._count / 3; sacClassFlush(sac, i, blockSize, (blockCount > 0) ? blockCount : 1); /* Leave the current one in the cache. */ esac->_freelists[i]._count += 1; /* @@@@ ignoring shields for now */ *ADDR_PTR(Addr, p) = esac->_freelists[i]._blocks; esac->_freelists[i]._blocks = p; } else { /* Free even the current one. */ PoolFree(sac->pool, p, blockSize); } }
/* MVFFFindFirstFree -- Finds 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. */ static Bool MVFFFindFirstFree(Addr *baseReturn, Addr *limitReturn, MVFF mvff, Size size) { Bool foundBlock; CBSFindDelete findDelete; AVER(baseReturn != NULL); AVER(limitReturn != NULL); AVERT(MVFF, mvff); AVER(size > 0); AVER(SizeIsAligned(size, PoolAlignment(MVFF2Pool(mvff)))); findDelete = mvff->slotHigh ? CBSFindDeleteHIGH : CBSFindDeleteLOW; foundBlock = (mvff->firstFit ? CBSFindFirst : CBSFindLast) (baseReturn, limitReturn, CBSOfMVFF(mvff), size, findDelete); if (foundBlock) mvff->free -= size; return foundBlock; }
/* MVFFFindFirstFree -- Finds 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. */ static Bool MVFFFindFirstFree(Addr *baseReturn, Addr *limitReturn, MVFF mvff, Size size) { Bool foundBlock; FindDelete findDelete; RangeStruct range, oldRange; AVER(baseReturn != NULL); AVER(limitReturn != NULL); AVERT(MVFF, mvff); AVER(size > 0); AVER(SizeIsAligned(size, PoolAlignment(MVFF2Pool(mvff)))); FreelistFlushToCBS(FreelistOfMVFF(mvff), CBSOfMVFF(mvff)); findDelete = mvff->slotHigh ? FindDeleteHIGH : FindDeleteLOW; foundBlock = (mvff->firstFit ? CBSFindFirst : CBSFindLast) (&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 ? FreelistFindFirst : FreelistFindLast) (&range, &oldRange, FreelistOfMVFF(mvff), size, findDelete); } if (foundBlock) { *baseReturn = RangeBase(&range); *limitReturn = RangeLimit(&range); mvff->free -= size; } return foundBlock; }
/* MVFFBufferFill -- Fill the buffer * * Fill it with the largest block we can find. */ static Res MVFFBufferFill(Addr *baseReturn, Addr *limitReturn, Pool pool, Buffer buffer, Size size, Bool withReservoirPermit) { Res res; MVFF mvff; RangeStruct range, oldRange; Bool found; Seg seg = NULL; AVER(baseReturn != NULL); AVER(limitReturn != NULL); AVERT(Pool, pool); mvff = Pool2MVFF(pool); AVERT(MVFF, mvff); AVERT(Buffer, buffer); AVER(size > 0); AVER(SizeIsAligned(size, PoolAlignment(pool))); AVERT(Bool, withReservoirPermit); found = MVFFFindLargest(&range, &oldRange, mvff, size, FindDeleteENTIRE); if (!found) { /* Add a new segment to the free list and try again. */ res = MVFFAddSeg(&seg, mvff, size, withReservoirPermit); if (res != ResOK) return res; found = MVFFFindLargest(&range, &oldRange, mvff, size, FindDeleteENTIRE); } AVER(found); AVER(RangeSize(&range) >= size); mvff->free -= RangeSize(&range); *baseReturn = RangeBase(&range); *limitReturn = RangeLimit(&range); return ResOK; }
Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount, SACClasses classes) { void *p; SAC sac; Res res; Index i, j; Index middleIndex; /* index of the size in the middle */ Size prevSize; unsigned totalFreq = 0; mps_sac_t esac; AVER(sacReturn != NULL); AVERT(Pool, pool); AVER(classesCount > 0); /* In this cache type, there is no upper limit on classesCount. */ prevSize = sizeof(Addr) - 1; /* must large enough for freelist link */ /* @@@@ It would be better to dynamically adjust the smallest class */ /* 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; /* no restrictions on count */ /* no restrictions on frequency */ } /* Calculate frequency scale */ for (i = 0; i < classesCount; ++i) { unsigned oldFreq = totalFreq; totalFreq += classes[i]._frequency; AVER(oldFreq <= totalFreq); /* check for overflow */ UNUSED(oldFreq); /* <code/mpm.c#check.unused> */ } /* 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]._frequency / 2) middleIndex = i; else middleIndex = i + 1; /* there must exist another class at i+1 */ /* Allocate SAC */ res = ControlAlloc(&p, PoolArena(pool), sacSize(middleIndex, classesCount), FALSE); if(res != ResOK) goto failSACAlloc; sac = p; /* Move classes in place */ /* 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]._count = 0; esac->_freelists[i]._count_max = classes[j]._cached_count; esac->_freelists[i]._blocks = NULL; } esac->_freelists[i]._size = SizeMAX; esac->_freelists[i]._count = 0; 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]._count = 0; esac->_freelists[i]._count_max = classes[j]._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]._blocks = NULL; /* finish init */ esac->_trapped = FALSE; esac->_middle = classes[middleIndex]._block_size; sac->pool = pool; sac->classesCount = classesCount; sac->middleIndex = middleIndex; sac->sig = SACSig; AVERT(SAC, sac); *sacReturn = sac; return ResOK; failSACAlloc: return res; }
static Res DebugPoolInit(Pool pool, ArgList args) { Res res; PoolDebugOptions options; PoolDebugMixin debug; TagInitMethod tagInit; Size tagSize; ArgStruct arg; 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; AVERT(PoolDebugOptions, options); /* @@@@ Tag parameters should be taken from options, but tags have */ /* not been published yet. */ tagInit = NULL; tagSize = 0; res = SuperclassOfPool(pool)->init(pool, args); if (res != ResOK) return res; debug = DebugPoolDebugMixin(pool); AVER(debug != NULL); /* fencepost init */ /* @@@@ This parses a user argument, options, so it should really */ /* go through the MPS interface. The template needs to be copied */ /* into Addr memory, to avoid breaking <design/type/#addr.use>. */ 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; tagInit = TagTrivInit; } debug->fenceTemplate = options->fenceTemplate; } /* free-checking init */ /* @@@@ This parses a user argument, options, so it should really */ /* go through the MPS interface. The template needs to be copied */ /* into Addr memory, to avoid breaking <design/type#addr.use>. */ debug->freeSize = options->freeSize; if (debug->freeSize != 0) { if (PoolAlignment(pool) % debug->freeSize != 0) { res = ResPARAM; goto alignFail; } debug->freeTemplate = options->freeTemplate; } /* tag init */ debug->tagInit = tagInit; if (debug->tagInit != NULL) { debug->tagSize = tagSize + sizeof(tagStruct) - 1; /* 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 */ MPS_ARGS_ADD(pcArgs, MPS_KEY_MFS_UNIT_SIZE, debug->tagSize); MPS_ARGS_DONE(pcArgs); res = PoolCreate(&debug->tagPool, PoolArena(pool), PoolClassMFS(), pcArgs); } MPS_ARGS_END(pcArgs); if (res != ResOK) goto tagFail; debug->missingTags = 0; SplayTreeInit(&debug->index, TagComp, NULL); }