Package org.objectweb.asm.util
Class CheckFrameAnalyzer<V extends Value>
- java.lang.Object
-
- org.objectweb.asm.tree.analysis.Analyzer<V>
-
- org.objectweb.asm.util.CheckFrameAnalyzer<V>
-
- Type Parameters:
V
- type of theValue
used for the analysis.
- All Implemented Interfaces:
Opcodes
class CheckFrameAnalyzer<V extends Value> extends Analyzer<V>
AnAnalyzer
subclass which checks that methods provide stack map frames where expected (i.e. at jump target and after instructions without immediate successor), and that these stack map frames are valid (for the provided interpreter; they may still be invalid for the JVM, if theInterpreter
uses a simplified type system compared to the JVM verifier). This is done in two steps:- First, the stack map frames in
FrameNode
s are expanded, and stored at their respective instruction offsets. The expansion process uncompresses the APPEND, CHOP and SAME frames to FULL frames. It also converts the stack map frame verification types toValue
s, via the providedInterpreter
. The expansion is done inexpandFrames(java.lang.String, org.objectweb.asm.tree.MethodNode, org.objectweb.asm.tree.analysis.Frame<V>)
, by looking at eachFrameNode
in sequence (compressed frames are defined relatively to the previousFrameNode
, or the implicit first frame). The actual decompression is done inexpandFrame(java.lang.String, org.objectweb.asm.tree.analysis.Frame<V>, org.objectweb.asm.tree.FrameNode)
, and the type conversion innewFrameValue(java.lang.String, org.objectweb.asm.tree.FrameNode, java.lang.Object)
. - Next, the method instructions are checked in sequence. Starting from the implicit initial
frame, the execution of each instruction i is simulated on the current stack map
frame, with the
Frame.execute(org.objectweb.asm.tree.AbstractInsnNode, org.objectweb.asm.tree.analysis.Interpreter<V>)
method. This gives a new stack map frame f, representing the stack map frame state after the execution of i. Then:- If there is a next instruction and if the control flow cannot continue to it (e.g. if i is a RETURN or an ATHROW, for instance): an existing stack map frame f0 (coming from the first step) is expected after i.
- If there is a next instruction and if the control flow can continue to it (e.g. if i is a ALOAD, for instance): either there an existing stack map frame f0 (coming from the first step) after i, or there is none. In the first case f and f0 must be compatible: the types in f must be sub types of the corresponding types in the existing frame f0 (otherwise an exception is thrown). In the second case, f0 is simply set to the value of f.
- If the control flow can continue to some instruction j (e.g. if i is an IF_EQ, for instance): an existing stack map frame f0 (coming from the first step) is expected at j, which must be compatible with f (as defined previously).
init(java.lang.String, org.objectweb.asm.tree.MethodNode)
, which is called from theAnalyzer.analyze(java.lang.String, org.objectweb.asm.tree.MethodNode)
method. Cases where the control flow cannot continue to the next instruction are handled inendControlFlow(int)
. Cases where the control flow can continue to the next instruction, or jump to another instruction, are handled incheckFrame(int, org.objectweb.asm.tree.analysis.Frame<V>, boolean)
. This method checks that an existing stack map frame is present when required, and checks the stack map frames compatibility withcheckMerge(org.objectweb.asm.tree.analysis.Frame<V>, org.objectweb.asm.tree.analysis.Frame<V>)
.
-
-
Field Summary
Fields Modifier and Type Field Description private int
currentLocals
The number of locals in the last stack map frame processed byexpandFrame(java.lang.String,org.objectweb.asm.tree.analysis.Frame<V>,org.objectweb.asm.tree.FrameNode)
.private InsnList
insnList
The instructions of the currently analyzed method.private Interpreter<V>
interpreter
The interpreter to use to symbolically interpret the bytecode instructions.-
Fields inherited from interface org.objectweb.asm.Opcodes
AALOAD, AASTORE, ACC_ABSTRACT, ACC_ANNOTATION, ACC_BRIDGE, ACC_DEPRECATED, ACC_ENUM, ACC_FINAL, ACC_INTERFACE, ACC_MANDATED, ACC_MODULE, ACC_NATIVE, ACC_OPEN, ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC, ACC_RECORD, ACC_STATIC, ACC_STATIC_PHASE, ACC_STRICT, ACC_SUPER, ACC_SYNCHRONIZED, ACC_SYNTHETIC, ACC_TRANSIENT, ACC_TRANSITIVE, ACC_VARARGS, ACC_VOLATILE, ACONST_NULL, ALOAD, ANEWARRAY, ARETURN, ARRAYLENGTH, ASM10_EXPERIMENTAL, ASM4, ASM5, ASM6, ASM7, ASM8, ASM9, ASTORE, ATHROW, BALOAD, BASTORE, BIPUSH, CALOAD, CASTORE, CHECKCAST, D2F, D2I, D2L, DADD, DALOAD, DASTORE, DCMPG, DCMPL, DCONST_0, DCONST_1, DDIV, DLOAD, DMUL, DNEG, DOUBLE, DREM, DRETURN, DSTORE, DSUB, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, F_APPEND, F_CHOP, F_FULL, F_NEW, F_SAME, F_SAME1, F2D, F2I, F2L, FADD, FALOAD, FASTORE, FCMPG, FCMPL, FCONST_0, FCONST_1, FCONST_2, FDIV, FLOAD, FLOAT, FMUL, FNEG, FREM, FRETURN, FSTORE, FSUB, GETFIELD, GETSTATIC, GOTO, H_GETFIELD, H_GETSTATIC, H_INVOKEINTERFACE, H_INVOKESPECIAL, H_INVOKESTATIC, H_INVOKEVIRTUAL, H_NEWINVOKESPECIAL, H_PUTFIELD, H_PUTSTATIC, I2B, I2C, I2D, I2F, I2L, I2S, IADD, IALOAD, IAND, IASTORE, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, ICONST_M1, IDIV, IF_ACMPEQ, IF_ACMPNE, IF_ICMPEQ, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ICMPLT, IF_ICMPNE, IFEQ, IFGE, IFGT, IFLE, IFLT, IFNE, IFNONNULL, IFNULL, IINC, ILOAD, IMUL, INEG, INSTANCEOF, INTEGER, INVOKEDYNAMIC, INVOKEINTERFACE, INVOKESPECIAL, INVOKESTATIC, INVOKEVIRTUAL, IOR, IREM, IRETURN, ISHL, ISHR, ISTORE, ISUB, IUSHR, IXOR, JSR, L2D, L2F, L2I, LADD, LALOAD, LAND, LASTORE, LCMP, LCONST_0, LCONST_1, LDC, LDIV, LLOAD, LMUL, LNEG, LONG, LOOKUPSWITCH, LOR, LREM, LRETURN, LSHL, LSHR, LSTORE, LSUB, LUSHR, LXOR, MONITORENTER, MONITOREXIT, MULTIANEWARRAY, NEW, NEWARRAY, NOP, NULL, POP, POP2, PUTFIELD, PUTSTATIC, RET, RETURN, SALOAD, SASTORE, SIPUSH, SOURCE_DEPRECATED, SOURCE_MASK, SWAP, T_BOOLEAN, T_BYTE, T_CHAR, T_DOUBLE, T_FLOAT, T_INT, T_LONG, T_SHORT, TABLESWITCH, TOP, UNINITIALIZED_THIS, V_PREVIEW, V1_1, V1_2, V1_3, V1_4, V1_5, V1_6, V1_7, V1_8, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, V21, V9
-
-
Constructor Summary
Constructors Constructor Description CheckFrameAnalyzer(Interpreter<V> interpreter)
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description private void
checkFrame(int insnIndex, Frame<V> frame, boolean requireFrame)
Checks that the given frame is compatible with the frame at the given instruction index, if any.private java.lang.String
checkMerge(Frame<V> srcFrame, Frame<V> dstFrame)
Checks that merging the two given frames would not produce any change, i.e.private void
endControlFlow(int insnIndex)
Ends the control flow graph at the given instruction.private Frame<V>
expandFrame(java.lang.String owner, Frame<V> previousFrame, FrameNode frameNode)
Returns the expanded representation of the givenFrameNode
.private void
expandFrames(java.lang.String owner, MethodNode method, Frame<V> initialFrame)
Expands theFrameNode
"instructions" of the given method intoFrame
objects and stores them at the corresponding indices of theAnalyzer.frames
array.private boolean
hasNextJvmInsnOrFrame(int insnIndex)
Returns true if the given instruction is followed by a JVM instruction or a by stack map frame.protected void
init(java.lang.String owner, MethodNode method)
Initializes this analyzer.private static boolean
isJvmInsnNode(AbstractInsnNode insnNode)
Returns true if the given instruction node corresponds to a real JVM instruction.private V
newFrameValue(java.lang.String owner, FrameNode frameNode, java.lang.Object type)
Creates a newValue
that represents the given stack map frame type.-
Methods inherited from class org.objectweb.asm.tree.analysis.Analyzer
analyze, analyzeAndComputeMaxs, getFrames, getHandlers, newControlFlowEdge, newControlFlowExceptionEdge, newControlFlowExceptionEdge, newFrame, newFrame
-
-
-
-
Field Detail
-
interpreter
private final Interpreter<V extends Value> interpreter
The interpreter to use to symbolically interpret the bytecode instructions.
-
insnList
private InsnList insnList
The instructions of the currently analyzed method.
-
currentLocals
private int currentLocals
The number of locals in the last stack map frame processed byexpandFrame(java.lang.String,org.objectweb.asm.tree.analysis.Frame<V>,org.objectweb.asm.tree.FrameNode)
. Long and double values are represented with two elements.
-
-
Constructor Detail
-
CheckFrameAnalyzer
CheckFrameAnalyzer(Interpreter<V> interpreter)
-
-
Method Detail
-
init
protected void init(java.lang.String owner, MethodNode method) throws AnalyzerException
Description copied from class:Analyzer
Initializes this analyzer. This method is called just before the execution of control flow analysis loop inAnalyzer.analyze(java.lang.String, org.objectweb.asm.tree.MethodNode)
. The default implementation of this method does nothing.- Overrides:
init
in classAnalyzer<V extends Value>
- Parameters:
owner
- the internal name of the class to which the method belongs (seeType.getInternalName()
).method
- the method to be analyzed.- Throws:
AnalyzerException
- if a problem occurs.
-
expandFrames
private void expandFrames(java.lang.String owner, MethodNode method, Frame<V> initialFrame) throws AnalyzerException
Expands theFrameNode
"instructions" of the given method intoFrame
objects and stores them at the corresponding indices of theAnalyzer.frames
array. The expanded frames are also associated with the label and line number nodes immediately preceding each frame node.- Parameters:
owner
- the internal name of the class to which 'method' belongs.method
- the method whose frames must be expanded.initialFrame
- the implicit initial frame of 'method'.- Throws:
AnalyzerException
- if the stack map frames of 'method', i.e. its FrameNode "instructions", are invalid.
-
expandFrame
private Frame<V> expandFrame(java.lang.String owner, Frame<V> previousFrame, FrameNode frameNode) throws AnalyzerException
Returns the expanded representation of the givenFrameNode
.- Parameters:
owner
- the internal name of the class to which 'frameNode' belongs.previousFrame
- the frame before 'frameNode', in expanded form.frameNode
- a possibly compressed stack map frame.- Returns:
- the expanded version of 'frameNode'.
- Throws:
AnalyzerException
- if 'frameNode' is invalid.
-
newFrameValue
private V newFrameValue(java.lang.String owner, FrameNode frameNode, java.lang.Object type) throws AnalyzerException
Creates a newValue
that represents the given stack map frame type.- Parameters:
owner
- the internal name of the class to which 'frameNode' belongs.frameNode
- the stack map frame to which 'type' belongs.type
- an Integer, String or LabelNode object representing a primitive, reference or uninitialized a stack map frame type, respectively. SeeFrameNode
.- Returns:
- a value that represents the given type.
- Throws:
AnalyzerException
- if 'type' is an invalid stack map frame type.
-
checkFrame
private void checkFrame(int insnIndex, Frame<V> frame, boolean requireFrame) throws AnalyzerException
Checks that the given frame is compatible with the frame at the given instruction index, if any. If there is no frame at this instruction index and none is required, the frame at 'insnIndex' is set to the given frame. Otherwise, if the merge of the two frames is not equal to the current frame at 'insnIndex', an exception is thrown.- Parameters:
insnIndex
- an instruction index.frame
- a frame. This frame is left unchanged by this method.requireFrame
- whether a frame must already exist or not inAnalyzer.frames
at 'insnIndex'.- Throws:
AnalyzerException
- if the frames have incompatible sizes or if the frame at 'insnIndex' is missing (if required) or not compatible with 'frame'.
-
checkMerge
private java.lang.String checkMerge(Frame<V> srcFrame, Frame<V> dstFrame)
Checks that merging the two given frames would not produce any change, i.e. that the types in the source frame are sub types of the corresponding types in the destination frame.- Parameters:
srcFrame
- a source frame. This frame is left unchanged by this method.dstFrame
- a destination frame. This frame is left unchanged by this method.- Returns:
- an error message if the frames have incompatible sizes, or if a type in the source frame is not a sub type of the corresponding type in the destination frame. Returns null otherwise.
-
endControlFlow
private void endControlFlow(int insnIndex) throws AnalyzerException
Ends the control flow graph at the given instruction. This method checks that there is an existing frame for the next instruction, if any.- Parameters:
insnIndex
- an instruction index.- Throws:
AnalyzerException
- if 'insnIndex' is not the last instruction and there is no frame at 'insnIndex' + 1 inAnalyzer.getFrames()
.
-
hasNextJvmInsnOrFrame
private boolean hasNextJvmInsnOrFrame(int insnIndex)
Returns true if the given instruction is followed by a JVM instruction or a by stack map frame.- Parameters:
insnIndex
- an instruction index.- Returns:
- true if 'insnIndex' is followed by a JVM instruction or a by stack map frame.
-
isJvmInsnNode
private static boolean isJvmInsnNode(AbstractInsnNode insnNode)
Returns true if the given instruction node corresponds to a real JVM instruction.- Parameters:
insnNode
- an instruction node.- Returns:
- true except for label, line number and stack map frame nodes.
-
-