mirror of
https://github.com/2006-Scape/Parabot.git
synced 2026-07-04 08:39:23 +00:00
Removed useless ASM files (not used by parabot)
This commit is contained in:
@@ -1,550 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.objectweb.asm.tree.analysis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.IincInsnNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
import org.objectweb.asm.tree.LookupSwitchInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.TableSwitchInsnNode;
|
||||
import org.objectweb.asm.tree.TryCatchBlockNode;
|
||||
import org.objectweb.asm.tree.VarInsnNode;
|
||||
|
||||
/**
|
||||
* A semantic bytecode analyzer. <i>This class does not fully check that JSR and
|
||||
* RET instructions are valid.</i>
|
||||
*
|
||||
* @param <V>
|
||||
* type of the Value used for the analysis.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class Analyzer<V extends Value> implements Opcodes {
|
||||
|
||||
private final Interpreter<V> interpreter;
|
||||
|
||||
private int n;
|
||||
|
||||
private InsnList insns;
|
||||
|
||||
private List<TryCatchBlockNode>[] handlers;
|
||||
|
||||
private Frame<V>[] frames;
|
||||
|
||||
private Subroutine[] subroutines;
|
||||
|
||||
private boolean[] queued;
|
||||
|
||||
private int[] queue;
|
||||
|
||||
private int top;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.tree.analysis.Analyzer}.
|
||||
*
|
||||
* @param interpreter
|
||||
* the interpreter to be used to symbolically interpret the
|
||||
* bytecode instructions.
|
||||
*/
|
||||
public Analyzer(final Interpreter<V> interpreter) {
|
||||
this.interpreter = interpreter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes the given method.
|
||||
*
|
||||
* @param owner
|
||||
* the internal name of the class to which the method belongs.
|
||||
* @param m
|
||||
* the method to be analyzed.
|
||||
* @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 and only if the corresponding
|
||||
* instruction cannot be reached (dead code).
|
||||
* @throws AnalyzerException
|
||||
* if a problem occurs during the analysis.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Frame<V>[] analyze(final String owner, final MethodNode m)
|
||||
throws AnalyzerException {
|
||||
if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) {
|
||||
frames = (Frame<V>[]) new Frame<?>[0];
|
||||
return frames;
|
||||
}
|
||||
n = m.instructions.size();
|
||||
insns = m.instructions;
|
||||
handlers = (List<TryCatchBlockNode>[]) new List<?>[n];
|
||||
frames = (Frame<V>[]) new Frame<?>[n];
|
||||
subroutines = new Subroutine[n];
|
||||
queued = new boolean[n];
|
||||
queue = new int[n];
|
||||
top = 0;
|
||||
|
||||
// computes exception handlers for each instruction
|
||||
for (int i = 0; i < m.tryCatchBlocks.size(); ++i) {
|
||||
TryCatchBlockNode tcb = m.tryCatchBlocks.get(i);
|
||||
int begin = insns.indexOf(tcb.start);
|
||||
int end = insns.indexOf(tcb.end);
|
||||
for (int j = begin; j < end; ++j) {
|
||||
List<TryCatchBlockNode> insnHandlers = handlers[j];
|
||||
if (insnHandlers == null) {
|
||||
insnHandlers = new ArrayList<TryCatchBlockNode>();
|
||||
handlers[j] = insnHandlers;
|
||||
}
|
||||
insnHandlers.add(tcb);
|
||||
}
|
||||
}
|
||||
|
||||
// computes the subroutine for each instruction:
|
||||
Subroutine main = new Subroutine(null, m.maxLocals, null);
|
||||
List<AbstractInsnNode> subroutineCalls = new ArrayList<AbstractInsnNode>();
|
||||
Map<LabelNode, Subroutine> subroutineHeads = new HashMap<LabelNode, Subroutine>();
|
||||
findSubroutine(0, main, subroutineCalls);
|
||||
while (!subroutineCalls.isEmpty()) {
|
||||
JumpInsnNode jsr = (JumpInsnNode) subroutineCalls.remove(0);
|
||||
Subroutine sub = subroutineHeads.get(jsr.label);
|
||||
if (sub == null) {
|
||||
sub = new Subroutine(jsr.label, m.maxLocals, jsr);
|
||||
subroutineHeads.put(jsr.label, sub);
|
||||
findSubroutine(insns.indexOf(jsr.label), sub, subroutineCalls);
|
||||
} else {
|
||||
sub.callers.add(jsr);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (subroutines[i] != null && subroutines[i].start == null) {
|
||||
subroutines[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// initializes the data structures for the control flow analysis
|
||||
Frame<V> current = newFrame(m.maxLocals, m.maxStack);
|
||||
Frame<V> handler = newFrame(m.maxLocals, m.maxStack);
|
||||
current.setReturn(interpreter.newValue(Type.getReturnType(m.desc)));
|
||||
Type[] args = Type.getArgumentTypes(m.desc);
|
||||
int local = 0;
|
||||
if ((m.access & ACC_STATIC) == 0) {
|
||||
Type ctype = Type.getObjectType(owner);
|
||||
current.setLocal(local++, interpreter.newValue(ctype));
|
||||
}
|
||||
for (int i = 0; i < args.length; ++i) {
|
||||
current.setLocal(local++, interpreter.newValue(args[i]));
|
||||
if (args[i].getSize() == 2) {
|
||||
current.setLocal(local++, interpreter.newValue(null));
|
||||
}
|
||||
}
|
||||
while (local < m.maxLocals) {
|
||||
current.setLocal(local++, interpreter.newValue(null));
|
||||
}
|
||||
merge(0, current, null);
|
||||
|
||||
init(owner, m);
|
||||
|
||||
// control flow analysis
|
||||
while (top > 0) {
|
||||
int insn = queue[--top];
|
||||
Frame<V> f = frames[insn];
|
||||
Subroutine subroutine = subroutines[insn];
|
||||
queued[insn] = false;
|
||||
|
||||
AbstractInsnNode insnNode = null;
|
||||
try {
|
||||
insnNode = m.instructions.get(insn);
|
||||
int insnOpcode = insnNode.getOpcode();
|
||||
int insnType = insnNode.getType();
|
||||
|
||||
if (insnType == AbstractInsnNode.LABEL
|
||||
|| insnType == AbstractInsnNode.LINE
|
||||
|| insnType == AbstractInsnNode.FRAME) {
|
||||
merge(insn + 1, f, subroutine);
|
||||
newControlFlowEdge(insn, insn + 1);
|
||||
} else {
|
||||
current.init(f).execute(insnNode, interpreter);
|
||||
subroutine = subroutine == null ? null : subroutine.copy();
|
||||
|
||||
if (insnNode instanceof JumpInsnNode) {
|
||||
JumpInsnNode j = (JumpInsnNode) insnNode;
|
||||
if (insnOpcode != GOTO && insnOpcode != JSR) {
|
||||
merge(insn + 1, current, subroutine);
|
||||
newControlFlowEdge(insn, insn + 1);
|
||||
}
|
||||
int jump = insns.indexOf(j.label);
|
||||
if (insnOpcode == JSR) {
|
||||
merge(jump, current, new Subroutine(j.label,
|
||||
m.maxLocals, j));
|
||||
} else {
|
||||
merge(jump, current, subroutine);
|
||||
}
|
||||
newControlFlowEdge(insn, jump);
|
||||
} else if (insnNode instanceof LookupSwitchInsnNode) {
|
||||
LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode;
|
||||
int jump = insns.indexOf(lsi.dflt);
|
||||
merge(jump, current, subroutine);
|
||||
newControlFlowEdge(insn, jump);
|
||||
for (int j = 0; j < lsi.labels.size(); ++j) {
|
||||
LabelNode label = lsi.labels.get(j);
|
||||
jump = insns.indexOf(label);
|
||||
merge(jump, current, subroutine);
|
||||
newControlFlowEdge(insn, jump);
|
||||
}
|
||||
} else if (insnNode instanceof TableSwitchInsnNode) {
|
||||
TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode;
|
||||
int jump = insns.indexOf(tsi.dflt);
|
||||
merge(jump, current, subroutine);
|
||||
newControlFlowEdge(insn, jump);
|
||||
for (int j = 0; j < tsi.labels.size(); ++j) {
|
||||
LabelNode label = tsi.labels.get(j);
|
||||
jump = insns.indexOf(label);
|
||||
merge(jump, current, subroutine);
|
||||
newControlFlowEdge(insn, jump);
|
||||
}
|
||||
} else if (insnOpcode == RET) {
|
||||
if (subroutine == null) {
|
||||
throw new AnalyzerException(insnNode,
|
||||
"RET instruction outside of a sub routine");
|
||||
}
|
||||
for (int i = 0; i < subroutine.callers.size(); ++i) {
|
||||
JumpInsnNode caller = subroutine.callers.get(i);
|
||||
int call = insns.indexOf(caller);
|
||||
if (frames[call] != null) {
|
||||
merge(call + 1, frames[call], current,
|
||||
subroutines[call], subroutine.access);
|
||||
newControlFlowEdge(insn, call + 1);
|
||||
}
|
||||
}
|
||||
} else if (insnOpcode != ATHROW
|
||||
&& (insnOpcode < IRETURN || insnOpcode > RETURN)) {
|
||||
if (subroutine != null) {
|
||||
if (insnNode instanceof VarInsnNode) {
|
||||
int var = ((VarInsnNode) insnNode).var;
|
||||
subroutine.access[var] = true;
|
||||
if (insnOpcode == LLOAD || insnOpcode == DLOAD
|
||||
|| insnOpcode == LSTORE
|
||||
|| insnOpcode == DSTORE) {
|
||||
subroutine.access[var + 1] = true;
|
||||
}
|
||||
} else if (insnNode instanceof IincInsnNode) {
|
||||
int var = ((IincInsnNode) insnNode).var;
|
||||
subroutine.access[var] = true;
|
||||
}
|
||||
}
|
||||
merge(insn + 1, current, subroutine);
|
||||
newControlFlowEdge(insn, insn + 1);
|
||||
}
|
||||
}
|
||||
|
||||
List<TryCatchBlockNode> insnHandlers = handlers[insn];
|
||||
if (insnHandlers != null) {
|
||||
for (int i = 0; i < insnHandlers.size(); ++i) {
|
||||
TryCatchBlockNode tcb = insnHandlers.get(i);
|
||||
Type type;
|
||||
if (tcb.type == null) {
|
||||
type = Type.getObjectType("java/lang/Throwable");
|
||||
} else {
|
||||
type = Type.getObjectType(tcb.type);
|
||||
}
|
||||
int jump = insns.indexOf(tcb.handler);
|
||||
if (newControlFlowExceptionEdge(insn, tcb)) {
|
||||
handler.init(f);
|
||||
handler.clearStack();
|
||||
handler.push(interpreter.newValue(type));
|
||||
merge(jump, handler, subroutine);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (AnalyzerException e) {
|
||||
throw new AnalyzerException(e.node, "Error at instruction "
|
||||
+ insn + ": " + e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
throw new AnalyzerException(insnNode, "Error at instruction "
|
||||
+ insn + ": " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
private void findSubroutine(int insn, final Subroutine sub,
|
||||
final List<AbstractInsnNode> calls) throws AnalyzerException {
|
||||
while (true) {
|
||||
if (insn < 0 || insn >= n) {
|
||||
throw new AnalyzerException(null,
|
||||
"Execution can fall off end of the code");
|
||||
}
|
||||
if (subroutines[insn] != null) {
|
||||
return;
|
||||
}
|
||||
subroutines[insn] = sub.copy();
|
||||
AbstractInsnNode node = insns.get(insn);
|
||||
|
||||
// calls findSubroutine recursively on normal successors
|
||||
if (node instanceof JumpInsnNode) {
|
||||
if (node.getOpcode() == JSR) {
|
||||
// do not follow a JSR, it leads to another subroutine!
|
||||
calls.add(node);
|
||||
} else {
|
||||
JumpInsnNode jnode = (JumpInsnNode) node;
|
||||
findSubroutine(insns.indexOf(jnode.label), sub, calls);
|
||||
}
|
||||
} else if (node instanceof TableSwitchInsnNode) {
|
||||
TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
|
||||
findSubroutine(insns.indexOf(tsnode.dflt), sub, calls);
|
||||
for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
|
||||
LabelNode l = tsnode.labels.get(i);
|
||||
findSubroutine(insns.indexOf(l), sub, calls);
|
||||
}
|
||||
} else if (node instanceof LookupSwitchInsnNode) {
|
||||
LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
|
||||
findSubroutine(insns.indexOf(lsnode.dflt), sub, calls);
|
||||
for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
|
||||
LabelNode l = lsnode.labels.get(i);
|
||||
findSubroutine(insns.indexOf(l), sub, calls);
|
||||
}
|
||||
}
|
||||
|
||||
// calls findSubroutine recursively on exception handler successors
|
||||
List<TryCatchBlockNode> insnHandlers = handlers[insn];
|
||||
if (insnHandlers != null) {
|
||||
for (int i = 0; i < insnHandlers.size(); ++i) {
|
||||
TryCatchBlockNode tcb = insnHandlers.get(i);
|
||||
findSubroutine(insns.indexOf(tcb.handler), sub, calls);
|
||||
}
|
||||
}
|
||||
|
||||
// if insn does not falls through to the next instruction, return.
|
||||
switch (node.getOpcode()) {
|
||||
case GOTO:
|
||||
case RET:
|
||||
case TABLESWITCH:
|
||||
case LOOKUPSWITCH:
|
||||
case IRETURN:
|
||||
case LRETURN:
|
||||
case FRETURN:
|
||||
case DRETURN:
|
||||
case ARETURN:
|
||||
case RETURN:
|
||||
case ATHROW:
|
||||
return;
|
||||
}
|
||||
insn++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<V>[] getFrames() {
|
||||
return frames;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<TryCatchBlockNode> getHandlers(final int insn) {
|
||||
return handlers[insn];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this analyzer. This method is called just before the
|
||||
* execution of control flow analysis loop in #analyze. The default
|
||||
* implementation of this method does nothing.
|
||||
*
|
||||
* @param owner
|
||||
* the internal name of the class to which the method belongs.
|
||||
* @param m
|
||||
* the method to be analyzed.
|
||||
* @throws AnalyzerException
|
||||
* if a problem occurs.
|
||||
*/
|
||||
protected void init(String owner, MethodNode m) throws AnalyzerException {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<V> newFrame(final int nLocals, final int nStack) {
|
||||
return new Frame<V>(nLocals, nStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new frame that is identical to the given frame.
|
||||
*
|
||||
* @param src
|
||||
* a frame.
|
||||
* @return the created frame.
|
||||
*/
|
||||
protected Frame<V> newFrame(final Frame<? extends V> src) {
|
||||
return new Frame<V>(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 insn
|
||||
* an instruction index.
|
||||
* @param successor
|
||||
* index of a successor instruction.
|
||||
*/
|
||||
protected void newControlFlowEdge(final int insn, final int successor) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a control flow graph edge corresponding to an exception handler.
|
||||
* The default implementation of this method does nothing. It can be
|
||||
* overridden 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 insn
|
||||
* an instruction index.
|
||||
* @param successor
|
||||
* index of a successor instruction.
|
||||
* @return true if this edge must be considered in the data flow analysis
|
||||
* performed by this analyzer, or false otherwise. The default
|
||||
* implementation of this method always returns true.
|
||||
*/
|
||||
protected boolean newControlFlowExceptionEdge(final int insn,
|
||||
final int successor) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a control flow graph edge corresponding to an exception handler.
|
||||
* The default implementation of this method delegates to
|
||||
* {@link #newControlFlowExceptionEdge(int, int)
|
||||
* newControlFlowExceptionEdge(int, int)}. It can be overridden 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 insn
|
||||
* an instruction index.
|
||||
* @param tcb
|
||||
* TryCatchBlockNode corresponding to this edge.
|
||||
* @return true if this edge must be considered in the data flow analysis
|
||||
* performed by this analyzer, or false otherwise. The default
|
||||
* implementation of this method delegates to
|
||||
* {@link #newControlFlowExceptionEdge(int, int)
|
||||
* newControlFlowExceptionEdge(int, int)}.
|
||||
*/
|
||||
protected boolean newControlFlowExceptionEdge(final int insn,
|
||||
final TryCatchBlockNode tcb) {
|
||||
return newControlFlowExceptionEdge(insn, insns.indexOf(tcb.handler));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private void merge(final int insn, final Frame<V> frame,
|
||||
final Subroutine subroutine) throws AnalyzerException {
|
||||
Frame<V> oldFrame = frames[insn];
|
||||
Subroutine oldSubroutine = subroutines[insn];
|
||||
boolean changes;
|
||||
|
||||
if (oldFrame == null) {
|
||||
frames[insn] = newFrame(frame);
|
||||
changes = true;
|
||||
} else {
|
||||
changes = oldFrame.merge(frame, interpreter);
|
||||
}
|
||||
|
||||
if (oldSubroutine == null) {
|
||||
if (subroutine != null) {
|
||||
subroutines[insn] = subroutine.copy();
|
||||
changes = true;
|
||||
}
|
||||
} else {
|
||||
if (subroutine != null) {
|
||||
changes |= oldSubroutine.merge(subroutine);
|
||||
}
|
||||
}
|
||||
if (changes && !queued[insn]) {
|
||||
queued[insn] = true;
|
||||
queue[top++] = insn;
|
||||
}
|
||||
}
|
||||
|
||||
private void merge(final int insn, final Frame<V> beforeJSR,
|
||||
final Frame<V> afterRET, final Subroutine subroutineBeforeJSR,
|
||||
final boolean[] access) throws AnalyzerException {
|
||||
Frame<V> oldFrame = frames[insn];
|
||||
Subroutine oldSubroutine = subroutines[insn];
|
||||
boolean changes;
|
||||
|
||||
afterRET.merge(beforeJSR, access);
|
||||
|
||||
if (oldFrame == null) {
|
||||
frames[insn] = newFrame(afterRET);
|
||||
changes = true;
|
||||
} else {
|
||||
changes = oldFrame.merge(afterRET, interpreter);
|
||||
}
|
||||
|
||||
if (oldSubroutine != null && subroutineBeforeJSR != null) {
|
||||
changes |= oldSubroutine.merge(subroutineBeforeJSR);
|
||||
}
|
||||
if (changes && !queued[insn]) {
|
||||
queued[insn] = true;
|
||||
queue[top++] = insn;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.objectweb.asm.tree.analysis;
|
||||
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
|
||||
/**
|
||||
* Thrown if a problem occurs during the analysis of a method.
|
||||
*
|
||||
* @author Bing Ran
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class AnalyzerException extends Exception {
|
||||
private static final long serialVersionUID = -1788355977291059681L;
|
||||
public final AbstractInsnNode node;
|
||||
|
||||
public AnalyzerException(final AbstractInsnNode node, final String msg) {
|
||||
super(msg);
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public AnalyzerException(final AbstractInsnNode node, final String msg,
|
||||
final Throwable exception) {
|
||||
super(msg, exception);
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public AnalyzerException(final AbstractInsnNode node, final String msg,
|
||||
final Object expected, final Value encountered) {
|
||||
super((msg == null ? "Expected " : msg + ": expected ") + expected
|
||||
+ ", but found " + encountered);
|
||||
this.node = node;
|
||||
}
|
||||
}
|
||||
@@ -1,358 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.objectweb.asm.tree.analysis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.IntInsnNode;
|
||||
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MultiANewArrayInsnNode;
|
||||
import org.objectweb.asm.tree.TypeInsnNode;
|
||||
|
||||
/**
|
||||
* An {@link Interpreter} for {@link BasicValue} values.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
* @author Bing Ran
|
||||
*/
|
||||
public class BasicInterpreter extends Interpreter<BasicValue> implements
|
||||
Opcodes {
|
||||
|
||||
public BasicInterpreter() {
|
||||
super(ASM4);
|
||||
}
|
||||
|
||||
protected BasicInterpreter(final int api) {
|
||||
super(api);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue newValue(final Type type) {
|
||||
if (type == null) {
|
||||
return BasicValue.UNINITIALIZED_VALUE;
|
||||
}
|
||||
switch (type.getSort()) {
|
||||
case Type.VOID:
|
||||
return null;
|
||||
case Type.BOOLEAN:
|
||||
case Type.CHAR:
|
||||
case Type.BYTE:
|
||||
case Type.SHORT:
|
||||
case Type.INT:
|
||||
return BasicValue.INT_VALUE;
|
||||
case Type.FLOAT:
|
||||
return BasicValue.FLOAT_VALUE;
|
||||
case Type.LONG:
|
||||
return BasicValue.LONG_VALUE;
|
||||
case Type.DOUBLE:
|
||||
return BasicValue.DOUBLE_VALUE;
|
||||
case Type.ARRAY:
|
||||
case Type.OBJECT:
|
||||
return BasicValue.REFERENCE_VALUE;
|
||||
default:
|
||||
throw new Error("Internal error");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue newOperation(final AbstractInsnNode insn)
|
||||
throws AnalyzerException {
|
||||
switch (insn.getOpcode()) {
|
||||
case ACONST_NULL:
|
||||
return newValue(Type.getObjectType("null"));
|
||||
case ICONST_M1:
|
||||
case ICONST_0:
|
||||
case ICONST_1:
|
||||
case ICONST_2:
|
||||
case ICONST_3:
|
||||
case ICONST_4:
|
||||
case ICONST_5:
|
||||
return BasicValue.INT_VALUE;
|
||||
case LCONST_0:
|
||||
case LCONST_1:
|
||||
return BasicValue.LONG_VALUE;
|
||||
case FCONST_0:
|
||||
case FCONST_1:
|
||||
case FCONST_2:
|
||||
return BasicValue.FLOAT_VALUE;
|
||||
case DCONST_0:
|
||||
case DCONST_1:
|
||||
return BasicValue.DOUBLE_VALUE;
|
||||
case BIPUSH:
|
||||
case SIPUSH:
|
||||
return BasicValue.INT_VALUE;
|
||||
case LDC:
|
||||
Object cst = ((LdcInsnNode) insn).cst;
|
||||
if (cst instanceof Integer) {
|
||||
return BasicValue.INT_VALUE;
|
||||
} else if (cst instanceof Float) {
|
||||
return BasicValue.FLOAT_VALUE;
|
||||
} else if (cst instanceof Long) {
|
||||
return BasicValue.LONG_VALUE;
|
||||
} else if (cst instanceof Double) {
|
||||
return BasicValue.DOUBLE_VALUE;
|
||||
} else if (cst instanceof String) {
|
||||
return newValue(Type.getObjectType("java/lang/String"));
|
||||
} else if (cst instanceof Type) {
|
||||
int sort = ((Type) cst).getSort();
|
||||
if (sort == Type.OBJECT || sort == Type.ARRAY) {
|
||||
return newValue(Type.getObjectType("java/lang/Class"));
|
||||
} else if (sort == Type.METHOD) {
|
||||
return newValue(Type
|
||||
.getObjectType("java/lang/invoke/MethodType"));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Illegal LDC constant "
|
||||
+ cst);
|
||||
}
|
||||
} else if (cst instanceof Handle) {
|
||||
return newValue(Type
|
||||
.getObjectType("java/lang/invoke/MethodHandle"));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Illegal LDC constant "
|
||||
+ cst);
|
||||
}
|
||||
case JSR:
|
||||
return BasicValue.RETURNADDRESS_VALUE;
|
||||
case GETSTATIC:
|
||||
return newValue(Type.getType(((FieldInsnNode) insn).desc));
|
||||
case NEW:
|
||||
return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
|
||||
default:
|
||||
throw new Error("Internal error.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue copyOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value) throws AnalyzerException {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue unaryOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value) throws AnalyzerException {
|
||||
switch (insn.getOpcode()) {
|
||||
case INEG:
|
||||
case IINC:
|
||||
case L2I:
|
||||
case F2I:
|
||||
case D2I:
|
||||
case I2B:
|
||||
case I2C:
|
||||
case I2S:
|
||||
return BasicValue.INT_VALUE;
|
||||
case FNEG:
|
||||
case I2F:
|
||||
case L2F:
|
||||
case D2F:
|
||||
return BasicValue.FLOAT_VALUE;
|
||||
case LNEG:
|
||||
case I2L:
|
||||
case F2L:
|
||||
case D2L:
|
||||
return BasicValue.LONG_VALUE;
|
||||
case DNEG:
|
||||
case I2D:
|
||||
case L2D:
|
||||
case F2D:
|
||||
return BasicValue.DOUBLE_VALUE;
|
||||
case IFEQ:
|
||||
case IFNE:
|
||||
case IFLT:
|
||||
case IFGE:
|
||||
case IFGT:
|
||||
case IFLE:
|
||||
case TABLESWITCH:
|
||||
case LOOKUPSWITCH:
|
||||
case IRETURN:
|
||||
case LRETURN:
|
||||
case FRETURN:
|
||||
case DRETURN:
|
||||
case ARETURN:
|
||||
case PUTSTATIC:
|
||||
return null;
|
||||
case GETFIELD:
|
||||
return newValue(Type.getType(((FieldInsnNode) insn).desc));
|
||||
case NEWARRAY:
|
||||
switch (((IntInsnNode) insn).operand) {
|
||||
case T_BOOLEAN:
|
||||
return newValue(Type.getType("[Z"));
|
||||
case T_CHAR:
|
||||
return newValue(Type.getType("[C"));
|
||||
case T_BYTE:
|
||||
return newValue(Type.getType("[B"));
|
||||
case T_SHORT:
|
||||
return newValue(Type.getType("[S"));
|
||||
case T_INT:
|
||||
return newValue(Type.getType("[I"));
|
||||
case T_FLOAT:
|
||||
return newValue(Type.getType("[F"));
|
||||
case T_DOUBLE:
|
||||
return newValue(Type.getType("[D"));
|
||||
case T_LONG:
|
||||
return newValue(Type.getType("[J"));
|
||||
default:
|
||||
throw new AnalyzerException(insn, "Invalid array type");
|
||||
}
|
||||
case ANEWARRAY:
|
||||
String desc = ((TypeInsnNode) insn).desc;
|
||||
return newValue(Type.getType("[" + Type.getObjectType(desc)));
|
||||
case ARRAYLENGTH:
|
||||
return BasicValue.INT_VALUE;
|
||||
case ATHROW:
|
||||
return null;
|
||||
case CHECKCAST:
|
||||
desc = ((TypeInsnNode) insn).desc;
|
||||
return newValue(Type.getObjectType(desc));
|
||||
case INSTANCEOF:
|
||||
return BasicValue.INT_VALUE;
|
||||
case MONITORENTER:
|
||||
case MONITOREXIT:
|
||||
case IFNULL:
|
||||
case IFNONNULL:
|
||||
return null;
|
||||
default:
|
||||
throw new Error("Internal error.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue binaryOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value1, final BasicValue value2)
|
||||
throws AnalyzerException {
|
||||
switch (insn.getOpcode()) {
|
||||
case IALOAD:
|
||||
case BALOAD:
|
||||
case CALOAD:
|
||||
case SALOAD:
|
||||
case IADD:
|
||||
case ISUB:
|
||||
case IMUL:
|
||||
case IDIV:
|
||||
case IREM:
|
||||
case ISHL:
|
||||
case ISHR:
|
||||
case IUSHR:
|
||||
case IAND:
|
||||
case IOR:
|
||||
case IXOR:
|
||||
return BasicValue.INT_VALUE;
|
||||
case FALOAD:
|
||||
case FADD:
|
||||
case FSUB:
|
||||
case FMUL:
|
||||
case FDIV:
|
||||
case FREM:
|
||||
return BasicValue.FLOAT_VALUE;
|
||||
case LALOAD:
|
||||
case LADD:
|
||||
case LSUB:
|
||||
case LMUL:
|
||||
case LDIV:
|
||||
case LREM:
|
||||
case LSHL:
|
||||
case LSHR:
|
||||
case LUSHR:
|
||||
case LAND:
|
||||
case LOR:
|
||||
case LXOR:
|
||||
return BasicValue.LONG_VALUE;
|
||||
case DALOAD:
|
||||
case DADD:
|
||||
case DSUB:
|
||||
case DMUL:
|
||||
case DDIV:
|
||||
case DREM:
|
||||
return BasicValue.DOUBLE_VALUE;
|
||||
case AALOAD:
|
||||
return BasicValue.REFERENCE_VALUE;
|
||||
case LCMP:
|
||||
case FCMPL:
|
||||
case FCMPG:
|
||||
case DCMPL:
|
||||
case DCMPG:
|
||||
return BasicValue.INT_VALUE;
|
||||
case IF_ICMPEQ:
|
||||
case IF_ICMPNE:
|
||||
case IF_ICMPLT:
|
||||
case IF_ICMPGE:
|
||||
case IF_ICMPGT:
|
||||
case IF_ICMPLE:
|
||||
case IF_ACMPEQ:
|
||||
case IF_ACMPNE:
|
||||
case PUTFIELD:
|
||||
return null;
|
||||
default:
|
||||
throw new Error("Internal error.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue ternaryOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value1, final BasicValue value2,
|
||||
final BasicValue value3) throws AnalyzerException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue naryOperation(final AbstractInsnNode insn,
|
||||
final List<? extends BasicValue> values) throws AnalyzerException {
|
||||
int opcode = insn.getOpcode();
|
||||
if (opcode == MULTIANEWARRAY) {
|
||||
return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc));
|
||||
} else if (opcode == INVOKEDYNAMIC) {
|
||||
return newValue(Type
|
||||
.getReturnType(((InvokeDynamicInsnNode) insn).desc));
|
||||
} else {
|
||||
return newValue(Type.getReturnType(((MethodInsnNode) insn).desc));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value, final BasicValue expected)
|
||||
throws AnalyzerException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue merge(final BasicValue v, final BasicValue w) {
|
||||
if (!v.equals(w)) {
|
||||
return BasicValue.UNINITIALIZED_VALUE;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.objectweb.asm.tree.analysis;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* A {@link Value} that is represented by its type in a seven types type system.
|
||||
* This type system distinguishes the UNINITIALZED, INT, FLOAT, LONG, DOUBLE,
|
||||
* REFERENCE and RETURNADDRESS types.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class BasicValue implements Value {
|
||||
|
||||
public static final BasicValue UNINITIALIZED_VALUE = new BasicValue(null);
|
||||
|
||||
public static final BasicValue INT_VALUE = new BasicValue(Type.INT_TYPE);
|
||||
|
||||
public static final BasicValue FLOAT_VALUE = new BasicValue(Type.FLOAT_TYPE);
|
||||
|
||||
public static final BasicValue LONG_VALUE = new BasicValue(Type.LONG_TYPE);
|
||||
|
||||
public static final BasicValue DOUBLE_VALUE = new BasicValue(
|
||||
Type.DOUBLE_TYPE);
|
||||
|
||||
public static final BasicValue REFERENCE_VALUE = new BasicValue(
|
||||
Type.getObjectType("java/lang/Object"));
|
||||
|
||||
public static final BasicValue RETURNADDRESS_VALUE = new BasicValue(
|
||||
Type.VOID_TYPE);
|
||||
|
||||
private final Type type;
|
||||
|
||||
public BasicValue(final Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return type == Type.LONG_TYPE || type == Type.DOUBLE_TYPE ? 2 : 1;
|
||||
}
|
||||
|
||||
public boolean isReference() {
|
||||
return type != null
|
||||
&& (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object value) {
|
||||
if (value == this) {
|
||||
return true;
|
||||
} else if (value instanceof BasicValue) {
|
||||
if (type == null) {
|
||||
return ((BasicValue) value).type == null;
|
||||
} else {
|
||||
return type.equals(((BasicValue) value).type);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return type == null ? 0 : type.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (this == UNINITIALIZED_VALUE) {
|
||||
return ".";
|
||||
} else if (this == RETURNADDRESS_VALUE) {
|
||||
return "A";
|
||||
} else if (this == REFERENCE_VALUE) {
|
||||
return "R";
|
||||
} else {
|
||||
return type.getDescriptor();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,433 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.objectweb.asm.tree.analysis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
|
||||
/**
|
||||
* An extended {@link org.objectweb.asm.tree.analysis.BasicInterpreter} that checks that bytecode instructions
|
||||
* are correctly used.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
* @author Bing Ran
|
||||
*/
|
||||
public class BasicVerifier extends BasicInterpreter {
|
||||
|
||||
public BasicVerifier() {
|
||||
super(ASM4);
|
||||
}
|
||||
|
||||
protected BasicVerifier(final int api) {
|
||||
super(api);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue copyOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value) throws AnalyzerException {
|
||||
Value expected;
|
||||
switch (insn.getOpcode()) {
|
||||
case ILOAD:
|
||||
case ISTORE:
|
||||
expected = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case FLOAD:
|
||||
case FSTORE:
|
||||
expected = BasicValue.FLOAT_VALUE;
|
||||
break;
|
||||
case LLOAD:
|
||||
case LSTORE:
|
||||
expected = BasicValue.LONG_VALUE;
|
||||
break;
|
||||
case DLOAD:
|
||||
case DSTORE:
|
||||
expected = BasicValue.DOUBLE_VALUE;
|
||||
break;
|
||||
case ALOAD:
|
||||
if (!value.isReference()) {
|
||||
throw new AnalyzerException(insn, null, "an object reference",
|
||||
value);
|
||||
}
|
||||
return value;
|
||||
case ASTORE:
|
||||
if (!value.isReference()
|
||||
&& !BasicValue.RETURNADDRESS_VALUE.equals(value)) {
|
||||
throw new AnalyzerException(insn, null,
|
||||
"an object reference or a return address", value);
|
||||
}
|
||||
return value;
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
if (!expected.equals(value)) {
|
||||
throw new AnalyzerException(insn, null, expected, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue unaryOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value) throws AnalyzerException {
|
||||
BasicValue expected;
|
||||
switch (insn.getOpcode()) {
|
||||
case INEG:
|
||||
case IINC:
|
||||
case I2F:
|
||||
case I2L:
|
||||
case I2D:
|
||||
case I2B:
|
||||
case I2C:
|
||||
case I2S:
|
||||
case IFEQ:
|
||||
case IFNE:
|
||||
case IFLT:
|
||||
case IFGE:
|
||||
case IFGT:
|
||||
case IFLE:
|
||||
case TABLESWITCH:
|
||||
case LOOKUPSWITCH:
|
||||
case IRETURN:
|
||||
case NEWARRAY:
|
||||
case ANEWARRAY:
|
||||
expected = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case FNEG:
|
||||
case F2I:
|
||||
case F2L:
|
||||
case F2D:
|
||||
case FRETURN:
|
||||
expected = BasicValue.FLOAT_VALUE;
|
||||
break;
|
||||
case LNEG:
|
||||
case L2I:
|
||||
case L2F:
|
||||
case L2D:
|
||||
case LRETURN:
|
||||
expected = BasicValue.LONG_VALUE;
|
||||
break;
|
||||
case DNEG:
|
||||
case D2I:
|
||||
case D2F:
|
||||
case D2L:
|
||||
case DRETURN:
|
||||
expected = BasicValue.DOUBLE_VALUE;
|
||||
break;
|
||||
case GETFIELD:
|
||||
expected = newValue(Type
|
||||
.getObjectType(((FieldInsnNode) insn).owner));
|
||||
break;
|
||||
case CHECKCAST:
|
||||
if (!value.isReference()) {
|
||||
throw new AnalyzerException(insn, null, "an object reference",
|
||||
value);
|
||||
}
|
||||
return super.unaryOperation(insn, value);
|
||||
case ARRAYLENGTH:
|
||||
if (!isArrayValue(value)) {
|
||||
throw new AnalyzerException(insn, null, "an array reference",
|
||||
value);
|
||||
}
|
||||
return super.unaryOperation(insn, value);
|
||||
case ARETURN:
|
||||
case ATHROW:
|
||||
case INSTANCEOF:
|
||||
case MONITORENTER:
|
||||
case MONITOREXIT:
|
||||
case IFNULL:
|
||||
case IFNONNULL:
|
||||
if (!value.isReference()) {
|
||||
throw new AnalyzerException(insn, null, "an object reference",
|
||||
value);
|
||||
}
|
||||
return super.unaryOperation(insn, value);
|
||||
case PUTSTATIC:
|
||||
expected = newValue(Type.getType(((FieldInsnNode) insn).desc));
|
||||
break;
|
||||
default:
|
||||
throw new Error("Internal error.");
|
||||
}
|
||||
if (!isSubTypeOf(value, expected)) {
|
||||
throw new AnalyzerException(insn, null, expected, value);
|
||||
}
|
||||
return super.unaryOperation(insn, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue binaryOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value1, final BasicValue value2)
|
||||
throws AnalyzerException {
|
||||
BasicValue expected1;
|
||||
BasicValue expected2;
|
||||
switch (insn.getOpcode()) {
|
||||
case IALOAD:
|
||||
expected1 = newValue(Type.getType("[I"));
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case BALOAD:
|
||||
if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
|
||||
expected1 = newValue(Type.getType("[Z"));
|
||||
} else {
|
||||
expected1 = newValue(Type.getType("[B"));
|
||||
}
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case CALOAD:
|
||||
expected1 = newValue(Type.getType("[C"));
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case SALOAD:
|
||||
expected1 = newValue(Type.getType("[S"));
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case LALOAD:
|
||||
expected1 = newValue(Type.getType("[J"));
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case FALOAD:
|
||||
expected1 = newValue(Type.getType("[F"));
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case DALOAD:
|
||||
expected1 = newValue(Type.getType("[D"));
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case AALOAD:
|
||||
expected1 = newValue(Type.getType("[Ljava/lang/Object;"));
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case IADD:
|
||||
case ISUB:
|
||||
case IMUL:
|
||||
case IDIV:
|
||||
case IREM:
|
||||
case ISHL:
|
||||
case ISHR:
|
||||
case IUSHR:
|
||||
case IAND:
|
||||
case IOR:
|
||||
case IXOR:
|
||||
case IF_ICMPEQ:
|
||||
case IF_ICMPNE:
|
||||
case IF_ICMPLT:
|
||||
case IF_ICMPGE:
|
||||
case IF_ICMPGT:
|
||||
case IF_ICMPLE:
|
||||
expected1 = BasicValue.INT_VALUE;
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case FADD:
|
||||
case FSUB:
|
||||
case FMUL:
|
||||
case FDIV:
|
||||
case FREM:
|
||||
case FCMPL:
|
||||
case FCMPG:
|
||||
expected1 = BasicValue.FLOAT_VALUE;
|
||||
expected2 = BasicValue.FLOAT_VALUE;
|
||||
break;
|
||||
case LADD:
|
||||
case LSUB:
|
||||
case LMUL:
|
||||
case LDIV:
|
||||
case LREM:
|
||||
case LAND:
|
||||
case LOR:
|
||||
case LXOR:
|
||||
case LCMP:
|
||||
expected1 = BasicValue.LONG_VALUE;
|
||||
expected2 = BasicValue.LONG_VALUE;
|
||||
break;
|
||||
case LSHL:
|
||||
case LSHR:
|
||||
case LUSHR:
|
||||
expected1 = BasicValue.LONG_VALUE;
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case DADD:
|
||||
case DSUB:
|
||||
case DMUL:
|
||||
case DDIV:
|
||||
case DREM:
|
||||
case DCMPL:
|
||||
case DCMPG:
|
||||
expected1 = BasicValue.DOUBLE_VALUE;
|
||||
expected2 = BasicValue.DOUBLE_VALUE;
|
||||
break;
|
||||
case IF_ACMPEQ:
|
||||
case IF_ACMPNE:
|
||||
expected1 = BasicValue.REFERENCE_VALUE;
|
||||
expected2 = BasicValue.REFERENCE_VALUE;
|
||||
break;
|
||||
case PUTFIELD:
|
||||
FieldInsnNode fin = (FieldInsnNode) insn;
|
||||
expected1 = newValue(Type.getObjectType(fin.owner));
|
||||
expected2 = newValue(Type.getType(fin.desc));
|
||||
break;
|
||||
default:
|
||||
throw new Error("Internal error.");
|
||||
}
|
||||
if (!isSubTypeOf(value1, expected1)) {
|
||||
throw new AnalyzerException(insn, "First argument", expected1,
|
||||
value1);
|
||||
} else if (!isSubTypeOf(value2, expected2)) {
|
||||
throw new AnalyzerException(insn, "Second argument", expected2,
|
||||
value2);
|
||||
}
|
||||
if (insn.getOpcode() == AALOAD) {
|
||||
return getElementValue(value1);
|
||||
} else {
|
||||
return super.binaryOperation(insn, value1, value2);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue ternaryOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value1, final BasicValue value2,
|
||||
final BasicValue value3) throws AnalyzerException {
|
||||
BasicValue expected1;
|
||||
BasicValue expected3;
|
||||
switch (insn.getOpcode()) {
|
||||
case IASTORE:
|
||||
expected1 = newValue(Type.getType("[I"));
|
||||
expected3 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case BASTORE:
|
||||
if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
|
||||
expected1 = newValue(Type.getType("[Z"));
|
||||
} else {
|
||||
expected1 = newValue(Type.getType("[B"));
|
||||
}
|
||||
expected3 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case CASTORE:
|
||||
expected1 = newValue(Type.getType("[C"));
|
||||
expected3 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case SASTORE:
|
||||
expected1 = newValue(Type.getType("[S"));
|
||||
expected3 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case LASTORE:
|
||||
expected1 = newValue(Type.getType("[J"));
|
||||
expected3 = BasicValue.LONG_VALUE;
|
||||
break;
|
||||
case FASTORE:
|
||||
expected1 = newValue(Type.getType("[F"));
|
||||
expected3 = BasicValue.FLOAT_VALUE;
|
||||
break;
|
||||
case DASTORE:
|
||||
expected1 = newValue(Type.getType("[D"));
|
||||
expected3 = BasicValue.DOUBLE_VALUE;
|
||||
break;
|
||||
case AASTORE:
|
||||
expected1 = value1;
|
||||
expected3 = BasicValue.REFERENCE_VALUE;
|
||||
break;
|
||||
default:
|
||||
throw new Error("Internal error.");
|
||||
}
|
||||
if (!isSubTypeOf(value1, expected1)) {
|
||||
throw new AnalyzerException(insn, "First argument", "a "
|
||||
+ expected1 + " array reference", value1);
|
||||
} else if (!BasicValue.INT_VALUE.equals(value2)) {
|
||||
throw new AnalyzerException(insn, "Second argument",
|
||||
BasicValue.INT_VALUE, value2);
|
||||
} else if (!isSubTypeOf(value3, expected3)) {
|
||||
throw new AnalyzerException(insn, "Third argument", expected3,
|
||||
value3);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue naryOperation(final AbstractInsnNode insn,
|
||||
final List<? extends BasicValue> values) throws AnalyzerException {
|
||||
int opcode = insn.getOpcode();
|
||||
if (opcode == MULTIANEWARRAY) {
|
||||
for (int i = 0; i < values.size(); ++i) {
|
||||
if (!BasicValue.INT_VALUE.equals(values.get(i))) {
|
||||
throw new AnalyzerException(insn, null,
|
||||
BasicValue.INT_VALUE, values.get(i));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) {
|
||||
Type owner = Type.getObjectType(((MethodInsnNode) insn).owner);
|
||||
if (!isSubTypeOf(values.get(i++), newValue(owner))) {
|
||||
throw new AnalyzerException(insn, "Method owner",
|
||||
newValue(owner), values.get(0));
|
||||
}
|
||||
}
|
||||
String desc = (opcode == INVOKEDYNAMIC) ? ((InvokeDynamicInsnNode) insn).desc
|
||||
: ((MethodInsnNode) insn).desc;
|
||||
Type[] args = Type.getArgumentTypes(desc);
|
||||
while (i < values.size()) {
|
||||
BasicValue expected = newValue(args[j++]);
|
||||
BasicValue encountered = values.get(i++);
|
||||
if (!isSubTypeOf(encountered, expected)) {
|
||||
throw new AnalyzerException(insn, "Argument " + j,
|
||||
expected, encountered);
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.naryOperation(insn, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value, final BasicValue expected)
|
||||
throws AnalyzerException {
|
||||
if (!isSubTypeOf(value, expected)) {
|
||||
throw new AnalyzerException(insn, "Incompatible return type",
|
||||
expected, value);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isArrayValue(final BasicValue value) {
|
||||
return value.isReference();
|
||||
}
|
||||
|
||||
protected BasicValue getElementValue(final BasicValue objectArrayValue)
|
||||
throws AnalyzerException {
|
||||
return BasicValue.REFERENCE_VALUE;
|
||||
}
|
||||
|
||||
protected boolean isSubTypeOf(final BasicValue value,
|
||||
final BasicValue expected) {
|
||||
return value.equals(expected);
|
||||
}
|
||||
}
|
||||
@@ -1,730 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.objectweb.asm.tree.analysis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.IincInsnNode;
|
||||
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MultiANewArrayInsnNode;
|
||||
import org.objectweb.asm.tree.VarInsnNode;
|
||||
|
||||
/**
|
||||
* A symbolic execution stack frame. A stack frame contains a set of local
|
||||
* variable slots, and an operand stack. Warning: long and double values are
|
||||
* represented by <i>two</i> slots in local variables, and by <i>one</i> slot in
|
||||
* the operand stack.
|
||||
*
|
||||
* @param <V>
|
||||
* type of the Value used for the analysis.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class Frame<V extends Value> {
|
||||
|
||||
/**
|
||||
* The expected return type of the analyzed method, or <tt>null</tt> if the
|
||||
* method returns void.
|
||||
*/
|
||||
private V returnValue;
|
||||
|
||||
/**
|
||||
* The local variables and operand stack of this frame.
|
||||
*/
|
||||
private V[] values;
|
||||
|
||||
/**
|
||||
* The number of local variables of this frame.
|
||||
*/
|
||||
private int locals;
|
||||
|
||||
/**
|
||||
* The number of elements in the operand stack.
|
||||
*/
|
||||
private int top;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Frame(final int nLocals, final int nStack) {
|
||||
this.values = (V[]) new Value[nLocals + nStack];
|
||||
this.locals = nLocals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new frame that is identical to the given frame.
|
||||
*
|
||||
* @param src
|
||||
* a frame.
|
||||
*/
|
||||
public Frame(final Frame<? extends V> src) {
|
||||
this(src.locals, src.values.length - src.locals);
|
||||
init(src);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the state of the given frame into this frame.
|
||||
*
|
||||
* @param src
|
||||
* a frame.
|
||||
* @return this frame.
|
||||
*/
|
||||
public Frame<V> init(final Frame<? extends V> src) {
|
||||
returnValue = src.returnValue;
|
||||
System.arraycopy(src.values, 0, values, 0, values.length);
|
||||
top = src.top;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expected return type of the analyzed method.
|
||||
*
|
||||
* @param v
|
||||
* the expected return type of the analyzed method, or
|
||||
* <tt>null</tt> if the method returns void.
|
||||
*/
|
||||
public void setReturn(final V v) {
|
||||
returnValue = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of local variables of this frame.
|
||||
*
|
||||
* @return the maximum number of local variables of this frame.
|
||||
*/
|
||||
public int getLocals() {
|
||||
return locals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the given local variable.
|
||||
*
|
||||
* @param i
|
||||
* a local variable index.
|
||||
* @return the value of the given local variable.
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the variable does not exist.
|
||||
*/
|
||||
public V getLocal(final int i) throws IndexOutOfBoundsException {
|
||||
if (i >= locals) {
|
||||
throw new IndexOutOfBoundsException(
|
||||
"Trying to access an inexistant local variable");
|
||||
}
|
||||
return values[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the given local variable.
|
||||
*
|
||||
* @param i
|
||||
* a local variable index.
|
||||
* @param value
|
||||
* the new value of this local variable.
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the variable does not exist.
|
||||
*/
|
||||
public void setLocal(final int i, final V value)
|
||||
throws IndexOutOfBoundsException {
|
||||
if (i >= locals) {
|
||||
throw new IndexOutOfBoundsException(
|
||||
"Trying to access an inexistant local variable " + i);
|
||||
}
|
||||
values[i] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of values in the operand stack of this frame. Long and
|
||||
* double values are treated as single values.
|
||||
*
|
||||
* @return the number of values in the operand stack of this frame.
|
||||
*/
|
||||
public int getStackSize() {
|
||||
return top;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the given operand stack slot.
|
||||
*
|
||||
* @param i
|
||||
* the index of an operand stack slot.
|
||||
* @return the value of the given operand stack slot.
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the operand stack slot does not exist.
|
||||
*/
|
||||
public V getStack(final int i) throws IndexOutOfBoundsException {
|
||||
return values[i + locals];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the operand stack of this frame.
|
||||
*/
|
||||
public void clearStack() {
|
||||
top = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops a value from the operand stack of this frame.
|
||||
*
|
||||
* @return the value that has been popped from the stack.
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the operand stack is empty.
|
||||
*/
|
||||
public V pop() throws IndexOutOfBoundsException {
|
||||
if (top == 0) {
|
||||
throw new IndexOutOfBoundsException(
|
||||
"Cannot pop operand off an empty stack.");
|
||||
}
|
||||
return values[--top + locals];
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes a value into the operand stack of this frame.
|
||||
*
|
||||
* @param value
|
||||
* the value that must be pushed into the stack.
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the operand stack is full.
|
||||
*/
|
||||
public void push(final V value) throws IndexOutOfBoundsException {
|
||||
if (top + locals >= values.length) {
|
||||
throw new IndexOutOfBoundsException(
|
||||
"Insufficient maximum stack size.");
|
||||
}
|
||||
values[top++ + locals] = value;
|
||||
}
|
||||
|
||||
public void execute(final AbstractInsnNode insn,
|
||||
final Interpreter<V> interpreter) throws AnalyzerException {
|
||||
V value1, value2, value3, value4;
|
||||
List<V> values;
|
||||
int var;
|
||||
|
||||
switch (insn.getOpcode()) {
|
||||
case Opcodes.NOP:
|
||||
break;
|
||||
case Opcodes.ACONST_NULL:
|
||||
case Opcodes.ICONST_M1:
|
||||
case Opcodes.ICONST_0:
|
||||
case Opcodes.ICONST_1:
|
||||
case Opcodes.ICONST_2:
|
||||
case Opcodes.ICONST_3:
|
||||
case Opcodes.ICONST_4:
|
||||
case Opcodes.ICONST_5:
|
||||
case Opcodes.LCONST_0:
|
||||
case Opcodes.LCONST_1:
|
||||
case Opcodes.FCONST_0:
|
||||
case Opcodes.FCONST_1:
|
||||
case Opcodes.FCONST_2:
|
||||
case Opcodes.DCONST_0:
|
||||
case Opcodes.DCONST_1:
|
||||
case Opcodes.BIPUSH:
|
||||
case Opcodes.SIPUSH:
|
||||
case Opcodes.LDC:
|
||||
push(interpreter.newOperation(insn));
|
||||
break;
|
||||
case Opcodes.ILOAD:
|
||||
case Opcodes.LLOAD:
|
||||
case Opcodes.FLOAD:
|
||||
case Opcodes.DLOAD:
|
||||
case Opcodes.ALOAD:
|
||||
push(interpreter.copyOperation(insn,
|
||||
getLocal(((VarInsnNode) insn).var)));
|
||||
break;
|
||||
case Opcodes.IALOAD:
|
||||
case Opcodes.LALOAD:
|
||||
case Opcodes.FALOAD:
|
||||
case Opcodes.DALOAD:
|
||||
case Opcodes.AALOAD:
|
||||
case Opcodes.BALOAD:
|
||||
case Opcodes.CALOAD:
|
||||
case Opcodes.SALOAD:
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
push(interpreter.binaryOperation(insn, value1, value2));
|
||||
break;
|
||||
case Opcodes.ISTORE:
|
||||
case Opcodes.LSTORE:
|
||||
case Opcodes.FSTORE:
|
||||
case Opcodes.DSTORE:
|
||||
case Opcodes.ASTORE:
|
||||
value1 = interpreter.copyOperation(insn, pop());
|
||||
var = ((VarInsnNode) insn).var;
|
||||
setLocal(var, value1);
|
||||
if (value1.getSize() == 2) {
|
||||
setLocal(var + 1, interpreter.newValue(null));
|
||||
}
|
||||
if (var > 0) {
|
||||
Value local = getLocal(var - 1);
|
||||
if (local != null && local.getSize() == 2) {
|
||||
setLocal(var - 1, interpreter.newValue(null));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Opcodes.IASTORE:
|
||||
case Opcodes.LASTORE:
|
||||
case Opcodes.FASTORE:
|
||||
case Opcodes.DASTORE:
|
||||
case Opcodes.AASTORE:
|
||||
case Opcodes.BASTORE:
|
||||
case Opcodes.CASTORE:
|
||||
case Opcodes.SASTORE:
|
||||
value3 = pop();
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
interpreter.ternaryOperation(insn, value1, value2, value3);
|
||||
break;
|
||||
case Opcodes.POP:
|
||||
if (pop().getSize() == 2) {
|
||||
throw new AnalyzerException(insn, "Illegal use of POP");
|
||||
}
|
||||
break;
|
||||
case Opcodes.POP2:
|
||||
if (pop().getSize() == 1) {
|
||||
if (pop().getSize() != 1) {
|
||||
throw new AnalyzerException(insn, "Illegal use of POP2");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Opcodes.DUP:
|
||||
value1 = pop();
|
||||
if (value1.getSize() != 1) {
|
||||
throw new AnalyzerException(insn, "Illegal use of DUP");
|
||||
}
|
||||
push(value1);
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
break;
|
||||
case Opcodes.DUP_X1:
|
||||
value1 = pop();
|
||||
value2 = pop();
|
||||
if (value1.getSize() != 1 || value2.getSize() != 1) {
|
||||
throw new AnalyzerException(insn, "Illegal use of DUP_X1");
|
||||
}
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
case Opcodes.DUP_X2:
|
||||
value1 = pop();
|
||||
if (value1.getSize() == 1) {
|
||||
value2 = pop();
|
||||
if (value2.getSize() == 1) {
|
||||
value3 = pop();
|
||||
if (value3.getSize() == 1) {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value3);
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw new AnalyzerException(insn, "Illegal use of DUP_X2");
|
||||
case Opcodes.DUP2:
|
||||
value1 = pop();
|
||||
if (value1.getSize() == 1) {
|
||||
value2 = pop();
|
||||
if (value2.getSize() == 1) {
|
||||
push(value2);
|
||||
push(value1);
|
||||
push(interpreter.copyOperation(insn, value2));
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
push(value1);
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
break;
|
||||
}
|
||||
throw new AnalyzerException(insn, "Illegal use of DUP2");
|
||||
case Opcodes.DUP2_X1:
|
||||
value1 = pop();
|
||||
if (value1.getSize() == 1) {
|
||||
value2 = pop();
|
||||
if (value2.getSize() == 1) {
|
||||
value3 = pop();
|
||||
if (value3.getSize() == 1) {
|
||||
push(interpreter.copyOperation(insn, value2));
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value3);
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
value2 = pop();
|
||||
if (value2.getSize() == 1) {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw new AnalyzerException(insn, "Illegal use of DUP2_X1");
|
||||
case Opcodes.DUP2_X2:
|
||||
value1 = pop();
|
||||
if (value1.getSize() == 1) {
|
||||
value2 = pop();
|
||||
if (value2.getSize() == 1) {
|
||||
value3 = pop();
|
||||
if (value3.getSize() == 1) {
|
||||
value4 = pop();
|
||||
if (value4.getSize() == 1) {
|
||||
push(interpreter.copyOperation(insn, value2));
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value4);
|
||||
push(value3);
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
push(interpreter.copyOperation(insn, value2));
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value3);
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
value2 = pop();
|
||||
if (value2.getSize() == 1) {
|
||||
value3 = pop();
|
||||
if (value3.getSize() == 1) {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value3);
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw new AnalyzerException(insn, "Illegal use of DUP2_X2");
|
||||
case Opcodes.SWAP:
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
if (value1.getSize() != 1 || value2.getSize() != 1) {
|
||||
throw new AnalyzerException(insn, "Illegal use of SWAP");
|
||||
}
|
||||
push(interpreter.copyOperation(insn, value2));
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
break;
|
||||
case Opcodes.IADD:
|
||||
case Opcodes.LADD:
|
||||
case Opcodes.FADD:
|
||||
case Opcodes.DADD:
|
||||
case Opcodes.ISUB:
|
||||
case Opcodes.LSUB:
|
||||
case Opcodes.FSUB:
|
||||
case Opcodes.DSUB:
|
||||
case Opcodes.IMUL:
|
||||
case Opcodes.LMUL:
|
||||
case Opcodes.FMUL:
|
||||
case Opcodes.DMUL:
|
||||
case Opcodes.IDIV:
|
||||
case Opcodes.LDIV:
|
||||
case Opcodes.FDIV:
|
||||
case Opcodes.DDIV:
|
||||
case Opcodes.IREM:
|
||||
case Opcodes.LREM:
|
||||
case Opcodes.FREM:
|
||||
case Opcodes.DREM:
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
push(interpreter.binaryOperation(insn, value1, value2));
|
||||
break;
|
||||
case Opcodes.INEG:
|
||||
case Opcodes.LNEG:
|
||||
case Opcodes.FNEG:
|
||||
case Opcodes.DNEG:
|
||||
push(interpreter.unaryOperation(insn, pop()));
|
||||
break;
|
||||
case Opcodes.ISHL:
|
||||
case Opcodes.LSHL:
|
||||
case Opcodes.ISHR:
|
||||
case Opcodes.LSHR:
|
||||
case Opcodes.IUSHR:
|
||||
case Opcodes.LUSHR:
|
||||
case Opcodes.IAND:
|
||||
case Opcodes.LAND:
|
||||
case Opcodes.IOR:
|
||||
case Opcodes.LOR:
|
||||
case Opcodes.IXOR:
|
||||
case Opcodes.LXOR:
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
push(interpreter.binaryOperation(insn, value1, value2));
|
||||
break;
|
||||
case Opcodes.IINC:
|
||||
var = ((IincInsnNode) insn).var;
|
||||
setLocal(var, interpreter.unaryOperation(insn, getLocal(var)));
|
||||
break;
|
||||
case Opcodes.I2L:
|
||||
case Opcodes.I2F:
|
||||
case Opcodes.I2D:
|
||||
case Opcodes.L2I:
|
||||
case Opcodes.L2F:
|
||||
case Opcodes.L2D:
|
||||
case Opcodes.F2I:
|
||||
case Opcodes.F2L:
|
||||
case Opcodes.F2D:
|
||||
case Opcodes.D2I:
|
||||
case Opcodes.D2L:
|
||||
case Opcodes.D2F:
|
||||
case Opcodes.I2B:
|
||||
case Opcodes.I2C:
|
||||
case Opcodes.I2S:
|
||||
push(interpreter.unaryOperation(insn, pop()));
|
||||
break;
|
||||
case Opcodes.LCMP:
|
||||
case Opcodes.FCMPL:
|
||||
case Opcodes.FCMPG:
|
||||
case Opcodes.DCMPL:
|
||||
case Opcodes.DCMPG:
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
push(interpreter.binaryOperation(insn, value1, value2));
|
||||
break;
|
||||
case Opcodes.IFEQ:
|
||||
case Opcodes.IFNE:
|
||||
case Opcodes.IFLT:
|
||||
case Opcodes.IFGE:
|
||||
case Opcodes.IFGT:
|
||||
case Opcodes.IFLE:
|
||||
interpreter.unaryOperation(insn, pop());
|
||||
break;
|
||||
case Opcodes.IF_ICMPEQ:
|
||||
case Opcodes.IF_ICMPNE:
|
||||
case Opcodes.IF_ICMPLT:
|
||||
case Opcodes.IF_ICMPGE:
|
||||
case Opcodes.IF_ICMPGT:
|
||||
case Opcodes.IF_ICMPLE:
|
||||
case Opcodes.IF_ACMPEQ:
|
||||
case Opcodes.IF_ACMPNE:
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
interpreter.binaryOperation(insn, value1, value2);
|
||||
break;
|
||||
case Opcodes.GOTO:
|
||||
break;
|
||||
case Opcodes.JSR:
|
||||
push(interpreter.newOperation(insn));
|
||||
break;
|
||||
case Opcodes.RET:
|
||||
break;
|
||||
case Opcodes.TABLESWITCH:
|
||||
case Opcodes.LOOKUPSWITCH:
|
||||
interpreter.unaryOperation(insn, pop());
|
||||
break;
|
||||
case Opcodes.IRETURN:
|
||||
case Opcodes.LRETURN:
|
||||
case Opcodes.FRETURN:
|
||||
case Opcodes.DRETURN:
|
||||
case Opcodes.ARETURN:
|
||||
value1 = pop();
|
||||
interpreter.unaryOperation(insn, value1);
|
||||
interpreter.returnOperation(insn, value1, returnValue);
|
||||
break;
|
||||
case Opcodes.RETURN:
|
||||
if (returnValue != null) {
|
||||
throw new AnalyzerException(insn, "Incompatible return type");
|
||||
}
|
||||
break;
|
||||
case Opcodes.GETSTATIC:
|
||||
push(interpreter.newOperation(insn));
|
||||
break;
|
||||
case Opcodes.PUTSTATIC:
|
||||
interpreter.unaryOperation(insn, pop());
|
||||
break;
|
||||
case Opcodes.GETFIELD:
|
||||
push(interpreter.unaryOperation(insn, pop()));
|
||||
break;
|
||||
case Opcodes.PUTFIELD:
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
interpreter.binaryOperation(insn, value1, value2);
|
||||
break;
|
||||
case Opcodes.INVOKEVIRTUAL:
|
||||
case Opcodes.INVOKESPECIAL:
|
||||
case Opcodes.INVOKESTATIC:
|
||||
case Opcodes.INVOKEINTERFACE: {
|
||||
values = new ArrayList<V>();
|
||||
String desc = ((MethodInsnNode) insn).desc;
|
||||
for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) {
|
||||
values.add(0, pop());
|
||||
}
|
||||
if (insn.getOpcode() != Opcodes.INVOKESTATIC) {
|
||||
values.add(0, pop());
|
||||
}
|
||||
if (Type.getReturnType(desc) == Type.VOID_TYPE) {
|
||||
interpreter.naryOperation(insn, values);
|
||||
} else {
|
||||
push(interpreter.naryOperation(insn, values));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Opcodes.INVOKEDYNAMIC: {
|
||||
values = new ArrayList<V>();
|
||||
String desc = ((InvokeDynamicInsnNode) insn).desc;
|
||||
for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) {
|
||||
values.add(0, pop());
|
||||
}
|
||||
if (Type.getReturnType(desc) == Type.VOID_TYPE) {
|
||||
interpreter.naryOperation(insn, values);
|
||||
} else {
|
||||
push(interpreter.naryOperation(insn, values));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Opcodes.NEW:
|
||||
push(interpreter.newOperation(insn));
|
||||
break;
|
||||
case Opcodes.NEWARRAY:
|
||||
case Opcodes.ANEWARRAY:
|
||||
case Opcodes.ARRAYLENGTH:
|
||||
push(interpreter.unaryOperation(insn, pop()));
|
||||
break;
|
||||
case Opcodes.ATHROW:
|
||||
interpreter.unaryOperation(insn, pop());
|
||||
break;
|
||||
case Opcodes.CHECKCAST:
|
||||
case Opcodes.INSTANCEOF:
|
||||
push(interpreter.unaryOperation(insn, pop()));
|
||||
break;
|
||||
case Opcodes.MONITORENTER:
|
||||
case Opcodes.MONITOREXIT:
|
||||
interpreter.unaryOperation(insn, pop());
|
||||
break;
|
||||
case Opcodes.MULTIANEWARRAY:
|
||||
values = new ArrayList<V>();
|
||||
for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) {
|
||||
values.add(0, pop());
|
||||
}
|
||||
push(interpreter.naryOperation(insn, values));
|
||||
break;
|
||||
case Opcodes.IFNULL:
|
||||
case Opcodes.IFNONNULL:
|
||||
interpreter.unaryOperation(insn, pop());
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Illegal opcode " + insn.getOpcode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges this frame with the given frame.
|
||||
*
|
||||
* @param frame
|
||||
* a frame.
|
||||
* @param interpreter
|
||||
* the interpreter used to merge values.
|
||||
* @return <tt>true</tt> if this frame has been changed as a result of the
|
||||
* merge operation, or <tt>false</tt> otherwise.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if the frames have incompatible sizes.
|
||||
*/
|
||||
public boolean merge(final Frame<? extends V> frame,
|
||||
final Interpreter<V> interpreter) throws AnalyzerException {
|
||||
if (top != frame.top) {
|
||||
throw new AnalyzerException(null, "Incompatible stack heights");
|
||||
}
|
||||
boolean changes = false;
|
||||
for (int i = 0; i < locals + top; ++i) {
|
||||
V v = interpreter.merge(values[i], frame.values[i]);
|
||||
if (!v.equals(values[i])) {
|
||||
values[i] = v;
|
||||
changes = true;
|
||||
}
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges this frame with the given frame (case of a RET instruction).
|
||||
*
|
||||
* @param frame
|
||||
* a frame
|
||||
* @param access
|
||||
* the local variables that have been accessed by the subroutine
|
||||
* to which the RET instruction corresponds.
|
||||
* @return <tt>true</tt> if this frame has been changed as a result of the
|
||||
* merge operation, or <tt>false</tt> otherwise.
|
||||
*/
|
||||
public boolean merge(final Frame<? extends V> frame, final boolean[] access) {
|
||||
boolean changes = false;
|
||||
for (int i = 0; i < locals; ++i) {
|
||||
if (!access[i] && !values[i].equals(frame.values[i])) {
|
||||
values[i] = frame.values[i];
|
||||
changes = true;
|
||||
}
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this frame.
|
||||
*
|
||||
* @return a string representation of this frame.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer b = new StringBuffer();
|
||||
for (int i = 0; i < getLocals(); ++i) {
|
||||
b.append(getLocal(i));
|
||||
}
|
||||
b.append(' ');
|
||||
for (int i = 0; i < getStackSize(); ++i) {
|
||||
b.append(getStack(i).toString());
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.objectweb.asm.tree.analysis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
|
||||
/**
|
||||
* A semantic bytecode interpreter. More precisely, this interpreter only
|
||||
* manages the computation of values from other values: it does not manage the
|
||||
* transfer of values to or from the stack, and to or from the local variables.
|
||||
* This separation allows a generic bytecode {@link org.objectweb.asm.tree.analysis.Analyzer} to work with
|
||||
* various semantic interpreters, without needing to duplicate the code to
|
||||
* simulate the transfer of values.
|
||||
*
|
||||
* @param <V>
|
||||
* type of the Value used for the analysis.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public abstract class Interpreter<V extends Value> {
|
||||
|
||||
protected final int api;
|
||||
|
||||
protected Interpreter(final int api) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new value that represents the given type.
|
||||
*
|
||||
* Called for method parameters (including <code>this</code>), exception
|
||||
* handler variable and with <code>null</code> type for variables reserved
|
||||
* by long and double types.
|
||||
*
|
||||
* @param type
|
||||
* a primitive or reference type, or <tt>null</tt> to represent
|
||||
* an uninitialized value.
|
||||
* @return a value that represents the given type. The size of the returned
|
||||
* value must be equal to the size of the given type.
|
||||
*/
|
||||
public abstract V newValue(Type type);
|
||||
|
||||
/**
|
||||
* Interprets a bytecode instruction without arguments. This method is
|
||||
* called for the following opcodes:
|
||||
*
|
||||
* ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4,
|
||||
* ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0,
|
||||
* DCONST_1, BIPUSH, SIPUSH, LDC, JSR, GETSTATIC, NEW
|
||||
*
|
||||
* @param insn
|
||||
* the bytecode instruction to be interpreted.
|
||||
* @return the result of the interpretation of the given instruction.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if an error occured during the interpretation.
|
||||
*/
|
||||
public abstract V newOperation(AbstractInsnNode insn)
|
||||
throws AnalyzerException;
|
||||
|
||||
/**
|
||||
* Interprets a bytecode instruction that moves a value on the stack or to
|
||||
* or from local variables. This method is called for the following opcodes:
|
||||
*
|
||||
* ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE,
|
||||
* ASTORE, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP
|
||||
*
|
||||
* @param insn
|
||||
* the bytecode instruction to be interpreted.
|
||||
* @param value
|
||||
* the value that must be moved by the instruction.
|
||||
* @return the result of the interpretation of the given instruction. The
|
||||
* returned value must be <tt>equal</tt> to the given value.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if an error occured during the interpretation.
|
||||
*/
|
||||
public abstract V copyOperation(AbstractInsnNode insn, V value)
|
||||
throws AnalyzerException;
|
||||
|
||||
/**
|
||||
* Interprets a bytecode instruction with a single argument. This method is
|
||||
* called for the following opcodes:
|
||||
*
|
||||
* INEG, LNEG, FNEG, DNEG, IINC, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L,
|
||||
* F2D, D2I, D2L, D2F, I2B, I2C, I2S, IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE,
|
||||
* TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN,
|
||||
* PUTSTATIC, GETFIELD, NEWARRAY, ANEWARRAY, ARRAYLENGTH, ATHROW, CHECKCAST,
|
||||
* INSTANCEOF, MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL
|
||||
*
|
||||
* @param insn
|
||||
* the bytecode instruction to be interpreted.
|
||||
* @param value
|
||||
* the argument of the instruction to be interpreted.
|
||||
* @return the result of the interpretation of the given instruction.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if an error occured during the interpretation.
|
||||
*/
|
||||
public abstract V unaryOperation(AbstractInsnNode insn, V value)
|
||||
throws AnalyzerException;
|
||||
|
||||
/**
|
||||
* Interprets a bytecode instruction with two arguments. This method is
|
||||
* called for the following opcodes:
|
||||
*
|
||||
* IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IADD,
|
||||
* LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV,
|
||||
* LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, ISHL, LSHL, ISHR, LSHR, IUSHR,
|
||||
* LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, LCMP, FCMPL, FCMPG, DCMPL,
|
||||
* DCMPG, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
|
||||
* IF_ACMPEQ, IF_ACMPNE, PUTFIELD
|
||||
*
|
||||
* @param insn
|
||||
* the bytecode instruction to be interpreted.
|
||||
* @param value1
|
||||
* the first argument of the instruction to be interpreted.
|
||||
* @param value2
|
||||
* the second argument of the instruction to be interpreted.
|
||||
* @return the result of the interpretation of the given instruction.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if an error occured during the interpretation.
|
||||
*/
|
||||
public abstract V binaryOperation(AbstractInsnNode insn, V value1, V value2)
|
||||
throws AnalyzerException;
|
||||
|
||||
/**
|
||||
* Interprets a bytecode instruction with three arguments. This method is
|
||||
* called for the following opcodes:
|
||||
*
|
||||
* IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE
|
||||
*
|
||||
* @param insn
|
||||
* the bytecode instruction to be interpreted.
|
||||
* @param value1
|
||||
* the first argument of the instruction to be interpreted.
|
||||
* @param value2
|
||||
* the second argument of the instruction to be interpreted.
|
||||
* @param value3
|
||||
* the third argument of the instruction to be interpreted.
|
||||
* @return the result of the interpretation of the given instruction.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if an error occured during the interpretation.
|
||||
*/
|
||||
public abstract V ternaryOperation(AbstractInsnNode insn, V value1,
|
||||
V value2, V value3) throws AnalyzerException;
|
||||
|
||||
/**
|
||||
* Interprets a bytecode instruction with a variable number of arguments.
|
||||
* This method is called for the following opcodes:
|
||||
*
|
||||
* INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE,
|
||||
* MULTIANEWARRAY and INVOKEDYNAMIC
|
||||
*
|
||||
* @param insn
|
||||
* the bytecode instruction to be interpreted.
|
||||
* @param values
|
||||
* the arguments of the instruction to be interpreted.
|
||||
* @return the result of the interpretation of the given instruction.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if an error occured during the interpretation.
|
||||
*/
|
||||
public abstract V naryOperation(AbstractInsnNode insn,
|
||||
List<? extends V> values) throws AnalyzerException;
|
||||
|
||||
/**
|
||||
* Interprets a bytecode return instruction. This method is called for the
|
||||
* following opcodes:
|
||||
*
|
||||
* IRETURN, LRETURN, FRETURN, DRETURN, ARETURN
|
||||
*
|
||||
* @param insn
|
||||
* the bytecode instruction to be interpreted.
|
||||
* @param value
|
||||
* the argument of the instruction to be interpreted.
|
||||
* @param expected
|
||||
* the expected return type of the analyzed method.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if an error occured during the interpretation.
|
||||
*/
|
||||
public abstract void returnOperation(AbstractInsnNode insn, V value,
|
||||
V expected) throws AnalyzerException;
|
||||
|
||||
/**
|
||||
* Merges two values. The merge operation must return a value that
|
||||
* represents both values (for instance, if the two values are two types,
|
||||
* the merged value must be a common super type of the two types. If the two
|
||||
* values are integer intervals, the merged value must be an interval that
|
||||
* contains the previous ones. Likewise for other types of values).
|
||||
*
|
||||
* @param v
|
||||
* a value.
|
||||
* @param w
|
||||
* another value.
|
||||
* @return the merged value. If the merged value is equal to <tt>v</tt>,
|
||||
* this method <i>must</i> return <tt>v</tt>.
|
||||
*/
|
||||
public abstract V merge(V v, V w);
|
||||
}
|
||||
@@ -1,320 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.objectweb.asm.tree.analysis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* An extended {@link org.objectweb.asm.tree.analysis.BasicVerifier} that performs more precise verifications.
|
||||
* This verifier computes exact class types, instead of using a single "object
|
||||
* reference" type (as done in the {@link org.objectweb.asm.tree.analysis.BasicVerifier}).
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
* @author Bing Ran
|
||||
*/
|
||||
public class SimpleVerifier extends BasicVerifier {
|
||||
|
||||
/**
|
||||
* The class that is verified.
|
||||
*/
|
||||
private final Type currentClass;
|
||||
|
||||
/**
|
||||
* The super class of the class that is verified.
|
||||
*/
|
||||
private final Type currentSuperClass;
|
||||
|
||||
/**
|
||||
* The interfaces implemented by the class that is verified.
|
||||
*/
|
||||
private final List<Type> currentClassInterfaces;
|
||||
|
||||
/**
|
||||
* If the class that is verified is an interface.
|
||||
*/
|
||||
private final boolean isInterface;
|
||||
|
||||
/**
|
||||
* The loader to use for referenced classes.
|
||||
*/
|
||||
private ClassLoader loader = getClass().getClassLoader();
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.tree.analysis.SimpleVerifier}.
|
||||
*/
|
||||
public SimpleVerifier() {
|
||||
this(null, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.tree.analysis.SimpleVerifier} to verify a specific class. This
|
||||
* class will not be loaded into the JVM since it may be incorrect.
|
||||
*
|
||||
* @param currentClass
|
||||
* the class that is verified.
|
||||
* @param currentSuperClass
|
||||
* the super class of the class that is verified.
|
||||
* @param isInterface
|
||||
* if the class that is verified is an interface.
|
||||
*/
|
||||
public SimpleVerifier(final Type currentClass,
|
||||
final Type currentSuperClass, final boolean isInterface) {
|
||||
this(currentClass, currentSuperClass, null, isInterface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.tree.analysis.SimpleVerifier} to verify a specific class. This
|
||||
* class will not be loaded into the JVM since it may be incorrect.
|
||||
*
|
||||
* @param currentClass
|
||||
* the class that is verified.
|
||||
* @param currentSuperClass
|
||||
* the super class of the class that is verified.
|
||||
* @param currentClassInterfaces
|
||||
* the interfaces implemented by the class that is verified.
|
||||
* @param isInterface
|
||||
* if the class that is verified is an interface.
|
||||
*/
|
||||
public SimpleVerifier(final Type currentClass,
|
||||
final Type currentSuperClass,
|
||||
final List<Type> currentClassInterfaces, final boolean isInterface) {
|
||||
this(ASM4, currentClass, currentSuperClass, currentClassInterfaces,
|
||||
isInterface);
|
||||
}
|
||||
|
||||
protected SimpleVerifier(final int api, final Type currentClass,
|
||||
final Type currentSuperClass,
|
||||
final List<Type> currentClassInterfaces, final boolean isInterface) {
|
||||
super(api);
|
||||
this.currentClass = currentClass;
|
||||
this.currentSuperClass = currentSuperClass;
|
||||
this.currentClassInterfaces = currentClassInterfaces;
|
||||
this.isInterface = isInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>ClassLoader</code> which will be used to load referenced
|
||||
* classes. This is useful if you are verifying multiple interdependent
|
||||
* classes.
|
||||
*
|
||||
* @param loader
|
||||
* a <code>ClassLoader</code> to use
|
||||
*/
|
||||
public void setClassLoader(final ClassLoader loader) {
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue newValue(final Type type) {
|
||||
if (type == null) {
|
||||
return BasicValue.UNINITIALIZED_VALUE;
|
||||
}
|
||||
|
||||
boolean isArray = type.getSort() == Type.ARRAY;
|
||||
if (isArray) {
|
||||
switch (type.getElementType().getSort()) {
|
||||
case Type.BOOLEAN:
|
||||
case Type.CHAR:
|
||||
case Type.BYTE:
|
||||
case Type.SHORT:
|
||||
return new BasicValue(type);
|
||||
}
|
||||
}
|
||||
|
||||
BasicValue v = super.newValue(type);
|
||||
if (BasicValue.REFERENCE_VALUE.equals(v)) {
|
||||
if (isArray) {
|
||||
v = newValue(type.getElementType());
|
||||
String desc = v.getType().getDescriptor();
|
||||
for (int i = 0; i < type.getDimensions(); ++i) {
|
||||
desc = '[' + desc;
|
||||
}
|
||||
v = new BasicValue(Type.getType(desc));
|
||||
} else {
|
||||
v = new BasicValue(type);
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isArrayValue(final BasicValue value) {
|
||||
Type t = value.getType();
|
||||
return t != null
|
||||
&& ("Lnull;".equals(t.getDescriptor()) || t.getSort() == Type.ARRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BasicValue getElementValue(final BasicValue objectArrayValue)
|
||||
throws AnalyzerException {
|
||||
Type arrayType = objectArrayValue.getType();
|
||||
if (arrayType != null) {
|
||||
if (arrayType.getSort() == Type.ARRAY) {
|
||||
return newValue(Type.getType(arrayType.getDescriptor()
|
||||
.substring(1)));
|
||||
} else if ("Lnull;".equals(arrayType.getDescriptor())) {
|
||||
return objectArrayValue;
|
||||
}
|
||||
}
|
||||
throw new Error("Internal error");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSubTypeOf(final BasicValue value,
|
||||
final BasicValue expected) {
|
||||
Type expectedType = expected.getType();
|
||||
Type type = value.getType();
|
||||
switch (expectedType.getSort()) {
|
||||
case Type.INT:
|
||||
case Type.FLOAT:
|
||||
case Type.LONG:
|
||||
case Type.DOUBLE:
|
||||
return type.equals(expectedType);
|
||||
case Type.ARRAY:
|
||||
case Type.OBJECT:
|
||||
if ("Lnull;".equals(type.getDescriptor())) {
|
||||
return true;
|
||||
} else if (type.getSort() == Type.OBJECT
|
||||
|| type.getSort() == Type.ARRAY) {
|
||||
return isAssignableFrom(expectedType, type);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
throw new Error("Internal error");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue merge(final BasicValue v, final BasicValue w) {
|
||||
if (!v.equals(w)) {
|
||||
Type t = v.getType();
|
||||
Type u = w.getType();
|
||||
if (t != null
|
||||
&& (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)) {
|
||||
if (u != null
|
||||
&& (u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY)) {
|
||||
if ("Lnull;".equals(t.getDescriptor())) {
|
||||
return w;
|
||||
}
|
||||
if ("Lnull;".equals(u.getDescriptor())) {
|
||||
return v;
|
||||
}
|
||||
if (isAssignableFrom(t, u)) {
|
||||
return v;
|
||||
}
|
||||
if (isAssignableFrom(u, t)) {
|
||||
return w;
|
||||
}
|
||||
// TODO case of array classes of the same dimension
|
||||
// TODO should we look also for a common super interface?
|
||||
// problem: there may be several possible common super
|
||||
// interfaces
|
||||
do {
|
||||
if (t == null || isInterface(t)) {
|
||||
return BasicValue.REFERENCE_VALUE;
|
||||
}
|
||||
t = getSuperClass(t);
|
||||
if (isAssignableFrom(t, u)) {
|
||||
return newValue(t);
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
}
|
||||
return BasicValue.UNINITIALIZED_VALUE;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
protected boolean isInterface(final Type t) {
|
||||
if (currentClass != null && t.equals(currentClass)) {
|
||||
return isInterface;
|
||||
}
|
||||
return getClass(t).isInterface();
|
||||
}
|
||||
|
||||
protected Type getSuperClass(final Type t) {
|
||||
if (currentClass != null && t.equals(currentClass)) {
|
||||
return currentSuperClass;
|
||||
}
|
||||
Class<?> c = getClass(t).getSuperclass();
|
||||
return c == null ? null : Type.getType(c);
|
||||
}
|
||||
|
||||
protected boolean isAssignableFrom(final Type t, final Type u) {
|
||||
if (t.equals(u)) {
|
||||
return true;
|
||||
}
|
||||
if (currentClass != null && t.equals(currentClass)) {
|
||||
if (getSuperClass(u) == null) {
|
||||
return false;
|
||||
} else {
|
||||
if (isInterface) {
|
||||
return u.getSort() == Type.OBJECT
|
||||
|| u.getSort() == Type.ARRAY;
|
||||
}
|
||||
return isAssignableFrom(t, getSuperClass(u));
|
||||
}
|
||||
}
|
||||
if (currentClass != null && u.equals(currentClass)) {
|
||||
if (isAssignableFrom(t, currentSuperClass)) {
|
||||
return true;
|
||||
}
|
||||
if (currentClassInterfaces != null) {
|
||||
for (int i = 0; i < currentClassInterfaces.size(); ++i) {
|
||||
Type v = currentClassInterfaces.get(i);
|
||||
if (isAssignableFrom(t, v)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Class<?> tc = getClass(t);
|
||||
if (tc.isInterface()) {
|
||||
tc = Object.class;
|
||||
}
|
||||
return tc.isAssignableFrom(getClass(u));
|
||||
}
|
||||
|
||||
protected Class<?> getClass(final Type t) {
|
||||
try {
|
||||
if (t.getSort() == Type.ARRAY) {
|
||||
return Class.forName(t.getDescriptor().replace('/', '.'),
|
||||
false, loader);
|
||||
}
|
||||
return Class.forName(t.getClassName(), false, loader);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.objectweb.asm.tree.analysis;
|
||||
|
||||
import java.util.AbstractSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A set of at most two elements.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
class SmallSet<E> extends AbstractSet<E> implements Iterator<E> {
|
||||
|
||||
// if e1 is null, e2 must be null; otherwise e2 must be different from e1
|
||||
|
||||
E e1, e2;
|
||||
|
||||
static final <T> Set<T> emptySet() {
|
||||
return new SmallSet<T>(null, null);
|
||||
}
|
||||
|
||||
SmallSet(final E e1, final E e2) {
|
||||
this.e1 = e1;
|
||||
this.e2 = e2;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Implementation of inherited abstract methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return new SmallSet<E>(e1, e2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return e1 == null ? 0 : (e2 == null ? 1 : 2);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Implementation of the Iterator interface
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public boolean hasNext() {
|
||||
return e1 != null;
|
||||
}
|
||||
|
||||
public E next() {
|
||||
if (e1 == null) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
E e = e1;
|
||||
e1 = e2;
|
||||
e2 = null;
|
||||
return e;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
Set<E> union(final SmallSet<E> s) {
|
||||
if ((s.e1 == e1 && s.e2 == e2) || (s.e1 == e2 && s.e2 == e1)) {
|
||||
return this; // if the two sets are equal, return this
|
||||
}
|
||||
if (s.e1 == null) {
|
||||
return this; // if s is empty, return this
|
||||
}
|
||||
if (e1 == null) {
|
||||
return s; // if this is empty, return s
|
||||
}
|
||||
if (s.e2 == null) { // s contains exactly one element
|
||||
if (e2 == null) {
|
||||
return new SmallSet<E>(e1, s.e1); // necessarily e1 != s.e1
|
||||
} else if (s.e1 == e1 || s.e1 == e2) { // s is included in this
|
||||
return this;
|
||||
}
|
||||
}
|
||||
if (e2 == null) { // this contains exactly one element
|
||||
// if (s.e2 == null) { // cannot happen
|
||||
// return new SmallSet(e1, s.e1); // necessarily e1 != s.e1
|
||||
// } else
|
||||
if (e1 == s.e1 || e1 == s.e2) { // this in included in s
|
||||
return s;
|
||||
}
|
||||
}
|
||||
// here we know that there are at least 3 distinct elements
|
||||
HashSet<E> r = new HashSet<E>(4);
|
||||
r.add(e1);
|
||||
if (e2 != null) {
|
||||
r.add(e2);
|
||||
}
|
||||
r.add(s.e1);
|
||||
if (s.e2 != null) {
|
||||
r.add(s.e2);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.objectweb.asm.tree.analysis;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
|
||||
/**
|
||||
* An {@link org.objectweb.asm.tree.analysis.Interpreter} for {@link SourceValue} values.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class SourceInterpreter extends Interpreter<SourceValue> implements
|
||||
Opcodes {
|
||||
|
||||
public SourceInterpreter() {
|
||||
super(ASM4);
|
||||
}
|
||||
|
||||
protected SourceInterpreter(final int api) {
|
||||
super(api);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue newValue(final Type type) {
|
||||
if (type == Type.VOID_TYPE) {
|
||||
return null;
|
||||
}
|
||||
return new SourceValue(type == null ? 1 : type.getSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue newOperation(final AbstractInsnNode insn) {
|
||||
int size;
|
||||
switch (insn.getOpcode()) {
|
||||
case LCONST_0:
|
||||
case LCONST_1:
|
||||
case DCONST_0:
|
||||
case DCONST_1:
|
||||
size = 2;
|
||||
break;
|
||||
case LDC:
|
||||
Object cst = ((LdcInsnNode) insn).cst;
|
||||
size = cst instanceof Long || cst instanceof Double ? 2 : 1;
|
||||
break;
|
||||
case GETSTATIC:
|
||||
size = Type.getType(((FieldInsnNode) insn).desc).getSize();
|
||||
break;
|
||||
default:
|
||||
size = 1;
|
||||
}
|
||||
return new SourceValue(size, insn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue copyOperation(final AbstractInsnNode insn,
|
||||
final SourceValue value) {
|
||||
return new SourceValue(value.getSize(), insn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue unaryOperation(final AbstractInsnNode insn,
|
||||
final SourceValue value) {
|
||||
int size;
|
||||
switch (insn.getOpcode()) {
|
||||
case LNEG:
|
||||
case DNEG:
|
||||
case I2L:
|
||||
case I2D:
|
||||
case L2D:
|
||||
case F2L:
|
||||
case F2D:
|
||||
case D2L:
|
||||
size = 2;
|
||||
break;
|
||||
case GETFIELD:
|
||||
size = Type.getType(((FieldInsnNode) insn).desc).getSize();
|
||||
break;
|
||||
default:
|
||||
size = 1;
|
||||
}
|
||||
return new SourceValue(size, insn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue binaryOperation(final AbstractInsnNode insn,
|
||||
final SourceValue value1, final SourceValue value2) {
|
||||
int size;
|
||||
switch (insn.getOpcode()) {
|
||||
case LALOAD:
|
||||
case DALOAD:
|
||||
case LADD:
|
||||
case DADD:
|
||||
case LSUB:
|
||||
case DSUB:
|
||||
case LMUL:
|
||||
case DMUL:
|
||||
case LDIV:
|
||||
case DDIV:
|
||||
case LREM:
|
||||
case DREM:
|
||||
case LSHL:
|
||||
case LSHR:
|
||||
case LUSHR:
|
||||
case LAND:
|
||||
case LOR:
|
||||
case LXOR:
|
||||
size = 2;
|
||||
break;
|
||||
default:
|
||||
size = 1;
|
||||
}
|
||||
return new SourceValue(size, insn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue ternaryOperation(final AbstractInsnNode insn,
|
||||
final SourceValue value1, final SourceValue value2,
|
||||
final SourceValue value3) {
|
||||
return new SourceValue(1, insn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue naryOperation(final AbstractInsnNode insn,
|
||||
final List<? extends SourceValue> values) {
|
||||
int size;
|
||||
int opcode = insn.getOpcode();
|
||||
if (opcode == MULTIANEWARRAY) {
|
||||
size = 1;
|
||||
} else {
|
||||
String desc = (opcode == INVOKEDYNAMIC) ? ((InvokeDynamicInsnNode) insn).desc
|
||||
: ((MethodInsnNode) insn).desc;
|
||||
size = Type.getReturnType(desc).getSize();
|
||||
}
|
||||
return new SourceValue(size, insn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnOperation(final AbstractInsnNode insn,
|
||||
final SourceValue value, final SourceValue expected) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue merge(final SourceValue d, final SourceValue w) {
|
||||
if (d.insns instanceof SmallSet && w.insns instanceof SmallSet) {
|
||||
Set<AbstractInsnNode> s = ((SmallSet<AbstractInsnNode>) d.insns)
|
||||
.union((SmallSet<AbstractInsnNode>) w.insns);
|
||||
if (s == d.insns && d.size == w.size) {
|
||||
return d;
|
||||
} else {
|
||||
return new SourceValue(Math.min(d.size, w.size), s);
|
||||
}
|
||||
}
|
||||
if (d.size != w.size || !d.insns.containsAll(w.insns)) {
|
||||
HashSet<AbstractInsnNode> s = new HashSet<AbstractInsnNode>();
|
||||
s.addAll(d.insns);
|
||||
s.addAll(w.insns);
|
||||
return new SourceValue(Math.min(d.size, w.size), s);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.objectweb.asm.tree.analysis;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
|
||||
/**
|
||||
* A {@link Value} that is represented by its type in a two types type system.
|
||||
* This type system distinguishes the ONEWORD and TWOWORDS types.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class SourceValue implements Value {
|
||||
|
||||
/**
|
||||
* The size of this value.
|
||||
*/
|
||||
public final int size;
|
||||
|
||||
/**
|
||||
* The instructions that can produce this value. For example, for the Java
|
||||
* code below, the instructions that can produce the value of <tt>i</tt> at
|
||||
* line 5 are the txo ISTORE instructions at line 1 and 3:
|
||||
*
|
||||
* <pre>
|
||||
* 1: i = 0;
|
||||
* 2: if (...) {
|
||||
* 3: i = 1;
|
||||
* 4: }
|
||||
* 5: return i;
|
||||
* </pre>
|
||||
*
|
||||
* This field is a set of {@link org.objectweb.asm.tree.AbstractInsnNode} objects.
|
||||
*/
|
||||
public final Set<AbstractInsnNode> insns;
|
||||
|
||||
public SourceValue(final int size) {
|
||||
this(size, SmallSet.<AbstractInsnNode> emptySet());
|
||||
}
|
||||
|
||||
public SourceValue(final int size, final AbstractInsnNode insn) {
|
||||
this.size = size;
|
||||
this.insns = new SmallSet<AbstractInsnNode>(insn, null);
|
||||
}
|
||||
|
||||
public SourceValue(final int size, final Set<AbstractInsnNode> insns) {
|
||||
this.size = size;
|
||||
this.insns = insns;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object value) {
|
||||
if (!(value instanceof SourceValue)) {
|
||||
return false;
|
||||
}
|
||||
SourceValue v = (SourceValue) value;
|
||||
return size == v.size && insns.equals(v.insns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return insns.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.objectweb.asm.tree.analysis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
|
||||
/**
|
||||
* A method subroutine (corresponds to a JSR instruction).
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
class Subroutine {
|
||||
|
||||
LabelNode start;
|
||||
|
||||
boolean[] access;
|
||||
|
||||
List<JumpInsnNode> callers;
|
||||
|
||||
private Subroutine() {
|
||||
}
|
||||
|
||||
Subroutine(final LabelNode start, final int maxLocals,
|
||||
final JumpInsnNode caller) {
|
||||
this.start = start;
|
||||
this.access = new boolean[maxLocals];
|
||||
this.callers = new ArrayList<JumpInsnNode>();
|
||||
callers.add(caller);
|
||||
}
|
||||
|
||||
public Subroutine copy() {
|
||||
Subroutine result = new Subroutine();
|
||||
result.start = start;
|
||||
result.access = new boolean[access.length];
|
||||
System.arraycopy(access, 0, result.access, 0, access.length);
|
||||
result.callers = new ArrayList<JumpInsnNode>(callers);
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean merge(final Subroutine subroutine) throws AnalyzerException {
|
||||
boolean changes = false;
|
||||
for (int i = 0; i < access.length; ++i) {
|
||||
if (subroutine.access[i] && !access[i]) {
|
||||
access[i] = true;
|
||||
changes = true;
|
||||
}
|
||||
}
|
||||
if (subroutine.start == start) {
|
||||
for (int i = 0; i < subroutine.callers.size(); ++i) {
|
||||
JumpInsnNode caller = subroutine.callers.get(i);
|
||||
if (!callers.contains(caller)) {
|
||||
callers.add(caller);
|
||||
changes = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.objectweb.asm.tree.analysis;
|
||||
|
||||
/**
|
||||
* An immutable symbolic value for semantic interpretation of bytecode.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public interface Value {
|
||||
|
||||
/**
|
||||
* Returns the size of this value in words.
|
||||
*
|
||||
* @return either 1 or 2.
|
||||
*/
|
||||
int getSize();
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
<html>
|
||||
<!--
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
<body>
|
||||
|
||||
<p>
|
||||
Provides a framework for static code analysis based on the asm.tree package.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Basic usage:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
ClassReader cr = new ClassReader(bytecode);
|
||||
ClassNode cn = new ClassNode();
|
||||
cr.accept(cn, ClassReader.SKIP_DEBUG);
|
||||
|
||||
List methods = cn.methods;
|
||||
for (int i = 0; i < methods.size(); ++i) {
|
||||
MethodNode method = (MethodNode) methods.get(i);
|
||||
if (method.instructions.size() > 0) {
|
||||
Analyzer a = new Analyzer(new BasicInterpreter());
|
||||
a.analyze(cn.name, method);
|
||||
Frame[] frames = a.getFrames();
|
||||
// Elements of the frames arrray now contains info for each instruction
|
||||
// from the analyzed method. BasicInterpreter creates BasicValue, that
|
||||
// is using simplified type system that distinguishes the UNINITIALZED,
|
||||
// INT, FLOAT, LONG, DOUBLE, REFERENCE and RETURNADDRESS types.
|
||||
...
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@since ASM 1.4.3
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user