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˜šœ œ%œ˜˜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šœ œ)˜˜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˜