WVMLoadState.mesa - cache of client pages
Copyright © 1985 by Xerox Corporation. All rights reserved.
Andrew Birrell December 2, 1983 3:08 pm
Russ Atkinson, February 6, 1985 9:23:50 pm PST
Russ Atkinson (RRA) May 14, 1985 10:38:11 am PDT
DIRECTORY
BasicLoadState USING [],
BasicLoadStateFormat USING [BcdInfo, ConfigIndex, Extension, ExtensionEntry, LoadStateObject, ModuleInfo, nullConfig, versionID],
LoadState USING [Handle, Object],
LoadStateFormat USING [CollisionTable, CollisionTableIndex, Config, ConfigID, ConfigObject, ConfigTable, CopyTable, Entry, Handle, HashIndex, htSize, ModuleEntry, nullCopyIndex, Object],
PrincOps USING [GFT, GFTIndex, GFTItem, GlobalFrameHandle],
WorldVM USING [Address, CopyRead, Long, LongRead, Read, WorldObject],
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 = BasicLoadStateFormat.Extension;
ExtensionEntry: TYPE = BasicLoadStateFormat.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[GFTArray]
];
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: BOOLTRUE;
exitCrock ← FALSE;
};
};
}.