-- File ModuleSymbolsImpl.mesa 
-- Last edited by Lewis on  5-Jan-82 19:46:02
-- Last edited by Satterthwaite, December 27, 1982 9:44 am

DIRECTORY
  BcdDefs USING [FTIndex, FTNull, FTSelf, MTIndex, SGIndex, SGNull, VersionStamp],
  CIFS: TYPE USING [OpenFile, GetFC],
  Environment USING [PageCount, wordsPerPage],
  Error USING [ErrorFile, WrongSymbolsVersion],
  FileTable USING [Build, Destroy, HandleForFile, UnknownFile],
  ModuleSymbols USING [],
  PackageSymbols,
  PackagerDefs USING [globalData],
  PrincOps USING [BytePC],
  SourceBcd USING [
    bcdBases, bcdHeader, EnumerateModules, ModuleNum, ModuleNumForMti],
  Space: TYPE USING [
    Handle, nullHandle, virtualMemory, CopyIn, Create, Delete, LongPointer, Map],
  String USING [SubString],
  SymbolPack,
  Symbols USING [HTIndex, HTNull, HTRecord],
  SymbolSegment USING [STHeader, VersionID],
  SymbolTable USING [Base],
  Table USING [Base];

ModuleSymbolsImpl: PROGRAM
    IMPORTS 
      CIFS, Error, FileTable, PackagerDefs, SourceBcd, Space,
      ownSymbolPack: SymbolPack
    EXPORTS ModuleSymbols =
  BEGIN  OPEN ModuleSymbols;

  InvalidSymbols: PUBLIC ERROR = CODE;
  SymbolsProblem: PUBLIC SIGNAL = CODE;
  
  symSeg: Space.Handle ← Space.nullHandle;
  symSegSize: Environment.PageCount ← 0;
  header: LONG POINTER TO SymbolSegment.STHeader ← NIL;
  symbolPackStarted: BOOL ← FALSE;
  
  nullFile: CIFS.OpenFile = NIL;
  
  SymbolInfoMap: TYPE = RECORD [
    SEQUENCE length: CARDINAL OF KnownSymbolsInfo];
  KnownSymbolsInfo: TYPE = RECORD [
    loadedBefore: BOOL,
    file: CIFS.OpenFile,
    base, pages: CARDINAL];
  knownSymbols: LONG POINTER TO SymbolInfoMap ← NIL;
    -- NB: the REFs here are protected by FileTableImpl
    
  outerPackArray: PUBLIC LONG DESCRIPTOR FOR
    ARRAY OF PackageSymbols.OuterPackRecord;
  innerPackArray: PUBLIC LONG DESCRIPTOR FOR
    ARRAY OF PackageSymbols.InnerPackRecord;
  constArray: PUBLIC LONG DESCRIPTOR FOR
    ARRAY OF PackageSymbols.ConstRecord;
  
  loadCodeOffsetTable: PUBLIC PackageSymbols.PCSeq;
  loadCodeByteOffsetTable: PUBLIC PackageSymbols.PCSeq;
  jumpIndirectTable: PUBLIC PackageSymbols.JISeq;


  Load: PUBLIC PROC [mti: BcdDefs.MTIndex] = {
    ENABLE UNWIND => Unload[];
    sgi: BcdDefs.SGIndex = SourceBcd.bcdBases.mtb[mti].sseg;
    fti: BcdDefs.FTIndex = SourceBcd.bcdBases.mtb[mti].file;
    mNum: SourceBcd.ModuleNum;
    -- known information about module mti
    base, pSymPages: CARDINAL;
    file: CIFS.OpenFile;
    codeVersion: BcdDefs.VersionStamp;
    
    PagesForWords: PROC [nWords: CARDINAL] RETURNS [Environment.PageCount] = INLINE
      BEGIN
      RETURN [(nWords + (Environment.wordsPerPage-1))/Environment.wordsPerPage]
      END;
      
    SELECT fti FROM
      BcdDefs.FTNull => {SIGNAL SymbolsProblem;  RETURN};
      BcdDefs.FTSelf => codeVersion ← SourceBcd.bcdHeader.version;
      ENDCASE => codeVersion ← SourceBcd.bcdBases.ftb[fti].version; 
    IF sgi = BcdDefs.SGNull THEN {SIGNAL SymbolsProblem;  RETURN};
    
    mNum ← SourceBcd.ModuleNumForMti[mti];
    [base: base, pages: pSymPages, file: file] ← knownSymbols[mNum];
    IF pSymPages > symSegSize THEN GrowSeg[minPages: pSymPages];
    symSeg.CopyIn[window: [file: file.GetFC, base: base]];
    IF ~knownSymbols[mNum].loadedBefore THEN {
      IF header.version # codeVersion THEN {
        Error.WrongSymbolsVersion[
          class: error, module: mti, 
	  requiredVersion: codeVersion, actualVersion: header.version];
	Unload[];
	ERROR InvalidSymbols};
      pSymPages ← PagesForWords[header.constBlock.offset + header.constBlock.size];
      IF pSymPages > symSegSize THEN GrowSeg[minPages: pSymPages];
      symSeg.CopyIn[window: [file: file.GetFC, base: base]];
      knownSymbols[mNum].pages ← pSymPages;
      knownSymbols[mNum].loadedBefore ← TRUE};
    InstallTable[ownSymbolPack ! ANY => Unload[]]};

  Unload: PUBLIC PROC = {
    outerPackArray ← NIL;
    innerPackArray ← NIL;
    constArray ← NIL;
    loadCodeOffsetTable ← NIL;
    loadCodeByteOffsetTable ← NIL;
    jumpIndirectTable ← NIL};
    
  InstallTable: PROC [base: SymbolTable.Base] = {
    b: LONG POINTER = LOOPHOLE[header];
    tB: Table.Base = LOOPHOLE[b];
    pCard: LONG POINTER TO CARDINAL;
    IF header.versionIdent # SymbolSegment.VersionID THEN ERROR InvalidSymbols;
    base.cacheInfo ← NIL;
    base.hashVec ← b + header.hvBlock.offset;
    base.ht ← DESCRIPTOR[
      b + header.htBlock.offset, 
      header.htBlock.size/SIZE[Symbols.HTRecord]];
    base.ssb ← b + header.ssBlock.offset;
    base.stHandle ← header;  
    base.sourceFile ← NIL;
    base.notifier ← base.NullNotifier;
    outerPackArray ← DESCRIPTOR[
      b + header.outerPackBlock.offset,
      (header.outerPackBlock.size / SIZE[PackageSymbols.OuterPackRecord])];
    innerPackArray ← DESCRIPTOR[
      b + header.innerPackBlock.offset,
      (header.innerPackBlock.size / SIZE[PackageSymbols.InnerPackRecord])];
    pCard ← LOOPHOLE[b + header.constBlock.offset];
    constArray ← DESCRIPTOR[pCard+1, pCard↑];
    loadCodeOffsetTable ← 
      LOOPHOLE[pCard + 1 + pCard↑ * SIZE[PackageSymbols.ConstRecord]];
    loadCodeByteOffsetTable ← LOOPHOLE[loadCodeOffsetTable + 1 + 
      loadCodeOffsetTable.length * SIZE[PrincOps.BytePC]];
    jumpIndirectTable ← LOOPHOLE[loadCodeByteOffsetTable + 1 + 
      loadCodeByteOffsetTable.length * SIZE[PrincOps.BytePC]]};


  FindProc: PUBLIC PROC [
      ss: String.SubString] RETURNS [opi: PackageSymbols.OPIndex] = {
    hti: Symbols.HTIndex = ownSymbolPack.FindString[ss];
    l, u, i: PackageSymbols.OPIndex;
    IF hti = Symbols.HTNull THEN RETURN[PackageSymbols.OPNull];
    l ← 1;  u ← (LENGTH[outerPackArray] - 1);
    WHILE l <= u DO
      i ← CARDINAL[l+u]/2;
      SELECT outerPackArray[i].hti FROM
	> hti => u ← i-1;
	< hti => l ← i+1;
	ENDCASE => RETURN[i];
      ENDLOOP;
    RETURN[PackageSymbols.OPNull]};


  Initialize: PUBLIC PROC [nModules: CARDINAL] = { 

    FillInKnowledge: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOL←FALSE] = {
      mNum: SourceBcd.ModuleNum = SourceBcd.ModuleNumForMti[mti];
      sgi: BcdDefs.SGIndex;
      base: CARDINAL;
      file: CIFS.OpenFile ← nullFile;
      IF SourceBcd.bcdBases.mtb[mti].tableCompiled THEN  -- ignore any symbols
        knownSymbols[mNum] ← [loadedBefore: FALSE, file: nullFile, base: 0, pages: 0]
      ELSE {
        sgi ← SourceBcd.bcdBases.mtb[mti].sseg;
        base ← SourceBcd.bcdBases.sgb[sgi].base;
        file ← FileTable.HandleForFile[SourceBcd.bcdBases.sgb[sgi].file
          ! FileTable.UnknownFile => { 
	      Error.ErrorFile[
	        error, "was needed for symbols but could not be found"L, fti];
	      CONTINUE} ];
        knownSymbols[mNum] ← [loadedBefore: FALSE, file: file, base: base, pages: 1]}; 
      RETURN};

    FileTable.Build[];
    CreateSeg[];
    knownSymbols ← PackagerDefs.globalData.zone.NEW[SymbolInfoMap[nModules]];
    SourceBcd.EnumerateModules[FillInKnowledge];
    IF ~symbolPackStarted THEN {START ownSymbolPack; symbolPackStarted ← TRUE}};

  Finalize: PUBLIC PROC = {
    Unload[];
    IF knownSymbols # NIL THEN {
      FOR i: CARDINAL IN [0..knownSymbols.length) DO
        knownSymbols[i].file ← nullFile;
	ENDLOOP;
      PackagerDefs.globalData.zone.FREE[@knownSymbols]};
    FileTable.Destroy[];
    DestroySeg[]};
    
    
 -- Input segment operations
  
  CreateSeg: PROC = {
    IF symSeg # Space.nullHandle THEN ERROR SymbolsProblem;
    symSegSize ← 30;
    symSeg ← Space.Create[size: symSegSize, parent: Space.virtualMemory];
--    file: NIL, release: [],
--    fileBase: 0, pages: symSegSize, swapInfo: [uniform[size: 3]]];
    symSeg.Map[];
    header ← symSeg.LongPointer};
    
  GrowSeg: PROC [minPages: Environment.PageCount] = {
    Space.Delete[symSeg];
    symSegSize ← ((minPages+2)/3 * 3);
    symSeg ← Space.Create[size: symSegSize, parent: Space.virtualMemory];
--  MSegment.Reset[
--   segment: symSeg, pages: symSegSize, swapInfo: [uniform[size: 4]]];
    symSeg.Map[];
    header ← symSeg.LongPointer};
      
  DestroySeg: PROC = {
    IF symSeg # Space.nullHandle THEN {
      Space.Delete[symSeg];
      symSeg ← Space.nullHandle; symSegSize ← 0; header ← NIL}};
    
  END.