ObjectOut.Mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Satterthwaite, May 8, 1986 4:41:52 pm PDT
Sweet, September 2, 1980 3:05 PM
Maxwell, August 11, 1983 8:38 am
Rovner, November 21, 1983 11:11 am
Russ Atkinson (RRA) March 6, 1985 9:58:17 pm PST
DIRECTORY
Alloc: TYPE USING [Base, Handle, Notifier, AddNotify, DropNotify, Bounds, Failure, Top],
Basics: TYPE USING [bytesPerWord, RawBytes],
BcdDefs: TYPE USING [SGRecord, VersionStamp, FTNull, PageSize],
ComData: TYPE USING [compilerVersion, codeSeg, defBodyLimit, fgTable, fixupLoc, globalFrameSize, importCtx, interface, mainCtx, moduleCtx, mtRoot, mtRootSize, nBodies, nInnerBodies, objectBytes, objectVersion, ownSymbols, source, symSeg, typeAtomRecord],
CompilerUtil: TYPE USING [Address],
ConvertUnsafe: TYPE USING [SubString, AppendSubStringToRefText],
FileParms: TYPE USING [Name],
IO: TYPE USING [GetIndex, SetIndex, STREAM, UnsafePutBlock],
Literals: TYPE USING [Base, STNull],
LiteralOps: TYPE USING [CopyLiteral, ForgetEntries, StringValue, TextType],
OSMiscOps: TYPE USING [FreePages, FreeWords, Words],
PackageSymbols: TYPE USING [OuterPackRecord, InnerPackRecord, IPIndex, IPNull],
PrincOpsUtils: TYPE USING [LongCopy],
RCMap: TYPE USING [Base],
RCMapOps: TYPE USING [RCMT, Acquire, Create, Destroy, GetSpan],
Rope: TYPE USING [Flatten, Length, Text],
RTBcd: TYPE USING [RefLitItem, RefLitList, RTHeader, StampIndex, StampList,TypeItem, TypeList, UTInfo, AnyStamp],
Symbols: TYPE USING [Base, HashVector, Name, Type, MDIndex, BodyInfo, BTIndex, MDNull, OwnMdi, BTNull, RootBti, lL],
SymbolSegment: TYPE USING [Base, FGHeader, FGTEntry, ExtRecord, ExtIndex, STHeader, WordOffset, VersionID, ltType, htType, ssType, seType, ctxType, mdType, bodyType, extType, constType],
SymbolOps: TYPE USING [EnumerateBodies, HashBlock, NameForSe, SiblingBti, SonBti, SubStringForName, UnderType],
SymLiteralOps: TYPE USING [RefLitItem, DescribeRefLits, DescribeTypes, EnumerateRefLits, EnumerateTypes, TypeIndex, UTypeId],
Table: TYPE USING [IPointer, Selector],
Tree: TYPE USING [Base, Index, Link, Map, Scan, Null, treeType],
TreeOps: TYPE USING [FreeTree, UpdateLeaves],
TypeStrings: TYPE USING [Create],
UnsafeStorage: TYPE USING [GetSystemUZone],
XSymbolSegment: TYPE SymbolSegment USING [ExtRecord],
XTree: TYPE Tree USING [Index, Link, Node],
XTreeOps: TYPE USING [ForEachSon, LinkToX];
ObjectOut: PROGRAM
IMPORTS Alloc, ConvertUnsafe, IO, PrincOpsUtils, OSMiscOps, LiteralOps, RCMapOps, Rope, SymbolOps, SymLiteralOps, TreeOps, TypeStrings, dataPtr: ComData, UnsafeStorage, XTreeOps
EXPORTS CompilerUtil = {
StreamIndex: TYPE = INT; -- FileStream.FileByteIndex
Address: TYPE = CompilerUtil.Address;
stream: IO.STREAMNIL;
zone: UNCOUNTED ZONE = UnsafeStorage.GetSystemUZone[];
PageSize: CARDINAL = BcdDefs.PageSize;
BytesPerWord: CARDINAL = Basics.bytesPerWord;
BytesPerPage: CARDINAL = PageSize*BytesPerWord;
NextFilePage: PUBLIC PROC RETURNS[CARDINAL] = {
fill: ARRAY [0..8) OF WORDALL[0];
r: INTEGER = (stream.GetIndex[] MOD BytesPerPage)/BytesPerWord;
m: INTEGER;
IF r # 0 THEN
FOR n: INTEGER ← PageSize-r, n-m WHILE n > 0 DO
m ← MIN[n, fill.LENGTH];
WriteObjectWords[LOOPHOLE[fill.BASE.LONG], m];
ENDLOOP;
RETURN[stream.GetIndex[]/BytesPerPage + 1]};
WriteObjectWords: PROC[addr: Address, n: CARDINAL] = {
stream.UnsafePutBlock[[base: addr, startIndex: 0, count: n*BytesPerWord]]};
RewriteObjectWords: PROC[index: StreamIndex, addr: Address, n: CARDINAL] = {
saveIndex: StreamIndex = stream.GetIndex[];
stream.SetIndex[index];
stream.UnsafePutBlock[[addr, 0, n*BytesPerWord]];
stream.SetIndex[saveIndex]};
WriteTableBlock: PROC[p: Table.IPointer, size: CARDINAL] = {
WriteObjectWords[LOOPHOLE[p], size]};
bcd i/o
bcdOffset: CARDINAL;
bcdIndex: StreamIndex;
BCDIndex: PROC[offset: CARDINAL] RETURNS[StreamIndex] = INLINE {
RETURN[bcdIndex + offset*BytesPerWord]};
StartBCD: PUBLIC PROC = {
[] ← NextFilePage[];
bcdIndex ← stream.GetIndex[];
bcdOffset ← 0};
ReadBCDOffset: PUBLIC PROC RETURNS[CARDINAL] = {RETURN[bcdOffset]};
ReadBCDIndex: PUBLIC PROC RETURNS[StreamIndex] = {
RETURN[BCDIndex[bcdOffset]]};
AppendBCDWord: PUBLIC PROC[word: UNSPECIFIED] = {
-- stream.PutWord[word];
stream.UnsafePutBlock[[@word, 0, 2]]; bcdOffset ← bcdOffset + 1};
AppendBCDWords: PUBLIC PROC[addr: Address, n: CARDINAL] = {
WriteObjectWords[addr, n]; bcdOffset ← bcdOffset + n};
AppendBCDString: PUBLIC PROC[s: LONG STRING] = {
header: StringBody ← [length: s.length, maxlength: s.length, text:];
AppendBCDWords[@header, StringBody[0].SIZE];
AppendBCDWords[@s.text, StringBody[s.length].SIZE - StringBody[0].SIZE]};
FillBCDPage: PUBLIC PROC = {
IF bcdOffset MOD PageSize # 0 THEN {
[] ← NextFilePage[]; bcdOffset ← bcdOffset + (PageSize - bcdOffset MOD PageSize)}
};
UpdateBCDWords: PUBLIC PROC[offset: CARDINAL, addr: Address, n: CARDINAL] = {
RewriteObjectWords[BCDIndex[offset], addr, n]};
EndBCD: PUBLIC PROC = {[] ← NextFilePage[]};
symbol table i/o
PageCount: PROC[words: CARDINAL] RETURNS[CARDINAL] = {
RETURN[(words+(PageSize-1))/PageSize]};
SetFgt: PROC[d: SymbolSegment.WordOffset, sourceFile: FileParms.Name]
RETURNS[fgBase, fgPages: CARDINAL] = {
np: CARDINAL = PageCount[d];
dataPtr.symSeg.pages ← np;
IF dataPtr.interface THEN {
fgBase ← 0;
dataPtr.symSeg.extraPages ← fgPages ← 0;
dataPtr.codeSeg.file ← BcdDefs.FTNull;
dataPtr.codeSeg.base ← dataPtr.codeSeg.pages ← 0;
dataPtr.objectBytes ← 0;
dataPtr.mtRoot.framesize ← dataPtr.globalFrameSize ← 0}
ELSE {
fgBase ← np;
dataPtr.symSeg.extraPages ← fgPages ← PageCount[
(StringBody[sourceFile.Length[]].SIZE-StringBody[0].SIZE) +
dataPtr.fgTable.LENGTH*SymbolSegment.FGTEntry.SIZE +
SymbolSegment.FGHeader.SIZE]};
dataPtr.codeSeg.class ← code; dataPtr.codeSeg.extraPages ← 0;
RETURN};
tree i/o
litBias: CARDINAL;
WriteExtensions: PROC[table: Alloc.Handle] RETURNS[size: CARDINAL] = {
OPEN SymbolSegment;
tb: Tree.Base;
ltb: Literals.Base;
treeLoc: Tree.Index ← Tree.Index.FIRST;
initialized: BOOLFALSE; -- set after rep of Tree.Null is written
OutputNotify: Alloc.Notifier = {
tb ← base[Tree.treeType]; ltb ← base[ltType];
seb ← base[seType]; ctxb ← base[ctxType];
extb ← base[extType]};
OutputLiteral: PROC[t: Tree.Link.literal] RETURNS[Tree.Link] = {
OPEN LiteralOps;
WITH lit: t.index SELECT FROM
word => lit.lti ← CopyLiteral[[baseP:@ltb, index:lit]].lti-litBias;
string => lit.sti ← Literals.STNull; -- temporary
ENDCASE => ERROR;
RETURN[t]};
SetEmpty: Tree.Map = {RETURN[Tree.Null]};
OutputTree: Tree.Map = {
WITH link: t SELECT FROM
literal => v ← OutputLiteral[link];
subtree => {
s: Tree.Link = TreeOps.UpdateLeaves[link, OutputTree];
IF s = Tree.Null AND initialized THEN v ← Tree.Null
ELSE
WITH s SELECT FROM
subtree => {
node: Tree.Index = index;
header: XTree.Node--[0]--;
nw: CARDINAL;
WriteSon: Tree.Scan = {
link: XTree.Link ← XTreeOps.LinkToX[t];
nw ← nw + XTree.Link.SIZE;
WriteTableBlock[@link, XTree.Link.SIZE]};
header ← [
free: FALSE,
name: tb[node].name,
attr1: tb[node].attr1, attr2: tb[node].attr2, attr3: tb[node].attr3,
shared: FALSE,
nSons: tb[node].nSons,
info: tb[node].info,
son: ];
temporary patch for backward compatibility
SELECT header.name FROM
IN [apply..typecode], textlit, exlist, shorten, IN [ord..val] =>
header.info ← SymbolOps.UnderType[header.info];
ENDCASE;
nw ← XTree.Node.SIZE;
WriteTableBlock[@header, XTree.Node.SIZE]; -- common header
XTreeOps.ForEachSon[[@tb, s], WriteSon];
[] ← TreeOps.FreeTree[TreeOps.UpdateLeaves[s, SetEmpty]];
v ← [subtree[index: treeLoc]]; treeLoc ← treeLoc + nw;
IF treeLoc-Tree.Index.FIRST > XTree.Index.LAST-XTree.Index.FIRST THEN
ERROR Alloc.Failure[table, Tree.treeType]
};
ENDCASE => v ← s};
ENDCASE => v ← link;
RETURN};
extb: SymbolSegment.Base;
extLimit: ExtIndex;
seb, ctxb: Symbols.Base;
table.AddNotify[OutputNotify];
[] ← OutputTree[Tree.Null]; initialized ← TRUE;
[extb, LOOPHOLE[extLimit, CARDINAL]] ← table.Bounds[extType];
FOR exti: ExtIndex ← ExtIndex.FIRST, exti + ExtRecord.SIZE UNTIL exti = extLimit DO
extb[exti].tree ←
IF dataPtr.interface OR extb[exti].type = value OR extb[exti].type = default
THEN OutputTree[extb[exti].tree]
ELSE Tree.Null;
ENDLOOP;
table.DropNotify[OutputNotify];
RETURN[treeLoc-Tree.Index.FIRST]};
WriteExtensionTable: PROC[table: Alloc.Handle] RETURNS[size: CARDINAL] = {
OPEN SymbolSegment;
extb: SymbolSegment.Base;
extLimit: ExtIndex;
OutputNotify: Alloc.Notifier = {extb ← base[extType]};
table.AddNotify[OutputNotify];
extLimit ← table.Top[extType]; size ← 0;
FOR exti: ExtIndex ← ExtIndex.FIRST, exti + ExtRecord.SIZE UNTIL exti = extLimit DO
IF extb[exti].tree # Tree.Null THEN {
extRecord: XSymbolSegment.ExtRecord ← [
type: extb[exti].type,
sei: extb[exti].sei,
tree: XTreeOps.LinkToX[extb[exti].tree]];
size ← size + XSymbolSegment.ExtRecord.SIZE;
WriteTableBlock[@extRecord, XSymbolSegment.ExtRecord.SIZE]};
ENDLOOP;
table.DropNotify[OutputNotify];
RETURN};
package table i/o
WritePackTables: PROC[table: Alloc.Handle] = {
OPEN Symbols, PackageSymbols;
bb: Symbols.Base;
OutputNotify: Alloc.Notifier = {bb ← base[SymbolSegment.bodyType]};
BodyLength: PROC[info: Symbols.BodyInfo] RETURNS[CARDINAL] = INLINE {
RETURN[WITH info SELECT FROM External => bytes, ENDCASE => 0]};
nOuter: CARDINAL = dataPtr.nBodies - dataPtr.nInnerBodies;
outer: LONG DESCRIPTOR FOR ARRAY OF OuterPackRecord ←
DESCRIPTOR[OSMiscOps.Words[nOuter*OuterPackRecord.SIZE], nOuter];
next: CARDINAL ← 0;
nextIP: IPIndex ← IPIndex.FIRST;
OuterBody: PROC[bti: BTIndex] = {
WITH body: bb[bti] SELECT FROM
Callable =>
IF ~body.inline THEN {
outer[next] ← OuterPackRecord[
hti: SymbolOps.NameForSe[body.id],
entryIndex: body.entryIndex,
length: BodyLength[body.info],
firstSon: InnerBodies[bti],
resident: body.resident];
next ← next + 1};
ENDCASE
};
InnerBodies: PROC[root: BTIndex] RETURNS[origin: IPIndex] = {
buffer: InnerPackRecord;
ProcessBody: PROC[bti: BTIndex] RETURNS[BOOL] = {
WITH body: bb[bti] SELECT FROM
Callable =>
IF ~body.inline AND body.level > Symbols.lL THEN {
IF origin # IPNull THEN WriteObjectWords[@buffer, InnerPackRecord.SIZE];
buffer ← InnerPackRecord[
entryIndex: body.entryIndex,
length: BodyLength[body.info],
lastSon: FALSE];
IF origin = IPNull THEN origin ← nextIP;
nextIP ← nextIP + 1};
ENDCASE => NULL;
RETURN[FALSE]};
origin ← IPNull;
IF root # Symbols.RootBti THEN [] ← SymbolOps.EnumerateBodies[root, ProcessBody]
ELSE
FOR sonBti: BTIndex ← SymbolOps.SonBti[root], SymbolOps.SiblingBti[sonBti]
UNTIL sonBti = BTNull DO
WITH body: bb[sonBti] SELECT FROM
Callable => NULL; -- processed as an outer body
ENDCASE => [] ← SymbolOps.EnumerateBodies[sonBti, ProcessBody];
ENDLOOP;
IF origin # IPNull THEN {
buffer.lastSon ← TRUE; WriteObjectWords[@buffer, InnerPackRecord.SIZE]};
RETURN};
table.AddNotify[OutputNotify];
OuterBody[Symbols.RootBti];
FOR bti: BTIndex ← SymbolOps.SonBti[Symbols.RootBti], SymbolOps.SiblingBti[bti]
UNTIL bti = BTNull DO
OuterBody[bti] ENDLOOP;
table.DropNotify[OutputNotify];
IF next # outer.LENGTH OR nextIP # dataPtr.nInnerBodies THEN ERROR;
SortPackInfo[outer, 1, outer.LENGTH];
WriteObjectWords[outer.BASE, nOuter*OuterPackRecord.SIZE];
OSMiscOps.FreeWords[outer.BASE]};
SortPackInfo: PROC[
a: LONG DESCRIPTOR FOR ARRAY OF PackageSymbols.OuterPackRecord,
l, u: CARDINAL] = {
Shell sort of a[l..u)
h, i, j, k: CARDINAL;
key: Symbols.Name;
t: PackageSymbols.OuterPackRecord;
h ← u - l;
DO
h ← h/2;
FOR k IN [l+h .. u) DO
i ← k; j ← k-h; key ← a[k].hti; t ← a[k];
WHILE key < a[j].hti DO
a[i] ← a[j]; i ← j;
IF j < l+h THEN EXIT; j ← j-h;
ENDLOOP;
a[i] ← t;
ENDLOOP;
IF h <= 1 THEN EXIT;
ENDLOOP
};
main drivers
StartObjectFile: PUBLIC PROC[objectStream: IO.STREAM] = {
stream ← objectStream};
TableOut: PUBLIC PROC[table: Alloc.Handle] = {
OPEN SymbolSegment;
h: STHeader;
fixupLoc: StreamIndex;
d: WordOffset;
nw: CARDINAL;
WriteSubTable: PROC[selector: Table.Selector] = {
base: Alloc.Base;
size: CARDINAL;
[base, size] ← table.Bounds[selector];
WriteTableBlock[base, size]};
dataPtr.symSeg.class ← symbols;
dataPtr.symSeg.base ← NextFilePage[];
h.versionIdent ← SymbolSegment.VersionID;
h.version ← dataPtr.objectVersion;
h.sourceVersion ← dataPtr.source.version;
h.creator ← dataPtr.compilerVersion;
h.definitionsFile ← dataPtr.interface;
h.extended ← TRUE;
h.directoryCtx ← dataPtr.moduleCtx;
h.importCtx ← dataPtr.importCtx;
h.outerCtx ← dataPtr.mainCtx;
d ← STHeader.SIZE;
h.hvBlock.offset ← d;
d ← d + (h.hvBlock.size ← Symbols.HashVector.SIZE);
h.htBlock.offset ← d; d ← d + (h.htBlock.size ← table.Bounds[htType].size);
h.ssBlock.offset ← d; d ← d + (h.ssBlock.size ← table.Bounds[ssType].size);
IF dataPtr.interface THEN h.innerPackBlock ← h.outerPackBlock ← [d, 0]
ELSE {
h.innerPackBlock.offset ← d;
d ← d + (h.innerPackBlock.size ← dataPtr.nInnerBodies*PackageSymbols.InnerPackRecord.SIZE);
h.outerPackBlock.offset ← d;
d ← d + (h.outerPackBlock.size ←
(dataPtr.nBodies-dataPtr.nInnerBodies)*PackageSymbols.OuterPackRecord.SIZE)};
h.constBlock.offset ← d; d ← d + (h.constBlock.size ← table.Bounds[constType].size);
h.seBlock.offset ← d; d ← d + (h.seBlock.size ← table.Bounds[seType].size);
h.ctxBlock.offset ← d; d ← d + (h.ctxBlock.size ← table.Bounds[ctxType].size);
h.mdBlock.offset ← d; d ← d + (h.mdBlock.size ← table.Bounds[mdType].size);
h.bodyBlock.offset ← d; d ← d + table.Bounds[bodyType].size;
h.bodyBlock.size ← dataPtr.defBodyLimit;
h.epMapBlock ← h.spareBlock ← [d, 0];
IF table.Bounds[extType].size # 0 THEN fixupLoc ← stream.GetIndex[]
ELSE {
h.treeBlock ← h.litBlock ← h.sLitBlock ← h.extBlock ← [d, 0];
[h.fgRelPgBase, h.fgPgCount] ← SetFgt[d, dataPtr.source.locator]};
WriteObjectWords[@h, STHeader.SIZE];
WriteObjectWords[SymbolOps.HashBlock[], h.hvBlock.size];
WriteSubTable[htType];
WriteSubTable[ssType];
IF ~dataPtr.interface THEN WritePackTables[table];
WriteSubTable[constType];
WriteSubTable[seType];
WriteSubTable[ctxType];
WriteSubTable[mdType];
WriteSubTable[bodyType];
IF table.Bounds[extType].size # 0 THEN {
litBias ← LiteralOps.ForgetEntries[];
h.treeBlock.offset ← d;
h.treeBlock.size ← WriteExtensions[table];
d ← d + h.treeBlock.size;
h.litBlock.offset ← d;
nw ← table.Bounds[ltType].size - litBias;
WriteTableBlock[table.Bounds[ltType].base+litBias, nw];
d ← d + (h.litBlock.size ← nw);
h.sLitBlock ← [d, 0];
h.extBlock.offset ← d;
h.extBlock.size ← WriteExtensionTable[table];
d ← d + h.extBlock.size;
[h.fgRelPgBase, h.fgPgCount] ← SetFgt[d, dataPtr.source.locator];
RewriteObjectWords[fixupLoc, @h, STHeader.SIZE]};
IF ~dataPtr.interface THEN {
fg: FGHeader;
s: Rope.Text ← Rope.Flatten[dataPtr.source.locator];
[] ← NextFilePage[];
nw ← StringBody[s.Length].SIZE-StringBody[0].SIZE;
fg.offset ← FGHeader.SIZE + nw;
fg.length ← dataPtr.fgTable.LENGTH;
fg.sourceFile ← StringBody[
length: s.Length,
maxlength: s.Length,
text: -- written separately -- ];
WriteObjectWords[@fg, FGHeader.SIZE];
WriteObjectWords[LOOPHOLE[s, LONG POINTER]+Rope.Text.SIZE, nw];
WriteObjectWords[dataPtr.fgTable.BASE, dataPtr.fgTable.LENGTH*FGTEntry.SIZE];
OSMiscOps.FreePages[dataPtr.fgTable.BASE]}
};
RTTableOut: PUBLIC PROC[table: Alloc.Handle] = {
nLits: CARDINAL = SymLiteralOps.DescribeRefLits[].length;
nTypes: CARDINAL = SymLiteralOps.DescribeTypes[].length;
IF nLits + nTypes # 0 THEN {
OPEN RTBcd;
rtOffset: CARDINAL ← RTHeader.SIZE;
header: RTHeader ← [
refLitTable: LOOPHOLE[rtOffset],
litBase: TRASH,
litLength: TRASH,
rcMapBase: TRASH,
rcMapLength: TRASH,
stampTable: TRASH,
typeTable: LOOPHOLE[rtOffset + RefLitList[nLits].SIZE]];
fixupOffset: CARDINAL = ReadBCDOffset[];
textBase: LONG POINTERNIL; -- to a sequence of StringBody's
textLimit: CARDINAL ← 0;
textLoc: CARDINAL ← 0;
EqText: PROC[rt: REF TEXT, pt: LONG POINTER TO TEXT] RETURNS[BOOL] = INLINE {
IF rt.length # pt.length THEN RETURN[FALSE];
FOR i: CARDINAL IN [0..rt.length) DO
IF rt[i] # pt[i] THEN RETURN[FALSE] ENDLOOP;
RETURN[TRUE]};
EnterText: PROC[s: REF TEXT] RETURNS[loc: CARDINAL] = {
t: LONG POINTER TO TEXT;
nw: CARDINAL;
FOR loc ← 0, loc + TEXT[t.length].SIZE UNTIL loc >= textLoc DO
t ← textBase + loc;
IF EqText[s, t] THEN RETURN;
ENDLOOP;
nw ← TEXT[s.length].SIZE;
WHILE textLoc + nw > textLimit DO
newLimit: CARDINAL = PageCount[textLimit+MAX[MIN[textLimit/2, 512], 64]];
newBase: LONG POINTER ← OSMiscOps.Words[newLimit*PageSize];
IF textBase # NIL THEN {
PrincOpsUtils.LongCopy[from: textBase, to: newBase, nwords: textLoc];
OSMiscOps.FreeWords[textBase]};
textBase ← newBase; textLimit ← newLimit*PageSize;
ENDLOOP;
loc ← textLoc;
PrincOpsUtils.LongCopy
[from: LOOPHOLE[s, LONG POINTER], to: textBase+loc, nwords: nw];
textLoc ← textLoc + nw;
RETURN};
stampList: REF RTBcd.StampList ← NIL;
nextStamp: NAT ← 1;
EnterStamp: PROC[mdi: Symbols.MDIndex] RETURNS[index: RTBcd.StampIndex] = {
IF mdi = Symbols.MDNull THEN index ← RTBcd.AnyStamp
ELSE {
stamp: BcdDefs.VersionStamp = table.Bounds[SymbolSegment.mdType].base[mdi].stamp;
FOR i: NAT IN [1 .. nextStamp) DO
IF stamp = stampList[i] THEN RETURN[[i]];
ENDLOOP;
IF stampList = NIL OR nextStamp >= stampList.limit THEN ExpandStampList[];
index ← [nextStamp]; stampList[nextStamp] ← stamp; nextStamp ← nextStamp + 1};
RETURN};
ExpandStampList: PROC = INLINE {
oldSize: NAT = nextStamp - 1;
AdjustStampList[oldSize + MAX[MIN[oldSize/2, 128], 32]]};
AdjustStampList: PROC[newSize: NAT] = {
oldSize: NAT = nextStamp - 1;
newList: REF RTBcd.StampList = NEW[RTBcd.StampList[newSize]];
FOR i: NAT IN [1 .. MIN[oldSize, newSize]] DO newList[i] ← stampList[i] ENDLOOP;
stampList ← newList};
AppendBCDWords[@header, RTHeader.SIZE];
AppendBCDWord[nLits];
IF nLits # 0 THEN {
WriteLitItem: PROC[item: SymLiteralOps.RefLitItem] = {
info: RefLitItem;
loc, chars: CARDINAL;
type: Symbols.Type;
WITH v: item SELECT FROM
atom => {
desc: ConvertUnsafe.SubString;
s: REF TEXT;
n: CARDINAL;
desc ← SymbolOps.SubStringForName[v.pName];
n ← desc.length + (desc.length MOD 2);
s ← NEW[TEXT[n]];
ConvertUnsafe.AppendSubStringToRefText[s, desc];
IF s.length < n THEN s[n-1] ← 0c;
loc ← EnterText[s]; chars ← s.length;
type ← dataPtr.typeAtomRecord;
s ← NIL};
text => {
s: LONG STRING = LiteralOps.StringValue[v.value];
loc ← EnterText[LOOPHOLE[s, REF TEXT]]; chars ← s.length; -- ARRGGH
type ← LiteralOps.TextType[v.value]};
ENDCASE;
info ← [
referentType: SymLiteralOps.TypeIndex[type, FALSE],
offset: loc, length: TEXT[chars].SIZE];
AppendBCDWords[@info, RefLitItem.SIZE]};
SymLiteralOps.EnumerateRefLits[WriteLitItem]};
AppendBCDWord[nTypes];
rtOffset ← rtOffset + RefLitList[nLits].SIZE + TypeList[nTypes].SIZE;
header.rcMapBase ← LOOPHOLE[rtOffset.LONG];
IF nTypes = 0 THEN header.rcMapLength ← 0
ELSE {
rcmt: RCMapOps.RCMT = RCMapOps.Create[
zone: zone, ptr: NIL, nPages: 0, expansionOK: TRUE];
EnterUT: PROC[type: Symbols.Type] RETURNS[RTBcd.UTInfo] = {
mdi: Symbols.MDIndex;
sei: Symbols.Type;
[mdi, sei] ← SymLiteralOps.UTypeId[type];
RETURN[[version: EnterStamp[mdi], sei: sei]]};
WriteTypeItem: PROC[canonical: BOOL, type: Symbols.Type] = {
s: LONG STRING ← TypeStrings.Create[dataPtr.ownSymbols, type, zone];
info: TypeItem ← [
table: dataPtr.mtRoot.sseg,
sei: type,
canonical: canonical,
rcMap: rcmt.Acquire[dataPtr.ownSymbols, type],
ct: [EnterText[LOOPHOLE[s, REF TEXT]]], -- ARRGGH
ut: EnterUT[type]];
zone.FREE[@s];
AppendBCDWords[@info, TypeItem.SIZE]};
[] ← EnterStamp[Symbols.OwnMdi];
SymLiteralOps.EnumerateTypes[WriteTypeItem];
header.rcMapLength ← rcmt.GetSpan[].size;
AppendBCDWords[rcmt.GetSpan[].base, header.rcMapLength];
rtOffset ← rtOffset + header.rcMapLength;
[] ← RCMapOps.Destroy[rcmt]};
header.stampTable ← LOOPHOLE[rtOffset];
AdjustStampList[nextStamp-1];
AppendBCDWords[LOOPHOLE[stampList, LONG POINTER], StampList[nextStamp-1].SIZE];
rtOffset ← rtOffset + StampList[nextStamp-1].SIZE;
stampList ← NIL;
header.litBase ← LOOPHOLE[rtOffset];
header.litLength ← textLoc;
IF textBase # NIL THEN {
AppendBCDWords[textBase, textLoc]; OSMiscOps.FreeWords[textBase]};
UpdateBCDWords[fixupOffset, @header, RTHeader.SIZE]}
};
EndObjectFile: PUBLIC PROC[update: BOOL] = {
IF stream # NIL AND update THEN {
saveIndex: StreamIndex = stream.GetIndex[];
stream.SetIndex[dataPtr.fixupLoc];
stream.UnsafePutBlock[[LOOPHOLE[(@dataPtr.codeSeg).LONG, LONG POINTER TO Basics.RawBytes], 0, BcdDefs.SGRecord.SIZE*BytesPerWord]];
stream.UnsafePutBlock[[LOOPHOLE[(@dataPtr.symSeg).LONG, LONG POINTER TO Basics.RawBytes], 0, BcdDefs.SGRecord.SIZE*BytesPerWord]];
stream.UnsafePutBlock[[LOOPHOLE[dataPtr.mtRoot, LONG POINTER TO Basics.RawBytes], 0, dataPtr.mtRootSize*BytesPerWord]];
stream.SetIndex[saveIndex]};
stream ← NIL};
}.