DIRECTORY BasicLoadState USING [ConfigID, ConfigInfo, Destroy, EnumerateConfigs, EnumerateModulesInConfig, GlobalFrameToType, ModuleIndex, ModuleToGlobalFrame, NullModule], BasicLoadStateFormat USING [ConfigIndex, LoadState, LoadStateObject, nullModule, versionID], Basics USING [DivMod], BcdDefs USING [Base, MTHandle, MTIndex, MTNull], BcdOps USING [ProcessModules], DebuggerSwap USING [NoteLoadstate, NoteRealLoadState], 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, EmptyGFTItem, EPBias, EPIndex, EPRange, FrameHandle, GFT, GFTIndex, MainBodyIndex, MaxNGfi, NullGlobalFrame, PrefixHandle, sCopy, SD, sGFTLength], PrincOpsUtils USING [Alloc, BITAND, BITSHIFT, Codebase, Copy, Free, GetReturnFrame, GlobalFrame, MakeFsi, SetReturnLink, LongZero], SafeStorageOps USING [CopyTypesAndLiterals], VM USING [AddressForPageNumber, Interval, PagesForWords, SimpleAllocate, WordsForPages]; LoadStateImpl: MONITOR IMPORTS BasicLoadState, Basics, 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[]; }; }; GetChangeCount: PUBLIC SAFE PROC [loadState: Handle] RETURNS [INT] = TRUSTED { RETURN[loadState.changeCount]; }; ConfigInfo: PUBLIC SAFE PROC [loadState: Handle, config: ConfigID] RETURNS [bcd: BcdBase, ref: REF ANY] = TRUSTED { c: Config; CheckAccess[loadState]; c _ loadState.configTable.configs[config]; RETURN[c.bcd, c.ref] }; 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; }; }; 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 => {config _ nullConfig; module _ BasicLoadState.NullModule}; }; 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]] ] }; BuildProcDescUsingGlobalFrame: PUBLIC SAFE PROC [loadState: Handle, gfh: GlobalFrameHandle, ep: NAT] RETURNS [PrincOps.ControlLink] = TRUSTED { epb: PrincOps.EPBias; epi: PrincOps.EPIndex; CheckLocal[loadState]; IF ep >= PrincOps.MaxNGfi*PrincOps.EPRange THEN ERROR CallerBug; [epb, epi] _ Basics.DivMod[ep, PrincOps.EPRange]; RETURN[[procedure[gfi: gfh.gfi + epb, ep: epi, tag: TRUE]]] }; LoadStateFull: PUBLIC SAFE ERROR = CODE; NewConfig: PUBLIC SAFE PROC [loadState: Handle, bcd: BcdBase, ref: REF ANY] 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.ref _ ref; 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[PrincOpsUtils.GlobalFrame[LOOPHOLE[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, c, 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 _ nullCopyIndex] = { entry: Entry = FindEntry[loadState, gfh]; WITH e: entry SELECT FROM original => { SELECT e.copyIndex FROM nullCopyIndex => RETURN; fuzzyCopyIndex => FOR ci: CopyIndex IN [fuzzyCopyIndex..loadState.copyTable.nCopies) DO IF loadState.copyTable.copies[ci].parent = gfh THEN RETURN [ci]; ENDLOOP; ENDCASE => RETURN[e.copyIndex] }; copy => RETURN[e.copyIndex] ENDCASE; }; 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; EXIT}; 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[LOOPHOLE[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] = { entry: Entry = FindEntry[local, old]; WITH e: entry SELECT FROM original => RETURN[old]; copy => RETURN[local.copyTable.copies[e.copyIndex].parent]; ENDCASE => RETURN [NIL]; }; AllocGlobalFrame: PROC [old: GlobalFrameHandle, cp: PrincOps.PrefixHandle] RETURNS [frame: GlobalFrameHandle, linkspace: CARDINAL] = { 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.LongZero[LONG[frame], nWords]; }; AddCopy: PROC [original: GlobalFrameHandle, copy: GlobalFrameHandle] = { 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: PrincOps.PrefixHandle; entry: Entry; ValidateGlobalFrame[local, old]; Acquire[local, exclusive]; old _ FindOriginal[old]; IF old = NIL THEN RETURN; [new, linkspace] _ AllocGlobalFrame[old, codebase _ PrincOpsUtils.Codebase[old]]; new _ new + linkspace; new.alloced _ new.shared _ new.copied _ TRUE; new.started _ new.trapxfers _ FALSE; new.codelinks _ old.codelinks; new.code _ old.code; new.code.out _ TRUE; -- will cause start trap new.global[0] _ LOOPHOLE[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] = { 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: PrincOps.PrefixHandle = 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: [1..LAST[PrincOps.GFTIndex]+1] _ 1; EnterGlobalFrame: PROC [frame: GlobalFrameHandle, nSlots: [1..PrincOps.MaxNGfi]] = { kMax: PrincOps.GFTIndex = PrincOps.SD[PrincOps.sGFTLength] - nSlots; start: PrincOps.GFTIndex _ MIN[kMax, gftRover]; DO FOR gfi: PrincOps.GFTIndex IN [start..kMax] DO IF PrincOps.GFT[gfi] = PrincOps.EmptyGFTItem THEN { IF nSlots # 1 THEN FOR k: PrincOps.GFTIndex IN [gfi+1..gfi+nSlots) DO IF PrincOps.GFT[k] # PrincOps.EmptyGFTItem THEN GO TO fail; ENDLOOP; frame.gfi _ gfi; FOR epOffset: PrincOps.EPBias IN [0..nSlots) DO PrincOps.GFT[gfi + epOffset].framePtr _ frame; PrincOps.GFT[gfi + epOffset].epbias _ epOffset; ENDLOOP; gftRover _ gfi+nSlots; RETURN; EXITS fail => {}; }; ENDLOOP; IF start = 1 THEN EXIT; start _ 1; ENDLOOP; ERROR LoadStateFull; }; RemoveGlobalFrame: PROC [frame: GlobalFrameHandle] = { gfi: PrincOps.GFTIndex = frame.gfi; data: [0..37777B] = PrincOps.GFT[gfi].data; IF gfi < gftRover THEN gftRover _ gfi; FOR k: PrincOps.GFTIndex IN [gfi..PrincOps.SD[PrincOps.sGFTLength]) DO IF PrincOps.GFT[k].data # data THEN EXIT; PrincOps.GFT[k] _ PrincOps.EmptyGFTItem; ENDLOOP; }; debuggerLoadState: BasicLoadStateFormat.LoadState; InitializeLoadState: PROC = { debuggerLSInterval: VM.Interval; InitializeDebuggerLoadstate: PROC = { maxConfigs: NAT = BasicLoadStateFormat.ConfigIndex.LAST; debuggerLSInterval _ VM.SimpleAllocate[ count: VM.PagesForWords[SIZE[BasicLoadStateFormat.LoadStateObject[maxConfigs]]]]; debuggerLoadState _ VM.AddressForPageNumber[debuggerLSInterval.page]; [] _ PrincOpsUtils.LongZero[debuggerLoadState, VM.WordsForPages[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, NIL]; 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]; DebuggerSwap.NoteRealLoadState[LOOPHOLE[local, LONG POINTER]]; BasicLoadState.Destroy[]; }; UpdateDebuggerLoadState: PROC [configID: ConfigID] = { bcd: BcdBase = ConfigInfo[local, configID].bcd; 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] _ LOOPHOLE[LocalCopyNew]; END. XLoadStateImpl.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Levin on September 20, 1983 4:07 pm Birrell and Rovner, December 2, 1983 11:13 am Rovner on December 8, 1983 8:32 am Russ Atkinson (RRA) March 28, 1986 3:33:58 pm PST Types and Constants Global variables 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 for creation of new GFT entries. 0 is reserved, and we must be able to handle gftRover = LAST[PrincOps.GFTIndex]+1! We have one free slot so far, try for more (if needed) We now have enough free slots (starting at gfi) Debugger LoadState The configuration will be entered in the debugger loadstate at commit time. Initialization Κk˜codešœ™Kšœ Οmœ7™BKšœ#™#K™-Kšœ"™"J™1K˜šΟk ˜ Kšœžœ˜£KšœžœC˜]Kšœžœ ˜Kšœžœ#˜0Kšœžœ˜Kšœ žœ$˜6Kšœ žœm˜|KšœžœΒ˜ΧKšœ žœDžœJžœ˜―Kšœžœ žœžœW˜ƒKšœžœ˜,KšžœžœP˜X——headšœž˜KšžœNž˜WKšžœ ˜Kšœž œ˜(—K˜™K˜Kšœžœ˜&šœžœžœ˜-K˜—Kšœ žœžœ˜1K˜šœ žœ%žœ˜˜E—K˜—K˜š ŸœžœžœžœQžœžœ˜¦Kšœ˜K˜ Kšœ"˜"K˜Kšœ*˜*Kšžœžœžœ ˜-Kšžœ"žœžœžœ ˜=š žœž œžœ žœž˜MKšœ˜Kšžœ˜—KšœC™Cšžœ˜šœ ˜ Kšœžœžœ žœ˜GKšœ˜Kšœžœ˜ —Kšœ˜—Kšœ˜—K˜šŸœžœžœžœ1žœžœžœ˜Kšœ˜Kšœ˜Kšœ˜Kšžœ)žœžœ ˜@Kšœ1˜1Kšžœ.žœ˜;Kšœ˜—K˜—™K™Kš œžœžœžœžœ˜(K˜šŸ œžœžœžœ(žœžœžœžœ˜tšŸœžœžœ˜˜MK˜ šžœžœžœž˜Kšœ˜Kšžœ˜—˜ K˜X—K˜—K˜š Ÿœžœžœžœ<žœ˜^Kšœ ˜ K˜"K˜Kšœ$˜$Kšœ"˜"šžœ žœž˜˜ K˜H—KšœžœΟc<˜KKšžœžœ˜—K˜—K˜šŸœžœžœžœžœžœžœžœ˜^Kšœžœ˜)K˜Kšžœžœ˜%K˜K˜—š Ÿœžœžœžœžœ˜CKšœžœ ˜-K˜Kšœ&˜&Kšœ˜K˜—K˜šŸ œžœžœžœ˜$KšœB˜BKšœ3˜3Kšœ%žœ˜˜LK˜Kšœ%˜%šžœ žœž˜Kšœ$˜$šœ ˜ šœ-˜-Kšžœ5˜9——šžœ˜ Kšœžœ+˜2Kšœ˜šžœžœž˜ Kšžœžœžœžœ˜%šž˜šžœ˜ šžœžœ˜$Kšœžœžœ ˜?Kšœ#˜#šžœžœž˜8Kšœ)˜)Kšžœ˜—Kšœ&˜&K˜—Kšœ˜Kšœ žœ˜%K˜——Kšžœ˜—Kšœžœžœžœ˜?Kšœ+˜+Kšœ˜——K˜—K˜šŸ œžœ0˜AK˜Kšœ%˜%šžœ žœž˜Kšœ+˜+Kšœ'˜'šœ˜KšœB˜BKšœžœ˜šžœžœž˜šžœžœž˜˜ šžœGž˜MKšžœžœ˜ ——Kšœžœ žœžœ˜(Kšžœžœ˜—K˜ K˜šž˜˜Kšžœžœžœ8˜JKšžœ˜—Kšžœžœ˜—Kšžœ˜—šžœ4žœžœ ˜SKšœG˜GKšœ.žœ˜2K˜—K˜—Kšžœžœ˜—K˜—K˜šŸœžœžœžœ˜BKšžœžœžœ žœ˜=K˜—K˜—™K™šŸœžœ˜"Kšœˆ™ˆKšœžœ˜šžœ$žœžœž˜:šžœ"žœ˜*Kšœ)˜)š Ÿ œžœžœžœžœ˜CK˜EK˜K˜K˜—Kš žœžœ,žœžœžœ˜TK˜AKšœ*žœ ˜GKšœ*˜*Kšžœžœžœžœ˜BK˜—Kšžœ ˜Kšžœ˜—K˜—K˜šŸœžœ*˜?Kšœ žœ+˜9K˜K˜—šŸœžœ˜,Kšœ žœžœžœ ˜$Kšœžœ˜Kšœžœ˜!šžœ$žœžœž˜:šžœ"žœ˜*Kšžœžœžœ˜!Kšœžœ&˜;Kšžœžœžœžœ˜BK˜—Kšžœ ˜Kšžœ˜—KšœT™Tšžœ.žœžœž˜DK˜$Kšžœ˜—K˜—K˜—™ K™šŸ œžœžœ˜QšŸ œžœžœ˜KKšœ%˜%šžœ žœž˜Kšœ žœ˜Kšœžœ-˜;Kšžœžœžœ˜—Kšœ˜—šŸœžœ4žœ'žœ˜†šœ žœ˜#Kšžœžœ2˜H—Kšœžœ˜)Kšœžœ˜šœ ˜ Kšžœžœž˜Kšœžœžœ žœ˜>—Kšœ˜Kšœ;˜;Kšœžœ˜1Kšœ˜—šŸœžœ;˜HKšœžœ˜$Kšœ/˜/šžœžœ˜šžœžœžœ *˜HKš žœžœžœžœ ˜Dšž˜šžœ˜ šžœžœ˜ Kšœžœ žœ˜5Kšœ˜šžœžœž˜*Kšœ!˜!Kšžœ˜—Kšœ˜K˜—K˜Kšœžœ˜K˜——Kšžœ˜—Kšœ+žœ˜0K˜"K˜—Kšœžœ˜8K˜8K˜—Kšœ žœ˜Kšœ ˜ K˜ Kšœ ˜ K˜K˜Kšžœžœžœžœ˜KšœQ˜QK˜Kšœ(žœ˜-Kšœžœ˜$Kšœ˜Kšœ˜Kšœžœ ˜.Kšœžœ˜3šžœž˜KšœR˜R—šœ/˜/šœ˜Kšœ$˜$Kšœ"žœ˜)Kšœ˜—Kšœ˜—Kšœ žœ˜Kšœ˜šžœ žœž˜˜ ˜$K˜J——Kšžœžœ˜—Kšœ"˜"Kšœ"žœ˜(Kšœ˜K˜—šŸ œžœžœ˜6šŸ œžœ˜.Kšœžœ˜Kšœžœ˜$Kšœ+˜+Kšžœžœžœ˜!šžœ4žœžœž˜Jšžœžœ˜Kšžœžœžœ!žœ˜OKšž˜K˜—K˜ šž˜Kšžœžœ˜—Kšžœ˜—šžœžœžœ '˜KKšœ9˜9—K˜K˜—K˜ K˜Kšœ ˜ šžœ žœž˜Kšœ/žœžœ ˜H˜ Kšœ@˜@KšŸœžœžœžœžœžœž œžœ˜OKšžœžœžœ˜Kšœ˜Kšœ˜KšœG˜GK˜—Kšžœžœ˜—Kšœ"žœ˜(K˜—K™—šœ™K™šœžœ˜-KšœžœBžœ™s—K˜šŸœžœ>˜TKšœ#žœ˜DKšœžœ˜/šž˜šžœžœž˜.šžœ žœžœ˜3Kšœ6™6šžœ ž˜šžœžœž˜2Kš žœ žœžœžœžœ˜;Kšžœ˜——Kšœ/™/K˜šžœžœ ž˜/Kšœ žœ"˜.Kšœ žœ#˜/Kšžœ˜—Kšœ˜Kšžœ˜Kšžœ ˜K˜—Kšžœ˜—Kšžœ žœžœ˜K˜ Kšžœ˜—Kšžœ˜K˜—K˜šŸœžœ˜6Kšœ#˜#Kšœžœ ˜+Kšžœžœ˜&šžœžœžœž˜FKšžœ žœžœžœ˜)Kšœ žœ˜(Kšžœ˜—K˜—K™—™K™Kšœ2˜2K˜šŸœžœ˜Kšœžœ ˜ šŸœžœ˜%Kšœ žœ$žœ˜8šœžœ˜'Kšœžœžœ5˜Q—Kšœžœ/˜EKšœ/žœ*˜[Kšœ@˜@šžœžœž˜2Kšœ=˜=Kšžœ˜—Kš žœžœžœžœžœ˜JK˜—Kšœ˜š Ÿ œžœžœžœžœ˜KKšœžœ˜K˜—š Ÿ œžœžœžœžœ˜JKšœIžœ˜NKšœ0˜0Kšœžœ˜5šŸ œžœ!˜2Kšžœžœžœ˜K˜DKšžœžœžœ$ž œ˜Mšžœžœžœ"ž˜1Kšœ˜Kšžœ˜—˜ K˜R—Kšœžœ)˜EK˜—K˜>KšœK™KK˜—Kšœ˜K˜3šœžœ ˜Kšœ ˜ Kš œ žœ žœžœžœ˜HKšœ žœ˜Kšœžœ˜(Kšœžœ ˜Kšœ˜—KšœB˜BKšœ ˜:K˜K˜2Kšœ"žœ 6˜`K˜4Kšœžœžœžœ˜>K˜K˜K˜—šŸœžœ˜6Kšœ/˜/Kšœžœ˜1š Ÿ œžœžœžœžœ˜BK˜K˜K˜;šžœžœžœž˜#Kšœ.žœ$˜WKšžœ˜—K˜—Kšžœ%žœžœ˜2Kšœ.˜.Kšœ2žœ˜7K˜