-- file DJumps.mesa
-- last modified by Sweet, March 20, 1979  4:53 PM
-- last modified by Satterthwaite, May 25, 1982 12:07 pm

DIRECTORY
  Alloc: TYPE USING [Base, Notifier],
  Code: TYPE USING [codeptr],
  CodeDefs: TYPE USING [
    Base, CCIndex, CCNull, codeType, JumpCCIndex, JumpType, RelativePC],
  OpCodeParams: TYPE USING [MaxBBJumps, MaxFBJumps, MaxFIAJumps, MaxFICJumps],
  P5F: TYPE USING [CodeJumpDist, StartIndex];

DJumps: PROGRAM
    IMPORTS CPtr: Code, P5F 
    EXPORTS CodeDefs, P5F =
  BEGIN
  OPEN OpCodeParams, CodeDefs;

  cb: CodeDefs.Base;        -- code base (local copy)

  DJumpsNotify: PUBLIC Alloc.Notifier =
    BEGIN  -- called by allocator whenever table area is repacked
    cb ← base[codeType];
    END;

  BindJump: PUBLIC PROC [min, max: INTEGER, c: JumpCCIndex]
      RETURNS [bindable: BOOLEAN ← TRUE] =
    BEGIN -- compute size of jump instruction(s)
    -- max and min are counts of the number of bytes between the
    -- jump and the label.
    t: JumpType = cb[c].jtype;
    js: [0..7];
    IF t = JumpC THEN
      BEGIN -- "bound" by OutBinary
      cb[c].fixedup ← TRUE;
      cb[c].completed ← TRUE;
      RETURN
      END;
    IF ~cb[c].forward THEN BEGIN max ← -max; min ← -min END;
    SELECT t FROM
      Jump, JumpA =>
	IF max IN [1..MaxFIAJumps] THEN js ← 1
	ELSE IF max IN (MaxFIAJumps..MaxFBJumps-2] AND min > MaxFIAJumps THEN js ← 2
	ELSE IF max IN [-MaxBBJumps..0] THEN js ← 2
	ELSE IF min NOT IN [-MaxBBJumps..MaxFBJumps-2] THEN js ← 3
	ELSE bindable ← FALSE;
      JumpE, JumpN =>
	IF max IN [1..MaxFICJumps] THEN js ← 1
	ELSE IF max IN (MaxFICJumps..MaxFBJumps-2] AND min > MaxFICJumps THEN js ← 2
	ELSE IF max IN [-MaxBBJumps..0] THEN js ← 2
	ELSE IF min NOT IN [-MaxBBJumps..MaxFBJumps-2] THEN js ← 4
	ELSE bindable ← FALSE;
      JumpCA =>
	IF max IN [-MaxBBJumps..MaxFBJumps-2] THEN js ← 2
	ELSE IF min NOT IN [-MaxBBJumps..MaxFBJumps-2] THEN js ← 3
	ELSE bindable ← FALSE;
      ENDCASE =>
	IF max IN [-MaxBBJumps..MaxFBJumps-2] THEN js ← 2
	ELSE IF min NOT IN [-MaxBBJumps..MaxFBJumps-2] THEN js ← 5
	ELSE bindable ← FALSE;
    IF bindable THEN {cb[c].fixedup ← TRUE; cb[c].jsize ← js};
    RETURN
    END;


  CodeJump: PUBLIC PROC [nbytes: INTEGER, c: JumpCCIndex] =
    BEGIN -- code all jump instruction(s)
    l: [0..7] = cb[c].jsize;
    forward: BOOLEAN = cb[c].forward;
    dist: INTEGER ← IF ~forward THEN -nbytes ELSE nbytes+l;
    IF l > 3 THEN dist ← dist + 3 - l;
    -- Computing dist copes with the fact that the parameter to a jump
    -- instruction is added to the byte pc of the first byte of the instruction
    -- nbytes is the number of bytes between the jump and its label
    CPtr.codeptr ← c;
    P5F.CodeJumpDist[dist, l, 0, c];
    END;

  dMinMax: ARRAY {unconditional, equal, relational} OF
    PACKED ARRAY BOOLEAN OF RECORD [min,max: [0..15]] ← [
      [[2,3], [1,3]], -- unconditional, (backward, forward)
      [[2,4], [1,4]], -- equal, (backward, forward)
      [[2,5], [2,5]]]; -- relational, (backward, forward)

  FillInPCEstimates: PUBLIC PROC =
    BEGIN
    min, max: RelativePC ← 0;
    FOR k: CCIndex ← P5F.StartIndex, cb[k].flink UNTIL k = CCNull DO
      WITH cc:cb[k] SELECT FROM
	code =>
	  BEGIN
	  t: CARDINAL = cc.isize;
	  min ← min + t;
	  max ← max + t;
	  END;
	jump => IF cc.jtype # JumpC THEN
	  BEGIN
	  IF ~cc.fixedup THEN
	    BEGIN
	    dMin, dMax: [0..15];
	    [dMin,dMax] ← dMinMax[(SELECT cc.jtype FROM
		Jump, JumpA, JumpCA => unconditional,
		JumpE, JumpN => equal,
		ENDCASE => relational)][cc.forward];
	    IF ~cc.forward THEN {cc.minPC ← min; cc.maxPC ← max};
	    min ← min+dMin; max ← max+dMax;
	    IF cc.forward THEN {cc.minPC ← min; cc.maxPC ← max};
	    END
	  ELSE IF ~cc.completed THEN
	    BEGIN
	    t: CARDINAL = cc.jsize;
	    IF ~cc.forward THEN {cc.minPC ← min; cc.maxPC ← max};
	    min ← min + t;
	    max ← max + t;
	    IF cc.forward THEN {cc.minPC ← min; cc.maxPC ← max};
	    END;
	  END;
	label => {cc.minPC ← min; cc.maxPC ← max};
	other =>  WITH cc SELECT FROM
	  table =>
	    BEGIN
	    min ← min + tablecodebytes;
	    max ← max + tablecodebytes;
	    END;
	  ENDCASE;
	ENDCASE;
      ENDLOOP;
    END;

  END.