-- file DJumps.mesa
-- last modified by Sweet, March 20, 1979 4:53 PM
-- last modified by Satterthwaite, November 2, 1982 3:52 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: BOOL ← 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: BOOL = 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, c];
END;

dMinMax: ARRAY {unconditional, equal, relational} OF
PACKED ARRAY BOOL 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.