The program representation that
we will be using is this class is a control flow graph, where basic blocks
consist of simple operations known as Quads. Quads consist of an Operator
and up to four Operands.
All operators are inherited from
the Operator class. Operators have the following
methods:
getThrownExceptions(): gets the exception handlers for
that operation. getDefinedRegisters(q): gets all the registers defined by
quad q. getUsedRegisters(q): gets all the registers used by quad
q. getReg1(q), getReg2(q), getReg3(q): gets the named register from quad
q. INSTANCE: All operators are implemented using
the Singleton pattern. This field holds the object associated with each
operator. All the operations are
hierarchically ordered. For example, there are different operations to write to
a field in a class, depending on the type of the field. For example, the
PUTFIELD_{I,F,L,D,A,B,C,S,Z} Operators represent array load instructions for
the types integer, floating-point, long, double, reference, byte, character,
short, and boolean. PUTFIELD_{I,F,L,D,A,B,C,S,Z}_DYNLINK are similar to
PUTFIELD_{I,F,L,D,A,B,C,S,Z}, except that the invoked function may need to be
loaded dynamically. We use the % symbol to stand for DYNLINK when printing the quads . All the various
PUTFIELD variants inherit from the Putfield class, which inherits from Operator. Associated with each class is a set of
methods, allowing the compiler writer to refer to the operands of a quad by
more meaningful names than getOp1, getOp2 etc. For example, the first operand
for Binary operations can be retrieved by invoking getDest on the quad
containing the operator.
|
Operator |
Short
Description |
Subclasses |
Methods |
|
Move |
Move between pseudo registers |
|
getMoveOp |
|
Binary |
Binary operation, with two sources and one destination |
|
getDest |
|
Unary |
Unary operation, with one source and one destination |
|
getDest |
|
Goto |
unconditional branch |
|
getTarget |
|
IntIfCmp |
conditional branch |
|
getSrc1 |
|
TableSwitch |
table switch instruction |
|
setTarget |
|
LookupSwitch |
lookup switch instruction |
|
setMatch |
|
Getstatic |
load from a static field |
|
getDest |
|
Putstatic |
store to a static field |
|
getSrc |
|
Getfield |
load from an object field |
|
getDest |
|
Putfield |
store to an object field |
|
getBase |
|
ALoad |
array load |
|
getDest |
|
AStore |
array store |
|
getValue |
|
ALength |
array length |
|
getDest |
|
BoundsCheck |
array bounds check |
|
getRef |
|
NullCheck |
null pointer check |
|
getDest |
|
ZeroCheck |
null pointer check |
|
getDest |
|
StoreCheck |
array object type store check |
|
getRef |
|
New |
allocate a new object |
|
getDest |
|
NewArray |
allocate a new array |
|
getDest |
|
CheckCast |
run time type check |
|
getDest |
|
InstanceOf |
run time type check |
|
getDest |
|
Invoke |
call another method |
|
setParam |
|
Jsr |
call an internal subroutine |
|
getDest |
|
Ret |
return from an internal subroutine |
|
getTarget |
|
Return |
return from the current method |
|
getSrc |
|
Monitor |
access atomic lock for an object |
|
getSrc |
The following provides a short
description of all the different kinds of operands.
|
RegisterOperand |
specifies an abstract location |
|
IConstOperand |
integer constant (32 bit) |
|
FConstOperand |
floating point constant operand (32 bit) |
|
LConstOperand |
long integer constant operand (64 bit) |
|
DConstOperand |
double-precision floating point constant operand (64 bit) |
|
AConstOperand |
object reference constant |
|
MethodOperand |
specifies the target method of a method call instruction |
|
ParamListOperand |
specifies the parameter list for a method call instruction |
|
FieldOperand |
specifies an object field associated with a get/put field instruction |
|
TypeOperand |
specifies a type for use in type check instructions |
|
ConditionOperand |
Specifies a condition code associated with a conditional branch instruction |
|
TargetOperand |
specifies the target of a branch instruction |
|
BasicBlockTableOperand |
specifies a table of targets, for use in switch instructions |
Quads are organized into BasicBlocks.
BasicBlocks are single-entry, meaning that control flow can only enter
at the start of a basic block. Barring exceptions and method calls, they are
also single-exit, meaning that control flow can only leave at the end
of a basic block. This is an important difference between the basic blocks
that were covered in lecture. Exceptions can cause basic blocks to exit early.
Each BasicBlock contains a list
of Quads. They also include a set of predecessor and successor basic blocks.
Basic blocks are numbered with unique integer identifiers. There are
two special basic blocks, the entry basic block and the exit
basic block. These basic blocks always have identifiers 0 and 1, respectively.
These blocks mark the method entry point and exit point. They never contain
instructions. Obviously, the entry basic block has no predecessors, and the
exit basic block has no successors.
Basic blocks also have exception
handlers. When an exception occurs within a basic block, control flow
jumps to the handler for that basic block that matches the type of the
exception that occurred.
BasicBlocks are contained in a ControlFlowGraph.
The ControlFlowGraph contains references to the start and end nodes and a list
of all exception handlers.