DIRECTORY BasicLoadState USING [ ConfigID, ConfigInfo, Destroy, EnumerateConfigs, EnumerateModulesInConfig, GlobalFrameToType, ModuleIndex, ModuleToGlobalFrame], BasicLoadStateFormat USING [ConfigIndex, LoadState, LoadStateObject, nullModule, versionID], BcdDefs USING [Base, MTHandle, MTIndex, MTNull], BcdOps USING [ProcessModules], DebuggerSwap USING [NoteLoadstate], LoadState USING [ Access, BcdBase, CopiesList, EnumerationOrder, GlobalFrameHandle, ModuleIndex, nullModule, nullType, Type], LoadStateFormat USING [ CollisionList, CollisionTable, CollisionTableIndex, Config, ConfigObject, ConfigID, ConfigTable, CopyIndex, CopyTable, Entry, fuzzyCopyIndex, Handle, HashIndex, htSize, nullCopyIndex, Object], PrincOps USING [ ControlLink, CSegPrefix, EmptyGFTItem, EPBias, EPIndex, FrameHandle, GFT, GFTIndex, MainBodyIndex, NullGlobalFrame, sCopy, SD, sGFTLength], PrincOpsUtils USING [ Alloc, BITAND, BITSHIFT, CodeBase, COPY, Free, GetReturnFrame, GlobalFrame, MakeFsi, SetReturnLink, ZERO], SafeStorageOps USING [CopyTypesAndLiterals], VM USING [Allocate, Interval, PageNumberToAddress, PagesToWords, WordsToPages]; LoadStateImpl: MONITOR IMPORTS BasicLoadState, BcdOps, DebuggerSwap, PrincOpsUtils, SafeStorageOps, VM EXPORTS LoadState = BEGIN OPEN LoadState, LoadStateFormat; Handle: TYPE = LoadStateFormat.Handle; Object: PUBLIC TYPE = LoadStateFormat.Object; ConfigID: PUBLIC TYPE = LoadStateFormat.ConfigID; nullConfig: PUBLIC ConfigID _ LoadStateFormat.ConfigID.LAST; local: PUBLIC Handle; UndoLog: TYPE = LIST OF UndoLogEntry; UndoLogEntry: TYPE = RECORD [loadState: Handle, configID: ConfigID]; released: CONDITION _ [timeout: 0]; undoLog: UndoLog _ NIL; Acquire: PUBLIC ENTRY SAFE PROC [loadState: Handle, access: Access] = TRUSTED { DO SELECT TRUE FROM access = shared AND loadState.useCount >= 0 => { loadState.useCount _ loadState.useCount.SUCC; EXIT}; access = exclusive AND loadState.useCount = 0 => { loadState.useCount _ -1; EXIT}; ENDCASE; WAIT released; ENDLOOP; }; Release: PUBLIC SAFE PROC [loadState: Handle, commit: BOOL] = TRUSTED { LogProcessingNeeded: ENTRY PROC RETURNS [doLog: BOOL] = { SELECT loadState.useCount FROM < 0 => RETURN [TRUE]; > 0 => { loadState.useCount _ loadState.useCount.PRED; BROADCAST released; RETURN [FALSE] }; ENDCASE => RETURN WITH ERROR CallerBug; }; LogProcessingDone: ENTRY PROC = { loadState.useCount _ 0; BROADCAST released; }; IF LogProcessingNeeded[] THEN { IF commit THEN { loadState.changeCount _ loadState.changeCount.SUCC; DiscardUndoLog[loadState]; } ELSE Undo[loadState]; LogProcessingDone[]; }; }; ConfigInfo: PUBLIC SAFE PROC [loadState: Handle, config: ConfigID] RETURNS [bcd: BcdBase] = TRUSTED { CheckAccess[loadState]; RETURN[loadState.configTable.configs[config].bcd] }; ModuleInfo: PUBLIC SAFE PROC [loadState: Handle, config: ConfigID, module: ModuleIndex] RETURNS [ gfh: GlobalFrameHandle, mti: BcdDefs.MTIndex, type: Type, copies: CopiesList ] = TRUSTED { c: Config; CheckAccess[loadState]; c _ loadState.configTable.configs[config]; IF module >= c.nModules THEN ERROR CallerBug; IF (mti _ c.modules[module].mti) = BcdDefs.MTNull THEN ERROR CallerBug; type _ c.modules[module].type; IF (gfh _ c.modules[module].gfh) = NIL THEN copies _ NIL ELSE { ci: CopyIndex = FindCopyIndex[loadState, gfh]; copies _ IF ci = nullCopyIndex THEN NIL ELSE loadState.copyTable.copies[ci].copies; }; }; BuildProcDescUsingModule: PUBLIC SAFE PROC [loadState: Handle, config: ConfigID, module: ModuleIndex, ep: PrincOps.EPIndex] RETURNS [PrincOps.ControlLink] = TRUSTED { gfh: GlobalFrameHandle; c: Config; firstModule: ModuleIndex _ module; CheckAccess[loadState]; c _ loadState.configTable.configs[config]; IF module >= c.nModules THEN ERROR CallerBug; IF (gfh _ c.modules[module].gfh) = NIL THEN ERROR CallerBug; FOR i: ModuleIndex DECREASING IN [0..module) UNTIL c.modules[i].gfh ~= gfh DO firstModule _ i; ENDLOOP; RETURN[ [procedure[ gfi: (IF loadState = local THEN gfh.gfi ELSE 0) + module - firstModule, ep: ep, tag: TRUE]] ] }; GlobalFrameToModule: PUBLIC SAFE PROC [loadState: Handle, gfh: GlobalFrameHandle] RETURNS [config: ConfigID, module: ModuleIndex] = TRUSTED { entry: Entry; CheckAccess[loadState]; ValidateGlobalFrame[loadState, gfh]; entry _ FindEntry[loadState, gfh]; WITH e: entry SELECT FROM original => RETURN[e.configID, e.module]; copy => [config, module] _ GlobalFrameToModule[loadState, loadState.copyTable.copies[e.copyIndex].parent]; ENDCASE => ERROR; }; LoadStateFull: PUBLIC SAFE ERROR = CODE; NewConfig: PUBLIC SAFE PROC [loadState: Handle, bcd: BcdBase] RETURNS [configID: ConfigID] = TRUSTED { NewConfigObject: PROC [bcd: BcdBase] RETURNS [c: Config] = { nModules: NAT _ 0; ComputeSize: PROC [mth: BcdDefs.MTHandle, mti: BcdDefs.MTIndex] RETURNS [BOOL _ FALSE] = { nModules _ MAX[nModules, mth.gfi+mth.ngfi]; }; FillInModules: PROC [mth: BcdDefs.MTHandle, mti: BcdDefs.MTIndex] RETURNS [BOOL _ FALSE] = { FOR i: NAT IN [0..mth.ngfi) DO c.modules[mth.gfi+i].mti _ mti; ENDLOOP; }; [] _ BcdOps.ProcessModules[bcd, ComputeSize]; c _ NEW[ConfigObject[nModules]]; c.bcd _ bcd; c.nModules _ nModules; FOR mi: ModuleIndex IN [0..nModules) DO c.modules[mi] _ [mti: BcdDefs.MTNull, gfh: NIL, type: nullType]; ENDLOOP; [] _ BcdOps.ProcessModules[bcd, FillInModules]; }; ct: REF ConfigTable; CheckAccess[loadState, exclusive]; CheckLocal[loadState]; ct _ loadState.configTable; IF ct.nConfigs = ct.length THEN IF ct.length = ConfigID.LAST THEN ERROR LoadStateFull ELSE { newCT: REF ConfigTable = NEW[ConfigTable[MIN[3*ct.length/2, ConfigID.LAST]]]; newCT.nConfigs _ ct.nConfigs; FOR ci: ConfigID IN [0..newCT.nConfigs) DO newCT.configs[ci] _ ct.configs[ci]; ENDLOOP; loadState.configTable _ ct _ newCT; }; ct.configs[configID _ ct.nConfigs] _ NewConfigObject[bcd]; ct.nConfigs _ ct.nConfigs.SUCC; AppendToUndoLog[loadState, configID]; }; SetGlobalFrame: PUBLIC SAFE PROC [ loadState: Handle, config: ConfigID, module: ModuleIndex, gfh: GlobalFrameHandle] = TRUSTED { c: Config; mth: BcdDefs.MTHandle; CheckAccess[loadState, exclusive]; CheckLocal[loadState]; c _ loadState.configTable.configs[config]; IF c.modules[module].gfh ~= NIL OR c.modules[module].mti = BcdDefs.MTNull THEN ERROR CallerBug; mth _ @LOOPHOLE[c.bcd + c.bcd.mtOffset, BcdDefs.Base][c.modules[module].mti]; EnterGlobalFrame[gfh, mth.ngfi]; FOR i: NAT IN [0..mth.ngfi) DO c.modules[module+i].gfh _ gfh; ENDLOOP; AddEntry[ loadState, gfh, [original[copyIndex: nullCopyIndex, configID: config, module: module]]]; }; SetType: PUBLIC SAFE PROC [ loadState: Handle, gfh: GlobalFrameHandle, type: Type] = TRUSTED { entry: Entry; CheckAccess[loadState, exclusive]; CheckLocal[loadState]; ValidateGlobalFrame[loadState, gfh]; entry _ FindEntry[loadState, gfh]; WITH e: entry SELECT FROM original => loadState.configTable.configs[e.configID].modules[e.module].type _ type; copy => NULL; -- could verify that it matches the type of the original... ENDCASE => ERROR; }; CopyNew: PUBLIC SAFE PROC [loadState: Handle, old: PROGRAM] RETURNS [new: PROGRAM] = TRUSTED { frame: GlobalFrameHandle = LOOPHOLE[old]; CheckLocal[loadState]; RETURN[LOOPHOLE[LocalCopyNew[frame]]] }; UnNew: PUBLIC UNSAFE PROC [loadState: Handle, program: PROGRAM] = { frame: GlobalFrameHandle = LOOPHOLE[program]; CheckLocal[loadState]; ValidateGlobalFrame[loadState, frame]; LocalUnNew[frame]; }; SelfDestruct: PUBLIC UNSAFE PROC = { destructee: PrincOps.FrameHandle = PrincOpsUtils.GetReturnFrame[]; PrincOpsUtils.SetReturnLink[destructee.returnlink]; LocalUnNew[LOOPHOLE[PrincOpsUtils.GlobalFrame[destructee]]]; PrincOpsUtils.Free[destructee]; }; EnumerateConfigs: PUBLIC SAFE PROC [ loadState: Handle, order: EnumerationOrder, proc: PROC [ConfigID] RETURNS [--stop:--BOOL]] RETURNS [config: ConfigID] = TRUSTED { CheckAccess[loadState]; SELECT order FROM newestFirst => FOR config DECREASING IN [0..loadState.configTable.nConfigs) DO IF proc[config] THEN EXIT; REPEAT FINISHED => RETURN [nullConfig]; ENDLOOP; oldestFirst => FOR config IN [0..loadState.configTable.nConfigs) DO IF proc[config] THEN EXIT; REPEAT FINISHED => RETURN [nullConfig]; ENDLOOP; ENDCASE; }; EnumerateModulesInConfig: PUBLIC SAFE PROC [ loadState: Handle, config: ConfigID, proc: PROC [ModuleIndex] RETURNS [--stop:--BOOL]] RETURNS [module: ModuleIndex, gfh: GlobalFrameHandle] = TRUSTED { c: Config; prev: GlobalFrameHandle _ NIL; CheckAccess[loadState]; c _ loadState.configTable.configs[config]; FOR module IN [1..c.nModules) DO -- index 0 is always unused gfh _ c.modules[module].gfh; IF gfh ~= NIL AND gfh ~= prev THEN { IF proc[module] THEN RETURN; prev _ gfh; }; ENDLOOP; RETURN [nullModule, NIL] }; EnumerateAllModules: PUBLIC SAFE PROC [ loadState: Handle, order: EnumerationOrder, proc: PROC [ConfigID, ModuleIndex] RETURNS [--stop:--BOOL]] RETURNS [config: ConfigID _ nullConfig, module: ModuleIndex _ nullModule] = TRUSTED { DoOneConfig: PROC [c: ConfigID] RETURNS [BOOL] = { PassItOn: PROC [m: ModuleIndex] RETURNS [stop: BOOL] = { IF (stop _ proc[c, m]) THEN {config _ c; module _ m}; }; RETURN[EnumerateModulesInConfig[loadState, config, PassItOn].module ~= nullModule] }; CheckAccess[loadState]; [] _ EnumerateConfigs[loadState, order, DoOneConfig]; }; CallerBug: ERROR = CODE; CheckAccess: ENTRY PROC [loadState: Handle, access: Access _ shared] = { IF loadState.useCount = 0 OR (loadState.useCount > 0 AND access = exclusive) THEN RETURN WITH ERROR CallerBug; }; CheckLocal: PROC [loadState: Handle] = { IF loadState ~= local THEN ERROR CallerBug; }; ValidateGlobalFrame: PROC [loadState: Handle, frame: GlobalFrameHandle] = { WITH FindEntry[loadState, frame] SELECT FROM empty => ERROR CallerBug; ENDCASE => RETURN; }; FindEntry: PROC [loadState: Handle, gfh: GlobalFrameHandle] RETURNS [entry: Entry] = { Match: PROC [entry: Entry] RETURNS [BOOL _ FALSE] = { WITH e: entry SELECT FROM original => IF loadState.configTable.configs[e.configID].modules[e.module].gfh = gfh THEN RETURN[TRUE]; copy => IF e.gfh = gfh THEN RETURN[TRUE]; ENDCASE; }; IF Match[entry _ loadState.gfht[Hash[gfh]]] THEN RETURN; WITH e: entry SELECT FROM collision => FOR list: CollisionList _ loadState.collisionTable.collisions[e.list], list.rest UNTIL list = NIL DO IF Match[list.first] THEN RETURN[list.first]; ENDLOOP; ENDCASE; RETURN[[empty[]]] }; FindCopyIndex: PROC [loadState: Handle, gfh: GlobalFrameHandle] RETURNS [CopyIndex] = { entry: Entry = FindEntry[loadState, gfh]; WITH e: entry SELECT FROM original => { SELECT e.copyIndex FROM nullCopyIndex => RETURN[nullCopyIndex]; fuzzyCopyIndex => FOR ci: CopyIndex IN [fuzzyCopyIndex..loadState.copyTable.nCopies) DO IF loadState.copyTable.copies[ci].parent = gfh THEN RETURN [ci]; REPEAT FINISHED => ERROR; ENDLOOP; ENDCASE => RETURN[e.copyIndex] }; copy => RETURN[e.copyIndex] ENDCASE => ERROR; }; SetCopyIndex: PROC [loadState: Handle, gfh: GlobalFrameHandle, copyIndex: CopyIndex] = { entry: LONG POINTER TO Entry = @loadState.gfht[Hash[gfh]]; copyIndex _ MIN[copyIndex, fuzzyCopyIndex]; WITH e: entry SELECT FROM original => e.copyIndex _ copyIndex; collision => FOR list: CollisionList _ loadState.collisionTable.collisions[e.list], list.rest UNTIL list = NIL DO WITH f: list.first SELECT FROM original => IF loadState.configTable.configs[f.configID].modules[f.module].gfh = gfh THEN f.copyIndex _ copyIndex; copy => NULL; ENDCASE => ERROR; REPEAT FINISHED => ERROR; ENDLOOP; ENDCASE => ERROR; }; AddEntry: PROC [loadState: Handle, gfh: GlobalFrameHandle, entry: Entry] = { hi: HashIndex = Hash[gfh]; oldEntry: Entry = loadState.gfht[hi]; WITH e: oldEntry SELECT FROM empty => loadState.gfht[hi] _ entry; collision => loadState.collisionTable.collisions[e.list] _ CONS[entry, loadState.collisionTable.collisions[e.list]]; ENDCASE => { ct: REF CollisionTable _ loadState.collisionTable; ci: CollisionTableIndex; FOR ci IN [0..ct.nCollisions) DO IF ct.collisions[ci] = NIL THEN EXIT; REPEAT FINISHED => { IF ct.nCollisions = ct.length THEN { newCT: REF CollisionTable = NEW[CollisionTable[3*ct.length/2]]; newCT.nCollisions _ ct.nCollisions; FOR ci: CollisionTableIndex IN [0..newCT.nCollisions) DO newCT.collisions[ci] _ ct.collisions[ci]; ENDLOOP; loadState.collisionTable _ ct _ newCT; }; ci _ ct.nCollisions; ct.nCollisions _ ct.nCollisions.SUCC; }; ENDLOOP; ct.collisions[ci] _ CONS[entry, CONS[loadState.gfht[hi], NIL]]; loadState.gfht[hi] _ [collision[list: ci]]; }; }; RemoveEntry: PROC [loadState: Handle, gfh: GlobalFrameHandle] = { hi: HashIndex = Hash[gfh]; oldEntry: Entry = loadState.gfht[hi]; WITH e: oldEntry SELECT FROM original => loadState.gfht[hi] _ [empty[]]; copy => loadState.gfht[hi] _ [empty[]]; collision => { list: CollisionList _ loadState.collisionTable.collisions[e.list]; prev: CollisionList _ NIL; UNTIL list = NIL DO WITH f: list.first SELECT FROM original => IF loadState.configTable.configs[f.configID].modules[f.module].gfh = gfh THEN GO TO found; copy => IF f.gfh = gfh THEN GO TO found; ENDCASE => ERROR; prev _ list; list _ list.rest; REPEAT found => IF prev = NIL THEN loadState.collisionTable.collisions[e.list] _ list.rest ELSE prev.rest _ list.rest; FINISHED => ERROR; ENDLOOP; IF loadState.collisionTable.collisions[e.list].rest = NIL THEN { -- collisions gone loadState.gfht[hi] _ loadState.collisionTable.collisions[e.list].first; loadState.collisionTable.collisions[e.list] _ NIL; }; }; ENDCASE => ERROR; }; Hash: PROC [gfh: GlobalFrameHandle] RETURNS [HashIndex] = INLINE { RETURN [PrincOpsUtils.BITSHIFT[gfh, -2] MOD htSize] }; Undo: PROC [loadState: Handle] = { prev: UndoLog _ NIL; FOR list: UndoLog _ undoLog, list.rest UNTIL list = NIL DO IF list.first.loadState = loadState THEN { configID: ConfigID = list.first.configID; RemoveModule: PROC [module: ModuleIndex] RETURNS [BOOL _ FALSE] = { gfh: GlobalFrameHandle = ModuleInfo[loadState, configID, module].gfh; RemoveGlobalFrame[gfh]; RemoveEntry[loadState, gfh]; }; IF loadState ~= local OR configID ~= loadState.configTable.nConfigs.PRED THEN ERROR; [] _ EnumerateModulesInConfig[loadState, configID, RemoveModule]; loadState.configTable.configs[configID] _ NIL; -- make collector happy loadState.configTable.nConfigs _ configID; IF prev = NIL THEN undoLog _ list.rest ELSE prev.rest _ list.rest; } ELSE prev _ list; ENDLOOP; }; AppendToUndoLog: PROC [loadState: Handle, config: ConfigID] = { undoLog _ CONS[UndoLogEntry[loadState, config], undoLog]; }; DiscardUndoLog: PROC [loadState: Handle] = { ConfigList: TYPE = LIST OF ConfigID; prev: UndoLog _ NIL; debuggerLSList: ConfigList _ NIL; FOR list: UndoLog _ undoLog, list.rest UNTIL list = NIL DO IF list.first.loadState = loadState THEN { IF loadState ~= local THEN ERROR; debuggerLSList _ CONS[list.first.configID, debuggerLSList]; IF prev = NIL THEN undoLog _ list.rest ELSE prev.rest _ list.rest; } ELSE prev _ list; ENDLOOP; FOR list: ConfigList _ debuggerLSList, list.rest UNTIL list = NIL DO UpdateDebuggerLoadState[list.first]; ENDLOOP; }; LocalCopyNew: PROC [old: GlobalFrameHandle] RETURNS [new: GlobalFrameHandle] = { FindOriginal: PROC [old: GlobalFrameHandle] RETURNS [GlobalFrameHandle] = --INLINE-- { entry: Entry = FindEntry[local, old]; WITH e: entry SELECT FROM original => RETURN[old]; copy => RETURN[local.copyTable.copies[e.copyIndex].parent]; ENDCASE => ERROR; }; AllocGlobalFrame: PROC [ old: GlobalFrameHandle, cp: LONG POINTER TO PrincOps.CSegPrefix] RETURNS [frame: GlobalFrameHandle, linkspace: CARDINAL] = --INLINE-- { pGFSize: LONG POINTER TO CARDINAL = LOOPHOLE[cp + CARDINAL[cp.entry[PrincOps.MainBodyIndex].initialpc] - 1]; nLinks: CARDINAL = cp.header.info.nlinks; nWords: CARDINAL; linkspace _ IF old.codelinks THEN 0 ELSE nLinks + PrincOpsUtils.BITAND[-LOOPHOLE[nLinks, INTEGER], 3B]; nWords _ pGFSize^ + linkspace; frame _ PrincOpsUtils.Alloc[PrincOpsUtils.MakeFsi[nWords]]; [] _ PrincOpsUtils.ZERO[LONG[frame], nWords]; }; AddCopy: PROC [original: GlobalFrameHandle, copy: GlobalFrameHandle] = --INLINE-- { ct: REF CopyTable _ local.copyTable; ci: CopyIndex _ FindCopyIndex[local, original]; IF ci = nullCopyIndex THEN { FOR ci IN [1..ct.nCopies) DO -- slot 0 is never used ( = nullCopyIndex) IF ct.copies[ci].copies = NIL THEN EXIT; -- reuse an available slot REPEAT FINISHED => { IF ct.nCopies = ct.length THEN { newCT: REF CopyTable = NEW[CopyTable[3*ct.length/2]]; newCT.nCopies _ ct.nCopies; FOR ci: CopyIndex IN [0..newCT.nCopies) DO newCT.copies[ci] _ ct.copies[ci]; ENDLOOP; local.copyTable _ ct _ newCT; }; ci _ ct.nCopies; ct.nCopies _ ct.nCopies.SUCC; }; ENDLOOP; ct.copies[ci] _ [parent: original, copies: NIL]; SetCopyIndex[local, original, ci]; }; ct.copies[ci].copies _ CONS[copy, ct.copies[ci].copies]; AddEntry[local, copy, [copy[copyIndex: ci, gfh: copy]]]; }; linkspace: CARDINAL; codebase: LONG POINTER TO PrincOps.CSegPrefix; entry: Entry; ValidateGlobalFrame[local, old]; Acquire[local, exclusive]; old _ FindOriginal[old]; [new, linkspace] _ AllocGlobalFrame[old, codebase _ PrincOpsUtils.CodeBase[old]]; new _ new + linkspace; new^ _ [ gfi: , alloced: TRUE, shared: TRUE, copied: TRUE, started: FALSE, trapxfers: FALSE, codelinks: old.codelinks, code: old.code, global:]; new.code.out _ TRUE; -- cause start trap new.global[0] _ PrincOps.NullGlobalFrame; IF linkspace ~= 0 THEN PrincOpsUtils.COPY[from: old - linkspace, to: new - linkspace, nwords: linkspace]; EnterGlobalFrame[new, codebase.header.info.ngfi ! LoadStateFull => { PrincOpsUtils.Free[new - linkspace]; Release[loadState: local, commit: FALSE]; } ]; old.shared _ TRUE; entry _ FindEntry[local, old]; WITH e: entry SELECT FROM original => SafeStorageOps.CopyTypesAndLiterals[ bcd: local.configTable[e.configID].bcd, mi: e.module, old: old, new: new]; ENDCASE => ERROR; AddCopy[original: old, copy: new]; Release[loadState: local, commit: TRUE]; }; LocalUnNew: UNSAFE PROC [frame: GlobalFrameHandle] = { RemoveCopy: PROC [copy: GlobalFrameHandle] = --INLINE-- { prev: CopiesList _ NIL; ct: REF CopyTable = local.copyTable; ci: CopyIndex = FindCopyIndex[local, copy]; IF ci = nullCopyIndex THEN ERROR; FOR list: CopiesList _ ct.copies[ci].copies, list.rest UNTIL list = NIL DO IF list.first = copy THEN { IF prev = NIL THEN ct.copies[ci].copies _ list.rest ELSE prev.rest _ list.rest; EXIT }; prev _ list; REPEAT FINISHED => ERROR; ENDLOOP; IF ct.copies[ci].copies = NIL THEN -- last copy of parent has been UnNewed SetCopyIndex[local, ct.copies[ci].parent, nullCopyIndex]; RemoveEntry[local, copy]; }; entry: Entry; Acquire[local, exclusive]; entry _ FindEntry[local, frame]; WITH e: entry SELECT FROM original => {Release[loadState: local, commit: FALSE]; ERROR CallerBug}; copy => { codebase: LONG POINTER TO PrincOps.CSegPrefix = PrincOpsUtils.CodeBase[frame]; Align: PROC [POINTER, WORD] RETURNS [POINTER] = LOOPHOLE[PrincOpsUtils.BITAND]; IF ~frame.alloced THEN ERROR; RemoveGlobalFrame[frame]; RemoveCopy[frame]; PrincOpsUtils.Free[Align[frame - codebase.header.info.nlinks, 177774B]] }; ENDCASE => ERROR; Release[loadState: local, commit: TRUE]; }; gftRover: CARDINAL _ 1; -- for creation of new GFT entries. (Note that 0 is reserved.) EnterGlobalFrame: PROC [frame: GlobalFrameHandle, nSlots: PrincOps.EPBias] = { k: PrincOps.GFTIndex _ gftRover; kMax: PrincOps.GFTIndex = PrincOps.SD[PrincOps.sGFTLength] - nSlots; n: NAT _ 0; DO IF (k _ IF k >= kMax THEN 1 ELSE k + 1) = gftRover THEN ERROR LoadStateFull; IF PrincOps.GFT[k] ~= PrincOps.EmptyGFTItem THEN n _ 0 ELSE IF (n _ n + 1) = nSlots THEN EXIT; ENDLOOP; frame.gfi _ (gftRover _ k) - nSlots + 1; FOR epOffset: PrincOps.EPBias IN [0..nSlots) DO PrincOps.GFT[frame.gfi + epOffset].framePtr _ frame; PrincOps.GFT[frame.gfi + epOffset].epbias _ epOffset; ENDLOOP; }; RemoveGlobalFrame: PROC [frame: GlobalFrameHandle] = { codebase: LONG POINTER TO PrincOps.CSegPrefix = PrincOpsUtils.CodeBase[frame]; FOR k: NAT IN [0..codebase.header.info.ngfi) DO PrincOps.GFT[frame.gfi+k] _ PrincOps.EmptyGFTItem; ENDLOOP; }; debuggerLoadState: BasicLoadStateFormat.LoadState; InitializeLoadState: PROC = { debuggerLSInterval: VM.Interval; InitializeDebuggerLoadstate: PROC = { maxConfigs: NAT = BasicLoadStateFormat.ConfigIndex.LAST; debuggerLSInterval _ VM.Allocate[ count: VM.WordsToPages[SIZE[BasicLoadStateFormat.LoadStateObject[maxConfigs]]]]; debuggerLoadState _ VM.PageNumberToAddress[debuggerLSInterval.page]; [] _ PrincOpsUtils.ZERO[debuggerLoadState, VM.PagesToWords[debuggerLSInterval.count]]; debuggerLoadState.versionident _ BasicLoadStateFormat.versionID; FOR gfi: PrincOps.GFTIndex IN PrincOps.GFTIndex DO debuggerLoadState.gft[gfi] _ BasicLoadStateFormat.nullModule; ENDLOOP; LOOPHOLE[@debuggerLoadState.bcds, LONG POINTER TO CARDINAL]^ _ maxConfigs; }; nConfigs: ConfigID _ 0; CountConfigs: PROC [bc: BasicLoadState.ConfigID] RETURNS [BOOL _ FALSE] = { nConfigs _ nConfigs.SUCC; }; DoOneConfig: PROC [bc: BasicLoadState.ConfigID] RETURNS [BOOL _ FALSE] = { configID: ConfigID = NewConfig[local, BasicLoadState.ConfigInfo[bc].bcd]; c: Config = local.configTable.configs[configID]; mtb: BcdDefs.Base = LOOPHOLE[c.bcd + c.bcd.mtOffset]; DoOneModule: PROC [bm: BasicLoadState.ModuleIndex] RETURNS [BOOL _ FALSE] = { gfh: GlobalFrameHandle = BasicLoadState.ModuleToGlobalFrame[bc, bm]; IF c.modules[bm].gfh ~= NIL OR c.modules[bm].mti = BcdDefs.MTNull THEN ERROR; FOR i: NAT IN [0..mtb[c.modules[bm].mti].ngfi) DO c.modules[bm+i].gfh _ gfh; ENDLOOP; AddEntry[ local, gfh, [original[copyIndex: nullCopyIndex, configID: configID, module: bm]]]; SetType[local, gfh, LOOPHOLE[BasicLoadState.GlobalFrameToType[gfh]]]; }; [] _ BasicLoadState.EnumerateModulesInConfig[bc, DoOneModule]; }; InitializeDebuggerLoadstate[]; [] _ BasicLoadState.EnumerateConfigs[CountConfigs]; local _ NEW[Object _ [ useCount: 0, configTable: NEW[ConfigTable[MIN[MAX[3*nConfigs/2, 2], ConfigID.LAST]]], copyTable: NEW[CopyTable[5]], collisionTable: NEW[CollisionTable[10]], gfht: ALL[[empty[]]] ]]; local.configTable.nConfigs _ local.collisionTable.nCollisions _ 0; local.copyTable.nCopies _ 1; -- because slot 0 isn't used Acquire[local, exclusive]; [] _ BasicLoadState.EnumerateConfigs[DoOneConfig]; Release[loadState: local, commit: TRUE]; -- enters all configurations in the debugger loadstate DebuggerSwap.NoteLoadstate[debuggerLSInterval.page]; BasicLoadState.Destroy[]; }; UpdateDebuggerLoadState: PROC [configID: ConfigID] = { bcd: BcdBase = ConfigInfo[local, configID]; mtb: BcdDefs.Base = LOOPHOLE[bcd + bcd.mtOffset]; DoOneModule: PROC [module: ModuleIndex] RETURNS [BOOL _ FALSE] = { gfh: GlobalFrameHandle; mti: BcdDefs.MTIndex; [gfh: gfh, mti: mti] _ ModuleInfo[local, configID, module]; FOR i: NAT IN [0..mtb[mti].ngfi) DO debuggerLoadState.gft[gfh.gfi+i] _ [resolved: FALSE, config: configID, module: module]; ENDLOOP; }; IF configID ~= debuggerLoadState.nBcds THEN ERROR; debuggerLoadState.bcds[configID] _ [ptr[bcd]]; debuggerLoadState.nBcds _ debuggerLoadState.nBcds.SUCC; [] _ EnumerateModulesInConfig[local, configID, DoOneModule]; }; InitializeLoadState[]; PrincOps.SD[PrincOps.sCopy] _ LocalCopyNew; END. ��^��LoadStateImpl.mesa last edited by Levin on August 8, 1983 1:41 pm Last Edited by: Birrell and Rovner, July 7, 1983 2:03 pm Types and Constants Global variables Procedures exported to LoadState Synchronization Interrogation Procedures See note in interface for an explanation of the following ugliness. Modification Procedures Enumerators Internal procedures Validation LoadState Maintenance Undo Log Maintenance Note: This code assumes that, if there are multiple configs to be undone, they appear in descending order of configID on the undo list. We can now do the debugger loadstate list in the proper order (ascending configIDs). New and UnNew GFT Maintenance Debugger LoadState (a cleverer worldswap debugger would render this unnecessary) The configuration will be entered in the debugger loadstate at commit time. Initialization �Ê��˜�Jšœ™Jšœ.™.J™8J˜�šÏk ˜ šœœ˜Jšœ˜—JšœœC˜]Jšœœ#˜0Jšœœ˜Jšœ œ˜#šœ œ˜Jšœk˜k—šœœ˜JšœÀ˜À—šœ œ˜JšœEœ3œ˜‹—šœœ˜Jš œœœœ=œ˜j—Jšœœ˜,JšœœG˜O—J˜�šœ˜JšœF˜OJšœ˜—J˜�Jš˜J˜�Jšœ˜ J˜�J˜�™J˜�—Jšœœ˜&šœœœ˜-J˜�—Jšœ œœ˜1J˜�šœœ%œ˜<J˜�—Jšœœ˜J˜�Jšœ œœœ˜%J˜�šœœœ)˜DJ˜�—J™�J™J˜�Jšœ œ˜#J˜�šœœ˜J˜�—J™�J™ ™�J™J™�šÏnœœœœœ'œ˜Oš˜šœœ˜šœœ˜0Jšœ(œœ˜4—šœœ˜2Jšœœ˜—Jšœ˜—Jšœ ˜Jšœ˜—J˜—J˜�šžœœœœœœ˜Gš žœœœœ œ˜9šœ˜Jšœœœ˜šœ˜Jšœ(œ˜-Jš œ ˜Jšœœ˜J˜—Jšœœœœ˜'—J˜—šžœœœ˜!Jšœ˜Jš œ ˜J˜—šœœ˜šœœ˜Jšœ.œ˜3Jšœ˜J˜—Jšœ˜J˜Jšœ˜—J˜—J™�J™J™�šž œœ œ&˜BJšœœ˜"J˜Jšœ+˜1Jšœ˜—J˜�šž œœ;˜Wšœ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœœ˜ —J˜ J˜Jšœ*˜*Jšœœœ˜-Jšœ0œœ˜GJšœ˜šœ"œ˜,Jšœ ˜—šœ˜Jšœ.˜.Jš œ œœœœ'˜SJšœ˜—Jšœ˜—šžœœœ˜*JšœP˜PJšœœ˜*Jšœ˜J˜ Jšœ"˜"J˜Jšœ*˜*Jšœœœ˜-Jšœ"œœœ˜=š œ œœ œ˜MJšœ˜Jšœ˜—JšœC™Cšœ˜šœ˜Jšœœœ œ˜GJšœ˜Jšœœ˜—Jšœ˜—Jšœ˜—J˜�šžœœ,˜QJšœ+œ˜;J˜ J˜Jšœ$˜$Jšœ"˜"šœ œ˜Jšœœ˜)šœ˜šœ˜JšœO˜O——Jšœœ˜—J˜——˜�J˜�J™J™�Jš œœœœœ˜(J˜�šž œœ"˜=Jšœœ˜(šžœœœ˜<Jšœ œ˜šžœœ.˜?Jšœœœ˜Jšœœ˜+J˜—šž œœ.˜AJšœœœ˜šœœœ˜Jšœ˜Jšœ˜—J˜—Jšœ-˜-Jšœœ˜ J˜J˜šœœ˜'Jšœ+œ˜@Jšœ˜—Jšœ/˜/J˜—Jšœœ ˜J˜"J˜Jšœ˜šœœ˜ Jšœœœœ˜5šœ˜Jš œœœ œœ˜MJšœ˜šœœ˜*Jšœ#˜#Jšœ˜—Jšœ#˜#J˜——Jšœ:˜:Jšœœ˜J˜%J˜—J˜�šžœœœœ˜"Jšœ˜Jšœ&˜&Jšœœ˜#J˜ J˜J˜"J˜Jšœ*˜*šœœœ(˜NJšœ˜—Jšœœ>˜MJ˜ šœœœ˜Jšœ˜Jšœ˜—˜ J˜X—J˜—J˜�šžœœœœ˜Jšœ9œ˜BJ˜ J˜"J˜Jšœ$˜$Jšœ"˜"šœ œ˜˜J˜H—JšœœÏc<˜KJšœœ˜—J˜—J˜�š žœœœœœ˜;Jšœœœ˜"Jšœœ˜)J˜Jšœœ˜%J˜J˜�—š žœœœœœ˜CJšœœ ˜-J˜Jšœ&˜&Jšœ˜J˜—J˜�šžœœœœ˜$JšœB˜BJšœ3˜3Jšœœ)˜<Jšœ˜J˜—J™�Jšœ™J™�šžœœœœ˜$Jšœ˜Jšœ˜JšœœœŸ œ˜.Jšœœ˜&J˜šœ˜šœ˜šœ œœ%˜?Jšœœœ˜š˜Jšœœ˜ —Jšœ˜——šœ˜šœœ%˜4Jšœœœ˜š˜Jšœœ˜ —Jšœ˜——Jšœ˜—J˜—J˜�šžœœœœ˜,Jšœ˜Jšœ˜JšœœœŸ œ˜1Jšœ1œ˜AJšœ ˜ Jšœœ˜J˜Jšœ*˜*šœœœŸ˜=J˜šœœœ œ˜$Jšœœœ˜J˜J˜—Jšœ˜—Jšœœ˜J˜—J˜�šžœœœœ˜'Jšœ˜Jšœ˜JšœœœŸ œ˜;JšœEœ˜Ušžœœœœ˜2šžœœœœ˜8Jšœœ˜5J˜—JšœL˜RJ˜—J˜J˜5J˜—J™�—J™�Jšœ™J˜�Jšœœœ˜˜�Jšœ ™ J™�šžœœœ1˜Hšœœœ˜QJšœ˜—J˜—J˜�šž œœ˜(Jšœ œ˜+J˜—J˜�šžœœ2˜Kšœœ˜,Jšœ œ˜Jšœœ˜—Jšœ˜J˜�—J™J™�šž œœ-œ˜Vš žœœœœœ˜5šœ œ˜šœ˜šœG˜MJšœœ˜ ——Jš œœ œœœ˜)Jšœ˜—J˜—Jšœ*œœ˜8šœ œ˜šœ˜šœNœœ˜dJšœœœ ˜-Jšœ˜——Jšœ˜—Jšœ˜Jšœ˜—J˜�šž œœ,œ˜WJšœ)˜)šœ œ˜˜ šœ ˜Jšœœ˜'šœ˜šœœ/˜EJšœ-œ˜@š˜Jšœœ˜—Jšœ˜——Jšœœ ˜Jšœ˜——Jšœœ ˜Jšœœ˜—J˜—J˜�šžœœF˜XJšœœœœ$˜:Jšœœ˜+šœ œ˜Jšœ$˜$šœ˜šœMœœ˜dšœœ˜šœ˜šœG˜MJšœ˜——Jšœœ˜ Jšœœ˜—š˜Jšœœ˜—Jšœ˜——Jšœœ˜—J˜J˜�—šžœœ>˜LJ˜Jšœ%˜%šœ œ˜Jšœ$˜$šœ˜šœ-˜-Jšœ5˜9——šœ˜Jšœœ+˜2Jšœ˜šœœ˜ Jšœœœœ˜%š˜šœ˜ šœœ˜$Jšœœœ ˜?Jšœ#˜#šœœ˜8Jšœ)˜)Jšœ˜—Jšœ&˜&J˜—Jšœ˜Jšœ œ˜%J˜——Jšœ˜—Jšœœœœ˜?Jšœ+˜+Jšœ˜——J˜—J˜�šžœœ0˜AJ˜Jšœ%˜%šœ œ˜Jšœ+˜+Jšœ'˜'šœ˜JšœB˜BJšœœ˜šœœ˜šœœ˜˜šœG˜MJšœœ˜——Jšœœ œœ˜(Jšœœ˜—J˜J˜š˜˜Jšœœœ8˜JJšœ˜—Jšœœ˜—Jšœ˜—šœ4œœŸ˜SJšœG˜GJšœ.œ˜2J˜—J˜—Jšœœ˜—J˜—J˜�šžœœœœ˜BJšœœ œ˜3J˜—J˜�J™J™�šžœœ˜"Jšœˆ™ˆJšœœ˜šœ$œœ˜:šœ"œ˜*Jšœ)˜)š žœœœœœ˜CJ˜EJ˜J˜J˜—Jš œœ,œœœ˜TJ˜AJšœ*œŸ˜GJšœ*˜*Jšœœœœ˜BJ˜—Jšœ ˜Jšœ˜—J˜—J˜�šžœœ*˜?Jšœ œ+˜9J˜J˜�—šžœœ˜,Jšœœœœ ˜$Jšœœ˜Jšœœ˜!šœ$œœ˜:šœ"œ˜*Jšœœœ˜!Jšœœ&˜;Jšœœœœ˜BJ˜—Jšœ ˜Jšœ˜—JšœT™Tšœ.œœ˜DJ˜$Jšœ˜—J˜—J˜�J™ J™�šžœœœ˜QšžœœœŸ œ˜VJšœ%˜%šœ œ˜Jšœœ˜Jšœœ-˜;Jšœœ˜—Jšœ˜—šžœœ˜Jšœœœœ˜@Jšœ'œŸ œ˜Fšœ œ˜#Jšœœ2˜H—Jšœœ˜)Jšœœ˜šœ˜Jšœœ˜Jšœœœ œ˜>—Jšœ˜Jšœ;˜;Jšœœœ˜-Jšœ˜—šžœœ:Ÿ œ˜SJšœœ˜$Jšœ/˜/šœœ˜šœœœŸ*˜HJš œœœœŸ˜Dš˜šœ˜ šœœ˜ Jšœœ œ˜5Jšœ˜šœœ˜*Jšœ!˜!Jšœ˜—Jšœ˜J˜—J˜Jšœœ˜J˜——Jšœ˜—Jšœ+œ˜0J˜"J˜—Jšœœ˜8J˜8J˜—Jšœœ˜Jšœ œœœ˜.J˜ Jšœ ˜ J˜J˜JšœQ˜QJ˜˜Jš œœ œ œœ˜AJšœœ5˜E—JšœœŸ˜)Jšœ)˜)šœ˜Jšœœ@˜R—šœ/˜/šœ˜Jšœ$˜$Jšœ"œ˜)Jšœ˜—Jšœ˜—Jšœ œ˜Jšœ˜šœ œ˜˜˜$J˜J——Jšœœ˜—Jšœ"˜"Jšœ"œ˜(Jšœ˜J˜�—šž œœœ˜6šž œœŸ œ˜9Jšœœ˜Jšœœ˜$Jšœ+˜+Jšœœœ˜!šœ4œœ˜Jšœœ˜Jšœœœ!œ˜OJš˜J˜—J˜š˜Jšœœ˜—Jšœ˜—šœœœŸ'˜KJšœ9˜9—J˜J˜—J˜ J˜Jšœ ˜ šœ œ˜Jšœ/œœ˜H˜ Jšœ œœœ5˜Nšžœœœœœœ˜/Jšœœ˜—Jšœœœ˜Jšœ˜Jšœ˜JšœG˜GJ˜—Jšœœ˜—Jšœ"œ˜(J˜—J™�Jšœ™J™�Jšœ œŸ>˜WJ˜�šžœœ8˜NJšœ ˜ Jšœ#œ˜DJšœœ˜š˜Jšœœœœœœ˜LJšœ œœ˜6Jšœœœœ˜'Jšœ˜—J˜(šœœ ˜/Jšœ œ(˜4Jšœ œ)˜5Jšœ˜—J˜—J˜�šžœœ˜6Jšœ œœœ5˜Nšœœœ ˜/Jšœ œ&˜2Jšœ˜—J˜—J™�J™PJ™�Jšœ2˜2J˜�šžœœ˜Jšœœ ˜ šžœœ˜%Jšœœ$œ˜8šœœ ˜!Jšœœœ5˜P—Jšœœ.˜DJšœœœ)˜VJšœ@˜@šœœ˜2Jšœ=˜=Jšœ˜—Jš œœœœœ˜JJ˜—Jšœ˜š žœœœœœ˜KJšœœ˜J˜—š žœœœœœ˜JJ˜IJšœ0˜0Jšœœ˜5šžœœ!˜2Jšœœœ˜J˜DJšœœœ$ œ˜Mšœœœ"˜1Jšœ˜Jšœ˜—˜ J˜R—Jšœœ)˜EJ˜—J˜>JšœK™KJ˜—Jšœ˜J˜3šœœ˜Jšœ˜Jš œ œ œœœ˜HJšœœ˜Jšœœ˜(Jšœœ˜Jšœ˜—JšœB˜BJšœŸ˜:J˜J˜2Jšœ"œŸ6˜`J˜4J˜J˜J˜�—šžœœ˜6Jšœ+˜+Jšœœ˜1š žœœœœœ˜BJ˜J˜J˜;šœœœ˜#Jšœ.œ$˜WJšœ˜—J˜—Jšœ%œœ˜2Jšœ.˜.Jšœ2œ˜7J˜<J˜J˜�—J˜�—Jšœ™J˜�Jšœ˜Jšœ œ ˜+J˜�Jšœ˜J˜�—�…—����Y°��y��