Class Frame
- Direct Known Subclasses:
CurrentFrame
Stack map frames are computed in two steps:
- During the visit of each instruction in MethodWriter, the state of the frame at the end of the current basic block is updated by simulating the action of the instruction on the previous state of this so called "output frame".
- After all instructions have been visited, a fix point algorithm is used in MethodWriter to
compute the "input frame" of each basic block (i.e. the stack map frame at the beginning of
the basic block). See
MethodWriter.computeAllFrames()
.
Output stack map frames are computed relatively to the input frame of the basic block, which is not yet known when output frames are computed. It is therefore necessary to be able to represent abstract types such as "the type at position x in the input frame locals" or "the type at position x from the top of the input frame stack" or even "the type at position x in the input frame, with y more (or less) array dimensions". This explains the rather complicated type format used in this class, explained below.
The local variables and the operand stack of input and output frames contain values called "abstract types" hereafter. An abstract type is represented with 4 fields named DIM, KIND, FLAGS and VALUE, packed in a single int value for better performance and memory efficiency:
===================================== |...DIM|KIND|.F|...............VALUE| =====================================
- the DIM field, stored in the 6 most significant bits, is a signed number of array
dimensions (from -32 to 31, included). It can be retrieved with
DIM_MASK
and a right shift ofDIM_SHIFT
. - the KIND field, stored in 4 bits, indicates the kind of VALUE used. These 4 bits can be
retrieved with
KIND_MASK
and, without any shift, must be equal toCONSTANT_KIND
,REFERENCE_KIND
,UNINITIALIZED_KIND
,LOCAL_KIND
orSTACK_KIND
. - the FLAGS field, stored in 2 bits, contains up to 2 boolean flags. Currently only one flag
is defined, namely
TOP_IF_LONG_OR_DOUBLE_FLAG
. - the VALUE field, stored in the remaining 20 bits, contains either
- one of the constants
ITEM_TOP
,ITEM_ASM_BOOLEAN
,ITEM_ASM_BYTE
,ITEM_ASM_CHAR
orITEM_ASM_SHORT
,ITEM_INTEGER
,ITEM_FLOAT
,ITEM_LONG
,ITEM_DOUBLE
,ITEM_NULL
orITEM_UNINITIALIZED_THIS
, if KIND is equal toCONSTANT_KIND
. - the index of a
Symbol.TYPE_TAG
Symbol
in the type table of aSymbolTable
, if KIND is equal toREFERENCE_KIND
. - the index of an
Symbol.UNINITIALIZED_TYPE_TAG
Symbol
in the type table of a SymbolTable, if KIND is equal toUNINITIALIZED_KIND
. - the index of a local variable in the input stack frame, if KIND is equal to
LOCAL_KIND
. - a position relatively to the top of the stack of the input stack frame, if KIND is
equal to
STACK_KIND
,
- one of the constants
Output frames can contain abstract types of any kind and with a positive or negative array dimension (and even unassigned types, represented by 0 - which does not correspond to any valid abstract type value). Input frames can only contain CONSTANT_KIND, REFERENCE_KIND or UNINITIALIZED_KIND abstract types of positive or null array dimension. In all cases the type table contains only internal type names (array type descriptors are forbidden - array dimensions must be represented through the DIM field).
The LONG and DOUBLE types are always represented by using two slots (LONG + TOP or DOUBLE + TOP), for local variables as well as in the operand stack. This is necessary to be able to simulate DUPx_y instructions, whose effect would be dependent on the concrete types represented by the abstract types in the stack (which are not always known).
-
Field Summary
FieldsModifier and TypeFieldDescription(package private) static final int
private static final int
The constant to be added to an abstract type to get one with one more array dimension.private static final int
private static final int
private static final int
(package private) static final int
private static final int
private static final int
private static final int
private static final int
private static final int
private static final int
The constant to be added to an abstract type to get one with one less array dimension.private static final int
private static final int
private static final int
(package private) static final int
private int
The number of types that are initialized in the basic block.private int[]
The abstract types that are initialized in the basic block.private int[]
The input stack map frame locals.private int[]
The input stack map frame stack.private static final int
private static final int
private static final int
private static final int
private static final int
(package private) static final int
(package private) static final int
(package private) static final int
(package private) static final int
(package private) static final int
(package private) static final int
(package private) static final int
(package private) static final int
(package private) static final int
private static final int
private static final int
private static final int
private static final int
private static final int
private static final int
private int[]
The output stack map frame locals.private int[]
The output stack map frame stack.private short
The start of the output stack, relatively to the input stack.private short
The index of the top stack element inoutputStack
.(package private) Label
The basic block to which these input and output stack map frames correspond.private static final int
(package private) static final int
(package private) static final int
(package private) static final int
(package private) static final int
(package private) static final int
private static final int
private static final int
private static final int
private static final int
A flag used for LOCAL_KIND and STACK_KIND abstract types, indicating that if the resolved, concrete type is LONG or DOUBLE, TOP should be used instead (because the value has been partially overridden with an xSTORE instruction).private static final int
private static final int
private static final int
private static final int
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescription(package private) final void
accept
(MethodWriter methodWriter) Makes the givenMethodWriter
visit the input frame of thisFrame
.private void
addInitializedType
(int abstractType) Adds an abstract type to the list of types on which a constructor is invoked in the basic block.(package private) final void
Sets this frame to the value of the given frame.(package private) void
execute
(int opcode, int arg, Symbol argSymbol, SymbolTable symbolTable) Simulates the action of the given instruction on the output stack frame.(package private) static int
getAbstractTypeFromApiFormat
(SymbolTable symbolTable, Object type) Returns the abstract type corresponding to the given public API frame element type.private static int
getAbstractTypeFromDescriptor
(SymbolTable symbolTable, String buffer, int offset) Returns the abstract type corresponding to the given type descriptor.(package private) static int
getAbstractTypeFromInternalName
(SymbolTable symbolTable, String internalName) Returns the abstract type corresponding to the internal name of a class.private int
getConcreteOutputType
(int abstractOutputType, int numStack) Computes the concrete output type corresponding to a given abstract output type.private int
getInitializedType
(SymbolTable symbolTable, int abstractType) Returns the "initialized" abstract type corresponding to the given abstract type.(package private) final int
private int
getLocal
(int localIndex) Returns the abstract type stored at the given local variable index in the output frame.private static boolean
merge
(SymbolTable symbolTable, int sourceType, int[] dstTypes, int dstIndex) Merges the type at the given index in the given abstract type array with the given type.(package private) final boolean
merge
(SymbolTable symbolTable, Frame dstFrame, int catchTypeIndex) private int
pop()
Pops an abstract type from the output frame stack and returns its value.private void
pop
(int elements) Pops the given number of abstract types from the output frame stack.private void
Pops as many abstract types from the output frame stack as described by the given descriptor.private void
push
(int abstractType) Pushes the given abstract type on the output frame stack.private void
push
(SymbolTable symbolTable, String descriptor) Pushes the abstract type corresponding to the given descriptor on the output frame stack.(package private) static void
putAbstractType
(SymbolTable symbolTable, int abstractType, ByteVector output) Put the given abstract type in the given ByteVector, using the JVMS verification_type_info format used in StackMapTable attributes.(package private) final void
setInputFrameFromApiFormat
(SymbolTable symbolTable, int numLocal, Object[] local, int numStack, Object[] stack) Sets the input frame from the given public API frame description.(package private) final void
setInputFrameFromDescriptor
(SymbolTable symbolTable, int access, String descriptor, int maxLocals) Sets the input frame from the given method description.private void
setLocal
(int localIndex, int abstractType) Replaces the abstract type stored at the given local variable index in the output frame.
-
Field Details
-
SAME_FRAME
static final int SAME_FRAME- See Also:
-
SAME_LOCALS_1_STACK_ITEM_FRAME
static final int SAME_LOCALS_1_STACK_ITEM_FRAME- See Also:
-
RESERVED
static final int RESERVED- See Also:
-
SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED
static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED- See Also:
-
CHOP_FRAME
static final int CHOP_FRAME- See Also:
-
SAME_FRAME_EXTENDED
static final int SAME_FRAME_EXTENDED- See Also:
-
APPEND_FRAME
static final int APPEND_FRAME- See Also:
-
FULL_FRAME
static final int FULL_FRAME- See Also:
-
ITEM_TOP
static final int ITEM_TOP- See Also:
-
ITEM_INTEGER
static final int ITEM_INTEGER- See Also:
-
ITEM_FLOAT
static final int ITEM_FLOAT- See Also:
-
ITEM_DOUBLE
static final int ITEM_DOUBLE- See Also:
-
ITEM_LONG
static final int ITEM_LONG- See Also:
-
ITEM_NULL
static final int ITEM_NULL- See Also:
-
ITEM_UNINITIALIZED_THIS
static final int ITEM_UNINITIALIZED_THIS- See Also:
-
ITEM_OBJECT
static final int ITEM_OBJECT- See Also:
-
ITEM_UNINITIALIZED
static final int ITEM_UNINITIALIZED- See Also:
-
ITEM_ASM_BOOLEAN
private static final int ITEM_ASM_BOOLEAN- See Also:
-
ITEM_ASM_BYTE
private static final int ITEM_ASM_BYTE- See Also:
-
ITEM_ASM_CHAR
private static final int ITEM_ASM_CHAR- See Also:
-
ITEM_ASM_SHORT
private static final int ITEM_ASM_SHORT- See Also:
-
DIM_SIZE
private static final int DIM_SIZE- See Also:
-
KIND_SIZE
private static final int KIND_SIZE- See Also:
-
FLAGS_SIZE
private static final int FLAGS_SIZE- See Also:
-
VALUE_SIZE
private static final int VALUE_SIZE- See Also:
-
DIM_SHIFT
private static final int DIM_SHIFT- See Also:
-
KIND_SHIFT
private static final int KIND_SHIFT- See Also:
-
FLAGS_SHIFT
private static final int FLAGS_SHIFT- See Also:
-
DIM_MASK
private static final int DIM_MASK- See Also:
-
KIND_MASK
private static final int KIND_MASK- See Also:
-
VALUE_MASK
private static final int VALUE_MASK- See Also:
-
ARRAY_OF
private static final int ARRAY_OFThe constant to be added to an abstract type to get one with one more array dimension.- See Also:
-
ELEMENT_OF
private static final int ELEMENT_OFThe constant to be added to an abstract type to get one with one less array dimension.- See Also:
-
CONSTANT_KIND
private static final int CONSTANT_KIND- See Also:
-
REFERENCE_KIND
private static final int REFERENCE_KIND- See Also:
-
UNINITIALIZED_KIND
private static final int UNINITIALIZED_KIND- See Also:
-
LOCAL_KIND
private static final int LOCAL_KIND- See Also:
-
STACK_KIND
private static final int STACK_KIND- See Also:
-
TOP_IF_LONG_OR_DOUBLE_FLAG
private static final int TOP_IF_LONG_OR_DOUBLE_FLAGA flag used for LOCAL_KIND and STACK_KIND abstract types, indicating that if the resolved, concrete type is LONG or DOUBLE, TOP should be used instead (because the value has been partially overridden with an xSTORE instruction).- See Also:
-
TOP
private static final int TOP- See Also:
-
BOOLEAN
private static final int BOOLEAN- See Also:
-
BYTE
private static final int BYTE- See Also:
-
CHAR
private static final int CHAR- See Also:
-
SHORT
private static final int SHORT- See Also:
-
INTEGER
private static final int INTEGER- See Also:
-
FLOAT
private static final int FLOAT- See Also:
-
LONG
private static final int LONG- See Also:
-
DOUBLE
private static final int DOUBLE- See Also:
-
NULL
private static final int NULL- See Also:
-
UNINITIALIZED_THIS
private static final int UNINITIALIZED_THIS- See Also:
-
owner
Label ownerThe basic block to which these input and output stack map frames correspond. -
inputLocals
private int[] inputLocalsThe input stack map frame locals. This is an array of abstract types. -
inputStack
private int[] inputStackThe input stack map frame stack. This is an array of abstract types. -
outputLocals
private int[] outputLocalsThe output stack map frame locals. This is an array of abstract types. -
outputStack
private int[] outputStackThe output stack map frame stack. This is an array of abstract types. -
outputStackStart
private short outputStackStartThe start of the output stack, relatively to the input stack. This offset is always negative or null. A null offset means that the output stack must be appended to the input stack. A -n offset means that the first n output stack elements must replace the top n input stack elements, and that the other elements must be appended to the input stack. -
outputStackTop
private short outputStackTopThe index of the top stack element inoutputStack
. -
initializationCount
private int initializationCountThe number of types that are initialized in the basic block. Seeinitializations
. -
initializations
private int[] initializationsThe abstract types that are initialized in the basic block. A constructor invocation on an UNINITIALIZED or UNINITIALIZED_THIS abstract type must replace every occurrence of this type in the local variables and in the operand stack. This cannot be done during the first step of the algorithm since, during this step, the local variables and the operand stack types are still abstract. It is therefore necessary to store the abstract types of the constructors which are invoked in the basic block, in order to do this replacement during the second step of the algorithm, where the frames are fully computed. Note that this array can contain abstract types that are relative to the input locals or to the input stack.
-
-
Constructor Details
-
Frame
Frame(Label owner) Constructs a new Frame.- Parameters:
owner
- the basic block to which these input and output stack map frames correspond.
-
-
Method Details
-
copyFrom
Sets this frame to the value of the given frame.WARNING: after this method is called the two frames share the same data structures. It is recommended to discard the given frame to avoid unexpected side effects.
- Parameters:
frame
- The new frame value.
-
getAbstractTypeFromApiFormat
Returns the abstract type corresponding to the given public API frame element type.- Parameters:
symbolTable
- the type table to use to lookup and store typeSymbol
.type
- a frame element type described using the same format as inMethodVisitor.visitFrame(int, int, java.lang.Object[], int, java.lang.Object[])
, i.e. eitherOpcodes.TOP
,Opcodes.INTEGER
,Opcodes.FLOAT
,Opcodes.LONG
,Opcodes.DOUBLE
,Opcodes.NULL
, orOpcodes.UNINITIALIZED_THIS
, or the internal name of a class, or a Label designating a NEW instruction (for uninitialized types).- Returns:
- the abstract type corresponding to the given frame element type.
-
getAbstractTypeFromInternalName
Returns the abstract type corresponding to the internal name of a class.- Parameters:
symbolTable
- the type table to use to lookup and store typeSymbol
.internalName
- the internal name of a class. This must not be an array type descriptor.- Returns:
- the abstract type value corresponding to the given internal name.
-
getAbstractTypeFromDescriptor
private static int getAbstractTypeFromDescriptor(SymbolTable symbolTable, String buffer, int offset) Returns the abstract type corresponding to the given type descriptor.- Parameters:
symbolTable
- the type table to use to lookup and store typeSymbol
.buffer
- a string ending with a type descriptor.offset
- the start offset of the type descriptor in buffer.- Returns:
- the abstract type corresponding to the given type descriptor.
-
setInputFrameFromDescriptor
final void setInputFrameFromDescriptor(SymbolTable symbolTable, int access, String descriptor, int maxLocals) Sets the input frame from the given method description. This method is used to initialize the first frame of a method, which is implicit (i.e. not stored explicitly in the StackMapTable attribute).- Parameters:
symbolTable
- the type table to use to lookup and store typeSymbol
.access
- the method's access flags.descriptor
- the method descriptor.maxLocals
- the maximum number of local variables of the method.
-
setInputFrameFromApiFormat
final void setInputFrameFromApiFormat(SymbolTable symbolTable, int numLocal, Object[] local, int numStack, Object[] stack) Sets the input frame from the given public API frame description.- Parameters:
symbolTable
- the type table to use to lookup and store typeSymbol
.numLocal
- the number of local variables.local
- the local variable types, described using the same format as inMethodVisitor.visitFrame(int, int, java.lang.Object[], int, java.lang.Object[])
.numStack
- the number of operand stack elements.stack
- the operand stack types, described using the same format as inMethodVisitor.visitFrame(int, int, java.lang.Object[], int, java.lang.Object[])
.
-
getInputStackSize
final int getInputStackSize() -
getLocal
private int getLocal(int localIndex) Returns the abstract type stored at the given local variable index in the output frame.- Parameters:
localIndex
- the index of the local variable whose value must be returned.- Returns:
- the abstract type stored at the given local variable index in the output frame.
-
setLocal
private void setLocal(int localIndex, int abstractType) Replaces the abstract type stored at the given local variable index in the output frame.- Parameters:
localIndex
- the index of the output frame local variable that must be set.abstractType
- the value that must be set.
-
push
private void push(int abstractType) Pushes the given abstract type on the output frame stack.- Parameters:
abstractType
- an abstract type.
-
push
Pushes the abstract type corresponding to the given descriptor on the output frame stack.- Parameters:
symbolTable
- the type table to use to lookup and store typeSymbol
.descriptor
- a type or method descriptor (in which case its return type is pushed).
-
pop
private int pop()Pops an abstract type from the output frame stack and returns its value.- Returns:
- the abstract type that has been popped from the output frame stack.
-
pop
private void pop(int elements) Pops the given number of abstract types from the output frame stack.- Parameters:
elements
- the number of abstract types that must be popped.
-
pop
Pops as many abstract types from the output frame stack as described by the given descriptor.- Parameters:
descriptor
- a type or method descriptor (in which case its argument types are popped).
-
addInitializedType
private void addInitializedType(int abstractType) Adds an abstract type to the list of types on which a constructor is invoked in the basic block.- Parameters:
abstractType
- an abstract type on a which a constructor is invoked.
-
getInitializedType
Returns the "initialized" abstract type corresponding to the given abstract type.- Parameters:
symbolTable
- the type table to use to lookup and store typeSymbol
.abstractType
- an abstract type.- Returns:
- the REFERENCE_KIND abstract type corresponding to abstractType if it is UNINITIALIZED_THIS or an UNINITIALIZED_KIND abstract type for one of the types on which a constructor is invoked in the basic block. Otherwise returns abstractType.
-
execute
Simulates the action of the given instruction on the output stack frame.- Parameters:
opcode
- the opcode of the instruction.arg
- the numeric operand of the instruction, if any.argSymbol
- the Symbol operand of the instruction, if any.symbolTable
- the type table to use to lookup and store typeSymbol
.
-
getConcreteOutputType
private int getConcreteOutputType(int abstractOutputType, int numStack) Computes the concrete output type corresponding to a given abstract output type.- Parameters:
abstractOutputType
- an abstract output type.numStack
- the size of the input stack, used to resolve abstract output types of STACK_KIND kind.- Returns:
- the concrete output type corresponding to 'abstractOutputType'.
-
merge
Merges the input frame of the givenFrame
with the input and output frames of thisFrame
. Returns true if the given frame has been changed by this operation (the input and output frames of thisFrame
are never changed).- Parameters:
symbolTable
- the type table to use to lookup and store typeSymbol
.dstFrame
- theFrame
whose input frame must be updated. This should be the frame of a successor, in the control flow graph, of the basic block corresponding to this frame.catchTypeIndex
- if 'frame' corresponds to an exception handler basic block, the type table index of the caught exception type, otherwise 0.- Returns:
- true if the input frame of 'frame' has been changed by this operation.
-
merge
Merges the type at the given index in the given abstract type array with the given type. Returns true if the type array has been modified by this operation.- Parameters:
symbolTable
- the type table to use to lookup and store typeSymbol
.sourceType
- the abstract type with which the abstract type array element must be merged. This type should be ofCONSTANT_KIND
,REFERENCE_KIND
orUNINITIALIZED_KIND
kind, with positive or null array dimensions.dstTypes
- an array of abstract types. These types should be ofCONSTANT_KIND
,REFERENCE_KIND
orUNINITIALIZED_KIND
kind, with positive or null array dimensions.dstIndex
- the index of the type that must be merged in dstTypes.- Returns:
- true if the type array has been modified by this operation.
-
accept
Makes the givenMethodWriter
visit the input frame of thisFrame
. The visit is done with theMethodWriter.visitFrameStart(int, int, int)
,MethodWriter.visitAbstractType(int, int)
andMethodWriter.visitFrameEnd()
methods.- Parameters:
methodWriter
- theMethodWriter
that should visit the input frame of thisFrame
.
-
putAbstractType
Put the given abstract type in the given ByteVector, using the JVMS verification_type_info format used in StackMapTable attributes.- Parameters:
symbolTable
- the type table to use to lookup and store typeSymbol
.abstractType
- an abstract type, restricted toCONSTANT_KIND
,REFERENCE_KIND
orUNINITIALIZED_KIND
types.output
- where the abstract type must be put.- See Also:
-