WALA/com.ibm.wala.core/src/com/ibm/wala/analysis/stackMachine/AbstractIntStackMachine.java

1156 lines
33 KiB
Java

/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.wala.analysis.stackMachine;
import java.util.Iterator;
import com.ibm.wala.cfg.ShrikeCFG;
import com.ibm.wala.cfg.ShrikeCFG.BasicBlock;
import com.ibm.wala.dataflow.graph.AbstractMeetOperator;
import com.ibm.wala.dataflow.graph.BasicFramework;
import com.ibm.wala.dataflow.graph.DataflowSolver;
import com.ibm.wala.dataflow.graph.IKilldallFramework;
import com.ibm.wala.dataflow.graph.ITransferFunctionProvider;
import com.ibm.wala.fixpoint.AbstractStatement;
import com.ibm.wala.fixpoint.AbstractVariable;
import com.ibm.wala.fixpoint.FixedPointConstants;
import com.ibm.wala.fixpoint.IVariable;
import com.ibm.wala.fixpoint.UnaryOperator;
import com.ibm.wala.shrikeBT.ArrayLengthInstruction;
import com.ibm.wala.shrikeBT.ConstantInstruction;
import com.ibm.wala.shrikeBT.Constants;
import com.ibm.wala.shrikeBT.DupInstruction;
import com.ibm.wala.shrikeBT.IArrayLoadInstruction;
import com.ibm.wala.shrikeBT.IArrayStoreInstruction;
import com.ibm.wala.shrikeBT.IBinaryOpInstruction;
import com.ibm.wala.shrikeBT.IComparisonInstruction;
import com.ibm.wala.shrikeBT.IConditionalBranchInstruction;
import com.ibm.wala.shrikeBT.IConversionInstruction;
import com.ibm.wala.shrikeBT.IGetInstruction;
import com.ibm.wala.shrikeBT.IInstanceofInstruction;
import com.ibm.wala.shrikeBT.IInstruction;
import com.ibm.wala.shrikeBT.IInvokeInstruction;
import com.ibm.wala.shrikeBT.ILoadInstruction;
import com.ibm.wala.shrikeBT.IPutInstruction;
import com.ibm.wala.shrikeBT.IShiftInstruction;
import com.ibm.wala.shrikeBT.IStoreInstruction;
import com.ibm.wala.shrikeBT.IUnaryOpInstruction;
import com.ibm.wala.shrikeBT.MonitorInstruction;
import com.ibm.wala.shrikeBT.NewInstruction;
import com.ibm.wala.shrikeBT.PopInstruction;
import com.ibm.wala.shrikeBT.SwapInstruction;
import com.ibm.wala.shrikeBT.SwitchInstruction;
import com.ibm.wala.shrikeBT.ThrowInstruction;
import com.ibm.wala.shrikeBT.Util;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.CancelRuntimeException;
import com.ibm.wala.util.shrike.ShrikeUtil;
/**
* Skeleton of functionality to propagate information through the Java bytecode stack machine using ShrikeBT.
* <p>
* This class computes properties the Java operand stack and of the local variables at the beginning of each basic block.
* <p>
* In this implementation, each dataflow variable value is an integer, and the "meeter" object provides the meets
*/
public abstract class AbstractIntStackMachine implements FixedPointConstants {
private static final boolean DEBUG = false;
public static final int TOP = -1;
public static final int BOTTOM = -2;
public static final int UNANALYZED = -3;
public static final int IGNORE = -4;
/**
* The solver
*/
private DataflowSolver<BasicBlock,MachineState> solver;
/**
* The control flow graph to analyze
*/
final private ShrikeCFG cfg;
/**
* Should uninitialized variables be considered TOP (optimistic) or BOTTOM (pessimistic);
*/
final public static boolean OPTIMISTIC = true;
protected AbstractIntStackMachine(final ShrikeCFG G) {
if (G == null) {
throw new IllegalArgumentException("G is null");
}
this.cfg = G;
}
protected void init(Meeter meeter, final FlowProvider flow) {
final MeetOperator meet = new MeetOperator(meeter);
ITransferFunctionProvider<BasicBlock, MachineState> xferFunctions = new ITransferFunctionProvider<BasicBlock, MachineState>() {
@Override
public boolean hasNodeTransferFunctions() {
return flow.needsNodeFlow();
}
@Override
public boolean hasEdgeTransferFunctions() {
return flow.needsEdgeFlow();
}
@Override
public UnaryOperator<MachineState> getNodeTransferFunction(final BasicBlock node) {
return new UnaryOperator<MachineState>() {
@Override
public byte evaluate(MachineState lhs, MachineState rhs) {
MachineState exit = lhs;
MachineState entry = rhs;
MachineState newExit = flow.flow(entry, node);
if (newExit.stateEquals(exit)) {
return NOT_CHANGED;
} else {
exit.copyState(newExit);
return CHANGED;
}
}
@Override
public String toString() {
return "NODE-FLOW";
}
@Override
public int hashCode() {
return 9973 * node.hashCode();
}
@Override
public boolean equals(Object o) {
return this == o;
}
};
}
@Override
public UnaryOperator<MachineState> getEdgeTransferFunction(final BasicBlock from, final BasicBlock to) {
return new UnaryOperator<MachineState>() {
@Override
public byte evaluate(MachineState lhs, MachineState rhs) {
MachineState exit = lhs;
MachineState entry = rhs;
MachineState newExit = flow.flow(entry, from, to);
if (newExit.stateEquals(exit)) {
return NOT_CHANGED;
} else {
exit.copyState(newExit);
return CHANGED;
}
}
@Override
public String toString() {
return "EDGE-FLOW";
}
@Override
public int hashCode() {
return 9973 * (from.hashCode() ^ to.hashCode());
}
@Override
public boolean equals(Object o) {
return this == o;
}
};
}
@Override
public AbstractMeetOperator<MachineState> getMeetOperator() {
return meet;
}
};
IKilldallFramework<BasicBlock, MachineState> problem = new BasicFramework<BasicBlock, MachineState>(cfg, xferFunctions);
solver = new DataflowSolver<BasicBlock, MachineState>(problem) {
private MachineState entry;
@Override
protected MachineState makeNodeVariable(BasicBlock n, boolean IN) {
assert n != null;
MachineState result = new MachineState(n);
if (IN && n.equals(cfg.entry())) {
entry = result;
}
return result;
}
@Override
protected MachineState makeEdgeVariable(BasicBlock from, BasicBlock to) {
assert from != null;
assert to != null;
MachineState result = new MachineState(from);
return result;
}
@Override
protected void initializeWorkList() {
super.buildEquations(false, false);
/*
* Add only the entry variable to the work list.
*/
for (Iterator it = getFixedPointSystem().getStatementsThatUse(entry); it.hasNext();) {
AbstractStatement s = (AbstractStatement) it.next();
addToWorkList(s);
}
}
@Override
protected void initializeVariables() {
super.initializeVariables();
AbstractIntStackMachine.this.initializeVariables();
}
@Override
protected MachineState[] makeStmtRHS(int size) {
return new MachineState[size];
}
};
}
public boolean solve() {
try {
return solver.solve(null);
} catch (CancelException e) {
throw new CancelRuntimeException(e);
}
}
/**
* Convenience method ... a little ugly .. perhaps delete later.
*/
protected void initializeVariables() {
}
public MachineState getEntryState() {
return solver.getIn(cfg.entry());
}
/**
* @return the state at the entry to a given block
*/
public MachineState getIn(ShrikeCFG.BasicBlock bb) {
return solver.getIn(bb);
}
private class MeetOperator extends AbstractMeetOperator<MachineState> {
private final Meeter meeter;
MeetOperator(Meeter meeter) {
this.meeter = meeter;
}
@Override
public boolean isUnaryNoOp() {
return false;
}
@Override
public byte evaluate(MachineState lhs, MachineState[] rhs) {
BasicBlock bb = lhs.getBasicBlock();
if (!bb.isCatchBlock()) {
return meet(lhs, rhs, bb, meeter) ? CHANGED : NOT_CHANGED;
} else {
return meetForCatchBlock(lhs, rhs, bb, meeter) ? CHANGED : NOT_CHANGED;
}
}
@Override
public int hashCode() {
return 72223 * meeter.hashCode();
}
@Override
public boolean equals(Object o) {
if (o instanceof MeetOperator) {
MeetOperator other = (MeetOperator) o;
return meeter.equals(other.meeter);
} else {
return false;
}
}
@Override
public String toString() {
return "MEETER";
}
}
/**
* A Meeter object provides the dataflow logic needed to meet the abstract machine state for a dataflow meet.
*/
protected interface Meeter {
/**
* Return the integer that represents the meet of a particular stack slot at the entry to a basic block.
*
* @param slot The stack slot to meet
* @param rhs The values to meet
* @param bb The basic block at whose entry this meet occurs
* @return The value result of the meet
*/
int meetStack(int slot, int[] rhs, BasicBlock bb);
/**
* Return the integer that represents stack slot 0 after a meet at the entry to a catch block.
*
* @param bb The basic block at whose entry this meet occurs
* @return The value of stack slot 0 after the meet
*/
int meetStackAtCatchBlock(BasicBlock bb);
/**
* Return the integer that represents the meet of a particular local at the entry to a basic block.
*
* @param n The number of the local
* @param rhs The values to meet
* @param bb The basic block at whose entry this meet occurs
* @return The value of local n after the meet.
*/
int meetLocal(int n, int[] rhs, BasicBlock bb);
}
/**
* Evaluate a meet of machine states.
*
* TODO: add some efficiency shortcuts. TODO: clean up and refactor.
*
* @param bb the basic block at whose entry the meet occurs
* @return true if the lhs value changes. false otherwise.
*/
private static boolean meet(IVariable lhs, IVariable[] rhs, BasicBlock bb, Meeter meeter) {
boolean changed = meetStacks(lhs, rhs, bb, meeter);
changed |= meetLocals(lhs, rhs, bb, meeter);
return changed;
}
/**
* Evaluate a meet of machine states at a catch block.
*
* TODO: add some efficiency shortcuts. TODO: clean up and refactor.
*
* @param bb the basic block at whose entry the meet occurs
* @return true if the lhs value changes. false otherwise.
*/
private static boolean meetForCatchBlock(IVariable lhs, IVariable[] rhs, BasicBlock bb, Meeter meeter) {
boolean changed = meetStacksAtCatchBlock(lhs, bb, meeter);
changed |= meetLocals(lhs, rhs, bb, meeter);
return changed;
}
/**
* Evaluate a meet of the stacks of machine states at the entry of a catch block.
*
* TODO: add some efficiency shortcuts. TODO: clean up and refactor.
*
* @param bb the basic block at whose entry the meet occurs
* @return true if the lhs value changes. false otherwise.
*/
private static boolean meetStacksAtCatchBlock(IVariable lhs, BasicBlock bb, Meeter meeter) {
boolean changed = false;
MachineState L = (MachineState) lhs;
// evaluate the meet of the stack of height 1, which holds the exception
// object.
// allocate lhs.stack if it's
// not already allocated.
if (L.stack == null) {
L.allocateStack(1);
L.stackHeight = 1;
}
int meet = meeter.meetStackAtCatchBlock(bb);
if (L.stack[0] == TOP) {
if (meet != TOP) {
changed = true;
L.stack[0] = meet;
}
} else if (meet != L.stack[0]) {
changed = true;
L.stack[0] = meet;
}
return changed;
}
/**
* Evaluate a meet of the stacks of machine states at the entry of a basic block.
*
* TODO: add some efficiency shortcuts. TODO: clean up and refactor.
*
* @param bb the basic block at whose entry the meet occurs
* @return true if the lhs value changes. false otherwise.
*/
private static boolean meetStacks(IVariable lhs, IVariable[] rhs, BasicBlock bb, Meeter meeter) {
boolean changed = false;
MachineState L = (MachineState) lhs;
// evaluate the element-wise meet over the stacks
// first ... how high are the stacks?
int height = computeMeetStackHeight(rhs);
// if there's any stack height to meet, allocate lhs.stack if it's
// not already allocated.
if (height > -1 && (L.stack == null || L.stack.length < height)) {
L.allocateStack(height);
L.stackHeight = height;
changed = true;
}
// now do the element-wise meet.
for (int i = 0; i < height; i++) {
int[] R = new int[rhs.length];
for (int j = 0; j < R.length; j++) {
MachineState m = (MachineState) rhs[j];
if (m.stack == null || m.stack.length < i+1) {
R[j] = TOP;
} else {
R[j] = m.stack[i];
if (R[j] == 0) {
R[j] = TOP;
}
}
}
int meet = meeter.meetStack(i, R, bb);
if (L.stack[i] == TOP) {
if (meet != TOP) {
changed = true;
L.stack[i] = meet;
}
} else if (meet != L.stack[i]) {
changed = true;
L.stack[i] = meet;
}
}
return changed;
}
/**
* Evaluate a meet of locals of machine states at the entry to a basic block.
*
* TODO: add some efficiency shortcuts. TODO: clean up and refactor.
*
* @param bb the basic block at whose entry the meet occurs
* @return true if the lhs value changes. false otherwise.
*/
private static boolean meetLocals(IVariable lhs, IVariable[] rhs, BasicBlock bb, Meeter meeter) {
boolean changed = false;
MachineState L = (MachineState) lhs;
// need we allocate lhs.locals?
int nLocals = computeMeetNLocals(rhs);
if (nLocals > -1 && (L.locals == null || L.locals.length < nLocals)) {
L.allocateLocals(nLocals);
}
// evaluate the element-wise meet over the locals.
for (int i = 0; i < nLocals; i++) {
int[] R = new int[rhs.length];
for (int j = 0; j < rhs.length; j++) {
R[j] = ((MachineState) rhs[j]).getLocal(i);
}
int meet = meeter.meetLocal(i, R, bb);
if (L.locals[i] == TOP) {
if (meet != TOP) {
changed = true;
L.locals[i] = meet;
}
} else if (meet != L.locals[i]) {
changed = true;
L.locals[i] = meet;
}
}
return changed;
}
/**
* @return the number of locals to meet. Return -1 if there is no local meet necessary.
* @param operands The operands for this operator. operands[0] is the left-hand side.
*/
private static int computeMeetNLocals(IVariable[] operands) {
MachineState lhs = (MachineState) operands[0];
int nLocals = -1;
if (lhs.locals != null) {
nLocals = lhs.locals.length;
} else {
for (int i = 1; i < operands.length; i++) {
MachineState rhs = (MachineState) operands[i];
if (rhs.locals != null) {
nLocals = rhs.locals.length;
break;
}
}
}
return nLocals;
}
/**
* @return the height of stacks that are being meeted. Return -1 if there is no stack meet necessary.
* @param operands The operands for this operator. operands[0] is the left-hand side.
*/
private static int computeMeetStackHeight(IVariable[] operands) {
MachineState lhs = (MachineState) operands[0];
int height = -1;
if (lhs.stack != null) {
height = lhs.stackHeight;
} else {
for (int i = 1; i < operands.length; i++) {
MachineState rhs = (MachineState) operands[i];
if (rhs.stack != null) {
height = rhs.stackHeight;
break;
}
}
}
return height;
}
/**
* Representation of the state of the JVM stack machine at some program point.
*/
public class MachineState extends AbstractVariable<MachineState> {
private int[] stack;
private int[] locals;
// NOTE: stackHeight == -1 is a special code meaning "this variable is TOP"
private int stackHeight;
private final BasicBlock bb;
/**
* I'm not using clone because I don't want to necessarily inherit the AbstractVariable state from the superclass
*/
public MachineState duplicate() {
MachineState result = new MachineState(bb);
result.copyState(this);
return result;
}
public MachineState(BasicBlock bb) {
setTOP();
this.bb = bb;
}
public BasicBlock getBasicBlock() {
return bb;
}
void setTOP() {
stackHeight = -1;
stack = null;
}
boolean isTOP() {
return stackHeight == -1;
}
public void push(int i) {
if (stack == null || stackHeight >= stack.length)
allocateStack(stackHeight+1);
stack[stackHeight++] = i;
}
public int pop() {
if (stackHeight <= 0) {
assert stackHeight > 0 : "can't pop stack of height " + stackHeight;
}
stackHeight -= 1;
return stack[stackHeight];
}
public int peek() {
return stack[stackHeight - 1];
}
public void swap() {
int temp = stack[stackHeight - 1];
stack[stackHeight - 1] = stack[stackHeight - 2];
stack[stackHeight - 2] = temp;
}
private void allocateStack(int stackHeight) {
if (stack == null) {
stack = new int[stackHeight + 1 ];
this.stackHeight = 0;
} else {
int[] newStack = new int[ Math.max(stack.length, stackHeight) * 2 + 1 ];
System.arraycopy(stack, 0, newStack, 0, stack.length);
stack = newStack;
}
}
private void allocateLocals(int maxLocals) {
int[] result = new int[maxLocals];
int start = 0;
if (locals != null) {
System.arraycopy(locals, 0, result, 0, locals.length);
start = locals.length;
}
for (int i = start; i < maxLocals; i++) {
result[i] = OPTIMISTIC ? TOP : BOTTOM;
}
locals = result;
}
public void clearStack() {
stackHeight = 0;
}
/**
* set the value of local i to symbol j
*
* @param i
* @param j
*/
public void setLocal(int i, int j) {
if (locals == null || locals.length < i+1) {
if (OPTIMISTIC && (j == TOP)) {
return;
} else {
allocateLocals(i+1);
}
}
locals[i] = j;
}
/**
* @param i
* @return the number of the symbol corresponding to local i
*/
public int getLocal(int i) {
if (locals == null || locals.length < i+1) {
if (OPTIMISTIC) {
return TOP;
} else {
return BOTTOM;
}
} else {
return locals[i];
}
}
public void replaceValue(int from, int to) {
if (stack != null)
for (int i = 0; i < stackHeight; i++)
if (stack[i] == from)
stack[i] = to;
if (locals != null)
for (int i = 0; i < locals.length; i++)
if (locals[i] == from)
locals[i] = to;
}
public boolean hasValue(int val) {
if (stack != null)
for (int i = 0; i < stackHeight; i++)
if (stack[i] == val)
return true;
if (locals != null)
for (int i = 0; i < locals.length; i++)
if (locals[i] == val)
return true;
return false;
}
@Override
public String toString() {
if (isTOP()) {
return "<TOP>@" + System.identityHashCode(this);
}
StringBuffer result = new StringBuffer("<");
result.append("S");
if (stackHeight == 0) {
result.append("[empty]");
} else {
result.append(array2StringBuffer(stack, stackHeight));
}
result.append("L");
result.append(array2StringBuffer(locals, locals==null?0:locals.length));
result.append(">");
return result.toString();
}
private StringBuffer array2StringBuffer(int[] array, int n) {
StringBuffer result = new StringBuffer("[");
if (array == null) {
result.append(OPTIMISTIC ? "TOP" : "BOTTOM");
} else {
for (int i = 0; i < n - 1; i++) {
result.append(array[i]).append(",");
}
result.append(array[n - 1]);
}
result.append("]");
return result;
}
@Override
public void copyState(MachineState other) {
if (other.stack == null) {
stack = null;
} else {
stack = new int[other.stack.length];
System.arraycopy(other.stack, 0, stack, 0, other.stack.length);
}
if (other.locals == null) {
locals = null;
} else {
locals = new int[other.locals.length];
System.arraycopy(other.locals, 0, locals, 0, other.locals.length);
}
stackHeight = other.stackHeight;
}
boolean stateEquals(MachineState exit) {
if (stackHeight != exit.stackHeight)
return false;
if (locals == null) {
if (exit.locals != null)
return false;
} else {
if (exit.locals == null)
return false;
else if (locals.length != exit.locals.length)
return false;
}
for (int i = 0; i < stackHeight; i++) {
if (stack[i] != exit.stack[i])
return false;
}
if (locals != null) {
for (int i = 0; i < locals.length; i++) {
if (locals[i] == TOP) {
if (exit.locals[i] != TOP)
return false;
}
if (locals[i] != exit.locals[i])
return false;
}
}
return true;
}
/**
* Returns the stackHeight.
*
* @return int
*/
public int getStackHeight() {
return stackHeight;
}
/**
* Use with care.
*/
public int[] getLocals() {
return locals;
}
}
/**
* Interface which defines a flow function for a basic block
*/
public interface FlowProvider {
public boolean needsNodeFlow();
public boolean needsEdgeFlow();
/**
* Compute the MachineState at the exit of a basic block, given a MachineState at the block's entry.
*/
public MachineState flow(MachineState entry, BasicBlock basicBlock);
/**
* Compute the MachineState at the end of an edge, given a MachineState at the edges's entry.
*/
public MachineState flow(MachineState entry, BasicBlock from, BasicBlock to);
}
/**
* This gives some basic facilities for shoving things around on the stack. Client analyses should subclass this as needed.
*/
protected static abstract class BasicStackFlowProvider implements FlowProvider, Constants {
private final ShrikeCFG cfg;
protected MachineState workingState;
private BasicStackMachineVisitor visitor;
private com.ibm.wala.shrikeBT.IInstruction.Visitor edgeVisitor;
private int currentInstructionIndex = 0;
private BasicBlock currentBlock;
private BasicBlock currentSuccessorBlock;
/**
* Only subclasses can instantiate
*/
protected BasicStackFlowProvider(ShrikeCFG cfg) {
this.cfg = cfg;
}
/**
* Initialize the visitors used to perform the flow functions
*/
protected void init(BasicStackMachineVisitor v, com.ibm.wala.shrikeBT.IInstruction.Visitor ev) {
this.visitor = v;
this.edgeVisitor = ev;
}
@Override
public boolean needsNodeFlow() {
return true;
}
@Override
public boolean needsEdgeFlow() {
return false;
}
@Override
public MachineState flow(MachineState entry, BasicBlock basicBlock) {
workingState = entry.duplicate();
currentBlock = basicBlock;
currentSuccessorBlock = null;
IInstruction[] instructions = getInstructions();
if (DEBUG) {
System.err.println(("Entry to BB" + cfg.getNumber(basicBlock) + " " + workingState));
}
for (int i = basicBlock.getFirstInstructionIndex(); i <= basicBlock.getLastInstructionIndex(); i++) {
currentInstructionIndex = i;
instructions[i].visit(visitor);
if (DEBUG) {
System.err.println(("After " + instructions[i] + " " + workingState));
}
}
return workingState;
}
@Override
public MachineState flow(MachineState entry, BasicBlock from, BasicBlock to) {
workingState = entry.duplicate();
currentBlock = from;
currentSuccessorBlock = to;
IInstruction[] instructions = getInstructions();
if (DEBUG) {
System.err.println(("Entry to BB" + cfg.getNumber(from) + " " + workingState));
}
for (int i = from.getFirstInstructionIndex(); i <= from.getLastInstructionIndex(); i++) {
currentInstructionIndex = i;
instructions[i].visit(edgeVisitor);
if (DEBUG) {
System.err.println(("After " + instructions[i] + " " + workingState));
}
}
return workingState;
}
protected int getCurrentInstructionIndex() {
return currentInstructionIndex;
}
protected int getCurrentProgramCounter() {
return cfg.getProgramCounter(currentInstructionIndex);
}
protected BasicBlock getCurrentBlock() {
return currentBlock;
}
protected BasicBlock getCurrentSuccessor() {
return currentSuccessorBlock;
}
public abstract IInstruction[] getInstructions();
/**
* Update the machine state to account for an instruction
*/
protected class BasicStackMachineVisitor extends IInstruction.Visitor {
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitArrayLength(ArrayLengthInstruction)
*/
@Override
public void visitArrayLength(ArrayLengthInstruction instruction) {
workingState.pop();
workingState.push(UNANALYZED);
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitArrayLoad(IArrayLoadInstruction)
*/
@Override
public void visitArrayLoad(IArrayLoadInstruction instruction) {
workingState.pop();
workingState.pop();
workingState.push(UNANALYZED);
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitArrayStore(IArrayStoreInstruction)
*/
@Override
public void visitArrayStore(IArrayStoreInstruction instruction) {
workingState.pop();
workingState.pop();
workingState.pop();
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitBinaryOp(IBinaryOpInstruction)
*/
@Override
public void visitBinaryOp(IBinaryOpInstruction instruction) {
workingState.pop();
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitComparison(IComparisonInstruction)
*/
@Override
public void visitComparison(IComparisonInstruction instruction) {
workingState.pop();
workingState.pop();
workingState.push(UNANALYZED);
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitConditionalBranch(IConditionalBranchInstruction)
*/
@Override
public void visitConditionalBranch(IConditionalBranchInstruction instruction) {
workingState.pop();
workingState.pop();
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitConstant(ConstantInstruction)
*/
@Override
public void visitConstant(ConstantInstruction instruction) {
workingState.push(UNANALYZED);
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitConversion(IConversionInstruction)
*/
@Override
public void visitConversion(IConversionInstruction instruction) {
workingState.pop();
workingState.push(UNANALYZED);
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitDup(DupInstruction)
*/
@Override
public void visitDup(DupInstruction instruction) {
int size = instruction.getSize();
int delta = instruction.getDelta();
assert size == 1 || size == 2;
assert delta == 0 || delta == 1 || delta == 2;
int toPop = size + delta;
int v1 = workingState.pop();
int v2 = (toPop > 1) ? workingState.pop() : IGNORE;
int v3 = (toPop > 2) ? workingState.pop() : IGNORE;
int v4 = (toPop > 3) ? workingState.pop() : IGNORE;
if (size > 1) {
workingState.push(v2);
}
workingState.push(v1);
if (v4 != IGNORE) {
workingState.push(v4);
}
if (v3 != IGNORE) {
workingState.push(v3);
}
if (v2 != IGNORE) {
workingState.push(v2);
}
workingState.push(v1);
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitGet(IGetInstruction)
*/
@Override
public void visitGet(IGetInstruction instruction) {
popN(instruction);
workingState.push(UNANALYZED);
}
protected void popN(IInstruction instruction) {
for (int i = 0; i < instruction.getPoppedCount(); i++) {
workingState.pop();
}
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitInstanceof(IInstanceofInstruction)
*/
@Override
public void visitInstanceof(IInstanceofInstruction instruction) {
workingState.pop();
workingState.push(UNANALYZED);
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitInvoke(IInvokeInstruction)
*/
@Override
public void visitInvoke(IInvokeInstruction instruction) {
popN(instruction);
ClassLoaderReference loader = cfg.getMethod().getDeclaringClass().getClassLoader().getReference();
TypeReference returnType = ShrikeUtil.makeTypeReference(loader, Util.getReturnType(instruction.getMethodSignature()));
if (!returnType.equals(TypeReference.Void)) {
workingState.push(UNANALYZED);
}
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitMonitor(MonitorInstruction)
*/
@Override
public void visitMonitor(MonitorInstruction instruction) {
workingState.pop();
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitLocalLoad(ILoadInstruction)
*/
@Override
public void visitLocalLoad(ILoadInstruction instruction) {
int t = workingState.getLocal(instruction.getVarIndex());
workingState.push(t);
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitLocalStore(IStoreInstruction)
*/
@Override
public void visitLocalStore(IStoreInstruction instruction) {
int index = instruction.getVarIndex();
workingState.setLocal(index, workingState.pop());
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitNew(NewInstruction)
*/
@Override
public void visitNew(NewInstruction instruction) {
popN(instruction);
workingState.push(UNANALYZED);
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitPop(PopInstruction)
*/
@Override
public void visitPop(PopInstruction instruction) {
if (instruction.getPoppedCount() > 0) {
workingState.pop();
}
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitPut(IPutInstruction)
*/
@Override
public void visitPut(IPutInstruction instruction) {
popN(instruction);
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitShift(IShiftInstruction)
*/
@Override
public void visitShift(IShiftInstruction instruction) {
workingState.pop();
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitSwap(SwapInstruction)
*/
@Override
public void visitSwap(SwapInstruction instruction) {
workingState.swap();
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitSwitch(SwitchInstruction)
*/
@Override
public void visitSwitch(SwitchInstruction instruction) {
workingState.pop();
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitThrow(ThrowInstruction)
*/
@Override
public void visitThrow(ThrowInstruction instruction) {
int exceptionType = workingState.pop();
workingState.clearStack();
workingState.push(exceptionType);
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitUnaryOp(IUnaryOpInstruction)
*/
@Override
public void visitUnaryOp(IUnaryOpInstruction instruction) {
// treated as a no-op in basic scheme
}
}
}
}