-- file PackCodeImplA.mesa -- last edited by Lewis 6-Dec-82 14:09:07 -- last edited by Satterthwaite, December 29, 1982 12:06 pm DIRECTORY Alloc USING [AddNotify, Bounds, DropNotify, Handle, Notifier, Top, Words], BcdDefs, BcdOps USING [MTHandle, NameString], BcdUtilDefs: TYPE USING [EnterName], CatchFormat USING [EnableHandle, EnableItem, EnableTableBody], CharIO, CIFS: TYPE USING [OpenFile, GetFC], CodePackProcs USING [ EnumerateCodePacks, EnumerateModules, EnumerateProcs, EnumerateSegments, HtiForCodePackNode, IsDiscardCodePack, ModuleIndex, SubStringForCodePackNode, SubStringForSegmentNode, TreeIndex], Environment USING [Byte, bytesPerPage, bytesPerWord, wordsPerPage], Error USING [EmptyCodePack, ErrorFile, SegmentTooLarge], FileStream: TYPE USING [Create, GetIndex, GetLeaderProperties], FileTable USING [HandleForFile, UnknownFile], FramePackModules USING [ EnumerateFramePacks, EnumerateModules, SubStringForFramePackNode], HashOps USING [HTIndex], Inline USING [LongCOPY, LongDiv, LongDivMod, LongMult, LowHalf], ModuleSymbols, Mopcodes USING [zJIB], PackagerDefs USING [packtreetype, globalData, GlobalData], PackageSymbols, PackCode, PieceTable USING [ Append, AppendPage, AppendQuadWord, AppendWord, CopyFromFile, Delete, Finalize, GetByte, GetPlace, GetVPos, GetWord, Initialize, Length, Move, NullPiece, PieceIndex, Place, Position, PutWord, PutZeros, SetVPos, Store], PrincOps USING [BytePC, CSegPrefix, EntryVectorItem, PrefixHeader], SourceBcd USING [ bcdBases, bcdHeader, BcdTableLoc, CTreeIndex, Index, LookupSS, moduleCount, ModuleNum, ModuleNumForMti, nullCTreeIndex, Prev], Stream USING [Delete, Handle, PutByte, PutBlock], String, SymbolOps, Symbols, Table USING [Base, Limit], Time USING [Append, Current, Packed, Unpack], Tree: FROM "PackTree" USING [Index]; PackCodeImplA: PROGRAM IMPORTS Alloc, BcdUtilDefs, CharIO, CIFS, CodePackProcs, Error, FileStream, FileTable, FramePackModules, Inline, ModuleSymbols, PackagerDefs, PackCode, PieceTable, SourceBcd, Stream, String, SymbolOps, Time EXPORTS PackCode = BEGIN OPEN PackCode; -- private data structures WordIndexSeqBody: TYPE = RECORD [SEQUENCE COMPUTED NAT OF WordIndex]; WordIndexSeq: TYPE = LONG POINTER TO WordIndexSeqBody; SeenModuleSeqBody: TYPE = RECORD[ SEQUENCE COMPUTED [0..1024) OF SeenModuleHandle]; SeenModuleSeq: TYPE = LONG POINTER TO SeenModuleSeqBody; Address: TYPE = [0..77777b]; -- max of 32K WordIndex: TYPE = PackageSymbols.WordIndex; NullWordIndex: WordIndex = WordIndex.LAST; BodyDataRec: TYPE = RECORD [ oldPC: PrincOps.BytePC, bytes: CARDINAL, newPC: PrincOps.BytePC ← [0], pending: FixupHandle ← NIL]; FixupRec: TYPE = RECORD [ next: FixupHandle, loc: LONG CARDINAL, target: PrincOps.BytePC]; FixupHandle: TYPE = LONG POINTER TO FixupRec; SeenModuleRecord: TYPE = RECORD [ newOffset: Address, -- of entry vector within segment newPiece: PieceTable.PieceIndex, -- of beginning of vector oldCodeFile: CIFS.OpenFile, oldCodePosition: LONG CARDINAL, newConstants: WordIndexSeq ← NIL, -- of new constant values enablePlace: PieceTable.Place ← [PieceTable.NullPiece, 0, 0], discarded: BOOL ← FALSE, thisSeg: BOOL ← TRUE, body: SEQUENCE nBodies: [0..128] OF BodyDataRec ← NULL]; SeenModuleHandle: TYPE = LONG POINTER TO SeenModuleRecord; -- state variables gd: PackagerDefs.GlobalData; z: UNCOUNTED ZONE ← NIL; table: Alloc.Handle ← NIL; tb, spb, sgb, fpb: Table.Base; itb, etb, ctb, mtb, ntb, lfb: Table.Base; ssb: BcdOps.NameString; NotifyA: Alloc.Notifier = BEGIN tb ← base[PackagerDefs.packtreetype]; sgb ← base[BcdDefs.sgtype]; spb ← base[BcdDefs.sptype]; fpb ← base[BcdDefs.fptype]; ssb ← base[BcdDefs.sstype]; itb ← base[BcdDefs.imptype]; etb ← base[BcdDefs.exptype]; ctb ← base[BcdDefs.cttype]; mtb ← base[BcdDefs.mttype]; ntb ← base[BcdDefs.nttype]; lfb ← base[BcdDefs.lftype]; NotifyB[base]; END; EntryIndex: TYPE = [0..PackageSymbols.MaxEntries]; PackError: PUBLIC SIGNAL [reason: PackCode.Problem] = CODE; cstb: LONG DESCRIPTOR FOR ARRAY OF PackageSymbols.ConstRecord; seenModules: SeenModuleSeq ← NIL; cur: SeenModuleHandle; newConstants: WordIndexSeq ← NIL; oldCodeFile: PUBLIC CIFS.OpenFile; oldCodeBasePosition: LONG CARDINAL; currentModule: BcdDefs.MTIndex; currentCodePackHti: HashOps.HTIndex; firstCodeSgi: BcdDefs.SGIndex; currentCodeSegment: BcdDefs.SGIndex; currentSpaceIndex: BcdDefs.SPIndex; segmentPosition: PieceTable.Position; codePackPosition: PieceTable.Position; codeBasePosition: PieceTable.Position; codeBaseOffset: Address; -- from start of code segment procOffset, oldProcOffset: CARDINAL; -- from codeBase procPosition: PieceTable.Position; lastProcEnd: PieceTable.Position; firstCodePack, currentCodePackResident: BOOL; outStream: Stream.Handle; WriteChar: PROC [c: CHARACTER] = {IF gd.mapStream # NIL THEN CharIO.PutChar[gd.mapStream, c]}; WriteString: PROC [s: LONG STRING] = {IF gd.mapStream # NIL THEN CharIO.PutString[gd.mapStream, s]}; WriteSubString: PROC [ss: String.SubString] = BEGIN FOR i: CARDINAL IN [ss.offset..ss.offset+ss.length) DO WriteChar[ss.base[i]]; ENDLOOP; END; WriteDecimal: PROC [n: CARDINAL] = {IF gd.mapStream # NIL THEN CharIO.PutDecimal[gd.mapStream, n]}; WriteOctal: PROC [n: CARDINAL] = {IF gd.mapStream # NIL THEN CharIO.PutOctal[gd.mapStream, n]}; WriteNumber: PROC [n: CARDINAL, fmt: CharIO.NumberFormat] = {IF gd.mapStream # NIL THEN CharIO.PutNumber[gd.mapStream, n, fmt]}; WriteTime: PROC [t: Time.Packed] = BEGIN s: STRING ← [20]; Time.Append[s, Time.Unpack[t]]; WriteString[s]; END; PagesForWords: PROC [nWords: CARDINAL] RETURNS [CARDINAL] = { RETURN [(nWords + (Environment.wordsPerPage-1))/Environment.wordsPerPage]}; Initialize: PROC [nModules: CARDINAL] = BEGIN gd ← PackagerDefs.globalData; table ← gd.ownTable; z ← gd.zone; table.AddNotify[NotifyA]; PackCode.InitBcdTab[]; seenModules ← z.NEW[SeenModuleSeqBody[nModules]]; FOR i: CARDINAL IN [0..nModules) DO seenModules[i] ← NIL ENDLOOP; nMods ← nModules; END; nMods: CARDINAL; FixupCodeByteOffset: PROC = BEGIN loc: LONG CARDINAL = PieceTable.GetVPos[]; target: PrincOps.BytePC = PieceTable.GetWord[]; FOR ep: CARDINAL IN [0..cur.nBodies) DO old, new: PrincOps.BytePC; bytes: CARDINAL; [oldPC: old, newPC: new, bytes: bytes] ← cur[ep]; IF target IN [old..old+bytes) THEN BEGIN IF new = 0 THEN { f: FixupHandle = z.NEW[FixupRec ← [ next: cur[ep].pending, loc: loc, target: target]]; cur[ep].pending ← f; RETURN}; PieceTable.Delete[-2]; PieceTable.PutWord[target - old + new]; RETURN; END; ENDLOOP; ERROR PackError[StrangeLIO]; END; NoteNewPC: PROC [ep: CARDINAL, new: PrincOps.BytePC] = BEGIN IF cur[ep].pending # NIL THEN BEGIN vicinity: PieceTable.Place ← PieceTable.GetPlace[]; savePos: LONG CARDINAL = PieceTable.GetVPos[]; old: PrincOps.BytePC; f: FixupHandle; [oldPC: old, pending: f] ← cur[ep]; WHILE f # NIL DO fn: FixupHandle = f.next; PieceTable.SetVPos[f.loc]; PieceTable.Delete[2]; PieceTable.PutWord[f.target - old + new]; z.FREE[@f]; f ← fn; ENDLOOP; PieceTable.SetVPos[savePos, @vicinity]; cur[ep].pending ← NIL; END; cur[ep].newPC ← new; END; FixupCodeOffset: PROC = BEGIN old: CARDINAL = PieceTable.GetWord[]; new: CARDINAL = NewOffset[old]; PieceTable.Delete[-2]; PieceTable.PutWord[new]; END; Finalize: PUBLIC PROC = BEGIN IF table # NIL THEN table.DropNotify[NotifyA]; IF seenModules = NIL THEN RETURN; FOR i: CARDINAL IN [0..nMods) DO cur ← seenModules[i]; IF cur = NIL THEN LOOP; IF cur.newConstants # NIL THEN z.FREE[@cur.newConstants]; IF cur.oldCodeFile # NIL THEN cur.oldCodeFile ← NIL; FOR ep: CARDINAL IN [0..cur.nBodies) DO IF cur[ep].pending # NIL THEN BEGIN f: FixupHandle ← cur[ep].pending; IF ~cur.discarded THEN SIGNAL PackError[StrangeLIO]; WHILE f # NIL DO fn: FixupHandle ← f.next; z.FREE[@f]; f ← fn; ENDLOOP; END; ENDLOOP; z.FREE[@cur]; ENDLOOP; PackCode.FinalizeBcdTab[]; IF seenModules # NIL THEN z.FREE[@seenModules]; table ← NIL; END; FixLoads: PROC [ lc: PackageSymbols.PCSeq, start: PrincOps.BytePC, bytes: CARDINAL, FixProc: PROC] = BEGIN l, u, i: INTEGER; stop: PrincOps.BytePC = [start + bytes]; pci: PrincOps.BytePC; l ← 0; u ← lc.length; IF u = 0 THEN RETURN; UNTIL l > u DO i ← (l+u)/2; SELECT lc[i] FROM < start => l ← i+1; > start => u ← i-1; ENDCASE => EXIT; REPEAT FINISHED => i ← l; ENDLOOP; -- lc[i] >= start; WHILE CARDINAL[i] < lc.length AND (pci ← lc[i]) < stop DO IF pci >= start THEN { PieceTable.SetVPos[procPosition + pci - oldProcOffset + 1]; FixProc[]}; i ← i + 1; ENDLOOP; END; FixJumpImmediates: PROC [ jc: PackageSymbols.JISeq, start: PrincOps.BytePC, bytes: CARDINAL] = BEGIN l, u, i: INTEGER; op: Environment.Byte; stop: PrincOps.BytePC = [start + bytes]; pci: PrincOps.BytePC; l ← 0; u ← jc.length; IF u = 0 THEN RETURN; UNTIL l > u DO i ← (l+u)/2; SELECT jc[i].pc FROM < start => l ← i+1; > start => u ← i-1; ENDCASE => EXIT; REPEAT FINISHED => i ← l; ENDLOOP; -- jc[i].pc >= start; IF i < 0 THEN ERROR PackError[InvalidCodeOffset]; WHILE CARDINAL[i] < jc.length AND (pci ← jc[i].pc) < stop DO IF pci >= start THEN { size: CARDINAL ← jc[i].tableSize; savePos: PieceTable.Position; newTableOffset, oldTableOffset: WordIndex; PieceTable.SetVPos[procPosition + pci - oldProcOffset]; op ← PieceTable.GetByte[]; oldTableOffset ← PieceTable.GetWord[]; savePos ← PieceTable.GetVPos[]; IF op = Mopcodes.zJIB THEN size ← (size+1)/2; newTableOffset ← CodeOffset[PieceTable.AppendWord[]]; PieceTable.CopyFromFile[ file: oldCodeFile, position: oldCodeBasePosition+oldTableOffset*2, length: size*2]; PieceTable.SetVPos[savePos]; PieceTable.Delete[-2]; PieceTable.PutWord[newTableOffset]}; i ← i + 1; ENDLOOP; END; NewOffset: PROC [old: WordIndex] RETURNS [WordIndex] = BEGIN -- address in new segment of multiword constant a "old" in old l, u, i: INTEGER; delta: CARDINAL; l ← 0; u ← LENGTH[cstb]; UNTIL l > u DO i ← (l+u)/2; SELECT cstb[i].offset FROM < old => l ← i+1; > old => u ← i-1; ENDCASE => EXIT; REPEAT FINISHED => i ← u; ENDLOOP; IF i < 0 THEN ERROR PackError[InvalidCodeOffset]; delta ← old - cstb[i].offset; IF delta > cstb[i].length THEN ERROR PackError[InvalidCodeOffset]; IF newConstants[i] = NullWordIndex THEN BEGIN savePos: PieceTable.Position = PieceTable.GetVPos[]; newConstants[i] ← CodeOffset[PieceTable.AppendWord[]]; PieceTable.CopyFromFile[ file: oldCodeFile, position: oldCodeBasePosition + cstb[i].offset*2, length: cstb[i].length*2]; PieceTable.SetVPos[savePos]; END; RETURN[newConstants[i] + delta]; END; firstBody: BOOL; CopyModuleBodies: PROC [root: PackageSymbols.OPIndex] RETURNS [stop: BOOL] = BEGIN OPEN PackageSymbols; SELECT root FROM OPEntry => CopyEV[currentModule]; OPCatch => { length: CARDINAL = cur[cur.nBodies-1].bytes; IF length # 0 AND cur[cur.nBodies-1].oldPC # 0 THEN { IF gd.printMap THEN DisplayNumbers[ ep: epCatch, length: length, hti: Symbols.HTNull]; IF firstBody THEN SetupCurrentOffsets[]; CopyOneBody[ep: cur.nBodies-1, length: length, catch: TRUE, needsFixup: TRUE]; CopyNestedBodies[LENGTH[ModuleSymbols.outerPackArray]-1]}}; ENDCASE => { IF firstBody THEN SetupCurrentOffsets[]; CopyBodies[root]}; RETURN[FALSE]; END; SetupCurrentOffsets: PROC = BEGIN IF cur = NIL THEN ERROR PackError[EVNotPlaced]; [newOffset: codeBaseOffset, newPiece: evPlace.pi, oldCodeFile: oldCodeFile, oldCodePosition: oldCodeBasePosition, newConstants: newConstants] ← cur↑; codeBasePosition ← segmentPosition + 2*codeBaseOffset; evPlace.pos ← codeBasePosition; evPlace.filePos ← evPlace.pi.position; -- first two words don't get deleted firstBody ← FALSE; END; CopyBodies: PROC [root: PackageSymbols.OPIndex] = BEGIN -- copy procedure (and any nested below unless main body) IF gd.printMap THEN DisplayNumbers[ ep: ModuleSymbols.outerPackArray[root].entryIndex, length: ModuleSymbols.outerPackArray[root].length, hti: ModuleSymbols.outerPackArray[root].hti]; CopyOneBody[ ep: ModuleSymbols.outerPackArray[root].entryIndex, length: ModuleSymbols.outerPackArray[root].length, catch: FALSE, needsFixup: ModuleSymbols.outerPackArray[root].needsFixup]; CopyNestedBodies[root]; END; CopyNestedBodies: PROC [root: PackageSymbols.OPIndex] = BEGIN i: PackageSymbols.IPIndex ← ModuleSymbols.outerPackArray[root].firstSon; IF i # PackageSymbols.IPNull THEN DO IF gd.printMap THEN DisplayNumbers[ ep: ModuleSymbols.innerPackArray[i].entryIndex, length: ModuleSymbols.innerPackArray[i].length, hti: Symbols.HTNull]; CopyOneBody[ ep: ModuleSymbols.innerPackArray[i].entryIndex, length: ModuleSymbols.innerPackArray[i].length, catch: FALSE, needsFixup: ModuleSymbols.innerPackArray[i].needsFixup]; IF ModuleSymbols.innerPackArray[i].lastSon THEN EXIT; i ← i+1; ENDLOOP; END; SegmentOffset: PROC [pos: PieceTable.Position] RETURNS [WordIndex] = BEGIN new: LONG CARDINAL = pos - segmentPosition; IF new > LAST[CARDINAL] THEN SIGNAL PackError[SegmentTooBig]; RETURN [Inline.LowHalf[new]/2]; END; CodeByteOffset: PROC [pos: PieceTable.Position] RETURNS [CARDINAL] = BEGIN new: LONG CARDINAL = pos - codeBasePosition; IF new > LAST[CARDINAL] THEN SIGNAL PackError[SegmentTooBig]; RETURN [Inline.LowHalf[new]]; END; CodeOffset: PROC [pos: PieceTable.Position] RETURNS [WordIndex] = INLINE BEGIN RETURN [CodeByteOffset[pos]/2]; END; ProcessEnables: PROC [mod: SeenModuleHandle] = BEGIN ep: PieceTable.Place; cLength: CARDINAL; alsoNested: BOOL ← TRUE; et: CatchFormat.EnableHandle; buffer: RECORD [SELECT OVERLAID * FROM ei => [item: CatchFormat.EnableItem], aa => [a: ARRAY [0..SIZE[CatchFormat.EnableItem]) OF CARDINAL], ENDCASE]; cur ← mod; cur.thisSeg ← FALSE; ep ← cur.enablePlace; IF ep.pi = PieceTable.NullPiece THEN RETURN; SetupCurrentOffsets[]; PieceTable.SetVPos[ep.pos, @ep]; WHILE alsoNested DO cLength ← PieceTable.GetWord[]; alsoNested ← FALSE; THROUGH [0..cLength) DO -- assumes SIZE[EnableItem] = 3 temp: CARDINAL; FixupCodeByteOffset[]; [] ← PieceTable.GetWord[]; temp ← PieceTable.GetWord[]; alsoNested ← alsoNested OR (temp MOD 2 # 0); ENDLOOP; -- ****** Now sort the damned things ***** IF cLength = 0 THEN EXIT; PieceTable.Move[-cLength*SIZE[CatchFormat.EnableItem]*2]; et ← z.NEW[CatchFormat.EnableTableBody[cLength]]; FOR i: CARDINAL IN [0..cLength) DO FOR j: CARDINAL IN [0..SIZE[CatchFormat.EnableItem]) DO buffer.a[j] ← PieceTable.GetWord[]; ENDLOOP; et[i] ← buffer.item; ENDLOOP; SortEnables[et]; PieceTable.Delete[-cLength*SIZE[CatchFormat.EnableItem]*2]; FOR i: CARDINAL IN [0..cLength) DO buffer.item ← et[i]; FOR j: CARDINAL IN [0..SIZE[CatchFormat.EnableItem]) DO PieceTable.PutWord[buffer.a[j]]; ENDLOOP; ENDLOOP; z.FREE[@et]; ENDLOOP; END; SortEnables: PROC [et: CatchFormat.EnableHandle] = BEGIN n: CARDINAL = et.count; i: CARDINAL; temp: CatchFormat.EnableItem; SiftUp: PROC [l, u: CARDINAL] = BEGIN s: CARDINAL; key: CatchFormat.EnableItem ← et[l-1]; DO s ← l*2; IF s > u THEN EXIT; IF s < u AND et[s+1-1].start > et[s-1].start THEN s ← s+1; IF key.start > et[s-1].start THEN EXIT; et[l-1] ← et[s-1]; l ← s; ENDLOOP; et[l-1] ← key; END; FOR i DECREASING IN [2..n/2] DO SiftUp[i, n]; ENDLOOP; FOR i DECREASING IN [2..n] DO SiftUp[1, i]; temp ← et[1-1]; et[1-1] ← et[i-1]; et[i-1] ← temp; ENDLOOP; END; CopyOneBody: PROC [ep: EntryIndex, length: CARDINAL, catch, needsFixup: BOOL] = BEGIN eviOffset: POINTER; codeLength: CARDINAL ← length; vicinity: PieceTable.Place; -- copy code into output file procPosition ← IF catch THEN PieceTable.AppendWord[] ELSE PieceTable.Append[]; procOffset ← CodeByteOffset[procPosition]; vicinity ← PieceTable.GetPlace[]; -- fix up entry vector for module eviOffset ← @(LOOPHOLE[1, POINTER TO PrincOps.CSegPrefix].entry[ep]) - 1; PieceTable.SetVPos[ codeBasePosition + 2*LOOPHOLE[eviOffset, CARDINAL], @evPlace]; oldProcOffset ← PieceTable.GetWord[]; PieceTable.Delete[-2]; IF catch AND length = 0 THEN procOffset ← 0; PieceTable.PutWord[procOffset]; PieceTable.SetVPos[procPosition, @vicinity]; IF catch AND length = 0 THEN RETURN; PieceTable.CopyFromFile[ file: oldCodeFile, position: oldProcOffset + oldCodeBasePosition, length: length]; NoteNewPC[ep: ep, new: [procOffset]]; IF catch THEN BEGIN cLength: CARDINAL; delta: CARDINAL = procOffset - oldProcOffset; -- update entry vector, etc. PieceTable.SetVPos[procPosition, @vicinity]; -- we are at the catch entry vector cLength ← PieceTable.GetWord[]; THROUGH [0..cLength) DO cOffset: CARDINAL = PieceTable.GetWord[]; PieceTable.Delete[-2]; PieceTable.PutWord[cOffset + delta]; ENDLOOP; -- wait to do enables until we are sure of no pending fixups cLength ← PieceTable.GetWord[]; IF cLength # 0 THEN cur.enablePlace ← PieceTable.GetPlace[]; END; -- now get ready to look for multiword constants IF needsFixup THEN { FixLoads[ lc: ModuleSymbols.loadCodeOffsetTable, start: [oldProcOffset], bytes: length, FixProc: FixupCodeOffset]; FixLoads[ lc: ModuleSymbols.loadCodeByteOffsetTable, start: [oldProcOffset], bytes: length, FixProc: FixupCodeByteOffset]; FixJumpImmediates[ jc: ModuleSymbols.jumpIndirectTable, start: [oldProcOffset], bytes: length]}; END; CreateNewSegment: PROC [segNode: CodePackProcs.TreeIndex] RETURNS [BOOL] = BEGIN endPosition: PieceTable.Position; base, pages: CARDINAL; desc: String.SubStringDescriptor; CodePackProcs.SubStringForSegmentNode[@desc, segNode]; IF gd.printMap THEN BEGIN WriteString["\nSegment: "L]; WriteSubString[@desc]; WriteChar['\n]; WriteChar['\n]; END; currentCodeSegment ← table.Words[BcdDefs.sgtype, SIZE[BcdDefs.SGRecord]]; currentSpaceIndex ← table.Words[BcdDefs.sptype, SIZE[BcdDefs.SPRecord]]; spb[currentSpaceIndex] ← [ name: BcdUtilDefs.EnterName[@desc], seg: currentCodeSegment, length: 0, spaces: NULL]; segmentPosition ← PieceTable.AppendPage[]; firstCodePack ← TRUE; CodePackProcs.EnumerateCodePacks[segNode, CreateCodePack ! PackError => IF reason = SegmentTooBig THEN Error.SegmentTooLarge[error, @desc]]; IF ~firstCodePack THEN FinishCodePack[]; endPosition ← PieceTable.Length[]; base ← Inline.LongDiv[segmentPosition, Environment.bytesPerPage]; pages ← PagesForWords[(CARDINAL[endPosition - segmentPosition]+1)/2]; sgb[currentCodeSegment] ← [ class: code, file: BcdDefs.FTSelf, base: base, pages: pages, extraPages: 0]; FOR i: CARDINAL IN [0..nMods) DO mod: SeenModuleHandle = seenModules[i]; IF mod # NIL AND mod.thisSeg THEN ProcessEnables[mod]; ENDLOOP; RETURN[FALSE]; END; CreateFramePack: PROC [fpNode: CodePackProcs.TreeIndex] RETURNS [BOOL] = BEGIN fpi: BcdDefs.FPIndex = table.Words[BcdDefs.fptype, SIZE[BcdDefs.FPRecord]]; desc: String.SubStringDescriptor; name: BcdDefs.NameRecord; totalWordsWCodeLinks, totalWordsWFrameLinks, inLastPage: CARDINAL ← 0; AddModToPack: PROC [mti: BcdDefs.MTIndex] RETURNS [BOOL] = { n: CARDINAL = fpb[fpi].length; offset: CARDINAL ← 0; [] ← table.Words[BcdDefs.fptype, SIZE[BcdDefs.MTIndex]]; fpb[fpi].modules[n] ← mti; fpb[fpi].length ← n+1; IF gd.printMap THEN { mth: BcdOps.MTHandle = @mtb[mti]; linkArea: CARDINAL = (IF mth.links # BcdDefs.LFNull THEN lfb[mth.links].length*SIZE[BcdDefs.Link] ELSE 0); -- print frame size and offset assuming codelinks IF (mth.linkLoc = code AND mth.code.linkspace) THEN offset ← ((totalWordsWCodeLinks+3)/4)*4 ELSE -- links before frame offset ← ((totalWordsWCodeLinks + linkArea+3)/4)*4; WriteNumber[mth.framesize, Decimal6]; WriteNumber[offset, Octal7]; WriteChar['B]; totalWordsWCodeLinks ← offset + mth.framesize; -- now, assuming framelinks only offset ← ((totalWordsWFrameLinks + linkArea+3)/4)*4; WriteNumber[mth.framesize, Decimal6]; WriteNumber[offset, Octal7]; WriteChar['B]; totalWordsWFrameLinks ← (offset + mth.framesize); WriteString[" "L]; [] ← WriteName[mth.name]; WriteChar['\n]}; RETURN[FALSE]}; FramePackModules.SubStringForFramePackNode[@desc, fpNode]; fpb[fpi].name ← name ← BcdUtilDefs.EnterName[@desc]; IF gd.printMap THEN { WriteString["\nFrame Pack: "L]; [] ← WriteName[name]; WriteString["\nLoad description\n"L]; WriteString["w/ codelinks framelinks only\n"L]; WriteString["Length offset length offset Module\n"L]}; fpb[fpi].length ← 0; FramePackModules.EnumerateModules[fpNode, AddModToPack]; IF gd.printMap THEN { inLastPage ← totalWordsWCodeLinks MOD Environment.wordsPerPage; WriteNumber[Environment.wordsPerPage - inLastPage, Decimal6]; WriteString[" "L]; inLastPage ← totalWordsWFrameLinks MOD Environment.wordsPerPage; WriteNumber[Environment.wordsPerPage - inLastPage, Decimal6]; WriteString[" unused\n"L]; WriteNumber[PagesForWords[totalWordsWCodeLinks], Decimal6]; WriteString[" "L]; WriteNumber[PagesForWords[totalWordsWFrameLinks], Decimal6]; WriteString[" frame pack pages\n\n"L]}; RETURN[FALSE]; END; StartModule: PROC [mti: BcdDefs.MTIndex] = BEGIN mNum: SourceBcd.ModuleNum = SourceBcd.ModuleNumForMti[mti]; currentModule ← mti; cur ← seenModules[mNum]; cstb ← ModuleSymbols.constArray; firstBody ← TRUE; END; CopyEV: PROC [mti: BcdDefs.MTIndex] = BEGIN mNum: SourceBcd.ModuleNum = SourceBcd.ModuleNumForMti[mti]; mth: BcdOps.MTHandle = @mtb[mti]; cd: BcdDefs.CodeDesc ← mth.code; file: BcdDefs.FTIndex = mth.file; name: BcdDefs.NameRecord = mth.name; sgr: BcdDefs.SGRecord = SourceBcd.bcdBases.sgb[cd.sgi]; nEntries: CARDINAL = LENGTH[ModuleSymbols.outerPackArray] + LENGTH[ModuleSymbols.innerPackArray]; evWords: CARDINAL = SIZE[PrincOps.CSegPrefix] + nEntries * SIZE[PrincOps.EntryVectorItem]; oldCodeFile ← FileTable.HandleForFile[sgr.file]; oldCodeBasePosition ← 2 * (Inline.LongMult[sgr.base-1, Environment.wordsPerPage] + LONG[cd.offset]); IF mth.linkLoc = code THEN BEGIN pos: LONG CARDINAL ← PieceTable.AppendWord[]; lfi: BcdDefs.LFIndex = mth.links; fLength: CARDINAL = lfb[lfi].length; delta: CARDINAL ← (CARDINAL[Inline.LowHalf[pos]] + fLength) MOD 4; IF delta # 0 THEN delta ← 4 - delta; PieceTable.PutZeros[(fLength + delta)*2]; cd.linkspace ← TRUE; END; codeBasePosition ← PieceTable.AppendQuadWord[]; codeBaseOffset ← SegmentOffset[codeBasePosition]; IF gd.printMap THEN DisplayNumbers[ep: epEv, length: evWords*2, hti: Symbols.HTNull]; PieceTable.CopyFromFile[ file: oldCodeFile, position: oldCodeBasePosition, length: evWords*2]; evPlace ← PieceTable.GetPlace[]; -- update seenModules array entry IF LENGTH[cstb] = 0 THEN newConstants ← NIL ELSE BEGIN SetBlock: PROC [p: LONG POINTER, v: UNSPECIFIED, n: CARDINAL] = INLINE { p↑ ← v; Inline.LongCOPY[from: p, to: (p+1), nwords: (n-1)]}; newConstants ← z.NEW[WordIndexSeqBody[LENGTH[cstb]]]; SetBlock[ p: newConstants, v: NullWordIndex, n: LENGTH[cstb] * SIZE[WordIndex]]; END; cur ← z.NEW[SeenModuleRecord[nEntries] ← [ newOffset: codeBaseOffset, newPiece: evPlace.pi, oldCodeFile: oldCodeFile, oldCodePosition: oldCodeBasePosition, newConstants: newConstants]]; PieceTable.SetVPos[codeBasePosition + SIZE[PrincOps.PrefixHeader]*2]; FOR ep: NAT IN [0..nEntries) DO cur[ep] ← [oldPC: PieceTable.GetWord[], bytes: ]; ENDLOOP; FOR i: NAT IN [0..LENGTH[ModuleSymbols.outerPackArray]) DO ep: EntryIndex; bytes: CARDINAL; [entryIndex: ep, length: bytes] ← ModuleSymbols.outerPackArray[i]; cur[ep].bytes ← bytes; ENDLOOP; FOR i: NAT IN [0..LENGTH[ModuleSymbols.innerPackArray]) DO ep: EntryIndex; bytes: CARDINAL; [entryIndex: ep, length: bytes] ← ModuleSymbols.innerPackArray[i]; cur[ep].bytes ← bytes; ENDLOOP; seenModules[mNum] ← cur; -- update module table in bcd cd.offset ← codeBaseOffset; cd.sgi ← currentCodeSegment; cd.length ← 0; BEGIN -- look for all prototypes of this name desc: String.SubStringDescriptor ← [ base: @ssb.string, offset: name, length: ssb.size[name]]; cTreeNode: SourceBcd.CTreeIndex ← SourceBcd.LookupSS[@desc, prototype]; WHILE cTreeNode # SourceBcd.nullCTreeIndex DO index: SourceBcd.BcdTableLoc = cTreeNode.Index; WITH ctr: index SELECT FROM module => BEGIN pmth: BcdOps.MTHandle = @mtb[ctr.mti]; IF pmth.file = file THEN pmth.code ← cd; END; ENDCASE; cTreeNode ← cTreeNode.Prev[$prototype]; ENDLOOP; END; END; evPlace: PieceTable.Place; CopyFakeModule: PROC [mti: BcdDefs.MTIndex] = BEGIN mth: BcdOps.MTHandle = @mtb[mti]; cd: BcdDefs.CodeDesc ← mth.code; file: BcdDefs.FTIndex = mth.file; name: BcdDefs.NameRecord = mth.name; sgr: BcdDefs.SGRecord = SourceBcd.bcdBases.sgb[cd.sgi]; oldCodeFile ← FileTable.HandleForFile[sgr.file]; oldCodeBasePosition ← 2 * (Inline.LongMult[sgr.base-1, Environment.wordsPerPage] + LONG[cd.offset]); codeBasePosition ← PieceTable.AppendQuadWord[]; codeBaseOffset ← SegmentOffset[codeBasePosition]; IF gd.printMap THEN DisplayNumbers[ep: epEv, length: cd.length, hti: Symbols.HTNull]; PieceTable.CopyFromFile[ file: oldCodeFile, position: oldCodeBasePosition, length: cd.length]; IF (codeBaseOffset + cd.length) > LAST[CARDINAL] THEN PackError[SegmentTooBig]; -- update module table in bcd cd.offset ← codeBaseOffset; cd.sgi ← currentCodeSegment; cd.length ← 0; BEGIN -- look for all prototypes of this name desc: String.SubStringDescriptor ← [ base: @ssb.string, offset: name, length: ssb.size[name]]; cTreeNode: SourceBcd.CTreeIndex ← SourceBcd.LookupSS[@desc, prototype]; WHILE cTreeNode # SourceBcd.nullCTreeIndex DO index: SourceBcd.BcdTableLoc = cTreeNode.Index; WITH ctr: index SELECT FROM module => BEGIN pmth: BcdOps.MTHandle = @mtb[ctr.mti]; IF pmth.file = file THEN pmth.code ← cd; END; ENDCASE; cTreeNode ← cTreeNode.Prev[$prototype]; ENDLOOP; END; END; DiscardAllInPack: PROC [cpNode: CodePackProcs.TreeIndex] = BEGIN CodePackProcs.EnumerateModules[cpNode, DiscardThisModule]; END; DiscardThisModule: PROC [mti: BcdDefs.MTIndex, module: CodePackProcs.ModuleIndex] RETURNS [BOOL] = BEGIN StartModule[mti]; SetupCurrentOffsets[]; -- you can't discard the EV, it should be already out CodePackProcs.EnumerateProcs[module, DiscardModuleProc]; newConstants ← NIL; RETURN[FALSE] END; DiscardModuleProc: PROC [root: PackageSymbols.OPIndex] RETURNS [stop: BOOL] = BEGIN SELECT root FROM PackageSymbols.OPEntry => ERROR PackError[EVNotPlaced]; PackageSymbols.OPCatch => DiscardThisProc[LENGTH[ModuleSymbols.outerPackArray]-1]; ENDCASE => DiscardThisProc[root]; RETURN[FALSE]; END; DiscardThisProc: PROC [root: PackageSymbols.OPIndex] = BEGIN -- copy procedure (and any nested below unless main body) DiscardOneBody[ModuleSymbols.outerPackArray[root].entryIndex]; DiscardNested[root]; END; DiscardNested: PROC [root: PackageSymbols.OPIndex] = BEGIN i: PackageSymbols.IPIndex ← ModuleSymbols.outerPackArray[root].firstSon; IF i # PackageSymbols.IPNull THEN DO DiscardOneBody[ModuleSymbols.innerPackArray[i].entryIndex]; IF ModuleSymbols.innerPackArray[i].lastSon THEN EXIT; i ← i+1; ENDLOOP; END; DiscardOneBody: PROC [ep: EntryIndex] = BEGIN eviOffset: POINTER; -- fix up entry vector for module (works for catch stuff, too) eviOffset ← @(LOOPHOLE[1, POINTER TO PrincOps.CSegPrefix].entry[ep]) - 1; PieceTable.SetVPos[codeBasePosition + 2*LOOPHOLE[eviOffset, CARDINAL]]; PieceTable.Delete[2]; PieceTable.PutWord[0]; cur.discarded ← TRUE; -- something is discarded from this module END; CreateCodePack: PROC [cpNode: CodePackProcs.TreeIndex] RETURNS [BOOL] = BEGIN saveIndex: CARDINAL = gd.textIndex; offset, pages: CARDINAL; spii: Table.Base RELATIVE POINTER [0..Table.Limit) TO BcdDefs.SpaceID; name: BcdDefs.NameRecord; nameCopy: STRING ← [80]; desc: String.SubStringDescriptor; endPosition: PieceTable.Position; discard: BOOL = CodePackProcs.IsDiscardCodePack[cpNode]; gd.textIndex ← tb[LOOPHOLE[cpNode, Tree.Index]].info; CodePackProcs.SubStringForCodePackNode[@desc, cpNode]; String.AppendSubString[nameCopy, @desc]; desc ← [base: nameCopy, offset: 0, length: nameCopy.length]; name ← BcdUtilDefs.EnterName[@desc]; IF gd.printMap THEN BEGIN IF firstCodePack THEN firstCodePack ← FALSE ELSE FinishCodePack[]; WriteString["Code Pack: "L]; [] ← WriteName[name]; WriteChar['\n]; PrintHeader[]; END; currentCodePackHti ← CodePackProcs.HtiForCodePackNode[cpNode]; IF discard THEN {DiscardAllInPack[cpNode]; RETURN [FALSE]}; currentCodePackResident ← FALSE; -- set TRUE if any modules resident lastProcEnd ← codePackPosition ← PieceTable.AppendPage[]; CodePackProcs.EnumerateModules[cpNode, CopyModuleToPack]; endPosition ← PieceTable.Length[]; offset ← Inline.LongDiv[ codePackPosition - segmentPosition, Environment.bytesPerPage]; pages ← PagesForWords[(CARDINAL[endPosition - codePackPosition]+1)/2]; spii ← table.Words[BcdDefs.sptype, SIZE[BcdDefs.SpaceID]]; spb[spii] ← [ name: name, resident: currentCodePackResident, offset: offset, pages: pages]; spb[currentSpaceIndex].length ← spb[currentSpaceIndex].length + 1; gd.textIndex ← saveIndex; RETURN[FALSE] END; FinishCodePack: PROC = BEGIN endPosition: PieceTable.Position = PieceTable.Append[]; totalBytes: CARDINAL ← Inline.LowHalf[endPosition - codePackPosition]; pages: CARDINAL = (totalBytes + Environment.bytesPerPage-1)/Environment.bytesPerPage; gap: CARDINAL; delta: CARDINAL = CARDINAL[Inline.LowHalf[endPosition]] MOD Environment.bytesPerPage; IF gd.printMap THEN { IF lastProcEnd # 0 AND endPosition > lastProcEnd THEN NoteData[ offset: SegmentOffset[lastProcEnd], length: Inline.LowHalf[endPosition-lastProcEnd]]; WriteString["------------\n"L]; IF delta # 0 THEN { gap ← Environment.bytesPerPage - delta; WriteNumber[gap, Octal5]; IF gap > 7 THEN WriteChar['B] ELSE WriteChar[' ]; WriteString[" unused bytes (last page has "L]; WriteOctal[delta]; IF delta > 7 THEN WriteChar['B]; WriteString[" bytes)\n"L]}; WriteString["Code pack pages: "L]; WriteDecimal[pages]; WriteChar['\n]; WriteChar['\n]}; IF pages = 0 THEN Error.EmptyCodePack[class: error, cpId: currentCodePackHti]; firstCodePack ← FALSE; END; CopyModuleToPack: PROC [mti: BcdDefs.MTIndex, module: CodePackProcs.ModuleIndex] RETURNS [stop: BOOL] = { BEGIN currentModule ← mti; IF mtb[mti].tableCompiled THEN CopyFakeModule[mti ! FileTable.UnknownFile --[fti]-- => { Error.ErrorFile[error, "was needed for code but could not be found"L, fti]; GOTO CodeFileNotFound}] ELSE { IF mtb[mti].residentFrame THEN currentCodePackResident ← TRUE; StartModule[mti ! FileTable.UnknownFile --[fti]-- => { Error.ErrorFile[error, "was needed for code but could not be found"L, fti]; newConstants ← NIL; GOTO CodeFileNotFound}]; CodePackProcs.EnumerateProcs[module, CopyModuleBodies]; newConstants ← NIL}; EXITS CodeFileNotFound => NULL; END; RETURN[FALSE]}; ComputeCodePlacement: PUBLIC PROC = BEGIN ENABLE UNWIND => CleanupCodePlacementComputation[ ! PackError => RESUME]; Initialize[SourceBcd.moduleCount]; RemapOldBcd[]; IF gd.errors THEN RETURN; firstCodeSgi ← LOOPHOLE[table.Top[BcdDefs.sgtype]]; PieceTable.Initialize[]; firstCodePack ← TRUE; lastProcEnd ← 0; IF gd.printMap THEN { WriteString["\nFile "L]; WriteString[gd.mapFileName]; WriteString[" created by Packager from "L]; WriteString[gd.packName]; WriteString[" on "L]; WriteTime[Time.Current[]]; WriteChar['\n]}; CodePackProcs.EnumerateSegments[CreateNewSegment]; FramePackModules.EnumerateFramePacks[CreateFramePack]; IF gd.printMap AND gd.mapStream # NIL THEN { gd.mapStream.Delete[]; gd.mapStream ← NIL}; END; CleanupCodePlacementComputation: PROC = { IF gd.printMap AND gd.mapStream # NIL THEN { gd.mapStream.Delete[]; gd.mapStream ← NIL}; PieceTable.Finalize[]; Finalize[]}; WriteBcdToFile: PUBLIC PROC = BEGIN limitSgi: BcdDefs.SGIndex; bcdPages, bcdPos, size: CARDINAL; desc: String.SubStringDescriptor; byte: CARDINAL; newHeader: LONG POINTER TO BcdDefs.BCD; -- open output stream as a byte stream IF gd.errors THEN RETURN; outStream ← FileStream.Create[gd.outputBcdFile.GetFC]; -- compute size of new bcd bcdPos ← SIZE[BcdDefs.BCD]; newHeader ← z.NEW[BcdDefs.BCD ← SourceBcd.bcdHeader↑]; desc ← [base: gd.packName, offset: 0, length: gd.packName.length]; newHeader.source ← BcdUtilDefs.EnterName[@desc]; newHeader.creator ← gd.packagerVersion; newHeader.sourceVersion ← gd.packVersion; newHeader.version ← [ time: FileStream.GetLeaderProperties[outStream].create, net: gd.network, host: gd.host]; newHeader.repackaged ← TRUE; size ← table.Bounds[BcdDefs.sstype].size; newHeader.ssOffset ← bcdPos; newHeader.ssLimit ← LOOPHOLE[size]; bcdPos ← bcdPos + size; newHeader.ctOffset ← bcdPos; bcdPos ← bcdPos + LOOPHOLE[newHeader.ctLimit, CARDINAL]; newHeader.mtOffset ← bcdPos; bcdPos ← bcdPos + LOOPHOLE[newHeader.mtLimit, CARDINAL]; newHeader.lfOffset ← bcdPos; bcdPos ← bcdPos + LOOPHOLE[newHeader.lfLimit, CARDINAL]; newHeader.impOffset ← bcdPos; bcdPos ← bcdPos + LOOPHOLE[newHeader.impLimit, CARDINAL]; newHeader.expOffset ← bcdPos; bcdPos ← bcdPos + LOOPHOLE[newHeader.expLimit, CARDINAL]; newHeader.evOffset ← bcdPos; bcdPos ← bcdPos + LOOPHOLE[newHeader.evLimit, CARDINAL]; size ← table.Bounds[BcdDefs.sgtype].size; newHeader.sgOffset ← bcdPos; newHeader.sgLimit ← LOOPHOLE[size]; bcdPos ← bcdPos + size; size ← table.Bounds[BcdDefs.fttype].size; newHeader.ftOffset ← bcdPos; newHeader.ftLimit ← LOOPHOLE[size]; bcdPos ← bcdPos + size; size ← table.Bounds[BcdDefs.sptype].size; newHeader.spOffset ← bcdPos; newHeader.spLimit ← LOOPHOLE[size]; bcdPos ← bcdPos + size; newHeader.ntOffset ← bcdPos; bcdPos ← bcdPos + LOOPHOLE[newHeader.ntLimit, CARDINAL]; newHeader.typOffset ← bcdPos; bcdPos ← bcdPos + LOOPHOLE[newHeader.typLimit, CARDINAL]; newHeader.tmOffset ← bcdPos; bcdPos ← bcdPos + LOOPHOLE[newHeader.tmLimit, CARDINAL]; size ← table.Bounds[BcdDefs.fptype].size; newHeader.fpOffset ← bcdPos; newHeader.fpLimit ← LOOPHOLE[size]; bcdPos ← bcdPos + size; bcdPages ← PagesForWords[bcdPos]; newHeader.nPages ← bcdPages; limitSgi ← LOOPHOLE[table.Top[BcdDefs.sgtype]]; FOR sgi: BcdDefs.SGIndex ← firstCodeSgi, sgi+SIZE[BcdDefs.SGRecord] UNTIL sgi = limitSgi DO sgb[sgi].base ← sgb[sgi].base + bcdPages + 1; ENDLOOP; -- write bcd to stream [] ← PutBlock[ outStream, newHeader, SIZE[BcdDefs.BCD]]; [] ← PutBlock[ outStream, table.Bounds[BcdDefs.sstype].base, LOOPHOLE[newHeader.ssLimit]]; [] ← PutBlock[ outStream, table.Bounds[BcdDefs.cttype].base, LOOPHOLE[newHeader.ctLimit]]; [] ← PutBlock[ outStream, table.Bounds[BcdDefs.mttype].base, LOOPHOLE[newHeader.mtLimit]]; [] ← PutBlock[ outStream, SourceBcd.bcdHeader + SourceBcd.bcdHeader.lfOffset, LOOPHOLE[newHeader.lfLimit]]; [] ← PutBlock[ outStream, table.Bounds[BcdDefs.imptype].base, LOOPHOLE[newHeader.impLimit]]; [] ← PutBlock[ outStream, table.Bounds[BcdDefs.exptype].base, LOOPHOLE[newHeader.expLimit]]; [] ← PutBlock[ outStream, SourceBcd.bcdHeader + SourceBcd.bcdHeader.evOffset, LOOPHOLE[newHeader.evLimit]]; [] ← PutBlock[ outStream, table.Bounds[BcdDefs.sgtype].base, LOOPHOLE[newHeader.sgLimit]]; [] ← PutBlock[ outStream, table.Bounds[BcdDefs.fttype].base, LOOPHOLE[newHeader.ftLimit]]; [] ← PutBlock[ outStream, table.Bounds[BcdDefs.sptype].base, LOOPHOLE[newHeader.spLimit]]; [] ← PutBlock[ outStream, table.Bounds[BcdDefs.nttype].base, LOOPHOLE[newHeader.ntLimit]]; [] ← PutBlock[ outStream, SourceBcd.bcdHeader + SourceBcd.bcdHeader.typOffset, LOOPHOLE[newHeader.typLimit]]; [] ← PutBlock[ outStream, SourceBcd.bcdHeader + SourceBcd.bcdHeader.tmOffset, LOOPHOLE[newHeader.tmLimit]]; [] ← PutBlock[ outStream, table.Bounds[BcdDefs.fptype].base, LOOPHOLE[newHeader.fpLimit]]; z.FREE[@newHeader]; -- fill out to a page boundary byte ← Inline.LongDivMod[ num: FileStream.GetIndex[outStream], den: Environment.bytesPerPage].remainder; IF byte # 0 THEN THROUGH (byte..Environment.bytesPerPage] DO outStream.PutByte[0]; ENDLOOP; -- throw out allocator space and source bcd END; PutBlock: PROC [stream: Stream.Handle, p: LONG POINTER, n: CARDINAL] = { stream.PutBlock[[LOOPHOLE[p], 0, n*Environment.bytesPerWord]]}; WriteCodeToBcdFile: PUBLIC PROC = BEGIN ENABLE UNWIND => { PieceTable.Finalize[]; Finalize[]}; -- close piece table IF ~gd.errors THEN PieceTable.Store[outStream] ELSE PieceTable.Finalize[]; outStream.Delete[]; outStream ← NIL; Finalize[]; END; -- procedures to create new name, file, and segment tables for output bcd -- update source bcd in place, creating new tables: -- name table (ssb), file table, and segment table -- after this update, the following is true: -- All "name" fields refer to new NameRecords -- In module table, -- "sseg" refers to new segment table -- "code.sgi" refers to old segment table -- In new segment table, "file" refers to new file table -- In old segment table, "file" refers to old file table PrintHeader: PROC = BEGIN -- should print bcd version in file WriteString["Bytes EVI Offset IPC Module"L]; THROUGH [("Module"L).length..modCols] DO WriteChar[' ] ENDLOOP; WriteString["Procedure\n\n"L]; END; -- ** Loadmap stuff modCols: CARDINAL ← 20; Decimal4: CharIO.NumberFormat = [base: 10, zerofill: FALSE, unsigned: TRUE, columns: 4]; Decimal5: CharIO.NumberFormat = [base: 10, zerofill: FALSE, unsigned: TRUE, columns: 5]; Decimal6: CharIO.NumberFormat = [base: 10, zerofill: FALSE, unsigned: TRUE, columns: 6]; Octal5: CharIO.NumberFormat = [base: 8, zerofill: FALSE, unsigned: TRUE, columns: 5]; Octal7: CharIO.NumberFormat = [base: 8, zerofill: FALSE, unsigned: TRUE, columns: 7]; NoteData: PROC [offset, length: CARDINAL] = BEGIN WriteNumber[length, Decimal5]; WriteString[" -"L]; WriteNumber[offset, Octal7]; WriteChar['B]; WriteString[" <data>\n"L]; END; epEv: INTEGER = -1; epCatch: INTEGER = -2; epLinks: INTEGER = -3; DisplayNumbers: PROC [ep: INTEGER, length: CARDINAL, hti: Symbols.HTIndex] = BEGIN -- write out module, entry, segOffset, codeOffset -- called when codeBasePosition and segmentPosition are valid pos: PieceTable.Position ← PieceTable.Append[]; offset, cols: CARDINAL; IF lastProcEnd # 0 AND pos > lastProcEnd THEN NoteData[ offset: SegmentOffset[lastProcEnd], length: Inline.LowHalf[pos-lastProcEnd]]; lastProcEnd ← pos + length; WriteNumber[length, Octal5]; IF length > 7 THEN WriteChar['B] ELSE WriteChar[' ]; SELECT ep FROM epEv => WriteString[" EV"L]; epCatch => WriteString[" Cat"L]; epLinks => WriteString[" LNKS"L]; ENDCASE => WriteNumber[ep, Decimal5]; offset ← Inline.LowHalf[pos - segmentPosition]; WriteNumber[offset, Octal7]; WriteChar['B]; IF ep = epEv OR ep = epLinks THEN WriteString[" "L] ELSE BEGIN offset ← CodeByteOffset[pos]; WriteNumber[offset, Octal7]; WriteChar['B]; END; WriteString[" "L]; cols ← WriteName[mtb[currentModule].name]; IF ep >= 0 THEN BEGIN THROUGH [cols..modCols) DO WriteChar[' ] ENDLOOP; WriteChar[' ]; IF ep = 0 THEN WriteString["MAIN"L] ELSE IF hti = Symbols.HTNull THEN WriteString[" <nested>"L] ELSE [] ← WriteProcName[hti] END; WriteChar['\n]; END; WriteName: PROC [name: BcdDefs.NameRecord] RETURNS [length: CARDINAL] = BEGIN desc: String.SubStringDescriptor; desc ← [base: @ssb.string, offset: name, length: ssb.size[name]]; WriteSubString[@desc]; RETURN [desc.length]; END; WriteProcName: PROC [hti: Symbols.HTIndex] RETURNS [length: CARDINAL] = BEGIN desc: String.SubStringDescriptor; IF hti = Symbols.HTNull THEN RETURN[0]; SymbolOps.SubStringForHash[@desc, hti]; WriteSubString[@desc]; RETURN [desc.length]; END; END.