Analyzerpublic class Analyzer extends Object implements ConstantsA semantic bytecode analyzer. |
Fields Summary |
---|
private Interpreter | interpreter | private int | n | private IntMap | indexes | private List[] | handlers | private Frame[] | frames | private Subroutine[] | subroutines | private boolean[] | queued | private int[] | queue | private int | top | private boolean | jsr |
Constructors Summary |
---|
public Analyzer(Interpreter interpreter)Constructs a new {@link Analyzer}.
this.interpreter = interpreter;
|
Methods Summary |
---|
public Frame[] | analyze(oracle.toplink.libraries.asm.tree.ClassNode c, oracle.toplink.libraries.asm.tree.MethodNode m)Analyzes the given method.
n = m.instructions.size();
indexes = new IntMap(2*n);
handlers = new List[n];
frames = new Frame[n];
subroutines = new Subroutine[n];
queued = new boolean[n];
queue = new int[n];
top = 0;
// computes instruction indexes
for (int i = 0; i < n; ++i) {
indexes.put(m.instructions.get(i), i);
}
// computes exception handlers for each instruction
for (int i = 0; i < m.tryCatchBlocks.size(); ++i) {
TryCatchBlockNode tcb = (TryCatchBlockNode)m.tryCatchBlocks.get(i);
int begin = indexes.get(tcb.start);
int end = indexes.get(tcb.end);
for (int j = begin; j < end; ++j) {
List insnHandlers = handlers[j];
if (insnHandlers == null) {
insnHandlers = new ArrayList();
handlers[j] = insnHandlers;
}
insnHandlers.add(tcb);
}
}
// initializes the data structures for the control flow analysis algorithm
Frame current = newFrame(m.maxLocals, m.maxStack);
Frame handler = newFrame(m.maxLocals, m.maxStack);
Type[] args = Type.getArgumentTypes(m.desc);
int local = 0;
if ((m.access & ACC_STATIC) == 0) {
Type ctype = Type.getType("L" + c.name + ";");
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);
// control flow analysis
while (top > 0) {
int insn = queue[--top];
Frame f = frames[insn];
Subroutine subroutine = subroutines[insn];
queued[insn] = false;
try {
Object o = m.instructions.get(insn);
jsr = false;
if (o instanceof Label) {
merge(insn + 1, f, subroutine);
} else {
AbstractInsnNode insnNode = (AbstractInsnNode)o;
int insnOpcode = insnNode.getOpcode();
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);
}
if (insnOpcode == JSR) {
jsr = true;
merge(indexes.get(j.label), current, new Subroutine(j.label, m.maxLocals, j));
} else {
merge(indexes.get(j.label), current, subroutine);
}
} else if (insnNode instanceof LookupSwitchInsnNode) {
LookupSwitchInsnNode lsi = (LookupSwitchInsnNode)insnNode;
merge(indexes.get(lsi.dflt), current, subroutine);
for (int j = 0; j < lsi.labels.size(); ++j) {
Label label = (Label)lsi.labels.get(j);
merge(indexes.get(label), current, subroutine);
}
} else if (insnNode instanceof TableSwitchInsnNode) {
TableSwitchInsnNode tsi = (TableSwitchInsnNode)insnNode;
merge(indexes.get(tsi.dflt), current, subroutine);
for (int j = 0; j < tsi.labels.size(); ++j) {
Label label = (Label)tsi.labels.get(j);
merge(indexes.get(label), current, subroutine);
}
} else if (insnOpcode == RET) {
if (subroutine == null) {
throw new AnalyzerException(
"RET instruction outside of a sub routine");
} else {
for (int i = 0; i < subroutine.callers.size(); ++i) {
int caller = indexes.get(subroutine.callers.get(i));
merge(caller + 1, frames[caller], current, subroutines[caller], subroutine.access);
}
}
} 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);
}
}
List insnHandlers = handlers[insn];
if (insnHandlers != null) {
for (int i = 0; i < insnHandlers.size(); ++i) {
TryCatchBlockNode tcb = (TryCatchBlockNode)insnHandlers.get(i);
Type type;
if (tcb.type == null) {
type = Type.getType("Ljava/lang/Throwable;");
} else {
type = Type.getType("L" + tcb.type + ";");
}
handler.init(f);
handler.clearStack();
handler.push(interpreter.newValue(type));
merge(indexes.get(tcb.handler), handler, subroutine);
}
}
} catch (Exception e) {
throw new AnalyzerException(
"Error at instruction " + insn + ": " + e.getMessage());
}
}
return frames;
| public Frame[] | getFrames()Returns the symbolic stack frame for each instruction of the last recently
analyzed method.
return frames;
| public java.util.List | getHandlers(int insn)Returns the exception handlers for the given instruction.
return handlers[insn];
| public int | getIndex(java.lang.Object insn)Returns the index of the given instruction.
return indexes.get(insn);
| private void | merge(int insn, Frame beforeJSR, Frame afterRET, oracle.toplink.libraries.asm.tree.analysis.Analyzer$Subroutine subroutineBeforeJSR, boolean[] access)
if (insn > n - 1) {
throw new AnalyzerException("Execution can fall off end of the code");
} else {
Frame oldFrame = frames[insn];
Subroutine oldSubroutine = subroutines[insn];
boolean changes = false;
afterRET.merge(beforeJSR, access);
if (oldFrame == null) {
frames[insn] = newFrame(afterRET);
changes = true;
} else {
changes |= oldFrame.merge(afterRET, access);
}
newControlFlowEdge(afterRET, oldFrame);
if (oldSubroutine == null) {
if (subroutineBeforeJSR != null) {
subroutines[insn] = subroutineBeforeJSR.copy();
changes = true;
}
} else {
if (subroutineBeforeJSR != null) {
changes |= oldSubroutine.merge(subroutineBeforeJSR, !jsr);
}
}
if (changes && !queued[insn]) {
queued[insn] = true;
queue[top++] = insn;
}
}
| private void | merge(int insn, Frame frame, oracle.toplink.libraries.asm.tree.analysis.Analyzer$Subroutine subroutine)
if (insn > n - 1) {
throw new AnalyzerException("Execution can fall off end of the code");
} else {
Frame oldFrame = frames[insn];
Subroutine oldSubroutine = subroutines[insn];
boolean changes = false;
if (oldFrame == null) {
frames[insn] = newFrame(frame);
changes = true;
} else {
changes |= oldFrame.merge(frame, interpreter);
}
newControlFlowEdge(frame, oldFrame);
if (oldSubroutine == null) {
if (subroutine != null) {
subroutines[insn] = subroutine.copy();
changes = true;
}
} else {
if (subroutine != null) {
changes |= oldSubroutine.merge(subroutine, !jsr);
}
}
if (changes && !queued[insn]) {
queued[insn] = true;
queue[top++] = insn;
}
}
| protected void | newControlFlowEdge(Frame frame, Frame successor)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).
| protected Frame | newFrame(int nLocals, int nStack)Constructs a new frame with the given size.
return new Frame(nLocals, nStack);
| protected Frame | newFrame(Frame src)Constructs a new frame that is identical to the given frame.
return new Frame(src);
|
|