-- file ObjectOut.Mesa -- last modified by Satterthwaite, June 10, 1982 11:29 am -- last modified by Sweet, September 2, 1980 3:05 PM DIRECTORY Alloc: TYPE USING [Base, Handle, Notifier, AddNotify, DropNotify, Bounds], BcdDefs: TYPE USING [SGRecord, VersionStamp, FTNull], ComData: TYPE USING [ compilerVersion, codeSeg, defBodyLimit, definitionsOnly, fgTable, fixupLoc, globalFrameSize, importCtx, mainCtx, moduleCtx, mtRoot, mtRootSize, nBodies, nInnerBodies, objectBytes, objectVersion, ownSymbols, source, symSeg, typeAtomRecord], CompilerUtil: TYPE USING [Address], Environment: TYPE USING [bytesPerWord, wordsPerPage], FileStream: TYPE USING [FileByteIndex, GetIndex, SetIndex], Heap: TYPE USING [FreeNode, MakeNode], Inline: TYPE USING [LongCOPY], Literals: TYPE USING [Base, STNull], LiteralOps: TYPE USING [CopyLiteral, ForgetEntries, StringValue, TextType], OSMiscOps: TYPE USING [FreeWords, Words], PackageSymbols: TYPE USING [OuterPackRecord, InnerPackRecord, IPIndex, IPNull], RCMap: TYPE USING [Base], RCMapOps: TYPE USING [Acquire, Finalize, GetBase, Initialize], RTBcd: TYPE USING [ RefLitItem, RefLitList, RTHeader, StampIndex, StampList,TypeItem, TypeList, UTInfo, AnyStamp], Stream: TYPE USING [Handle, PutBlock, PutWord], Strings: TYPE USING [String, SubString, SubStringDescriptor, AppendSubString], Symbols: TYPE USING [ Base, HashVector, HTIndex, SEIndex, 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, HashForSe, SiblingBti, SonBti, SubStringForHash], 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, FileStream, Heap, Inline, OSMiscOps, LiteralOps, RCMapOps, Stream, Strings, SymbolOps, SymLiteralOps, TreeOps, TypeStrings, dataPtr: ComData EXPORTS CompilerUtil = { StreamIndex: TYPE = FileStream.FileByteIndex; Address: TYPE = CompilerUtil.Address; GetShortIndex: PROC [stream: Stream.Handle] RETURNS [CARDINAL] = INLINE { RETURN [FileStream.GetIndex[stream]]}; stream: Stream.Handle _ NIL; zone: UNCOUNTED ZONE _ NIL; PageSize: CARDINAL = Environment.wordsPerPage; BytesPerWord: CARDINAL = Environment.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, LENGTH[fill]]; stream.PutBlock[[BASE[fill], 0, m*BytesPerWord]]; ENDLOOP; RETURN [GetShortIndex[stream]/BytesPerPage + 1]}; WriteObjectWords: PROC [addr: Address, n: CARDINAL] = { stream.PutBlock[[addr, 0, n*BytesPerWord]]}; RewriteObjectWords: PROC [index: StreamIndex, addr: Address, n: CARDINAL] = { saveIndex: StreamIndex = FileStream.GetIndex[stream]; FileStream.SetIndex[stream, index]; stream.PutBlock[[addr, 0, n*BytesPerWord]]; FileStream.SetIndex[stream, saveIndex]}; WriteTableBlock: PROC [p: Table.IPointer, size: CARDINAL] = { stream.PutBlock[[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 _ FileStream.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]; bcdOffset _ bcdOffset + 1}; AppendBCDWords: PUBLIC PROC [addr: Address, n: CARDINAL] = { WriteObjectWords[addr, n]; bcdOffset _ bcdOffset + n}; AppendBCDString: PUBLIC PROC [s: Strings.String] = { header: StringBody _ [length: s.length, maxlength: s.length, text:]; AppendBCDWords[@header, SIZE[StringBody[0]]]; AppendBCDWords[@s.text, SIZE[StringBody[s.length]] - SIZE[StringBody[0]]]}; 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: Strings.SubString] RETURNS [fgBase, fgPages: CARDINAL] = { np: CARDINAL = PageCount[d]; dataPtr.symSeg.pages _ np; IF dataPtr.definitionsOnly 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[ (SIZE[StringBody[sourceFile.length]]-SIZE[StringBody[0]]) + LENGTH[dataPtr.fgTable]*SIZE[SymbolSegment.FGTEntry] + SIZE[SymbolSegment.FGHeader]]}; 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: literal Tree.Link] RETURNS [Tree.Link] = { OPEN LiteralOps; WITH t.info SELECT FROM word => index _ CopyLiteral[[baseP:@ltb, index:index]]-litBias; string => index _ 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], SIZE[Tree.Node]]; treeLoc _ FIRST[Tree.Index] + SIZE[Tree.Node]; [extb, LOOPHOLE[extLimit, CARDINAL]] _ table.Bounds[extType]; FOR exti: ExtIndex _ FIRST[ExtIndex], exti + SIZE[ExtRecord] UNTIL exti = extLimit DO extb[exti].tree _ IF dataPtr.definitionsOnly OR extb[exti].type = value OR extb[exti].type = default THEN OutputTree[extb[exti].tree] ELSE Tree.Null; ENDLOOP; table.DropNotify[OutputNotify]; RETURN [treeLoc-FIRST[Tree.Index]]}; -- 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*SIZE[OuterPackRecord]], nOuter]; next: CARDINAL _ 0; nextIP: IPIndex _ FIRST[IPIndex]; OuterBody: PROC [bti: BTIndex] = { WITH body: bb[bti] SELECT FROM Callable => IF ~body.inline THEN { outer[next] _ OuterPackRecord[ hti: SymbolOps.HashForSe[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 [BOOLEAN] = { WITH body: bb[bti] SELECT FROM Callable => IF ~body.inline AND body.level > Symbols.lL THEN { IF origin # IPNull THEN WriteObjectWords[@buffer, SIZE[InnerPackRecord]]; 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, SIZE[InnerPackRecord]]}; 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 # LENGTH[outer] OR nextIP # dataPtr.nInnerBodies THEN ERROR; SortPackInfo[outer, 1, LENGTH[outer]]; WriteObjectWords[BASE[outer], nOuter*SIZE[OuterPackRecord]]; OSMiscOps.FreeWords[BASE[outer]]}; 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.HTIndex; 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: Stream.Handle, 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.definitionsOnly; h.extended _ TRUE; h.directoryCtx _ dataPtr.moduleCtx; h.importCtx _ dataPtr.importCtx; h.outerCtx _ dataPtr.mainCtx; d _ SIZE[STHeader]; h.hvBlock.offset _ d; d _ d + (h.hvBlock.size _ SIZE[Symbols.HashVector]); 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.definitionsOnly THEN h.innerPackBlock _ h.outerPackBlock _ [d, 0] ELSE { h.innerPackBlock.offset _ d; d _ d + (h.innerPackBlock.size _ dataPtr.nInnerBodies*SIZE[PackageSymbols.InnerPackRecord]); h.outerPackBlock.offset _ d; d _ d + (h.outerPackBlock.size _ (dataPtr.nBodies-dataPtr.nInnerBodies)*SIZE[PackageSymbols.OuterPackRecord])}; 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 _ FileStream.GetIndex[stream] ELSE { h.treeBlock _ h.litBlock _ h.sLitBlock _ h.extBlock _ [d, 0]; [h.fgRelPgBase, h.fgPgCount] _ SetFgt[d, @dataPtr.source.locator]}; WriteObjectWords[@h, SIZE[STHeader]]; WriteObjectWords[SymbolOps.HashBlock[], h.hvBlock.size]; WriteSubTable[htType]; WriteSubTable[ssType]; IF ~dataPtr.definitionsOnly 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, SIZE[STHeader]]}; IF ~dataPtr.definitionsOnly THEN { fg: FGHeader; s: Strings.String _ zone.NEW[StringBody[dataPtr.source.locator.length]]; Strings.AppendSubString[s, @dataPtr.source.locator]; [] _ NextFilePage[]; nw _ SIZE[StringBody[s.length]]-SIZE[StringBody[0]]; fg.offset _ SIZE[FGHeader] + nw; fg.length _ LENGTH[dataPtr.fgTable]; fg.sourceFile _ StringBody[ length: s.length, maxlength: s.length, text: -- written separately -- ]; WriteObjectWords[@fg, SIZE[FGHeader]]; WriteObjectWords[@s.text, nw]; WriteObjectWords[BASE[dataPtr.fgTable], LENGTH[dataPtr.fgTable]*SIZE[FGTEntry]]; zone.FREE[@s]; OSMiscOps.FreeWords[BASE[dataPtr.fgTable]]}}; 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 _ SIZE[RTHeader]; header: RTHeader _ [ refLitTable: LOOPHOLE[rtOffset], litBase: NULL, litLength: NULL, rcMapBase: NULL, rcMapLength: NULL, stampTable: NULL, typeTable: LOOPHOLE[rtOffset + SIZE[RefLitList[nLits]]]]; fixupOffset: CARDINAL = ReadBCDOffset[]; textBase: LONG POINTER _ NIL; -- to a sequence of StringBody's textLimit: CARDINAL _ 0; textLoc: CARDINAL _ 0; EqText: PROC [t1, t2: Strings.String] RETURNS [BOOLEAN] = 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: Strings.String] RETURNS [loc: CARDINAL] = { t: Strings.String; nw: CARDINAL; FOR loc _ 0, loc + SIZE[StringBody[t.length]] UNTIL loc >= textLoc DO t _ textBase + loc; IF EqText[s, t] THEN RETURN; ENDLOOP; nw _ SIZE[StringBody[s.length]]; WHILE textLoc + nw > textLimit DO newLimit: CARDINAL = textLimit + MAX[MIN[textLimit/2, 256], 64]; newBase: LONG POINTER = Heap.MakeNode[zone, newLimit]; IF textBase # NIL THEN { Inline.LongCOPY[from: textBase, to: newBase, nwords: textLoc]; Heap.FreeNode[zone, textBase]}; textBase _ newBase; textLimit _ newLimit; ENDLOOP; loc _ textLoc; Inline.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, SIZE[RTHeader]]; AppendBCDWord[nLits]; IF nLits # 0 THEN { WriteLitItem: PROC [item: SymLiteralOps.RefLitItem] = { info: RefLitItem; loc, chars: CARDINAL; type: Symbols.SEIndex; WITH v: item SELECT FROM atom => { desc: Strings.SubStringDescriptor; s: Strings.String; n: CARDINAL; SymbolOps.SubStringForHash[@desc, v.pName]; n _ IF desc.length MOD 2 = 0 THEN desc.length ELSE desc.length+1; s _ zone.NEW[StringBody[n]]; Strings.AppendSubString[s, @desc]; IF s.length < n THEN s[n-1] _ 0c; loc _ EnterText[s]; chars _ s.length; type _ dataPtr.typeAtomRecord; zone.FREE[@s]}; text => { s: Strings.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: SIZE[TEXT[chars]]]; AppendBCDWords[@info, SIZE[RefLitItem]]}; SymLiteralOps.EnumerateRefLits[WriteLitItem]}; AppendBCDWord[nTypes]; rtOffset _ rtOffset + SIZE[RefLitList[nLits]] + SIZE[TypeList[nTypes]]; header.rcMapBase _ LOOPHOLE[LONG[rtOffset]]; IF nTypes = 0 THEN header.rcMapLength _ 0 ELSE { EnterUT: PROC [type: Symbols.SEIndex] RETURNS [RTBcd.UTInfo] = { mdi: Symbols.MDIndex; sei: Symbols.SEIndex; [mdi, sei] _ SymLiteralOps.UTypeId[type]; RETURN [[version: EnterStamp[mdi], sei: sei]]}; WriteTypeItem: PROC [canonical: BOOLEAN, type: Symbols.SEIndex] = { s: Strings.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, SIZE[TypeItem]]}; 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, SIZE[StampList[nextStamp-1]]]; rtOffset _ rtOffset + SIZE[StampList[nextStamp-1]]; zone.FREE[@stampList]; header.litBase _ LOOPHOLE[rtOffset]; header.litLength _ textLoc; IF textBase # NIL THEN { AppendBCDWords[textBase, textLoc]; Heap.FreeNode[zone, textBase]}; UpdateBCDWords[fixupOffset, @header, SIZE[RTHeader]]}}; EndObjectFile: PUBLIC PROC [update: BOOLEAN] = { IF stream # NIL AND update THEN { saveIndex: StreamIndex = FileStream.GetIndex[stream]; FileStream.SetIndex[stream, dataPtr.fixupLoc]; stream.PutBlock[[@dataPtr.codeSeg, 0, SIZE[BcdDefs.SGRecord]*BytesPerWord]]; stream.PutBlock[[@dataPtr.symSeg, 0, SIZE[BcdDefs.SGRecord]*BytesPerWord]]; stream.PutBlock[[dataPtr.mtRoot, 0, dataPtr.mtRootSize*BytesPerWord]]; FileStream.SetIndex[stream, saveIndex]}; IF dataPtr.mtRoot # NIL THEN { Heap.FreeNode[zone, dataPtr.mtRoot]; dataPtr.mtRoot _ NIL}; stream _ NIL; zone _ NIL}; }.