MobOpsImpl.mesa
Copyright Ó 1988, 1991 by Xerox Corporation. All rights reserved.
Andy Litman August 24, 1988 8:52:52 pm PDT
JKF January 11, 1989 9:18:59 pm PST
Peter B. Kessler October 18, 1988 4:57:32 pm PDT
Russ Atkinson (RRA) December 19, 1988 5:02:37 pm PST
DIRECTORY
IO USING [GetLength, SetIndex, STREAM, UnsafeGetBlock],
MobDefs USING [Base, FTSelf, MobBase, MTIndex, SGHandle, SGNull, VersionStamp],
MobMapper USING [AlterMob],
MobOps USING [],
Rope USING [ROPE],
Symbols USING [Base, MDFirst],
SymbolSegment USING [Base, biases, bodyType, ctxType, ExtFirst, extType, FGHeader, htType, ltType, mdType, seType, ssType, STHeader, stType, treeType, VersionID],
SymbolTable USING [],
SymbolTablePrivate USING [SymbolTableBaseRep],
VM USING [AddressForPageNumber, Free, Interval, nullInterval, PagesForBytes, SimpleAllocate];
MobOpsImpl: PROGRAM
IMPORTS IO, MobMapper, VM
EXPORTS MobOps, SymbolTable
~ {
Cookies avoid having any global state
Cookie: TYPE = REF CookieObj;
CookieObj: PUBLIC TYPE = RECORD [
mob: MobDefs.MobBase,
openFile: IO.STREAM
];
bytesPerUnit: NAT = BYTES[UNIT];
FileError: PUBLIC ERROR[err: Rope.ROPE] = CODE;
WrongMobdefsVersion: PUBLIC ERROR = CODE;
Configuration: PUBLIC ERROR = CODE;
NoSymbols: PUBLIC ERROR = CODE;
WrongSymbolsVersion: PUBLIC ERROR = CODE;
DoMobStream: PUBLIC PROC
[file: IO.STREAM, proc: PROC[mob: MobDefs.MobBase, cookie: Cookie]] = {
mob: MobDefs.MobBase;
interval: VM.Interval ¬ VM.nullInterval;
openFile: IO.STREAM;
allocedBytes: INT ¬ IO.GetLength[file];
err: Rope.ROPE ¬ NIL;
Cleanup: PROC[] = {VM.Free[interval]};
openFile ¬ file;
IF err # NIL THEN ERROR FileError[err];
interval ¬ VM.SimpleAllocate[VM.PagesForBytes[allocedBytes]];
mob ¬ VM.AddressForPageNumber[interval.page];
IO.SetIndex[openFile, 0];
[] ¬ IO.UnsafeGetBlock[openFile, [LOOPHOLE[mob], 0, allocedBytes]];
IF MobMapper.AlterMob[mob, LOOPHOLE[mob], allocedBytes/BYTES[UNIT]] = badVersion THEN {
Cleanup[];
ERROR WrongMobdefsVersion;
};
proc[mob, NEW[CookieObj ¬ [mob, openFile]]
! UNWIND => Cleanup[];
];
Cleanup[];
};
STB: TYPE = REF SymbolTableBaseRep;
SymbolTableBaseRep: PUBLIC TYPE = SymbolTablePrivate.SymbolTableBaseRep;
DoSymbols: PUBLIC PROC [cookie: Cookie, proc: PROC[sym: STB]] = {
sym: STB ¬ NIL;
sgb: MobDefs.Base = LOOPHOLE[cookie.mob+cookie.mob.sgOffset.units];
mtb: MobDefs.Base = LOOPHOLE[cookie.mob+cookie.mob.mtOffset.units];
sgh: MobDefs.SGHandle = IF mtb[FIRST[MobDefs.MTIndex]].sseg = MobDefs.SGNull
THEN ERROR NoSymbols
ELSE @sgb[mtb[FIRST[MobDefs.MTIndex]].sseg];
stb: LONG POINTER TO SymbolSegment.STHeader = LOOPHOLE[cookie.mob+sgh.base.units];
IF cookie.mob.nConfigs # 0 THEN ERROR Configuration;
IF sgh.file # MobDefs.FTSelf OR sgh.units.units = 0 THEN ERROR NoSymbols;
IF stb.versionIdent # SymbolSegment.VersionID THEN
Consistency check failed!
ERROR WrongSymbolsVersion;
sym ¬ InstallTable[stb];
proc[sym];
};
InstallTable: PROC [node: LONG POINTER] RETURNS [STB] = {
b: LONG POINTER = node;
tB: SymbolSegment.Base = LOOPHOLE[b];
p: LONG POINTER TO SymbolSegment.STHeader = b;
base: STB ¬ NEW[SymbolTableBaseRep];
base.cacheInfo ¬ LOOPHOLE[node];
base.hashVec ¬ b+p.hvBlock.offset;
base.htb ¬ tB + p.htBlock.offset - SymbolSegment.biases[SymbolSegment.htType];
base.ssb ¬ b + p.ssBlock.offset - SymbolSegment.biases[SymbolSegment.ssType];
base.seb ¬ tB + p.seBlock.offset - SymbolSegment.biases[SymbolSegment.seType];
base.ctxb ¬ tB + p.ctxBlock.offset - SymbolSegment.biases[SymbolSegment.ctxType];
base.mdb ¬ tB + p.mdBlock.offset - SymbolSegment.biases[SymbolSegment.mdType];
base.bb ¬ tB + p.bodyBlock.offset - SymbolSegment.biases[SymbolSegment.bodyType];
base.tb ¬ tB + p.treeBlock.offset - SymbolSegment.biases[SymbolSegment.treeType];
base.ltb ¬ tB + p.litBlock.offset - SymbolSegment.biases[SymbolSegment.ltType];
base.stb ¬ tB + p.sLitBlock.offset - SymbolSegment.biases[SymbolSegment.stType];
base.extb ¬ tB + p.extBlock.offset - SymbolSegment.biases[SymbolSegment.extType];
base.mdLimit ¬ Symbols.MDFirst + p.mdBlock.size;
base.extLimit ¬ SymbolSegment.ExtFirst + p.extBlock.size;
base.mainCtx ¬ p.outerCtx; base.stHandle ¬ p;
IF p.fgRelBase = 0
THEN {
base.sourceFile ¬ NIL;
base.fgTable ¬ NIL;
}
ELSE {
bytesPerAU: NAT = BYTES[UNIT];
q: LONG POINTER TO SymbolSegment.FGHeader
= LOOPHOLE[b + p.fgRelBase/bytesPerAU];
source: LONG STRING = LOOPHOLE[q + SIZE[SymbolSegment.FGHeader[0]] - SIZE[StringBody[0]]];
base.sourceFile ¬ source;
base.fgTable ¬ DESCRIPTOR[q + q.offset, q.length];
};
IF base.ssb.length = 0 OR base.ssb.length > base.ssb.maxlength THEN ERROR;
Something is NOT kosher with the string table!
RETURN [base];
};
Cache: TYPE ~ REF CacheList ¬ NIL;
CacheRep: PUBLIC TYPE = CacheList;
CacheList: TYPE = REF CacheListRep;
CacheListRep: TYPE ~ RECORD [
rest: CacheList,
version: MobDefs.VersionStamp,
stb: STB,
interval: VM.Interval];
DoCachedSymbols: PUBLIC PROC [cookie: Cookie, proc: PROC[sym: STB], cache: Cache] = {
interval: VM.Interval;
sym: STB ¬ NIL;
sgb: MobDefs.Base = LOOPHOLE[cookie.mob+cookie.mob.sgOffset.units];
mtb: MobDefs.Base = LOOPHOLE[cookie.mob+cookie.mob.mtOffset.units];
sgh: MobDefs.SGHandle ¬ IF mtb[FIRST[MobDefs.MTIndex]].sseg = MobDefs.SGNull
THEN ERROR NoSymbols
ELSE @sgb[mtb[FIRST[MobDefs.MTIndex]].sseg];
bytes: INT = (sgh.units.units+sgh.extraUnits.units)*BYTES[UNIT];
stb: LONG POINTER TO SymbolSegment.STHeader ¬ LOOPHOLE[cookie.mob+sgh.base.units];
symbolSegment: LONG POINTER TO SymbolSegment.STHeader ¬ NIL;
IF cookie.mob.nConfigs # 0 THEN ERROR Configuration;
IF sgh.file # MobDefs.FTSelf OR sgh.units.units = 0 THEN ERROR NoSymbols;
IF stb.versionIdent # SymbolSegment.VersionID THEN ERROR WrongSymbolsVersion;
IF cache = NIL THEN {
No caching, so no copying
sym ¬ InstallTable[stb];
proc[sym];
RETURN;
};
FOR each: CacheList ¬ cache­, each.rest WHILE each # NIL DO
Search the cache for the desired version
IF each.version = stb.version THEN {
Found it!
proc[each.stb];
RETURN;
};
ENDLOOP;
interval ¬ VM.SimpleAllocate[VM.PagesForBytes[bytes]];
symbolSegment ¬ VM.AddressForPageNumber[interval.page];
CopyWords[
dst: LOOPHOLE[symbolSegment],
src: LOOPHOLE[stb],
nwords: bytes/BYTES[WORD]];
sym ¬ InstallTable[symbolSegment];
cache­ ¬ NEW[CacheListRep ¬ [cache­, symbolSegment.version, sym, interval]];
proc[sym];
};
NewCache: PUBLIC PROC RETURNS [Cache] ~ {
cache: Cache ~ NEW[CacheList ¬ NIL];
RETURN [cache];
};
FlushCache: PUBLIC PROC [cache: Cache] ~ {
IF cache # NIL THEN {
list: CacheList = cache­;
cache­ ¬ NIL;
FOR left: CacheList ¬ list, left.rest UNTIL left = NIL DO
VM.Free[left.interval];
ENDLOOP;
cache­ ¬ NIL;
};
};
CopyWords: PROC [dst, src: LONG POINTER TO WORD, nwords: CARD] = {
Copy from the src into the dst (dumb, really)
BlockPtr: TYPE = LONG POINTER TO Block;
Block: TYPE = ARRAY [0..16) OF WORD;
WHILE nwords >= WORDS[Block] DO
LOOPHOLE[dst, BlockPtr]­ ¬ LOOPHOLE[src, BlockPtr]­;
src ¬ src + SIZE[Block];
dst ¬ dst + SIZE[Block];
nwords ¬ nwords - WORDS[Block];
ENDLOOP;
WHILE nwords # 0 DO
dst­ ¬ src­;
src ¬ src + SIZE[WORD];
dst ¬ dst + SIZE[WORD];
nwords ¬ nwords - 1;
ENDLOOP;
};
}.