class Frame
extends java.lang.Object
Stack map frames are computed in two steps:
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| =====================================
DIM_MASK
and a
right shift of DIM_SHIFT
.
KIND_MASK
and, without any shift, must be equal to CONSTANT_KIND
, REFERENCE_KIND
, UNINITIALIZED_KIND
, LOCAL_KIND
or STACK_KIND
.
TOP_IF_LONG_OR_DOUBLE_FLAG
.
ITEM_TOP
, ITEM_ASM_BOOLEAN
, ITEM_ASM_BYTE
, ITEM_ASM_CHAR
or ITEM_ASM_SHORT
, ITEM_INTEGER
, ITEM_FLOAT
, ITEM_LONG
, ITEM_DOUBLE
, ITEM_NULL
or ITEM_UNINITIALIZED_THIS
, if KIND is equal to CONSTANT_KIND
.
Symbol.TYPE_TAG
Symbol
in the type table of a SymbolTable
, if KIND is equal to REFERENCE_KIND
.
Symbol.UNINITIALIZED_TYPE_TAG
Symbol
in the type
table of a SymbolTable, if KIND is equal to UNINITIALIZED_KIND
.
LOCAL_KIND
.
STACK_KIND
,
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).
Modifier and Type | Field and Description |
---|---|
(package private) static int |
APPEND_FRAME |
private static int |
ARRAY_OF
The constant to be added to an abstract type to get one with one more array dimension.
|
private static int |
BOOLEAN |
private static int |
BYTE |
private static int |
CHAR |
(package private) static int |
CHOP_FRAME |
private static int |
CONSTANT_KIND |
private static int |
DIM_MASK |
private static int |
DIM_SHIFT |
private static int |
DIM_SIZE |
private static int |
DOUBLE |
private static int |
ELEMENT_OF
The constant to be added to an abstract type to get one with one less array dimension.
|
private static int |
FLAGS_SHIFT |
private static int |
FLAGS_SIZE |
private static int |
FLOAT |
(package private) static int |
FULL_FRAME |
private int |
initializationCount
The number of types that are initialized in the basic block.
|
private int[] |
initializations
The abstract types that are initialized in the basic block.
|
private int[] |
inputLocals
The input stack map frame locals.
|
private int[] |
inputStack
The input stack map frame stack.
|
private static int |
INTEGER |
private static int |
ITEM_ASM_BOOLEAN |
private static int |
ITEM_ASM_BYTE |
private static int |
ITEM_ASM_CHAR |
private static int |
ITEM_ASM_SHORT |
(package private) static int |
ITEM_DOUBLE |
(package private) static int |
ITEM_FLOAT |
(package private) static int |
ITEM_INTEGER |
(package private) static int |
ITEM_LONG |
(package private) static int |
ITEM_NULL |
(package private) static int |
ITEM_OBJECT |
(package private) static int |
ITEM_TOP |
(package private) static int |
ITEM_UNINITIALIZED |
(package private) static int |
ITEM_UNINITIALIZED_THIS |
private static int |
KIND_MASK |
private static int |
KIND_SHIFT |
private static int |
KIND_SIZE |
private static int |
LOCAL_KIND |
private static int |
LONG |
private static int |
NULL |
private int[] |
outputLocals
The output stack map frame locals.
|
private int[] |
outputStack
The output stack map frame stack.
|
private short |
outputStackStart
The start of the output stack, relatively to the input stack.
|
private short |
outputStackTop
The index of the top stack element in
outputStack . |
(package private) Label |
owner
The basic block to which these input and output stack map frames correspond.
|
private static int |
REFERENCE_KIND |
(package private) static int |
RESERVED |
(package private) static int |
SAME_FRAME |
(package private) static int |
SAME_FRAME_EXTENDED |
(package private) static int |
SAME_LOCALS_1_STACK_ITEM_FRAME |
(package private) static int |
SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED |
private static int |
SHORT |
private static int |
STACK_KIND |
private static int |
TOP |
private static int |
TOP_IF_LONG_OR_DOUBLE_FLAG
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 int |
UNINITIALIZED_KIND |
private static int |
UNINITIALIZED_THIS |
private static int |
VALUE_MASK |
private static int |
VALUE_SIZE |
Constructor and Description |
---|
Frame(Label owner)
Constructs a new Frame.
|
Modifier and Type | Method and Description |
---|---|
(package private) void |
accept(MethodWriter methodWriter)
Makes the given
MethodWriter visit the input frame of this Frame . |
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) void |
copyFrom(Frame frame)
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,
java.lang.Object type)
Returns the abstract type corresponding to the given public API frame element type.
|
private static int |
getAbstractTypeFromDescriptor(SymbolTable symbolTable,
java.lang.String buffer,
int offset)
Returns the abstract type corresponding to the given type descriptor.
|
(package private) static int |
getAbstractTypeFromInternalName(SymbolTable symbolTable,
java.lang.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) int |
getInputStackSize() |
private int |
getLocal(int localIndex)
Returns the abstract type stored at the given local variable index in the output frame.
|
(package private) boolean |
merge(SymbolTable symbolTable,
Frame dstFrame,
int catchTypeIndex)
|
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.
|
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 |
pop(java.lang.String descriptor)
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,
java.lang.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) void |
setInputFrameFromApiFormat(SymbolTable symbolTable,
int numLocal,
java.lang.Object[] local,
int numStack,
java.lang.Object[] stack)
Sets the input frame from the given public API frame description.
|
(package private) void |
setInputFrameFromDescriptor(SymbolTable symbolTable,
int access,
java.lang.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.
|
static final int SAME_FRAME
static final int SAME_LOCALS_1_STACK_ITEM_FRAME
static final int RESERVED
static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED
static final int CHOP_FRAME
static final int SAME_FRAME_EXTENDED
static final int APPEND_FRAME
static final int FULL_FRAME
static final int ITEM_TOP
static final int ITEM_INTEGER
static final int ITEM_FLOAT
static final int ITEM_DOUBLE
static final int ITEM_LONG
static final int ITEM_NULL
static final int ITEM_UNINITIALIZED_THIS
static final int ITEM_OBJECT
static final int ITEM_UNINITIALIZED
private static final int ITEM_ASM_BOOLEAN
private static final int ITEM_ASM_BYTE
private static final int ITEM_ASM_CHAR
private static final int ITEM_ASM_SHORT
private static final int DIM_SIZE
private static final int KIND_SIZE
private static final int FLAGS_SIZE
private static final int VALUE_SIZE
private static final int DIM_SHIFT
private static final int KIND_SHIFT
private static final int FLAGS_SHIFT
private static final int DIM_MASK
private static final int KIND_MASK
private static final int VALUE_MASK
private static final int ARRAY_OF
private static final int ELEMENT_OF
private static final int CONSTANT_KIND
private static final int REFERENCE_KIND
private static final int UNINITIALIZED_KIND
private static final int LOCAL_KIND
private static final int STACK_KIND
private static final int TOP_IF_LONG_OR_DOUBLE_FLAG
private static final int TOP
private static final int BOOLEAN
private static final int BYTE
private static final int CHAR
private static final int SHORT
private static final int INTEGER
private static final int FLOAT
private static final int LONG
private static final int DOUBLE
private static final int NULL
private static final int UNINITIALIZED_THIS
Label owner
private int[] inputLocals
private int[] inputStack
private int[] outputLocals
private int[] outputStack
private short outputStackStart
private short outputStackTop
outputStack
.private int initializationCount
initializations
.private int[] initializations
Frame(Label owner)
owner
- the basic block to which these input and output stack map frames correspond.final void copyFrom(Frame 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.
frame
- The new frame value.static int getAbstractTypeFromApiFormat(SymbolTable symbolTable, java.lang.Object type)
symbolTable
- the type table to use to lookup and store type Symbol
.type
- a frame element type described using the same format as in MethodVisitor.visitFrame(int, int, java.lang.Object[], int, java.lang.Object[])
, i.e. either Opcodes.TOP
, Opcodes.INTEGER
, Opcodes.FLOAT
, Opcodes.LONG
, Opcodes.DOUBLE
, Opcodes.NULL
, or
Opcodes.UNINITIALIZED_THIS
, or the internal name of a class, or a Label designating
a NEW instruction (for uninitialized types).static int getAbstractTypeFromInternalName(SymbolTable symbolTable, java.lang.String internalName)
symbolTable
- the type table to use to lookup and store type Symbol
.internalName
- the internal name of a class. This must not be an array type
descriptor.private static int getAbstractTypeFromDescriptor(SymbolTable symbolTable, java.lang.String buffer, int offset)
symbolTable
- the type table to use to lookup and store type Symbol
.buffer
- a string ending with a type descriptor.offset
- the start offset of the type descriptor in buffer.final void setInputFrameFromDescriptor(SymbolTable symbolTable, int access, java.lang.String descriptor, int maxLocals)
symbolTable
- the type table to use to lookup and store type Symbol
.access
- the method's access flags.descriptor
- the method descriptor.maxLocals
- the maximum number of local variables of the method.final void setInputFrameFromApiFormat(SymbolTable symbolTable, int numLocal, java.lang.Object[] local, int numStack, java.lang.Object[] stack)
symbolTable
- the type table to use to lookup and store type Symbol
.numLocal
- the number of local variables.local
- the local variable types, described using the same format as in MethodVisitor.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 in MethodVisitor.visitFrame(int, int, java.lang.Object[], int, java.lang.Object[])
.final int getInputStackSize()
private int getLocal(int localIndex)
localIndex
- the index of the local variable whose value must be returned.private void setLocal(int localIndex, int abstractType)
localIndex
- the index of the output frame local variable that must be set.abstractType
- the value that must be set.private void push(int abstractType)
abstractType
- an abstract type.private void push(SymbolTable symbolTable, java.lang.String descriptor)
symbolTable
- the type table to use to lookup and store type Symbol
.descriptor
- a type or method descriptor (in which case its return type is pushed).private int pop()
private void pop(int elements)
elements
- the number of abstract types that must be popped.private void pop(java.lang.String descriptor)
descriptor
- a type or method descriptor (in which case its argument types are popped).private void addInitializedType(int abstractType)
abstractType
- an abstract type on a which a constructor is invoked.private int getInitializedType(SymbolTable symbolTable, int abstractType)
symbolTable
- the type table to use to lookup and store type Symbol
.abstractType
- an abstract type.void execute(int opcode, int arg, Symbol argSymbol, SymbolTable symbolTable)
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 type Symbol
.private int getConcreteOutputType(int abstractOutputType, int numStack)
abstractOutputType
- an abstract output type.numStack
- the size of the input stack, used to resolve abstract output types of
STACK_KIND kind.final boolean merge(SymbolTable symbolTable, Frame dstFrame, int catchTypeIndex)
Frame
with the input and output frames of this
Frame
. Returns true if the given frame has been changed by this operation
(the input and output frames of this Frame
are never changed).symbolTable
- the type table to use to lookup and store type Symbol
.dstFrame
- the Frame
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.private static boolean merge(SymbolTable symbolTable, int sourceType, int[] dstTypes, int dstIndex)
symbolTable
- the type table to use to lookup and store type Symbol
.sourceType
- the abstract type with which the abstract type array element must be merged.
This type should be of CONSTANT_KIND
, REFERENCE_KIND
or UNINITIALIZED_KIND
kind, with positive or null array dimensions.dstTypes
- an array of abstract types. These types should be of CONSTANT_KIND
,
REFERENCE_KIND
or UNINITIALIZED_KIND
kind, with positive or null array dimensions.dstIndex
- the index of the type that must be merged in dstTypes.final void accept(MethodWriter methodWriter)
MethodWriter
visit the input frame of this Frame
. The visit is
done with the MethodWriter.visitFrameStart(int, int, int)
, MethodWriter.visitAbstractType(int, int)
and
MethodWriter.visitFrameEnd()
methods.methodWriter
- the MethodWriter
that should visit the input frame of this Frame
.static void putAbstractType(SymbolTable symbolTable, int abstractType, ByteVector output)
symbolTable
- the type table to use to lookup and store type Symbol
.abstractType
- an abstract type, restricted to CONSTANT_KIND
, REFERENCE_KIND
or UNINITIALIZED_KIND
types.output
- where the abstract type must be put.