WVMLoadState.mesa
Cedar Remote Debugging: cache of client pages
Andrew Birrell December 2, 1983 3:08 pm
Russ Atkinson, May 15, 1984 5:07:14 pm PDT
DIRECTORY
BasicLoadState,
BasicLoadStateFormat,
BasicLoadStateFormatExtension,
PrincOps,
LoadState,
LoadStateFormat,
WorldVM,
WVMPrivate USING [ WorldObject ];
WVMLoadState:
MONITOR
IMPORTS WorldVM
EXPORTS LoadState--opaque type--, WorldVM--opaque type--, WVMPrivate = {
Types and things
Address: TYPE = WorldVM.Address;
BcdInfo: TYPE = BasicLoadStateFormat.BcdInfo;
Config:
TYPE = LoadStateFormat.Config;
ConfigObject: TYPE = LoadStateFormat.ConfigObject;
ConfigID: PUBLIC TYPE = LoadStateFormat.ConfigID;
ConfigIndex:
TYPE = BasicLoadStateFormat.ConfigIndex;
nullConfig: ConfigIndex = BasicLoadStateFormat.nullConfig;
ConfigTable: TYPE = LoadStateFormat.ConfigTable;
CollisionTable: TYPE = LoadStateFormat.CollisionTable;
CollisionTableIndex: TYPE = LoadStateFormat.CollisionTableIndex;
CopyTable: TYPE = LoadStateFormat.CopyTable;
Entry: TYPE = LoadStateFormat.Entry;
Extension: TYPE = BasicLoadStateFormatExtension.Extension;
ExtensionEntry: TYPE = BasicLoadStateFormatExtension.ExtensionEntry;
ModuleInfo: TYPE = BasicLoadStateFormat.ModuleInfo;
World: TYPE = REF WorldObject;
GFTIndex: TYPE = PrincOps.GFTIndex;
GFTItem: TYPE = PrincOps.GFTItem;
GFTArray: TYPE = ARRAY GFTIndex OF GFTItem;
WorldObject: PUBLIC TYPE = WVMPrivate.WorldObject;
GetLoadState:
PUBLIC
PROC [world: World, basic, real: Address] = {
basicWords: NAT = SIZE[BasicLoadStateFormat.LoadStateObject[0]];
realWords:
NAT =
SIZE[LoadStateFormat.Object] - LoadStateFormat.htSize*SIZE[LoadStateFormat.Entry];
cheat: ARRAY [0..MAX[basicWords, realWords]) OF CARDINAL;
IF real = 0
THEN {
The world we are examining has no "real" load state, so check its version, then copy the basic load state.
basicPtr: POINTER TO BasicLoadStateFormat.LoadStateObject = LOOPHOLE[@cheat];
WorldVM.CopyRead[world: world, to: @cheat, from: basic, nwords: basicWords];
IF basicPtr.versionident # BasicLoadStateFormat.versionID THEN ERROR BadLoadState;
CopyBasicLoadState[world, basic];
}
ELSE {
The world we are exmining claims to have a "real" load state.
realPtr: POINTER TO LoadStateFormat.Object = LOOPHOLE[@cheat];
WorldVM.CopyRead[world: world, to: @cheat, from: basic, nwords: realWords];
CopyRealLoadState[world, real];
};
};
BadLoadState: ERROR = CODE;
--LoadState.--Object: PUBLIC TYPE = LoadStateFormat.Object;
CopyRealLoadState:
PROC[world: World, real: Address] = {
loadState: REF Object = NEW[Object];
loadState.useCount ← 0;
loadState.changeCount ←
LOOPHOLE[WorldVM.LongRead[
world: world,
addr: real + (LOOPHOLE[@loadState.changeCount,Address]-LOOPHOLE[loadState,Address])
]];
loadState.configTable ← CopyConfigTable[
world: world,
from: WorldVM.LongRead[world,
real + (LOOPHOLE[@loadState.configTable,Address]-LOOPHOLE[loadState,Address])]
];
loadState.copyTable ← CopyCopyTable[
world: world,
from: WorldVM.LongRead[world,
real + (LOOPHOLE[@loadState.copyTable,Address]-LOOPHOLE[loadState,Address])]
];
loadState.collisionTable ← CopyCollisionTable[
world: world,
from: WorldVM.LongRead[world,
real + (LOOPHOLE[@loadState.collisionTable,Address]-LOOPHOLE[loadState,Address])]
];
WorldVM.CopyRead[
world: world,
from: real + (LOOPHOLE[@loadState.gfht,Address]-LOOPHOLE[loadState,Address]),
to: @loadState.gfht,
nwords: SIZE[ARRAY LoadStateFormat.HashIndex OF LoadStateFormat.Entry]
];
world.loadState ← loadState;
};
CopyConfigTable:
PROC [world: World, from: Address]
RETURNS [to:
REF ConfigTable] = {
minSize: CARDINAL = SIZE[LoadStateFormat.ConfigTable[0]];
temp: ARRAY [0..minSize) OF WORD;
cheat: POINTER TO LoadStateFormat.ConfigTable = LOOPHOLE[@temp];
WorldVM.CopyRead[
world: world,
from: from,
to: @temp,
nwords: minSize];
to ← NEW[LoadStateFormat.ConfigTable[cheat.length]];
to.nConfigs ← cheat.nConfigs;
FOR i: NAT IN [0..to.nConfigs)
DO to[i] ← CopyConfig[
world: world,
from: WorldVM.LongRead[world,
from + (LOOPHOLE[@to[i],Address]-LOOPHOLE[to,Address])]
];
ENDLOOP;
};
CopyCopyTable:
PROC
[world: World, from: Address] RETURNS [to: REF LoadStateFormat.CopyTable] = {
minSize: CARDINAL = SIZE[LoadStateFormat.CopyTable[0]];
temp: ARRAY [0..minSize) OF WORD;
cheat: POINTER TO LoadStateFormat.CopyTable = LOOPHOLE[@temp];
WorldVM.CopyRead[
world: world,
from: from,
to: @temp,
nwords: minSize];
to ← NEW[LoadStateFormat.CopyTable[cheat.length]];
to.nCopies ← cheat.nCopies;
FOR i:
NAT
IN [0..to.nCopies)
DO
to[i].parent ←
LOOPHOLE[WorldVM.Read[world,
from + (LOOPHOLE[@to[i].parent,Address]-LOOPHOLE[to,Address])]];
to[i].copies ← CopyCopiesList[
world: world,
from: WorldVM.LongRead[world,
from + (LOOPHOLE[@to[i].copies,Address]-LOOPHOLE[to,Address])]
];
ENDLOOP;
};
CopyCollisionTable:
PROC
[world: World, from: Address] RETURNS [to: REF LoadStateFormat.CollisionTable] = {
minSize: CARDINAL = SIZE[LoadStateFormat.CollisionTable[0]];
temp: ARRAY [0..minSize) OF WORD;
cheat: POINTER TO LoadStateFormat.CollisionTable = LOOPHOLE[@temp];
WorldVM.CopyRead[
world: world,
from: from,
to: @temp,
nwords: minSize];
to ← NEW[LoadStateFormat.CollisionTable[cheat.length]];
to.nCollisions ← cheat.nCollisions;
FOR i:
NAT
IN [0..to.nCollisions)
DO
to[i] ← CopyCollisionList[
world: world,
from: WorldVM.LongRead[
world, from + (LOOPHOLE[@to[i],Address]-LOOPHOLE[to,Address])]
];
ENDLOOP;
};
CopyConfig:
PROC
[world: World, from: Address] RETURNS [to: REF LoadStateFormat.ConfigObject] = {
minSize: CARDINAL = SIZE[LoadStateFormat.ConfigObject[0]];
temp: ARRAY [0..minSize) OF WORD;
cheat: POINTER TO LoadStateFormat.ConfigObject = LOOPHOLE[@temp];
WorldVM.CopyRead[
world: world,
from: from,
to: @temp,
nwords: minSize];
to ← NEW[LoadStateFormat.ConfigObject[cheat.length]];
to.bcd ← cheat.bcd;
to.ref ← NIL;
to.nModules ← cheat.nModules;
IF to.nModules > 0
THEN
WorldVM.CopyRead[
world: world,
from: from + (LOOPHOLE[@to[0],Address]-LOOPHOLE[to,Address]),
to: @to[0],
nwords: to.nModules * SIZE[LoadStateFormat.ModuleEntry]
];
};
CopyCopiesList:
PROC
[world: World, from: Address] RETURNS [to: LIST OF PrincOps.GlobalFrameHandle ← NIL] = {
fromPos: Address ← from;
toPos: LIST OF PrincOps.GlobalFrameHandle ← NIL;
dummy: LIST OF PrincOps.GlobalFrameHandle = CONS[first: NULL, rest: NIL];
firstOffset:
CARDINAL =
LOOPHOLE[@dummy.first,Address]-LOOPHOLE[dummy,Address];
restOffset:
CARDINAL =
LOOPHOLE[@dummy.rest,Address]-LOOPHOLE[dummy,Address];
UNTIL fromPos = 0
--NIL--
DO
this: PrincOps.GlobalFrameHandle = LOOPHOLE[WorldVM.Read[world, fromPos + firstOffset]];
new: LIST OF PrincOps.GlobalFrameHandle = CONS[first: this, rest: NIL];
IF to = NIL THEN to ← new ELSE toPos.rest ← new;
toPos ← new;
fromPos ← WorldVM.LongRead[world, fromPos + restOffset];
ENDLOOP;
};
CopyCollisionList:
PROC
[world: World, from: Address] RETURNS [to: LIST OF LoadStateFormat.Entry ← NIL] = {
fromPos: Address ← from;
toPos: LIST OF LoadStateFormat.Entry ← NIL;
dummy: LIST OF LoadStateFormat.Entry = CONS[first: NULL, rest: NIL];
firstOffset:
CARDINAL =
LOOPHOLE[@dummy.first,Address]-LOOPHOLE[dummy,Address];
restOffset:
CARDINAL =
LOOPHOLE[@dummy.rest,Address]-LOOPHOLE[dummy,Address];
UNTIL fromPos = 0
--NIL--
DO
this: LoadStateFormat.Entry;
new: LIST OF LoadStateFormat.Entry;
WorldVM.CopyRead[
world: world,
from: fromPos + firstOffset,
to: @this,
nwords: SIZE[LoadStateFormat.Entry]];
new ← CONS[first: this, rest: NIL];
IF to = NIL THEN to ← new ELSE toPos.rest ← new;
toPos ← new;
fromPos ← WorldVM.LongRead[world, fromPos + restOffset];
ENDLOOP;
};
CopyBasicLoadState:
PROC [world: World, basic: Address] = {
RRA: This routine was written nearly from scratch to transform a basic load state into a real live Cedar load state. It is used whenever there is a basic load state and no real Cedar load state, which is true during the initialization of the world. Once things start to get loaded from Basic.Loadees, the load state is just fine.
minSize: CARDINAL = SIZE[BasicLoadStateFormat.LoadStateObject[0]];
temp: ARRAY [0..minSize) OF WORD;
cheat: POINTER TO BasicLoadStateFormat.LoadStateObject = LOOPHOLE[@temp];
nConfigs: CARDINAL ← 0;
local: LoadStateFormat.Handle ← NIL;
extension: REF Extension = NEW[Extension];
gft: REF GFTArray = NEW[GFTArray];
basicLoadState: REF BasicLoadStateFormat.LoadStateObject ← world.basicLoadState;
Copy the first part of the basic load state to determine the real length
WorldVM.CopyRead[world: world,
to: @temp,
from: basic,
nwords: minSize];
IF basicLoadState =
NIL
OR cheat.length # basicLoadState.length
THEN
world.basicLoadState ← basicLoadState ←
NEW[BasicLoadStateFormat.LoadStateObject[cheat.length]];
Copy the basic load state, which maps
gft: gfi -> <ConfigIndex, ModuleIndex>
bcds: ConfigIndex -> BcdInfo
WorldVM.CopyRead[world: world,
to: LOOPHOLE[basicLoadState, LONG POINTER],
from: basic,
nwords: SIZE[BasicLoadStateFormat.LoadStateObject[cheat.length]]
];
Copy the load state extension, which maps gfi -> <mti, type>
WorldVM.CopyRead[world: world,
to: LOOPHOLE[extension, LONG POINTER],
from: basic+SIZE[BasicLoadStateFormat.LoadStateObject[cheat.length]],
nwords: SIZE[Extension]
];
Copy the GFT, which maps gfi -> <gfh, epi>
WorldVM.CopyRead[world: world,
to: LOOPHOLE[gft, LONG POINTER],
from: WorldVM.Long[world, LOOPHOLE[PrincOps.GFT]],
nwords: SIZE[Extension]
];
Allocate the load state
nConfigs ← basicLoadState.nBcds;
world.loadState ← local ←
NEW[LoadStateFormat.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
Now initialize the load state, using the GFT and the extension
FOR outerGfi: GFTIndex
IN GFTIndex
DO
IF gft[outerGfi].data # 0
THEN {
We MAY have a new config!
cfi: ConfigIndex = basicLoadState.gft[outerGfi].config;
IF cfi # nullConfig
AND local.configTable[cfi] =
NIL
THEN {
We have a new config, sports fans!
c: Config ← NIL;
bcdInfo: BcdInfo ← basicLoadState[cfi];
nMod: NAT ← 1;
i: NAT ← 1; -- first index is not used (inscrutable, but true)
FOR gfi: GFTIndex
IN GFTIndex
DO
nmodinfo: ModuleInfo = basicLoadState.gft[gfi];
IF cfi = nmodinfo.config THEN nMod ← nMod + 1;
ENDLOOP;
Allocate the new config object
c ← NEW[ConfigObject[nMod]];
Place the config info into the config table
local.configTable[cfi] ← c;
IF cfi > local.configTable.nConfigs THEN local.configTable.nConfigs ← cfi;
Initialize the new config info
bcdInfo.exports ← bcdInfo.typeExported ←
FALSE;
Ensure no garbage in the bcd. Unfortunately, I don't know where this info gets used in the new load state (if at all)!
c.bcd ← bcdInfo.bcd;
c.ref ← NIL;
c.nModules ← nMod;
FOR gfi: GFTIndex
IN GFTIndex
DO
Fill in the entries for multi-gfi modules
modInfo: ModuleInfo = basicLoadState.gft[gfi];
IF cfi = modInfo.config
THEN {
ee: ExtensionEntry = extension[gfi];
item: GFTItem ← gft[gfi];
hi: CARDINAL = item.data MOD LoadStateFormat.htSize;
entry: LoadStateFormat.Entry ← [original[
copyIndex: LoadStateFormat.nullCopyIndex,
configID: cfi,
module: modInfo.module]];
oldEntry: LoadStateFormat.Entry = local.gfht[hi];
item.epbias ← 0; -- to make the frame pointer OK
c[i].mti ← ee.mti;
c[i].gfh ← item.framePtr;
c[i].type ← LOOPHOLE[ee.type]; -- is this really the same thing?
i ← i + 1;
Now place the new gfh info into the hash table as well
WITH e: oldEntry
SELECT
FROM
empty => local.gfht[hi] ← entry;
collision =>
local.collisionTable.collisions[e.list] ←
CONS[entry, local.collisionTable.collisions[e.list]];
ENDCASE => {
ct: REF CollisionTable ← local.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;
local.collisionTable ← ct ← newCT;
};
ci ← ct.nCollisions;
ct.nCollisions ← ct.nCollisions.SUCC;
};
ENDLOOP;
ct.collisions[ci] ← CONS[entry, CONS[local.gfht[hi], NIL]];
local.gfht[hi] ← [collision[list: ci]];
};
};
ENDLOOP;
};
};
ENDLOOP;
{exitCrock:
BOOL ←
TRUE;
exitCrock ← FALSE;
};
};
}.