<<>> <> <> <> <> <> <> <<>> 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 ~ { <> 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 <> 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; <> 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 { <> sym ¬ InstallTable[stb]; proc[sym]; RETURN; }; FOR each: CacheList ¬ cache­, each.rest WHILE each # NIL DO <> IF each.version = stb.version THEN { <> 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] = { <> 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; }; }.