<<>> <> <> <> <> <> <> DIRECTORY BasicTime USING[ToNSTime], CardTab USING[Create, Fetch, Insert, Ref, Store], Commander USING[CommandProc, Register], CommandTool USING[ArgumentVector, Parse], Convert USING[RopeFromCard], ConvertUnsafe USING[SubString, SubStringToRope], CountedVM USING[Handle, SimpleAllocate], IO USING[card, GetLength, PutF, PutFR, PutRope, rope, RopeFromROS, ROS, SetIndex, STREAM, UnsafeGetBlock, Value], MobAccess, MobDefs USING[Base, FTSelf, MobBase, MTIndex, NullVersion, SGHandle, SGNull, VersionID, VersionStamp], MobMapper USING[AlterMob], MobUtilDefs USING[MobHandle, MobObject], PBasics USING[BITLSHIFT, BITRSHIFT, BITXOR, LongNumber], PFS USING [UniqueID, PathFromRope, RopeFromPath], PFSNames USING [PATH], RefTab USING[Create, Fetch, Key, Insert, Ref], Rope USING[Cat, Equal, ROPE], Symbols, SymbolSegment USING[Base, biases, bodyType, ctxType, ExtFirst, extType, FGHeader, htType, ltType, mdType, seType, ssType, stType, STHeader, treeType, VersionID], SymbolTablePrivate USING[SymbolTableBaseRep], SystemInterface USING[FileSet, CirioFile, GetStreamForFile, ReleaseStreamForFile, GetFileInfo, CirioFileInfo, CreateFileSet, GetCirioFile, CloseFileSet, GetNameOfFile], VM USING[PagesForBytes, WordsForPages]; <<>> MobAccessImpl: CEDAR PROGRAM IMPORTS BasicTime, CardTab, Commander, CommandTool, Convert, ConvertUnsafe, CountedVM, IO, MobMapper, PBasics, PFS, RefTab, Rope, SystemInterface, VM EXPORTS MobAccess = BEGIN MobError: PUBLIC ERROR[msg: Rope.ROPE] = CODE; <MobMapperImpl.mesa>> <<>> <> <> <<>> MobCookie: TYPE = REF MobCookieBody; MobCookieBody: PUBLIC TYPE = RECORD[ file: SystemInterface.CirioFile, <> mobHandle: MobUtilDefs.MobHandle, -- contains some of the table bases mobBase: MobDefs.MobBase, sym: SymbolTableBase, <> leftShift: CARD, rightShift: CARD, <> recentBtiParent: Symbols.BTIndex _ Symbols.BTFirst, <> seiTable: RefTab.Ref, ctxTable: RefTab.Ref, btTable: RefTab.Ref, mdTable: CardTab.Ref, stringTable: CardTab.Ref, lostSeis: CardTab.Ref ]; GetFileForMobCookie: PUBLIC PROC [mc: MobCookie] RETURNS [SystemInterface.CirioFile] = {RETURN [mc.file]}; CreateMobCookie: PUBLIC PROC[f: SystemInterface.CirioFile] RETURNS[MobCookie] = { newCookie: MobCookie _ NEW[MobCookieBody]; stream: IO.STREAM _ SystemInterface.GetStreamForFile[f]; ctxh: CTXH; ctxr: CTXR; seh: SEH; BEGIN ENABLE UNWIND => SystemInterface.ReleaseStreamForFile[f, stream]; newCookie.file _ f; newCookie.seiTable _ RefTab.Create[equal: SEIKeyEqualProc, hash: SEIKeyHashProc]; newCookie.ctxTable _ RefTab.Create[equal: CTXKeyEqualProc, hash: CTXKeyHashProc]; newCookie.btTable _ RefTab.Create[equal: BTKeyEqualProc, hash: BTKeyHashProc]; newCookie.mdTable _ CardTab.Create[]; newCookie.stringTable _ CardTab.Create[]; newCookie.lostSeis _ CardTab.Create[]; <> <> < SystemInterface.ReleaseStreamForFile[f, stream]>> TRUSTED { [newCookie.mobHandle, newCookie.mobBase] _ ReadMob[stream]}; TRUSTED{newCookie.sym _ GetSymbols[newCookie.mobBase]; newCookie.leftShift _ SELECT TRUE FROM BITS[UNIT] >= newCookie.mobBase.format.bitsPerUnit[0] => 0, BITS[UNIT] = 8 AND newCookie.mobBase.format.bitsPerUnit[0] = 16 => 1, ENDCASE => ERROR MobError["can't adjust mob"]; newCookie.rightShift _ SELECT TRUE FROM BITS[UNIT] <= newCookie.mobBase.format.bitsPerUnit[0] => 0, BITS[UNIT] = 16 AND newCookie.mobBase.format.bitsPerUnit[0] = 8 => 1, ENDCASE => ERROR MobError["can't adjust mob"]}; END; SystemInterface.ReleaseStreamForFile[f, stream]; ctxh _ ReallyMakeCTXH[newCookie, Symbols.CTXNull]; ctxr _ FetchCTXR[ctxh]; IF ctxr#NIL THEN seh _ ctxr.seList; WHILE seh#NIL DO ser: SER ~ FetchSER[seh]; WITH ser.body SELECT FROM idser: REF id BodySE => { IF idser.idCtx=NIL OR idser.idCtx=ctxh THEN [] _ newCookie.lostSeis.Store[LOOPHOLE[seh.sei], $T]; seh _ idser.ctxLink}; ENDCASE => NULL; ENDLOOP; RETURN[newCookie]}; IsLost: PUBLIC PROC[seh: SEH] RETURNS[BOOL] ~ {RETURN [seh.mob.lostSeis.Fetch[LOOPHOLE[seh.sei]].found]}; ReadMobVersionStamp: PUBLIC PROC[mob: MobCookie] RETURNS[MobDefs.VersionStamp] = BEGIN versionStamp: MobDefs.VersionStamp _ ALL[0]; LookForVersionStamp: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED {versionStamp _ mobBase.version}; ExamineMob[mob, LookForVersionStamp]; RETURN[versionStamp]; END; ReadSourceVersionStamp: PUBLIC PROC[mob: MobCookie] RETURNS[MobDefs.VersionStamp] = BEGIN versionStamp: MobDefs.VersionStamp _ ALL[0]; LookForSourceVersionStamp: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED {versionStamp _ mobBase.sourceVersion}; ExamineMob[mob, LookForSourceVersionStamp]; RETURN[versionStamp]; END; <> <CcDeps.mesa MobStampFromTime>> ComputeSourceVersionStamp: PUBLIC PROC[mesaSourceFile: SystemInterface.CirioFile] RETURNS[MobDefs.VersionStamp] = BEGIN fileInfo: SystemInterface.CirioFileInfo _ SystemInterface.GetFileInfo[mesaSourceFile]; vs: MobDefs.VersionStamp _ MobDefs.NullVersion; vs[0] _ BasicTime.ToNSTime[fileInfo.uniqueID.egmt.time]; RETURN[vs]; END; ExamineMob: PROC[cookie: MobCookie, examiner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase]] = {examiner[cookie.mobHandle, cookie.mobBase, cookie.sym]}; VSKeyEqualProc: PROC[key1, key2: RefTab.Key] RETURNS[BOOL] = BEGIN vs1AsKey: REF MobDefs.VersionStamp _ NARROW[key1]; vs2AsKey: REF MobDefs.VersionStamp _ NARROW[key2]; RETURN[vs1AsKey^ = vs2AsKey^]; END; VSKeyHashProc: PROC[key: RefTab.Key] RETURNS[CARDINAL] = TRUSTED BEGIN vsAsKey: REF MobDefs.VersionStamp _ NARROW[key]; word0: PBasics.LongNumber _ LOOPHOLE[vsAsKey^[0]]; word1: PBasics.LongNumber _ LOOPHOLE[vsAsKey^[1]]; RETURN[PBasics.BITXOR[PBasics.BITXOR[word0.lo, word0.hi], PBasics.BITXOR[word1.lo, word1.hi]]]; END; <MobUtilities.mesa>> <<>> bytesPerWord: CARD = BYTES[WORD]; bytesPerVMWord: CARD = BYTES[WORD]; ReadMob: PROC [stream: IO.STREAM] RETURNS [h: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase] = TRUSTED { bytes: INT _ IO.GetLength[stream]; allocatedBytes: CARD _ VM.WordsForPages[VM.PagesForBytes[bytes]] * bytesPerVMWord; vmh: CountedVM.Handle; IF bytes = 0 THEN ERROR MobError["empty mob file"]; vmh _ CountedVM.SimpleAllocate[allocatedBytes/bytesPerWord]; <> IO.SetIndex[stream, 0]; [] _ IO.UnsafeGetBlock[ self: stream, block: [base: vmh.pointer, startIndex: 0, count: bytes]]; mobBase _ LOOPHOLE[vmh.pointer]; IF MobMapper.AlterMob[mobBase, LOOPHOLE[mobBase], bytes/BYTES[UNIT]] = badVersion THEN ERROR MobError["MobMapper.AlterMob failed in MobUtilities.ReadMob"]; IF mobBase.versionIdent # MobDefs.VersionID THEN MobError["not a MOB file"]; <> h _ NEW[MobUtilDefs.MobObject _ [ bHeader: mobBase, countedVMHandle: vmh, bases: [ ctb: LOOPHOLE[mobBase + mobBase.ctOffset.units], mtb: LOOPHOLE[mobBase + mobBase.mtOffset.units], lfb: LOOPHOLE[mobBase + mobBase.lfOffset.units], rfb: LOOPHOLE[mobBase + mobBase.rfOffset.units], tfb: LOOPHOLE[mobBase + mobBase.tfOffset.units], etb: LOOPHOLE[mobBase + mobBase.expOffset.units], itb: LOOPHOLE[mobBase + mobBase.impOffset.units], sgb: LOOPHOLE[mobBase + mobBase.sgOffset.units], ftb: LOOPHOLE[mobBase + mobBase.ftOffset.units], ssb: LOOPHOLE[mobBase + mobBase.ssOffset.units], evb: LOOPHOLE[mobBase + mobBase.evOffset.units], tyb: LOOPHOLE[mobBase + mobBase.typOffset.units], tmb: LOOPHOLE[mobBase + mobBase.tmOffset.units], ntb: LOOPHOLE[mobBase + mobBase.ntOffset.units], spb: LOOPHOLE[mobBase + mobBase.spOffset.units], fpb: LOOPHOLE[mobBase + mobBase.fpOffset.units] ], limits: [ ct: mobBase.ctLimit, mt: mobBase.mtLimit, et: mobBase.expLimit, it: mobBase.impLimit, sg: mobBase.sgLimit, ft: mobBase.ftLimit, tm: mobBase.tmLimit, nt: mobBase.ntLimit, sp: mobBase.spLimit, fp: mobBase.fpLimit] ]]; }; <KLister.mesa ProcessSymbols>> SymbolTableBase: TYPE = REF SymbolTableBaseRep; SymbolTableBaseRep: TYPE = SymbolTablePrivate.SymbolTableBaseRep; GetSymbols: PROC[mob: MobDefs.MobBase] RETURNS[SymbolTableBase] = TRUSTED BEGIN sgb: MobDefs.Base = LOOPHOLE[mob+mob.sgOffset.units]; mtb: MobDefs.Base = LOOPHOLE[mob+mob.mtOffset.units]; sgh: MobDefs.SGHandle = IF mtb[FIRST[MobDefs.MTIndex]].sseg = MobDefs.SGNull THEN ERROR MobError["NoSymbols"] ELSE @sgb[mtb[FIRST[MobDefs.MTIndex]].sseg]; stb: LONG POINTER TO SymbolSegment.STHeader = LOOPHOLE[mob+sgh.base.units]; IF mob.nConfigs # 0 THEN ERROR MobError["Can't get symbols from a config"]; IF sgh.file # MobDefs.FTSelf OR sgh.units.units = 0 THEN ERROR MobError["funny looking mob"]; --NoSymbols; IF stb.versionIdent # SymbolSegment.VersionID THEN ERROR MobError["invalid-looking mob"]; -- WrongSymbolsVersion; RETURN[InstallSymbolTable[stb]] END; InstallSymbolTable: PROC [node: LONG POINTER] RETURNS [SymbolTableBase] = TRUSTED { b: LONG POINTER = node; tB: SymbolSegment.Base = LOOPHOLE[b]; p: LONG POINTER TO SymbolSegment.STHeader = b; base: SymbolTableBase _ 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 OR p.fgCount = 0 THEN { base.sourceFile _ NIL; base.fgTable _ NIL; } ELSE { q: LONG POINTER TO SymbolSegment.FGHeader = LOOPHOLE[b + p.fgRelBase]; source: LONG STRING = LOOPHOLE[q + SIZE[SymbolSegment.FGHeader[0]] - SIZE[StringBody[0]]]; base.sourceFile _ source; base.fgTable _ DESCRIPTOR[q + q.offset, q.length]; }; RETURN [base]; }; <> <<>> BTR: TYPE = MobAccess.BTR; BTRBody: TYPE = MobAccess.BTRBody; BodyLinkRcd: TYPE = MobAccess.BodyLinkRcd; BTH: TYPE = REF BTHBody; BTHBody: PUBLIC TYPE = RECORD[ mob: MobCookie, bti: Symbols.BTIndex, btr: BTR]; BTHDetails: PUBLIC PROC [bth: BTH] RETURNS [mob: MobCookie, bti: Symbols.BTIndex] ~ {RETURN [bth.mob, bth.bti]}; MakeBTH: PUBLIC PROC[mob: MobCookie, bti: Symbols.BTIndex] RETURNS[BTH] = BEGIN IF bti = Symbols.BTNull THEN RETURN[NIL] ELSE BEGIN btiAsKey: REF Symbols.BTIndex _ NEW[Symbols.BTIndex _ bti]; bth: BTH _ NARROW[RefTab.Fetch[mob.btTable, btiAsKey].val]; IF bth # NIL THEN RETURN[bth]; bth _ NEW[BTHBody_[mob, bti, NIL]]; IF NOT RefTab.Insert[mob.btTable, btiAsKey, bth] THEN ERROR MobError["MobAccessImpl confused (by concurrent access?)"]; RETURN[bth] END END; <> MakeBTHFromCodedBti: PUBLIC PROC[mob: MobCookie, codedBti: CARD] RETURNS[BTH] = BEGIN tentativeResult: BTH _ NIL; Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN shiftedBti: CARD _ SELECT TRUE FROM mob.leftShift # 0 => PBasics.BITLSHIFT[codedBti, mob.leftShift], mob.rightShift # 0 => PBasics.BITRSHIFT[codedBti, mob.rightShift], ENDCASE => codedBti; tentativeBti: Symbols.BTIndex _ LOOPHOLE[shiftedBti]; <> tentativeBtiAsKey: REF Symbols.BTIndex _ NEW[Symbols.BTIndex _ tentativeBti]; tentativeResult _ NARROW[RefTab.Fetch[mob.btTable, tentativeBtiAsKey].val]; IF tentativeResult = NIL THEN -- we have to build it from scratch BEGIN [] _ CheckTentativeBti[tentativeBti, mob, sym, 0 ! BadTentativeBti => {GOTO failure}]; tentativeResult _ MakeBTH[mob, tentativeBti]; EXITS failure => NULL; -- thus, leaving result = NIL END; END; ExamineMob[mob, Inner]; RETURN[tentativeResult]; END; GetRootBTH: PUBLIC PROC[mob: MobCookie] RETURNS[BTH] ~ {RETURN MakeBTH[mob, Symbols.BTFirst]}; <> CheckTentativeBti: PROC[tentativeBti: Symbols.BTIndex, mob: MobCookie, sym: SymbolTableBase, checkDepth: CARD] RETURNS[Symbols.BTIndex] = TRUSTED BEGIN IF checkDepth > 15 THEN BadTentativeBti[tentativeBti]; <> [] _ BoundsCheckTentativeBti[tentativeBti, sym]; IF tentativeBti = Symbols.BTFirst THEN RETURN[tentativeBti]; IF tentativeBti = mob.recentBtiParent THEN RETURN[tentativeBti]; <> BEGIN counter: INT _ 0; scan: Symbols.BTIndex _ tentativeBti; parent: Symbols.BTIndex; DO IF sym.bb[scan].link.which = parent THEN EXIT; IF counter > 1000 THEN BadTentativeBti[tentativeBti]; <> counter _ counter + 1; IF sym.bb[scan].link.which = sibling THEN {scan _ BoundsCheckTentativeBti[sym.bb[scan].link.index, sym]; LOOP}; BadTentativeBti[tentativeBti]; ENDLOOP; <> parent _ CheckTentativeBti[sym.bb[scan].link.index, mob, sym, checkDepth+1]; scan _ BoundsCheckTentativeBti[sym.bb[parent].firstSon, sym]; DO IF counter > 1000 THEN BadTentativeBti[tentativeBti]; <> counter _ counter + 1; IF scan = tentativeBti THEN {mob.recentBtiParent _ parent; RETURN[tentativeBti]}; IF sym.bb[scan].link.which = parent THEN BadTentativeBti[tentativeBti]; IF sym.bb[scan].link.which = sibling THEN scan _ BoundsCheckTentativeBti[sym.bb[scan].link.index, sym]; ENDLOOP; END; END; BoundsCheckTentativeBti: PROC[tentativeBti: Symbols.BTIndex, sym: SymbolTableBase] RETURNS[Symbols.BTIndex] = TRUSTED BEGIN -- this must act like a relative pointer that lands within the body table addr: CARD _ LOOPHOLE[sym.bb, CARD] + LOOPHOLE[tentativeBti, CARD]; <> tableBase: CARD _ LOOPHOLE[sym.stHandle, CARD] + LOOPHOLE[sym.stHandle.bodyBlock.offset, CARD]; IF addr < tableBase THEN <> BadTentativeBti[tentativeBti]; IF addr >= tableBase+sym.stHandle.bodyBlock.size THEN <> BadTentativeBti[tentativeBti]; RETURN[tentativeBti]; END; BadTentativeBti: ERROR[Symbols.BTIndex] = CODE; <> GenCallableBodies: PUBLIC PROC[mob: MobCookie, for: PROC[callableBody: BTH]] = TRUSTED BEGIN Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN Visit: PROC[bti: Symbols.BTIndex] = TRUSTED {IF sym.bb[bti].kind = Callable THEN for[MakeBTH[mob, bti]]}; ScanSubTree: PROC[treeRoot: Symbols.BTIndex] = TRUSTED BEGIN IF sym.bb[treeRoot].firstSon # Symbols.BTNull THEN FOR scan: Symbols.BTIndex _ sym.bb[treeRoot].firstSon, sym.bb[scan].link.index WHILE scan # treeRoot DO ScanSubTree[scan]; Visit[scan]; ENDLOOP; END; ScanSubTree[Symbols.RootBti]; Visit[Symbols.RootBti]; END; ExamineMob[mob, Inner]; END; GetParentOfBTH: PUBLIC PROC[bth: BTH] RETURNS[BTH] = BEGIN result: BTH _ NIL; -- tentative Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN IF bth.bti = Symbols.RootBti THEN {result _ NIL} ELSE BEGIN x: Symbols.BTIndex _ bth.bti; WHILE sym.bb[x].link.which # parent DO x _ sym.bb[x].link.index ENDLOOP; result _ MakeBTH[bth.mob, sym.bb[x].link.index]; END; END; ExamineMob[bth.mob, Inner]; RETURN[result]; END; GetCodedBTIFromBTH: PUBLIC PROC[bth: BTH] RETURNS[CARD] = BEGIN result: CARD _ 0; Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN <> result _ SELECT TRUE FROM bth.mob.leftShift # 0 => PBasics.BITRSHIFT[LOOPHOLE[bth.bti], bth.mob.leftShift], bth.mob.rightShift # 0 => PBasics.BITLSHIFT[LOOPHOLE[bth.bti], bth.mob.rightShift], ENDCASE => LOOPHOLE[bth.bti]; END; ExamineMob[bth.mob, Inner]; RETURN[result] END; BTKeyEqualProc: PROC[key1, key2: RefTab.Key] RETURNS [BOOL] = BEGIN bti1Ref: REF Symbols.BTIndex _ NARROW[key1]; bti2Ref: REF Symbols.BTIndex _ NARROW[key2]; RETURN[bti1Ref^ = bti2Ref^]; END; BTKeyHashProc: PROC[key: RefTab.Key] RETURNS [CARDINAL] = BEGIN btiRef: REF Symbols.BTIndex _ NARROW[key]; asLongNumber: Basics.LongNumber _ LOOPHOLE[btiRef^]; RETURN[Basics.BITXOR[asLongNumber.lo, asLongNumber.hi]]; END; FetchBTR: PUBLIC PROC[bth: BTH] RETURNS[BTR] = BEGIN Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN bth.btr _ NEW[BTRBody_[ link: [ which: IF sym.bb[bth.bti].link.which = sibling THEN sibling ELSE parent, index: MakeBTH[bth.mob, sym.bb[bth.bti].link.index]], firstSon: MakeBTH[bth.mob, sym.bb[bth.bti].firstSon], type: MakeSEH[bth.mob, sym.bb[bth.bti].type], localCtx: MakeCTXH[bth.mob, sym.bb[bth.bti].localCtx], sourceIndex: sym.bb[bth.bti].sourceIndex, info: MakeBTInfo[bth, mobHandle, mobBase, sym], level: sym.bb[bth.bti].level, class: sym.bb[bth.bti].class, extension: MakeBTExtension[bth, mobHandle, mobBase, sym]]]; END; IF bth = NIL THEN RETURN[NIL]; IF bth.btr = NIL THEN ExamineMob[bth.mob, Inner]; RETURN[bth.btr]; END; MakeBTInfo: PROC[bth: BTH, mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] RETURNS[REF MobAccess.BodyInfo] = TRUSTED BEGIN WITH info: sym.bb[bth.bti].info SELECT FROM Internal => RETURN[NEW[Internal MobAccess.BodyInfo _ [Internal[info.frameSize]]]]; External => RETURN[NEW[External MobAccess.BodyInfo _ [External[ bytes: info.bytes, startIndex: info.startIndex, indexLength: info.indexLength]]]]; ENDCASE => ERROR MobError["invalid BodyInfo.mark"]; END; MakeBTExtension: PROC[bth: BTH, mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] RETURNS[REF MobAccess.BTRExtension] = TRUSTED BEGIN WITH extension: sym.bb[bth.bti] SELECT FROM Callable => RETURN[NEW[Callable MobAccess.BTRExtension _ [Callable[ id: MakeSEH[bth.mob, extension.id], ioType: MakeSEH[bth.mob, extension.ioType], frameOffset: extension.frameOffset, entryIndex: extension.entryIndex, hints: [extension.hints.safe, extension.hints.argUpdated, extension.hints.nameSafe, extension.hints.noStrings], entry: extension.entry, internal: extension.internal, inline: extension.inline, monitored: extension.monitored, noXfers: extension.noXfers, resident: extension.resident, kind: SELECT extension.kind FROM Outer => Outer, Inner => Inner, Catch => Catch, Other => Other, ENDCASE => ERROR MobError["invalid Callable BodyRecord BodyKind"] ]]]]; Other => RETURN[NEW[Other MobAccess.BTRExtension _ [Other[extension.relOffset]]]]; ENDCASE => ERROR MobError["invalid BodyRecord kind"]; END; GenBodiesWithDepth: PROC[mob: MobCookie, body: BTH, baseDepth: INT, for: PROC[body: BTH, depth: INT]] = TRUSTED BEGIN Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN Visit: PROC[bti: Symbols.BTIndex] = TRUSTED BEGIN bth: BTH _ MakeBTH[mob, bti]; for[bth, baseDepth+1]; GenBodiesWithDepth[mob, bth, baseDepth+1, for]; END; ScanSubTree: PROC[treeRoot: Symbols.BTIndex] = TRUSTED BEGIN IF sym.bb[treeRoot].firstSon # Symbols.BTNull THEN FOR scan: Symbols.BTIndex _ sym.bb[treeRoot].firstSon, sym.bb[scan].link.index WHILE scan # treeRoot DO ScanSubTree[scan]; Visit[scan]; ENDLOOP; END; ScanSubTree[body.bti]; END; ExamineMob[mob, Inner]; END; MobBodyTreeToRope: PROC[mob: MobCookie] RETURNS[Rope.ROPE] = {RETURN[BodyTreeToRope[mob, MakeBTH[mob, Symbols.RootBti]]]}; BodyTreeToRope: PROC[mob: MobCookie, body: BTH] RETURNS[Rope.ROPE] = BEGIN rope: Rope.ROPE _ NIL; eachBody: PROC[body: BTH, depth: INT] = BEGIN rope _ Rope.Cat[rope, BodyToRope[body, depth], "\N"]; END; eachBody[body, 0]; GenBodiesWithDepth[mob, body, 1, eachBody]; RETURN[rope]; END; BodyToRope: PROC[body: BTH, depth: INT] RETURNS[Rope.ROPE] = BEGIN btr: BTR _ FetchBTR[body]; st: IO.STREAM _ IO.ROS[]; putDepth: PROC[d: INT_0] = {FOR I: INT IN [0..depth+d) DO IO.PutF[st, " "] ENDLOOP}; rope: PROC[r: Rope.ROPE, d: INT _ 0] = {putDepth[d]; IO.PutRope[st, r]}; put: PROC[d: INT, f: Rope.ROPE, v1, v2, v3, v4, v5: IO.Value _ [null[]]] = BEGIN putDepth[d]; IO.PutF[st, f, v1, v2, v3, v4, v5]; END; rope["body"]; put[0, " source index = %g\N", IO.card[btr.sourceIndex]]; rope[CTXToRope[btr.localCtx, depth+5]]; RETURN[IO.RopeFromROS[st]]; END; <<>> <<>> <> <<>> <<>> MDR: TYPE = MobAccess.MDR; MDRBody: TYPE = MobAccess.MDRBody; MDH: TYPE = REF MDHBody; MDHBody: PUBLIC TYPE = RECORD[ mob: MobCookie, mdi: Symbols.MDIndex, mdr: MDR]; MakeMDH: PUBLIC PROC[mob: MobCookie, mdi: Symbols.MDIndex] RETURNS[MDH] = BEGIN IF mdi = Symbols.MDNull THEN RETURN[NIL] ELSE BEGIN mdiAsKey: CARD ~ LOOPHOLE[mdi]; mdh: MDH _ NARROW[CardTab.Fetch[mob.mdTable, mdiAsKey].val]; IF mdh # NIL THEN RETURN[mdh]; mdh _ NEW[MDHBody_[mob, mdi, NIL]]; IF NOT CardTab.Insert[mob.mdTable, mdiAsKey, mdh] THEN ERROR MobError["MobAccessImpl confused (by concurrent access?)"]; RETURN[mdh] END END; FetchMDR: PUBLIC PROC[mdh: MDH] RETURNS[MDR] = BEGIN Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN raw: LONG POINTER TO Symbols.MDRecord ~ @sym.mdb[mdh.mdi]; mdh.mdr _ NEW[MDRBody_[ stamp: raw.stamp, moduleId: RopeForName[mdh.mob, mobHandle, mobBase, sym, raw.moduleId], fileId: RopeForName[mdh.mob, mobHandle, mobBase, sym, raw.fileId], shared: raw.shared, exported: raw.exported, ctx: MakeCTXH[mdh.mob, raw.ctx], defaultImport: MakeCTXH[mdh.mob, raw.defaultImport] ]]; END; IF mdh = NIL THEN RETURN[NIL]; IF mdh.mdr = NIL THEN ExamineMob[mdh.mob, Inner]; RETURN[mdh.mdr]; END; GetMobForMDH: PUBLIC PROC[mdh: MDH] RETURNS[MobCookie] = {RETURN[mdh.mob]}; GetMdiForMDH: PUBLIC PROC[mdh: MDH] RETURNS[Symbols.MDIndex] = {RETURN[mdh.mdi]}; <> <<>> <<>> CTXR: TYPE = MobAccess.CTXR; CTXRBody: TYPE = MobAccess.CTXRBody; CTXH: TYPE = REF CTXHBody; CTXHBody: PUBLIC TYPE = RECORD[ mob: MobCookie, ctx: Symbols.CTXIndex, ctxr: CTXR]; MakeCTXH: PUBLIC PROC[mob: MobCookie, ctx: Symbols.CTXIndex] RETURNS[CTXH] = { IF ctx = Symbols.CTXNull THEN RETURN[NIL] ELSE RETURN ReallyMakeCTXH[mob, ctx]}; ReallyMakeCTXH: PROC[mob: MobCookie, ctx: Symbols.CTXIndex] RETURNS[CTXH] = { ctxAsKey: REF Symbols.CTXIndex _ NEW[Symbols.CTXIndex _ ctx]; ctxh: CTXH _ NARROW[RefTab.Fetch[mob.ctxTable, ctxAsKey].val]; IF ctxh # NIL THEN RETURN[ctxh]; ctxh _ NEW[CTXHBody_[mob, ctx, NIL]]; IF NOT RefTab.Insert[mob.ctxTable, ctxAsKey, ctxh] THEN ERROR MobError["MobAccessImpl confused (by concurrent access?)"]; RETURN[ctxh]}; MakeStdCtxh: PUBLIC PROC[mob: MobCookie] RETURNS[CTXH] ~ {RETURN MakeCTXH[mob, Symbols.FirstStandardCtx]}; BoundsCheckTentativeCTX: PROC[tentativeCTX: Symbols.CTXIndex, sym: SymbolTableBase] RETURNS[Symbols.CTXIndex] = TRUSTED BEGIN addr: CARD _ LOOPHOLE[sym.ctxb, CARD] + LOOPHOLE[tentativeCTX, CARD]; <> tableBase: CARD _ LOOPHOLE[sym.stHandle, CARD] + LOOPHOLE[sym.stHandle.ctxBlock.offset, CARD]; IF tentativeCTX = Symbols.CTXNull THEN BadTentativeCTX[tentativeCTX]; IF addr < tableBase THEN <> BadTentativeCTX[tentativeCTX]; IF addr >= tableBase+sym.stHandle.ctxBlock.size THEN <> BadTentativeCTX[tentativeCTX]; RETURN[tentativeCTX]; END; BadTentativeCTX: ERROR[Symbols.CTXIndex] = CODE; CTXKeyEqualProc: PROC[key1, key2: RefTab.Key] RETURNS [BOOL] = BEGIN ctx1Ref: REF Symbols.CTXIndex _ NARROW[key1]; ctx2Ref: REF Symbols.CTXIndex _ NARROW[key2]; RETURN[ctx1Ref^ = ctx2Ref^]; END; CTXKeyHashProc: PROC[key: RefTab.Key] RETURNS [CARDINAL] = BEGIN ctxRef: REF Symbols.CTXIndex _ NARROW[key]; asLongNumber: Basics.LongNumber _ LOOPHOLE[ctxRef^]; RETURN[Basics.BITXOR[asLongNumber.lo, asLongNumber.hi]]; END; FetchCTXR: PUBLIC PROC[ctxh: CTXH] RETURNS[CTXR] = BEGIN Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN seH: SEH ~ MakeSEH[ctxh.mob, sym.ctxb[ctxh.ctx].seList]; lvl: Symbols.ContextLevel ~ sym.ctxb[ctxh.ctx].level; varUpdated: BOOL ~ sym.ctxb[ctxh.ctx].varUpdated; WITH x: sym.ctxb[ctxh.ctx] SELECT FROM simple => ctxh.ctxr _ NEW[CTXRBody_[seList: seH, level: lvl, varUpdated: varUpdated, extension: simple[copied: x.copied] ]]; included => ctxh.ctxr _ NEW[CTXRBody_[seList: seH, level: lvl, varUpdated: varUpdated, extension: included[ chain: MakeCTXH[ctxh.mob, x.chain], module: MakeMDH[ctxh.mob, x.module], map: x.map, copied: x.copied, reset: x.reset, closed: x.closed, complete: x.complete, restricted: x.restricted ] ]]; imported => ctxh.ctxr _ NEW[CTXRBody_[seList: seH, level: lvl, varUpdated: varUpdated, extension: imported[MakeCTXH[ctxh.mob, x.includeLink]] ]]; nil => ctxh.ctxr _ NEW[CTXRBody_[seList: seH, level: lvl, varUpdated: varUpdated, extension: nil[] ]]; ENDCASE => ERROR MobError["invalid CTXRecord ctxType"]; END; IF ctxh = NIL THEN RETURN[NIL]; IF ctxh.ctxr = NIL THEN ExamineMob[ctxh.mob, Inner]; RETURN[ctxh.ctxr]; END; GetMobForCTXH: PUBLIC PROC[ctxh: CTXH] RETURNS[MobCookie] = {RETURN[ctxh.mob]}; GetCtxForCTXH: PUBLIC PROC[ctxh: CTXH] RETURNS[Symbols.CTXIndex] = {RETURN[ctxh.ctx]}; <> <> CTXToRope: PROC[ctxh: CTXH, depth: INT] RETURNS[Rope.ROPE] = BEGIN IF ctxh = NIL THEN RETURN[NIL] ELSE BEGIN ctxr: CTXR _ FetchCTXR[ctxh]; st: IO.STREAM _ IO.ROS[]; seh: SEH _ ctxr.seList; putDepth: PROC[d: INT_0] = {FOR I: INT IN [0..depth+d) DO IO.PutF[st, " "] ENDLOOP}; putDepth[]; IO.PutF[st, "ctx = %g, level = %g\N", IO.rope[Convert.RopeFromCard[LOOPHOLE[ctxh.ctx]]], IO.card[ctxr.level]]; WHILE seh # NIL DO ser: SER _ FetchSER[seh]; IO.PutF[st, "%g", IO.rope[SEHToRope[seh, depth+2]]]; WITH ser.body SELECT FROM id: REF id BodySE => seh _ id.ctxLink; ENDCASE => seh _ NIL; ENDLOOP; RETURN[IO.RopeFromROS[st]]; END END; <<>> <<>> <> <<>> SER: TYPE = MobAccess.SER; SERBody: TYPE = MobAccess.SERBody; BodySE: TYPE = MobAccess.BodySE; TypeInfoConsSE: TYPE = MobAccess.TypeInfoConsSE; SEH: TYPE = REF SEHBody; SEHBody: PUBLIC TYPE = RECORD[ mob: MobCookie, sei: Symbols.SEIndex, ser: SER]; MakeSEH: PUBLIC PROC[mob: MobCookie, sei: Symbols.SEIndex] RETURNS[SEH] = BEGIN IF sei = Symbols.SENull THEN RETURN[NIL] ELSE BEGIN seiAsKey: REF Symbols.SEIndex _ NEW[Symbols.SEIndex _ sei]; seh: SEH _ NARROW[RefTab.Fetch[mob.seiTable, seiAsKey].val]; IF seh # NIL THEN RETURN[seh]; seh _ NEW[SEHBody_[mob, sei, NIL]]; IF NOT RefTab.Insert[mob.seiTable, seiAsKey, seh] THEN ERROR MobError["MobAccessImpl confused (by concurrent access?)"]; RETURN[seh] END; END; <> MakeSEHFromCodedSei: PUBLIC PROC[mob: MobCookie, codedSei: CARD, name: Rope.ROPE] RETURNS[SEH] = TRUSTED BEGIN tentativeResult: SEH _ NIL; <> Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN seNull: CARD ~ LOOPHOLE[Symbols.SENull]; <> <> shiftedSei: CARD _ SELECT TRUE FROM mob.leftShift # 0 => PBasics.BITLSHIFT[codedSei, mob.leftShift], mob.rightShift # 0 => PBasics.BITRSHIFT[codedSei, mob.rightShift], ENDCASE => codedSei; tentativeSei: Symbols.SEIndex _ LOOPHOLE[shiftedSei+seNull]; <> tentativeSeiAsKey: REF Symbols.SEIndex _ NEW[Symbols.SEIndex _ tentativeSei]; tentativeResult _ NARROW[RefTab.Fetch[mob.seiTable, tentativeSeiAsKey].val]; IF tentativeResult = NIL THEN -- we have to build it from scratch BEGIN CheckTentativeISei[tentativeSei, sym ! BadTentativeSei, BadTentativeCTX => {GOTO failure}]; tentativeResult _ MakeSEH[mob, tentativeSei]; EXITS failure => NULL; -- thus, leaving result = NIL END; END; ExamineMob[mob, Inner]; IF tentativeResult # NIL THEN RETURN[CheckSEHName[tentativeResult, name]] ELSE RETURN[NIL]; END; GetCodedSeiFromSEH: PUBLIC PROC[seh: SEH] RETURNS[CARD] = BEGIN result: CARD _ 0; Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN <> nominal: CARD _ LOOPHOLE[seh.sei, CARD] - LOOPHOLE[Symbols.SENull, CARD]; result _ SELECT TRUE FROM seh.mob.leftShift # 0 => PBasics.BITRSHIFT[nominal, seh.mob.leftShift], seh.mob.rightShift # 0 => PBasics.BITLSHIFT[nominal, seh.mob.rightShift], ENDCASE => nominal; END; ExamineMob[seh.mob, Inner]; RETURN[result] END; <> CheckSEHName: PROC[seh: SEH, name: Rope.ROPE] RETURNS[SEH] = BEGIN ser: SER _ FetchSER[seh]; body: REF BodySE _ ser.body; IF name = NIL THEN RETURN[seh]; -- client didn't really want to check WITH body SELECT FROM id: REF id BodySE => IF Rope.Equal[name, id.hash] THEN RETURN[seh] ELSE RETURN[NIL]; -- name didn't check ENDCASE => RETURN[NIL]; -- was expecting an id seh END; <> CheckTentativeISei: PROC[tentativeISei: Symbols.SEIndex, sym: SymbolTableBase] = TRUSTED BEGIN [] _ BoundsCheckTentativeSei[tentativeISei, sym]; WITH body: sym.seb[tentativeISei] SELECT FROM id => -- at least its got the right tag BEGIN tentativeCtx: Symbols.CTXIndex _ BoundsCheckTentativeCTX[body.idCtx, sym]; firstSei: Symbols.SEIndex _ BoundsCheckTentativeSei[sym.ctxb[tentativeCtx].seList, sym]; nextSei: Symbols.SEIndex _ firstSei; <> DO sei: Symbols.SEIndex _ BoundsCheckTentativeSei[nextSei, sym]; IF sei = tentativeISei THEN RETURN; <> <<>> WITH body: sym.seb[sei] SELECT FROM id => -- at least its got the right tag BEGIN WITH lnk: body SELECT FROM terminal => BadTentativeSei[tentativeISei]; sequential => {nextSei _ sei + Symbols.SERecord.id.sequential.SIZE; LOOP}; linked => {nextSei _ lnk.link; LOOP}; embedded => BadTentativeSei[tentativeISei]; -- I am not sure if this is what I should do here ENDCASE => BadTentativeSei[tentativeISei]; END ENDCASE => BadTentativeSei[tentativeISei]; ENDLOOP; END; ENDCASE => BadTentativeSei[tentativeISei]; END; <> BoundsCheckTentativeSei: PROC[tentativeSei: Symbols.SEIndex, sym: SymbolTableBase] RETURNS[Symbols.SEIndex] = TRUSTED BEGIN -- this must act like a relative pointer that lands within the se table addr: CARD _ LOOPHOLE[sym.seb, CARD] + LOOPHOLE[tentativeSei, CARD]; <> tableBase: CARD _ LOOPHOLE[sym.stHandle, CARD] + LOOPHOLE[sym.stHandle.seBlock.offset, CARD]; IF addr < tableBase THEN <> BadTentativeSei[tentativeSei]; IF addr >= tableBase+sym.stHandle.seBlock.size THEN <> BadTentativeSei[tentativeSei]; RETURN[tentativeSei]; END; BadTentativeSei: ERROR[tentativeSei: Symbols.SEIndex] = CODE; <> CheckTentativeName: PROC[name: Symbols.Name, sym: SymbolTableBase] = TRUSTED BEGIN addr: CARD _ LOOPHOLE[sym.htb, CARD] + LOOPHOLE[name, CARD]; tableBase: CARD _ LOOPHOLE[sym.stHandle, CARD] + LOOPHOLE[sym.stHandle.htBlock.offset, CARD]; IF addr < tableBase THEN <> BadTentativeName[name]; IF addr >= tableBase+sym.stHandle.htBlock.size THEN <> BadTentativeName[name]; IF (addr-tableBase) MOD SIZE[Symbols.HTRecord] # 0 THEN <> BadTentativeName[name]; END; BadTentativeName: SIGNAL[Symbols.Name] ~ CODE; SEIKeyEqualProc: PROC[key1, key2: RefTab.Key] RETURNS [BOOL] = BEGIN sei1Ref: REF Symbols.SEIndex _ NARROW[key1]; sei2Ref: REF Symbols.SEIndex _ NARROW[key2]; RETURN[sei1Ref^ = sei2Ref^]; END; SEIKeyHashProc: PROC[key: RefTab.Key] RETURNS [CARDINAL] = BEGIN seiRef: REF Symbols.SEIndex _ NARROW[key]; asLongNumber: Basics.LongNumber _ LOOPHOLE[seiRef^]; RETURN[Basics.BITXOR[asLongNumber.lo, asLongNumber.hi]]; END; <<>> <Mimosa>SymbolOpsImpl.UnderType contains a LOOPHOLE under similar circumstances.>> FetchSER: PUBLIC PROC[seh: SEH] RETURNS[SER] = BEGIN Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN IF seh.sei-Symbols.SEFirst<0 OR CARD[seh.sei-Symbols.SEFirst]>=sym.stHandle.seBlock.size THEN ERROR MobError[IO.PutFR["bogus SEI %x into %g", [cardinal[LOOPHOLE[seh.sei]]], [rope[PFS.RopeFromPath[SystemInterface.GetNameOfFile[seh.mob.file]]]] ]]; seh.ser _ NEW[SERBody _ [ body: WITH body: sym.seb[seh.sei] SELECT FROM id => NEW[BodySE _ [id[ extended: body.extended, public: body.public, immutable: body.immutable, constant: body.constant, linkSpace: body.linkSpace, idDecl: body.idDecl, idCtx: MakeCTXH[seh.mob, body.idCtx], idType: MakeSEH[seh.mob, body.idType], idInfoAndValue: NIL, -- filled in below hash: RopeForName[seh.mob, mobHandle, mobBase, sym, body.hash], flags: body.flags, special: body.special, ctxLink: WITH lnk: body SELECT FROM terminal => NIL, sequential => MakeSEH[seh.mob, seh.sei + Symbols.SERecord.id.sequential.SIZE], linked => MakeSEH[seh.mob, lnk.link], embedded => ERROR MobError["MobAccessImpl can't handle embedded ISEIs"], ENDCASE => ERROR MobError["invalid id SERecord linkTag"] ]]], cons => NEW[BodySE _ [cons[ align: body.align, typeInfo: WITH cons: body SELECT FROM mode => NEW[TypeInfoConsSE _ [mode[]]], basic => NEW[TypeInfoConsSE _ [basic[ ordered: cons.ordered, code: cons.code, length: cons.length]]], signed => NEW[TypeInfoConsSE _ [signed[cons.length]]], unsigned => NEW[TypeInfoConsSE _ [unsigned[cons.length]]], real => NEW[TypeInfoConsSE _ [real[cons.length]]], enumerated => NEW[TypeInfoConsSE _ [enumerated[ range: cons.range, valueCtx: MakeCTXH[seh.mob, cons.valueCtx], empty: cons.empty, sparse: cons.sparse, painted: cons.painted, ordered: cons.ordered, machineDep: cons.machineDep]]], record => NEW[TypeInfoConsSE _ [record[ length: cons.length, fieldCtx: MakeCTXH[seh.mob, cons.fieldCtx], bitOrder: MyifyBitOrder[cons.bitOrder], grain: cons.grain, hints: [ comparable: cons.hints.comparable, assignable: cons.hints.assignable, unifield: cons.hints.unifield, variant: cons.hints.variant, privateFields: cons.hints.privateFields, refField: cons.hints.refField, default: cons.hints.default, voidable: cons.hints.voidable], packed: cons.packed, list: cons.list, argument: cons.argument, monitored: cons.monitored, machineDep: cons.machineDep, painted: cons.painted, linkPart: WITH link: cons SELECT FROM notLinked => NIL, linked => MakeSEH[seh.mob, link.linkType], ENDCASE => ERROR MobError["invalid record cons SERecord linkTag"] ]]], ref => NEW[TypeInfoConsSE _ [ref[ refType: MakeSEH[seh.mob, cons.refType], counted: cons.counted, ordered: cons.ordered, readOnly: cons.readOnly, list: cons.list, var: cons.var, basing: cons.basing, length: cons.length ]]], array => NEW[TypeInfoConsSE _ [array[ componentType: MakeSEH[seh.mob, cons.componentType], indexType: MakeSEH[seh.mob, cons.indexType], packed: cons.packed, bitOrder: MyifyBitOrder[cons.bitOrder]]]], arraydesc => NEW[TypeInfoConsSE _ [arraydesc[ describedType: MakeSEH[seh.mob, cons.describedType], var: cons.var, readOnly: cons.readOnly, bitOrder: MyifyBitOrder[cons.bitOrder], length: cons.length]]], transfer => NEW[TypeInfoConsSE _ [transfer[ safe: cons.safe, mode: SELECT cons.mode FROM proc => proc, port => port, signal => signal, error => error, process => process, program => program, none => none, ENDCASE => ERROR MobError["invalid transfer cons SERecord mode"], typeIn: MakeSEH[seh.mob, cons.typeIn], typeOut: MakeSEH[seh.mob, cons.typeOut], length: cons.length]]], definition => NEW[TypeInfoConsSE _ [definition[ defCtx: MakeCTXH[seh.mob, cons.defCtx], slots: cons.slots, named: cons.named]]], union => NEW[TypeInfoConsSE _ [union[ caseCtx: MakeCTXH[seh.mob, cons.caseCtx], tagSei: MakeSEH[seh.mob, cons.tagSei], hints: [ equalLengths: cons.hints.equalLengths, refField: cons.hints.refField, default: cons.hints.default, voidable: cons.hints.voidable], overlaid: cons.overlaid, controlled: cons.controlled, machineDep: cons.machineDep, bitOrder: MyifyBitOrder[cons.bitOrder], grain: cons.grain]]], sequence => NEW[TypeInfoConsSE _ [sequence[ parentType: MakeSEH[seh.mob, cons.parentType], tagSei: MakeSEH[seh.mob, cons.tagSei], componentType: MakeSEH[seh.mob, cons.componentType], packed: cons.packed, controlled: cons.controlled, machineDep: cons.machineDep, bitOrder: MyifyBitOrder[cons.bitOrder], grain: cons.grain]]], relative => NEW[TypeInfoConsSE _ [relative[ baseType: MakeSEH[seh.mob, cons.baseType], offsetType: MakeSEH[seh.mob, cons.offsetType], resultType: MakeSEH[seh.mob, cons.resultType]]]], subrange => NEW[TypeInfoConsSE _ [subrange[ empty: cons.empty, biased: cons.biased, filled: cons.filled, rangeType: MakeSEH[seh.mob, cons.rangeType], origin: cons.origin, range: cons.range]]], opaque => NEW[TypeInfoConsSE _ [opaque[ id: MakeSEH[seh.mob, cons.id], length: cons.length, lengthKnown: cons.lengthKnown]]], zone => NEW[TypeInfoConsSE _ [zone[ counted: cons.counted, mds: cons.mds, length: cons.length]]], any => NEW[TypeInfoConsSE _ [any[]]], nil => NEW[TypeInfoConsSE _ [nil[]]], ENDCASE => ERROR MobError["invalid cons SERecord typeTag"] ]]], ENDCASE => ERROR MobError["invalid SERecord seTag"] ]]; <> <<(We delay because we must compute the idType SEH first, and we can't guarantee the order in which the fields are computed)>> <<(Further, as this is a complicated computation, it must be done offline, either in a procedure, or a separate statement.)>> WITH bodySource: sym.seb[seh.sei] SELECT FROM id => WITH bodyTarget: seh.ser.body SELECT FROM id => BEGIN <> <> IF bodySource.idType = Symbols.typeTYPE THEN BEGIN idInfoSEI: Symbols.SEIndex _ LOOPHOLE[bodySource.idInfo]; idInfoSEH: SEH _ MakeSEH[seh.mob, idInfoSEI]; bodyTarget.idInfoAndValue _ NEW[MobAccess.TypeDesc _ [idInfoSEH, LOOPHOLE[bodySource.idValue]]]; GOTO installed; END; <> <MobMapperImpl.AlterSERecord2>> <<>> BEGIN entrySEI: Symbols.SEIndex _ UnderType[bodySource.idType, sym]; isBTI: BOOLEAN _ FALSE; WITH entryTypeBody: sym.seb[entrySEI] SELECT FROM cons => SELECT TRUE FROM bodySource.constant AND NOT bodySource.extended => WITH etb: entryTypeBody SELECT FROM transfer => SELECT etb.mode FROM proc, signal, error, program => isBTI _ TRUE; ENDCASE => NULL; ENDCASE => NULL; bodySource.constant AND bodySource.extended => WITH etb: entryTypeBody SELECT FROM transfer => SELECT etb.mode FROM proc => isBTI _ TRUE; ENDCASE => NULL; ENDCASE => NULL ENDCASE => NULL; ENDCASE => ERROR MobError["Can't happen: UnderType returned a non-cons sei"]; IF isBTI THEN BEGIN bodyTarget.idInfoAndValue _ NEW [MobAccess.BlockDesc _ [MakeBTH[seh.mob, LOOPHOLE[bodySource.idInfo]], LOOPHOLE[bodySource.idValue]]]; GOTO installed; END; END; <> <<>> IF bodySource.constant THEN -- we are dealing with a constant <> BEGIN bodyTarget.idInfoAndValue _ NEW[MobAccess.ConstVal _ [LOOPHOLE[bodySource.idValue]]]; GOTO installed; END; <<>> <<>> <> BEGIN bitSize: CARD _ LOOPHOLE[bodySource.idInfo, CARD]; -- size of field (in bits) bitOffset: INT _ LOOPHOLE[bodySource.idValue, INT]; -- offset of field from the appropriate base (in bits) bodyTarget.idInfoAndValue _ NEW[MobAccess.FieldDesc _ [bitSize, bitOffset]]; GOTO installed; END; <MobMapperImpl.AlterSERecord2, although that code is really trying to decide whether to do some alterations or not, and stops its analysis as soon as it knows.>> <<>> EXITS installed => NULL; END; ENDCASE => ERROR MobError["can't happen: we just made it the other way"]; ENDCASE => NULL; END; IF seh = NIL THEN RETURN[NIL]; IF seh.ser = NIL THEN ExamineMob[seh.mob, Inner]; RETURN[seh.ser] END; MyifyBitOrder: ARRAY Symbols.BitOrder OF MobAccess.BitOrder = [msBit: msBit, lsBit: lsBit]; GetMobForSEH: PUBLIC PROC[seh: SEH] RETURNS[MobCookie] = {RETURN[seh.mob]}; GetSeiForSEH: PUBLIC PROC[seh: SEH] RETURNS[sei: Symbols.SEIndex] = {RETURN[seh.sei]}; UnderType: PROC[sei: Symbols.SEIndex, sym: SymbolTableBase] RETURNS [Symbols.SEIndex] = TRUSTED BEGIN DO WITH se: sym.seb[sei] SELECT FROM id => IF se.idType = Symbols.typeTYPE THEN {sei _ LOOPHOLE[se.idInfo]; LOOP}; cons => RETURN [sei]; ENDCASE; ERROR MobError["BadMobContents"]; ENDLOOP; END; SEHToRope: PROC[seh: SEH, depth: INT] RETURNS[Rope.ROPE] = BEGIN ser: SER _ FetchSER[seh]; st: IO.STREAM _ IO.ROS[]; putDepth: PROC[d: INT_0] = {FOR I: INT IN [0..depth+d) DO IO.PutF[st, " "] ENDLOOP}; rope: PROC[r: Rope.ROPE, d: INT _ 0] = {putDepth[d]; IO.PutRope[st, r]}; put: PROC[d: INT, f: Rope.ROPE, v1, v2, v3, v4, v5: IO.Value _ [null[]]] = BEGIN putDepth[d]; IO.PutF[st, f, v1, v2, v3, v4, v5]; END; put[0, "sei = %g\N", IO.rope[Convert.RopeFromCard[LOOPHOLE[seh.sei]]]]; WITH ser.body SELECT FROM id: REF id BodySE => BEGIN put[0, "id = %g\N", [rope[id.hash]]]; put[0, "ctx = %g\N", [rope[IF id.idCtx = NIL THEN "NIL" ELSE Convert.RopeFromCard[LOOPHOLE[id.idCtx.ctx]]]]]; SELECT id.special FROM normal => rope[" normal\N"]; globalLink => rope[" globalLink\N"]; staticLink => rope[" staticLink\N"]; frameExtension => rope[" frameExtension\N"]; memoryLink => rope[" memoryLink\N"]; returnLink => rope[" returnLink\N"]; ENDCASE => rope[" unknown special\N"]; IF id.flags.valid THEN BEGIN IF id.flags.used THEN rope[" used"] ELSE rope[" not-used"]; IF id.flags.addressed THEN rope[" addressed"] ELSE rope[" not-addressed"]; IF id.flags.assigned THEN rope[" assigned"] ELSE rope[" not-assigned"]; IF id.flags.upLevel THEN rope[" upLevel\N"] ELSE rope[" not-upLevel\N"]; END; END; cons: REF cons BodySE => rope["cons\N"]; ENDCASE => rope["unknown ser\N"]; RETURN[IO.RopeFromROS[st]]; END; <> <> RopeHolder: TYPE = REF RopeHolderBody; RopeHolderBody: TYPE = RECORD[rope: Rope.ROPE]; <> <> RopeForName: PROC[cookie: MobCookie, mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase, name: Symbols.Name] RETURNS[Rope.ROPE] = BEGIN IF name = Symbols.nullName THEN RETURN[NIL] ELSE TRUSTED BEGIN ropeHolder: RopeHolder _ NARROW[CardTab.Fetch[cookie.stringTable, sym.htb[name].ssIndex].val]; IF ropeHolder # NIL THEN RETURN[ropeHolder.rope] ELSE BEGIN offset: CARDINAL _ sym.htb[name-Symbols.HTRecord.SIZE].ssIndex+1; ss: ConvertUnsafe.SubString _ [ base: sym.ssb, offset: offset, length: sym.htb[name].ssIndex - offset]; rope: Rope.ROPE; IF ss.offset > ss.base.length OR ss.length > CARD[ss.base.length-ss.offset] THEN ERROR MobError["bogus name"]; rope _ ConvertUnsafe.SubStringToRope[ss]; -- The current DMachine Cedar version of this routine allocates new storage for the rope. I.E., we do not end up pointing back into the symbol table. This is good, because if we ended up pointing back into the symbol table, we would be in deep trouble if the symbol table left the symbol table cache. ropeHolder _ NEW[RopeHolderBody_[rope]]; IF NOT CardTab.Insert[cookie.stringTable, sym.htb[name].ssIndex, ropeHolder] THEN ERROR MobError["MobAccessImpl confused (by concurrent access?)"]; RETURN[rope]; END; END; END; <> ViewMob: Commander.CommandProc = BEGIN args: CommandTool.ArgumentVector _ CommandTool.Parse[cmd]; path: PFSNames.PATH _ PFS.PathFromRope[args[1]]; fileSet: SystemInterface.FileSet _ SystemInterface.CreateFileSet[]; BEGIN ENABLE UNWIND => SystemInterface.CloseFileSet[fileSet]; file: SystemInterface.CirioFile _ SystemInterface.GetCirioFile[fileSet, path]; mob: MobCookie _ CreateMobCookie[file]; inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = BEGIN ERROR; -- so that we can look around with the debugger END; ExamineMob[mob, inner]; END; SystemInterface.CloseFileSet[fileSet]; END; <
> Commander.Register["ViewMob", ViewMob]; <> <<>> <> END..