WALA/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java

1526 lines
67 KiB
Java

/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation and others.
* 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
* Adam Fuchs, Avik Chaudhuri, Steve Suh - Modified from stack to registers
*******************************************************************************/
package com.ibm.wala.dalvik.ssa;
import java.util.Iterator;
import com.ibm.wala.cfg.IBasicBlock;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.Language;
import com.ibm.wala.dalvik.classLoader.DexCFG;
import com.ibm.wala.dalvik.classLoader.DexCFG.BasicBlock;
import com.ibm.wala.dalvik.classLoader.DexIMethod;
import com.ibm.wala.dalvik.classLoader.Literal;
import com.ibm.wala.dalvik.dex.instructions.ArrayFill;
import com.ibm.wala.dalvik.dex.instructions.ArrayGet;
import com.ibm.wala.dalvik.dex.instructions.ArrayLength;
import com.ibm.wala.dalvik.dex.instructions.ArrayPut;
import com.ibm.wala.dalvik.dex.instructions.BinaryLiteralOperation;
import com.ibm.wala.dalvik.dex.instructions.BinaryOperation;
import com.ibm.wala.dalvik.dex.instructions.Branch;
import com.ibm.wala.dalvik.dex.instructions.CheckCast;
import com.ibm.wala.dalvik.dex.instructions.Constant;
import com.ibm.wala.dalvik.dex.instructions.GetField;
import com.ibm.wala.dalvik.dex.instructions.Goto;
import com.ibm.wala.dalvik.dex.instructions.InstanceOf;
import com.ibm.wala.dalvik.dex.instructions.Instruction;
import com.ibm.wala.dalvik.dex.instructions.Instruction.Visitor;
import com.ibm.wala.dalvik.dex.instructions.Invoke;
import com.ibm.wala.dalvik.dex.instructions.Monitor;
import com.ibm.wala.dalvik.dex.instructions.New;
import com.ibm.wala.dalvik.dex.instructions.NewArray;
import com.ibm.wala.dalvik.dex.instructions.NewArrayFilled;
import com.ibm.wala.dalvik.dex.instructions.PutField;
import com.ibm.wala.dalvik.dex.instructions.Return;
import com.ibm.wala.dalvik.dex.instructions.Switch;
import com.ibm.wala.dalvik.dex.instructions.Throw;
import com.ibm.wala.dalvik.dex.instructions.UnaryOperation;
import com.ibm.wala.shrikeBT.ArrayLengthInstruction;
import com.ibm.wala.shrikeBT.ConstantInstruction;
import com.ibm.wala.shrikeBT.GotoInstruction;
import com.ibm.wala.shrikeBT.IArrayLoadInstruction;
import com.ibm.wala.shrikeBT.IArrayStoreInstruction;
import com.ibm.wala.shrikeBT.IBinaryOpInstruction;
import com.ibm.wala.shrikeBT.IConditionalBranchInstruction;
import com.ibm.wala.shrikeBT.IGetInstruction;
import com.ibm.wala.shrikeBT.IInvokeInstruction;
import com.ibm.wala.shrikeBT.IUnaryOpInstruction;
import com.ibm.wala.shrikeBT.MonitorInstruction;
import com.ibm.wala.shrikeBT.NewInstruction;
import com.ibm.wala.shrikeBT.ReturnInstruction;
import com.ibm.wala.shrikeBT.SwitchInstruction;
import com.ibm.wala.shrikeBT.ThrowInstruction;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.ISSABasicBlock;
import com.ibm.wala.ssa.PhiValue;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.ssa.SSACFG;
import com.ibm.wala.ssa.SSACFG.ExceptionHandlerBasicBlock;
import com.ibm.wala.ssa.SSAConditionalBranchInstruction;
import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAInstructionFactory;
import com.ibm.wala.ssa.SSAInvokeInstruction;
import com.ibm.wala.ssa.SSALoadMetadataInstruction;
import com.ibm.wala.ssa.SSAPhiInstruction;
import com.ibm.wala.ssa.SSAPiInstruction;
import com.ibm.wala.ssa.SSAPiNodePolicy;
import com.ibm.wala.ssa.ShrikeIndirectionData;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.graph.dominators.Dominators;
import com.ibm.wala.util.intset.IntPair;
/**
* This class constructs an SSA {@link IR} from a backing ShrikeBT instruction stream.
*
* The basic algorithm here is an abstract interpretation over the Java bytecode to determine types of stack locations and local
* variables. As a side effect, the flow functions of the abstract interpretation emit instructions, eliminating the stack
* abstraction and moving to a register-transfer language in SSA form.
*/
public class DexSSABuilder extends AbstractIntRegisterMachine {
public static DexSSABuilder make(DexIMethod method, SSACFG cfg, DexCFG scfg, SSAInstruction[] instructions,
SymbolTable symbolTable, boolean buildLocalMap, SSAPiNodePolicy piNodePolicy) throws IllegalArgumentException {
if (scfg == null) {
throw new IllegalArgumentException("scfg == null");
}
return new DexSSABuilder(method, cfg, scfg, instructions, symbolTable, buildLocalMap, piNodePolicy);
}
/**
* A wrapper around the method being analyzed.
*/
final private DexIMethod method;
/**
* Governing symbol table
*/
final private SymbolTable symbolTable;
/**
* A logical mapping from <bcIndex, valueNumber> -> local number if null, don't build it.
*/
private final SSA2LocalMap localMap;
/**
* a factory to create concrete instructions
*/
private final SSAInstructionFactory insts;
/**
* information about indirect use of local variables in the bytecode
*/
// private final IndirectionData bytecodeIndirections;
private final ShrikeIndirectionData shrikeIndirections;
private DexSSABuilder(DexIMethod method, SSACFG cfg, DexCFG scfg, SSAInstruction[] instructions, SymbolTable symbolTable,
boolean buildLocalMap, SSAPiNodePolicy piNodePolicy) {
super(scfg);
localMap = buildLocalMap ? new SSA2LocalMap(scfg, instructions.length, cfg.getNumberOfNodes(), method.getMaxLocals()) : null;
init(new SymbolTableMeeter(cfg, scfg), new SymbolicPropagator(scfg, instructions,
cfg, piNodePolicy));
this.method = method;
this.symbolTable = symbolTable;
this.insts = method.getDeclaringClass().getClassLoader().getInstructionFactory();
// this.bytecodeIndirections = method.getIndirectionData();
this.shrikeIndirections = new ShrikeIndirectionData(instructions.length);
assert cfg != null : "Null CFG";
}
private class SymbolTableMeeter implements Meeter {
final SSACFG cfg;
final DexCFG dexCFG;
SymbolTableMeeter(SSACFG cfg, DexCFG dexCFG) {
this.cfg = cfg;
// this.instructions = instructions;
this.dexCFG = dexCFG;
}
// public int meetStack(int slot, int[] rhs, IBasicBlock<Instruction> bb) {
//
// assert bb != null : "null basic block";
//
// if (bb.isExitBlock()) {
// return TOP;
// }
//
// if (allTheSame(rhs)) {
// for (int i = 0; i < rhs.length; i++) {
// if (rhs[i] != TOP) {
// return rhs[i];
// }
// }
// // didn't find anything but TOP
// return TOP;
// } else {
// SSACFG.BasicBlock newBB = cfg.getNode(dexCFG.getNumber(bb));
// // if we already have a phi for this stack location
// SSAPhiInstruction phi = newBB.getPhiForStackSlot(slot);
// int result;
// if (phi == null) {
// // no phi already exists. create one.
// result = symbolTable.newPhi(rhs);
// PhiValue v = symbolTable.getPhiValue(result);
// phi = v.getPhiInstruction();
// newBB.addPhiForStackSlot(slot, phi);
// } else {
// // already created a phi. update it to account for the
// // new merge.
// result = phi.getDef();
// phi.setValues(rhs.clone());
// }
// return result;
// }
// }
@Override
public int meetLocal(int n, int[] rhs, DexCFG.BasicBlock bb) {
if (allTheSame(rhs)) {
for (int rh : rhs) {
if (rh != TOP) {
return rh;
}
}
// didn't find anything but TOP
return TOP;
} else {
SSACFG.BasicBlock newBB = cfg.getNode(dexCFG.getNumber(bb));
if (bb.isExitBlock()) {
// no phis in exit block please
return TOP;
}
// if we already have a phi for this local
SSAPhiInstruction phi = newBB.getPhiForLocal(n);
int result;
if (phi == null) {
// no phi already exists. create one.
result = symbolTable.newPhi(rhs);
PhiValue v = symbolTable.getPhiValue(result);
phi = v.getPhiInstruction();
newBB.addPhiForLocal(n, phi);
} else {
// already created a phi. update it to account for the
// new merge.
result = phi.getDef();
phi.setValues(rhs.clone());
}
return result;
}
}
/**
* Are all rhs values all the same? Note, we consider TOP (-1) to be same as everything else.
*
* @param rhs
* @return boolean
*/
private boolean allTheSame(int[] rhs) {
int x = -1;
// set x := the first non-TOP value
int i = 0;
for (i = 0; i < rhs.length; i++) {
if (rhs[i] != TOP) {
x = rhs[i];
break;
}
}
// check the remaining values
for (i = i + 1; i < rhs.length; i++) {
if (rhs[i] != x && rhs[i] != TOP)
return false;
}
return true;
}
}
@Override
protected void initializeVariables() {
MachineState entryState = getEntryState();
int parameterNumber = 0;
// added -2 to account for the return and exception register
// int local = method.getMaxLocals() - method.getNumberOfParameters() - 1 - 2;
//can't use just getNumberOfParameters because it does not account for Long/Wide variables which take up 2 registers
//as the parameter
int local = method.getMaxLocals() - method.getNumberOfParameterRegisters() - 1 - 2;
// MyLogger.log(LogLevel.DEBUG, "DexSSABuilder - initializeVariables() - local: " + local);
//initialize the "this" parameter if it needs to be set.
//the "this" parameter will be symbol number 1 in a virtual method.
// if (method.getMaxLocals() - method.getNumberOfParameters() - 2 > 0)
// entryState.setLocal(local, 1);
// System.out.println("visiting initalizeVartiables()");
// if (method.isStatic())
// System.out.println("Static");
// if (method.isClinit())
// System.out.println("Clinit");
// System.out.println("GetNumberOfParameter: " + method.getNumberOfParameterRegisters());
// System.out.println("Total Registers: " + (method.getMaxLocals()-2));
// System.out.println("local: " + local);
// if (local >= 0) {
// System.out.println("Max Registers: " + (int)(method.getMaxLocals() - 2));
// System.out.println("Parameters: " + method.getNumberOfParameters());
// System.out.println("Setting Entry State, local:"+ local + " with 1");
// entryState.setLocal(local, 1);
// }
// System.out.println("Max Registers: " + (int)(method.getMaxLocals() - 2));
// System.out.println("Parameters: " + method.getNumberOfParameters());
entryState.allocateLocals();
for (int i = 0; i < method.getNumberOfParameters(); i++) {
local++;
TypeReference t = method.getParameterType(i);
if (t != null) {
int symbol = symbolTable.getParameter(parameterNumber++);
entryState.setLocal(local, symbol);
if (t.equals(TypeReference.Double) || t.equals(TypeReference.Long)) {
local++;
entryState.setLocal(local,symbol);
}
}
}
// MyLogger.log(LogLevel.DEBUG, "DexSSABuilder - initializeVariables() - local: " + local);
// This useless value ensures that the state cannot be empty, even
// for a static method with no arguments in blocks with an empty stack
// and no locals being used. This ensures that propagation of the
// state thru the CFGSystem will always show changes the first time
// it reaches a block, and thus no piece of the CFG will be skipped.
//
// (note that this bizarre state really happened, in java_cup)
//
// SJF: I don't understand how this is supposed to work. It
// causes a bug right now in normal cases, so I'm commenting it out
// for now. If there's a problem, let's add a regression test
// to catch it.
//
// TODO: if there's no stack do we need this?
//entryState.push(symbolTable.newSymbol());
}
/**
* This class defines the type abstractions for this analysis and the flow function for each instruction in the ShrikeBT IR.
*/
private class SymbolicPropagator extends BasicRegisterFlowProvider {
final SSAInstruction[] instructions;
final DexCFG dexCFG;
final SSACFG cfg;
final ClassLoaderReference loader;
/**
* creators[i] holds the instruction that defs value number i
*/
private SSAInstruction[] creators;
// final SSA2LocalMap localMap;
final SSAPiNodePolicy piNodePolicy;
public SymbolicPropagator(DexCFG dexCFG, SSAInstruction[] instructions, SSACFG cfg,
SSAPiNodePolicy piNodePolicy) {
super(dexCFG);
this.piNodePolicy = piNodePolicy;
this.cfg = cfg;
this.creators = new SSAInstruction[0];
this.dexCFG = dexCFG;
this.instructions = instructions;
this.loader = dexCFG.getMethod().getDeclaringClass().getClassLoader().getReference();
// this.localMap = localMap;
init(this.new NodeVisitor(cfg), this.new EdgeVisitor());
}
@Override
public boolean needsEdgeFlow() {
return piNodePolicy != null;
}
private void emitInstruction(SSAInstruction s) {
instructions[getCurrentInstructionIndex()] = s;
for (int i = 0; i < s.getNumberOfDefs(); i++) {
if (creators.length < (s.getDef(i) + 1)) {
SSAInstruction[] arr = new SSAInstruction[2 * s.getDef(i)];
System.arraycopy(creators, 0, arr, 0, creators.length);
creators = arr;
}
assert s.getDef(i) != -1 : "invalid def " + i + " for " + s;
creators[s.getDef(i)] = s;
}
}
private SSAInstruction getCurrentInstruction() {
return instructions[getCurrentInstructionIndex()];
}
/**
* If we've already created the current instruction, return the value number def'ed by the current instruction. Else, create a
* new symbol.
*/
private int reuseOrCreateDef() {
if (getCurrentInstruction() == null || !getCurrentInstruction().hasDef()) {
return symbolTable.newSymbol();
} else {
return getCurrentInstruction().getDef();
}
}
/**
* If we've already created the current instruction, return the value number representing the exception the instruction may
* throw. Else, create a new symbol
*/
private int reuseOrCreateException() {
if (getCurrentInstruction() != null) {
assert getCurrentInstruction() instanceof SSAInvokeInstruction;
}
if (getCurrentInstruction() == null) {
return symbolTable.newSymbol();
} else {
SSAInvokeInstruction s = (SSAInvokeInstruction) getCurrentInstruction();
return s.getException();
}
}
/**
* Update the machine state to account for an instruction
*/
class NodeVisitor extends BasicRegisterMachineVisitor {
private final SSACFG cfg;
public NodeVisitor(SSACFG cfg) {
this.cfg = cfg;
}
// TODO: make sure all visit functions are overridden
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitArrayLength(ArrayLengthInstruction)
*/
@Override
public void visitArrayLength(ArrayLength instruction) {
int arrayRef = workingState.getLocal(instruction.source);
int dest = instruction.destination;
int length = reuseOrCreateDef();
setLocal(dest, length);
emitInstruction(insts.ArrayLengthInstruction(getCurrentInstructionIndex(), length, arrayRef));
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitArrayLoad(IArrayLoadInstruction)
*/
@Override
public void visitArrayGet(ArrayGet instruction) {
int index = workingState.getLocal(instruction.offset);
int arrayRef = workingState.getLocal(instruction.array);
int dest = instruction.destination;
// int index = workingState.pop();
// int arrayRef = workingState.pop();
int result = reuseOrCreateDef();
setLocal(dest, result);
// workingState.push(result);
TypeReference t = instruction.getType();
// if (instruction.isAddressOf()) {
// emitInstruction(insts.AddressOfInstruction(result, arrayRef, index, t));
// } else {
emitInstruction(insts.ArrayLoadInstruction(getCurrentInstructionIndex(), result, arrayRef, index, t));
// }
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitArrayStore(IArrayStoreInstruction)
*/
@Override
public void visitArrayPut(ArrayPut instruction) {
int value = workingState.getLocal(instruction.source);
int index = workingState.getLocal(instruction.offset);
int arrayRef = workingState.getLocal(instruction.array);
TypeReference t = instruction.getType();
//System.out.println(t.getName().toString());
// int value = workingState.pop();
// int index = workingState.pop();
// int arrayRef = workingState.pop();
// TypeReference t = ShrikeUtil.makeTypeReference(loader, instruction.getType());
emitInstruction(insts.ArrayStoreInstruction(getCurrentInstructionIndex(), arrayRef, index, value, t));
}
@Override
public void visitArrayFill(ArrayFill instruction) {
Iterator<Number> iae = instruction.getTable().getArrayElements().iterator();
int i = 0;
while (iae.hasNext())
{
Number ae = iae.next();
int index = symbolTable.getConstant(i);
int arrayRef = workingState.getLocal(instruction.array);
TypeReference t = instruction.getType();
// System.out.println(t.getName().toString());
int value;
//
// System.out.println("Index: " + ae.bufferIndex + ", Width: " + ae.elementWidth + ", Value: " + byte_buffer.getSomethingDependingonType );
//okay to call the getConstant(String) for a char?
if (t.equals(TypeReference.Char))
value = symbolTable.getConstant((char) ae.intValue());
else if (t.equals(TypeReference.Byte))
value = symbolTable.getConstant(ae.byteValue());
else if (t.equals(TypeReference.Short))
value = symbolTable.getConstant(ae.shortValue());
else if (t.equals(TypeReference.Int))
value = symbolTable.getConstant(ae.intValue());
else if (t.equals(TypeReference.Long))
value = symbolTable.getConstant(ae.longValue());
else if (t.equals(TypeReference.Float))
value = symbolTable.getConstant(ae.floatValue());
else if (t.equals(TypeReference.Double))
value = symbolTable.getConstant(ae.doubleValue());
else if (t.equals(TypeReference.Boolean))
value = symbolTable.getConstant(ae.intValue() != 0);
else
{
value = 0;
}
emitInstruction(insts.ArrayStoreInstruction(getCurrentInstructionIndex(), arrayRef, index, value, t));
// System.out.println("Index: " + t.bufferIndex + ", Value: " + t.buffer[t.bufferIndex]);
i++;
}
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitBinaryOp(IBinaryOpInstruction)
*/
@Override
public void visitBinaryOperation(BinaryOperation instruction) {
int val2 = workingState.getLocal(instruction.oper2);
int val1 = workingState.getLocal(instruction.oper1);
int dest = instruction.destination;
// int val2 = workingState.pop();
// int val1 = workingState.pop();
int result = reuseOrCreateDef();
setLocal(dest, result);
// workingState.push(result);
// boolean isFloat = instruction.getType().equals(TYPE_double) || instruction.getType().equals(TYPE_float);
emitInstruction(insts.BinaryOpInstruction(getCurrentInstructionIndex(), instruction.getOperator(), false, instruction.isUnsigned(), result, val1, val2, !instruction.isFloat()));
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitBinaryOp(IBinaryOpInstruction)
*/
@Override
public void visitBinaryLiteral(BinaryLiteralOperation instruction) {
//int val2 = workingState.getLocal(instruction.oper2);
Literal lit = instruction.oper2;
int val2;
if (lit instanceof Literal.IntLiteral)
val2 = symbolTable.getConstant(((Literal.IntLiteral)lit).value);
else if (lit instanceof Literal.LongLiteral)
val2 = symbolTable.getConstant(((Literal.LongLiteral)lit).value);
else if (lit instanceof Literal.DoubleLiteral)
val2 = symbolTable.getConstant(((Literal.DoubleLiteral)lit).value);
else
val2 = symbolTable.getConstant(((Literal.FloatLiteral)lit).value);
int val1 = workingState.getLocal(instruction.oper1);
int dest = instruction.destination;
// int val2 = workingState.pop();
// int val1 = workingState.pop();
int result = reuseOrCreateDef();
setLocal(dest, result);
// workingState.push(result);
// boolean isFloat = instruction.getType().equals(TYPE_double) || instruction.getType().equals(TYPE_float);
try {
if (instruction.isSub())
emitInstruction(insts.BinaryOpInstruction(getCurrentInstructionIndex(), instruction.getOperator(), false, instruction.isUnsigned(), result, val2, val1, !instruction.isFloat()));
else
emitInstruction(insts.BinaryOpInstruction(getCurrentInstructionIndex(), instruction.getOperator(), false, instruction.isUnsigned(), result, val1, val2, !instruction.isFloat()));
} catch (AssertionError e) {
System.err.println("When visiting Instuction " + instruction);
throw e;
}
}
protected void setLocal(int dest, int result) {
assert result <= symbolTable.getMaxValueNumber();
workingState.setLocal(dest, result);
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitCheckCast
*/
@Override
public void visitCheckCast(CheckCast instruction) {
int val = workingState.getLocal(instruction.object);
// int val = workingState.pop();
// dex does not use this result, but we need it for the SSA CheckCastInstruction
int result = reuseOrCreateDef();
workingState.setLocal(instruction.object, result);
// workingState.push(result);
// TypeReference t = instruction.getType();
emitInstruction(insts.CheckCastInstruction(getCurrentInstructionIndex(), result, val, instruction.type, instruction.isPEI()));
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitConditionalBranch(IConditionalBranchInstruction)
*/
@Override
public void visitBranch(Branch instruction) {
if(instruction instanceof Branch.BinaryBranch)
{
Branch.BinaryBranch bbranch = (Branch.BinaryBranch)instruction;
int val2 = workingState.getLocal(bbranch.oper2);
int val1 = workingState.getLocal(bbranch.oper1);
// int val2 = workingState.pop();
// int val1 = workingState.pop();
TypeReference t = TypeReference.Int;
emitInstruction(insts.ConditionalBranchInstruction(getCurrentInstructionIndex(), instruction.getOperator(), t, val1, val2, -1));
}
else if(instruction instanceof Branch.UnaryBranch)
{
Branch.UnaryBranch ubranch = (Branch.UnaryBranch)instruction;
int val2 = symbolTable.getConstant(0);
int val1 = workingState.getLocal(ubranch.oper1);
TypeReference t = TypeReference.Int;
emitInstruction(insts.ConditionalBranchInstruction(getCurrentInstructionIndex(), instruction.getOperator(), t, val1, val2, -1));
}
else
{
throw new IllegalArgumentException("instruction is of an unknown subtype of Branch");
}
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitConstant(ConstantInstruction)
*/
@Override
public void visitConstant(Constant instruction) {
int dest = instruction.destination;
int symbol = 0;
if(instruction instanceof Constant.ClassConstant)
{
Constant.ClassConstant constInst = (Constant.ClassConstant)instruction;
// TODO: change to a symbol that represents the given IClass
// symbol = symbolTable.getConstant(((Constant.ClassConstant)instruction).value);
symbol = reuseOrCreateDef();
TypeReference typeRef = constInst.value;
SSALoadMetadataInstruction s =
insts.LoadMetadataInstruction(getCurrentInstructionIndex(), symbol, TypeReference.JavaLangClass, typeRef);
emitInstruction(s);
}
else if(instruction instanceof Constant.IntConstant)
{
symbol = symbolTable.getConstant(((Constant.IntConstant)instruction).value);
}
else if(instruction instanceof Constant.LongConstant)
{
symbol = symbolTable.getConstant(((Constant.LongConstant)instruction).value);
}
else if(instruction instanceof Constant.StringConstant)
{
symbol = symbolTable.getConstant(((Constant.StringConstant)instruction).value);
}
else
{
Assertions.UNREACHABLE("unexpected constant instruction " + instruction);
}
setLocal(dest, symbol);
// Language l = cfg.getMethod().getDeclaringClass().getClassLoader().getLanguage();
// TypeReference type = l.getConstantType(instruction.getValue());
// int symbol = 0;
// if (l.isNullType(type)) {
// symbol = symbolTable.getNullConstant();
// } else if (l.isIntType(type)) {
// Integer value = (Integer) instruction.getValue();
// symbol = symbolTable.getConstant(value.intValue());
// } else if (l.isLongType(type)) {
// Long value = (Long) instruction.getValue();
// symbol = symbolTable.getConstant(value.longValue());
// } else if (l.isFloatType(type)) {
// Float value = (Float) instruction.getValue();
// symbol = symbolTable.getConstant(value.floatValue());
// } else if (l.isDoubleType(type)) {
// Double value = (Double) instruction.getValue();
// symbol = symbolTable.getConstant(value.doubleValue());
// } else if (l.isStringType(type)) {
// String value = (String) instruction.getValue();
// symbol = symbolTable.getConstant(value);
// } else if (l.isMetadataType(type)) {
// Object rval = l.getMetadataToken(instruction.getValue());
// symbol = reuseOrCreateDef();
// emitInstruction(insts.LoadMetadataInstruction(symbol, type, rval));
// } else {
// Assertions.UNREACHABLE("unexpected " + type);
// }
// workingState.push(symbol);
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitConversion(IConversionInstruction)
*/
// TODO: is this just a unary operation?
// @Override
// public void visitConversion(IConversionInstruction instruction) {
//
// int val = workingState.pop();
// int result = reuseOrCreateDef();
// workingState.push(result);
//
// TypeReference fromType = ShrikeUtil.makeTypeReference(loader, instruction.getFromType());
// TypeReference toType = ShrikeUtil.makeTypeReference(loader, instruction.getToType());
//
// emitInstruction(insts.ConversionInstruction(result, val, fromType, toType, instruction.throwsExceptionOnOverflow()));
// }
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitGet(IGetInstruction)
*/
@Override
public void visitGetField(GetField instruction) {
int dest = instruction.destination;
int result = reuseOrCreateDef();
FieldReference f = FieldReference.findOrCreate(loader, instruction.clazzName, instruction.fieldName, instruction.fieldType);
// TODO: what is isAddressOf()?
// shouldn't matter, java doesn't allow isAddressOf()
if(instruction instanceof GetField.GetInstanceField)
{
int instance = workingState.getLocal(((GetField.GetInstanceField)instruction).instance);
emitInstruction(insts.GetInstruction(getCurrentInstructionIndex(), result, instance, f));
}
else if(instruction instanceof GetField.GetStaticField)
{
emitInstruction(insts.GetInstruction(getCurrentInstructionIndex(), result, f));
}
else
{
throw new IllegalArgumentException("unknown subclass of GetField: "+instruction);
}
// if (instruction.isAddressOf()) {
// int ref = instruction.isStatic()? -1: workingState.pop();
// emitInstruction(insts.AddressOfInstruction(result, ref, f, f.getFieldType()));
// } else if (instruction.isStatic()) {
// emitInstruction(insts.GetInstruction(result, f));
// } else {
// int ref = workingState.pop();
// emitInstruction(insts.GetInstruction(result, ref, f));
// }
setLocal(dest, result);
// workingState.push(result);
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitGoto(GotoInstruction)
*/
@Override
public void visitGoto(Goto instruction) {
emitInstruction(insts.GotoInstruction(getCurrentInstructionIndex(), instruction.destination));
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitInstanceof
*/
@Override
public void visitInstanceof(InstanceOf instruction) {
int ref = workingState.getLocal(instruction.source);
int dest = instruction.destination;
// int ref = workingState.pop();
int result = reuseOrCreateDef();
setLocal(dest, result);
// workingState.push(result);
// TypeReference t = ShrikeUtil.makeTypeReference(loader, instruction.getType());
emitInstruction(insts.InstanceofInstruction(getCurrentInstructionIndex(), result, ref, instruction.type));
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitInvoke(IInvokeInstruction)
*/
@Override
public void visitInvoke(Invoke instruction) {
// TODO: can other methods do indirect reads from a dex method?
// doIndirectReads(bytecodeIndirections.indirectlyReadLocals(getCurrentInstructionIndex()));
// int n = instruction.getPoppedCount();
// int n = instruction.args.length;
// int[] params = new int[n];
// for (int i = n - 1; i >= 0; i--) {
// params[i] = workingState.pop();
// }
Language lang = dexCFG.getMethod().getDeclaringClass().getClassLoader().getLanguage();
// TODO: check that the signature needed by findOrCreate can use the descriptor
MethodReference m = MethodReference.findOrCreate(lang, loader, instruction.clazzName, instruction.methodName, instruction.descriptor);
//((DexIClass)dexCFG.getDexMethod().getDeclaringClass()).getSuperclass().get
// MethodReference m = ((DexIClass)dexCFG.getDexMethod().getDeclaringClass()).loader.lookupClass(TypeName.findOrCreate(instruction.clazzName)).
// this.myClass.loader.lookupClass(TypeName.findOrCreate(cname)),
// ((Instruction21c)inst).getRegisterA()));
IInvokeInstruction.IDispatch code = instruction.getInvocationCode();
CallSiteReference site = CallSiteReference.make(getCurrentProgramCounter(), m, code);
int exc = reuseOrCreateException();
setLocal(dexCFG.getDexMethod().getExceptionReg(), exc);
int n = instruction.args.length;
for (int i = 0; i < m.getNumberOfParameters(); i++)
if (m.getParameterType(i) == TypeReference.Double || m.getParameterType(i) == TypeReference.Long)
n--;
int[] params = new int[n];
int arg_i = 0;
//there is no "this" parameter when calling this invoke call
if (n == m.getNumberOfParameters()) {
for (int i = 0; i < n; i++) {
params[i] = workingState.getLocal(instruction.args[arg_i]);
if (m.getParameterType(i) == TypeReference.Double || m.getParameterType(i) == TypeReference.Long)
arg_i++;
arg_i++;
}
}
//there is a "this" parameter in this invoke call
else if (n == m.getNumberOfParameters()+1) {
params[0] = workingState.getLocal(instruction.args[0]);
arg_i = 1;
for (int i = 0; i < (n-1); i++) {
params[i+1] = workingState.getLocal(instruction.args[arg_i]);
if (m.getParameterType(i) == TypeReference.Double || m.getParameterType(i) == TypeReference.Long)
arg_i++;
arg_i++;
}
}
//this should not happen
else
throw new UnsupportedOperationException("visitInvoke DexSSABuilder, error");
if(m.getReturnType().equals(TypeReference.Void))
{
SSAInstruction inst = insts.InvokeInstruction(getCurrentInstructionIndex(), params, exc, site, null);
//System.out.println("Emitting(1) InvokeInstruction: "+inst);
emitInstruction(inst);
} else {
int result = reuseOrCreateDef();
assert result != -1;
// TODO: check that this return register is correct
//I think it be registerCount() or registerCount()+1
// int dest = dexCFG.getDexMethod().regBank.getReturnReg().regID;
int dest = dexCFG.getDexMethod().getReturnReg();
setLocal(dest, result);
SSAInstruction inst = insts.InvokeInstruction(getCurrentInstructionIndex(), result, params, exc, site, null);
//System.out.println("Emitting(2) InvokeInstruction: "+inst);
emitInstruction(inst);
}
// if (instruction.getPushedWordSize() > 0) {
// int result = reuseOrCreateDef();
// workingState.push(result);
// emitInstruction(insts.InvokeInstruction(result, params, exc, site));
// } else {
// emitInstruction(insts.InvokeInstruction(params, exc, site));
// }
// TODO: can other methods do indirect writes to a dex method?
// doIndirectWrites(bytecodeIndirections.indirectlyWrittenLocals(getCurrentInstructionIndex()), -1);
}
// Dex doesn't have local load or store
// @Override
// public void visitLocalLoad(ILoadInstruction instruction) {
// if (instruction.isAddressOf()) {
// int result = reuseOrCreateDef();
//
// int t = workingState.getLocal(instruction.getVarIndex());
// if (t == -1) {
// doIndirectWrites(new int[]{instruction.getVarIndex()}, -1);
// t = workingState.getLocal(instruction.getVarIndex());
// }
//
// TypeReference type = ShrikeUtil.makeTypeReference(loader, instruction.getType());
// emitInstruction(insts.AddressOfInstruction(result, t, type));
// workingState.push(result);
// } else {
// super.visitLocalLoad(instruction);
// }
// }
//
// /*
// * @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitLocalStore(com.ibm.wala.shrikeBT.StoreInstruction)
// */
// @Override
// public void visitLocalStore(IStoreInstruction instruction) {
// if (localMap != null) {
// localMap.startRange(getCurrentInstructionIndex(), instruction.getVarIndex(), workingState.peek());
// }
// super.visitLocalStore(instruction);
// }
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitMonitor(MonitorInstruction)
*/
@Override
public void visitMonitor(Monitor instruction) {
int ref = workingState.getLocal(instruction.object);
// int ref = workingState.pop();
emitInstruction(insts.MonitorInstruction(getCurrentInstructionIndex(), ref, instruction.enter));
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitNew(NewInstruction)
*/
@Override
public void visitNew(New instruction) {
int dest = instruction.destination;
int result = reuseOrCreateDef();
// TypeReference t = ShrikeUtil.makeTypeReference(loader, instruction.getType());
// NewSiteReference ref = NewSiteReference.make(getCurrentProgramCounter(), t);
// if (t.isArrayType()) {
// int[] sizes = new int[instruction.getArrayBoundsCount()];
// for (int i = 0; i < instruction.getArrayBoundsCount(); i++) {
// sizes[instruction.getArrayBoundsCount() - 1 - i] = workingState.pop();
// }
// emitInstruction(insts.NewInstruction(result, ref, sizes));
// } else {
emitInstruction(insts.NewInstruction(getCurrentInstructionIndex(), result, instruction.newSiteRef));
// popN(instruction);
// }
setLocal(dest, result);
// workingState.push(result);
}
@Override
public void visitNewArray(NewArray instruction)
{
int dest = instruction.destination;
int result = reuseOrCreateDef();
int[] sizes = new int[instruction.sizes.length];
for(int i = 0; i < instruction.sizes.length; i++)
{
sizes[i] = workingState.getLocal(instruction.sizes[i]);
}
emitInstruction(insts.NewInstruction(getCurrentInstructionIndex(), result, instruction.newSiteRef, sizes));
setLocal(dest, result);
}
@Override
public void visitNewArrayFilled(NewArrayFilled instruction)
{
int dest = instruction.destination;
int result = reuseOrCreateDef();
int[] sizes = new int[instruction.sizes.length];
for(int i = 0; i < instruction.sizes.length; i++)
{
sizes[i] = symbolTable.getConstant(instruction.sizes[i]);
}
emitInstruction(insts.NewInstruction(getCurrentInstructionIndex(), result, instruction.newSiteRef, sizes));
setLocal(dest, result);
/*
* we need to emit these instructions somehow, but for now this clobbers the emitInstruction mechanism
*
for (int i = 0; i < instruction.args.length; i++)
{
int value = workingState.getLocal(instruction.args[i]);
int index = symbolTable.getConstant(i);
int arrayRef = result;
TypeReference t = instruction.myType;
emitInstruction(insts.ArrayStoreInstruction(getCurrentInstructionIndex(), arrayRef, index, value, t));
}
*/
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitGet(IGetInstruction)
*/
@Override
public void visitPutField(PutField instruction) {
int value = workingState.getLocal(instruction.source);
FieldReference f = FieldReference.findOrCreate(loader, instruction.clazzName, instruction.fieldName, instruction.fieldType);
// int value = workingState.pop();
if (instruction instanceof PutField.PutStaticField) {
// if (instruction.isStatic()) {
emitInstruction(insts.PutInstruction(getCurrentInstructionIndex(), value, f));
} else if (instruction instanceof PutField.PutInstanceField) {
// } else {
int ref = workingState.getLocal(((PutField.PutInstanceField)instruction).instance);
// int ref = workingState.pop();
emitInstruction(insts.PutInstruction(getCurrentInstructionIndex(), ref, value, f));
} else {
throw new IllegalArgumentException("Unknown subclass of PutField: "+instruction);
}
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitReturn(ReturnInstruction)
*/
@Override
public void visitReturn(Return instruction) {
if(instruction instanceof Return.ReturnDouble)
{
// TODO: figure out how to return a double
Return.ReturnDouble retD = (Return.ReturnDouble)instruction;
int result = workingState.getLocal(retD.source1);
// boolean isPrimitive = symbolTable.isLongConstant(result) || symbolTable.isDoubleConstant(result);
boolean isPrimitive = true;
emitInstruction(insts.ReturnInstruction(getCurrentInstructionIndex(), result, isPrimitive));
// throw new UnsupportedOperationException("can't yet support returning doubles");
} else if (instruction instanceof Return.ReturnSingle)
{
Return.ReturnSingle retS = (Return.ReturnSingle)instruction;
int result = workingState.getLocal(retS.source);
// TODO: figure out if this is primitive or not
//boolean isPrimitive = false;
boolean isPrimitive = retS.isPrimitive();
emitInstruction(insts.ReturnInstruction(getCurrentInstructionIndex(), result, isPrimitive));
} else if (instruction instanceof Return.ReturnVoid)
{
emitInstruction(insts.ReturnInstruction(getCurrentInstructionIndex()));
}
// if (instruction.getPoppedCount() == 1) {
// int result = workingState.pop();
// TypeReference t = ShrikeUtil.makeTypeReference(loader, instruction.getType());
// emitInstruction(insts.ReturnInstruction(result, t.isPrimitiveType()));
// } else {
// emitInstruction(insts.ReturnInstruction());
// }
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitShift(IShiftInstruction)
*/
// TODO: this is just a binary operation
// @Override
// public void visitShift(IShiftInstruction instruction) {
// int val2 = workingState.pop();
// int val1 = workingState.pop();
// int result = reuseOrCreateDef();
// workingState.push(result);
// emitInstruction(insts.BinaryOpInstruction(instruction.getOperator(), false, instruction.isUnsigned(), result, val1, val2,
// true));
// }
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitSwitch(SwitchInstruction)
*/
@Override
public void visitSwitch(Switch instruction) {
int val = workingState.getLocal(instruction.regA);
// int val = workingState.pop();
// TODO: figure out if the switch offset should refer to a pc offset or an instruction id or what
emitInstruction(insts.SwitchInstruction(getCurrentInstructionIndex(), val, instruction.getDefaultLabel(), instruction.getCasesAndLabels()));
}
private Dominators<ISSABasicBlock> dom = null;
@SuppressWarnings("unused")
private int findRethrowException() {
int index = getCurrentInstructionIndex();
SSACFG.BasicBlock bb = cfg.getBlockForInstruction(index);
if (bb.isCatchBlock()) {
SSACFG.ExceptionHandlerBasicBlock newBB = (SSACFG.ExceptionHandlerBasicBlock) bb;
SSAGetCaughtExceptionInstruction s = newBB.getCatchInstruction();
return s.getDef();
} else {
// TODO: should we really use dominators here? maybe it would be cleaner to propagate
// the notion of 'current exception to rethrow' using the abstract interpreter.
if (dom == null) {
dom = Dominators.make(cfg, cfg.entry());
}
ISSABasicBlock x = bb;
while (x != null) {
if (x.isCatchBlock()) {
SSACFG.ExceptionHandlerBasicBlock newBB = (SSACFG.ExceptionHandlerBasicBlock) x;
SSAGetCaughtExceptionInstruction s = newBB.getCatchInstruction();
return s.getDef();
} else {
x = dom.getIdom(x);
}
}
// assert false;
return -1;
}
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitThrow(ThrowInstruction)
*/
@Override
public void visitThrow(Throw instruction) {
int throwable = workingState.getLocal(instruction.throwable);
assert symbolTable.getMaxValueNumber() >= throwable;
emitInstruction(insts.ThrowInstruction(getCurrentInstructionIndex(), throwable));
// if (instruction.isRethrow()) {
// workingState.clearStack();
// emitInstruction(insts.ThrowInstruction(findRethrowException()));
// } else {
// int exception = workingState.pop();
// workingState.clearStack();
// workingState.push(exception);
// emitInstruction(insts.ThrowInstruction(exception));
// }
}
/**
* @see com.ibm.wala.shrikeBT.IInstruction.Visitor#visitUnaryOp(IUnaryOpInstruction)
*/
@Override
public void visitUnaryOperation(UnaryOperation instruction) {
if (instruction.op == UnaryOperation.OpID.MOVE_EXCEPTION) {
int idx = getCurrentInstructionIndex();
int bbidx = dexCFG.getBlockForInstruction(idx).getNumber();
ExceptionHandlerBasicBlock newBB = (ExceptionHandlerBasicBlock) cfg.getBasicBlock(bbidx);
SSAGetCaughtExceptionInstruction s = newBB.getCatchInstruction();
int exceptionValue;
if (s == null) {
exceptionValue = symbolTable.newSymbol();
s = insts.GetCaughtExceptionInstruction(newBB.getLastInstructionIndex(), bbidx, exceptionValue);
newBB.setCatchInstruction(s);
} else {
exceptionValue = s.getException();
}
setLocal(instruction.destination, exceptionValue);
return;
}
//System.out.println("Instruction: " + getCurrentInstructionIndex());
int val = workingState.getLocal(instruction.source);
// int val = workingState.pop();
// workingState.push(result);
if(instruction.isConversion())
{
TypeReference fromType, toType;
boolean overflows = false;
// TODO: figure out if any of these can overflow
switch(instruction.op)
{
case DOUBLETOLONG:
fromType = TypeReference.Double;
toType = TypeReference.Long;
break;
case DOUBLETOFLOAT:
fromType = TypeReference.Double;
toType = TypeReference.Float;
break;
case INTTOBYTE:
fromType = TypeReference.Int;
toType = TypeReference.Byte;
break;
case INTTOCHAR:
fromType = TypeReference.Int;
toType = TypeReference.Char;
break;
case INTTOSHORT:
fromType = TypeReference.Int;
toType = TypeReference.Short;
break;
case DOUBLETOINT:
fromType = TypeReference.Double;
toType = TypeReference.Int;
break;
case FLOATTODOUBLE:
fromType = TypeReference.Float;
toType = TypeReference.Double;
break;
case FLOATTOLONG:
fromType = TypeReference.Float;
toType = TypeReference.Long;
break;
case FLOATTOINT:
fromType = TypeReference.Float;
toType = TypeReference.Int;
break;
case LONGTODOUBLE:
fromType = TypeReference.Long;
toType = TypeReference.Double;
break;
case LONGTOFLOAT:
fromType = TypeReference.Long;
toType = TypeReference.Float;
break;
case LONGTOINT:
fromType = TypeReference.Long;
toType = TypeReference.Int;
break;
case INTTODOUBLE:
fromType = TypeReference.Int;
toType = TypeReference.Double;
break;
case INTTOFLOAT:
fromType = TypeReference.Int;
toType = TypeReference.Float;
break;
case INTTOLONG:
fromType = TypeReference.Int;
toType = TypeReference.Long;
break;
default:
throw new IllegalArgumentException("unknown conversion type "+instruction.op+" in unary instruction: "+instruction);
}
int dest = instruction.destination;
int result = reuseOrCreateDef();
setLocal(dest, result);
emitInstruction(insts.ConversionInstruction(getCurrentInstructionIndex(), result, val, fromType, toType, overflows));
}
else
{
if (instruction.op == UnaryOperation.OpID.MOVE) {
setLocal(instruction.destination, workingState.getLocal(instruction.source));
}
else if (instruction.op == UnaryOperation.OpID.MOVE_WIDE) {
setLocal(instruction.destination, workingState.getLocal(instruction.source));
if (instruction.source == dexCFG.getDexMethod().getReturnReg())
setLocal(instruction.destination+1, workingState.getLocal(instruction.source));
else
setLocal(instruction.destination+1, workingState.getLocal(instruction.source+1));
} else {
int dest = instruction.destination;
int result = reuseOrCreateDef();
setLocal(dest, result);
emitInstruction(insts.UnaryOpInstruction(getCurrentInstructionIndex(), instruction.getOperator(), result, val));
}
}
}
// dex doesn't have indirect reads
// private void doIndirectReads(int[] locals) {
// for(int i = 0; i < locals.length; i++) {
// ssaIndirections.setUse(getCurrentInstructionIndex(), new ShrikeLocalName(locals[i]), workingState.getLocal(locals[i]));
// }
// }
// dex doesn't have load or store, even with indirection
// @Override
// public void visitLoadIndirect(ILoadIndirectInstruction instruction) {
// int addressVal = workingState.pop();
// int result = reuseOrCreateDef();
// doIndirectReads(bytecodeIndirections.indirectlyReadLocals(getCurrentInstructionIndex()));
// TypeReference t = ShrikeUtil.makeTypeReference(loader, instruction.getPushedType(null));
// emitInstruction(insts.LoadIndirectInstruction(result, t, addressVal));
// workingState.push(result);
// }
//
// private void doIndirectWrites(int[] locals, int rval) {
// for(int i = 0; i < locals.length; i++) {
// ShrikeLocalName name = new ShrikeLocalName(locals[i]);
// int idx = getCurrentInstructionIndex();
// if (ssaIndirections.getDef(idx, name) == -1) {
// ssaIndirections.setDef(idx, name, rval==-1? symbolTable.newSymbol(): rval);
// }
// workingState.setLocal(locals[i], ssaIndirections.getDef(idx, name));
// }
// }
//
// @Override
// public void visitStoreIndirect(IStoreIndirectInstruction instruction) {
// int val = workingState.pop();
// int addressVal = workingState.pop();
// doIndirectWrites(bytecodeIndirections.indirectlyWrittenLocals(getCurrentInstructionIndex()), val);
// TypeReference t = ShrikeUtil.makeTypeReference(loader, instruction.getType());
// emitInstruction(insts.StoreIndirectInstruction(addressVal, val, t));
// }
}
/**
* @param piCause
* @param ref
*/
private void reuseOrCreatePi(SSAInstruction piCause, int ref) {
int n = getCurrentInstructionIndex();
SSACFG.BasicBlock bb = cfg.getBlockForInstruction(n);
BasicBlock path = getCurrentSuccessor();
int outNum = dexCFG.getNumber(path);
SSAPiInstruction pi = bb.getPiForRefAndPath(ref, path);
if (pi == null) {
pi = insts.PiInstruction(getCurrentInstructionIndex(), symbolTable.newSymbol(), ref, bb.getNumber(), outNum, piCause);
bb.addPiForRefAndPath(ref, path, pi);
}
workingState.replaceValue(ref, pi.getDef());
}
// private void maybeInsertPi(int val) {
// if ((addPiForFieldSelect) && (creators.length > val) && (creators[val] instanceof SSAGetInstruction)
// && !((SSAGetInstruction) creators[val]).isStatic()) {
// reuseOrCreatePi(creators[val], val);
// } else if ((addPiForDispatchSelect)
// && (creators.length > val)
// && (creators[val] instanceof SSAInvokeInstruction)
// && (((SSAInvokeInstruction) creators[val]).getInvocationCode() == IInvokeInstruction.Dispatch.VIRTUAL ||
// ((SSAInvokeInstruction) creators[val])
// .getInvocationCode() == IInvokeInstruction.Dispatch.INTERFACE)) {
// reuseOrCreatePi(creators[val], val);
// }
// }
private void maybeInsertPi(SSAAbstractInvokeInstruction call) {
if (piNodePolicy != null) {
Pair<Integer, SSAInstruction> pi = piNodePolicy.getPi(call, symbolTable);
if (pi != null) {
reuseOrCreatePi(pi.snd, pi.fst);
}
}
}
private void maybeInsertPi(SSAConditionalBranchInstruction cond) {
if (piNodePolicy != null) {
Pair<Integer, SSAInstruction> pi = piNodePolicy.getPi(cond, getDef(cond.getUse(0)), getDef(cond.getUse(1)), symbolTable);
if (pi != null) {
reuseOrCreatePi(pi.snd, pi.fst);
}
}
}
private SSAInstruction getDef(int vn) {
if (vn < creators.length) {
return creators[vn];
} else {
return null;
}
}
class EdgeVisitor extends Visitor {
@Override
public void visitInvoke(Invoke instruction) {
maybeInsertPi((SSAAbstractInvokeInstruction) getCurrentInstruction());
}
@Override
public void visitBranch(Branch instruction) {
maybeInsertPi((SSAConditionalBranchInstruction) getCurrentInstruction());
}
}
@Override
public Instruction[] getInstructions() {
return dexCFG.getDexMethod().getDexInstructions();
}
}
/**
* Build the IR
*/
public void build() {
try {
solve();
if (localMap != null) {
localMap.finishLocalMap(this);
}
} catch (AssertionError e) {
System.err.println("When handling method " + method.getReference());
e.printStackTrace();
//throw e;
}
}
public SSA2LocalMap getLocalMap() {
return localMap;
}
public ShrikeIndirectionData getIndirectionData() {
return shrikeIndirections;
}
/**
* A logical mapping from &lt;pc, valueNumber&gt; -&gt; local number Note: make sure this class remains static: this persists as part of
* the IR!!
*/
private static class SSA2LocalMap implements com.ibm.wala.ssa.IR.SSA2LocalMap {
private final DexCFG dexCFG;
/**
* Mapping Integer -&gt; IntPair where p maps to (vn,L) iff we've started a range at pc p where value number vn corresponds to
* local L
*/
private final IntPair[] localStoreMap;
/**
* For each basic block i and local j, block2LocalState[i][j] gives the contents of local j at the start of block i
*/
private final int[][] block2LocalState;
/**
* maximum number of locals used at any program point
*/
private final int maxLocals;
/**
* @param nInstructions number of instructions in the bytecode for this method
* @param nBlocks number of basic blocks in the CFG
*/
SSA2LocalMap(DexCFG dexCfg, int nInstructions, int nBlocks, int maxLocals) {
dexCFG = dexCfg;
localStoreMap = new IntPair[nInstructions];
block2LocalState = new int[nBlocks][];
this.maxLocals = maxLocals;
}
/**
* Record the beginning of a new range, starting at the given program counter, in which a particular value number corresponds to
* a particular local number
*/
@SuppressWarnings("unused")
void startRange(int pc, int localNumber, int valueNumber) {
int max = ((DexIMethod)dexCFG.getMethod()).getMaxLocals();
if (localNumber >= max) {
assert false : "invalid local " + localNumber + ">" + max;
}
localStoreMap[pc] = new IntPair(valueNumber, localNumber);
}
/**
* Finish populating the map of local variable information
*/
private void finishLocalMap(DexSSABuilder builder) {
for (BasicBlock bb : dexCFG) {
MachineState S = builder.getIn(bb);
int number = bb.getNumber();
block2LocalState[number] = S.getLocals();
}
}
/**
* @param index - index into IR instruction array
* @param vn - value number
*/
@Override
public String[] getLocalNames(int index, int vn) {
try {
if (!dexCFG.getMethod().hasLocalVariableTable()) {
return null;
} else {
int[] localNumbers = findLocalsForValueNumber(index, vn);
if (localNumbers == null) {
return null;
} else {
DexIMethod m = dexCFG.getDexMethod();
String[] result = new String[localNumbers.length];
for (int i = 0; i < localNumbers.length; i++) {
result[i] = m.getLocalVariableName(m.getBytecodeIndex(index), localNumbers[i]);
}
return result;
}
}
} catch (Exception e) {
e.printStackTrace();
Assertions.UNREACHABLE();
return null;
}
}
/**
* @param pc a program counter (index into ShrikeBT instruction array)
* @param vn a value number
* @return if we know that immediately after the given program counter, v_vn corresponds to some set of locals, then return an
* array of the local numbers. else return null.
*/
private int[] findLocalsForValueNumber(int pc, int vn) {
IBasicBlock<Instruction> bb = dexCFG.getBlockForInstruction(pc);
int firstInstruction = bb.getFirstInstructionIndex();
// walk forward from the first instruction to reconstruct the
// state of the locals at this pc
int[] locals = block2LocalState[bb.getNumber()];
if (locals == null) {
locals = allocateNewLocalsArray();
}
for (int i = firstInstruction; i <= pc; i++) {
if (localStoreMap[i] != null) {
IntPair p = localStoreMap[i];
locals[p.getY()] = p.getX();
}
}
return extractIndices(locals, vn);
}
public int[] allocateNewLocalsArray() {
int[] result = new int[maxLocals];
for (int i = 0; i < maxLocals; i++) {
result[i] = OPTIMISTIC ? TOP : BOTTOM;
}
return result;
}
/**
* @return the indices i s.t. x[i] == y, or null if none found.
*/
private static int[] extractIndices(int[] x, int y) {
int count = 0;
for (int element : x) {
if (element == y) {
count++;
}
}
if (count == 0) {
return null;
} else {
int[] result = new int[count];
int j = 0;
for (int i = 0; i < x.length; i++) {
if (x[i] == y) {
result[j++] = i;
}
}
return result;
}
}
}
}