MODULE PCARMCP;
IMPORT SYSTEM, PCO := PCOARM, PCM, PCBT, KernelLog;
CONST
Trace = FALSE;
ErrInternalError* = 100;
ErrConstantNotRegistered* = 101;
ErrAddressNotRegistered* = 102;
FlushThreshold = 80H;
TYPE
UseList = OBJECT
VAR
pc: LONGINT;
next: UseList;
PROCEDURE &Init*(pc: LONGINT);
BEGIN SELF.pc := pc
END Init;
END UseList;
Element = OBJECT
VAR
pc: LONGINT;
firstUse:LONGINT;
next: Element;
uses: UseList;
PROCEDURE &InitElement*;
BEGIN pc := -1
END InitElement;
END Element;
Constant = OBJECT(Element)
VAR
value: LONGINT;
PROCEDURE &Init*(value: LONGINT);
BEGIN InitElement; SELF.value := value
END Init;
END Constant;
Address = OBJECT(Element)
VAR
adr: PCM.Attribute;
PROCEDURE &Init*(adr: PCM.Attribute);
BEGIN InitElement; SELF.adr := adr
END Init;
END Address;
ConstantPool* = OBJECT
VAR items: Element;
limitPC: LONGINT;
PROCEDURE &Init*;
BEGIN PCO.SetConstantPoolBarrierCallback(FlushCallback); limitPC := -1
END Init;
PROCEDURE Insert(i: Element);
VAR p,c: Element;
BEGIN
c := items; p := NIL;
WHILE (c # NIL) & (c.firstUse < i.firstUse) DO p := c; c := c.next END;
IF (p = NIL) THEN
i.next := c; items := i
ELSE
i.next := p.next; p.next := i
END
END Insert;
PROCEDURE AddConstant*(pc, c: LONGINT): LONGINT;
VAR i, p: Element; cnst: Constant; use: UseList;
BEGIN { EXCLUSIVE }
IF Trace THEN
KernelLog.Enter;
KernelLog.String("Adding constant "); KernelLog.Int(c, 0); KernelLog.String(" @ "); KernelLog.Int(pc, 0);
KernelLog.Exit
END;
i := items; p := NIL;
WHILE (i # NIL) & (~(i IS Constant) OR (i(Constant).value # c)) DO p := i; i := i.next END;
IF (i = NIL) THEN
NEW(cnst, c); i := cnst; i.firstUse := pc;
Insert(i)
ELSIF (i.firstUse > pc) THEN
i.firstUse := pc;
IF ((p # NIL) & (p.firstUse > i.firstUse)) OR ((i.next # NIL) & (i.next.firstUse < i.firstUse)) THEN
IF (p # NIL) THEN p.next := i.next
ELSE items := i.next
END;
Insert(i)
END
END;
IF (i.pc # -1) THEN
IF (pc + 8 - i.pc < 1000H) THEN RETURN i.pc - pc - 8
ELSE i.pc := -1
END
END;
NEW(use, pc); use.next := i.uses; i.uses := use;
IF (limitPC = -1) THEN
limitPC := pc + 1000H - 2*PCO.InstructionSize - FlushThreshold;
PCO.SetConstantPoolBarrier(limitPC)
END;
RETURN 0
END AddConstant;
PROCEDURE AddAddress*(pc: LONGINT; adr: PCM.Attribute): LONGINT;
VAR i, p: Element; address: Address; use: UseList;
BEGIN { EXCLUSIVE }
IF Trace THEN
KernelLog.Enter;
KernelLog.String("Adding address "); KernelLog.Hex(SYSTEM.ADR(adr^), 8); KernelLog.String(" @ "); KernelLog.Int(pc, 0);
KernelLog.Exit
END;
i := items;
WHILE (i # NIL) & (~(i IS Address) OR (i(Address).adr # adr)) DO p := i; i := i.next END;
IF (i = NIL) THEN
NEW(address, adr); i := address; i.firstUse := pc;
Insert(i)
ELSIF (i.firstUse > pc) THEN
i.firstUse := pc;
IF ((p # NIL) & (p.firstUse > i.firstUse)) OR ((i.next # NIL) & (i.next.firstUse < i.firstUse)) THEN
IF (p # NIL) THEN p.next := i.next
ELSE items := i.next
END;
Insert(i)
END
END;
IF (i.pc # -1) THEN
IF (pc + 8 - i.pc < 1000H) THEN RETURN i.pc - pc - 8
ELSE i.pc := -1
END
END;
IF (adr IS PCBT.GlobalVariable) THEN
ELSIF (adr IS PCBT.Procedure) THEN
ELSE Error(pc, "AddAddress: unknown 'adr' type")
END;
NEW(use, pc); use.next := i.uses; i.uses := use;
IF (limitPC = -1) THEN
limitPC := pc + 1000H - 2*PCO.InstructionSize - FlushThreshold;
PCO.SetConstantPoolBarrier(limitPC)
END;
RETURN 0
END AddAddress;
PROCEDURE Flush*(pc: LONGINT);
VAR i: Element; u: UseList; adr: PCM.Attribute; cnt: LONGINT;
BEGIN
IF Trace THEN
KernelLog.Enter; KernelLog.String("Flushing Constant Pool..."); KernelLog.Ln
END;
i := items;
WHILE (i # NIL) DO
i.firstUse := MAX(LONGINT);
IF (i.uses # NIL) & (i.pc = -1) THEN
INC(cnt);
IF Trace THEN
IF (i IS Constant) THEN KernelLog.String(" constant (value = "); KernelLog.Int(i(Constant).value, 0)
ELSE KernelLog.String(" address (id = "); KernelLog.Hex(SYSTEM.ADR(i(Address).adr^), 8)
END;
KernelLog.String("); pc = ")
END;
i.pc := PCO.GetCodePos();
IF (i IS Constant) THEN PCO.DCD(i(Constant).value)
ELSE
adr := i(Address).adr;
IF (adr IS PCBT.GlobalVariable) THEN
WITH adr: PCBT.GlobalVariable DO
PCO.DCD(adr.offset);
PCBT.context.UseVariable(adr, i.pc DIV 4)
END
ELSIF (adr IS PCBT.Procedure) THEN
WITH adr: PCBT.Procedure DO
PCO.DCD(0);
PCBT.context.UseProcedure(adr, i.pc DIV 4)
END
ELSE Error(pc, "Flush: unknown 'adr' type")
END;
END;
IF Trace THEN
KernelLog.Hex(i.pc, 8); KernelLog.Ln;
KernelLog.String(" fixing references at pos: ")
END;
u := i.uses;
WHILE (u # NIL) DO
IF Trace THEN KernelLog.Int(u.pc, 5) END;
PCO.FixLoad(u.pc, i.pc - (u.pc + 8));
u := u.next
END;
IF Trace THEN KernelLog.Ln END;
i.uses := NIL
END;
i := i.next
END;
limitPC := -1;
PCO.SetConstantPoolBarrier(limitPC);
IF Trace THEN KernelLog.String(" # of addresses/constants flushed: "); KernelLog.Int(cnt, 0); KernelLog.Exit END
END Flush;
PROCEDURE FlushCallback(pc: LONGINT);
BEGIN
IF Trace THEN
KernelLog.Enter; KernelLog.Hex(pc, 8); KernelLog.String(": Constant Pool: Flush callback called"); KernelLog.Exit
END;
PCO.B(PCO.AL, 0);
Flush(pc);
PCO.FixJump(pc, (PCO.GetCodePos() - (pc + 8)) DIV 4)
END FlushCallback;
PROCEDURE Error(pc: LONGINT; CONST msg: ARRAY OF CHAR);
BEGIN
KernelLog.Enter;
KernelLog.String("ConstantPool Error @ pc = "); KernelLog.Hex(pc, 8); KernelLog.String("h: ");
KernelLog.String(msg);
KernelLog.Exit;
HALT(ErrInternalError);
END Error;
END ConstantPool;
END PCARMCP.