mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-18 03:40:47 -08:00
1. Where Type is a pointer type with a signature, replace CHECKL(TypeCheck(val)) with CHECKD(Type, val). 2. Where Type is a pointer type with no signature, replace CHECKL(TypeCheck(val)) with CHECKD_NOSIG(Type, val). 3. Where Type is a pointer type with a signature, but the structure is not visible at point of checking, replace CHECKL(TypeCheck(val)) with CHECKD_NOSIG(Type, val). Reference <design/check/#.hidden-type> 4. Make BTCheck extern and use it where possible. 5. Replace AVER(TypeCheck(val)) with AVERT(Type, val). Copied from Perforce Change: 185263 ServerID: perforce.ravenbrook.com
424 lines
13 KiB
C
424 lines
13 KiB
C
/* sac.c: SEGREGATED ALLOCATION CACHES
|
|
*
|
|
* $Id$
|
|
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
|
|
*/
|
|
|
|
#include "mpm.h"
|
|
#include "sac.h"
|
|
|
|
SRCID(sac, "$Id$");
|
|
|
|
|
|
typedef _mps_sac_freelist_block_s *SACFreeListBlock;
|
|
|
|
|
|
/* SACCheck -- check function for SACs */
|
|
|
|
static Bool sacFreeListBlockCheck(SACFreeListBlock fb)
|
|
{
|
|
Count j;
|
|
Addr cb;
|
|
|
|
/* nothing to check about size */
|
|
CHECKL(fb->_count <= fb->_count_max);
|
|
/* check the freelist has the right number of blocks */
|
|
for (j = 0, cb = fb->_blocks; j < fb->_count; ++j) {
|
|
CHECKL(cb != NULL);
|
|
/* @@@@ ignoring shields for now */
|
|
cb = *ADDR_PTR(Addr, cb);
|
|
}
|
|
CHECKL(cb == NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool SACCheck(SAC sac)
|
|
{
|
|
Index i, j;
|
|
Bool b;
|
|
Size prevSize;
|
|
mps_sac_t esac;
|
|
|
|
CHECKS(SAC, sac);
|
|
esac = ExternalSACOfSAC(sac);
|
|
CHECKU(Pool, sac->pool);
|
|
CHECKL(sac->classesCount > 0);
|
|
CHECKL(sac->classesCount > sac->middleIndex);
|
|
CHECKL(BoolCheck(esac->_trapped));
|
|
CHECKL(esac->_middle > 0);
|
|
/* check classes above middle */
|
|
prevSize = esac->_middle;
|
|
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);
|
|
/* check classes below middle */
|
|
prevSize = esac->_middle;
|
|
for (j = sac->middleIndex, i = 1; j > 0; --j, i += 2) {
|
|
CHECKL(prevSize > esac->_freelists[i]._size);
|
|
b = sacFreeListBlockCheck(&(esac->_freelists[i]));
|
|
if (!b) return b;
|
|
prevSize = esac->_freelists[i]._size;
|
|
}
|
|
/* check smallest class */
|
|
CHECKL(esac->_freelists[i]._size == 0);
|
|
b = sacFreeListBlockCheck(&(esac->_freelists[i]));
|
|
return b;
|
|
}
|
|
|
|
|
|
/* sacSize -- calculate size of a SAC structure */
|
|
|
|
static Size sacSize(Index middleIndex, Count classesCount)
|
|
{
|
|
Index indexMax; /* max index for the freelist */
|
|
SACStruct dummy;
|
|
|
|
if (middleIndex + 1 < classesCount - middleIndex)
|
|
indexMax = 2 * (classesCount - middleIndex - 1);
|
|
else
|
|
indexMax = 1 + 2 * middleIndex;
|
|
return PointerOffset(&dummy, &dummy.esac_s._freelists[indexMax+1]);
|
|
}
|
|
|
|
|
|
/* SACCreate -- create an SAC object */
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/* SACDestroy -- destroy an SAC object */
|
|
|
|
void SACDestroy(SAC sac)
|
|
{
|
|
AVERT(SAC, sac);
|
|
SACFlush(sac);
|
|
sac->sig = SigInvalid;
|
|
ControlFree(PoolArena(sac->pool), sac,
|
|
sacSize(sac->middleIndex, sac->classesCount));
|
|
}
|
|
|
|
|
|
/* sacFind -- find the index corresponding to size
|
|
*
|
|
* This function replicates the loop in MPS_SAC_ALLOC_FAST, only with
|
|
* added checks.
|
|
*/
|
|
|
|
static void sacFind(Index *iReturn, Size *blockSizeReturn,
|
|
SAC sac, Size size)
|
|
{
|
|
Index i, j;
|
|
mps_sac_t esac;
|
|
|
|
esac = ExternalSACOfSAC(sac);
|
|
if (size > esac->_middle) {
|
|
i = 0; j = sac->middleIndex + 1;
|
|
AVER(j <= sac->classesCount);
|
|
while (size > esac->_freelists[i]._size) {
|
|
AVER(j < sac->classesCount);
|
|
i += 2; ++j;
|
|
}
|
|
*blockSizeReturn = esac->_freelists[i]._size;
|
|
} else {
|
|
Size prevSize = esac->_middle;
|
|
|
|
i = 1; j = sac->middleIndex;
|
|
while (size <= esac->_freelists[i]._size) {
|
|
AVER(j > 0);
|
|
prevSize = esac->_freelists[i]._size;
|
|
i += 2; --j;
|
|
}
|
|
*blockSizeReturn = prevSize;
|
|
}
|
|
*iReturn = i;
|
|
}
|
|
|
|
|
|
/* SACFill -- alloc an object, and perhaps fill the cache */
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/* sacClassFlush -- discard elements from the cache for a given class
|
|
*
|
|
* blockCount says how many elements to discard.
|
|
*/
|
|
|
|
static void sacClassFlush(SAC sac, Index i, Size blockSize,
|
|
Count blockCount)
|
|
{
|
|
Addr cb, fl;
|
|
Count j;
|
|
mps_sac_t esac;
|
|
|
|
esac = ExternalSACOfSAC(sac);
|
|
for (j = 0, fl = esac->_freelists[i]._blocks;
|
|
j < blockCount; ++j) {
|
|
/* @@@@ ignoring shields for now */
|
|
cb = fl; fl = *ADDR_PTR(Addr, cb);
|
|
PoolFree(sac->pool, cb, blockSize);
|
|
}
|
|
esac->_freelists[i]._count -= blockCount;
|
|
esac->_freelists[i]._blocks = fl;
|
|
}
|
|
|
|
|
|
/* SACEmpty -- free an object, and perhaps empty the cache */
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
/* SACFlush -- flush the cache, releasing all memory held in it */
|
|
|
|
void SACFlush(SAC sac)
|
|
{
|
|
Index i, j;
|
|
Size prevSize;
|
|
mps_sac_t esac;
|
|
|
|
AVERT(SAC, sac);
|
|
|
|
esac = ExternalSACOfSAC(sac);
|
|
for (j = sac->middleIndex + 1, i = 0;
|
|
j < sac->classesCount; ++j, i += 2) {
|
|
sacClassFlush(sac, i, esac->_freelists[i]._size,
|
|
esac->_freelists[i]._count);
|
|
AVER(esac->_freelists[i]._blocks == NULL);
|
|
}
|
|
/* no need to flush overlarge, there's nothing there */
|
|
prevSize = esac->_middle;
|
|
for (j = sac->middleIndex, i = 1; j > 0; --j, i += 2) {
|
|
sacClassFlush(sac, i, prevSize, esac->_freelists[i]._count);
|
|
AVER(esac->_freelists[i]._blocks == NULL);
|
|
prevSize = esac->_freelists[i]._size;
|
|
}
|
|
/* flush smallest class */
|
|
sacClassFlush(sac, i, prevSize, esac->_freelists[i]._count);
|
|
AVER(esac->_freelists[i]._blocks == NULL);
|
|
}
|
|
|
|
|
|
/* C. COPYRIGHT AND LICENSE
|
|
*
|
|
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
|
* 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.
|
|
*/
|