📄 analyzer.java
字号:
current,
subroutine );
}
} else if ( insnOpcode == Opcodes.RET ) {
if ( subroutine == null ) {
throw new AnalyzerException( "RET instruction outside of a sub routine" );
}
for ( int i = 0; i < subroutine.callers.size(); ++i ) {
final int caller = this.indexes.get( subroutine.callers.get( i ) );
merge( caller + 1,
this.frames[caller],
current,
this.subroutines[caller],
subroutine.access );
}
} else if ( insnOpcode != Opcodes.ATHROW && (insnOpcode < Opcodes.IRETURN || insnOpcode > Opcodes.RETURN) ) {
if ( subroutine != null ) {
if ( insnNode instanceof VarInsnNode ) {
final int var = ((VarInsnNode) insnNode).var;
subroutine.access[var] = true;
if ( insnOpcode == Opcodes.LLOAD || insnOpcode == Opcodes.DLOAD || insnOpcode == Opcodes.LSTORE || insnOpcode == Opcodes.DSTORE ) {
subroutine.access[var + 1] = true;
}
} else if ( insnNode instanceof IincInsnNode ) {
final int var = ((IincInsnNode) insnNode).var;
subroutine.access[var] = true;
}
}
merge( insn + 1,
current,
subroutine );
}
}
final List insnHandlers = this.handlers[insn];
if ( insnHandlers != null ) {
for ( int i = 0; i < insnHandlers.size(); ++i ) {
final TryCatchBlockNode tcb = (TryCatchBlockNode) insnHandlers.get( i );
Type type;
if ( tcb.type == null ) {
type = Type.getType( "Ljava/lang/Throwable;" );
} else {
type = Type.getType( "L" + tcb.type + ";" );
}
handler.init( f );
handler.clearStack();
handler.push( this.interpreter.newValue( type ) );
merge( this.indexes.get( tcb.handler ),
handler,
subroutine );
}
}
} catch ( final AnalyzerException e ) {
throw new AnalyzerException( "Error at instruction " + insn + ": " + e.getMessage(),
e );
} catch ( final Exception e ) {
throw new AnalyzerException( "Error at instruction " + insn + ": " + e.getMessage(),
e );
}
}
return this.frames;
}
/**
* Returns the symbolic stack frame for each instruction of the last
* recently analyzed method.
*
* @return the symbolic state of the execution stack frame at each bytecode
* instruction of the method. The size of the returned array is
* equal to the number of instructions (and labels) of the method. A
* given frame is <tt>null</tt> if the corresponding instruction
* cannot be reached, or if an error occured during the analysis of
* the method.
*/
public Frame[] getFrames() {
return this.frames;
}
/**
* Returns the index of the given instruction.
*
* @param insn a {@link Label} or {@link AbstractInsnNode} of the last
* recently analyzed method.
* @return the index of the given instruction of the last recently analyzed
* method.
*/
public int getIndex(final Object insn) {
return this.indexes.get( insn );
}
/**
* Returns the exception handlers for the given instruction.
*
* @param insn the index of an instruction of the last recently analyzed
* method.
* @return a list of {@link TryCatchBlockNode} objects.
*/
public List getHandlers(final int insn) {
return this.handlers[insn];
}
/**
* Constructs a new frame with the given size.
*
* @param nLocals the maximum number of local variables of the frame.
* @param nStack the maximum stack size of the frame.
* @return the created frame.
*/
protected Frame newFrame(final int nLocals,
final int nStack) {
return new Frame( nLocals,
nStack );
}
/**
* Constructs a new frame that is identical to the given frame.
*
* @param src a frame.
* @return the created frame.
*/
protected Frame newFrame(final Frame src) {
return new Frame( src );
}
/**
* Creates a control flow graph edge. The default implementation of this
* method does nothing. It can be overriden in order to construct the
* control flow graph of a method (this method is called by the
* {@link #analyze analyze} method during its visit of the method's code).
*
* @param frame the frame corresponding to an instruction.
* @param successor the frame corresponding to a successor instruction.
*/
protected void newControlFlowEdge(final Frame frame,
final Frame successor) {
}
// -------------------------------------------------------------------------
private void merge(final int insn,
final Frame frame,
final Subroutine subroutine) throws AnalyzerException {
if ( insn > this.n - 1 ) {
throw new AnalyzerException( "Execution can fall off end of the code" );
}
final Frame oldFrame = this.frames[insn];
final Subroutine oldSubroutine = this.subroutines[insn];
boolean changes = false;
if ( oldFrame == null ) {
this.frames[insn] = newFrame( frame );
changes = true;
} else {
changes |= oldFrame.merge( frame,
this.interpreter );
}
newControlFlowEdge( frame,
oldFrame );
if ( oldSubroutine == null ) {
if ( subroutine != null ) {
this.subroutines[insn] = subroutine.copy();
changes = true;
}
} else {
if ( subroutine != null ) {
changes |= oldSubroutine.merge( subroutine,
!this.jsr );
}
}
if ( changes && !this.queued[insn] ) {
this.queued[insn] = true;
this.queue[this.top++] = insn;
}
}
private void merge(final int insn,
final Frame beforeJSR,
final Frame afterRET,
final Subroutine subroutineBeforeJSR,
final boolean[] access) throws AnalyzerException {
if ( insn > this.n - 1 ) {
throw new AnalyzerException( "Execution can fall off end of the code" );
}
final Frame oldFrame = this.frames[insn];
final Subroutine oldSubroutine = this.subroutines[insn];
boolean changes = false;
afterRET.merge( beforeJSR,
access );
if ( oldFrame == null ) {
this.frames[insn] = newFrame( afterRET );
changes = true;
} else {
changes |= oldFrame.merge( afterRET,
access );
}
newControlFlowEdge( afterRET,
oldFrame );
if ( oldSubroutine == null ) {
if ( subroutineBeforeJSR != null ) {
this.subroutines[insn] = subroutineBeforeJSR.copy();
changes = true;
}
} else {
if ( subroutineBeforeJSR != null ) {
changes |= oldSubroutine.merge( subroutineBeforeJSR,
!this.jsr );
}
}
if ( changes && !this.queued[insn] ) {
this.queued[insn] = true;
this.queue[this.top++] = insn;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -