soot.dava.toolkits.base.AST.structuredAnalysis.DavaFlowSet 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) 2005 Nomair A. Naeem
* %%
* 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.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import soot.dava.internal.AST.ASTNode;
import soot.dava.internal.SET.SETNodeLabel;
import soot.dava.internal.javaRep.DAbruptStmt;
import soot.dava.toolkits.base.AST.traversals.ClosestAbruptTargetFinder;
import soot.toolkits.scalar.AbstractFlowSet;
import soot.toolkits.scalar.FlowSet;
public class DavaFlowSet extends AbstractFlowSet {
static final int DEFAULT_SIZE = 8;
int numElements;
int maxElements;
protected T[] elements;
/**
* Whenever in a structured flow analysis a break or continue stmt is encountered the current DavaFlowSet is stored in the
* break/continue list with the appropriate label for the target code. This is how explicit breaks and continues are
* handled by the analysis framework
*/
HashMap>> breakList;
HashMap>> continueList;
/**
* To handle implicit breaks and continues the following HashMaps store the DavaFlowSets as value with the key being the
* targeted piece of code (an ASTNode)
*/
HashMap>> implicitBreaks; // map a node
// and all the
// dataflowsets
// due to
// implicit
// breaks
// targetting it
HashMap>> implicitContinues; // map a node
// and all
// the
// dataflowsets
// due to
// implicit
// continues
// targetting
// it
public DavaFlowSet() {
maxElements = DEFAULT_SIZE;
elements = (T[]) new Object[DEFAULT_SIZE];
numElements = 0;
breakList = new HashMap>>();
continueList = new HashMap>>();
implicitBreaks = new HashMap>>();
implicitContinues = new HashMap>>();
}
public DavaFlowSet(DavaFlowSet other) {
numElements = other.numElements;
maxElements = other.maxElements;
elements = other.elements.clone();
breakList = (HashMap>>) other.breakList.clone();
continueList = (HashMap>>) other.continueList.clone();
implicitBreaks = (HashMap>>) other.implicitBreaks.clone();
implicitContinues = (HashMap>>) other.implicitContinues.clone();
}
/** Returns true if flowSet is the same type of flow set as this. */
private boolean sameType(Object flowSet) {
return (flowSet instanceof DavaFlowSet);
}
public DavaFlowSet clone() {
return new DavaFlowSet(this);
}
public FlowSet emptySet() {
return new DavaFlowSet();
}
public void clear() {
numElements = 0;
}
public int size() {
return numElements;
}
public boolean isEmpty() {
return numElements == 0;
}
/** Returns a unbacked list of elements in this set. */
public List toList() {
@SuppressWarnings("unchecked")
T[] copiedElements = (T[]) new Object[numElements];
System.arraycopy(elements, 0, copiedElements, 0, numElements);
return Arrays.asList(copiedElements);
}
/*
* Expand array only when necessary, pointed out by Florian Loitsch March 08, 2002
*/
@Override
public void add(T e) {
/* Expand only if necessary! and removes one if too:) */
// Add element
if (!contains(e)) {
// Expand array if necessary
if (numElements == maxElements) {
doubleCapacity();
}
elements[numElements++] = e;
}
}
private void doubleCapacity() {
int newSize = maxElements * 2;
@SuppressWarnings("unchecked")
T[] newElements = (T[]) new Object[newSize];
System.arraycopy(elements, 0, newElements, 0, numElements);
elements = newElements;
maxElements = newSize;
}
@Override
public void remove(Object obj) {
for (int i = 0; i < numElements; i++) {
if (elements[i].equals(obj)) {
remove(i);
break;
}
}
}
public void remove(int idx) {
elements[idx] = elements[--numElements];
}
/**
* Notice that the union method only merges the elements of the flow set DavaFlowSet also contains information regarding
* abrupt control flow This should also be merged using the copyInternalDataFrom method
*/
public void union(FlowSet otherFlow, FlowSet destFlow) {
if (sameType(otherFlow) && sameType(destFlow)) {
DavaFlowSet other = (DavaFlowSet) otherFlow;
DavaFlowSet dest = (DavaFlowSet) destFlow;
// For the special case that dest == other
if (dest == other) {
for (int i = 0; i < this.numElements; i++) {
dest.add(this.elements[i]);
}
}
// Else, force that dest starts with contents of this
else {
if (this != dest) {
copy(dest);
}
for (int i = 0; i < other.numElements; i++) {
dest.add(other.elements[i]);
}
}
} else {
super.union(otherFlow, destFlow);
}
}
/**
* Notice that the intersection method only merges the elements of the flow set DavaFlowSet also contains information
* regarding abrupt control flow This should also be merged using the copyInternalDataFrom method
*/
public void intersection(FlowSet otherFlow, FlowSet destFlow) {
// System.out.println("DAVA FLOWSET INTERSECTION INVOKED!!!");
if (sameType(otherFlow) && sameType(destFlow)) {
DavaFlowSet other = (DavaFlowSet) otherFlow;
DavaFlowSet dest = (DavaFlowSet) destFlow;
DavaFlowSet workingSet;
if (dest == other || dest == this) {
workingSet = new DavaFlowSet();
} else {
workingSet = dest;
workingSet.clear();
}
for (int i = 0; i < this.numElements; i++) {
if (other.contains(this.elements[i])) {
workingSet.add(this.elements[i]);
}
}
if (workingSet != dest) {
workingSet.copy(dest);
}
} else {
super.intersection(otherFlow, destFlow);
}
}
public void difference(FlowSet otherFlow, FlowSet destFlow) {
if (sameType(otherFlow) && sameType(destFlow)) {
DavaFlowSet other = (DavaFlowSet) otherFlow;
DavaFlowSet dest = (DavaFlowSet) destFlow;
DavaFlowSet workingSet;
if (dest == other || dest == this) {
workingSet = new DavaFlowSet();
} else {
workingSet = dest;
workingSet.clear();
}
for (int i = 0; i < this.numElements; i++) {
if (!other.contains(this.elements[i])) {
workingSet.add(this.elements[i]);
}
}
if (workingSet != dest) {
workingSet.copy(dest);
}
} else {
super.difference(otherFlow, destFlow);
}
}
public boolean contains(Object obj) {
for (int i = 0; i < numElements; i++) {
if (elements[i].equals(obj)) {
return true;
}
}
return false;
}
/**
* Notice that the equals method only checks the equality of the elements of the flow set DavaFlowSet also contains
* information regarding abrupt control flow This should also be checked by invoking the internalDataMatchesTo method
*/
public boolean equals(Object otherFlow) {
if (sameType(otherFlow)) {
@SuppressWarnings("unchecked")
DavaFlowSet other = (DavaFlowSet) otherFlow;
if (other.numElements != this.numElements) {
return false;
}
int size = this.numElements;
// Make sure that thisFlow is contained in otherFlow
for (int i = 0; i < size; i++) {
if (!other.contains(this.elements[i])) {
return false;
}
}
/*
* both arrays have the same size, no element appears twice in one array, all elements of ThisFlow are in otherFlow ->
* they are equal! we don't need to test again! // Make sure that otherFlow is contained in ThisFlow for(int i = 0; i <
* size; i++) if(!this.contains(other.elements[i])) return false;
*/
return true;
} else {
return super.equals(otherFlow);
}
}
public void copy(FlowSet destFlow) {
if (this == destFlow) {
return;
}
if (sameType(destFlow)) {
DavaFlowSet dest = (DavaFlowSet) destFlow;
while (dest.maxElements < this.maxElements) {
dest.doubleCapacity();
}
dest.numElements = this.numElements;
System.arraycopy(this.elements, 0, dest.elements, 0, this.numElements);
} else {
super.copy(destFlow);
}
}
/**
* A private method used to add an element into a List if it is NOT a duplicate
*/
private List> addIfNotDuplicate(List> into, DavaFlowSet addThis) {
// if set is not already present in the labelsBreakList then add it
Iterator> it = into.iterator();
boolean found = false;
while (it.hasNext()) {
DavaFlowSet temp = it.next();
if (temp.equals(addThis) && temp.internalDataMatchesTo(addThis)) {
found = true;
break;
}
}
if (!found) {
into.add(addThis);
}
return into;
}
/**
* When an explicit break statement is encountered this method should be called to store the current davaflowset
*/
public void addToBreakList(String labelBroken, DavaFlowSet set) {
List> labelsBreakList = breakList.get(labelBroken);
if (labelsBreakList == null) {
labelsBreakList = new ArrayList>();
labelsBreakList.add(set);
breakList.put(labelBroken, labelsBreakList);
// System.out.println("ADDED"+labelBroken+" with"+set.toString());
} else {
// add set into this list if its not a duplicate and update the
// hashMap
breakList.put(labelBroken, addIfNotDuplicate(labelsBreakList, set));
}
}
/**
* When an explicit continue statement is encountered this method should be called to store the current davaflowset
*/
public void addToContinueList(String labelContinued, DavaFlowSet set) {
List> labelsContinueList = continueList.get(labelContinued);
if (labelsContinueList == null) {
labelsContinueList = new ArrayList>();
labelsContinueList.add(set);
continueList.put(labelContinued, labelsContinueList);
} else {
continueList.put(labelContinued, addIfNotDuplicate(labelsContinueList, set));
}
}
/**
* Checks whether the input stmt is an implicit break/continue A abrupt stmt is implicit if the SETLabelNode is null or the
* label.toString results in null
*/
private boolean checkImplicit(DAbruptStmt ab) {
SETNodeLabel label = ab.getLabel();
if ((label == null) || (label.toString() == null)) {
return true;
}
return false;
}
/**
* The next two methods take an abruptStmt as input along with a flowSet. It should be only invoked for abrupt stmts which
* do not have explicit labels
*
* The node being targeted by this implicit stmt should be found Then the flow set should be added to the list within the
* appropriate hashmap
*/
public void addToImplicitBreaks(DAbruptStmt ab, DavaFlowSet set) {
if (!checkImplicit(ab)) {
throw new RuntimeException("Tried to add explicit break statement in the implicit list in");
}
if (!ab.is_Break()) {
throw new RuntimeException("Tried to add continue statement in the break list in DavaFlowSet.addToImplicitBreaks");
}
// okkay so its an implicit break
// get the targetted node, use the ClosestAbruptTargetFinder
ASTNode node = ClosestAbruptTargetFinder.v().getTarget(ab);
// get the list of flow sets already stored for this node
List> listSets = implicitBreaks.get(node);
if (listSets == null) {
listSets = new ArrayList>();
}
// if set is not already present in listSets add it and update hashMap
implicitBreaks.put(node, addIfNotDuplicate(listSets, set));
}
public void addToImplicitContinues(DAbruptStmt ab, DavaFlowSet set) {
if (!checkImplicit(ab)) {
throw new RuntimeException("Tried to add explicit continue statement in the implicit list ");
}
if (!ab.is_Continue()) {
throw new RuntimeException("Tried to add break statement in the continue list");
}
// okkay so its an implicit continue
// get the targetted node, use the ClosestAbruptTargetFinder
ASTNode node = ClosestAbruptTargetFinder.v().getTarget(ab);
// get the list of flow sets already stored for this node
List> listSets = implicitContinues.get(node);
if (listSets == null) {
listSets = new ArrayList>();
}
// if set is not already present in listSets add it and update hashMap
implicitContinues.put(node, addIfNotDuplicate(listSets, set));
}
private HashMap>> getBreakList() {
return breakList;
}
private HashMap>> getContinueList() {
return continueList;
}
public HashMap>> getImplicitBreaks() {
return implicitBreaks;
}
public HashMap>> getImplicitContinues() {
return implicitContinues;
}
public List> getImplicitlyBrokenSets(ASTNode node) {
List> toReturn = implicitBreaks.get(node);
if (toReturn != null) {
return toReturn;
}
return null;
}
public List> getImplicitlyContinuedSets(ASTNode node) {
List> toReturn = implicitContinues.get(node);
if (toReturn != null) {
return toReturn;
}
return null;
}
/**
* An internal method used to copy non-duplicate entries from the temp list into the currentList
*/
private List> copyDavaFlowSetList(List> currentList, List> temp) {
Iterator> tempIt = temp.iterator();
while (tempIt.hasNext()) {
DavaFlowSet check = tempIt.next();
Iterator> currentListIt = currentList.iterator();
boolean found = false;
while (currentListIt.hasNext()) {
// see if currentList has check
DavaFlowSet currentSet = currentListIt.next();
if (check.equals(currentSet) && check.internalDataMatchesTo(currentSet)) {
found = true;
break;
}
}
if (!found) {
currentList.add(check);
}
}
return currentList;
}
public void copyInternalDataFrom(DavaFlowSet fromThis) {
if (!sameType(fromThis)) {
return;
}
// copy elements of breaklist
{
Map>> fromThisBreakList = fromThis.getBreakList();
Iterator keys = fromThisBreakList.keySet().iterator();
while (keys.hasNext()) {
String labelBroken = (String) keys.next();
List> temp = fromThisBreakList.get(labelBroken);
List> currentList = breakList.get(labelBroken);
if (currentList == null) {
breakList.put(labelBroken, temp);
} else {
List> complete = copyDavaFlowSetList(currentList, temp);
breakList.put(labelBroken, complete);
}
}
}
// copy elements of continuelist
{
HashMap>> fromThisContinueList = fromThis.getContinueList();
Iterator keys = fromThisContinueList.keySet().iterator();
while (keys.hasNext()) {
String labelContinued = (String) keys.next();
List> temp = fromThisContinueList.get(labelContinued);
List> currentList = continueList.get(labelContinued);
if (currentList == null) {
continueList.put(labelContinued, temp);
} else {
List> complete = copyDavaFlowSetList(currentList, temp);
continueList.put(labelContinued, complete);
}
}
}
// copy elements of implicitBreaks
// this hashMap contains a mapping of ASTNodes to DavaFlowSets due to
// impicit breaks
{
HashMap>> copyThis = fromThis.getImplicitBreaks();
Iterator it = copyThis.keySet().iterator();
while (it.hasNext()) { // going through all nodes in the other
// objects implicitBreaks hashMap
// each is a node
ASTNode node = (ASTNode) it.next();
// get list of dava flow sets targetting this node implicitly
List> fromDavaFlowSets = copyThis.get(node);
// Have copy non duplicates in this to the implicitbreak hashMap
// the current dava flow set has
List> toDavaFlowSets = implicitBreaks.get(node);
if (toDavaFlowSets == null) {
// there was no dava flow set currently targetting this node
// implicitly
// put the fromDavaFlowSets into the hashMap
implicitBreaks.put(node, fromDavaFlowSets);
} else {
List> complete = copyDavaFlowSetList(toDavaFlowSets, fromDavaFlowSets);
implicitBreaks.put(node, complete);
}
}
}
// copy elements of implicitContinues
// this hashMap contains a mapping of ASTNodes to DavaFlowSets due to
// impicit continues
{
HashMap>> copyThis = fromThis.getImplicitContinues();
Iterator it = copyThis.keySet().iterator();
while (it.hasNext()) { // going through all nodes in the other
// objects implicitcontinues hashMap
// each is a node
ASTNode node = (ASTNode) it.next();
// get list of dava flow sets targetting this node implicitly
List> fromDavaFlowSets = copyThis.get(node);
// Have copy non duplicates in this to the implicitContinue
// hashMap the current dava flow set has
List> toDavaFlowSets = implicitContinues.get(node);
if (toDavaFlowSets == null) {
// there was no dava flow set currently targetting this node
// implicitly
// put the fromDavaFlowSets into the hashMap
implicitContinues.put(node, fromDavaFlowSets);
} else {
List> complete = copyDavaFlowSetList(toDavaFlowSets, fromDavaFlowSets);
implicitContinues.put(node, complete);
}
}
}
}
private boolean compareLists(List listOne, List listTwo) {
if (listOne == null && listTwo == null) {
return true;
}
// compare elements of the list
if (listOne == null || listTwo == null || (listOne.size() != listTwo.size())) {
// size has to be same for lists to match
return false;
}
Iterator listOneIt = listOne.iterator();
boolean found = false;
while (listOneIt.hasNext()) {
// going through the first list
Object listOneObj = listOneIt.next();
Iterator listTwoIt = listTwo.iterator();
while (listTwoIt.hasNext()) {
// find the object in the second list
Object listTwoObj = listTwoIt.next();
if (listOneObj.equals(listTwoObj)) {
// if object is found stop search
found = true;
break;
}
}
if (!found) {
// if didnt find object return false
return false;
}
found = false;
}
return true;
}
public boolean internalDataMatchesTo(Object otherObj) {
if (!(otherObj instanceof DavaFlowSet)) {
return false;
}
@SuppressWarnings("unchecked")
DavaFlowSet other = (DavaFlowSet) otherObj;
// check if same break list
HashMap>> otherMap = other.getBreakList();
if (!compareHashMaps(breakList, otherMap)) {
return false;
}
// check if same continue list
otherMap = other.getContinueList();
if (!compareHashMaps(continueList, otherMap)) {
return false;
}
// check implicitBreaks match
otherMap = other.getImplicitBreaks();
if (!compareHashMaps(implicitBreaks, otherMap)) {
return false;
}
// check implicitContinues match
otherMap = other.getImplicitContinues();
if (!compareHashMaps(implicitContinues, otherMap)) {
return false;
}
return true;
}
private boolean compareHashMaps(HashMap>> thisMap,
HashMap>> otherMap) {
List otherKeyList = new ArrayList();
Iterator keys = otherMap.keySet().iterator();
while (keys.hasNext()) {
String otherKey = (String) keys.next();
otherKeyList.add(otherKey);
List> listOther = otherMap.get(otherKey);
List> listThis = thisMap.get(otherKey);
// compare the two lists
if (!compareLists(listOther, listThis)) {
// if lists dont match internalData doesnt match
return false;
}
}
// have gone through otherMap
// going through thisMap
keys = thisMap.keySet().iterator();
while (keys.hasNext()) {
String key = (String) keys.next();
Iterator keyListIt = otherKeyList.iterator();
boolean alreadyDone = false;
while (keyListIt.hasNext()) {
String doneKey = keyListIt.next();
if (key.equals(doneKey)) {
alreadyDone = true;
break;
}
}
if (!alreadyDone) {
/*
* we have come across a label which was not done by the first hashmap meaning it was NOT in the first hashMap
*/
return false;
}
}
return true;
}
public List> getContinueSet(String label) {
return continueList.remove(label);
}
public List> getBreakSet(String label) {
return breakList.remove(label);
}
public String toString() {
StringBuffer b = new StringBuffer();
b.append(" SET={");
for (int i = 0; i < this.numElements; i++) {
if (i != 0) {
b.append(" , ");
}
b.append(this.elements[i].toString());
}
b.append(" }");
return b.toString();
}
@Override
public Iterator iterator() {
return new Iterator() {
int lastIdx = 0;
@Override
public boolean hasNext() {
return lastIdx < numElements;
}
@Override
public T next() {
return elements[lastIdx++];
}
@Override
public void remove() {
DavaFlowSet.this.remove(--lastIdx);
}
};
}
/*
* public String toString(){ StringBuffer b = new StringBuffer(); b.append("\nSETTTTT\n"); for(int i = 0; i <
* this.numElements; i++){ b.append("\t"+this.elements[i]+"\n"); } b.append("BREAK LIST\n");
* b.append("\t"+breakList.toString()+"\n");
*
*
* b.append("CONTINUE LIST\n"); b.append("\t"+continueList.toString()+"\n");
*
* b.append("EXCEPTION LIST\n"); b.append("\t"+exceptionList.toString()+"\n"); return b.toString(); }
*/
public int getElementCount() {
return elements.length;
}
public T getElementAt(int idx) {
return elements[idx];
}
}