VMLowCoreImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) April 9, 1986 2:31:19 pm PST
DIRECTORY
VM USING [Allocate, Interval, AddressForPageNumber, PageCount, PagesForWords, PageNumberForAddress, Pin, WordsForPages],
VMInternal USING [Crash],
VMStatistics USING [];
VMLowCoreImpl: MONITOR
IMPORTS VM, VMInternal
EXPORTS VM, VMStatistics = BEGIN
Types
ZoneRep: TYPE = LONG POINTER TO ZoneObject;
ZoneObject: TYPE = MACHINE DEPENDENT RECORD [
procs(0:0..31): LONG POINTER TO ZoneProcs,
data(2:0..31): ZoneData
];
ZoneProcs: TYPE = MACHINE DEPENDENT RECORD [
allocate(0): PROC [UNCOUNTED ZONE, WordCount] RETURNS [LONG POINTER],
free(1): PROC [UNCOUNTED ZONE, LONG POINTER]
];
ZoneData: TYPE = ZoneChunk;
ZoneChunk: TYPE = LONG POINTER TO ZoneChunkObject;
ZoneChunkObject: TYPE = RECORD [
seal: INT ← chunkSeal,
nextChunk: ZoneChunk, -- could be a 16-bit relative pointer, but why bother?
wordsInChunk: INT,
wordsInUse: INT
];
WordCount: TYPE = CARDINAL;
Global "Variables"
lowCoreZone: ZoneObject ← [procs: @lowCoreZoneProcs, data: NIL];
lowCoreZoneProcs: ZoneProcs ← [allocate: Allocate, free: Free];
chunkSeal: INT = 32415;
alignment: WordCount = 16;
chunkOverhead: WordCount = Align[SIZE[ZoneChunkObject]];
Exports to VMStatistics
lowCoreAllocations, lowCoreWords, lowCorePages: PUBLIC INT ← 0;
Exports to VMSideDoor
lowCore: PUBLIC UNCOUNTED ZONE;
Internal Procedures
Align: PROC [w: WordCount] RETURNS [WordCount] = INLINE {
RETURN[((w + alignment - 1) / alignment) * alignment];
};
Allocate: ENTRY PROC [z: UNCOUNTED ZONE, nWords: WordCount] RETURNS [p: LONG POINTER] = {
previousChunk: ZoneChunk ← NIL;
chunk: ZoneChunk;
IF z ~= lowCore THEN VMInternal.Crash[];
nWords ← Align[MAX[nWords, 1]];
FOR chunk ← lowCoreZone.data, chunk.nextChunk UNTIL chunk = NIL DO
IF chunk.seal ~= chunkSeal THEN VMInternal.Crash[];
IF chunk.wordsInUse + nWords <= chunk.wordsInChunk
AND ( -- verify block would lie in a single page
VM.PageNumberForAddress[chunk + chunk.wordsInUse] =
VM.PageNumberForAddress[chunk + chunk.wordsInUse + nWords - 1]
OR VM.PagesForWords[nWords+chunkOverhead] > 1
)
THEN EXIT;
previousChunk ← chunk;
REPEAT
FINISHED => {
pages: VM.PageCount = VM.PagesForWords[nWords+chunkOverhead];
interval: VM.Interval = VM.Allocate[count: pages, partition: $lowCore];
--*stats*-- lowCorePages ← lowCorePages + pages;
VM.Pin[interval];
chunk ← VM.AddressForPageNumber[interval.page];
chunk^ ← [
nextChunk: IF previousChunk = NIL THEN NIL ELSE previousChunk.nextChunk,
wordsInChunk: VM.WordsForPages[interval.count],
wordsInUse: chunkOverhead
];
IF previousChunk = NIL THEN lowCoreZone.data ← chunk
ELSE previousChunk.nextChunk ← chunk;
};
ENDLOOP;
p ← chunk + chunk.wordsInUse;
chunk.wordsInUse ← chunk.wordsInUse + nWords;
--*stats*-- lowCoreAllocations ← lowCoreAllocations.SUCC;
--*stats*-- lowCoreWords ← lowCoreWords + nWords;
};
Free: ENTRY PROC [z: UNCOUNTED ZONE, p: LONG POINTER] = {};
Initialization
lowCore ← LOOPHOLE[LONG[@lowCoreZone]];
END.