-- RCMapWalkerImpl.mesa
  -- Last Modified By Paul Rovner On 8-Mar-82 10:46:25

DIRECTORY
        Inline USING[LongCOPY],
        RTBasic USING[Pointer],
        SafeStorage USING[],
        RTStorageOps USING[],
        RTFlags USING[checking],
        RTCommon USING[FetchField],
        RCMap USING[Base, Index],
        RCMapOps USING[GetBase],
        RTTypesBasic USING[GetReferentType, Type],
        RTTypesBasicPrivate USING[MapTiRcmx];

RCMapWalkerImpl: PROGRAM
  IMPORTS RCMapOps, RTCommon, RTTypesBasic, RTTypesBasicPrivate, Inline
  EXPORTS RTStorageOps, RTTypesBasicPrivate

= BEGIN OPEN RTBasic, SafeStorage, RTStorageOps, RTTypesBasic, RTTypesBasicPrivate, RTCommon;

  NotImplemented: PUBLIC ERROR[msg: STRING] = CODE;

  checking: BOOLEAN = RTFlags.checking;
  rcmb: RCMap.Base = RCMapOps.GetBase[].base;

  AssignComposite: PUBLIC PROC[rhs, lhs: Pointer, type: Type, nwords: CARDINAL] =
    {DoAssignComposite[rhs, lhs, type, nwords]};
    
  DoAssignComposite: PROC[rhs, lhs: Pointer, type: Type, nwords: CARDINAL] =
INLINE
    { rcmx: RCMap.Index = MapTiRcmx[type];
      IF checking THEN
            WITH rcmr: rcmb[rcmx] SELECT FROM  -- in case there are mutable variants
              variant =>
                { v1: CARDINAL =
                        FetchField[lhs + rcmr.fdTag.wordOffset,
                                   [bitFirst: rcmr.fdTag.bitFirst,
                                    bitCount: rcmr.fdTag.bitCount]];
                  v2: CARDINAL =
                        FetchField[rhs + rcmr.fdTag.wordOffset,
                                   [bitFirst: rcmr.fdTag.bitFirst,
                                    bitCount: rcmr.fdTag.bitCount]];
                  IF v1 # v2 THEN ERROR NotImplemented["mutable variant records"]};
              sequence =>
                { v1: CARDINAL =
                        FetchField[lhs + rcmr.fdLength.wordOffset,
                                   [bitFirst: rcmr.fdLength.bitFirst,
                                    bitCount: rcmr.fdLength.bitCount]];
                  v2: CARDINAL =
                        FetchField[rhs + rcmr.fdLength.wordOffset,
                                   [bitFirst: rcmr.fdLength.bitFirst, 
                                    bitCount: rcmr.fdLength.bitCount]];
                  IF v1 # v2 THEN ERROR NotImplemented["mutable sequences"]};
             ENDCASE;
      ASSIGNify[rhs, rcmx, LOOPHOLE[lhs, LONG CARDINAL] - LOOPHOLE[rhs, LONG CARDINAL]];
      Inline.LongCOPY[from: rhs, to: lhs, nwords: nwords]};

  AssignCompositeNew: PUBLIC PROC[rhs, lhs: Pointer, type: Type, nwords: CARDINAL] =
    { d: LONG CARDINAL = LOOPHOLE[lhs, LONG CARDINAL] - LOOPHOLE[rhs, LONG CARDINAL];
      ASSIGNNEWify[rhs, MapTiRcmx[type], d];
      Inline.LongCOPY[from: rhs, to: lhs, nwords: nwords]};

  FreeCollectibleObject: PUBLIC PROC[refObj: REF ANY] =
    {NILify[LOOPHOLE[refObj], MapTiRcmx[GetReferentType[refObj]]]};

  MapRefs: PUBLIC PROC[ptr: Pointer, rcmx: RCMap.Index, procLeaf: PROC[p: REF ANY]] =
    {MapComponents[ptr, rcmx, procLeaf]};

  DoFREEify: PUBLIC PROC[ptr: Pointer, rcmx: RCMap.Index, procLeaf: PROC[p: REF ANY]] =
    {INLDoMapComponents[ptr, rcmx, procLeaf]};

  MapRefOffsets: PUBLIC PROC[ref: REF ANY, procLeaf: PROC[offset: LONG CARDINAL]] =
    {DoMapRefOffsets[LOOPHOLE[ref], MapTiRcmx[GetReferentType[ref]], procLeaf]};

  DoMapRefOffsets: PROC[ptr: Pointer, rcmx: RCMap.Index, procLeaf: PROC[offset: LONG CARDINAL]] =
    { WITH rcmr: rcmb[rcmx] SELECT FROM
        simple =>
            {FOR i: CARDINAL IN [0..rcmr.length) DO IF rcmr.refs[i] THEN procLeaf[i] ENDLOOP};
        oneRef => procLeaf[rcmr.offset];
        ref => procLeaf[0];
        null => NULL;
        nonVariant =>
          FOR i: CARDINAL IN [0..rcmr.nComponents) DO
            DoMapRefOffsets[ptr + rcmr.components[i].wordOffset, rcmr.components[i].rcmi, procLeaf];
           ENDLOOP;
        variant =>
          {v: CARDINAL =
                 FetchField[ptr + rcmr.fdTag.wordOffset,
                            [bitFirst: rcmr.fdTag.bitFirst, bitCount: rcmr.fdTag.bitCount]];
           IF checking THEN IF v > rcmr.nVariants THEN ERROR;
           DoMapRefOffsets[ptr, rcmr.variants[v], procLeaf]};
        array =>
          FOR i: CARDINAL IN [0..rcmr.nElements) DO
            DoMapRefOffsets[ptr + i * rcmr.wordsPerElement, rcmr.rcmi, procLeaf];
           ENDLOOP;
        sequence =>
          {length: CARDINAL =
                 FetchField[ptr+rcmr.fdLength.wordOffset,
                            [bitFirst: rcmr.fdLength.bitFirst, bitCount: rcmr.fdLength.bitCount]];
           DoMapRefOffsets[ptr, rcmr.commonPart, procLeaf];
           FOR i: CARDINAL IN [0..length) DO
             DoMapRefOffsets[ptr + rcmr.dataOffset + i * rcmr.wordsPerElement, rcmr.rcmi, procLeaf];
            ENDLOOP};
       ENDCASE => ERROR
    };

  ASSIGNNEWify: PROC[ptr: Pointer, rcmx: RCMap.Index, d: LONG CARDINAL] =
  INLINE
     {WITH rcmr: rcmb[rcmx] SELECT FROM
          simple =>
            { FOR i: CARDINAL IN [0..rcmr.length) DO
               IF rcmr.refs[i] THEN
                 { LOOPHOLE[ptr+i+d, REF LONG CARDINAL]↑ ← 0;
                   LOOPHOLE[ptr+i+d, REF REF ANY]↑ ← LOOPHOLE[ptr+i, LONG POINTER TO REF ANY]↑};
               ENDLOOP};
          oneRef =>
            { f: CARDINAL = rcmr.offset;
              LOOPHOLE[ptr+d+f, REF LONG CARDINAL]↑ ← 0;
              LOOPHOLE[ptr+d+f, REF REF ANY]↑ ← LOOPHOLE[ptr+f, LONG POINTER TO REF ANY]↑};
          ref =>
            { LOOPHOLE[ptr+d, REF LONG CARDINAL]↑ ← 0;
              LOOPHOLE[ptr+d, REF REF ANY]↑ ← LOOPHOLE[ptr, LONG POINTER TO REF ANY]↑};
          null => NULL;
         ENDCASE => DoASSIGNNEWify[ptr, rcmx, d]};

  DoASSIGNNEWify: PROC[ptr: Pointer, rcmx: RCMap.Index, d: LONG CARDINAL] =
     { WITH rcmr: rcmb[rcmx] SELECT FROM
        nonVariant =>
          FOR i: CARDINAL IN [0..rcmr.nComponents) DO
            ASSIGNNEWify[ptr + rcmr.components[i].wordOffset, rcmr.components[i].rcmi, d];
           ENDLOOP;
        variant =>
          {v: CARDINAL =
                 FetchField[ptr + rcmr.fdTag.wordOffset,
                            [bitFirst: rcmr.fdTag.bitFirst, bitCount: rcmr.fdTag.bitCount]];
           IF checking THEN IF v > rcmr.nVariants THEN ERROR;
           ASSIGNNEWify[ptr, rcmr.variants[v], d]};
        array =>
          FOR i: CARDINAL IN [0..rcmr.nElements) DO
            ASSIGNNEWify[ptr + i * rcmr.wordsPerElement, rcmr.rcmi, d];
           ENDLOOP;
        sequence =>
          {length: CARDINAL =
                 FetchField[ptr+rcmr.fdLength.wordOffset,
                            [bitFirst: rcmr.fdLength.bitFirst, bitCount: rcmr.fdLength.bitCount]];
           ASSIGNNEWify[ptr, rcmr.commonPart, d];
           FOR i: CARDINAL IN [0..length) DO
             ASSIGNNEWify[ptr + rcmr.dataOffset + i * rcmr.wordsPerElement, rcmr.rcmi, d];
            ENDLOOP;
          };
       ENDCASE => ERROR
     };

  ASSIGNify: PROC[ptr: Pointer, rcmx: RCMap.Index, d: LONG CARDINAL] =
  INLINE
     {  WITH rcmr: rcmb[rcmx] SELECT FROM
          simple =>
            FOR i: CARDINAL IN [0..rcmr.length) DO
              IF rcmr.refs[i] THEN
                LOOPHOLE[ptr+i+d, REF REF ANY]↑ ← LOOPHOLE[ptr+i, LONG POINTER TO REF ANY]↑;
             ENDLOOP;
          oneRef =>
            { f: CARDINAL = rcmr.offset;
              LOOPHOLE[ptr+d+f, REF REF ANY]↑ ← LOOPHOLE[ptr+f, LONG POINTER TO REF ANY]↑};
          ref => LOOPHOLE[ptr+d, REF REF ANY]↑ ← LOOPHOLE[ptr, LONG POINTER TO REF ANY]↑;
          null => NULL;
         ENDCASE => DoASSIGNify[ptr, rcmx, d]};

  DoASSIGNify: PROC[ptr: Pointer, rcmx: RCMap.Index, d: LONG CARDINAL] =
     { WITH rcmr: rcmb[rcmx] SELECT FROM
        nonVariant =>
          FOR i: CARDINAL IN [0..rcmr.nComponents) DO
            ASSIGNify[ptr + rcmr.components[i].wordOffset, rcmr.components[i].rcmi, d];
           ENDLOOP;
        variant =>
          {v: CARDINAL =
                 FetchField[ptr + rcmr.fdTag.wordOffset,
                            [bitFirst: rcmr.fdTag.bitFirst, bitCount: rcmr.fdTag.bitCount]];
           IF checking THEN IF v > rcmr.nVariants THEN ERROR;
           ASSIGNify[ptr, rcmr.variants[v], d]};
        array =>
          FOR i: CARDINAL IN [0..rcmr.nElements) DO
            ASSIGNify[ptr + i * rcmr.wordsPerElement, rcmr.rcmi, d];
           ENDLOOP;
        sequence =>
          {length: CARDINAL =
                 FetchField[ptr+rcmr.fdLength.wordOffset,
                            [bitFirst: rcmr.fdLength.bitFirst, bitCount: rcmr.fdLength.bitCount]];
           ASSIGNify[ptr, rcmr.commonPart, d];
           FOR i: CARDINAL IN [0..length) DO
             ASSIGNify[ptr + rcmr.dataOffset + i * rcmr.wordsPerElement, rcmr.rcmi, d];
            ENDLOOP};
       ENDCASE => ERROR};

  NILify: PROC[ptr: Pointer, rcmx: RCMap.Index] =
  INLINE
     {  WITH rcmr: rcmb[rcmx] SELECT FROM
          simple =>
            FOR i: CARDINAL IN [0..rcmr.length) DO
              IF rcmr.refs[i] THEN LOOPHOLE[ptr+i, REF REF ANY]↑ ← NIL; ENDLOOP;
          oneRef => LOOPHOLE[ptr+rcmr.offset, REF REF ANY]↑ ← NIL;
          ref => LOOPHOLE[ptr, REF REF ANY]↑ ← NIL;
          null => NULL;
        ENDCASE => DoNILify[ptr, rcmx]};

  DoNILify: PROC[ptr: Pointer, rcmx: RCMap.Index] =
     { WITH rcmr: rcmb[rcmx] SELECT FROM
        nonVariant =>
          FOR i: CARDINAL IN [0..rcmr.nComponents) DO
            NILify[ptr + rcmr.components[i].wordOffset, rcmr.components[i].rcmi];
           ENDLOOP;
        variant =>
          {v: CARDINAL =
                 FetchField[ptr + rcmr.fdTag.wordOffset,
                            [bitFirst: rcmr.fdTag.bitFirst, bitCount: rcmr.fdTag.bitCount]];
           IF checking THEN IF v > rcmr.nVariants THEN ERROR;
           NILify[ptr, rcmr.variants[v]]};
        array =>
          FOR i: CARDINAL IN [0..rcmr.nElements) DO
            NILify[ptr + i * rcmr.wordsPerElement, rcmr.rcmi];
           ENDLOOP;
        sequence =>
          {length: CARDINAL =
                 FetchField[ptr+rcmr.fdLength.wordOffset,
                            [bitFirst: rcmr.fdLength.bitFirst, bitCount: rcmr.fdLength.bitCount]];
           NILify[ptr, rcmr.commonPart];
           FOR i: CARDINAL IN [0..length) DO
             NILify[ptr + rcmr.dataOffset + i * rcmr.wordsPerElement, rcmr.rcmi];
            ENDLOOP};
       ENDCASE => ERROR};

  MapComponents: PROC[ptr: Pointer, rcmx: RCMap.Index, procLeaf: PROC[p: REF ANY]] =
  INLINE
     { WITH rcmr: rcmb[rcmx] SELECT FROM
          simple =>
            FOR i: CARDINAL IN [0..rcmr.length) DO
              IF rcmr.refs[i] THEN
               {ref: REF ANY = LOOPHOLE[ptr+i, REF REF ANY]↑; IF ref # NIL THEN procLeaf[ref]};
             ENDLOOP;
          oneRef => {ref: REF ANY = LOOPHOLE[ptr+rcmr.offset, REF REF ANY]↑;
                     IF ref # NIL THEN procLeaf[ref]};
          ref => {ref: REF ANY = LOOPHOLE[ptr, REF REF ANY]↑; IF ref # NIL THEN procLeaf[ref]};
          null => NULL;
         ENDCASE => DoMapComponents[ptr, rcmx, procLeaf]};

  DoMapComponents: PROC[ptr: Pointer, rcmx: RCMap.Index, procLeaf: PROC[p: REF ANY]] =
     {INLDoMapComponents[ptr, rcmx, procLeaf]};

  INLDoMapComponents: PROC[ptr: Pointer, rcmx: RCMap.Index, procLeaf: PROC[p: REF ANY]] =
  INLINE
     {WITH rcmr: rcmb[rcmx] SELECT FROM
        nonVariant =>
          FOR i: CARDINAL IN [0..rcmr.nComponents) DO
            MapComponents[ptr + rcmr.components[i].wordOffset, rcmr.components[i].rcmi, procLeaf];
           ENDLOOP;
        variant =>
          {v: CARDINAL =
                 FetchField[ptr + rcmr.fdTag.wordOffset,
                            [bitFirst: rcmr.fdTag.bitFirst, bitCount: rcmr.fdTag.bitCount]];
           IF checking THEN IF v > rcmr.nVariants THEN ERROR;
           MapComponents[ptr, rcmr.variants[v], procLeaf]};
        array =>
          FOR i: CARDINAL IN [0..rcmr.nElements) DO
            MapComponents[ptr + i * rcmr.wordsPerElement, rcmr.rcmi, procLeaf];
           ENDLOOP;
        sequence =>
          {length: CARDINAL =
                 FetchField[ptr+rcmr.fdLength.wordOffset,
                            [bitFirst: rcmr.fdLength.bitFirst, bitCount: rcmr.fdLength.bitCount]];
           MapComponents[ptr, rcmr.commonPart, procLeaf];
           FOR i: CARDINAL IN [0..length) DO
             MapComponents[ptr + rcmr.dataOffset + i * rcmr.wordsPerElement, rcmr.rcmi, procLeaf];
            ENDLOOP};
       ENDCASE => ERROR};

END.