/* Soot - a J*va Optimization Framework
* Copyright (C) 2003 Jennifer Lhotak
*
* This library 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 library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
package soot.jimple.toolkits.annotation.parity;
import soot.*;
import soot.util.*;
import java.util.*;
import soot.jimple.*;
import soot.toolkits.graph.*;
import soot.toolkits.scalar.*;
import soot.options.*;
// STEP 1: What are we computing?
// SETS OF PAIRS of form (X, T) => Use ArraySparseSet.
//
// STEP 2: Precisely define what we are computing.
// For each statement compute the parity of all variables
// in the program.
//
// STEP 3: Decide whether it is a backwards or forwards analysis.
// FORWARDS
//
//
public class ParityAnalysis extends ForwardFlowAnalysis {
private UnitGraph g;
private final static String TOP = "top";
private final static String BOTTOM = "bottom";
private final static String EVEN = "even";
private final static String ODD = "odd";
private LiveLocals filter;
public ParityAnalysis(UnitGraph g, LiveLocals filter)
{
super(g);
this.g = g;
this.filter = filter;
filterUnitToBeforeFlow = new HashMap<Stmt, HashMap>();
buildBeforeFilterMap();
filterUnitToAfterFlow = new HashMap<Stmt, HashMap>();
doAnalysis();
}
public ParityAnalysis(UnitGraph g){
super(g);
this.g = g;
doAnalysis();
}
private void buildBeforeFilterMap(){
Iterator it = g.getBody().getUnits().iterator();
while (it.hasNext()){
Stmt s = (Stmt)it.next();
//if (!(s instanceof DefinitionStmt)) continue;
//Value left = ((DefinitionStmt)s).getLeftOp();
//if (!(left instanceof Local)) continue;
//if (!((left.getType() instanceof IntegerType) || (left.getType() instanceof LongType))) continue;
List list = filter.getLiveLocalsBefore(s);
HashMap map = new HashMap();
Iterator listIt = list.iterator();
while (listIt.hasNext()){
map.put(listIt.next(), BOTTOM);
}
filterUnitToBeforeFlow.put(s, map);
}
//System.out.println("init filtBeforeMap: "+filterUnitToBeforeFlow);
}
// STEP 4: Is the merge operator union or intersection?
//
// merge | bottom | even | odd | top
// -------+--------+--------+-------+--------
// bottom | bottom | even | odd | top
// -------+--------+--------+-------+--------
// even | even | even | top | top
// -------+--------+--------+-------+--------
// odd | odd | top | odd | top
// -------+--------+--------+-------+--------
// top | top | top | top | top
//
protected void merge(Object in1, Object in2, Object out)
{
HashMap inMap1 = (HashMap) in1;
HashMap inMap2 = (HashMap) in2;
HashMap<Object, String> outMap = (HashMap<Object, String>) out;
Set keys = inMap1.keySet();
Iterator it = keys.iterator();
while (it.hasNext()) {
Object var1 = it.next();
//System.out.println(var1);
String inVal1 = (String)inMap1.get(var1);
//System.out.println(inVal1);
String inVal2 = (String)inMap2.get(var1);
//System.out.println(inVal2);
// System.out.println("before out "+outMap.get(var1));
if (inVal2 == null){
outMap.put(var1, inVal1);
}
else if (inVal1.equals(BOTTOM)) {
outMap.put(var1, inVal2);
}
else if (inVal2.equals(BOTTOM)) {
outMap.put(var1, inVal1);
}
else if ((inVal1.equals(EVEN)) &&
(inVal2.equals(EVEN))) {
outMap.put(var1, EVEN);
}
else if ((inVal1.equals(ODD)) &&
(inVal2.equals(ODD))) {
outMap.put(var1, ODD);
}
else {
outMap.put(var1, TOP);
}
}
}
// STEP 5: Define flow equations.
// in(s) = ( out(s) minus defs(s) ) union uses(s)
//
protected void copy(Object source, Object dest) {
//System.out.println("copy");
HashMap sourceIn = (HashMap)source;
HashMap destOut = (HashMap)dest;
//dest = new HashMap();
//HashMap destOut = new HashMap();
destOut.putAll(sourceIn);
dest = destOut;
}
// Parity Tests: even + even = even
// even + odd = odd
// odd + odd = even
//
// even * even = even
// even * odd = even
// odd * odd = odd
//
// constants are tested mod 2
//
private String getParity(HashMap<Value, String> in, Value val) {
//System.out.println("get Parity in: "+in);
if ((val instanceof AddExpr) | (val instanceof SubExpr)) {
String resVal1 = getParity(in, ((BinopExpr)val).getOp1());
String resVal2 = getParity(in, ((BinopExpr)val).getOp2());
if (resVal1.equals(TOP) | resVal2.equals(TOP)) {
return TOP;
}
else if (resVal1.equals(BOTTOM) | resVal2.equals(BOTTOM)){
return BOTTOM;
}
else if (resVal1.equals(resVal2)) {
return EVEN;
}
else {
return ODD;
}
}
else if (val instanceof MulExpr) {
String resVal1 = getParity(in, ((BinopExpr)val).getOp1());
String resVal2 = getParity(in, ((BinopExpr)val).getOp2());
if (resVal1.equals(TOP) | resVal2.equals(TOP)) {
return TOP;
}
else if (resVal1.equals(BOTTOM) | resVal2.equals(BOTTOM)){
return BOTTOM;
}
else if (resVal1.equals(ODD) && resVal2.equals(ODD)) {
return ODD;
}
else {
return EVEN;
}
}
else if (val instanceof IntConstant) {
int value = ((IntConstant)val).value;
if ((value % 2) == 0) {
return EVEN;
}
else {
return ODD;
}
}
else if (val instanceof LongConstant) {
long value = ((LongConstant)val).value;
if ((value % 2) == 0) {
return EVEN;
}
else {
return ODD;
}
}
else if (in.containsKey(val)) {
return in.get(val);
}
else {
return TOP;
}
}
protected void flowThrough(Object inValue, Object unit,
Object outValue)
{
HashMap in = (HashMap) inValue;
HashMap<Value, String> out = (HashMap<Value, String>) outValue;
Stmt s = (Stmt) unit;
// copy in to out
out.putAll(in);
// for each stmt where leftOp is defintionStmt find the parity
// of rightOp and update parity to EVEN, ODD or TOP
//boolean useS = false;
if (s instanceof DefinitionStmt) {
Value left = ((DefinitionStmt)s).getLeftOp();
if (left instanceof Local) {
if ((left.getType() instanceof IntegerType) || (left.getType() instanceof LongType)){
//useS = true;
Value right = ((DefinitionStmt)s).getRightOp();
out.put(left, getParity(out, right));
}
}
}
// get all use and def boxes of s
// if use or def is int or long constant add their parity
Iterator it = s.getUseAndDefBoxes().iterator();
while (it.hasNext()){
Object next = it.next();
Value val = ((ValueBox)next).getValue();
//System.out.println("val: "+val.getClass());
if (val instanceof ArithmeticConstant){
out.put(val, getParity(out, val));
//System.out.println("out map: "+out);
}
}
//if (useS){
if (Options.v().interactive_mode()){
buildAfterFilterMap(s);
updateAfterFilterMap(s);
}
//}
}
private void buildAfterFilterMap(Stmt s){
List list = filter.getLiveLocalsAfter(s);
HashMap map = new HashMap();
Iterator listIt = list.iterator();
while (listIt.hasNext()){
map.put(listIt.next(), BOTTOM);
}
filterUnitToAfterFlow.put(s, map);
//System.out.println("built afterflow filter map: "+filterUnitToAfterFlow);
}
// STEP 6: Determine value for start/end node, and
// initial approximation.
//
// start node: locals with BOTTOM
// initial approximation: locals with BOTTOM
protected Object entryInitialFlow()
{
/*HashMap initMap = new HashMap();
Chain locals = g.getBody().getLocals();
Iterator it = locals.iterator();
while (it.hasNext()) {
initMap.put(it.next(), BOTTOM);
}
return initMap;*/
return newInitialFlow();
}
private void updateBeforeFilterMap(){
Iterator<Stmt> filterIt = filterUnitToBeforeFlow.keySet().iterator();
while (filterIt.hasNext()){
Stmt s = filterIt.next();
HashMap allData = (HashMap)unitToBeforeFlow.get(s);
HashMap filterData = (HashMap) filterUnitToBeforeFlow.get(s);
filterUnitToBeforeFlow.put(s, updateFilter(allData, filterData));
}
}
private void updateAfterFilterMap(Stmt s){
HashMap allData = (HashMap)unitToAfterFlow.get(s);
HashMap filterData = (HashMap) filterUnitToAfterFlow.get(s);
filterUnitToAfterFlow.put(s, updateFilter(allData, filterData));
}
private HashMap updateFilter(HashMap allData, HashMap filterData){
if (allData == null) return filterData;
Iterator<Value> filterVarsIt = filterData.keySet().iterator();
ArrayList<Value> toRemove = new ArrayList<Value>();
while (filterVarsIt.hasNext()){
Value v = filterVarsIt.next();
if (allData.get(v) == null){
toRemove.add(v);
//filterData.put(v, new HashMap());
}
else {
filterData.put(v, allData.get(v));
}
}
Iterator<Value> removeIt = toRemove.iterator();
while (removeIt.hasNext()){
filterData.remove(removeIt.next());
}
return filterData;
}
protected Object newInitialFlow()
{
HashMap<Value, String> initMap = new HashMap<Value, String>();
Chain locals = g.getBody().getLocals();
Iterator it = locals.iterator();
while (it.hasNext()) {
Local next = (Local)it.next();
//System.out.println("next local: "+next);
if ((next.getType() instanceof IntegerType) || (next.getType() instanceof LongType)){
initMap.put(next, BOTTOM);
}
}
Iterator boxIt = g.getBody().getUseAndDefBoxes().iterator();
while (boxIt.hasNext()){
Value val = ((ValueBox)boxIt.next()).getValue();
if (val instanceof ArithmeticConstant) {
initMap.put(val, getParity(initMap, val));
}
}
if (Options.v().interactive_mode()){
updateBeforeFilterMap();
}
return initMap;
}
}