-- BcdMerge.Mesa Edited by Sandman on October 2, 1980 5:02 PM
-- Copyright Xerox Corporation 1979, 1980
DIRECTORY
AltoDefs USING [PageSize],
BcdDefs USING [
Base, BCD, BinderNTables, CTIndex, CTNull, CTRecord, cttype, EVIndex, EVNull,
EVRecord, evtype, EXPIndex, EXPRecord, exptype, FTIndex, FTNull, FTRecord,
FTSelf, fttype, GFTIndex, IMPIndex, IMPNull, IMPRecord, imptype, Link,
MTIndex, MTNull, MTRecord, mttype, Namee, NameRecord, NTIndex, NTRecord,
nttype, NullLink, NullName, NullVersion, SGIndex, SGRecord, sgtype, sstype,
TMIndex, TMNull, TMRecord, tmtype, TYPIndex, TYPRecord, typtype, UnboundLink,
VersionID, VersionStamp],
BcdMergeOps USING [],
BcdOps USING [
BcdBase, CTHandle, EVHandle, EXPHandle, IMPHandle, MTHandle, NameString,
ProcessConfigs, ProcessExports, ProcessImports, ProcessModules, FindName,
SGHandle, TMHandle],
SymbolOps: FROM "BcdSymbolOps" USING [
EnterString, FindEquivalentString, Finalize, FindString, HTIndex, Initialize,
SubStringForHash],
ControlDefs USING [ControlLink, GFT, GlobalFrameHandle, NullLink, UnboundLink],
FrameDefs USING [DeletedFrame],
FrameOps USING [ValidGlobalFrame],
ImageDefs USING [ImageVersion],
InlineDefs USING [COPY],
LoaderOps USING [CloseLinkSpace, OpenLinkSpace, ReadLink],
LoadStateFormat USING [ConfigIndex, ModuleTable],
LoadStateOps USING [Map],
MiscDefs USING [CurrentTime, GetNetworkNumber, Zero],
OsStaticDefs USING [OsStatics],
SegmentDefs USING [
Append, ChangeDataToFileSegment, DefaultBase, DefaultMDSBase,
DeleteFileSegment, FileSegmentAddress, HardDown, MakeSwappedIn,
MoveFileSegment, NewFile, NewFileSegment, Read, SwapOut, Unlock,
VMtoDataSegment, Write, FileSegmentHandle],
StringDefs USING [SubString, SubStringDescriptor],
Storage USING [Node, Pages, Free, FreePages, PagesForWords],
Table USING [
AddNotify, Allocate, Base, Bounds, Create, Destroy, DropNotify, Notifier,
Overflow];
BcdMerge: PROGRAM
IMPORTS
BcdOps, SymbolOps, FrameDefs, FrameOps, ImageDefs, InlineDefs, MiscDefs,
SegmentDefs, Storage, Table, LoaderOps
EXPORTS BcdMergeOps =PUBLIC
BEGIN OPEN LoadStateFormat, BcdOps, BcdDefs;
GlobalFrameHandle: TYPE = ControlDefs.GlobalFrameHandle;
HTIndex: TYPE = SymbolOps.HTIndex;
SubStringDescriptor: TYPE = StringDefs.SubStringDescriptor;
SubString: TYPE = StringDefs.SubString;
Map: TYPE = LoadStateOps.Map;
ControlLink: TYPE = ControlDefs.ControlLink;
MergeData: TYPE = RECORD [
bcd: BcdOps.BcdBase,
mtb, ftb, ctb, itb, etb, evb, ntb, sgb, typb, tmb: Table.Base,
ssb: NameString,
configOffset: CARDINAL,
nextDummyGfi, nextGfi: GFTIndex,
bcdFile: FTIndex,
name: STRING,
table: BcdDefs.Base,
expandedtable: BOOLEAN,
tableSegment: SegmentDefs.FileSegmentHandle,
tablePages: CARDINAL,
header: BCD];
data: POINTER TO MergeData;
Notify: PRIVATE Table.Notifier =
BEGIN OPEN BcdDefs, data;
mtb ← base[mttype];
ftb ← base[fttype];
ctb ← base[cttype];
itb ← base[imptype];
etb ← base[exptype];
ntb ← base[nttype];
sgb ← base[sgtype];
evb ← base[evtype];
typb ← base[typtype];
tmb ← base[tmtype];
ssb ← LOOPHOLE[base[sstype]];
END;
EnterName: PROCEDURE [ss: SubString] RETURNS [NameRecord] =
BEGIN OPEN SymbolOps;
lss: SubStringDescriptor;
hti: HTIndex = EnterString[ss];
SubStringForHash[@lss, hti];
RETURN[[lss.offset]];
END;
MapName: PROCEDURE [bcd: BcdBase, n: NameRecord] RETURNS [NameRecord] =
BEGIN
ssb: NameString ← LOOPHOLE[bcd + bcd.ssOffset];
ss: SubStringDescriptor ← [base: @ssb.string, offset: n, length: ssb.size[n]];
RETURN[EnterName[@ss]];
END;
MapEquivalentName: PROCEDURE [bcd: BcdBase, n: NameRecord]
RETURNS [NameRecord] =
BEGIN
found: BOOLEAN;
hti: HTIndex;
ssb: NameString ← LOOPHOLE[bcd + bcd.ssOffset];
ss: SubStringDescriptor ← [base: @ssb.string, offset: n, length: ssb.size[n]];
[found, hti] ← SymbolOps.FindEquivalentString[@ss];
IF found THEN RETURN[NameForHti[hti]];
RETURN[EnterName[@ss]];
END;
HtiName: PROCEDURE [n: NameRecord] RETURNS [HTIndex] =
BEGIN OPEN data;
ss: SubStringDescriptor ← [base: @ssb.string, offset: n, length: ssb.size[n]];
RETURN[SymbolOps.FindString[@ss].hti];
END;
NameForHti: PROCEDURE [hti: HTIndex] RETURNS [NameRecord] =
BEGIN
ss: SubStringDescriptor;
SymbolOps.SubStringForHash[@ss, hti];
RETURN[[ss.offset]];
END;
MergeFile: PROCEDURE [bcd: BcdBase, oldfti: FTIndex] RETURNS [fti: FTIndex] =
BEGIN OPEN data;
oldftb: Table.Base = LOOPHOLE[bcd + bcd.ftOffset];
ftLimit: FTIndex = LOOPHOLE[Table.Bounds[fttype].size];
fn: NameRecord;
IF oldfti = FTSelf THEN RETURN[WhoIsFTSelf[]];
fn ← MapEquivalentName[bcd, oldftb[oldfti].name];
FOR fti ← FIRST[FTIndex], fti + SIZE[FTRecord] UNTIL fti = ftLimit DO
OPEN new: ftb[fti], old: oldftb[oldfti];
IF new.name = fn THEN
BEGIN
SELECT TRUE FROM
(new.version = NullVersion) =>
BEGIN new.version ← old.version; RETURN END;
(new.version = old.version), (old.version = NullVersion) => RETURN;
ENDCASE;
END;
ENDLOOP;
fti ← Table.Allocate[fttype, SIZE[FTRecord]];
ftb[fti] ← [name: fn, version: oldftb[oldfti].version];
RETURN
END;
MergeSegment: PROCEDURE [bcd: BcdBase, sgh: SGHandle, fti: FTIndex]
RETURNS [sgi: SGIndex] =
BEGIN OPEN data;
sgLimit: SGIndex = LOOPHOLE[Table.Bounds[sgtype].size];
IF fti = FTNull THEN fti ← MergeFile[bcd, sgh.file];
FOR sgi ← FIRST[SGIndex], sgi + SIZE[SGRecord] UNTIL sgi = sgLimit DO
OPEN new: sgb[sgi];
IF new.class = sgh.class AND new.file = fti AND new.base = sgh.base AND
new.pages = sgh.pages AND new.extraPages = sgh.extraPages THEN RETURN;
ENDLOOP;
sgi ← Table.Allocate[sgtype, SIZE[SGRecord]];
sgb[sgi] ←
[class: sgh.class, file: fti, base: sgh.base, pages: sgh.pages,
extraPages: sgh.extraPages];
RETURN
END;
GetDummyGfi: PROCEDURE [n: CARDINAL] RETURNS [gfi: GFTIndex] =
BEGIN
gfi ← data.nextDummyGfi;
data.nextDummyGfi ← data.nextDummyGfi + n;
RETURN
END;
GetGfi: PROCEDURE [n: CARDINAL] RETURNS [gfi: GFTIndex] =
BEGIN gfi ← data.nextGfi; data.nextGfi ← data.nextGfi + n; RETURN END;
MergeModule: PUBLIC PROCEDURE [
frame, copied: GlobalFrameHandle, mt: ModuleTable] =
BEGIN OPEN data;
ccgfi: GFTIndex;
mti, newmti: MTIndex;
mth, newmth: MTHandle;
i: CARDINAL;
ccgfi ← mt[copied.gfi].gfi;
FOR mti ← FIRST[MTIndex], mti + SIZE[MTRecord] + mtb[mti].frame.length UNTIL
mti = LOOPHOLE[Table.Bounds[mttype].size, MTIndex] DO
IF mtb[mti].gfi = ccgfi THEN EXIT; REPEAT FINISHED => ERROR; ENDLOOP;
newmti ← Table.Allocate[
mttype, SIZE[MTRecord] + mtb[mti].frame.length !
Table.Overflow =>
BEGIN ExpandTable[]; RESUME [[table, tablePages*AltoDefs.PageSize]]; END];
mth ← @mtb[mti];
newmth ← @mtb[newmti];
InlineDefs.COPY[
from: mth, to: newmth, nwords: SIZE[MTRecord] + mth.frame.length];
newmth.namedInstance ← FALSE;
newmth.gfi ← mt[frame.gfi].gfi;
FOR i IN [0..newmth.frame.length) DO
IF newmth.frame.frag[i].gfi IN [mth.gfi..mth.gfi + mth.ngfi) THEN
newmth.frame.frag[i].gfi ← newmth.gfi + mth.frame.frag[i].gfi - mth.gfi;
ENDLOOP;
END;
MergeModuleTable: PROCEDURE [map: Map, config: ConfigIndex, mt: ModuleTable] =
BEGIN OPEN data;
MoveModule: PROCEDURE [old: MTHandle, mti: MTIndex] RETURNS [BOOLEAN] =
BEGIN
rgfi: GFTIndex ← map[old.gfi];
frame: GlobalFrameHandle ← ControlDefs.GFT[rgfi].frame;
newmti: MTIndex;
oldsgb: Table.Base ← LOOPHOLE[bcd + bcd.sgOffset];
IF ~FrameDefs.DeletedFrame[rgfi] THEN
BEGIN OPEN m: mtb[newmti];
header.nModules ← header.nModules + 1;
newmti ← Table.Allocate[mttype, SIZE[MTRecord] + old.frame.length];
mtb[newmti] ← old↑;
m.name ← MapName[bcd, old.name];
IF old.namedInstance THEN
BEGIN
EnterNameInTable[
[module[newmti]], MapName[bcd, FindName[bcd, [module[mti]]]]];
m.namedInstance ← TRUE
END
ELSE m.namedInstance ← FALSE;
m.file ← MergeFile[bcd, old.file];
m.code.sgi ← MergeSegment[bcd, @oldsgb[old.code.sgi], FTSelf];
m.sseg ← MergeSegment[bcd, @oldsgb[old.sseg], FTNull];
m.gfi ← mt[map[old.gfi]].gfi;
m.variables ← MergeVariables[bcd, old];
MergeLinks[frame, newmti, old, mt];
IF old.config # CTNull THEN
BEGIN OPEN cti: ctb[m.config];
m.config ← old.config + configOffset;
IF cti.nControls # 0 AND cti.controls[0] = mti THEN
cti.controls[0] ← newmti;
END
ELSE
IF bcd.nConfigs = 0 THEN
BEGIN
m.config ← Table.Allocate[cttype, SIZE[CTRecord]];
ctb[m.config] ← CTRecord[
name: m.name, namedInstance: FALSE, file: m.file, config: CTNull,
nControls: 0, controls:];
END
ELSE m.config ← CTNull;
END
ELSE
IF old.config # CTNull AND ctb[old.config + configOffset].nControls # 0
AND ctb[old.config + configOffset].controls[0] = mti THEN
ctb[old.config + configOffset].controls[0] ← MTNull;
RETURN[FALSE];
END;
[] ← ProcessModules[bcd, MoveModule];
END;
-- Variables and types are not merged correctly. After a makeimage, types
-- in the frame are not necessarily correct
MergeLinks: PROCEDURE [
frame: GlobalFrameHandle, newmti: MTIndex, old: MTHandle, mt: ModuleTable] =
BEGIN OPEN data, m: mtb[newmti];
cl: ControlLink;
link: Link;
i: CARDINAL;
LoaderOps.OpenLinkSpace[frame, old];
FOR i IN [0..old.frame.length) DO
cl ← LoaderOps.ReadLink[i];
IF cl = ControlDefs.NullLink OR cl = ControlDefs.UnboundLink THEN
link ← AddImport[old.frame.frag[i]]
ELSE link ← MapLink[cl];
m.frame.frag[i] ← link;
ENDLOOP;
LoaderOps.CloseLinkSpace[frame];
RETURN
END;
MapLink: PROCEDURE [cl: ControlLink] RETURNS [bl: Link] =
BEGIN
SELECT cl.tag FROM
frame =>
BEGIN OPEN f: LOOPHOLE[cl.frame, GlobalFrameHandle];
IF FrameOps.ValidGlobalFrame[@f] THEN
bl ← [variable[vgfi: f.gfi, var: 0, vtag: var]]
ELSE bl ← NullLink;
END;
procedure => bl ← [procedure[gfi: cl.gfi, ep: cl.ep, tag: TRUE]];
ENDCASE => bl ← UnboundLink;
RETURN
END;
MergeVariables: PROCEDURE [bcd: BcdBase, old: MTHandle] RETURNS [evi: EVIndex] =
BEGIN
evh, newevh: EVHandle;
evLimit: EVIndex = LOOPHOLE[Table.Bounds[evtype].size];
i: CARDINAL;
IF old.variables = EVNull THEN RETURN[EVNull];
evh ← @LOOPHOLE[bcd + bcd.evOffset, Table.Base][old.variables];
FOR evi ← FIRST[EVIndex], evi + SIZE[EVRecord] + data.evb[evi].length UNTIL
evi = evLimit DO
newevh ← @data.evb[evi];
IF evh.length <= newevh.length THEN
FOR i IN [1..evh.length] DO
IF evh.offsets[i] # newevh.offsets[i] THEN EXIT;
REPEAT FINISHED => RETURN[evi];
ENDLOOP;
ENDLOOP;
evi ← Table.Allocate[evtype, SIZE[EVRecord] + evh.length];
InlineDefs.COPY[
from: evh, to: @data.evb[evi], nwords: SIZE[EVRecord] + evh.length];
RETURN
END;
MergeExportTable: PROCEDURE [map: Map, mt: ModuleTable] =
BEGIN OPEN data;
MapExport: PROCEDURE [old: EXPHandle, eti: EXPIndex] RETURNS [BOOLEAN] =
BEGIN
neweti: EXPIndex;
oldftb: Table.Base ← LOOPHOLE[bcd + bcd.ftOffset];
oldssb: NameString ← LOOPHOLE[bcd + bcd.ssOffset];
i: CARDINAL;
found: BOOLEAN;
hti: HTIndex;
oldname: StringDefs.SubStringDescriptor;
oldname ←
[base: @oldssb.string, offset: old.name, length: oldssb.size[old.name]];
[found, hti] ← SymbolOps.FindString[@oldname];
IF found THEN
BEGIN
neweti ← FIRST[EXPIndex];
DO
OPEN new: etb[neweti];
IF hti = HtiName[new.name] AND new.port = old.port THEN
BEGIN
IF oldftb[old.file].version = ftb[new.file].version THEN
BEGIN
FOR i IN [0..old.size) DO
IF old.links[i].gfi # 0 THEN
-- assumes that most recently loaded config
-- merged last
BEGIN
new.links[i] ← old.links[i];
new.links[i].gfi ← mt[map[old.links[i].gfi]].gfi;
END;
ENDLOOP;
IF ~new.namedInstance AND old.namedInstance THEN
BEGIN
new.namedInstance ← TRUE;
EnterNameInTable[
[export[neweti]], MapName[bcd, FindName[bcd, [export[eti]]]]];
END;
RETURN[FALSE];
END;
END;
neweti ← neweti + new.size + SIZE[EXPRecord];
IF neweti = LOOPHOLE[Table.Bounds[exptype].size] THEN EXIT;
ENDLOOP;
END;
[] ← MakeNewExport[old, eti, map, mt];
RETURN[FALSE];
END;
[] ← ProcessExports[bcd, MapExport];
END;
MakeNewExport: PROCEDURE [
old: EXPHandle, eti: EXPIndex, map: Map, mt: ModuleTable]
RETURNS [neweti: EXPIndex] =
BEGIN OPEN data;
i: CARDINAL;
header.nExports ← header.nExports + 1;
neweti ← Table.Allocate[exptype, old.size + SIZE[EXPRecord]];
FOR i IN [0..old.size) DO
etb[neweti].links[i] ← old.links[i];
etb[neweti].links[i].gfi ← mt[map[old.links[i].gfi]].gfi;
ENDLOOP;
etb[neweti].name ← MapName[bcd, old.name];
etb[neweti].file ← MergeFile[bcd, old.file];
etb[neweti].port ← old.port;
etb[neweti].size ← old.size;
IF old.namedInstance THEN
BEGIN
etb[neweti].namedInstance ← TRUE;
EnterNameInTable[
[export[neweti]], MapName[bcd, FindName[bcd, [export[eti]]]]];
END
ELSE etb[neweti].namedInstance ← FALSE;
END;
AddImport: PROCEDURE [link: Link] RETURNS [Link] =
BEGIN OPEN data;
FindImport: PROCEDURE [imp: IMPHandle, iti: IMPIndex] RETURNS [BOOLEAN] =
BEGIN RETURN[link.gfi IN [imp.gfi..imp.gfi + imp.ngfi)]; END;
old: IMPHandle;
iti, newiti: IMPIndex;
oldftb: Table.Base ← LOOPHOLE[bcd + bcd.ftOffset];
olditb: Table.Base ← LOOPHOLE[bcd + bcd.impOffset];
oldssb: NameString ← LOOPHOLE[bcd + bcd.ssOffset];
oldname: SubStringDescriptor;
found: BOOLEAN;
hti: HTIndex;
iti ← ProcessImports[bcd, FindImport].iti;
IF iti = IMPNull THEN RETURN[AddNewImport[link]];
old ← @olditb[iti];
oldname ← [@oldssb.string, old.name, oldssb.size[old.name]];
[found, hti] ← SymbolOps.FindString[@oldname];
IF found THEN
FOR newiti ← FIRST[IMPIndex], newiti + SIZE[IMPRecord] UNTIL newiti =
LOOPHOLE[Table.Bounds[imptype].size] DO
OPEN new: itb[newiti];
IF hti = HtiName[new.name] THEN
BEGIN OPEN oldfile: oldftb[old.file], newfile: ftb[new.file];
oldname.offset ← oldfile.name;
oldname.length ← oldssb.size[oldfile.name];
IF SymbolOps.FindEquivalentString[@oldname].found AND oldfile.version =
newfile.version THEN
BEGIN
IF ~new.namedInstance AND old.namedInstance THEN
BEGIN
new.namedInstance ← TRUE;
EnterNameInTable[
[import[newiti]], MapName[bcd, FindName[bcd, [import[iti]]]]];
END;
link.gfi ← new.gfi + link.gfi - old.gfi;
RETURN[link];
END;
END;
ENDLOOP;
header.nImports ← header.nImports + 1;
newiti ← Table.Allocate[imptype, SIZE[IMPRecord]];
itb[newiti].name ← MapName[bcd, old.name];
itb[newiti].file ← MergeFile[bcd, old.file];
IF old.namedInstance THEN
BEGIN
itb[newiti].namedInstance ← TRUE;
EnterNameInTable[
[import[newiti]], MapName[bcd, FindName[bcd, [import[iti]]]]];
END
ELSE itb[newiti].namedInstance ← FALSE;
itb[newiti].gfi ← GetDummyGfi[itb[newiti].ngfi ← old.ngfi];
itb[newiti].port ← old.port;
link.gfi ← itb[newiti].gfi + link.gfi - old.gfi;
RETURN[link];
END;
AddNewImport: PROCEDURE [link: Link] RETURNS [Link] = {RETURN[UnboundLink]};
MergeConfigTable: PROCEDURE [size: CARDINAL] RETURNS [delta: CARDINAL] =
BEGIN OPEN data;
ConfigMap: PROCEDURE [old: CTHandle, cti: CTIndex] RETURNS [BOOLEAN] =
BEGIN OPEN new: ctb[cti + delta];
i: CARDINAL;
new.name ← MapName[bcd, old.name];
IF old.namedInstance THEN
BEGIN
EnterNameInTable[
[config[cti + delta]], MapName[bcd, FindName[bcd, [config[cti]]]]];
new.namedInstance ← TRUE
END
ELSE new.namedInstance ← FALSE;
new.nControls ← old.nControls;
FOR i IN [0..new.nControls ← old.nControls) DO
new.controls[i] ← old.controls[i] ENDLOOP;
new.file ← IF old.file = FTSelf THEN FTSelf ELSE MergeFile[bcd, old.file];
new.config ← IF old.config = CTNull THEN CTNull ELSE old.config + delta;
RETURN[FALSE];
END;
delta ← LOOPHOLE[Table.Allocate[cttype, size]];
header.nConfigs ← header.nConfigs + bcd.nConfigs;
[] ← ProcessConfigs[bcd, ConfigMap];
RETURN
END;
EnterNameInTable: PROCEDURE [owner: Namee, name: NameRecord] =
BEGIN
nti: NTIndex ← Table.Allocate[nttype, SIZE[NTRecord]];
data.ntb[nti] ← [name, owner];
END;
WhoIsFTSelf: PROCEDURE RETURNS [FTIndex] =
BEGIN OPEN data;
ss: SubStringDescriptor ← [base: name, offset: 0, length: name.length];
n: NameRecord;
IF bcdFile = FTNull THEN
BEGIN
bcdFile ← Table.Allocate[fttype, SIZE[FTRecord]];
n ← EnterName[@ss];
ftb[bcdFile] ← [n, bcd.version];
END;
RETURN[bcdFile];
END;
MergeTypeMap: PROCEDURE [bcd: BcdBase] =
BEGIN OPEN data;
typLimit: TYPIndex = LOOPHOLE[Table.Bounds[typtype].size];
typ: TYPIndex;
oldtypb: Base = LOOPHOLE[bcd + bcd.typOffset];
ScanTypeMap: PROCEDURE [tmh: TMHandle, tmi: TMIndex] RETURNS [BOOLEAN] =
BEGIN
FOR typ ← FIRST[TYPIndex], typ + SIZE[TYPRecord] UNTIL typ = typLimit DO
IF oldtypb[tmh.map] = typb[typ] THEN EXIT;
REPEAT
FINISHED => {
typ ← Table.Allocate[typtype, SIZE[TYPRecord]];
typb[typ] ← oldtypb[tmh.map]};
ENDLOOP;
tmi ← Table.Allocate[tmtype, SIZE[TMRecord]];
tmb[tmi] ← [version: tmh.version, offset: tmh.offset, map: typ];
RETURN[FALSE];
END;
[] ← ProcessTypeMap[bcd, ScanTypeMap];
RETURN
END;
ProcessTypeMap: PROCEDURE [
bcd: BcdBase, proc: PROC [TMHandle, TMIndex] RETURNS [BOOLEAN]]
RETURNS [tmh: TMHandle, tmi: TMIndex] =
BEGIN
tmb: Base = LOOPHOLE[bcd + bcd.tmOffset];
FOR tmi ← FIRST[TMIndex], tmi + SIZE[TMRecord] UNTIL tmi = bcd.tmLimit DO
IF proc[tmh ← @tmb[tmi], tmi] THEN RETURN; ENDLOOP;
RETURN[NIL, TMNull];
END;
MergeBcd: PUBLIC PROCEDURE [
mergee: BcdBase, map: Map, config: ConfigIndex, mt: ModuleTable,
bcdname: STRING] =
BEGIN OPEN data;
BEGIN
ENABLE
Table.Overflow =>
BEGIN ExpandTable[]; RESUME [[table, tablePages*AltoDefs.PageSize]]; END;
bcd ← mergee;
bcdFile ← FTNull;
name ← bcdname;
configOffset ←
IF bcd.nConfigs = 0 THEN 0
ELSE MergeConfigTable[LOOPHOLE[bcd.ctLimit, CARDINAL]];
MergeModuleTable[map, config, mt];
MergeExportTable[map, mt];
MergeTypeMap[mergee];
END;
END;
Size: PUBLIC PROCEDURE RETURNS [size: CARDINAL] =
BEGIN OPEN data.header, BcdDefs, Table;
s: CARDINAL;
size ← SIZE[BCD];
ssOffset ← size;
size ← size + (ssLimit ← Bounds[sstype].size);
ctOffset ← size;
size ← size + (s ← Bounds[cttype].size);
ctLimit ← LOOPHOLE[s, CTIndex];
mtOffset ← size;
size ← size + (s ← Bounds[mttype].size);
mtLimit ← LOOPHOLE[s, MTIndex];
impOffset ← size;
size ← size + (s ← Bounds[imptype].size);
impLimit ← LOOPHOLE[s, IMPIndex];
expOffset ← size;
size ← size + (s ← Bounds[exptype].size);
expLimit ← LOOPHOLE[s, EXPIndex];
evOffset ← size;
size ← size + (s ← Bounds[evtype].size);
evLimit ← LOOPHOLE[s, EVIndex];
sgOffset ← size;
size ← size + (s ← Bounds[sgtype].size);
sgLimit ← LOOPHOLE[s, SGIndex];
ftOffset ← size;
size ← size + (s ← Bounds[fttype].size);
ftLimit ← LOOPHOLE[s, FTIndex];
ntOffset ← size;
size ← size + (s ← Bounds[nttype].size);
ntLimit ← LOOPHOLE[s, NTIndex];
typOffset ← size;
size ← size + (s ← Bounds[typtype].size);
typLimit ← LOOPHOLE[s, TYPIndex];
tmOffset ← size;
size ← size + (s ← Bounds[tmtype].size);
tmLimit ← LOOPHOLE[s, TMIndex];
nPages ← Storage.PagesForWords[size];
nDummies ← GetDummyGfi[0] - firstdummy;
END;
Write: PUBLIC PROCEDURE [movewords: PROCEDURE [POINTER, CARDINAL]] =
BEGIN OPEN BcdDefs;
base: Table.Base;
size: CARDINAL;
movewords[@data.header, SIZE[BCD]];
[base, size] ← Table.Bounds[sstype];
movewords[LOOPHOLE[base], size];
[base, size] ← Table.Bounds[cttype];
movewords[LOOPHOLE[base], size];
[base, size] ← Table.Bounds[mttype];
movewords[LOOPHOLE[base], size];
[base, size] ← Table.Bounds[imptype];
movewords[LOOPHOLE[base], size];
[base, size] ← Table.Bounds[exptype];
movewords[LOOPHOLE[base], size];
[base, size] ← Table.Bounds[evtype];
movewords[LOOPHOLE[base], size];
[base, size] ← Table.Bounds[sgtype];
movewords[LOOPHOLE[base], size];
[base, size] ← Table.Bounds[fttype];
movewords[LOOPHOLE[base], size];
[base, size] ← Table.Bounds[nttype];
movewords[LOOPHOLE[base], size];
[base, size] ← Table.Bounds[typtype];
movewords[LOOPHOLE[base], size];
[base, size] ← Table.Bounds[tmtype];
movewords[LOOPHOLE[base], size];
END;
-- Administrative Procedures
Initialize: PUBLIC PROCEDURE [sizeoftable: CARDINAL, lastrealgfi: GFTIndex] =
BEGIN OPEN data, Table;
net: CARDINAL ← MiscDefs.GetNetworkNumber[];
tableweights: ARRAY [0..BinderNTables) OF CARDINAL ← ALL[1];
data ← Storage.Node[SIZE[MergeData]];
tablePages ← Storage.PagesForWords[sizeoftable];
table ← LOOPHOLE[Storage.Pages[tablePages]];
Create[[table, tablePages*AltoDefs.PageSize], DESCRIPTOR[tableweights]];
AddNotify[Notify];
SymbolOps.Initialize[];
nextGfi ← 1;
MiscDefs.Zero[@data.header, SIZE[BCD]];
header.firstdummy ← nextDummyGfi ← lastrealgfi + 1;
header.versionIdent ← BcdDefs.VersionID;
header.source ← NullName;
header.creator ← ImageDefs.ImageVersion[];
header.version ← VersionStamp[
time: MiscDefs.CurrentTime[], net: net,
host: OsStaticDefs.OsStatics.SerialNumber];
header.definitions ← FALSE;
expandedtable ← FALSE;
RETURN
END;
Finalize: PUBLIC PROCEDURE =
BEGIN
SymbolOps.Finalize[];
Table.DropNotify[Notify];
Table.Destroy[];
IF data.expandedtable THEN
BEGIN OPEN SegmentDefs;
Unlock[data.tableSegment];
DeleteFileSegment[data.tableSegment]
END
ELSE Storage.FreePages[LOOPHOLE[data.table]];
Storage.Free[data];
RETURN
END;
ExpandTable: PROCEDURE =
BEGIN OPEN SegmentDefs, data;
IF ~expandedtable THEN
BEGIN
tableSegment ← NewFileSegment[
NewFile["swatee"L, Read + Write + Append], 1, tablePages, Read + Write];
ChangeDataToFileSegment[VMtoDataSegment[LOOPHOLE[table]], tableSegment];
expandedtable ← TRUE;
END;
Unlock[tableSegment];
SwapOut[tableSegment];
MoveFileSegment[tableSegment, DefaultBase, tablePages ← tablePages + 1];
MakeSwappedIn[tableSegment, DefaultMDSBase, HardDown];
table ← LOOPHOLE[FileSegmentAddress[tableSegment]];
END;
END.