Pass4B.mesa
Copyright Ó 1985, 1986, 1987, 1988, 1991 by Xerox Corporation. All rights reserved.
Satterthwaite, June 18, 1986 12:33:20 pm PDT
Russ Atkinson (RRA) June 21, 1989 1:40:46 pm PDT
DIRECTORY
Alloc USING [Top],
CompilerUtil USING [AppendMobPair, AppendMobString, AppendMobUnits, EndMob, FileByteIndex, FillMobPage, ReadMobIndex, ReadMobOffset, RTTableOut, StartMob, UpdateMobUnits],
ConstArith USING [FromInt],
ConvertUnsafe USING [AppendRope, EqualSubStrings, SubString],
MimData USING [base, codeSeg, compilerVersion, fixupLoc, importCtx, interface, linkCount, mainCtx, matched, mobSeg, moduleCtx, monitored, mtRoot, mtRootSize, nBodies, nSigCodes, objectVersion, ownSymbols, pattern, source, switches, symSeg, table, tC0, tC1, textIndex],
MimosaCopier USING [FreeSymbolTable, GetSymbolTable, MapSymbols, UnmapSymbols],
MimosaEvents USING [Callback, RegisterSet, Trigger],
MimosaLog USING [ErrorN, ErrorSei, ErrorType, WarningRope, WarningSei, WarningSubString],
MimP4 USING [AssignEntries, Attr, Bias, Body, DeclItem, DefaultBasicOps, ExpANotify, ExpBNotify, ExpCNotify, ExpInit, ExpReset, ImplicitRecord, LayoutNotify, MatchMob, OperandStruct, OpsNotify, ownGfi, StmtNotify, TypeExp, VarInit, voidAttr],
MimZones USING [permUZ, tempUZ, tempZone],
MobDefs USING [Mob, MobBase, CodeDesc, CTIndex, CTNull, EVHandle, EVIndex, EVNull, EVRecord, EXPIndex, EXPLink, EXPRecord, FPIndex, FTIndex, FTRecord, FTSelf, IMPIndex, IMPRecord, LFIndex, LFNull, Link, LinkOffset, ModuleIndex, MTHandle, MTIndex, MTRecord, Namee, NameRecord, NameString, NTIndex, NTRecord, nullLink, NullName, ProcIndex, procLimit, RefLitIndex, RFIndex, RFNull, SGIndex, SGRecord, SPIndex, TFIndex, TFNull, TMIndex, TMRecord, TypeIndex, TYPIndex, TYPRecord, varLimit, VersionID],
OSMiscOps USING [mobFormat, bytesPerFilePage],
Pass4Parms USING [links],
Pass4ToPass5 USING [ImportsVisitor, ExportsVisitor],
RefText USING [Append],
Rope USING [Length, ROPE],
SourceMap USING [Loc],
Symbols USING [Base, bodyType, BTIndex, BTNull, CBTIndex, CSEIndex, CTXIndex, CTXNull, ctxType, IncludedCTXIndex, ISEIndex, ISENull, Linkage, MDIndex, MDNull, MDRecord, mdType, Name, nullFileIndex, nullName, OwnMdi, RecordSEIndex, RecordSENull, RootBti, seType, Type, typeANY, typeTYPE],
SymbolOps,
SymbolTable USING [Base],
SymbolTablePrivate USING [SymbolTableBaseRep],
SymLiteralOps USING [DescribeRefLits, DescribeTypes, EnumerateRefLits, EnumerateTypes, RefLitsVisitor, TypeIndex, TypesVisitor, UTypeId],
Target: TYPE MachineParms USING [bitsPerAU],
Tree USING [Base, Index, Link, nullIndex, Scan, treeType],
TreeOps USING [FreeNode, GetNode, GetSe, GetTag, ListLength, NthSon, OpName, ScanList, ToLoc],
Types USING [Assignable, Equivalent, Handle],
TypeStrings USING [Create, TypeString];
Pass4B: PROGRAM
IMPORTS Alloc, CompilerUtil, ConstArith, ConvertUnsafe, MimData, MimosaCopier, MimosaEvents, MimosaLog, MimP4, MimZones, OSMiscOps, RefText, Rope, SymbolOps, SymLiteralOps, TreeOps, Types, TypeStrings
EXPORTS CompilerUtil, MimP4, Pass4ToPass5, SymbolTable = {
OPEN Symbols;
STB: TYPE = REF SymbolTableBaseRep;
SymbolTableBaseRep: PUBLIC TYPE = SymbolTablePrivate.SymbolTableBaseRep;
tb: Tree.Base; -- tree base address (local copy)
seb: Symbols.Base; -- se table base address (local copy)
ctxb: Symbols.Base; -- context table base address (local copy)
mdb: Symbols.Base; -- body table base address (local copy)
bb: Symbols.Base; -- body table base address (local copy)
Exported variables
tTRUE: PUBLIC Tree.Link;
tFALSE: PUBLIC Tree.Link;
intermediate result bookkeeping
returnRecord: PUBLIC RecordSEIndex;
resumeRecord: PUBLIC RecordSEIndex;
implicit: PUBLIC MimP4.ImplicitRecord;
nullBias: PUBLIC MimP4.Bias; -- constant bias of zero
lockNode: PUBLIC Tree.Index;
resident: PUBLIC BOOL;
FileByteIndex: TYPE = CompilerUtil.FileByteIndex;
also see ObjectOut.mesa
Formerly in Pass4
P4Notify: MimosaEvents.Callback = {
called by allocator whenever table area is repacked
SELECT class FROM
zoneReset, cleanup => {
typeMap ¬ NIL;
nStringREFTEXT ¬ NIL;
nString ¬ NIL;
Reset[];
};
relocate => {
tb ¬ MimData.base[Tree.treeType];
seb ¬ MimData.base[seType];
ctxb ¬ MimData.base[ctxType];
mdb ¬ MimData.base[mdType];
bb ¬ MimData.base[bodyType];
MimP4.LayoutNotify[MimData.base];
MimP4.StmtNotify[MimData.base];
MimP4.OpsNotify[MimData.base];
MimP4.ExpANotify[MimData.base];
MimP4.ExpBNotify[MimData.base];
MimP4.ExpCNotify[MimData.base];
};
ENDCASE;
};
P4Unit: PUBLIC PROC [unit: Tree.Link] = {
EXPORTED to CompilerUtil
node: Tree.Index;
tTRUE ¬ MimData.tC1;
tFALSE ¬ MimData.tC0;
implicit.type ¬ typeANY;
implicit.lb ¬ implicit.ub ¬ nullBias ¬ implicit.bias ¬ ConstArith.FromInt[0];
implicit.attr ¬ MimP4.voidAttr;
implicit.sef ¬ TRUE;
resumeRecord ¬ RecordSENull;
MimP4.ExpInit[];
node ¬ TreeOps.GetNode[unit];
Module[node ! MimP4.VarInit => {RESUME [TRUE]}];
MimP4.ExpReset[];
TreeOps.FreeNode[node];
};
Module: PROC [node: Tree.Index] = {
subNode: Tree.Index = TreeOps.GetNode[tb[node].son[6]];
saveIndex: SourceMap.Loc = MimData.textIndex;
MimData.textIndex ¬ TreeOps.ToLoc[tb[subNode].info];
InitMob[tb[subNode].son[1]];
MimData.textIndex ¬ TreeOps.ToLoc[tb[node].info];
lockNode ¬ Tree.nullIndex;
IF MimData.monitored THEN {
lockNode ¬ TreeOps.GetNode[tb[node].son[5]];
IF tb[lockNode].name = lambda THEN {
son1: Tree.Link ¬ tb[lockNode].son[1];
IF TreeOps.OpName[son1] = decl THEN
There is a type expression that needs processing
MimP4.TypeExp[TreeOps.NthSon[son1, 2]];
};
};
resident ¬ tb[node].attr1;
Reset[];
Just to keep things clean
MimP4.AssignEntries[Symbols.RootBti];
AssignImports[tb[node].son[2]];
MimP4.DeclItem[tb[node].son[6]];
MimP4.Body[Symbols.RootBti];
TreeOps.ScanList[tb[node].son[1], DirectoryItem];
formerly: ProcessDirectory[tb[node].son[1]];
ProcessImports[tb[node].son[2]];
ProcessExports[tb[node].son[3]];
IF MimData.interface THEN {
def: ISEIndex = ctxb[MimData.moduleCtx].seList;
defType: CSEIndex = SymbolOps.UnderType[SymbolOps.own, seb[def].idType];
WITH d: seb[defType] SELECT FROM
definition => {
Scan the context to determine the necessary size of the interface record
slots: CARDINAL ¬ 0;
FOR sei: ISEIndex ¬ ctxb[d.defCtx].seList, SymbolOps.NextSe[SymbolOps.own, sei]
WHILE sei # ISENull DO
mode: Linkage = SymbolOps.LinkMode[SymbolOps.own, sei];
IF mode # manifest THEN slots ¬ slots + 1;
ENDLOOP;
d.slots ¬ slots;
This is passed on as the number of slots in the interface record
};
ENDCASE => ERROR;
};
FinishMob[tb[subNode].son[1]];
IF MimData.matched THEN MimData.matched ¬ MimP4.MatchMob[];
MimData.textIndex ¬ saveIndex;
};
Global types, constants & variables
bitsPerAU: CARDINAL = Target.bitsPerAU;
mobHeader: MobDefs.MobBase;
initialized in START code, below
mobIndex: FileByteIndex;
mtIndex: FileByteIndex;
permUZ: UNCOUNTED ZONE = MimZones.permUZ;
tempUZ: UNCOUNTED ZONE = MimZones.tempUZ;
z: ZONE = MimZones.tempZone;
pageBytes: NAT = OSMiscOps.bytesPerFilePage;
nString: MobDefs.NameString;
nStringREFTEXT: REF TEXT;
NOTE SHARING with nString
ASSUME bitwise compatibility with LONG STRING & REF TEXT
firstPorted: MDIndex = OwnMdi + MDRecord.SIZE;
lastPorted: MDIndex ¬ firstPorted; -- im/exported files in [firstPorted..lastPorted)
evList: MobDefs.EVHandle ¬ NIL; -- initialized in START code, below
evListMax: NAT ¬ 60; -- the # of elements allocated for evList
protoMTRecord: MobDefs.MTHandle; -- initialized in START code, below
ImportList: TYPE = REF ImportListRep;
ImportListRep: TYPE = RECORD [
mdi: Symbols.MDIndex,
formal: Symbols.Name,
irSei: ISEIndex,
irType: CSEIndex,
src: ISEIndex,
link: MobDefs.Link,
next: ImportList ¬ NIL
];
importHead: ImportList ¬ NIL;
importTail: ImportList ¬ NIL;
ExportList: TYPE = REF ExportListRep;
ExportListRep: TYPE = RECORD [
mdi: Symbols.MDIndex,
formal: Symbols.Name,
irSei: ISEIndex,
irType: CSEIndex,
ts: TypeStrings.TypeString,
src: ISEIndex,
link: MobDefs.EXPLink,
next: ExportList ¬ NIL
];
exportHead: ExportList ¬ NIL;
exportTail: ExportList ¬ NIL;
Service routines
ModuleIndex: TYPE = MobDefs.ModuleIndex;
ProcIndex: TYPE = MobDefs.ProcIndex;
procLimit: CARDINAL = MobDefs.procLimit;
varLimit: CARDINAL = MobDefs.varLimit;
MobLink: TYPE = MobDefs.Link;
ownGfi: ModuleIndex = MimP4.ownGfi;
MakeEPLink: PUBLIC PROC [ep: CARDINAL, gfi: ModuleIndex] RETURNS [MobLink] = {
RETURN [[tag: proc, offset: ep MOD procLimit, modIndex: gfi + ep/procLimit]];
};
MakeFrameLink: PROC [ep: CARDINAL, gfi: ModuleIndex] RETURNS [MobLink] = INLINE {
RETURN [[tag: var, offset: ep MOD varLimit, modIndex: gfi + ep/varLimit]];
};
MakeTypeLink: PROC [index: MobDefs.TYPIndex] RETURNS [MobLink] = INLINE {
offset: CARD ¬ LOOPHOLE[index, CARD] / MobDefs.TYPRecord.SIZE;
IF offset >= MobDefs.LinkOffset.LAST THEN ERROR;
RRA: How the hell did we get so many?
RETURN [[tag: type, offset: offset]];
};
MdiForCtx: PROC [ctx: CTXIndex] RETURNS [MDIndex] = INLINE {
WITH c: ctxb[ctx] SELECT FROM
included => RETURN [c.module];
imported => RETURN [ctxb[c.includeLink].module];
ENDCASE => RETURN [OwnMdi]
};
PortedCtx: PROC [ctx: CTXIndex] RETURNS [MobDefs.FTIndex] = INLINE {
RETURN [PortedFile[MdiForCtx[ctx]]];
};
PortedFile: PROC [mdi: MDIndex] RETURNS [fti: MobDefs.FTIndex ¬ MobDefs.FTSelf] = {
IF mdi # OwnMdi THEN {
n: CARDINAL;
IF mdi IN [firstPorted .. lastPorted)
THEN
n ¬ LOOPHOLE[mdi-firstPorted, CARD]/MDRecord.SIZE
ELSE {
n ¬ LOOPHOLE[lastPorted-firstPorted, CARD]/MDRecord.SIZE;
{
Formerly SwapMdi
mdi1: MDIndex ¬ mdi;
mdi2: MDIndex ¬ lastPorted;
IF mdi1 # mdi2 THEN {
t: MDRecord;
FOR ctx: IncludedCTXIndex ¬ mdb[mdi1].ctx, ctxb[ctx].chain
UNTIL ctx = CTXNull DO
ctxb[ctx].module ¬ mdi2;
ENDLOOP;
FOR ctx: IncludedCTXIndex ¬ mdb[mdi2].ctx, ctxb[ctx].chain
UNTIL ctx = CTXNull DO
ctxb[ctx].module ¬ mdi1;
ENDLOOP;
t ¬ mdb[mdi1];
mdb[mdi1] ¬ mdb[mdi2];
mdb[mdi2] ¬ t;
}
};
lastPorted ¬ lastPorted + MDRecord.SIZE;
};
fti ¬ MobDefs.FTIndex.FIRST + n*MobDefs.FTRecord.SIZE;
};
};
EnterId: PROC [id: ConvertUnsafe.SubString, ignoreCase: BOOL]
RETURNS [MobDefs.NameRecord] = {
i: CARDINAL ¬ 0;
s: ConvertUnsafe.SubString;
s.base ¬ LOOPHOLE[nString];
assume bitwise compatibility with LONG STRING & REF TEXT
UNTIL i = nString.length DO
s.offset ¬ i+1;
s.length ¬ nString[i].ORD;
IF id.EqualSubStrings[s2: s, case: ~ignoreCase] THEN RETURN [[i]];
i ¬ i + s.length+1;
REPEAT
FINISHED => {
len: [0..255) = id.length;
nLen: NAT ¬ nString.length+(len+1);
IF nLen > nString.maxLength THEN {
tLen: NAT ¬ nString.maxLength + MAX[(len+1), 512];
t: REF TEXT ¬ z.NEW[TEXT[tLen]];
t ¬ RefText.Append[t, nStringREFTEXT];
z.FREE[@nStringREFTEXT];
nStringREFTEXT ¬ t;
nString ¬ LOOPHOLE[nStringREFTEXT, MobDefs.NameString];
};
nString[i] ¬ VAL[len];
FOR j: CARDINAL IN [0..len) DO
nString[i+1+j] ¬ id.base[id.offset+j];
ENDLOOP;
nString.length ¬ i + len + 1;
};
ENDLOOP;
RETURN [[i]];
};
EnterSymbolId: PROC [sei: ISEIndex] RETURNS [MobDefs.NameRecord] = {
s: ConvertUnsafe.SubString = SymbolOps.SubStringForName[SymbolOps.own, seb[sei].hash];
RETURN [EnterId[s, FALSE]];
};
EnterFileId: PROC [mdi: MDIndex] RETURNS [MobDefs.NameRecord] = {
ext: LONG STRING = ".mob";
extLength: CARDINAL = ext.length;
s: ConvertUnsafe.SubString ¬ SymbolOps.SubStringForName[SymbolOps.own, mdb[mdi].fileId];
IF s.base[s.offset+s.length-1] = '. THEN s.length ¬ s.length - 1;
IF s.length > extLength THEN {
s1: ConvertUnsafe.SubString ¬ [
base: s.base, offset: s.offset+s.length-extLength, length: extLength];
s2: ConvertUnsafe.SubString ¬ [base: ext, offset: 0, length: extLength];
IF ConvertUnsafe.EqualSubStrings[s1: s1, s2: s2, case: FALSE] THEN
s.length ¬ s.length - extLength;
};
RETURN [EnterId[s, TRUE]];
};
Enumerating the current exports (to later passes)
Reset: PUBLIC PROC = {
WHILE importHead # NIL DO
lag: ImportList ¬ importHead;
importHead ¬ importHead.next;
z.FREE[@lag];
ENDLOOP;
importHead ¬ importTail ¬ NIL;
FOR each: ExportList ¬ exportHead, each.next WHILE each # NIL DO
IF each.ts # NIL THEN tempUZ.FREE[@each.ts];
ENDLOOP;
WHILE exportHead # NIL DO
lag: ExportList ¬ exportHead;
exportHead ¬ exportHead.next;
z.FREE[@lag];
ENDLOOP;
exportHead ¬ exportTail ¬ NIL;
};
VisitImports: PUBLIC PROC [visitor: Pass4ToPass5.ImportsVisitor] = {
FOR each: ImportList ¬ importHead, each.next WHILE each # NIL DO
visitor[each.mdi, each.formal, each.irSei, each.irType, each.src, each.link];
ENDLOOP;
};
VisitExports: PUBLIC PROC [visitor: Pass4ToPass5.ExportsVisitor] = {
FOR each: ExportList ¬ exportHead, each.next WHILE each # NIL DO
visitor[each.mdi, each.formal, each.irSei, each.irType, each.ts, each.src, each.link];
ENDLOOP;
};
Processing directory entries (to file table)
DirectoryItem: Tree.Scan = {
node: Tree.Index = TreeOps.GetNode[t];
sei: ISEIndex = TreeOps.GetSe[tb[node].son[1]];
type: CSEIndex = SymbolOps.UnderType[SymbolOps.own, seb[sei].idType];
WITH t: seb[type] SELECT FROM
definition => [] ¬ PortedCtx[t.defCtx];
transfer => {
bti: BTIndex = SymbolOps.DecodeBti[seb[sei].idInfo];
IF bti # BTNull THEN [] ¬ PortedCtx[bb[bti].localCtx];
};
ENDCASE;
};
Relocating imported control links
AssignImports: PUBLIC Tree.Scan = {
gfi: ModuleIndex ¬ mobHeader.firstdummy ¬ ownGfi + 1;
RRA: this is obsolete, so we should get rid of it some day
saveIndex: SourceMap.Loc = MimData.textIndex;
MimData.mtRoot.modIndex ¬ ownGfi;
MimData.mtRoot.entries ¬ MAX[MimData.nBodies, MimData.nSigCodes];
FOR sei: ISEIndex ¬ SymbolOps.FirstCtxSe[SymbolOps.own, MimData.importCtx], SymbolOps.NextSe[SymbolOps.own, sei] UNTIL sei = ISENull DO
node: Tree.Index = SymbolOps.DecodeTreeIndex[seb[sei].idValue];
id: ISEIndex ¬ sei;
formal: Symbols.Name ¬ seb[sei].hash;
type: CSEIndex = SymbolOps.UnderType[SymbolOps.own, seb[sei].idType];
new: ImportList ¬ NIL;
IF node # Tree.nullIndex THEN {
fSon: Tree.Link = tb[node].son[1];
MimData.textIndex ¬ TreeOps.ToLoc[tb[node].info];
WITH e: fSon SELECT TreeOps.GetTag[fSon] FROM
hash => formal ¬ e.index;
symbol => formal ¬ seb[e.index].hash;
ENDCASE;
};
WITH se: seb[type] SELECT FROM
definition => {
slots: CARDINAL = se.slots;
ctx: CTXIndex = se.defCtx;
IF ctxb[ctx].seList = ISENull THEN MimosaLog.WarningSei[unusedImport, sei];
IF ~MimData.interface THEN {
relocate the imports
mdi: MDIndex ¬ MdiForCtx[ctx];
FOR sei: ISEIndex ¬ SymbolOps.FirstCtxSe[SymbolOps.own, ctx], SymbolOps.NextSe[SymbolOps.own, sei] UNTIL sei = ISENull DO
IF ~seb[sei].constant THEN {
ut: CSEIndex = SymbolOps.UnderType[SymbolOps.own, seb[sei].idType];
epN: CARDINAL = SymbolOps.DecodeCard[seb[sei].idValue];
link: MobLink ¬ MakeEPLink[epN, gfi];
SELECT seb[ut].typeTag FROM
ref => link.tag ¬ var;
transfer => link.tag ¬ proc;
ENDCASE => link.tag ¬ other;
seb[sei].idValue ¬ SymbolOps.EncodeLink[link];
new ¬ z.NEW[ImportListRep ¬ [
mdi: mdi,
formal: formal,
irSei: id,
irType: type,
src: sei,
link: link]];
IF importTail = NIL THEN importHead ¬ new ELSE importTail.next ¬ new;
importTail ¬ new;
};
ENDLOOP;
};
seb[sei].idInfo ¬ SymbolOps.EncodeCard[slots];
gfi ¬ gfi + 1;
};
ref => {
IF ~MimData.interface THEN {
link: MobLink ¬ MakeEPLink[0, gfi];
seb[sei].idValue ¬ SymbolOps.EncodeLink[link];
new ¬ z.NEW[ImportListRep ¬ [
mdi: MDNull,
formal: formal,
irSei: id,
irType: type,
src: sei,
link: link]];
IF importTail = NIL THEN importHead ¬ new ELSE importTail.next ¬ new;
importTail ¬ new;
};
gfi ¬ gfi + 1;
};
ENDCASE;
seb[sei].mark4 ¬ TRUE;
ENDLOOP;
mobHeader.nDummies ¬ gfi - mobHeader.firstdummy;
MimData.textIndex ¬ saveIndex;
};
Writing frame fragments (link fragment written by Pass4L)
ProcessSymLiterals: PUBLIC PROC = {
rfOffset: CARD = CompilerUtil.ReadMobOffset[];
mobHeader.rfOffset.units ¬ rfOffset;
mobHeader.lfLimit ¬ MobDefs.LFIndex.FIRST + (rfOffset - mobHeader.lfOffset.units);
IF ~MimData.interface THEN {
rfi: MobDefs.RefLitIndex ¬ [0];
length: CARD ¬ 0;
offset: CARD ¬ 0;
AppendLitItem: SymLiteralOps.RefLitsVisitor = {
CompilerUtil.AppendMobUnits[@rfi, MobDefs.RefLitIndex.SIZE];
rfi ¬ [rfi + 1];
};
[offset, length] ¬ SymLiteralOps.DescribeRefLits[];
IF length # 0 THEN {
MimData.mtRoot.refLiterals ¬ MobDefs.RFIndex.FIRST;
CompilerUtil.AppendMobPair[offset, length];
SymLiteralOps.EnumerateRefLits[AppendLitItem];
}
};
{
tfOffset: CARD = CompilerUtil.ReadMobOffset[];
mobHeader.tfOffset.units ¬ tfOffset;
mobHeader.rfLimit ¬ MobDefs.RFIndex.FIRST + (tfOffset-rfOffset);
IF NOT MimData.interface THEN {
length: CARD ¬ 0;
offset: CARD ¬ 0;
tfi: MobDefs.TypeIndex ¬ [0];
AppendTypeIndex: SymLiteralOps.TypesVisitor = {
CompilerUtil.AppendMobUnits[@tfi, MobDefs.TypeIndex.SIZE];
tfi ¬ [tfi + 1];
};
[offset, length] ¬ SymLiteralOps.DescribeTypes[];
IF length # 0 THEN {
MimData.mtRoot.types ¬ MobDefs.TFIndex.FIRST;
CompilerUtil.AppendMobPair[offset, length];
SymLiteralOps.EnumerateTypes[AppendTypeIndex];
}
};
mobHeader.tfLimit ¬ MobDefs.TFIndex.FIRST + (CompilerUtil.ReadMobOffset[]-tfOffset);
};
};
Writing import records
ProcessImports: Tree.Scan = {
ProcessSei: PROC [sei, tSei: ISEIndex, implicit: BOOL] = {
type: CSEIndex = SymbolOps.UnderType[SymbolOps.own, seb[sei].idType];
entry: MobDefs.IMPRecord ¬ [
name: EnterSymbolId[tSei],
port: interface,
namedInstance: seb[sei].hash # seb[tSei].hash,
modIndex: nextSlot,
offset: 0];
WITH t: seb[type] SELECT FROM
definition => {
entry.file ¬ PortedCtx[t.defCtx];
seb[sei].idValue ¬ SymbolOps.EncodeCard[nextSlot];
RRA: the idValue field appears to hold the assigned slot in the local world
nextSlot ¬ nextSlot + 1;
};
ref => {
rType: RecordSEIndex =
LOOPHOLE[SymbolOps.UnderType[SymbolOps.own, t.refType]];
entry.port ¬ module;
entry.file ¬ PortedCtx[seb[rType].fieldCtx];
nextSlot ¬ nextSlot + 1;
};
ENDCASE;
nImports ¬ nImports + 1;
IF entry.namedInstance THEN anyNamed ¬ TRUE;
CompilerUtil.AppendMobUnits[@entry, MobDefs.IMPRecord.SIZE];
};
ImportItem: Tree.Scan = {
node: Tree.Index = TreeOps.GetNode[t];
ProcessSei[sei, TreeOps.GetSe[tb[node].son[2]], FALSE];
sei ¬ SymbolOps.NextSe[SymbolOps.own, sei];
};
NameItem: Tree.Scan = {
node: Tree.Index = TreeOps.GetNode[t];
sei: ISEIndex = TreeOps.GetSe[tb[node].son[1]];
tSei: ISEIndex = TreeOps.GetSe[tb[node].son[2]];
entry: MobDefs.NTRecord;
IF seb[sei].hash # seb[tSei].hash THEN {
entry ¬ [name: EnterSymbolId[sei], item: MobDefs.Namee[0, 0, import[impi]]];
CompilerUtil.AppendMobUnits[@entry, MobDefs.NTRecord.SIZE];
};
impi ¬ impi + MobDefs.IMPRecord.SIZE;
};
units: CARD ¬ mobHeader.impOffset.units ¬ CompilerUtil.ReadMobOffset[];
nImports: CARDINAL ¬ 0;
impi: MobDefs.IMPIndex ¬ MobDefs.IMPIndex.FIRST;
nextSlot: CARDINAL ¬ mobHeader.firstdummy;
N.B. nextSlot must be regenerated to match AssignImports
anyNamed: BOOL ¬ FALSE;
sei: ISEIndex ¬ SymbolOps.FirstCtxSe[SymbolOps.own, MimData.importCtx];
updated by ImportItem
TreeOps.ScanList[t, ImportItem];
UNTIL sei = ISENull DO
ProcessSei[sei, sei, TRUE];
sei ¬ SymbolOps.NextSe[SymbolOps.own, sei];
ENDLOOP;
mobHeader.nImports ¬ nImports;
mobHeader.impLimit ¬ MobDefs.IMPIndex.FIRST + (CompilerUtil.ReadMobOffset[]-units);
mobHeader.ntOffset.units ¬ units ¬ CompilerUtil.ReadMobOffset[];
IF anyNamed THEN TreeOps.ScanList[t, NameItem];
matches importCtx prefix
mobHeader.ntLimit ¬ MobDefs.NTIndex.FIRST + (CompilerUtil.ReadMobOffset[]-units);
};
Writing export records
EnterEVOffset: PROC [offset: CARDINAL] RETURNS [CARDINAL] = {
index: CARDINAL ¬ 0;
IF offset # 0 THEN {
FOR i: CARDINAL IN [1 .. evList.length] DO
IF offset = evList.offsets[i] THEN RETURN [i];
ENDLOOP;
index ¬ evList.length + 1;
IF index >= evListMax THEN {
Need to expand the evList
newMax: NAT = evListMax + MIN[evListMax, 1024];
new: MobDefs.EVHandle = permUZ.NEW[MobDefs.EVRecord[newMax]];
FOR i: NAT IN [1 .. evList.length] DO new.offsets[i] ¬ evList.offsets[i]; ENDLOOP;
new.pad ¬ evList.pad;
permUZ.FREE[@evList];
evList ¬ new;
evListMax ¬ newMax;
};
evList.offsets[index] ¬ offset;
evList.length ¬ index;
};
RETURN [index];
};
TypeMap: TYPE = RECORD [SEQUENCE length: CARDINAL OF TypeMapEntry];
TypeMapEntry: TYPE = RECORD [opaque: MobDefs.TMRecord, concrete: MobDefs.TYPRecord];
typeMap: REF TypeMap ¬ NIL;
mapIndex: CARDINAL ¬ 0;
typeIndex: MobDefs.TYPIndex ¬ MobDefs.TYPIndex.FIRST;
EnterType: PROC [mdi: MDIndex, offset: CARDINAL, sei: ISEIndex]
RETURNS [typeId: MobDefs.TYPIndex] = {
entry: MobDefs.TYPRecord = MakeTypeId[sei];
IF typeMap = NIL OR mapIndex >= typeMap.length THEN AdjustTypeMap[8];
FOR i: CARDINAL IN [0..mapIndex) DO
IF typeMap[i].concrete = entry THEN GO TO matched;
REPEAT
matched => typeId ¬ typeMap[i].opaque.map;
FINISHED => {typeId ¬ typeIndex; typeIndex ¬ typeIndex + MobDefs.TYPRecord.SIZE};
ENDLOOP;
typeMap[mapIndex] ¬ [
opaque: [version: mdb[mdi].stamp, offset: offset, map: typeId],
concrete: entry];
mapIndex ¬ mapIndex + 1;
};
MakeTypeId: PROC [id: ISEIndex] RETURNS [MobDefs.TYPRecord] = {
sei: ISEIndex ¬ id;
DO
next: Type = SymbolOps.DecodeType[seb[sei].idInfo];
WITH seb[next] SELECT FROM
id => sei ¬ LOOPHOLE[next];
ENDCASE => {
mdi: MDIndex = MdiForCtx[seb[sei].idCtx];
RETURN [[version: mdb[mdi].stamp, id: SymbolOps.DecodeInt[seb[sei].idValue]]];
};
ENDLOOP;
};
AdjustTypeMap: PROC [delta: CARDINAL] = {
oldN: CARDINAL = IF typeMap = NIL THEN 0 ELSE typeMap.length;
newMap: REF TypeMap = z.NEW[TypeMap[oldN+delta]];
FOR i: CARDINAL IN [0 .. oldN) DO newMap[i] ¬ typeMap[i] ENDLOOP;
z.FREE[@typeMap];
typeMap ¬ newMap;
};
WriteTypeTable: PROC = {
next: MobDefs.TYPIndex ¬ MobDefs.TYPIndex.FIRST;
offset: CARD ¬ CompilerUtil.ReadMobOffset[];
mobHeader.typOffset.units ¬ offset;
FOR i: CARDINAL IN [0 .. mapIndex) DO
FOR j: CARDINAL IN [0..i) DO
IF typeMap[i].opaque.map = typeMap[j].opaque.map THEN EXIT
REPEAT
FINISHED => {
CompilerUtil.AppendMobUnits[@typeMap[i].concrete, MobDefs.TYPRecord.SIZE];
next ¬ next + MobDefs.TYPRecord.SIZE};
ENDLOOP;
ENDLOOP;
mobHeader.typLimit ¬
MobDefs.TYPIndex.FIRST + CARDINAL[CompilerUtil.ReadMobOffset[]-offset];
offset ¬ CompilerUtil.ReadMobOffset[];
mobHeader.tmOffset.units ¬ offset;
FOR i: CARDINAL IN [0 .. mapIndex) DO
CompilerUtil.AppendMobUnits[@typeMap[i].opaque, MobDefs.TMRecord.SIZE];
ENDLOOP;
mobHeader.tmLimit ¬ MobDefs.TMIndex.FIRST + (CompilerUtil.ReadMobOffset[]-offset);
};
ExportItem: Tree.Scan = {
node: Tree.Index = TreeOps.GetNode[t];
saveIndex: SourceMap.Loc = MimData.textIndex;
son1: Tree.Link = tb[node].son[1];
son2: Tree.Link = tb[node].son[2];
expType: CSEIndex = MimP4.OperandStruct[son2, FALSE];
MimData.textIndex ¬ TreeOps.ToLoc[tb[node].info];
WITH se: seb[expType] SELECT FROM
definition => {
id: ISEIndex = TreeOps.GetSe[son2];
ctx: IncludedCTXIndex = IF ctxb[se.defCtx].ctxType = included THEN LOOPHOLE[se.defCtx] ELSE ERROR;
mdi: MDIndex = ctxb[ctx].module;
iBase: STB = MimosaCopier.GetSymbolTable[mdi];
IF iBase # NIL THEN {
expHeader: LONG POINTER TO MobDefs.EXPRecord ¬ NIL;
size: NAT ¬ 0;
epN: CARDINAL ¬ 0;
typeExported: BOOL ¬ FALSE;
used: BOOL ¬ FALSE;
formal: Symbols.Name ¬ nullName;
WITH e: son1 SELECT TreeOps.GetTag[son1] FROM
hash => formal ¬ e.index;
symbol => formal ¬ seb[e.index].hash;
ENDCASE;
FOR iSei: ISEIndex ¬ SymbolOps.FirstCtxSe[iBase, ctxb[ctx].map], SymbolOps.NextSe[iBase, iSei]
UNTIL iSei = ISENull DO
SELECT SymbolOps.LinkMode[iBase, iSei] FROM
val, ref => size ¬ size + 1;
type => {typeExported ¬ TRUE; size ¬ size + 1};
ENDCASE;
ENDLOOP;
expHeader ¬ permUZ.NEW[MobDefs.EXPRecord[size]];
expHeader.name ¬ EnterSymbolId[id];
expHeader.port ¬ interface;
expHeader.namedInstance ¬ FALSE;
expHeader.typeExported ¬ FALSE;
expHeader.file ¬ PortedCtx[ctx];
FOR iSei: ISEIndex ¬ SymbolOps.FirstCtxSe[iBase, ctxb[ctx].map], SymbolOps.NextSe[iBase, iSei] UNTIL iSei = ISENull DO
mode: Linkage = SymbolOps.LinkMode[iBase, iSei];
link: MobLink ¬ MobDefs.nullLink;
destOffset: MobDefs.LinkOffset ¬ epN;
RRA: for now we leave these records indexed directly by the interface record offset. However, the definitions support a better encoding!
expLink: MobDefs.EXPLink ¬ [to: destOffset, from: link];
iTarget: Type = iBase.seb[iSei].idType;
iType: CSEIndex = SymbolOps.UnderType[iBase, iTarget];
sei: ISEIndex ¬ ISENull;
ss: ConvertUnsafe.SubString
= SymbolOps.SubStringForName[iBase, iBase.seb[iSei].hash];
name: Name ¬ SymbolOps.FindString[SymbolOps.own, ss];
IF name # nullName THEN {
sei ¬ SymbolOps.SearchContext[SymbolOps.own, name, MimData.mainCtx];
IF sei = ISENull THEN
sei ¬ SymbolOps.SearchContext[SymbolOps.own, name, MimData.moduleCtx];
};
IF sei # ISENull THEN {
public: BOOL = seb[sei].public;
type: CSEIndex = SymbolOps.UnderType[SymbolOps.own, seb[sei].idType];
warnPrivate: BOOL ¬ NOT public AND seb[sei].idCtx = MimData.mainCtx;
SELECT mode FROM
$val => {
SELECT TRUE FROM
warnPrivate => {
MimosaLog.WarningSei[privateExport, sei];
GO TO noValue;
};
seb[type].typeTag = definition => {
Just in case the interface name collides with an exported item
GO TO noValue;
};
NOT Types.Assignable[[iBase, iType], [MimData.ownSymbols, type]] => {
MimosaLog.ErrorType[exportClash, [symbol[sei]], [iBase, iTarget]];
GO TO noValue;
};
NOT seb[sei].constant, seb[sei].extended => {
MimosaLog.ErrorSei[varExport, sei];
GO TO noValue;
};
ENDCASE;
SELECT SymbolOps.XferMode[SymbolOps.own, type] FROM
program => link ¬ [tag: other, modIndex: 0, offset: 0];
ENDCASE => link ¬ SymbolOps.DecodeLink[seb[sei].idValue];
};
$ref => {
iVType: CSEIndex ¬ iType;
iConst: BOOL ¬ iBase.seb[iSei].immutable;
WITH t: iBase.seb[iType] SELECT FROM
ref =>
IF t.var THEN {
iVType ¬ SymbolOps.UnderType[iBase, t.refType];
iConst ¬ t.readOnly;
};
ENDCASE;
SELECT TRUE FROM
warnPrivate => {
MimosaLog.WarningSei[privateExport, sei];
GO TO noValue;
};
NOT Types.Equivalent[
[iBase, iVType], [MimData.ownSymbols, type]] => {
MimosaLog.ErrorType[exportClash, [symbol[sei]], [iBase, iTarget]];
GO TO noValue;
};
seb[sei].constant => {
MimosaLog.ErrorSei[varExport, sei];
GO TO noValue;
};
seb[sei].immutable AND ~iConst => {
MimosaLog.ErrorSei[updateClash, sei];
GO TO noValue;
};
ENDCASE;
link ¬ MakeFrameLink[
ep: EnterEVOffset[
SymbolOps.DecodeBitAddr[seb[sei].idValue].bd/bitsPerAU],
gfi: ownGfi];
};
$type => {
SELECT TRUE FROM
warnPrivate => {
No warnings about types
GO TO noValue;
};
type # typeTYPE,
SymbolOps.TypeForm[SymbolOps.own, sei] = $opaque => {
MimosaLog.ErrorSei[exportClash, sei];
GO TO noValue;
};
ENDCASE => {
iValue: CSEIndex = SymbolOps.UnderType[iBase, iSei];
WITH it: iBase.seb[iValue] SELECT FROM
opaque =>
IF it.lengthKnown
AND ~MimP4.DefaultBasicOps[sei, it.length] THEN {
MimosaLog.ErrorSei[exportAttr, sei];
GO TO noValue;
};
ENDCASE => ERROR;
link ¬ MakeTypeLink[EnterType[mdi, epN, sei]];
mobHeader.typeExported ¬ TRUE;
};
};
$manifest => {
SELECT TRUE FROM
NOT public => {};
type # typeTYPE, iBase.seb[iSei].idType # typeTYPE =>
MimosaLog.WarningSei[voidExport, sei];
ENDCASE;
GO TO noValue;
};
ENDCASE =>
GO TO noValue;
IF link # MobDefs.nullLink THEN {
This is an exported item
iT: Type = SymbolOps.DecodeType[iBase.seb[iSei].idInfo];
ts: TypeStrings.TypeString = IF mode = type
THEN TypeStrings.Create[iBase, iT, tempUZ] ELSE NIL;
new: ExportList;
expLink.from ¬ link;
new ¬ z.NEW[ExportListRep ¬ [
mdi: mdi,
formal: formal,
irSei: id,
irType: expType,
ts: ts,
src: sei,
link: expLink]];
IF exportTail = NIL THEN exportHead ¬ new ELSE exportTail.next ¬ new;
exportTail ¬ new;
used ¬ TRUE;
};
EXITS noValue => {};
};
IF mode # $manifest THEN {
expHeader[epN] ¬ expLink;
epN ¬ epN + 1;
};
ENDLOOP;
CompilerUtil.AppendMobUnits[expHeader, MobDefs.EXPRecord[size].SIZE];
permUZ.FREE[@expHeader];
MimosaCopier.FreeSymbolTable[iBase];
IF ~used THEN MimosaLog.WarningSei[unusedExport, id];
};
};
ENDCASE;
MimData.textIndex ¬ saveIndex;
};
ProcessExports: PROC [t: Tree.Link] = {
offset: CARD ¬ CompilerUtil.ReadMobOffset[];
mobHeader.expOffset.units ¬ offset;
mobHeader.nExports ¬ TreeOps.ListLength[t];
evList.length ¬ evList.pad ¬ 0;
typeIndex ¬ MobDefs.TYPIndex.FIRST;
mapIndex ¬ 0;
typeMap ¬ NIL;
TreeOps.ScanList[t, ExportItem];
mobHeader.expLimit ¬ MobDefs.EXPIndex.FIRST + (CompilerUtil.ReadMobOffset[]-offset);
mobHeader.evOffset.units ¬ offset ¬ CompilerUtil.ReadMobOffset[];
SELECT evList.length FROM
0 => MimData.mtRoot.variables ¬ MobDefs.EVNull;
ENDCASE => {
units: NAT = SIZE[MobDefs.EVRecord[evList.length]];
MimData.mtRoot.entries ¬ MAX[MimData.mtRoot.entries, evList.length+1];
MimData.mtRoot.variables ¬ MobDefs.EVIndex.FIRST;
CompilerUtil.AppendMobUnits[evList, units];
};
mobHeader.evLimit ¬ MobDefs.EVIndex.FIRST + (CompilerUtil.ReadMobOffset[]-offset);
WriteTypeTable[];
typeMap ¬ NIL;
};
Initialization/finalization
InitMob: PUBLIC PROC [ids: Tree.Link] = {
nIds: CARDINAL ¬ TreeOps.ListLength[ids];
IF nIds > 1 AND ~MimData.interface THEN {MimosaLog.ErrorN[listLong, nIds-1]; nIds ¬ 1};
lastPorted ¬ firstPorted;
nStringREFTEXT ¬ z.NEW[TEXT[pageBytes-4]];
nString ¬ LOOPHOLE[nStringREFTEXT, MobDefs.NameString];
allocate the null name
nString[MobDefs.NullName] ¬ 0C;
nString.length ¬ MobDefs.NullName + 1;
mdb[OwnMdi].stamp ¬ MimData.objectVersion; -- update from DIRECTORY processing
CompilerUtil.StartMob[];
mobHeader.versionIdent ¬ MobDefs.VersionID;
mobHeader.format ¬ OSMiscOps.mobFormat;
mobHeader.version ¬ MimData.objectVersion;
mobHeader.creator ¬ MimData.compilerVersion;
mobHeader.sourceVersion ¬ MimData.source.version;
mobHeader.nConfigs ¬ 0;
mobHeader.nModules ¬ nIds;
mobHeader.nImports ¬ mobHeader.nExports ¬ 0;
mobHeader.definitions ¬ MimData.interface;
mobHeader.typeExported ¬ FALSE;
mobHeader.repackaged ¬ FALSE;
mobHeader.inlineFloat ¬ MimData.switches['f];
mobHeader.versions ¬ FALSE;
mobHeader.extended ¬ TRUE;
mobHeader.mappingStarted ¬ FALSE;
mobHeader.mappingFinished ¬ FALSE;
mobHeader.ctOffset.units ¬ 0; mobHeader.ctLimit ¬ MobDefs.CTIndex.FIRST;
mobHeader.spOffset.units ¬ 0; mobHeader.spLimit ¬ MobDefs.SPIndex.FIRST;
mobHeader.fpOffset.units ¬ 0; mobHeader.fpLimit ¬ MobDefs.FPIndex.FIRST;
{
Must be compatible with EnterId.
source: Rope.ROPE = MimData.source.locator;
len: [0..255] ¬ Rope.Length[source];
nString[nString.length] ¬ VAL[len];
nString.length ¬ nString.length + 1;
ConvertUnsafe.AppendRope[to: LOOPHOLE[nString], from: source];
};
mobIndex ¬ CompilerUtil.ReadMobIndex[];
CompilerUtil.AppendMobUnits[mobHeader, MobDefs.Mob.SIZE];
MimData.fixupLoc ¬ CompilerUtil.ReadMobIndex[];
RRA: someday fix this up
mobHeader.sgOffset.units ¬ CompilerUtil.ReadMobOffset[];
CompilerUtil.AppendMobUnits[@MimData.codeSeg, MobDefs.SGRecord.SIZE];
CompilerUtil.AppendMobUnits[@MimData.symSeg, MobDefs.SGRecord.SIZE];
mobHeader.mtOffset.units ¬ CompilerUtil.ReadMobOffset[];
mtIndex ¬ CompilerUtil.ReadMobIndex[];
mobHeader.sgLimit ¬ MobDefs.SGIndex.FIRST
+ (mobHeader.mtOffset.units - mobHeader.sgOffset.units);
MimData.mtRootSize ¬ MobDefs.MTRecord.SIZE;
MimData.mtRoot ¬ protoMTRecord;
MimData.mtRoot.links ¬
(IF MimData.interface THEN MobDefs.LFNull ELSE MobDefs.LFIndex.FIRST);
MimData.mtRoot.refLiterals ¬ MobDefs.RFNull;
MimData.mtRoot.types ¬ MobDefs.TFNull;
FOR i: CARDINAL IN [0..nIds) DO
CompilerUtil.AppendMobUnits[MimData.mtRoot, MimData.mtRootSize]
ENDLOOP;
mobHeader.lfOffset.units ¬ CompilerUtil.ReadMobOffset[];
mobHeader.mtLimit ¬ MobDefs.MTIndex.FIRST
+ (mobHeader.lfOffset.units-mobHeader.mtOffset.units);
};
FinishMob: PUBLIC PROC [ids: Tree.Link] = {
unitsPerPage: CARDINAL = OSMiscOps.bytesPerFilePage / BYTES[UNIT];
Alignment: CARDINAL = 4; -- Code Segments must start at 0 MOD Alignment
nLinks: CARDINAL = MimData.linkCount;
codeLinks: BOOL = FALSE;
embeddedLinks: BOOL ¬ Pass4Parms.links.embedded;
RRA: temporary until we get better parameterization of machine model
gfType: RecordSEIndex = bb[RootBti].type;
mtRoot: MobDefs.MTHandle = MimData.mtRoot;
fill MTRecord
IF TreeOps.ListLength[ids] > 1 THEN {
complete nString now
inner: Tree.Scan = {[] ¬ EnterSymbolId[TreeOps.GetSe[t]]};
TreeOps.ScanList[ids, inner];
};
mtRoot.name ¬ EnterSymbolId[bb[RootBti].id];
mtRoot.namedInstance ¬ FALSE;
mtRoot.initial ¬ TRUE;
{
fti: MobDefs.FTIndex = PortedCtx[MimData.mainCtx];
mtRoot.file ¬ fti;
MimData.mobSeg.file ¬ fti;
MimData.codeSeg.file ¬ fti;
MimData.symSeg.file ¬ fti;
};
MimData.mobSeg.base.units ¬ 0;
mtRoot.linkLoc ¬ SELECT TRUE FROM
embeddedLinks => inFrame,
codeLinks => codePrefix,
ENDCASE => framePrefix;
mtRoot.config ¬ MobDefs.CTNull;
mtRoot.code ¬ MobDefs.CodeDesc[
sgi: MobDefs.SGIndex.FIRST,
packed: FALSE,
linkspace: codeLinks,
offset: (IF codeLinks AND nLinks # 0 AND NOT embeddedLinks
THEN (nLinks+1) + (Alignment-1 - (nLinks MOD Alignment))
ELSE 0),
length: 0]; -- will be updated
mtRoot.sseg ¬ MobDefs.SGIndex.FIRST + MobDefs.SGRecord.SIZE;
IF seb[gfType].hints.refField
THEN {
mtRoot.frameRefs ¬ TRUE;
mtRoot.frameType ¬ SymLiteralOps.TypeIndex[gfType];
}
ELSE {
mtRoot.frameRefs ¬ seb[gfType].hints.refField;
mtRoot.frameType ¬ [0];
};
mtRoot.framesize ¬ 0; -- will be updated
mtRoot.inlineFloat ¬ MimData.switches['f];
mtRoot.residentFrame ¬ resident;
mtRoot.boundsChecks ¬ MimData.switches['b];
mtRoot.nilChecks ¬ MimData.switches['n];
mtRoot.packageable ¬ TRUE;
{
Formerly in ProcessFiles
limit: MDIndex = Alloc.Top[MimData.table, mdType];
EnterCanonicalFile: SymLiteralOps.TypesVisitor = {
IF NOT canonical THEN {
mdi: MDIndex;
[mdi, ] ¬ SymLiteralOps.UTypeId[type];
IF mdi # MDNull THEN [] ¬ PortedFile[mdi];
};
};
offset: CARD = CompilerUtil.ReadMobOffset[];
FOR mdi: MDIndex ¬ lastPorted, mdi + MDRecord.SIZE UNTIL mdi = limit DO
IF mdb[mdi].file # nullFileIndex THEN [] ¬ PortedFile[mdi];
add any files opened during compilation
ENDLOOP;
mobHeader.ftOffset.units ¬ offset;
SymLiteralOps.EnumerateTypes[EnterCanonicalFile];
FOR mdi: MDIndex ¬ firstPorted, mdi + MDRecord.SIZE UNTIL mdi = lastPorted DO
ftEntry: MobDefs.FTRecord ¬ [name: EnterFileId[mdi], version: mdb[mdi].stamp];
CompilerUtil.AppendMobUnits[@ftEntry, MobDefs.FTRecord.SIZE];
ENDLOOP;
mobHeader.ftLimit ¬ MobDefs.FTIndex.FIRST + (CompilerUtil.ReadMobOffset[]-offset);
};
mobHeader.ssOffset.units ¬ CompilerUtil.ReadMobOffset[];
CompilerUtil.AppendMobString[LOOPHOLE[nString]];
mobHeader.ssLimit.units ¬ (CompilerUtil.ReadMobOffset[]-mobHeader.ssOffset.units);
IF MimData.interface
THEN {
mobHeader.rtOffset.units ¬ 0;
mobHeader.rtLimit.units ¬ 0;
}
ELSE {
CompilerUtil.FillMobPage[];
mobHeader.rtOffset.units ¬ CompilerUtil.ReadMobOffset[];
CompilerUtil.RTTableOut[MimData.table];
mobHeader.rtLimit.units ¬ CompilerUtil.ReadMobOffset[] - mobHeader.rtOffset.units;
};
mobHeader.nBytes ¬ CompilerUtil.ReadMobIndex[];
CompilerUtil.UpdateMobUnits[mobIndex, mobHeader, MobDefs.Mob.SIZE];
MimData.mobSeg.base.units ¬ 0;
MimData.mobSeg.units ¬ [domestic[unitsPerPage]];
IF MimData.interface AND TreeOps.ListLength[ids] > 1 THEN {
index: FileByteIndex ¬ mtIndex;
saveName: MobDefs.NameRecord = mtRoot.name;
UpdateMDEntry: Tree.Scan = {
mtRoot.name ¬ EnterSymbolId[TreeOps.GetSe[t]];
CompilerUtil.UpdateMobUnits[index, mtRoot, MimData.mtRootSize];
index ¬ index + (MimData.mtRootSize)*BYTES[UNIT];
};
TreeOps.ScanList[ids, UpdateMDEntry];
mtRoot.name ¬ saveName;
};
CompilerUtil.EndMob[];
z.FREE[@nStringREFTEXT];
nString ¬ NIL;
};
MatchMob: PUBLIC PROC RETURNS [matched: BOOL ¬ FALSE] = {
oldSymbols: SymbolTable.Base = MimosaCopier.MapSymbols[MimData.pattern];
IF oldSymbols = NIL
THEN MimosaLog.WarningRope[fileName, MimData.pattern.locator]
ELSE {
matched ¬ MatchedBodies[
[oldSymbols, RootBti], [MimData.ownSymbols, RootBti]
! Unmatched => {
stb: STB ¬ id.stb;
n: Symbols.Name ¬ SymbolOps.NameForSe[SymbolOps.own, id.sei];
d: ConvertUnsafe.SubString ¬ SymbolOps.SubStringForName[stb, n];
SELECT attr FROM
$strings => MimosaLog.WarningSubString[replString, d];
$id => MimosaLog.WarningSubString[replId, d];
ENDCASE;
RESUME}];
MimosaCopier.UnmapSymbols[oldSymbols];
};
};
Matching for module replacement (formerly in ReplPack)
IdHandle: TYPE = RECORD [
stb: SymbolTable.Base,
sei: Symbols.ISEIndex];
MatchedNames: PROC [id1, id2: IdHandle] RETURNS [BOOL] = {
IF id1.sei = ISENull OR id2.sei = ISENull
THEN RETURN [FALSE]
ELSE {
b1: STB = id1.stb;
b2: STB = id2.stb;
ss1: ConvertUnsafe.SubString = SymbolOps.SubStringForName[b1, b1.seb[id1.sei].hash];
ss2: ConvertUnsafe.SubString = SymbolOps.SubStringForName[b2, b2.seb[id2.sei].hash];
RETURN [ConvertUnsafe.EqualSubStrings[ss1, ss2]];
};
};
MatchMode: PROC [id: IdHandle] RETURNS [Linkage] = {
LinkMode for a virtual defs module
b: STB = id.stb;
note: must resample b if any table allocations occur (none do now)
IF b.seb[id.sei].idType = typeTYPE AND b.seb[id.sei].public THEN RETURN [$type];
IF b.seb[id.sei].constant THEN
SELECT SymbolOps.XferMode[b, b.seb[id.sei].idType] FROM
proc, program, signal, error => RETURN [$val];
ENDCASE => RETURN [$manifest];
RETURN [$ref];
};
MatchedAttrs: PROC [idL, idR: IdHandle] RETURNS [BOOL] = {
bL: STB = idL.stb;
bR: STB = idR.stb;
note: must resample bL & bR if any table allocations occur (none do now)
typeL: CSEIndex = SymbolOps.UnderType[bL, bL.seb[idL.sei].idType];
mode: Linkage = MatchMode[idL];
matched: BOOL;
IF idR.sei # ISENull
THEN {
typeR: CSEIndex = SymbolOps.UnderType[bR, bR.seb[idR.sei].idType];
matched ¬ (SELECT mode FROM
$val =>
Types.Assignable[[bL, typeL], [bR, typeR]]
AND
(bL.seb[idL.sei].idValue = bR.seb[idR.sei].idValue),
$ref =>
Types.Equivalent[[bL, typeL], [bR, typeR]]
AND
(bL.seb[idL.sei].idValue = bR.seb[idR.sei].idValue) -- offsets
AND
(bL.seb[idL.sei].idInfo = bR.seb[idR.sei].idInfo), -- sizes
$type =>
(bR.seb[idR.sei].idType = typeTYPE) AND (bR.seb[idR.sei].public)
AND
Types.Equivalent[
[bL, SymbolOps.UnderType[bL, idL.sei]],
[bR, SymbolOps.UnderType[bR, idR.sei]]],
ENDCASE => TRUE);
}
ELSE matched ¬ (mode = manifest);
IF ~matched THEN SIGNAL Unmatched[$id, idL];
RETURN [matched];
};
CTXHandle: TYPE = RECORD [
stb: SymbolTable.Base,
ctx: CTXIndex];
MatchedContexts: PROC [ctxL, ctxR: CTXHandle] RETURNS [BOOL] = {
bL: STB = ctxL.stb;
bR: STB = ctxR.stb;
note: must resample bL & bR if any table allocations occur (none do now)
n: CARDINAL ¬ 0;
FOR sei: ISEIndex ¬ SymbolOps.FirstCtxSe[bL, ctxL.ctx], SymbolOps.NextSe[bL, sei]
UNTIL sei = ISENull OR n > 4 DO
IF bL.seb[sei].hash # nullName THEN {
ss: ConvertUnsafe.SubString = SymbolOps.SubStringForName[bL, bL.seb[sei].hash];
seiR: Symbols.ISEIndex =
SymbolOps.SearchContext[bR, SymbolOps.FindString[bR, ss], ctxR.ctx];
IF ~MatchedAttrs[ [ctxL.stb, sei], [ctxR.stb, seiR]] THEN n ¬ n+1;
};
ENDLOOP;
RETURN [n = 0];
};
RecordHandle: TYPE = RECORD [
stb: SymbolTable.Base,
sei: RecordSEIndex];
MatchedRecords: PROC [recL, recR: RecordHandle] RETURNS [BOOL] = {
bL: STB = recL.stb;
bR: STB = recR.stb;
note: must resample bL & bR if any table allocations occur (none do now)
IF recL.sei = RecordSENull OR recR.sei = RecordSENull THEN
RETURN [recL.sei = recR.sei];
RETURN [MatchedContexts[[bL, bL.seb[recL.sei].fieldCtx], [bR, bR.seb[recR.sei].fieldCtx]]];
};
MatchedArgLists: PROC [argL, argR: Types.Handle] RETURNS [BOOL] = {
bL: STB = argL.stb;
bR: STB = argR.stb;
note: must resample bL & bR if any table allocations occur (none do now)
inL, inR, outL, outR: RecordSEIndex;
[inL, outL] ¬ SymbolOps.TransferTypes[bL, argL.sei];
[inR, outR] ¬ SymbolOps.TransferTypes[bR, argR.sei];
IF NOT MatchedRecords[[bL, inL], [bR, inR]] THEN RETURN [FALSE];
IF NOT MatchedRecords[[bL, outL], [bR, outR]] THEN RETURN [FALSE];
RETURN [TRUE];
};
BodyHandle: TYPE = RECORD [
stb: SymbolTable.Base,
bti: Symbols.CBTIndex];
MatchAttr: TYPE = {id, strings};
Unmatched: SIGNAL[attr: MatchAttr, id: IdHandle] = CODE;
MatchedBodies: PROC [bodyL, bodyR: BodyHandle] RETURNS [BOOL] = {
bL: STB = bodyL.stb;
bR: STB = bodyR.stb;
note: must resample bL & bR if any table allocations occur (none do now)
matched: BOOL ¬ TRUE;
IF NOT bL.bb[bodyL.bti].hints.noStrings THEN {
SIGNAL Unmatched[$strings, [bodyL.stb, bL.bb[bodyL.bti].id]];
matched ¬ FALSE;
};
IF NOT bR.bb[bodyR.bti].hints.noStrings THEN {
IF NOT matched THEN SIGNAL Unmatched[$strings, [bodyR.stb, bR.bb[bodyR.bti].id]];
matched ¬ FALSE;
};
IF NOT (
MatchedNames[[bodyL.stb, bL.bb[bodyL.bti].id], [bodyR.stb, bR.bb[bodyR.bti].id]]
AND (bL.bb[bodyL.bti].entryIndex = bR.bb[bodyR.bti].entryIndex)
AND Types.Assignable[
[bodyL.stb, bL.bb[bodyL.bti].ioType],
[bodyR.stb, bR.bb[bodyR.bti].ioType]]
AND MatchedArgLists[
[bodyL.stb, bL.bb[bodyL.bti].ioType],
[bodyR.stb, bR.bb[bodyR.bti].ioType]])
THEN {
SIGNAL Unmatched[$id, [bodyL.stb, bL.bb[bodyL.bti].id]];
matched ¬ FALSE;
};
IF NOT MatchedContexts[
[bodyL.stb, bL.bb[bodyL.bti].localCtx],
[bodyR.stb, bR.bb[bodyR.bti].localCtx]] THEN matched ¬ FALSE;
RETURN [matched];
};
Initialization
{
set: MimosaEvents.Trigger ¬ ALL[FALSE];
set[relocate] ¬ TRUE;
set[zoneReset] ¬ TRUE;
evList ¬ permUZ.NEW[MobDefs.EVRecord[evListMax]];
mobHeader ¬ permUZ.NEW[MobDefs.Mob];
protoMTRecord ¬ permUZ.NEW[MobDefs.MTRecord];
MimosaEvents.RegisterSet[P4Notify, ALL[TRUE]];
};
}.