
soot.dava.toolkits.base.AST.structuredAnalysis.CP Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of soot Show documentation
Show all versions of soot Show documentation
A Java Optimization Framework
package soot.dava.toolkits.base.AST.structuredAnalysis;
/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 1997 - 2018 Raja Vallée-Rai and others
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import soot.BooleanType;
import soot.ByteType;
import soot.CharType;
import soot.DoubleType;
import soot.FloatType;
import soot.IntType;
import soot.Local;
import soot.LongType;
import soot.PrimType;
import soot.ShortType;
import soot.SootField;
import soot.Type;
import soot.Value;
import soot.dava.DavaFlowAnalysisException;
import soot.dava.internal.AST.ASTBinaryCondition;
import soot.dava.internal.AST.ASTCondition;
import soot.dava.internal.AST.ASTIfElseNode;
import soot.dava.internal.AST.ASTIfNode;
import soot.dava.internal.AST.ASTMethodNode;
import soot.dava.internal.AST.ASTUnaryBinaryCondition;
import soot.dava.internal.AST.ASTUnaryCondition;
import soot.dava.internal.javaRep.DNotExpr;
import soot.dava.toolkits.base.AST.interProcedural.ConstantFieldValueFinder;
import soot.jimple.BinopExpr;
import soot.jimple.ConditionExpr;
import soot.jimple.DefinitionStmt;
import soot.jimple.FieldRef;
import soot.jimple.Stmt;
public class CP extends StructuredAnalysis {
/*
* Constant Propagation:
*
* Step 1: Sets of CPTuple (className, CPVariable, value) where: CPVariable contains a local or SootField
*
* Step 2: A local or SootField has a constant value at a program point p if on all program paths from the start of the
* method to point p the local or Sootfield has only been assigned this constant value.
*
* Step 3: Forward Analysis
*
* Step 4: Intersection (See intersection method in CPFlowSet)
*
* Step 5: See method processStatement
*
* Step 6: out(start) = all locals set to bottom(they shouldnt be present in the initialSet all formals set to Top, all
* constant fields set to constant values
*
* newInitialFlow: all locals and formals set to Top, all constant fields set to constant values remember new InitialFlow
* is ONLY used for input to catchBodies
*
* Any local or field which is not in the flow set at any time is necessarily bottom
*
*
* knowing how a condition evaluates can give us useful insight to the values of variables Handle this for a == b where
* both a and b are primtype and special case handle it for A where A is a unary boolean condition
*
* See following over-riden methods:
*
* public Object processASTIfElseNode(ASTIfElseNode node,Object input) public Object processASTIfNode(ASTIfNode node,Object
* input) public Object processASTSwitchNode(ASTSwitchNode node,Object input)
*/
ArrayList constantFieldTuples = null; // VariableTuples of
// constantFields
ArrayList formals = null; // VariableTuples for formals initially
// set to T
ArrayList locals = null; // VariableTuples for locals initially set
// to default
ArrayList initialInput = null; // VariableTuples of constantFields,
// locals set to 0 and formals set
// to T
ASTMethodNode methodNode = null;
String localClassName = null;
/*
* The start of the analysis takes place whenever this constructor is invoked
*/
public CP(ASTMethodNode analyze, HashMap constantFields,
HashMap classNameFieldNameToSootFieldMapping) {
super();
/*
* DEBUG = true; DEBUG_IF = true; DEBUG_WHILE = true; DEBUG_STATEMENTS = true;
*/
this.methodNode = analyze;
localClassName = analyze.getDavaBody().getMethod().getDeclaringClass().getName();
// Create a list of VariableValueTuples for all the constantFields
createConstantFieldsList(constantFields, classNameFieldNameToSootFieldMapping);
// Create the complete list of vars to go into constant propagation
createInitialInput();
// input to constant propagation should not be an empty flow set it is
// the set of all constant fields, locals assigned 0 and formals
// assigned T
CPFlowSet initialSet = new CPFlowSet();
Iterator it = initialInput.iterator();
while (it.hasNext()) {
initialSet.add(it.next());
}
// System.out.println("Initial set"+initialSet.toString());
CPFlowSet result = (CPFlowSet) process(analyze, initialSet);
// System.out.println("Last result :"+result.toString());
}
/*
* constant fields added with KNOWN CONSTANT VALUE formals added with TOP locals added with 0 other fields IGNORED
*/
public void createInitialInput() {
initialInput = new ArrayList();
// adding constant fields
initialInput.addAll(constantFieldTuples);
// String className =
// analyze.getDavaBody().getMethod().getDeclaringClass().getName();
// adding formals
formals = new ArrayList();
// System.out.println("Adding following formals: with TOP");
Collection col = methodNode.getDavaBody().get_ParamMap().values();
Iterator it = col.iterator();
while (it.hasNext()) {
Object temp = it.next();
if (temp instanceof Local) {
Local tempLocal = (Local) temp;
if (!(tempLocal.getType() instanceof PrimType)) {
continue;
}
CPVariable newVar = new CPVariable(tempLocal);
// new tuple set to top since this is a formal and we dont know
// what value we will get into it
CPTuple newTuple = new CPTuple(localClassName, newVar, true);
initialInput.add(newTuple);
formals.add(newTuple);
// System.out.print("\t"+tempLocal.getName());
}
}
// System.out.println();
// adding locals
List decLocals = methodNode.getDeclaredLocals();
it = decLocals.iterator();
locals = new ArrayList();
// System.out.println("Adding following locals with default values:");
while (it.hasNext()) {
Object temp = it.next();
if (temp instanceof Local) {
Local tempLocal = (Local) temp;
Type localType = tempLocal.getType();
if (!(localType instanceof PrimType)) {
continue;
}
CPVariable newVar = new CPVariable(tempLocal);
// store the default value into this object
Object value;
// locals value is set to the default value that it can have
// depending on its type
if (localType instanceof BooleanType) {
value = new Boolean(false);
} else if (localType instanceof ByteType) {
value = new Integer(0);
} else if (localType instanceof CharType) {
value = new Integer(0);
} else if (localType instanceof DoubleType) {
value = new Double(0);
} else if (localType instanceof FloatType) {
value = new Float(0);
} else if (localType instanceof IntType) {
value = new Integer(0);
} else if (localType instanceof LongType) {
value = new Long(0);
} else if (localType instanceof ShortType) {
value = new Integer(0);
} else {
throw new DavaFlowAnalysisException("Unknown PrimType");
}
CPTuple newTuple = new CPTuple(localClassName, newVar, value);
/*
* Commenting the next line since we dont want initial Input to have any locals in it all locals are considered
* bottom initially
*/
// initialInput.add(newTuple);
locals.add(newTuple);
// System.out.print("\t"+tempLocal.getName());
} // was a local
}
// System.out.println();
}
/*
* Uses the results of the ConstantValueFinder to create a list of constantField CPTuple
*/
private void createConstantFieldsList(HashMap constantFields,
HashMap classNameFieldNameToSootFieldMapping) {
constantFieldTuples = new ArrayList();
Iterator it = constantFields.keySet().iterator();
// System.out.println("Adding constant fields to initial set: ");
while (it.hasNext()) {
String combined = it.next();
int temp = combined.indexOf(ConstantFieldValueFinder.combiner, 0);
if (temp > 0) {
String className = combined.substring(0, temp);
// String fieldName = combined.substring(temp+
// ConstantFieldValueFinder.combiner.length());
SootField field = classNameFieldNameToSootFieldMapping.get(combined);
// String fieldName = field.getName();
if (!(field.getType() instanceof PrimType)) {
// we only care about PrimTypes
continue;
}
// object type is double float long boolean or integer
Object value = constantFields.get(combined);
CPVariable var = new CPVariable(field);
CPTuple newTuples = new CPTuple(className, var, value);
constantFieldTuples.add(newTuples);
// System.out.print("Class: "+className +
// " Field: "+fieldName+" Value: "+value+" ");
} else {
throw new DavaFlowAnalysisException("Second argument of VariableValuePair not a variable");
}
}
// System.out.println("");
}
@Override
public DavaFlowSet emptyFlowSet() {
return new CPFlowSet();
}
/*
* Setting the mergetype to intersection but since we are going to have constantpropagation flow sets the intersection
* method for this flow set will be invoked which defines the correct semantics of intersection for the case of constant
* propagation
*/
public void setMergeType() {
MERGETYPE = INTERSECTION;
}
/*
* newInitialFlow is invoked for the input set of the catchBodies
*
* formals initialized to top since we dont know what has happened so far in the body locals initialized to top since we
* dont know what has happened so far in the method body constant fields present with their constant value since that never
* changes
*/
@Override
public DavaFlowSet newInitialFlow() {
CPFlowSet flowSet = new CPFlowSet();
// formals and locals should be both initialized to top since we dont
// know what has happened so far in the body
ArrayList localsAndFormals = new ArrayList();
localsAndFormals.addAll(formals);
localsAndFormals.addAll(locals);
Iterator it = localsAndFormals.iterator();
while (it.hasNext()) {
CPTuple tempTuple = (CPTuple) it.next().clone();
// just making sure all are set to Top
if (!tempTuple.isTop()) {
tempTuple.setTop();
}
flowSet.add(tempTuple);
}
// constant fields should be present with their constant value since
// that never changes
it = constantFieldTuples.iterator();
while (it.hasNext()) {
flowSet.add(it.next());
}
return flowSet;
}
@Override
public DavaFlowSet cloneFlowSet(DavaFlowSet flowSet) {
if (flowSet instanceof CPFlowSet) {
return ((CPFlowSet) flowSet).clone();
} else {
throw new RuntimeException("cloneFlowSet not implemented for other flowSet types" + flowSet.toString());
}
}
/*
* Since we are only keeping track of constant fields now there will be no kill if we were keeping track of fields then we
* woul dneed to kill all non constant fields if there was an invokeExpr
*/
@Override
public DavaFlowSet processUnaryBinaryCondition(ASTUnaryBinaryCondition cond, DavaFlowSet input) {
if (!(input instanceof CPFlowSet)) {
throw new RuntimeException("processCondition is not implemented for other flowSet types" + input.toString());
}
CPFlowSet inSet = (CPFlowSet) input;
return inSet;
}
/*
* Has no effect whatsoever on the analysis
*/
@Override
public DavaFlowSet processSynchronizedLocal(Local local, DavaFlowSet input) {
if (!(input instanceof CPFlowSet)) {
throw new RuntimeException("processSynchronized is not implemented for other flowSet types" + input.toString());
}
DavaFlowSet inSet = (DavaFlowSet) input;
return inSet;
}
/*
* no effect on the analysis since we are keeping track of non constant fields only if we were tracking other fields then
* If the value contained an invoke expr top all non constant fields similar to as done for unarybinary condition
*/
@Override
public DavaFlowSet processSwitchKey(Value key, DavaFlowSet input) {
if (!(input instanceof CPFlowSet)) {
throw new RuntimeException("processCondition is not implemented for other flowSet types" + input.toString());
}
CPFlowSet inSet = (CPFlowSet) input;
return inSet;
}
/*
* x = expr;
*
* expr is a constant
*
* epr is a local (Note we are not going to worry about fieldRefs)
*
* expr is a Unary op with neg followed by a local or field
*
* expr is actually exp1 op expr2 ..... ( x = x+1, y = i * 3, x = 3 *0
*
* expr contains an invokeExpr
*/
@Override
public DavaFlowSet processStatement(Stmt s, DavaFlowSet input) {
if (!(input instanceof CPFlowSet)) {
throw new RuntimeException("processStatement is not implemented for other flowSet types");
}
CPFlowSet inSet = (CPFlowSet) input;
if (inSet == NOPATH) {
return inSet;
}
if (!(s instanceof DefinitionStmt)) {
return inSet;
}
DefinitionStmt defStmt = (DefinitionStmt) s;
// x = expr;
// confirm that the left side is a local with a primitive type
Value left = defStmt.getLeftOp();
if (!(left instanceof Local && ((Local) left).getType() instanceof PrimType)) {
return inSet;
}
// left is a primitive primitive local
CPFlowSet toReturn = (CPFlowSet) cloneFlowSet(inSet);
/*
* KILL ANY PREVIOUS VALUE OF this local as this is an assignment Remember the returned value can be null if the element
* was not found or it was TOP
*/
Object killedValue = killButGetValueForUse((Local) left, toReturn);
Value right = defStmt.getRightOp();
Object value = CPHelper.isAConstantValue(right);
if (value != null) {
// EXPR IS A CONSTANT
if (left.getType() instanceof BooleanType) {
Integer tempValue = (Integer) value;
if (tempValue.intValue() == 0) {
value = new Boolean(false);
} else {
value = new Boolean(true);
}
}
addOrUpdate(toReturn, (Local) left, value);
} else {
// EXPR IS NOT A CONSTANT
handleMathematical(toReturn, (Local) left, right, killedValue);
}
return toReturn;
}
/*
* The returned value is the current constant associated with left. Integer/Long/Double/Float/Boolean The returned value
* can also be null if the element was not found or it was TOP
*/
public Object killButGetValueForUse(Local left, CPFlowSet toReturn) {
for (CPTuple tempTuple : toReturn) {
if (!(tempTuple.getSootClassName().equals(localClassName))) {
continue;
}
// className is the same check if the variable is the same or not
if (tempTuple.containsLocal()) { // remmeber the sets contain
// constant fields also
Local tempLocal = tempTuple.getVariable().getLocal();
if (left.getName().equals(tempLocal.getName())) {
// KILL THIS SUCKA!!!
Object killedValue = tempTuple.getValue();
tempTuple.setTop();
return killedValue;
}
}
} // going through all elements of the flow set
// if this element was no where enter it with top
CPVariable newVar = new CPVariable(left);
// create the CPTuple
// System.out.println("trying to kill something which was not present so added with TOP");
CPTuple newTuple = new CPTuple(localClassName, newVar, false);
toReturn.add(newTuple);
return null;
}
/*
* Create a CPTuple for left with the val and update the toReturn set
*/
private void addOrUpdate(CPFlowSet toReturn, Local left, Object val) {
CPVariable newVar = new CPVariable(left);
CPTuple newTuple = new CPTuple(localClassName, newVar, val);
toReturn.addIfNotPresent(newTuple);
// System.out.println("DefinitionStmt checked right expr for constants"+toReturn.toString());
}
/*
* x = b where b is in the before set of the statement as a constant then we can simply say x = that constant also
*
* TODO: DONT WANT TO DO IT:::: If right expr is a unary expression see if the stuff inside is a Local
*
* x = exp1 op exp2 (check if both exp1 and exp2 are int constants
*
* killedValuse is either the constant value which left had before this assignment stmt or null if left was Top or not in
* the set
*
* handle the special case when the inputset could not find a value because its the killed value //eg. x = x+1 since we top
* x first we will never get a match IMPORTANT
*/
private void handleMathematical(CPFlowSet toReturn, Local left, Value right, Object killedValue) {
// if right expr is a local or field
Object value = isANotTopConstantInInputSet(toReturn, right);
if (value != null) {
// right was a local or field with a value other than top
// dont send value SEND A CLONE OF VALUE.....IMPORTANT!!!!
Object toSend = CPHelper.wrapperClassCloner(value);
if (toSend != null) {
addOrUpdate(toReturn, left, toSend);
}
// return if value was != null as this means that the left was a
// primitive local assigned some value from the right
return;
}
// if we get here we know that right is not a local or field whose value
// we could find in the set
if (right instanceof BinopExpr) {
Value op1 = ((BinopExpr) right).getOp1();
Value op2 = ((BinopExpr) right).getOp2();
Object op1Val = CPHelper.isAConstantValue(op1);
Object op2Val = CPHelper.isAConstantValue(op2);
if (op1Val == null) {
op1Val = isANotTopConstantInInputSet(toReturn, op1);
}
if (op2Val == null) {
op2Val = isANotTopConstantInInputSet(toReturn, op2);
}
if (op1 == left) {
// System.out.println("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>OP1 is the same as LHS");
op1Val = killedValue;
}
if (op2 == left) {
// System.out.println("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>OP2 is the same as LHS");
op2Val = killedValue;
}
if (op1Val != null && op2Val != null) {
// System.out.println("found constant values for both operands of binary expression");
if (left.getType() instanceof IntType && op1Val instanceof Integer && op2Val instanceof Integer) {
// only caring about operations on two integers and result
// is an integer
int op1IntValue = ((Integer) op1Val).intValue();
int op2IntValue = ((Integer) op2Val).intValue();
String tempStr = ((BinopExpr) right).getSymbol();
if (tempStr.length() > 1) {
char symbol = tempStr.charAt(1);
// System.out.println("found symbol "+symbol+" for the operands of binary expression");
int newValue = 0;
boolean set = false;
switch (symbol) {
case '+':
// System.out.println("Adding");
newValue = op1IntValue + op2IntValue;
set = true;
break;
case '-':
// System.out.println("Subtracting");
newValue = op1IntValue - op2IntValue;
set = true;
break;
case '*':
// System.out.println("Multiplying");
newValue = op1IntValue * op2IntValue;
set = true;
break;
}
if (set) {
// we have our new value
Integer newValueObject = new Integer(newValue);
addOrUpdate(toReturn, left, newValueObject);
return;
}
}
}
} else {
// System.out.println("atleast one value is not constant so cant simplify expression");
}
}
// System.out.println("DefinitionStmt checked right expr for mathematical stuff"+toReturn.toString());
}
/*
* Check whether it is a local or field which has a constant value (could be top) in the current inSet
*
* The method returns null if its not found or its TOP Otherwise it will return the constant value
*/
private Object isANotTopConstantInInputSet(CPFlowSet set, Value toCheck) {
if (toCheck instanceof Local || toCheck instanceof FieldRef) {
String toCheckClassName = null;
if (toCheck instanceof Local) {
toCheckClassName = localClassName;
} else {
toCheckClassName = ((FieldRef) toCheck).getField().getDeclaringClass().getName();
}
for (CPTuple tempTuple : set) {
// check that the classNames are the same
if (!(tempTuple.getSootClassName().equals(toCheckClassName))) {
// classNames are not the same no point in continuing with
// checks
continue;
}
boolean tupleFound = false;
if (tempTuple.containsLocal() && toCheck instanceof Local) {
// check they are the same Local
Local tempLocal = tempTuple.getVariable().getLocal();
if (tempLocal.getName().equals(((Local) toCheck).getName())) {
// the set does have a constant value for this local
tupleFound = true;
}
} else if (tempTuple.containsField() && toCheck instanceof FieldRef) {
SootField toCheckField = ((FieldRef) toCheck).getField();
SootField tempField = tempTuple.getVariable().getSootField();
if (tempField.getName().equals(toCheckField.getName())) {
// the set contains a constant value for this field
tupleFound = true;
}
}
if (tupleFound) {
if (tempTuple.isTop()) {
return null;
} else {
return tempTuple.getValue();
}
}
}
}
return null;
}
/*
* over-riding the StructuredFlow Analysis implementation because we want to be able to gather information about the truth
* value in the condition
*/
@Override
public DavaFlowSet processASTIfNode(ASTIfNode node, DavaFlowSet input) {
if (DEBUG_IF) {
System.out.println("Processing if node using over-ridden process if method" + input.toString());
}
;
input = processCondition(node.get_Condition(), input);
if (!(input instanceof CPFlowSet)) {
throw new DavaFlowAnalysisException("not a flow set");
}
CPFlowSet inputToBody = ((CPFlowSet) input).clone();
CPTuple tuple = checkForValueHints(node.get_Condition(), inputToBody, false);
if (tuple != null) {
// if not null, is a belief going into the if branch simply add it
// into the input set
// System.out.println(">>>>>Adding tuple because of condition"+tuple.toString());
inputToBody.addIfNotPresentButDontUpdate(tuple);
}
DavaFlowSet output1 = processSingleSubBodyNode(node, inputToBody);
if (DEBUG_IF) {
System.out.println("\n\nINPUTS TO MERGE ARE input (original):" + input.toString() + "processingBody output:"
+ output1.toString() + "\n\n\n");
}
// merge with input which tells if the cond did not evaluate to true
DavaFlowSet output2 = merge(input, output1);
// handle break
String label = getLabel(node);
DavaFlowSet temp = handleBreak(label, output2, node);
if (DEBUG_IF) {
System.out.println("Exiting if node" + temp.toString());
}
;
return temp;
}
@Override
public DavaFlowSet processASTIfElseNode(ASTIfElseNode node, DavaFlowSet input) {
if (DEBUG_IF) {
System.out.println("Processing IF-ELSE node using over-ridden process if method" + input.toString());
}
;
if (!(input instanceof CPFlowSet)) {
throw new DavaFlowAnalysisException("not a flow set");
}
// get the subBodies
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy