<<>> <> <> <> <> 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) <> tTRUE: PUBLIC Tree.Link; tFALSE: PUBLIC Tree.Link; <> 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; <> <> P4Notify: MimosaEvents.Callback = { <> 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] = { <> 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 <> MimP4.TypeExp[TreeOps.NthSon[son1, 2]]; }; }; resident ¬ tb[node].attr1; Reset[]; <> 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]; <> 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 => { <> 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; <> }; ENDCASE => ERROR; }; FinishMob[tb[subNode].son[1]]; IF MimData.matched THEN MimData.matched ¬ MimP4.MatchMob[]; MimData.textIndex ¬ saveIndex; }; <> bitsPerAU: CARDINAL = Target.bitsPerAU; mobHeader: MobDefs.MobBase; <> 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; <> <> 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; <> 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; <> 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; { <> 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]; <> 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]]; }; <> 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; }; <> 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; }; <> AssignImports: PUBLIC Tree.Scan = { gfi: ModuleIndex ¬ mobHeader.firstdummy ¬ ownGfi + 1; <> 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 { <> 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; }; <> 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); }; }; <> 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]; <> 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; <> anyNamed: BOOL ¬ FALSE; sei: ISEIndex ¬ SymbolOps.FirstCtxSe[SymbolOps.own, MimData.importCtx]; <> 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]; <> mobHeader.ntLimit ¬ MobDefs.NTIndex.FIRST + (CompilerUtil.ReadMobOffset[]-units); }; <> 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 { <> 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; <> 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 => { <> 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 => { <> 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 { <> 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; }; <> 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]; <> 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; { <> 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[]; <> 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; <> gfType: RecordSEIndex = bb[RootBti].type; mtRoot: MobDefs.MTHandle = MimData.mtRoot; <> IF TreeOps.ListLength[ids] > 1 THEN { <> 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; { <> 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]; <> 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]; }; }; <> 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] = { <> b: STB = id.stb; <> 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; <> 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; <> 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; <> 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; <> 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; <> 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]; }; <> { 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]]; }; }.