mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-03-26 08:41:47 -07:00
Encoding the page state in the bottom two bits of the first field, rather than using up a whole word, in order to make room for a free list pointer.
Copied from Perforce Change: 184322 ServerID: perforce.ravenbrook.com
This commit is contained in:
parent
4329661aca
commit
40e4e93dec
3 changed files with 78 additions and 68 deletions
|
|
@ -1215,12 +1215,12 @@ static Bool pageDescIsMapped(VMChunk vmChunk, Index pi)
|
|||
* free.
|
||||
*/
|
||||
|
||||
static int pageType(VMChunk vmChunk, Index pi)
|
||||
static unsigned pageType(VMChunk vmChunk, Index pi)
|
||||
{
|
||||
Chunk chunk = VMChunk2Chunk(vmChunk);
|
||||
if (pageDescIsMapped(vmChunk, pi))
|
||||
return PageType(&chunk->pageTable[pi]);
|
||||
return PageTypeFree;
|
||||
return PageStateFREE;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1235,7 +1235,7 @@ static void sparePageRelease(VMChunk vmChunk, Index pi)
|
|||
Arena arena = ChunkArena(chunk);
|
||||
Page page = &chunk->pageTable[pi];
|
||||
|
||||
AVER(PageType(page) == PageTypeSpare);
|
||||
AVER(PageType(page) == PageStateSPARE);
|
||||
AVER(arena->spareCommitted >= ChunkPageSize(chunk));
|
||||
|
||||
arena->spareCommitted -= ChunkPageSize(chunk);
|
||||
|
|
@ -1272,14 +1272,14 @@ static void tablePagesUnmap(VMChunk vmChunk, Index basePage, Index limitPage)
|
|||
beginning of the table. */
|
||||
while (basePage > 0 &&
|
||||
pageDescIsMapped(vmChunk, basePage) &&
|
||||
PageType(&chunk->pageTable[basePage]) == PageTypeFree)
|
||||
PageType(&chunk->pageTable[basePage]) == PageStateFREE)
|
||||
--basePage;
|
||||
|
||||
/* Raise limitPage until we reach a descriptor we can't unmap, or the end
|
||||
of the table. */
|
||||
while (limitPage < chunk->pages &&
|
||||
pageDescIsMapped(vmChunk, limitPage) &&
|
||||
PageType(&chunk->pageTable[limitPage]) == PageTypeFree)
|
||||
PageType(&chunk->pageTable[limitPage]) == PageStateFREE)
|
||||
++limitPage;
|
||||
|
||||
/* Calculate the range of pages in the page table. */
|
||||
|
|
@ -1289,14 +1289,14 @@ static void tablePagesUnmap(VMChunk vmChunk, Index basePage, Index limitPage)
|
|||
|
||||
/* If we can't unmap the base page, step up. */
|
||||
if (!pageDescIsMapped(vmChunk, basePage) ||
|
||||
PageType(&chunk->pageTable[basePage]) != PageTypeFree)
|
||||
PageType(&chunk->pageTable[basePage]) != PageStateFREE)
|
||||
base = AddrAdd(base, chunk->pageSize);
|
||||
/* If that leaves any pages, then if the limit page contains a desciptor
|
||||
we can't unmap, step down. Note, limit is the base of the page table
|
||||
page *after* the one containing the desc for limitPage. */
|
||||
if (base < limit) {
|
||||
if (limitPage < chunk->pages &&
|
||||
pageType(vmChunk, limitPage) != PageTypeFree)
|
||||
pageType(vmChunk, limitPage) != PageStateFREE)
|
||||
limit = AddrSub(limit, chunk->pageSize);
|
||||
/* If that leaves any pages, unmap them. */
|
||||
if (base < limit) {
|
||||
|
|
@ -1334,7 +1334,7 @@ static Res pagesMarkAllocated(VMArena vmArena, VMChunk vmChunk,
|
|||
Addr freeBase;
|
||||
|
||||
/* Allocate a run of spare pages. */
|
||||
while(i < limitIndex && PageType(&chunk->pageTable[i]) == PageTypeSpare) {
|
||||
while(i < limitIndex && PageType(&chunk->pageTable[i]) == PageStateSPARE) {
|
||||
sparePageRelease(vmChunk, i);
|
||||
PageAlloc(chunk, i, pool);
|
||||
++i;
|
||||
|
|
@ -1345,8 +1345,8 @@ static Res pagesMarkAllocated(VMArena vmArena, VMChunk vmChunk,
|
|||
|
||||
/* Allocate a run of free pages. */
|
||||
freeBase = PageIndexBase(chunk, i);
|
||||
AVER(PageType(&chunk->pageTable[i]) == PageTypeFree);
|
||||
while (i < limitIndex && PageType(&chunk->pageTable[i]) == PageTypeFree) {
|
||||
AVER(PageType(&chunk->pageTable[i]) == PageStateFREE);
|
||||
while (i < limitIndex && PageType(&chunk->pageTable[i]) == PageStateFREE) {
|
||||
PageAlloc(chunk, i, pool);
|
||||
++i;
|
||||
}
|
||||
|
|
@ -1518,7 +1518,7 @@ static Size chunkUnmapAroundPage(Chunk chunk, Size size, Page page)
|
|||
AVERT(Chunk, chunk);
|
||||
vmChunk = Chunk2VMChunk(chunk);
|
||||
AVERT(VMChunk, vmChunk);
|
||||
AVER(PageType(page) == PageTypeSpare);
|
||||
AVER(PageType(page) == PageStateSPARE);
|
||||
/* size is arbitrary */
|
||||
|
||||
pageSize = ChunkPageSize(chunk);
|
||||
|
|
@ -1537,10 +1537,10 @@ static Size chunkUnmapAroundPage(Chunk chunk, Size size, Page page)
|
|||
purged += pageSize;
|
||||
} while (purged < size &&
|
||||
limitPage < chunk->pages &&
|
||||
pageType(vmChunk, limitPage) == PageTypeSpare);
|
||||
pageType(vmChunk, limitPage) == PageStateSPARE);
|
||||
while (purged < size &&
|
||||
basePage > 0 &&
|
||||
pageType(vmChunk, basePage - 1) == PageTypeSpare) {
|
||||
pageType(vmChunk, basePage - 1) == PageStateSPARE) {
|
||||
--basePage;
|
||||
sparePageRelease(vmChunk, basePage);
|
||||
PageInit(chunk, basePage);
|
||||
|
|
@ -1667,8 +1667,8 @@ static void VMFree(Addr base, Size size, Pool pool)
|
|||
AVER(TractPool(tract) == pool);
|
||||
|
||||
TractFinish(tract);
|
||||
PagePool(page) = NULL;
|
||||
PageType(page) = PageTypeSpare;
|
||||
PageSetPool(page, NULL);
|
||||
PageSetType(page, PageStateSPARE);
|
||||
/* We must init the page's spare ring because it is a union with the
|
||||
tract and will contain junk. */
|
||||
RingInit(PageSpareRing(page));
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ void TractInit(Tract tract, Pool pool, Addr base)
|
|||
AVER(tract != NULL);
|
||||
AVERT(Pool, pool);
|
||||
|
||||
tract->pool = pool;
|
||||
tract->pool.pool = pool;
|
||||
tract->base = base;
|
||||
tract->p = NULL;
|
||||
tract->white = TraceSetEMPTY;
|
||||
|
|
@ -67,7 +67,7 @@ void TractFinish(Tract tract)
|
|||
|
||||
/* Check that there's no segment - and hence no shielding. */
|
||||
AVER(!TractHasSeg(tract));
|
||||
tract->pool = NULL;
|
||||
tract->pool.pool = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -628,8 +628,8 @@ void PageInit(Chunk chunk, Index pi)
|
|||
AVER(pi < chunk->pages);
|
||||
|
||||
BTRes(chunk->allocTable, pi);
|
||||
PagePool(&chunk->pageTable[pi]) = NULL;
|
||||
PageType(&chunk->pageTable[pi]) = PageTypeFree;
|
||||
PageSetPool(&chunk->pageTable[pi], NULL);
|
||||
PageSetType(&chunk->pageTable[pi], PageStateFREE);
|
||||
RingInit(PageSpareRing(&chunk->pageTable[pi]));
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
108
mps/code/tract.h
108
mps/code/tract.h
|
|
@ -13,6 +13,35 @@
|
|||
#include "bt.h"
|
||||
|
||||
|
||||
/* Page states
|
||||
*
|
||||
* .states: Pages (hence PageStructs that describe them) can be in
|
||||
* one of 3 states:
|
||||
* allocated (to a pool as tracts)
|
||||
* allocated pages are mapped
|
||||
* BTGet(allocTable, i) == 1
|
||||
* PageType() == PageStateALLOC
|
||||
* PagePool()->pool == pool
|
||||
* spare
|
||||
* these pages are mapped
|
||||
* BTGet(allocTable, i) == 0
|
||||
* PageType() == PageStateSPARE
|
||||
* PagePool() == NULL
|
||||
* free
|
||||
* these pages are not mapped
|
||||
* BTGet(allocTable, i) == 0
|
||||
* PTE may itself be unmapped, but when it is (use pageTableMapped
|
||||
* to determine whether page occupied by page table is mapped):
|
||||
* PagePool() == NULL
|
||||
* PageType() == PageStateFREE
|
||||
*/
|
||||
|
||||
#define PageStateALLOC 0
|
||||
#define PageStateSPARE 1
|
||||
#define PageStateFREE 2
|
||||
#define PageStateWIDTH 2 /* bitfield width */
|
||||
|
||||
|
||||
/* TractStruct -- tract structure
|
||||
*
|
||||
* .tract: Tracts represent the grains of memory allocation from
|
||||
|
|
@ -22,8 +51,13 @@
|
|||
* as type Bool. See <design/arena/#tract.field.hasSeg>.
|
||||
*/
|
||||
|
||||
typedef union TractPoolUnion {
|
||||
Pool pool;
|
||||
unsigned state : PageStateWIDTH; /* see .states */
|
||||
} TractPoolUnion;
|
||||
|
||||
typedef struct TractStruct { /* Tract structure */
|
||||
Pool pool; /* MUST BE FIRST (<design/arena/#tract.field> pool) */
|
||||
TractPoolUnion pool; /* MUST BE FIRST (<design/arena/#tract.field> pool) */
|
||||
void *p; /* pointer for use of owning pool */
|
||||
Addr base; /* Base address of the tract */
|
||||
TraceSet white : TraceLIMIT; /* traces for which tract is white */
|
||||
|
|
@ -35,7 +69,7 @@ extern Addr (TractBase)(Tract tract);
|
|||
#define TractBase(tract) ((tract)->base)
|
||||
extern Addr TractLimit(Tract tract);
|
||||
|
||||
#define TractPool(tract) ((tract)->pool)
|
||||
#define TractPool(tract) ((tract)->pool.pool)
|
||||
#define TractP(tract) ((tract)->p)
|
||||
#define TractSetP(tract, pp) ((void)((tract)->p = (pp)))
|
||||
#define TractHasSeg(tract) ((Bool)(tract)->hasSeg)
|
||||
|
|
@ -71,67 +105,43 @@ extern void TractFinish(Tract tract);
|
|||
*
|
||||
* .page: The "pool" field must be the first field of the "tail"
|
||||
* field of this union. See <design/arena/#tract.field.pool>.
|
||||
*
|
||||
* .states: Pages (hence PageStructs that describe them) can be in
|
||||
* one of 3 states:
|
||||
* allocated (to a pool as tracts)
|
||||
* allocated pages are mapped
|
||||
* BTGet(allocTable, i) == 1
|
||||
* PageRest()->pool == pool
|
||||
* spare
|
||||
* these pages are mapped
|
||||
* BTGet(allocTable, i) == 0
|
||||
* PageRest()->pool == NULL
|
||||
* PageRest()->type == PageTypeSpare
|
||||
* free
|
||||
* these pages are not mapped
|
||||
* BTGet(allocTable, i) == 0
|
||||
* PTE may itself be unmapped, but when it is (use pageTableMapped
|
||||
* to determine whether page occupied by page table is mapped):
|
||||
* PageRest()->pool == NULL
|
||||
* PageRest()->type == PageTypeFree
|
||||
*/
|
||||
|
||||
enum {PageTypeSpare=1, PageTypeFree};
|
||||
|
||||
typedef struct PageStruct { /* page structure */
|
||||
union PageStructUnion {
|
||||
TractPoolUnion pool;
|
||||
TractStruct tractStruct; /* allocated tract */
|
||||
struct {
|
||||
Pool pool; /* NULL, must be first field (.page) */
|
||||
int type; /* see .states */
|
||||
TractPoolUnion pool; /* MUST BE FIRST (<design/arena/#tract.field> pool) */
|
||||
RingStruct spareRing;
|
||||
} rest; /* other (non-allocated) page */
|
||||
} the;
|
||||
} PageStruct;
|
||||
|
||||
|
||||
/* PageTract -- tract descriptor of an allocated page */
|
||||
|
||||
#define PageTract(page) (&(page)->the.tractStruct)
|
||||
|
||||
/* PageOfTract -- VM page descriptor from arena tract */
|
||||
|
||||
#define PageOfTract(tract) PARENT(PageStruct, the, PARENT(union PageStructUnion, tractStruct, (tract)))
|
||||
|
||||
/* PagePool -- pool field of a page */
|
||||
|
||||
#define PagePool(page) ((page)->the.rest.pool)
|
||||
|
||||
/* PageIsAllocated -- is a page allocated?
|
||||
*
|
||||
* See <design/arenavm/#table.disc>.
|
||||
*/
|
||||
|
||||
#define PageIsAllocated(page) ((page)->the.rest.pool != NULL)
|
||||
|
||||
/* PageType -- type of page */
|
||||
|
||||
#define PageType(page) ((page)->the.rest.type)
|
||||
|
||||
#define PageSpareRing(page) (&(page)->the.rest.spareRing)
|
||||
#define PageTract(page) (&(page)->the.tractStruct)
|
||||
#define PageOfTract(tract) \
|
||||
PARENT(PageStruct, the, PARENT(union PageStructUnion, tractStruct, (tract)))
|
||||
#define PagePool(page) RVALUE((page)->the.pool.pool)
|
||||
#define PageIsAllocated(page) RVALUE(PagePool(page) != NULL)
|
||||
#define PageType(page) RVALUE((page)->the.pool.state)
|
||||
#define PageSpareRing(page) RVALUE(&(page)->the.rest.spareRing)
|
||||
#define PageOfSpareRing(node) RING_ELT(Page, the.rest.spareRing, node)
|
||||
|
||||
#define PageSetPool(page, _pool) \
|
||||
BEGIN \
|
||||
PageStruct *_page = (page); \
|
||||
_page->the.pool.pool = (_pool); \
|
||||
AVER(PageType(_page) == PageStateALLOC); \
|
||||
END
|
||||
|
||||
#define PageSetType(page, _state) \
|
||||
BEGIN \
|
||||
PageStruct *_page = (page); \
|
||||
AVER(PagePool(_page) == NULL); \
|
||||
_page->the.pool.state = (_state); \
|
||||
END
|
||||
|
||||
|
||||
/* Chunks */
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue