-- 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.