DIRECTORY
Alloc: TYPE USING [Base, Handle, Notifier, AddNotify, DropNotify, Bounds],
Basics: TYPE USING [bytesPerWord],
BcdDefs: TYPE USING [SGRecord, VersionStamp, FTNull],
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 [AppendRope, SubString, SubStringToRope],
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 [FreeWords, Words],
PackageSymbols: TYPE USING [OuterPackRecord, InnerPackRecord, IPIndex, IPNull],
PrincOps: TYPE USING [wordsPerPage],
PrincOpsUtils: TYPE USING [LongCOPY],
RCMap: TYPE USING [Base],
RCMapOps: TYPE USING [Acquire, Finalize, GetBase, Initialize],
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],
SymLiteralOps:
TYPE
USING [
RefLitItem, DescribeRefLits, DescribeTypes, EnumerateRefLits, EnumerateTypes,
TypeIndex, UTypeId],
Table: TYPE USING [IPointer, Selector],
Tree: TYPE USING [Base, Index, Link, Map, Node, Null, NullIndex, treeType],
TreeOps: TYPE USING [FreeTree, NodeSize, UpdateLeaves],
TypeStrings: TYPE USING [Create];
ObjectOut:
PROGRAM
IMPORTS
Alloc, ConvertUnsafe, IO, PrincOpsUtils, OSMiscOps, LiteralOps, RCMapOps,
Rope, SymbolOps, SymLiteralOps, TreeOps, TypeStrings,
dataPtr: ComData
EXPORTS CompilerUtil
SHARES Rope = {
StreamIndex: TYPE = INT; -- FileStream.FileByteIndex
Address: TYPE = CompilerUtil.Address;
GetShortIndex:
PROC [stream:
IO.
STREAM]
RETURNS [
CARDINAL] =
INLINE {
RETURN [IO.GetIndex[stream]]};
stream: IO.STREAM ← NIL;
zone: UNCOUNTED ZONE ← NIL;
PageSize: CARDINAL = PrincOps.wordsPerPage;
BytesPerWord: CARDINAL = Basics.bytesPerWord;
BytesPerPage: CARDINAL = PageSize*BytesPerWord;
NextFilePage:
PUBLIC
PROC
RETURNS [
CARDINAL] = {
fill: ARRAY [0..8) OF WORD ← ALL[0];
r: INTEGER = (GetShortIndex[stream] 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];
stream.UnsafePutBlock[[fill.BASE, 0, m*BytesPerWord]];
ENDLOOP;
RETURN [GetShortIndex[stream]/BytesPerPage + 1]};
WriteObjectWords:
PROC [addr: Address, n:
CARDINAL] = {
stream.UnsafePutBlock[[addr, 0, n*BytesPerWord]]};
RewriteObjectWords:
PROC [index: StreamIndex, addr: Address, n:
CARDINAL] = {
saveIndex: StreamIndex = IO.GetIndex[stream];
IO.SetIndex[stream, index];
stream.UnsafePutBlock[[addr, 0, n*BytesPerWord]];
IO.SetIndex[stream, saveIndex]};
WriteTableBlock:
PROC [p: Table.IPointer, size:
CARDINAL] = {
stream.UnsafePutBlock[[p, 0, size*BytesPerWord]]};
bcd i/o
bcdOffset: CARDINAL;
bcdIndex: StreamIndex;
BCDIndex:
PROC [offset:
CARDINAL]
RETURNS [StreamIndex] =
INLINE {
RETURN [bcdIndex + offset*BytesPerWord]};
StartBCD:
PUBLIC
PROC = {
[] ← NextFilePage[];
bcdIndex ← IO.GetIndex[stream];
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, 1]]; 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;
WriteExtension:
PROC [table: Alloc.Handle]
RETURNS [size:
CARDINAL] = {
OPEN SymbolSegment;
tb: Tree.Base;
ltb: Literals.Base;
treeLoc: Tree.Index;
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 THEN v ← Tree.Null
ELSE
WITH s
SELECT
FROM
subtree => {
node: Tree.Index = index;
nw: CARDINAL = TreeOps.NodeSize[@tb, node];
WriteTableBlock[@tb[node], nw];
[] ← TreeOps.FreeTree[TreeOps.UpdateLeaves[s, SetEmpty]];
v ← [subtree[index: treeLoc]]; treeLoc ← treeLoc + nw};
ENDCASE => v ← s};
ENDCASE => v ← link;
RETURN};
extb: SymbolSegment.Base;
extLimit: ExtIndex;
seb, ctxb: Symbols.Base;
table.AddNotify[OutputNotify];
WriteTableBlock[@tb[Tree.NullIndex], Tree.Node.SIZE];
treeLoc ← Tree.Index.FIRST + Tree.Node.SIZE;
[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]};
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, scratchZone: UNCOUNTED ZONE] = {
stream ← objectStream; zone ← scratchZone};
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 ← IO.GetIndex[stream]
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 ← WriteExtension[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.extBlock.offset ← d;
h.sLitBlock ← [d, 0];
WriteSubTable[extType];
d ← d + (h.extBlock.size ← table.Bounds[extType].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[@s.text, nw];
WriteObjectWords[dataPtr.fgTable.BASE, dataPtr.fgTable.LENGTH*FGTEntry.SIZE];
zone.FREE[@s];
OSMiscOps.FreeWords[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: NULL,
litLength: NULL,
rcMapBase: NULL,
rcMapLength: NULL,
stampTable: NULL,
typeTable: LOOPHOLE[rtOffset + RefLitList[nLits].SIZE]];
fixupOffset: CARDINAL = ReadBCDOffset[];
textBase: LONG POINTER ← NIL; -- to a sequence of StringBody's
textLimit: CARDINAL ← 0;
textLoc: CARDINAL ← 0;
EqText:
PROC [t1, t2:
LONG
STRING]
RETURNS [
BOOL] =
INLINE {
IF t1.length # t2.length THEN RETURN [FALSE];
FOR i:
CARDINAL
IN [0..t1.length)
DO
IF t1[i] # t2[i] THEN RETURN [FALSE] ENDLOOP;
RETURN [TRUE]};
EnterText:
PROC [s:
LONG
STRING]
RETURNS [loc:
CARDINAL] = {
t: LONG STRING;
nw: CARDINAL;
FOR loc ← 0, loc + StringBody[t.length].
SIZE
UNTIL loc >= textLoc
DO
t ← textBase + loc;
IF EqText[s, t] THEN RETURN;
ENDLOOP;
nw ← StringBody[s.length].SIZE;
WHILE textLoc + nw > textLimit
DO
newLimit: CARDINAL = PageCount[textLimit+MAX[MIN[textLimit/2, 512], 64]]*PageSize;
newBase: LONG POINTER = OSMiscOps.Words[newLimit];
IF textBase #
NIL
THEN {
PrincOpsUtils.LongCOPY[from: textBase, to: newBase, nwords: textLoc];
OSMiscOps.FreeWords[textBase]};
textBase ← newBase; textLimit ← newLimit;
ENDLOOP;
loc ← textLoc;
PrincOpsUtils.LongCOPY[from: s, to: textBase+loc, nwords: nw];
textLoc ← textLoc + nw;
RETURN};
stampList: LONG POINTER TO 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:
LONG
POINTER
TO RTBcd.StampList =
zone.NEW[RTBcd.StampList[newSize]];
FOR i: NAT IN [1 .. MIN[oldSize, newSize]] DO newList[i] ← stampList[i] ENDLOOP;
IF stampList # NIL THEN zone.FREE[@stampList];
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: LONG STRING;
n: CARDINAL;
desc ← SymbolOps.SubStringForName[v.pName];
n ← desc.length + (desc.length MOD 2);
s ← zone.NEW[StringBody[n]];
ConvertUnsafe.AppendRope[s, ConvertUnsafe.SubStringToRope[desc]];
IF s.length < n THEN s[n-1] ← 0c;
loc ← EnterText[s]; chars ← s.length;
type ← dataPtr.typeAtomRecord;
zone.FREE[@s]};
text => {
s: LONG STRING = LiteralOps.StringValue[v.value];
loc ← EnterText[s]; chars ← s.length;
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[LONG[rtOffset]];
IF nTypes = 0 THEN header.rcMapLength ← 0
ELSE {
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: RCMapOps.Acquire[dataPtr.ownSymbols, type],
ct: [EnterText[s]],
ut: EnterUT[type]];
zone.FREE[@s];
AppendBCDWords[@info, TypeItem.SIZE]};
RCMapOps.Initialize[ptr: NIL, nPages: 0, expansionZone: zone];
[] ← EnterStamp[Symbols.OwnMdi];
SymLiteralOps.EnumerateTypes[WriteTypeItem];
header.rcMapLength ← RCMapOps.GetBase[].nWords;
AppendBCDWords[RCMapOps.GetBase[].base, header.rcMapLength];
rtOffset ← rtOffset + header.rcMapLength;
RCMapOps.Finalize[]};
header.stampTable ← LOOPHOLE[rtOffset];
AdjustStampList[nextStamp-1];
AppendBCDWords[stampList, StampList[nextStamp-1].SIZE];
rtOffset ← rtOffset + StampList[nextStamp-1].SIZE;
zone.FREE[@stampList];
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 = IO.GetIndex[stream];
IO.SetIndex[stream, dataPtr.fixupLoc];
stream.UnsafePutBlock[[@dataPtr.codeSeg, 0, BcdDefs.SGRecord.SIZE*BytesPerWord]];
stream.UnsafePutBlock[[@dataPtr.symSeg, 0, BcdDefs.SGRecord.SIZE*BytesPerWord]];
stream.UnsafePutBlock[[dataPtr.mtRoot, 0, dataPtr.mtRootSize*BytesPerWord]];
IO.SetIndex[stream, saveIndex]};
IF dataPtr.mtRoot # NIL THEN zone.FREE[@dataPtr.mtRoot];
stream ← NIL; zone ← NIL};
}.