<> <> <> DIRECTORY Basics: TYPE USING [bytesPerWord], BasicTime: TYPE USING [GMT, ToNSTime], BcdDefs: TYPE USING [ Base, BCD, BcdBase, ControlItem, CTIndex, CTNull, CTRecord, EVIndex, EVRecord, EVNull, EXPIndex, EXPRecord, FTHandle, FTIndex, FTNull, FTRecord, FTSelf, IMPIndex, IMPRecord, LFIndex, LFNull, Link, LinkFrag, ModuleIndex, MTHandle, MTIndex, MTRecord, MTNull, NameRecord, NameString, NTIndex, NTRecord, NullLink, NullModule, NullName, NullVersion, RefLitFrag, RFIndex, RFNull, SGHandle, SGIndex, SGRecord, SGNull, TFIndex, TFNull, TypeFrag, VersionID, VersionStamp], BcdLiterals: TYPE USING [ LiteralState, Create, Finalize, SegmentSize, Load, MapLitLink, MapTypeLink, Unload, Write], BcdOps: TYPE USING [ProcessFiles, ProcessModules, ProcessSegs], FS: TYPE USING [OpenFile, Read], IO: TYPE USING [STREAM, GetLength, SetIndex, SetLength, UnsafePutBlock], LoaderOpsExtras: TYPE USING [AcquireFileProc], LoadState: TYPE USING [ModuleIndex], PrincOps: TYPE USING [bytesPerWord, wordsPerPage], Rope: TYPE USING [ROPE, Concat, Equal, Fetch, Find, FromProc, Length, Substr], SMModelBcd: TYPE USING [], SMTree: TYPE Tree USING [Link], VM: TYPE USING [AddressForPageNumber, Interval, nullInterval, Allocate, Free]; SMModelBcdImpl: PROGRAM IMPORTS BasicTime, BcdLiterals, BcdOps, FS, IO, Rope, VM EXPORTS SMModelBcd ~ { OPEN Tree~~SMTree; Bcd: TYPE~REF BcdObject; BcdObject: PUBLIC TYPE~RECORD[ space: VM.Interval_VM.nullInterval, base: BcdDefs.BcdBase_NIL, literals: BcdLiterals.LiteralState_NIL]; MTHandle: PUBLIC TYPE~BcdDefs.MTIndex; <> MTPAGE: CARDINAL ~ (BcdDefs.BCD.SIZE/PrincOps.wordsPerPage) + 1; nmtp: CARDINAL ~ 20; FTPAGE: CARDINAL ~ MTPAGE + nmtp; nftp: CARDINAL ~ 6; SGPAGE: CARDINAL ~ FTPAGE + nftp; nsgp: CARDINAL ~ 6; CTPAGE: CARDINAL ~ SGPAGE + nsgp; nctp: CARDINAL ~ 1; SSPAGE: CARDINAL ~ CTPAGE + nctp; nssp: CARDINAL ~ 16; IMPAGE: CARDINAL ~ SSPAGE + nssp; nimp: CARDINAL ~ 3; EXPAGE: CARDINAL ~ IMPAGE + nssp; nexp: CARDINAL ~ 3; NTPAGE: CARDINAL ~ EXPAGE + nexp; nntp: CARDINAL ~ 1; EVPAGE: CARDINAL ~ NTPAGE + nntp; nevp: CARDINAL ~ 6; LFPAGE: CARDINAL ~ EVPAGE + nevp; nlfp: CARDINAL ~ 12; RFPAGE: CARDINAL ~ LFPAGE + nlfp; nrfp: CARDINAL ~ 6; TFPAGE: CARDINAL ~ RFPAGE + nrfp; ntfp: CARDINAL ~ 6; BCDPAGES: CARDINAL ~ TFPAGE + ntfp; RelPointer: TYPE~BcdDefs.Base RELATIVE POINTER [0..CARDINAL.LAST); relZero: RelPointer ~ RelPointer.FIRST; Overflow: PUBLIC ERROR ~ CODE; Check: PROC[val: RelPointer, limit: CARDINAL] ~ { IF (val - RelPointer.FIRST) > limit THEN ERROR Overflow}; AddName: PROC[bcd, iBcd: BcdDefs.BcdBase, iName: BcdDefs.NameRecord] RETURNS[name: BcdDefs.NameRecord] ~ { nameString: BcdDefs.NameString ~ LOOPHOLE[bcd + bcd.ssOffset]; iNameString: BcdDefs.NameString ~ LOOPHOLE[iBcd + iBcd.ssOffset]; length: CARDINAL ~ iNameString.size[iName]; nChars: CARDINAL ~ length+1; -- includes length byte name _ [nameString.string.length]; IF StringBody[name+nChars].SIZE > nssp*PrincOps.wordsPerPage THEN ERROR Overflow; nameString.size[name] _ length; FOR i: CARDINAL IN [0 .. length) DO nameString.string.text[name+i] _ iNameString.string.text[iName+i]; ENDLOOP; nameString.string.length _ name + nChars; RETURN}; NewName: PROC[bcd: BcdDefs.BcdBase, string: Rope.ROPE] RETURNS[name: BcdDefs.NameRecord] ~ { nameString: BcdDefs.NameString ~ LOOPHOLE[bcd + bcd.ssOffset]; length: CARDINAL ~ string.Length; nChars: CARDINAL ~ length+1; -- includes length byte name _ [nameString.string.length]; IF StringBody[name+nChars].SIZE > nssp*PrincOps.wordsPerPage THEN ERROR Overflow; nameString.size[name] _ length; FOR i: CARDINAL IN [0 .. length) DO nameString.string.text[name+i] _ string.Fetch[i]; ENDLOOP; nameString.string.length _ name + nChars; RETURN}; NewNamed: PROC[bcd: BcdDefs.BcdBase, pair: BcdDefs.NTRecord] ~ { ntb: BcdDefs.Base ~ LOOPHOLE[bcd + bcd.ntOffset]; nti: BcdDefs.NTIndex ~ bcd.ntLimit; Check[nti + BcdDefs.NTRecord.SIZE, nntp*PrincOps.wordsPerPage]; ntb[nti] _ pair; bcd.ntLimit _ bcd.ntLimit + BcdDefs.NTRecord.SIZE}; TrimFileName: PROC[name: Rope.ROPE] RETURNS[Rope.ROPE] ~ { pos: INT ~ name.Find[s2~".bcd", case~FALSE]; RETURN[IF pos > 0 THEN name.Substr[0, pos] ELSE name]}; AddFile: PROC[bcd, iBcd: BcdDefs.BcdBase, ifti: BcdDefs.FTIndex, iFileName: Rope.ROPE] RETURNS[fti: BcdDefs.FTIndex] ~ { IF ifti = BcdDefs.FTNull THEN fti _ BcdDefs.FTNull ELSE { ftb: BcdDefs.Base ~ LOOPHOLE[bcd + bcd.ftOffset]; iFtb: BcdDefs.Base ~ LOOPHOLE[iBcd + iBcd.ftOffset]; version: BcdDefs.VersionStamp ~ (IF ifti = BcdDefs.FTSelf THEN iBcd.version ELSE iFtb[ifti].version); CheckFile: PROC[fth: BcdDefs.FTHandle, fti: BcdDefs.FTIndex] RETURNS[BOOL] ~ { RETURN[ftb[fti].version = version]}; fti _ BcdOps.ProcessFiles[bcd, CheckFile].fti; IF fti = BcdDefs.FTNull THEN { fti _ bcd.ftLimit; Check[fti + BcdDefs.FTRecord.SIZE, nftp*PrincOps.wordsPerPage]; ftb[fti] _ [ name~(IF ifti = BcdDefs.FTSelf THEN NewName[bcd, TrimFileName[iFileName]] ELSE AddName[bcd, iBcd, iFtb[ifti].name]), version~version]; bcd.ftLimit _ fti + BcdDefs.FTRecord.SIZE}; }; RETURN}; NewFile: PROC[bcd: BcdDefs.BcdBase, version: BcdDefs.VersionStamp, string: Rope.ROPE] RETURNS[fti: BcdDefs.FTIndex] ~ { ftb: BcdDefs.Base ~ LOOPHOLE[bcd + bcd.ftOffset]; CheckFile: PROC[fth: BcdDefs.FTHandle, fti: BcdDefs.FTIndex] RETURNS[BOOL] ~ { RETURN[ftb[fti].version = version]}; fti _ BcdOps.ProcessFiles[bcd, CheckFile].fti; IF fti = BcdDefs.FTNull THEN { fti _ bcd.ftLimit; Check[fti + BcdDefs.FTRecord.SIZE, nftp*PrincOps.wordsPerPage]; ftb[fti] _ [name~NewName[bcd, TrimFileName[string]], version~version]; bcd.ftLimit _ fti + BcdDefs.FTRecord.SIZE}; RETURN}; AddSegment: PROC[bcd, iBcd: BcdDefs.BcdBase, isgi: BcdDefs.SGIndex, iFileName: Rope.ROPE] RETURNS[sgi: BcdDefs.SGIndex] ~ { sgb: BcdDefs.Base ~ LOOPHOLE[bcd + bcd.sgOffset]; iSgb: BcdDefs.Base ~ LOOPHOLE[iBcd + iBcd.sgOffset]; fti: BcdDefs.FTIndex ~ AddFile[bcd, iBcd, iSgb[isgi].file, iFileName]; CheckSegment: PROC[sgh: BcdDefs.SGHandle, sgi: BcdDefs.SGIndex] RETURNS[BOOL] ~ { RETURN[sgb[sgi].file = fti AND sgb[sgi].class = iSgb[isgi].class AND sgb[sgi].base = iSgb[isgi].base AND sgb[sgi].pages = iSgb[isgi].pages AND sgb[sgi].extraPages = iSgb[isgi].extraPages] }; sgi _ BcdOps.ProcessSegs[bcd, CheckSegment].sgi; IF sgi = BcdDefs.SGNull THEN { sgi _ bcd.sgLimit; Check[sgi + BcdDefs.SGRecord.SIZE, nsgp*PrincOps.wordsPerPage]; sgb[sgi] _ iSgb[isgi]; sgb[sgi].file _ fti; bcd.sgLimit _ sgi + BcdDefs.SGRecord.SIZE}; RETURN}; AddVariables: PROC[bcd, iBcd: BcdDefs.BcdBase, ievi: BcdDefs.EVIndex] RETURNS[evi: BcdDefs.EVIndex] ~ { IF ievi = BcdDefs.EVNull THEN evi _ BcdDefs.EVNull ELSE { evb: BcdDefs.Base ~ LOOPHOLE[bcd + bcd.evOffset]; iEvb: BcdDefs.Base ~ LOOPHOLE[iBcd + iBcd.evOffset]; size: CARDINAL ~ BcdDefs.EVRecord.SIZE + iEvb[ievi].length*CARDINAL.SIZE; evi _ bcd.evLimit; Check[evi + size, nevp*PrincOps.wordsPerPage]; evb[evi] _ iEvb[ievi]; FOR i: CARDINAL IN [1..iEvb[ievi].length] DO evb[evi].offsets[i] _ iEvb[ievi].offsets[i] ENDLOOP; bcd.evLimit _ evi + size}; RETURN}; IndexToMti: PROC[base: BcdDefs.BcdBase, index: BcdDefs.ModuleIndex] RETURNS[BcdDefs.MTIndex] ~ { TestMti: PROC[mth: BcdDefs.MTHandle, mti: BcdDefs.MTIndex] RETURNS[stop: BOOL] ~ { RETURN[index = mth.gfi]}; RETURN[BcdOps.ProcessModules[base, TestMti].mti]}; BuildBcd: PUBLIC SAFE PROC[ name: Rope.ROPE, stamp: BasicTime.GMT, root: Tree.Link, EnumerateComponents: SAFE PROC[ root: Tree.Link, ProcessComponent: SAFE PROC[BcdDefs.BcdBase, Rope.ROPE] RETURNS[LoadState.ModuleIndex]], oldBcd: Bcd] RETURNS[Bcd] ~ TRUSTED { bcdSpace: VM.Interval _ VM.nullInterval; bcd: BcdDefs.BcdBase _ NIL; oldSpace: VM.Interval ~ (IF oldBcd = NIL THEN VM.nullInterval ELSE oldBcd.space); { ENABLE UNWIND => { IF bcdSpace ~= VM.nullInterval AND oldSpace = VM.nullInterval THEN bcdSpace.Free[] }; ctb, mtb: BcdDefs.Base; nameString: BcdDefs.NameString; nGfi: CARDINAL _ 1; MergeBcd: SAFE PROC[iBcd: BcdDefs.BcdBase, iFileName: Rope.ROPE] RETURNS[relGfi: LoadState.ModuleIndex] ~ TRUSTED { ForEachModule: PROC[imth: BcdDefs.MTHandle, imti: BcdDefs.MTIndex] RETURNS[stop: BOOL_FALSE] ~ { mti: BcdDefs.MTIndex ~ bcd.mtLimit; sgi: BcdDefs.SGIndex ~ bcd.sgLimit; mtSize: NAT ~ BcdDefs.MTRecord.multiple.SIZE; -- always builds this variant Check[mti + mtSize, nmtp*PrincOps.wordsPerPage]; mtb[mti] _ BcdDefs.MTRecord[ name~AddName[bcd, iBcd, imth.name], namedInstance~FALSE, initial~imth.initial, file~AddFile[bcd, iBcd, imth.file, iFileName], linkLoc~imth.linkLoc, config~BcdDefs.CTIndex.FIRST, code~[ sgi~AddSegment[bcd, iBcd, imth.code.sgi, iFileName], packed~imth.code.packed, linkspace~imth.code.linkspace, offset~imth.code.offset, length~imth.code.length], sseg~AddSegment[bcd, iBcd, imth.sseg, iFileName], long~imth.long, tableCompiled~imth.tableCompiled, boundsChecks~imth.boundsChecks, nilChecks~imth.nilChecks, frameRefs~imth.frameRefs, frameType~imth.frameType, framesize~imth.framesize, altoCode~imth.altoCode, residentFrame~imth.residentFrame, crossJumped~imth.crossJumped, packageable~imth.packageable, -- ??? gfi~nGfi, ngfi~imth.ngfi, variables~AddVariables[bcd, iBcd, imth.variables], extension~multiple[ -- this fake config has NO linkage information links~BcdDefs.LFNull, refLiterals~BcdDefs.RFNull, types~BcdDefs.TFNull]]; nGfi _ nGfi + imth.ngfi; bcd.mtLimit _ mti + mtSize; bcd.nModules _ bcd.nModules + 1}; relGfi _ nGfi; [] _ BcdOps.ProcessModules[iBcd, ForEachModule]; RETURN}; bcdSpace _ (IF oldSpace ~= VM.nullInterval THEN oldSpace ELSE VM.Allocate[count~BCDPAGES]); bcd _ VM.AddressForPageNumber[bcdSpace.page]; bcd^ _ [ versionIdent~BcdDefs.VersionID, version~BcdDefs.NullVersion, creator~BcdDefs.NullVersion, sourceVersion~[net~0, host~0, time~BasicTime.ToNSTime[LOOPHOLE[stamp]]], source~TRASH, spare1~TRUE, spare2~FALSE, nPages~BCDPAGES, nConfigs~1, nModules~0, nImports~0, nExports~0, definitions~FALSE, repackaged~FALSE, typeExported~FALSE, tableCompiled~FALSE, versions~FALSE, extended~TRUE, firstdummy~TRASH, nDummies~TRASH, ssOffset~SSPAGE*PrincOps.wordsPerPage, ssLimit~TRASH, ctOffset~CTPAGE*PrincOps.wordsPerPage, ctLimit~BcdDefs.CTIndex.FIRST, mtOffset~MTPAGE*PrincOps.wordsPerPage, mtLimit~BcdDefs.MTIndex.FIRST, impOffset~IMPAGE*PrincOps.wordsPerPage, impLimit~BcdDefs.IMPIndex.FIRST, expOffset~EXPAGE*PrincOps.wordsPerPage, expLimit~BcdDefs.EXPIndex.FIRST, evOffset~EVPAGE*PrincOps.wordsPerPage, evLimit~BcdDefs.EVIndex.FIRST, sgOffset~SGPAGE*PrincOps.wordsPerPage, sgLimit~BcdDefs.SGIndex.FIRST, ftOffset~FTPAGE*PrincOps.wordsPerPage, ftLimit~BcdDefs.FTIndex.FIRST, spOffset~0, spLimit~relZero, ntOffset~NTPAGE*PrincOps.wordsPerPage, ntLimit~BcdDefs.NTIndex.FIRST, typOffset~0, typLimit~relZero, tmOffset~0, tmLimit~relZero, fpOffset~0, fpLimit~relZero, lfOffset~LFPAGE*PrincOps.wordsPerPage, lfLimit~BcdDefs.LFIndex.FIRST, rfOffset~RFPAGE*PrincOps.wordsPerPage, rfLimit~BcdDefs.RFIndex.FIRST, tfOffset~TFPAGE*PrincOps.wordsPerPage, tfLimit~BcdDefs.TFIndex.FIRST, rtPages~[0, 0]]; ctb _ LOOPHOLE[bcd + bcd.ctOffset]; mtb _ LOOPHOLE[bcd + bcd.mtOffset]; nameString _ LOOPHOLE[bcd + bcd.ssOffset]; nameString.string _ [ length~BcdDefs.NullName, maxlength~(nssp*PrincOps.wordsPerPage-StringBody[0].SIZE)*PrincOps.bytesPerWord, text~]; nameString.size[BcdDefs.NullName] _ 0; bcd.source _ NewName[bcd, name.Concat[".model"]]; ctb[BcdDefs.CTIndex.FIRST] _ [ name~NewName[bcd, name], namedInstance~FALSE, file~BcdDefs.FTNull, -- try no backing file config~BcdDefs.CTNull, nControls~0, controls~]; bcd.ctLimit _ BcdDefs.CTIndex.FIRST + BcdDefs.CTRecord.SIZE; EnumerateComponents[root, MergeBcd]; bcd.firstdummy _ nGfi; -- gfis needed bcd.nDummies _ 0; bcd.ssLimit _ StringBody[nameString.string.length].SIZE; }; RETURN[NEW[BcdObject _ [space~bcdSpace, base~bcd]]]}; ReplaceComponent: PUBLIC SAFE PROC[ config: Bcd, relGfi: LoadState.ModuleIndex, iBcd: BcdDefs.BcdBase, iFileName: Rope.ROPE] ~ TRUSTED { bcd: BcdDefs.BcdBase~config.base; nameString: BcdDefs.NameString ~ LOOPHOLE[bcd + bcd.ssOffset]; mtb: BcdDefs.Base ~ LOOPHOLE[bcd + bcd.mtOffset]; nGfi: CARDINAL; ForEachModule: PROC[imth: BcdDefs.MTHandle, imti: BcdDefs.MTIndex] RETURNS[stop: BOOL_FALSE] ~ { mti: BcdDefs.MTIndex ~ IndexToMti[bcd, nGfi]; sgi: BcdDefs.SGIndex ~ bcd.sgLimit; IF mti = BcdDefs.MTNull THEN ERROR; mtb[mti] _ BcdDefs.MTRecord[ name~AddName[bcd, iBcd, imth.name], namedInstance~FALSE, initial~imth.initial, file~AddFile[bcd, iBcd, imth.file, iFileName], linkLoc~$code, -- imth.linkLoc, *** frame links not currently supported config~BcdDefs.CTIndex.FIRST, code~[ sgi~AddSegment[bcd, iBcd, imth.code.sgi, iFileName], packed~imth.code.packed, linkspace~imth.code.linkspace, offset~imth.code.offset, length~imth.code.length], sseg~AddSegment[bcd, iBcd, imth.sseg, iFileName], long~imth.long, tableCompiled~imth.tableCompiled, boundsChecks~imth.boundsChecks, nilChecks~imth.nilChecks, frameRefs~imth.frameRefs, frameType~imth.frameType, framesize~imth.framesize, altoCode~imth.altoCode, residentFrame~imth.residentFrame, crossJumped~imth.crossJumped, packageable~FALSE, gfi~nGfi, ngfi~imth.ngfi, variables~AddVariables[bcd, iBcd, imth.variables], extension~multiple[ -- this fake config has NO linkage information links~BcdDefs.LFNull, refLiterals~BcdDefs.RFNull, types~BcdDefs.TFNull]]; nGfi _ nGfi + imth.ngfi}; nGfi _ relGfi; [] _ BcdOps.ProcessModules[iBcd, ForEachModule]; bcd.ssLimit _ StringBody[nameString.string.length].SIZE}; WriteBcd: PUBLIC SAFE PROC[ bcd: Bcd, stream: IO.STREAM, AcquireFile: LoaderOpsExtras.AcquireFileProc] ~ TRUSTED { base: BcdDefs.BcdBase ~ bcd.base; next: CARDINAL _ BcdDefs.BCD.SIZE; Chunk: TYPE~RECORD[offset: CARDINAL, size: CARDINAL, next: REF Chunk_NIL]; chunkHead, chunkTail: REF Chunk _ NIL; LinkChunk: PROC[oldOffset: CARDINAL, limit: RelPointer] RETURNS[offset: CARDINAL] ~ { size: CARDINAL ~ limit-RelPointer.FIRST; node: REF Chunk ~ NEW[Chunk _ [offset~oldOffset, size~size]]; IF chunkHead = NIL THEN chunkHead _ chunkTail _ node ELSE chunkTail _ chunkTail.next _ node; offset _ next; next _ next + size; RETURN}; PutBlock: PROC[addr: LONG POINTER, size: CARDINAL] ~ { stream.UnsafePutBlock[[base~addr, startIndex~0, count~size*Basics.bytesPerWord]]}; MoveToPage: PROC[page: CARDINAL] ~ { pos: INT ~ page.LONG*(PrincOps.wordsPerPage*Basics.bytesPerWord); IF pos > stream.GetLength THEN stream.SetLength[pos]; stream.SetIndex[pos]}; AppendPages: PROC[file: FS.OpenFile, base, count: CARDINAL] ~ { bufferSpace: VM.Interval _ VM.Allocate[count~count]; { ENABLE UNWIND => bufferSpace.Free[]; buffer: LONG POINTER ~ VM.AddressForPageNumber[bufferSpace.page]; file.Read[from~base, nPages~count, to~buffer]; PutBlock[buffer, count*PrincOps.wordsPerPage]; }; VM.Free[bufferSpace]}; ctb: BcdDefs.Base ~ LOOPHOLE[base + base.ctOffset]; sgb: BcdDefs.Base ~ LOOPHOLE[base + base.sgOffset]; ftb: BcdDefs.Base ~ LOOPHOLE[base + base.ftOffset]; nameString: BcdDefs.NameString ~ LOOPHOLE[base + base.ssOffset]; basePages, rtPages, nextPage: CARDINAL; SegLoc: TYPE~RECORD[fti: BcdDefs.FTIndex, base: CARDINAL, next: REF SegLoc_NIL]; mapHead, mapTail: REF SegLoc _ NIL; EnumerateSegs: PROC[ForEach: PROC[sgi: BcdDefs.SGIndex]] ~ { <> FOR sgi: BcdDefs.SGIndex _ BcdDefs.SGIndex.FIRST, sgi + BcdDefs.SGRecord.SIZE UNTIL sgi = base.sgLimit DO ForEach[sgi] ENDLOOP }; MapCodeSegs: PROC[sgi: BcdDefs.SGIndex]~ { IF sgb[sgi].class = $code THEN { node: REF SegLoc ~ NEW[SegLoc _ [fti~sgb[sgi].file, base~sgb[sgi].base]]; IF mapHead = NIL THEN mapHead _ mapTail _ node ELSE mapTail _ mapTail.next _ node; sgb[sgi].file _ BcdDefs.FTSelf; sgb[sgi].base _ nextPage+1; -- + 1 for old Alto confusion nextPage _ nextPage + (sgb[sgi].pages + sgb[sgi].extraPages)}; }; MoveCodeSegs: PROC[sgi: BcdDefs.SGIndex] ~ { IF sgb[sgi].class = $code THEN { fti: BcdDefs.FTIndex ~ mapHead.fti; file: FS.OpenFile ~ AcquireFile[RopeFromNS[base, ftb[fti].name], ftb[fti].version]; AppendPages[file, mapHead.base-1, sgb[sgi].pages + sgb[sgi].extraPages]; -- - 1, ditto mapHead _ mapHead.next}; }; ctb[BcdDefs.CTIndex.FIRST].file _ BcdDefs.FTSelf; base.ssLimit _ StringBody[nameString.string.length].SIZE; base.ssOffset _ LinkChunk[base.ssOffset, RelPointer.FIRST+base.ssLimit]; base.ctOffset _ LinkChunk[base.ctOffset, base.ctLimit]; base.mtOffset _ LinkChunk[base.mtOffset, base.mtLimit]; base.impOffset _ LinkChunk[base.impOffset, base.impLimit]; base.expOffset _ LinkChunk[base.expOffset, base.expLimit]; base.ntOffset _ LinkChunk[base.ntOffset, base.ntLimit]; base.evOffset _ LinkChunk[base.evOffset, base.evLimit]; base.sgOffset _ LinkChunk[base.sgOffset, base.sgLimit]; base.ftOffset _ LinkChunk[base.ftOffset, base.ftLimit]; base.lfOffset _ LinkChunk[base.lfOffset, base.lfLimit]; base.rfOffset _ LinkChunk[base.rfOffset, base.rfLimit]; base.tfOffset _ LinkChunk[base.tfOffset, base.tfLimit]; basePages _ (next + (PrincOps.wordsPerPage-1))/PrincOps.wordsPerPage; rtPages _ ((bcd.literals).SegmentSize + (PrincOps.wordsPerPage-1))/PrincOps.wordsPerPage; base.nPages _ nextPage _ basePages + rtPages; base.rtPages _ [relPageBase~basePages, pages~rtPages]; EnumerateSegs[MapCodeSegs]; PutBlock[base, BcdDefs.BCD.SIZE]; FOR chunk: REF Chunk _ chunkHead, chunk.next UNTIL chunk = NIL DO PutBlock[base+chunk.offset, chunk.size]; ENDLOOP; MoveToPage[basePages]; IF rtPages # 0 THEN {(bcd.literals).Write[stream]; MoveToPage[base.nPages]}; EnumerateSegs[MoveCodeSegs]}; DeleteBcd: PUBLIC SAFE PROC[bcd: Bcd] ~ TRUSTED { IF bcd # NIL AND bcd.space # VM.nullInterval THEN { IF bcd.literals # NIL THEN {(bcd.literals).Finalize[]; bcd.literals _ NIL}; bcd.space.Free[]; bcd.space _ VM.nullInterval; bcd.base _ NIL}; }; <> DeclareControl: PUBLIC SAFE PROC[bcd: Bcd, module: LoadState.ModuleIndex] ~ TRUSTED { ctb: BcdDefs.Base ~ LOOPHOLE[bcd.base + bcd.base.ctOffset]; cti: BcdDefs.CTIndex ~ BcdDefs.CTIndex.FIRST; n: CARDINAL ~ ctb[cti].nControls; size: CARDINAL ~ BcdDefs.CTRecord.SIZE + (n+1)*BcdDefs.ControlItem.SIZE; Check[cti+size, nctp*PrincOps.wordsPerPage]; ctb[cti].controls[n] _ [module[IndexToMti[bcd.base, module]]]; ctb[cti].nControls _ n+1; bcd.base.ctLimit _ cti+size}; DeclareImport: PUBLIC SAFE PROC[ bcd: Bcd, formal, type: Rope.ROPE, stamp: BcdDefs.VersionStamp] RETURNS[index: CARDINAL] ~ TRUSTED { impb: BcdDefs.Base ~ LOOPHOLE[bcd.base + bcd.base.impOffset]; impi: BcdDefs.IMPIndex ~ bcd.base.impLimit; Check[impi + BcdDefs.IMPRecord.SIZE, nimp*PrincOps.wordsPerPage]; bcd.base.impLimit _ impi + BcdDefs.IMPRecord.SIZE; impb[impi] _ [ name~NewName[bcd.base, type], port~$interface, namedInstance~FALSE, file~BcdDefs.FTNull, gfi~BcdDefs.NullModule, ngfi~TRASH]; IF ~formal.Equal[type] THEN { NewNamed[bcd.base, [NewName[bcd.base, formal], [import[impi]]]]; impb[impi].namedInstance _ TRUE}; bcd.base.nImports _ bcd.base.nImports+1; RETURN[(impi-BcdDefs.IMPIndex.FIRST)/BcdDefs.IMPRecord.SIZE]}; FillImport: PUBLIC SAFE PROC[ bcd: Bcd, index: CARDINAL, iBcd: BcdDefs.BcdBase, iImpi: BcdDefs.IMPIndex] RETURNS[BcdDefs.ModuleIndex] ~ TRUSTED { base: BcdDefs.BcdBase ~ bcd.base; impb: BcdDefs.Base ~ LOOPHOLE[base + base.impOffset]; impi: BcdDefs.IMPIndex ~ BcdDefs.IMPIndex.FIRST + index*BcdDefs.IMPRecord.SIZE; iImpb: BcdDefs.Base ~ LOOPHOLE[iBcd + iBcd.impOffset]; impb[impi].port _ iImpb[iImpi].port; impb[impi].file _ AddFile[base, iBcd, iImpb[iImpi].file, NIL]; impb[impi].gfi _ bcd.base.firstdummy+bcd.base.nDummies; impb[impi].ngfi _ iImpb[iImpi].ngfi; bcd.base.nDummies _ bcd.base.nDummies+impb[impi].ngfi; RETURN[impb[impi].gfi]}; DeclareExport: PUBLIC SAFE PROC[ bcd: Bcd, name: Rope.ROPE, stamp: BcdDefs.VersionStamp, size: NAT, getLink: SAFE PROC[NAT] RETURNS[BcdDefs.Link]] ~ TRUSTED { expb: BcdDefs.Base ~ LOOPHOLE[bcd.base + bcd.base.expOffset]; expi: BcdDefs.EXPIndex ~ bcd.base.expLimit; expSize: NAT ~ BcdDefs.EXPRecord.SIZE + size*BcdDefs.Link.SIZE; Check[expi + expSize, nexp*PrincOps.wordsPerPage]; bcd.base.expLimit _ expi + expSize; expb[expi] _ [ name~NewName[bcd.base, name], size~size, port~$interface, namedInstance~FALSE, typeExported~FALSE, file~NewFile[bcd.base, stamp, name], links~TRASH]; FOR i: NAT IN [0 .. size) DO expb[expi].links[i] _ getLink[i] -- check for exported type here? ENDLOOP; bcd.base.nExports _ bcd.base.nExports+1}; OpenLinks: PUBLIC SAFE PROC[ bcd: Bcd, module: LoadState.ModuleIndex, relGfi: NAT, size: NAT] RETURNS[h: MTHandle] ~ TRUSTED { ForEachModule: PROC[mth: BcdDefs.MTHandle, mti: BcdDefs.MTIndex] RETURNS[stop: BOOL] ~ { IF module+relGfi IN [mth.gfi .. mth.gfi+mth.ngfi) THEN { WITH m~~mth SELECT FROM multiple => { lfb: BcdDefs.Base ~ LOOPHOLE[bcd.base + bcd.base.lfOffset]; lfi: BcdDefs.LFIndex ~ bcd.base.lfLimit; nw: CARDINAL ~ BcdDefs.LinkFrag[size].SIZE; Check[lfi + nw, nlfp*PrincOps.wordsPerPage]; m.links _ lfi; LOOPHOLE[@lfb[lfi].frag, LONG POINTER TO NAT]^ _ size; FOR i: NAT IN [0..size) DO lfb[lfi][i] _ BcdDefs.NullLink ENDLOOP; bcd.base.lfLimit _ lfi + nw}; ENDCASE => ERROR; h _ mti; stop _ TRUE} ELSE stop _ FALSE}; [] _ BcdOps.ProcessModules[bcd.base, ForEachModule]; RETURN}; ReadLink: PUBLIC SAFE PROC[bcd: Bcd, mth: MTHandle, offset: NAT] RETURNS[BcdDefs.Link] ~ TRUSTED { mtb: BcdDefs.Base ~ LOOPHOLE[bcd.base + bcd.base.mtOffset]; lfb: BcdDefs.Base ~ LOOPHOLE[bcd.base + bcd.base.lfOffset]; RETURN[WITH m~~mtb[mth] SELECT FROM direct => m.frag[offset], indirect => lfb[m.links].frag[offset], multiple => lfb[m.links].frag[offset], ENDCASE => BcdDefs.NullLink] }; WriteLink: PUBLIC SAFE PROC[ bcd: Bcd, mth: MTHandle, offset: NAT, link: BcdDefs.Link] ~ TRUSTED { mtb: BcdDefs.Base ~ LOOPHOLE[bcd.base + bcd.base.mtOffset]; lfb: BcdDefs.Base ~ LOOPHOLE[bcd.base + bcd.base.lfOffset]; WITH m~~mtb[mth] SELECT FROM direct => m.frag[offset] _ link; indirect => lfb[m.links].frag[offset] _ link; multiple => lfb[m.links].frag[offset] _ link; ENDCASE; }; OpenLiterals: PUBLIC SAFE PROC[bcd: Bcd, iBcd: BcdDefs.BcdBase] ~ TRUSTED { MapFile: PROC[iFti: BcdDefs.FTIndex] RETURNS[BcdDefs.FTIndex] ~ { RETURN[AddFile[bcd.base, iBcd, iFti, NIL]]}; MapSegment: PROC[iSgi: BcdDefs.SGIndex] RETURNS[BcdDefs.SGIndex] ~ { RETURN[AddSegment[bcd.base, iBcd, iSgi, NIL]]}; IF bcd.literals = NIL THEN bcd.literals _ BcdLiterals.Create[]; [] _ (bcd.literals).Load[iBcd, MapFile, MapSegment]}; ImportLiterals: PUBLIC SAFE PROC[ bcd: Bcd, mth: MTHandle, iBcd: BcdDefs.BcdBase, iMti: BcdDefs.MTIndex] ~ TRUSTED { mtb: BcdDefs.Base ~ LOOPHOLE[bcd.base + bcd.base.mtOffset]; iMtb: BcdDefs.Base ~ LOOPHOLE[iBcd + iBcd.mtOffset]; WITH m~~mtb[mth] SELECT FROM multiple => WITH iM~~iMtb[iMti] SELECT FROM multiple => { IF iM.refLiterals # BcdDefs.RFNull THEN { rfb: BcdDefs.Base ~ LOOPHOLE[bcd.base + bcd.base.rfOffset]; iRfb: BcdDefs.Base ~ LOOPHOLE[iBcd + iBcd.rfOffset]; rfi: BcdDefs.RFIndex ~ bcd.base.rfLimit; iRfi: BcdDefs.RFIndex ~ iM.refLiterals; nw: CARDINAL ~ BcdDefs.RefLitFrag[iRfb[iRfi].length].SIZE; Check[rfi + nw, nrfp*PrincOps.wordsPerPage]; m.refLiterals _ rfi; rfb[rfi].offset _ iRfb[iRfi].offset; LOOPHOLE[@rfb[rfi].frag, LONG POINTER TO NAT]^ _ iRfb[iRfi].length; FOR i: NAT IN [0 .. rfb[rfi].length) DO rfb[rfi].frag[i] _ (bcd.literals).MapLitLink[iRfb[iRfi].frag[i]] ENDLOOP; bcd.base.rfLimit _ rfi + nw}; IF iM.types # BcdDefs.TFNull THEN { tfb: BcdDefs.Base ~ LOOPHOLE[bcd.base + bcd.base.tfOffset]; iTfb: BcdDefs.Base ~ LOOPHOLE[iBcd + iBcd.tfOffset]; tfi: BcdDefs.TFIndex ~ bcd.base.tfLimit; iTfi: BcdDefs.TFIndex ~ iM.types; nw: CARDINAL ~ BcdDefs.TypeFrag[iTfb[iTfi].length].SIZE; Check[tfi + nw, ntfp*PrincOps.wordsPerPage]; m.types _ tfi; tfb[tfi].offset _ iTfb[iTfi].offset; LOOPHOLE[@tfb[tfi].frag, LONG POINTER TO NAT]^ _ iTfb[iTfi].length; FOR i: NAT IN [0 .. tfb[tfi].length) DO tfb[tfi].frag[i] _ (bcd.literals).MapTypeLink[iTfb[iTfi].frag[i]] ENDLOOP; bcd.base.tfLimit _ tfi + nw}; } ENDCASE => NULL; ENDCASE => ERROR }; CloseLiterals: PUBLIC SAFE PROC[bcd: Bcd, iBcd: BcdDefs.BcdBase] ~ TRUSTED { (bcd.literals).Unload[]}; <> Base: PUBLIC SAFE PROC[bcd: Bcd] RETURNS[BcdDefs.BcdBase] ~ CHECKED { RETURN[bcd.base]}; RopeFromNS: PUBLIC SAFE PROC[bcd: BcdDefs.BcdBase, name: BcdDefs.NameRecord] RETURNS[Rope.ROPE] ~ TRUSTED { nameString: BcdDefs.NameString ~ LOOPHOLE[bcd+bcd.ssOffset]; i: CARDINAL _ 0; EachChar: SAFE PROC RETURNS[c: CHAR] ~ TRUSTED { c _ nameString.string.text[name+i]; i _ i+1; RETURN}; RETURN[Rope.FromProc[nameString.size[name], EachChar]]}; }.