Copyright (C) 1994, Digital Equipment Corp.An RTMapOp.T is an instruction of the virtual machine used by RTTypeMap and RTHeapMap to locate fields of runtime values.
An RTTypeMap.T is a pointer to a byte stream that defines a program for a simple virtual machine. By executing that program each scalar field of a runtime value can be located.
INTERFACENote: all operands are little-endian, non-negative integersRTMapOp ; IMPORT RTTypeMap; TYPE T = { (* 0*) Stop, Mark, PushPtr, Return, (* 4*) Ref, UntracedRef, Proc, (* 7*) Real, Longreal, Extended, (*10*) Int_Field, Word_Field, (*12*) Int_1, Int_2, Int_4, Int_8, (*16*) Word_1, Word_2, Word_4, Word_8, (*20*) Set_1, Set_2, Set_3, Set_4, (*24*) OpenArray_1, OpenArray_2, (*26*) Array_1, Array_2, Array_3, Array_4, Array_5, Array_6, Array_7, Array_8, (*34*) Skip_1, Skip_2, Skip_3, Skip_4, Skip_5, Skip_6, Skip_7, Skip_8, (*42*) SkipF_1, SkipF_2, SkipF_3, SkipF_4, SkipF_5, SkipF_6, SkipF_7, SkipF_8, (*50*) SkipB_1, SkipB_2, SkipB_3, SkipB_4, SkipB_5, SkipB_6, SkipB_7, SkipB_8 }; TYPE Kind = RTTypeMap.Kind; Byte = BITS 8 FOR [0..255]; BP = UNTRACED REF Byte; IP = UNTRACED REF INTEGER; AP = UNTRACED REF ADDRESS; PC = UNTRACED REF T; CONST (* type of scalar field identified (Proc ==> none) *) OpKind = ARRAY T OF Kind { Kind.Proc, (* Stop *) Kind.Proc, (* Mark *) Kind.Proc, (* PushPtr *) Kind.Proc, (* Return *) Kind.Ref, (* Ref *) Kind.UntracedRef, (* UntracedRef *) Kind.Proc, (* Proc *) Kind.Real, (* Real *) Kind.Longreal, (* Longreal *) Kind.Extended, (* Extended *) Kind.Int_Field, (* Int_Field *) Kind.Word_Field, (* Word_Field *) Kind.Int_1, (* Int_1 *) Kind.Int_2, (* Int_2 *) Kind.Int_4, (* Int_4 *) Kind.Int_8, (* Int_8 *) Kind.Word_1, (* Word_1 *) Kind.Word_2, (* Word_2 *) Kind.Word_4, (* Word_4 *) Kind.Word_8, (* Word_8 *) Kind.Set, (* Set_1 *) Kind.Set, (* Set_2 *) Kind.Set, (* Set_3 *) Kind.Set, (* Set_4 *) Kind.Proc, (* OpenArray_1 *) Kind.Proc, (* OpenArray_2 *) Kind.Proc, (* Array_1 *) Kind.Proc, (* Array_2 *) Kind.Proc, (* Array_3 *) Kind.Proc, (* Array_4 *) Kind.Proc, (* Array_5 *) Kind.Proc, (* Array_6 *) Kind.Proc, (* Array_7 *) Kind.Proc, (* Array_8 *) Kind.Proc, (* Skip_1 *) Kind.Proc, (* Skip_2 *) Kind.Proc, (* Skip_3 *) Kind.Proc, (* Skip_4 *) Kind.Proc, (* Skip_5 *) Kind.Proc, (* Skip_6 *) Kind.Proc, (* Skip_7 *) Kind.Proc, (* Skip_8 *) Kind.Proc, (* SkipF_1 *) Kind.Proc, (* SkipF_2 *) Kind.Proc, (* SkipF_3 *) Kind.Proc, (* SkipF_4 *) Kind.Proc, (* SkipF_5 *) Kind.Proc, (* SkipF_6 *) Kind.Proc, (* SkipF_7 *) Kind.Proc, (* SkipF_8 *) Kind.Proc, (* SkipB_1 *) Kind.Proc, (* SkipB_2 *) Kind.Proc, (* SkipB_3 *) Kind.Proc, (* SkipB_4 *) Kind.Proc, (* SkipB_5 *) Kind.Proc, (* SkipB_6 *) Kind.Proc, (* SkipB_7 *) Kind.Proc (* SkipB_8 *) };
CONST (* # of bytes of operand in the map *)
OpArgBytes = ARRAY T OF [0..8] {
0, (* Stop *)
0, (* Mark *)
0, (* PushPtr *)
0, (* Return *)
0, (* Ref *)
0, (* UntracedRef *)
0, (* Proc *)
0, (* Real *)
0, (* Longreal *)
0, (* Extended *)
2, (* Int_Field - bit offset, bit size *)
2, (* Word_Field - bit offset, bit size *)
0, (* Int_1 *)
0, (* Int_2 *)
0, (* Int_4 *)
0, (* Int_8 *)
0, (* Word_1 *)
0, (* Word_2 *)
0, (* Word_4 *)
0, (* Word_8 *)
1, (* Set_1 - n = number of bytes *)
2, (* Set_2 *)
3, (* Set_3 *)
4, (* Set_4 *)
1, (* OpenArray_1 - n = number of open dimensions *)
2, (* OpenArray_2 *)
1, (* Array_1 - n = number of elements *)
2, (* Array_2 *)
3, (* Array_3 *)
4, (* Array_4 *)
5, (* Array_5 *)
6, (* Array_6 *)
7, (* Array_7 *)
8, (* Array_8 *)
0, (* Skip_1 *)
0, (* Skip_2 *)
0, (* Skip_3 *)
0, (* Skip_4 *)
0, (* Skip_5 *)
0, (* Skip_6 *)
0, (* Skip_7 *)
0, (* Skip_8 *)
1, (* SkipF_1 - n = number of bytes to skip forward *)
2, (* SkipF_2 *)
3, (* SkipF_3 *)
4, (* SkipF_4 *)
5, (* SkipF_5 *)
6, (* SkipF_6 *)
7, (* SkipF_7 *)
8, (* SkipF_8 *)
1, (* SkipB_1 - n = number of bytes to skip backward *)
2, (* SkipB_2 *)
3, (* SkipB_3 *)
4, (* SkipB_4 *)
5, (* SkipB_5 *)
6, (* SkipB_6 *)
7, (* SkipB_7 *)
8 (* SkipB_8 *)
};
CONST (* # of bytes occupied in the referent *)
OpSize = ARRAY T OF CARDINAL {
0, (* Stop *)
0, (* Mark *)
0, (* PushPtr -> ADRSIZE (ADDRESS) *)
0, (* Return *)
ADRSIZE (ADDRESS), (* Ref *)
ADRSIZE (ADDRESS), (* UntracedRef *)
ADRSIZE (ADDRESS), (* Proc *)
ADRSIZE (REAL), (* Real *)
ADRSIZE (LONGREAL), (* Longreal *)
ADRSIZE (EXTENDED), (* Extended *)
0, (* Int_Field *)
0, (* Word_Field *)
1 * ADRSIZE (Byte), (* Int_1 *)
2 * ADRSIZE (Byte), (* Int_2 *)
4 * ADRSIZE (Byte), (* Int_4 *)
8 * ADRSIZE (Byte), (* Int_8 *)
1 * ADRSIZE (Byte), (* Word_1 *)
2 * ADRSIZE (Byte), (* Word_2 *)
4 * ADRSIZE (Byte), (* Word_4 *)
8 * ADRSIZE (Byte), (* Word_8 *)
0, (* Set_1 -> n * Byte *)
0, (* Set_2 -> n * Byte *)
0, (* Set_3 -> n * Byte *)
0, (* Set_4 -> n * Byte *)
0, (* OpenArray_1 -> ADDRESS + n * INTEGER *)
0, (* OpenArray_2 -> ADDRESS + n * INTEGER *)
0, (* Array_1 -> n * element size *)
0, (* Array_2 -> n * element size *)
0, (* Array_3 -> n * element size *)
0, (* Array_4 -> n * element size *)
0, (* Array_5 -> n * element size *)
0, (* Array_6 -> n * element size *)
0, (* Array_7 -> n * element size *)
0, (* Array_8 -> n * element size *)
1 * ADRSIZE (Byte), (* Skip_1 *)
2 * ADRSIZE (Byte), (* Skip_2 *)
3 * ADRSIZE (Byte), (* Skip_3 *)
4 * ADRSIZE (Byte), (* Skip_4 *)
5 * ADRSIZE (Byte), (* Skip_5 *)
6 * ADRSIZE (Byte), (* Skip_6 *)
7 * ADRSIZE (Byte), (* Skip_7 *)
8 * ADRSIZE (Byte), (* Skip_8 *)
0, (* SkipF_1 -> n * Byte *)
0, (* SkipF_2 -> n * Byte *)
0, (* SkipF_3 -> n * Byte *)
0, (* SkipF_4 -> n * Byte *)
0, (* SkipF_5 -> n * Byte *)
0, (* SkipF_6 -> n * Byte *)
0, (* SkipF_7 -> n * Byte *)
0, (* SkipF_8 -> n * Byte *)
0, (* SkipB_1 -> -n * Byte *)
0, (* SkipB_2 -> -n * Byte *)
0, (* SkipB_3 -> -n * Byte *)
0, (* SkipB_4 -> -n * Byte *)
0, (* SkipB_5 -> -n * Byte *)
0, (* SkipB_6 -> -n * Byte *)
0, (* SkipB_7 -> -n * Byte *)
0 (* SkipB_8 -> -n * Byte *)
};
PROCEDURE GetInt (VAR pc: ADDRESS; size: [1..8]): INTEGER;
Read and return an arbitrarly aligned, non-negative, 'size' byte, little-endian integer starting at address 'pc' and increment 'pc' by ADRSIZE (INTEGER).
TYPE StackElt = RECORD pc: ADDRESS; count: INTEGER END; Stack = RECORD top: INTEGER := 0; data: ARRAY [0..127] OF StackElt END; PROCEDURE Push (VAR s: Stack; a: ADDRESS; b: INTEGER);
push(a, b)ons.
END RTMapOp.---------------------------------------------------------------------------
The machine's execution on a value at address x with an array of opcodes
at address pc is defined by the following psuedo-code.
The following abbreviations are used:
z:X -- LOOPHOLE (z, UNTRACED REF BITS 8*X FOR INTEGER)^ z:IP -- LOOPHOLE (z, UNTRACED REF INTEGER)^ z:AP -- LOOPHOLE (z, UNTRACED REF ADDRESS)^ z++T -- INC (z, ADRSIZE (T)) z++i -- INC (z, i * ADRSIZE (BYTE))
LOOP op := pc^; pc ++ Op; CASE op OF
Stop => stop and return the current value of 'x'.
Mark => push (pc := pc, count := -1).
PushPtr => push (pc := x, count := -1); x := x:AP
Return => x := pop().pc; x ++ ADDRESS
Ref => -- a traced reference is at 'x' -- x ++ ADDRESS;
UntracedRef => -- an untraced reference is at 'x' -- x ++ ADDRESS;
Proc => -- a procedure is at 'x' -- x ++ ADDRESS;
Real => -- a REAL is at 'x' -- x ++ REAL;
Longreal => -- a LONGREAL is at 'x' -- x ++ LONGREAL;
Extended => -- an EXTENDED is at 'x' -- x ++ EXTENDED;
Int_1 => -- a one byte, signed integer -- x ++ 1
Int_2 => -- a two byte, signed integer -- x ++ 2
Int_4 => -- a four byte, signed integer -- x ++ 4
Int_8 => -- an eight byte, signed integer -- x ++ 8
Word_1 => -- a one byte, unsigned integer -- x ++ 1
Word_2 => -- a two byte, unsigned integer -- x ++ 2
Word_4 => -- a four byte, unsigned integer -- x ++ 4
Word_8 => -- an eight byte, unsigned integer -- x ++ 8
Set_N => -- an n=pc:N byte SET is at 'x' -- x ++ n
Skip_N => x ++ N;
SkipF_N => x ++ pc:N ; pc ++ N;
SkipB_N => x ++ -(pc:N) ; pc ++ N;
Int_Field => n := pc^; m := (pc+1)^; pc ++ 2
-- an 'm'-bit signed integer begins 'n' bits beyond 'x'--
Word_Field => n := pc^; m := (pc+1)^; pc ++ 2
-- an 'm'-bit unsigned int begins 'n' bits beyond 'x'--
Array_N => WITH z = <top of stack> DO
IF z.count = -1 THEN z.count := pc:N END;
DEC (z.count);
pc ++ N;
IF (z.count > 0) THEN pc := z.pc ELSE pop() END;
END;
OpenArray_N => VAR n := pc:N; elts := x:AP; cnt := 1;
BEGIN
pc ++ N; x ++ ADDRESS;
FOR j := 1 TO n DO cnt := cnt * x:IP; x ++ INTEGER END;
FOR j := 1 TO cnt DO elts := Visit (elts, pc) END;
RETURN elts;
END;
END;
END;