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��