-- file OutCode.mesa -- last modified by Sweet, July 29, 1982 3:54 pm -- last modified by Satterthwaite, January 11, 1983 4:59 pm DIRECTORY Alloc: TYPE USING [Notifier], CatchFormat: TYPE USING [EnableItem], Code: TYPE USING [codeptr, enableList], CodeDefs: TYPE USING [ Base, BYTE, CCIndex, CCItem, CCNull, codeType, EINull, EnableIndex, LabelCCIndex, NULLfileindex, TableCodeBytes], ComData: TYPE USING [ catchBytes, catchIndex, codeByteOffsetList, codeOffsetList, codeSeg, fgTable, globalFrameSize, jumpIndirectList, linkCount, mtRoot, nBodies, nSigCodes, stopping, switches, zone], CompilerUtil: TYPE USING [AcquireStream, NextFilePage, ReleaseStream], Environment: TYPE USING [bytesPerPage, wordsPerPage], FileStream: TYPE USING [FileByteIndex, GetIndex, SetIndex], Fixup: TYPE USING [JIHandle, JIRec, PCHandle, PCRec], FOpCodes: TYPE USING [qBLTC, qLCO, qGA, qLA], Literals: TYPE USING [Base, MSTIndex, STIndex, stType], LiteralOps: TYPE USING [EnumerateLocalStrings, EnumerateMasterStrings], Log: TYPE USING [ErrorTree], Mopcodes: TYPE USING [zJIB, zJIW, zLIW], OSMiscOps: TYPE USING [FreePages, FreeWords, Pages, Words], P5: TYPE USING [C1W, P5Error], P5U: TYPE USING [ FreeChunk, Out0, Out1, ComputeFrameSize, PushLitVal, RecordConstant, WordsForString], PrincOps: TYPE USING [ AVHeapSize, BytePC, CSegPrefix, EntryVectorItem, EPRange, GlobalOverhead, MaxFrameSize], Stack: TYPE USING [Dump], Stream: TYPE USING [Block, Handle, PutBlock, PutByte, PutWord], Symbols: TYPE USING [Base, BodyInfo, bodyType, CBTIndex, RootBti], SymbolSegment: TYPE USING [FGTEntry, ObjectStep, SourceStep, Stride]; OutCode: PROGRAM IMPORTS MPtr: ComData, CPtr: Code, CompilerUtil, FileStream, LiteralOps, Log, OSMiscOps, P5, P5U, Stack, Stream EXPORTS CodeDefs, P5 = BEGIN OPEN CodeDefs; -- imported definitions Address: TYPE = CARDINAL; PageSize: CARDINAL = Environment.wordsPerPage; BodyInfo: TYPE = Symbols.BodyInfo; CBTIndex: TYPE = Symbols.CBTIndex; FGTEntry: TYPE = SymbolSegment.FGTEntry; STIndex: TYPE = Literals.STIndex; MSTIndex: TYPE = Literals.MSTIndex; cb: CodeDefs.Base; -- code base (local copy) bb: Symbols.Base; stb: Literals.Base; OutCodeNotify: PUBLIC Alloc.Notifier = BEGIN -- called by allocator whenever table area is repacked cb ← base[codeType]; bb ← base[Symbols.bodyType]; stb ← base[Literals.stType]; END; FileSequenceError: SIGNAL = CODE; ByteBlock: PROC [base: LONG POINTER, nw: CARDINAL] RETURNS [Stream.Block] = INLINE { RETURN [[LOOPHOLE[base], 0, 2*nw]]}; StreamIndex: TYPE = FileStream.FileByteIndex; fgt: LONG DESCRIPTOR FOR ARRAY OF FGTEntry; fgti: INTEGER; fgtPages: CARDINAL; LabelPcInfo: TYPE = RECORD [label: LabelCCIndex, pc: Address]; LabelPcSeq: TYPE = RECORD [ count: NAT, data: SEQUENCE max: [0 .. NAT.LAST/LabelPcInfo.SIZE) OF LabelPcInfo]; LabelPcList: TYPE = LONG POINTER TO LabelPcSeq; labelPcList: LabelPcList ← NIL; SetLabelPc: PROC [label: LabelCCIndex, pc: Address] = BEGIN count: NAT ← IF labelPcList = NIL THEN 0 ELSE labelPcList.count; FOR i: NAT IN [0..count) DO IF labelPcList[i].label = label THEN {labelPcList[i].pc ← pc; RETURN}; ENDLOOP; IF labelPcList = NIL OR count = labelPcList.max THEN { new: LabelPcList ← MPtr.zone.NEW[LabelPcSeq[count+20] ← [count: count, data:]]; FOR j: NAT IN [0..count) DO new[j] ← labelPcList[j] ENDLOOP; IF labelPcList # NIL THEN MPtr.zone.FREE[@labelPcList]; labelPcList ← new}; labelPcList[count] ← [label: label, pc: pc]; labelPcList.count ← count+1; END; GetLabelPc: PROC [label: LabelCCIndex] RETURNS [Address] = BEGIN IF labelPcList = NIL THEN ERROR; FOR i: NAT IN [0..labelPcList.count) DO IF labelPcList[i].label = label THEN RETURN [labelPcList[i].pc]; ENDLOOP; ERROR; END; objectStream: Stream.Handle ← NIL; codeBase: StreamIndex; entryVector: LONG DESCRIPTOR FOR ARRAY OF PrincOps.EntryVectorItem; catchEntry: LONG DESCRIPTOR FOR ARRAY OF PrincOps.BytePC; codeByteIndex: CARDINAL; lastObject, lastSource: CARDINAL; StartCodeFile: PUBLIC PROC = BEGIN -- called to set up bodytable and init binary file header OPEN MPtr, PrincOps; nGfi: CARDINAL = (MAX[nBodies, nSigCodes] + (PrincOps.EPRange-1))/PrincOps.EPRange; IF ~(nGfi IN [1..4]) THEN P5.P5Error[833]; IF linkCount > 377B THEN P5.P5Error[834]; objectStream ← CompilerUtil.AcquireStream[object]; codeSeg.base ← CompilerUtil.NextFilePage[]; fgti ← -1; fgtPages ← 1; IF mtRoot.code.offset # 0 THEN BEGIN objectStream.PutWord[mtRoot.code.offset]; THROUGH (1..mtRoot.code.offset] DO objectStream.PutWord[0] ENDLOOP; END; codeBase ← FileStream.GetIndex[objectStream]; codeByteIndex ← (CSegPrefix.SIZE+nBodies*EntryVectorItem.SIZE+1)*2; FileStream.SetIndex[objectStream, codeBase + codeByteIndex]; fgt ← DESCRIPTOR[OSMiscOps.Pages[fgtPages], (fgtPages*PageSize)/FGTEntry.SIZE]; entryVector ← DESCRIPTOR[ OSMiscOps.Words[nBodies*EntryVectorItem.SIZE], nBodies]; catchEntry ← DESCRIPTOR [ OSMiscOps.Words[MPtr.catchIndex*PrincOps.BytePC.SIZE], MPtr.catchIndex]; firstCatch ← lastCatch ← CCNull; END; MoveToCodeWord: PUBLIC PROC RETURNS [CARDINAL] = BEGIN IF codeByteIndex MOD 2 = 1 THEN { objectStream.PutByte[377B]; codeByteIndex ← codeByteIndex+1}; RETURN [codeByteIndex/2] END; WriteCodeWord: PUBLIC PROC [w: WORD] = BEGIN IF codeByteIndex MOD 2 = 1 THEN P5.P5Error[835]; objectStream.PutWord[w]; codeByteIndex ← codeByteIndex+2; END; WriteCodeByte: PROC [b: BYTE] = { objectStream.PutByte[b]; codeByteIndex ← codeByteIndex+1}; NewFgtEntry: PROC [source, object: CARDINAL] = BEGIN -- enters new value into fgt AddEntry: PROC [e: SymbolSegment.FGTEntry] = BEGIN IF (fgti ← fgti+1) >= fgt.LENGTH THEN BEGIN oldfgt: LONG DESCRIPTOR FOR ARRAY OF FGTEntry ← fgt; fgtPages ← fgtPages+1; fgt ← DESCRIPTOR[ OSMiscOps.Pages[fgtPages], (fgtPages*PageSize)/FGTEntry.SIZE]; FOR i: CARDINAL IN [0..oldfgt.LENGTH) DO fgt[i] ← oldfgt[i] ENDLOOP; OSMiscOps.FreePages[oldfgt.BASE]; END; fgt[fgti] ← e; END; t: CARDINAL; dSource: CARDINAL ← source - lastSource; dObject: CARDINAL ← object - lastObject; WHILE dSource > SymbolSegment.SourceStep DO t ← MIN[dSource, SymbolSegment.Stride]; AddEntry[[step[which: source, delta: t]]]; dSource ← dSource - t; ENDLOOP; WHILE dObject > SymbolSegment.ObjectStep DO t ← MIN[dObject, SymbolSegment.Stride]; AddEntry[[step[which: object, delta: t]]]; dObject ← dObject - t; ENDLOOP; AddEntry[[normal[deltaObject: dObject, deltaSource: dSource]]]; lastSource ← source; lastObject ← object; END; OutJumpTables: PUBLIC PROC [start: CCIndex] RETURNS [bodyStart: Address] = BEGIN -- outputs binary bytes starting at start c, cj: CCIndex; offset: CARDINAL; byteTable: BOOL; bodyStart ← codeByteIndex; offset ← bodyStart; FOR c ← start, cb[c].flink UNTIL c = CCNull DO WITH cc:cb[c] SELECT FROM code => offset ← offset + cc.isize; other => WITH cc SELECT FROM table => BEGIN offset ← offset + TableCodeBytes; taboffset ← MoveToCodeWord[]; byteTable ← btab ← ByteableJumps[flink]; FOR cj ← flink, cb[cj].flink DO WITH cb[cj] SELECT FROM jump => IF jtype = JumpC THEN BEGIN -- jBytes is surprisingly correct for both forward -- and backward jumps. jBytes: INTEGER ← cb[destlabel].pc - pc+1; jBytes ← jBytes+2; IF byteTable THEN WriteCodeByte[jBytes] ELSE WriteCodeWord[jBytes]; END ELSE EXIT; ENDCASE => EXIT; ENDLOOP; IF byteTable THEN [] ← MoveToCodeWord[]; bodyStart ← codeByteIndex; END; ENDCASE; ENDCASE; ENDLOOP; END; OutChunks: PUBLIC PROC [start: CCIndex] = BEGIN -- outputs binary bytes for body bti starting at start c, nextC: CCIndex; offset, nw: CARDINAL; bodyStart: Address ← codeByteIndex; labelToKeep: BOOL; offset ← bodyStart; FOR c ← start, nextC UNTIL c = CCNull DO labelToKeep ← FALSE; WITH cc:cb[c] SELECT FROM code => BEGIN IF ~cc.realinst THEN ERROR; SELECT cc.isize FROM 0 => IF cc.realinst THEN ERROR; 1 => BEGIN WriteCodeByte[cc.inst]; END; 2 => BEGIN WriteCodeByte[cc.inst]; WriteCodeByte[cc.parameters[1]]; END; 3 => BEGIN IF cc.inst = Mopcodes.zLIW AND cc.lco THEN { new: Fixup.PCHandle = MPtr.zone.NEW [Fixup.PCRec ← [ pc: [offset], next: ]]; IF MPtr.codeOffsetList = NIL THEN new.next ← new ELSE { new.next ← MPtr.codeOffsetList.next; MPtr.codeOffsetList.next ← new}; MPtr.codeOffsetList ← new; fixupThisProc ← TRUE}; WriteCodeByte[cc.inst]; WriteCodeByte[cc.parameters[1]]; WriteCodeByte[cc.parameters[2]]; END; ENDCASE => -- only from MACHINE CODE inlines BEGIN WriteCodeByte[cc.inst]; FOR i: CARDINAL IN [1..cc.isize) DO WriteCodeByte[cc.parameters[i]] ENDLOOP; END; offset ← offset+cc.isize; END; label => IF cc.offsetLoaded THEN {SetLabelPc[label: LOOPHOLE[c], pc: offset]; labelToKeep ← TRUE}; jump => IF cc.jtype = JumpLIO THEN BEGIN val: RECORD [SELECT OVERLAID * FROM card => [c: CARDINAL], pair => [b1, b2: [0..256)], ENDCASE]; new: Fixup.PCHandle = MPtr.zone.NEW [Fixup.PCRec ← [ pc: [offset], next: ]]; IF MPtr.codeByteOffsetList = NIL THEN new.next ← new ELSE { new.next ← MPtr.codeByteOffsetList.next; MPtr.codeByteOffsetList.next ← new}; MPtr.codeByteOffsetList ← new; val.c ← GetLabelPc[cc.destlabel]; WriteCodeByte[Mopcodes.zLIW]; WriteCodeByte[val.b1]; WriteCodeByte[val.b2]; offset ← offset + 3; fixupThisProc ← TRUE; END; other => WITH cc SELECT FROM table => BEGIN new: Fixup.JIHandle = MPtr.zone.NEW [Fixup.JIRec ← [ pc: [offset], tableSize: tableSize, next: ]]; IF MPtr.jumpIndirectList = NIL THEN new.next ← new ELSE { new.next ← MPtr.jumpIndirectList.next; MPtr.jumpIndirectList.next ← new}; MPtr.jumpIndirectList ← new; CPtr.codeptr ← c; P5.C1W[IF btab THEN Mopcodes.zJIB ELSE Mopcodes.zJIW, taboffset]; fixupThisProc ← TRUE; END; markbody => IF start THEN BEGIN -- immediately prior chunk was source unless catch WITH br: bb[index] SELECT FROM Other => br.relOffset ← offset - bodyStart; Callable => WITH brc: br SELECT FROM Catch => { catchEntry[brc.index] ← [offset]; lastSource ← brc.sourceIndex; lastObject ← bodyStart ← offset; NewFgtEntry[lastSource, lastObject]}; -- a [0,0] for this body ENDCASE => ERROR; ENDCASE => ERROR; bb[index].info ← BodyInfo[External[bytes: , startIndex: fgti, indexLength: ]]; END ELSE BEGIN WITH bi: bb[index].info SELECT FROM External => BEGIN bi.indexLength ← fgti-bi.startIndex+1; WITH br: bb[index] SELECT FROM Other => bi.bytes ← offset - br.relOffset - bodyStart; Callable => WITH brc: br SELECT FROM Catch => bi.bytes ← offset - catchEntry[brc.index]; ENDCASE => ERROR; ENDCASE => ERROR; END; ENDCASE; END; markCatch => IF start THEN cb[index].startPC ← offset ELSE cb[index].bytes ← offset - cb[index].startPC; source => IF index # NULLfileindex THEN BEGIN IF index > lastSource OR (index = lastSource AND offset # lastObject) THEN NewFgtEntry[index, offset]; END; ENDCASE; ENDCASE; nextC ← cb[c].flink; IF ~labelToKeep THEN { nw ← WITH cc: cb[c] SELECT FROM code => MAX[cc.isize, 1]-1 + CCItem.code.SIZE, label => CCItem.label.SIZE, jump => CCItem.jump.SIZE, other => CCItem.other.SIZE, ENDCASE => ERROR; P5U.FreeChunk[c, nw]}; ENDLOOP; END; fixupThisProc: BOOL; OutBinary: PUBLIC PROC [bti: CBTIndex, start: CCIndex] = BEGIN -- outputs binary bytes for body bti starting at start e, fs: CARDINAL; bodyStart: Address; fixupThisProc ← FALSE; bodyStart ← OutJumpTables[start]; RemoveCatchCode[start]; e ← bb[bti].entryIndex; lastSource ← bb[bti].sourceIndex; lastObject ← bodyStart; WITH bi: bb[bti].info SELECT FROM Internal => BEGIN fs ← P5U.ComputeFrameSize[bi.frameSize]; IF bb[bti].resident THEN fs ← fs+PrincOps.AVHeapSize; END; ENDCASE => P5.P5Error[836]; NewFgtEntry[source: lastSource, object: lastObject]; -- put out [0,0] entryVector[e].pc ← [bodyStart]; bb[bti].info ← BodyInfo[External[bytes: , startIndex: fgti, indexLength: ]]; WriteCodeByte[fs]; OutChunks[start]; WITH bb[bti].info SELECT FROM External => { indexLength ← fgti - startIndex+1; bytes ← codeByteIndex - bodyStart}; ENDCASE; -- bb[bti].hints.needsFixup ← fixupThisProc; END; RemoveCatchCode: PROC [start: CCIndex] = BEGIN c: CCIndex; FOR c ← start, cb[c].flink UNTIL c = CCNull DO WITH cc:cb[c] SELECT FROM other => WITH cc SELECT FROM markbody => IF start THEN BEGIN WITH br: bb[index] SELECT FROM Other => NULL; Callable => WITH brc: br SELECT FROM Catch => {DelinkCatch[c]; RETURN}; ENDCASE; ENDCASE; END; ENDCASE; ENDCASE; ENDLOOP; END; firstCatch, lastCatch: CCIndex; DelinkCatch: PROC [c: CCIndex] = BEGIN prev: CCIndex = cb[c].blink; IF firstCatch = CCNull THEN firstCatch ← c ELSE cb[lastCatch].flink ← c; cb[c].blink ← lastCatch; cb[prev].flink ← CCNull; lastCatch ← c; WHILE cb[lastCatch].flink # CCNull DO lastCatch ← cb[lastCatch].flink; ENDLOOP; END; ByteableJumps: PROC [j: CCIndex] RETURNS [BOOL] = BEGIN DO WITH cb[j] SELECT FROM jump => IF jtype = JumpC THEN BEGIN jBytes: INTEGER = cb[destlabel].pc - pc + 3; IF ~forward OR jBytes > BYTE.LAST THEN RETURN [FALSE]; j ← cb[j].flink; END ELSE RETURN [TRUE]; ENDCASE => RETURN [TRUE] ENDLOOP END; WriteCodeString: PROC [s: LONG POINTER, nw: CARDINAL] = BEGIN objectStream.PutBlock[ByteBlock[s, nw]]; END; ProcessGlobalStrings: PUBLIC PROC [framestart: CARDINAL] RETURNS [nextnewframe: CARDINAL] = BEGIN firstNewCode, nextNewCode: CARDINAL ← MoveToCodeWord[]; stSize, litSize: CARDINAL; DoString: PROC [msti: MSTIndex] = BEGIN nw: CARDINAL; IF stb[msti].info = 0 THEN {stb[msti].local ← TRUE; RETURN}; nw ← P5U.WordsForString[stb[msti].string.length]; stb[msti].info ← nextnewframe; nextnewframe ← nextnewframe+nw; IF nextnewframe > PrincOps.MaxFrameSize THEN Log.ErrorTree[addressOverflow, [literal[[string[msti]]]]]; stb[msti].codeIndex ← nextNewCode; nextNewCode ← nextNewCode + nw; WriteCodeString[@stb[msti].string, nw]; codeByteIndex ← codeByteIndex + 2*nw; END; -- of doglobal nextnewframe ← framestart; LiteralOps.EnumerateMasterStrings[DoString]; litSize ← nextNewCode - firstNewCode; stSize ← nextnewframe - framestart; IF litSize > 0 THEN BEGIN P5U.RecordConstant[firstNewCode, litSize]; IF stSize > 0 THEN BLTStrings[firstNewCode, stSize, framestart, FALSE]; END; END; ProcessLocalStrings: PUBLIC PROC [framestart: CARDINAL, first: STIndex] RETURNS [nextnewframe: CARDINAL] = BEGIN nStrings: CARDINAL ← 0; CountStrings: PROC [msti: MSTIndex] = BEGIN IF stb[msti].local AND stb[msti].codeIndex # 0 THEN nStrings ← nStrings+1; END; firstNewCode, nextNewCode: CARDINAL; firstCode: BOOL ← TRUE; stSize, i, nw: CARDINAL; curSize: CARDINAL ← 0; StringInfo: TYPE = RECORD [offset: CARDINAL, sti: MSTIndex]; star: LONG DESCRIPTOR FOR ARRAY OF StringInfo; InsertStrings: PROC [msti: MSTIndex] = BEGIN IF stb[msti].local THEN BEGIN co: CARDINAL = stb[msti].codeIndex; IF co # 0 THEN BEGIN FOR i ← curSize, i-1 WHILE i>0 AND co < star[i-1].offset DO star[i] ← star[i-1]; ENDLOOP; star[i] ← [co, msti]; curSize ← curSize+1; END ELSE BEGIN nw: CARDINAL = P5U.WordsForString[stb[msti].string.length]; stb[msti].info ← nextnewframe; nextnewframe ← nextnewframe+nw; IF nextnewframe > PrincOps.MaxFrameSize THEN Log.ErrorTree[addressOverflow, [literal[[string[msti]]]]]; IF firstCode THEN { firstCode ← FALSE; firstNewCode ← nextNewCode ← MoveToCodeWord[]}; stb[msti].codeIndex ← nextNewCode; nextNewCode ← nextNewCode + nw; WriteCodeString[@stb[msti].string, nw]; codeByteIndex ← codeByteIndex + nw*2; END; END; END; -- of InsertStrings nextnewframe ← framestart; LiteralOps.EnumerateLocalStrings[first, CountStrings]; IF nStrings # 0 THEN star ← DESCRIPTOR[OSMiscOps.Words[nStrings*StringInfo.SIZE], nStrings]; LiteralOps.EnumerateLocalStrings[first, InsertStrings]; stSize ← nextnewframe - framestart; IF stSize > 0 THEN BEGIN BLTStrings[firstNewCode, stSize, framestart, TRUE]; P5U.RecordConstant[firstNewCode, stSize]; END; i ← 0; WHILE i < nStrings DO framestart ← nextnewframe; nextNewCode ← firstNewCode ← star[i].offset; WHILE i < nStrings AND star[i].offset = nextNewCode DO nw ← P5U.WordsForString[stb[star[i].sti].string.length]; nextNewCode ← nextNewCode + nw; stb[star[i].sti].info ← nextnewframe; nextnewframe ← nextnewframe+nw; IF nextnewframe > PrincOps.MaxFrameSize THEN Log.ErrorTree[addressOverflow, [literal[[string[star[i].sti]]]]]; i ← i+1; ENDLOOP; stSize ← nextnewframe - framestart; BLTStrings[firstNewCode, stSize, framestart, TRUE]; ENDLOOP; IF nStrings # 0 THEN OSMiscOps.FreeWords[star.BASE]; END; BLTStrings: PROC [coffset, length, foffset: CARDINAL, local: BOOL] = BEGIN OPEN FOpCodes; Stack.Dump[]; -- though I don't see how it could be non-empty now P5U.Out1[qLCO, coffset]; P5U.PushLitVal[length]; P5U.Out1[IF local THEN qLA ELSE qGA, foffset]; P5U.Out0[qBLTC]; END; OutputCatchBodies: PROC = BEGIN IF firstCatch # CCNull THEN OutChunks[firstCatch]; MPtr.catchBytes ← codeByteIndex - 2*catchOffset; -- count CEV, etc END; OutputCatchTables: PROC = BEGIN maxLevel: CARDINAL = CPtr.enableList.LENGTH-1; OutEnableLevel: PROC [i: CARDINAL] = BEGIN n: CARDINAL ← 0; ei: EnableIndex; ee: CatchFormat.EnableItem; lei: EnableIndex = CPtr.enableList[i]; lnei: EnableIndex; FOR ei ← lei, cb[ei].next UNTIL ei = EINull DO n ← n+1; ENDLOOP; WriteCodeWord[n]; FOR ei ← lei, cb[ei].next UNTIL ei = EINull DO ee ← [ start: [cb[ei].startPC], length: cb[ei].bytes, index: bb[cb[ei].bti].index, alsoNested: FALSE]; IF i < maxLevel AND (lnei ← CPtr.enableList[i+1]) # EINull THEN BEGIN -- look for nexted catch phrases FOR nei: EnableIndex ← lnei, cb[nei].next UNTIL nei = EINull DO ns: CARDINAL = cb[nei].startPC; IF ns >= ee.start THEN { IF ns < ee.start + ee.length THEN ee.alsoNested ← TRUE; EXIT}; ENDLOOP; END; [] ← objectStream.PutBlock[ByteBlock[@ee, CatchFormat.EnableItem.SIZE]]; ENDLOOP; END; SortEnableLists[]; WriteCodeWord[catchEntry.LENGTH]; IF catchEntry.LENGTH # 0 THEN [] ← objectStream.PutBlock[ ByteBlock[catchEntry.BASE, catchEntry.LENGTH*PrincOps.BytePC.SIZE]]; IF CPtr.enableList[0] = EINull THEN WriteCodeWord[0]; FOR l: CARDINAL IN [0..maxLevel] WHILE CPtr.enableList[l] # EINull DO OutEnableLevel[l]; ENDLOOP; END; SortEnableLists: PROC = { FOR l: CARDINAL IN [0..CPtr.enableList.LENGTH) WHILE CPtr.enableList[l] # EINull DO new: EnableIndex ← EINull; next: EnableIndex; -- do simple insertion sort of each list FOR ei: EnableIndex ← CPtr.enableList[l], next UNTIL ei = EINull DO next ← cb[ei].next; IF new = EINull OR cb[ei].startPC < cb[new].startPC THEN {cb[ei].next ← new; new ← ei} ELSE { prevEi: EnableIndex ← new; WHILE cb[prevEi].next # EINull AND cb[cb[prevEi].next].startPC < cb[ei].startPC DO prevEi ← cb[prevEi].next; ENDLOOP; cb[ei].next ← cb[prevEi].next; cb[prevEi].next ← ei}; CPtr.enableList[l] ← new; ENDLOOP; ENDLOOP}; catchOffset: CARDINAL; EndCodeFile: PUBLIC PROC RETURNS [nbytes: CARDINAL] = BEGIN OPEN PrincOps; maxLevel: CARDINAL = CPtr.enableList.LENGTH-1; saveindex, catchIndex: StreamIndex; noCatch: BOOL = (catchEntry.LENGTH = 0); ctSize: CARDINAL ← 1 + catchEntry.LENGTH*PrincOps.BytePC.SIZE + 1; prefix: CSegPrefix; nGfi: CARDINAL = (MAX[MPtr.nBodies, MPtr.nSigCodes] + (EPRange-1))/EPRange; fs: CARDINAL; IF nGfi NOT IN [1..4] THEN P5.P5Error[833]; IF noCatch THEN {catchOffset ← 0; MPtr.catchBytes ← 0} ELSE { lei: EnableIndex; catchOffset ← MoveToCodeWord[]; catchIndex ← FileStream.GetIndex[objectStream]; FOR l: CARDINAL IN [0..maxLevel] WHILE (lei ← CPtr.enableList[l]) # EINull DO IF l # 0 THEN ctSize ← ctSize + 1; FOR ei: EnableIndex ← lei, cb[ei].next WHILE ei # EINull DO ctSize ← ctSize + CatchFormat.EnableItem.SIZE; ENDLOOP; ENDLOOP; codeByteIndex ← codeByteIndex + ctSize*2; -- make room for catch entry, enables FileStream.SetIndex[objectStream, codeBase + codeByteIndex]; OutputCatchBodies[]}; MPtr.mtRoot.code.length ← codeByteIndex; [] ← MoveToCodeWord[]; saveindex ← FileStream.GetIndex[objectStream]; IF ~noCatch THEN { FileStream.SetIndex[objectStream, catchIndex]; codeByteIndex ← catchOffset*2; OutputCatchTables[]}; MPtr.fgTable ← DESCRIPTOR[fgt.BASE, fgti+1]; MPtr.codeSeg.pages ← (2*MPtr.mtRoot.code.offset + MPtr.mtRoot.code.length + (Environment.bytesPerPage-1))/ Environment.bytesPerPage; FileStream.SetIndex[objectStream, codeBase]; fs ← P5U.ComputeFrameSize[MPtr.globalFrameSize]; IF bb[Symbols.RootBti].resident THEN fs ← fs+PrincOps.AVHeapSize; prefix ← [ header: [ globalFsi: fs, nEntries: MPtr.nBodies, info: [ available: 0, stops: MPtr.stopping, ngfi: nGfi, nlinks: MPtr.linkCount]], entry: NULL]; [] ← objectStream.PutBlock[ByteBlock[@prefix, CSegPrefix.SIZE]]; [] ← objectStream.PutBlock[ ByteBlock[entryVector.BASE, entryVector.LENGTH*PrincOps.EntryVectorItem.SIZE]]; objectStream.PutWord[catchOffset*2]; OSMiscOps.FreeWords[entryVector.BASE]; OSMiscOps.FreeWords[catchEntry.BASE]; MPtr.mtRoot.framesize ← MPtr.globalFrameSize + PrincOps.GlobalOverhead.SIZE; MPtr.mtRoot.crossJumped ← MPtr.switches['j]; FileStream.SetIndex[objectStream, saveindex]; CompilerUtil.ReleaseStream[object]; objectStream ← NIL; IF labelPcList # NIL THEN { FOR i: NAT IN [0..labelPcList.count) DO P5U.FreeChunk[labelPcList[i].label, CCItem.label.SIZE]; ENDLOOP; MPtr.zone.FREE[@labelPcList]}; IF MPtr.codeOffsetList # NIL THEN { p: Fixup.PCHandle = MPtr.codeOffsetList.next; MPtr.codeOffsetList.next ← NIL; MPtr.codeOffsetList ← p}; IF MPtr.codeByteOffsetList # NIL THEN { p: Fixup.PCHandle = MPtr.codeByteOffsetList.next; MPtr.codeByteOffsetList.next ← NIL; MPtr.codeByteOffsetList ← p}; IF MPtr.jumpIndirectList # NIL THEN { j: Fixup.JIHandle = MPtr.jumpIndirectList.next; MPtr.jumpIndirectList.next ← NIL; MPtr.jumpIndirectList ← j}; RETURN [MPtr.mtRoot.code.length] END; END.