-- IncludesSymTablesImpl.Mesa
-- Last modified by Sandman on July 8, 1980  9:16 AM
-- Last modified by Lewis on October 7, 1980  6:24 PM
-- Copyright  Xerox Corporation 1979, 1980

DIRECTORY
  AltoDefs USING [PageCount, PageNumber, PageSize],
  InlineDefs USING [DIVMOD],
  FileLists USING [tablesPages],
  IncludesSymTables USING [],
  SegmentDefs USING [
    DeleteFileSegment, FileHandle, FileSegmentAddress, FileSegmentHandle,
    NewFileSegment, Read, SwapIn, Unlock],
  SymbolSegment USING [BlockDescriptor, STHeader, VersionID],
  Symbols USING [HTIndex, HTRecord, MDIndex],
  Storage USING [PagesForWords],
  Table USING [Base];

IncludesSymTablesImpl: PROGRAM
    IMPORTS FileLists, InlineDefs, SegmentDefs, Storage
    EXPORTS IncludesSymTables =
  BEGIN
  
  ObsoleteSymbolTable: PUBLIC ERROR = CODE;
  
  SymTablesAlreadyOpen: ERROR = CODE;
  SymTablesNotOpen: ERROR = CODE;
  
  mdb: PUBLIC Table.Base;
  mdLimit: PUBLIC Symbols.MDIndex;
  ssb: PUBLIC STRING; 
  ht: PUBLIC DESCRIPTOR FOR ARRAY Symbols.HTIndex OF Symbols.HTRecord;
  
  
  fastAndLarge: BOOLEAN ← TRUE; -- true if one segment for symbols
  
  symFileSeg: SegmentDefs.FileSegmentHandle ← NIL; -- if fastAndLarge
  
  moduleTableFileSeg: SegmentDefs.FileSegmentHandle ← NIL; -- if ~fastAndLarge
  stringFileSeg: SegmentDefs.FileSegmentHandle ← NIL;
  hashTableFileSeg: SegmentDefs.FileSegmentHandle ← NIL;
  
  moduleTableDesc: SymbolSegment.BlockDescriptor;
  stringDesc: SymbolSegment.BlockDescriptor;
  hashTableDesc: SymbolSegment.BlockDescriptor;

  
  symTablesOpen: BOOLEAN ← FALSE;
  
  LoadSymTables: PUBLIC PROC [
      symFile: SegmentDefs.FileHandle,
      symSegBase, symSegSize: AltoDefs.PageNumber] =
    BEGIN
    IF symTablesOpen THEN ERROR SymTablesAlreadyOpen;
    fastAndLarge ← (FileLists.tablesPages < 70) AND (symSegSize < 30);
    IF fastAndLarge THEN 
      LoadSingleSymFileSeg[symFile, symSegBase, symSegSize]
    ELSE 
      LoadSeparateSymFileSegs[symFile, symSegBase];
    symTablesOpen ← TRUE;
    END;

    
  LoadSingleSymFileSeg: PROC [
      symFile: SegmentDefs.FileHandle,
      symSegBase, symSegSize: AltoDefs.PageNumber] =
    BEGIN OPEN SegmentDefs;
    symFileSeg ← NewFileSegment[symFile, symSegBase, symSegSize, Read];
    ReadSingleSymFileSeg[];
    END;
    
  ReadSingleSymFileSeg: PROC =
    BEGIN OPEN SegmentDefs;
    header: POINTER TO SymbolSegment.STHeader;
    SwapIn[symFileSeg];
    header ← FileSegmentAddress[symFileSeg];
    IF header.versionIdent # SymbolSegment.VersionID THEN
      ERROR ObsoleteSymbolTable[
	! UNWIND =>
	    BEGIN
	    Unlock[symFileSeg];
	    DeleteFileSegment[symFileSeg];
	    symFileSeg ← NIL;
	    END];
    moduleTableDesc ← header.mdBlock;
    stringDesc ← header.ssBlock;
    hashTableDesc ← header.htBlock;
    ht ← DESCRIPTOR[
      (FileSegmentAddress[symFileSeg] + hashTableDesc.offset),
	hashTableDesc.size/SIZE[Symbols.HTRecord]];
    ssb ← FileSegmentAddress[symFileSeg] + stringDesc.offset;
    mdb ←
      LOOPHOLE[FileSegmentAddress[symFileSeg], Table.Base] +
	moduleTableDesc.offset;
    mdLimit ← LOOPHOLE[moduleTableDesc.size];
    END;

    
  LoadSeparateSymFileSegs: PROC [
    symFile: SegmentDefs.FileHandle, symSegBase: AltoDefs.PageNumber] =
    BEGIN OPEN SegmentDefs;
    symSegHeaderFileSeg: FileSegmentHandle;
    header: POINTER TO SymbolSegment.STHeader;
    offsetPages: AltoDefs.PageNumber;
    offsetInPage: CARDINAL;
    modFileSegSize, strFileSegSize, hashFileSegSize: AltoDefs.PageNumber;
    symSegHeaderFileSeg ← NewFileSegment[
      file: symFile, 
      base: symSegBase, 
      pages: Storage.PagesForWords[SIZE[SymbolSegment.STHeader]],
      access: Read];
    SwapIn[symSegHeaderFileSeg];
    header ← FileSegmentAddress[symSegHeaderFileSeg];
    IF header.versionIdent # SymbolSegment.VersionID THEN
      ERROR ObsoleteSymbolTable[
	! UNWIND =>
	    BEGIN
	    Unlock[symSegHeaderFileSeg];
	    DeleteFileSegment[symSegHeaderFileSeg];
	    symSegHeaderFileSeg ← NIL;
	    END];
    moduleTableDesc ← header.mdBlock;
    stringDesc ← header.ssBlock;
    hashTableDesc ← header.htBlock;
    Unlock[symSegHeaderFileSeg];
    DeleteFileSegment[symSegHeaderFileSeg];
    [offsetPages, offsetInPage] ← InlineDefs.DIVMOD[ -- hash table
      hashTableDesc.offset, AltoDefs.PageSize];
    hashFileSegSize ← Storage.PagesForWords[hashTableDesc.size + offsetInPage];
    hashTableFileSeg ← NewFileSegment[
      symFile, (symSegBase + offsetPages), hashFileSegSize, Read];
    [offsetPages, offsetInPage] ← InlineDefs.DIVMOD[ -- string table
      stringDesc.offset, AltoDefs.PageSize];
    strFileSegSize ← Storage.PagesForWords[stringDesc.size + offsetInPage];
    stringFileSeg ← NewFileSegment[
      symFile, (symSegBase + offsetPages), strFileSegSize, Read];
    [offsetPages, offsetInPage] ← InlineDefs.DIVMOD[ -- module table
      moduleTableDesc.offset, AltoDefs.PageSize];
    modFileSegSize ← Storage.PagesForWords[moduleTableDesc.size + offsetInPage];
    moduleTableFileSeg ← NewFileSegment[
      symFile, (symSegBase + offsetPages), modFileSegSize, Read];
    ReadSeparateSymFileSegs[];
    END;
    
  ReadSeparateSymFileSegs: PROC =
    BEGIN OPEN SegmentDefs;
    offsetInPage: CARDINAL;
    SwapIn[hashTableFileSeg]; 
    offsetInPage ← hashTableDesc.offset MOD AltoDefs.PageSize;
    ht ← DESCRIPTOR[
      (FileSegmentAddress[hashTableFileSeg] + offsetInPage),
	hashTableDesc.size/SIZE[Symbols.HTRecord]];
    SwapIn[stringFileSeg]; 
    offsetInPage ← stringDesc.offset MOD AltoDefs.PageSize;
    ssb ← FileSegmentAddress[stringFileSeg] + offsetInPage;
    SwapIn[moduleTableFileSeg]; 
    offsetInPage ← moduleTableDesc.offset MOD AltoDefs.PageSize;
    mdb ←
      LOOPHOLE[FileSegmentAddress[moduleTableFileSeg], Table.Base] + offsetInPage;
    mdLimit ← LOOPHOLE[moduleTableDesc.size];
    END;

    
  ReleaseSymTables: PUBLIC PROC =
    BEGIN OPEN SegmentDefs;
    IF ~symTablesOpen THEN ERROR SymTablesNotOpen;
    IF fastAndLarge THEN
      {Unlock[symFileSeg];  DeleteFileSegment[symFileSeg];  symFileSeg ← NIL}
    ELSE
      BEGIN
      Unlock[moduleTableFileSeg];
      DeleteFileSegment[moduleTableFileSeg];
      Unlock[stringFileSeg];
      DeleteFileSegment[stringFileSeg];
      Unlock[hashTableFileSeg];
      DeleteFileSegment[hashTableFileSeg];
      moduleTableFileSeg ← stringFileSeg ← hashTableFileSeg ← NIL;
      END;
    symTablesOpen ← FALSE;
    END;

    
  -- allow symbol table file segments to be swapped out and relocated if 
  -- necessary during file list table enlargement
  UnlockSymFileSegments: PUBLIC PROC =
    BEGIN OPEN SegmentDefs;
    IF fastAndLarge THEN {IF symFileSeg # NIL THEN Unlock[symFileSeg]}
    ELSE
      BEGIN
      IF moduleTableFileSeg # NIL THEN Unlock[moduleTableFileSeg];
      IF stringFileSeg # NIL THEN Unlock[stringFileSeg];
      IF hashTableFileSeg # NIL THEN Unlock[hashTableFileSeg];
      END;
    END;
    
  -- swap in (possibly relocated) symbol table file segments
  ReloadSymFileSegments: PUBLIC PROC =
    BEGIN
    IF fastAndLarge THEN {IF symFileSeg # NIL THEN ReadSingleSymFileSeg[]}
    ELSE
      IF moduleTableFileSeg # NIL AND stringFileSeg # NIL 
      AND hashTableFileSeg # NIL THEN 
	ReadSeparateSymFileSegs[];
    END;

  END.