Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
soot.jimple.toolkits.annotation.arraycheck.RectangularArrayFinder Maven / Gradle / Ivy
/* Soot - a J*va Optimization Framework
* Copyright (C) 2000 Feng Qian
*
* 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.
*/
/*
* Modified by the Sable Research Group and others 1997-1999.
* See the 'credits' file distributed with Soot for the complete list of
* contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
*/
package soot.jimple.toolkits.annotation.arraycheck;
import soot.options.*;
import soot.*;
import soot.util.*;
import soot.jimple.*;
import soot.jimple.internal.*;
import soot.jimple.toolkits.callgraph.*;
import java.util.*;
/** Interprocedural analysis to identify rectangular multi-dimension array
* locals. It is based on the call graph.
*/
public class RectangularArrayFinder extends SceneTransformer
{
public RectangularArrayFinder( Singletons.Global g ) {}
public static RectangularArrayFinder v() { return G.v().soot_jimple_toolkits_annotation_arraycheck_RectangularArrayFinder(); }
private final ExtendedHashMutableDirectedGraph agraph =
new ExtendedHashMutableDirectedGraph();
private final Set falseSet = new HashSet();
private final Set trueSet = new HashSet();
private CallGraph cg;
protected void internalTransform(String phaseName, Map opts)
{
Scene sc = Scene.v();
cg = sc.getCallGraph();
Date start = new Date();
if (Options.v().verbose())
G.v().out.println("[ra] Finding rectangular arrays, start on "+start);
Chain appClasses = sc.getApplicationClasses();
Iterator classIt = appClasses.iterator();
while (classIt.hasNext())
{
SootClass c = (SootClass)classIt.next();
Iterator methodIt = c.methodIterator();
while (methodIt.hasNext())
{
SootMethod method = (SootMethod)methodIt.next();
if (!method.isConcrete())
continue;
if (!sc.getReachableMethods().contains(method))
continue;
recoverRectArray(method);
addInfoFromMethod(method);
}
}
/*
MutableDirectedGraph methodGraph = ig.newMethodGraph();
HashSet visitedMethods = new HashSet();
LinkedList tovisitMethods = new LinkedList();
List heads = methodGraph.getHeads();
Iterator headIt = heads.iterator();
while (headIt.hasNext())
{
SootMethod entry = (SootMethod)headIt.next();
String sig = entry.getSubSignature();
if (sig.equals(mainSignature))
tovisitMethods.add(entry);
}
while (!tovisitMethods.isEmpty())
{
SootMethod visiting = (SootMethod)tovisitMethods.removeFirst();
visitedMethods.add(visiting);
recoverRectArray(visiting);
addInfoFromMethod(visiting);
List succs = methodGraph.getSuccsOf(visiting);
Iterator succIt = succs.iterator();
while (succIt.hasNext())
{
Object succ = succIt.next();
if (!visitedMethods.contains(succ))
tovisitMethods.add(succ);
}
}
*/
/* propagate the graph info from FALSE node. */
if (agraph.containsNode(BoolValue.v(false)))
{
List changedNodeList = new ArrayList();
List startNodes = agraph.getSuccsOf(BoolValue.v(false));
falseSet.addAll(startNodes);
changedNodeList.addAll(startNodes);
while (!changedNodeList.isEmpty())
{
Object node = changedNodeList.remove(0);
List succs = agraph.getSuccsOf(node);
Iterator succsIt = succs.iterator();
while (succsIt.hasNext())
{
Object succ = succsIt.next();
if (!falseSet.contains(succ))
{
falseSet.add(succ);
changedNodeList.add(succ);
}
}
}
}
/* propagate graph info from TRUE node then. */
if (agraph.containsNode(BoolValue.v(true)))
{
List changedNodeList = new ArrayList();
List startNodes = agraph.getSuccsOf(BoolValue.v(true));
Iterator nodesIt = startNodes.iterator();
while (nodesIt.hasNext())
{
Object node = nodesIt.next();
if (falseSet.contains(node))
continue;
changedNodeList.add(node);
trueSet.add(node);
}
while (!changedNodeList.isEmpty())
{
Object node = changedNodeList.remove(0);
List succs = agraph.getSuccsOf(node);
Iterator succsIt = succs.iterator();
while (succsIt.hasNext())
{
Object succ = succsIt.next();
if (falseSet.contains(succ))
continue;
if (trueSet.contains(succ))
continue;
trueSet.add(succ);
changedNodeList.add(succ);
}
}
}
/* For verification, print out true set and false set. */
if (Options.v().debug())
{
G.v().out.println("Rectangular Array :");
{
Iterator nodeIt = trueSet.iterator();
while (nodeIt.hasNext())
{
Object node = nodeIt.next();
G.v().out.println(node);
}
}
G.v().out.println("\nNon-rectangular Array :");
{
Iterator nodeIt = falseSet.iterator();
while (nodeIt.hasNext())
{
Object node = nodeIt.next();
G.v().out.println(node);
}
}
}
Date finish = new Date();
if (Options.v().verbose())
{
long runtime = finish.getTime() - start.getTime();
long mins = runtime/60000;
long secs = (runtime%60000)/1000;
G.v().out.println("[ra] Rectangular array finder finishes."
+" It took "+mins+" mins and "+secs+" secs.");
}
}
private void addInfoFromMethod(SootMethod method)
{
if (Options.v().verbose())
G.v().out.println("[ra] Operating "+method.getSignature());
boolean needTransfer = true;
Body body = method.getActiveBody();
Set tmpNode = new HashSet();
/* check the return type of method, if it is multi-array. */
boolean trackReturn = false;
Type rtnType = method.getReturnType();
if (rtnType instanceof ArrayType)
{
if (((ArrayType)rtnType).numDimensions > 1)
{
trackReturn = true;
needTransfer = true;
}
}
Set arrayLocal = new HashSet();
/* Collect the multi-array locals */
Chain locals = body.getLocals();
Iterator localIt = locals.iterator();
while (localIt.hasNext())
{
Local local = (Local)localIt.next();
Type type = local.getType();
if (type instanceof ArrayType)
{
if ( ((ArrayType)type).numDimensions > 1)
{
arrayLocal.add(local);
}
else
tmpNode.add(new MethodLocal(method, local));
}
}
/* The method has a local graph. It will be merged to the whole graph after simplification. */
ExtendedHashMutableDirectedGraph ehmdg = new ExtendedHashMutableDirectedGraph();
Iterator unitIt = body.getUnits().snapshotIterator();
while (unitIt.hasNext())
{
Stmt s = (Stmt)unitIt.next();
/* for each invoke site, add edges from local parameter to the target methods' parameter node. */
if (s.containsInvokeExpr())
{
InvokeExpr iexpr = s.getInvokeExpr();
int argnum = iexpr.getArgCount();
for (int i=0; i tmpNodeIt = tmpNode.iterator();
while (tmpNodeIt.hasNext())
{
ehmdg.skipNode(tmpNodeIt.next());
}
/* Add local graph to whole graph */
agraph.mergeWith(ehmdg);
}
}
private void recoverRectArray(SootMethod method)
{
Body body = method.getActiveBody();
HashSet malocal = new HashSet();
Chain locals = body.getLocals();
Iterator localsIt = locals.iterator();
while (localsIt.hasNext())
{
Local local = (Local)localsIt.next();
Type type = local.getType();
if (!(type instanceof ArrayType))
continue;
if (((ArrayType)type).numDimensions == 2)
malocal.add(local);
}
if (malocal.size() == 0)
return;
Chain units = body.getUnits();
Stmt stmt = (Stmt)units.getFirst();
while (true)
{
if (stmt == null)
break;
/* only deal with the first block */
if (!stmt.fallsThrough())
break;
searchblock:
{
/* possible candidates */
if (!(stmt instanceof AssignStmt))
break searchblock;
Value leftOp = ((AssignStmt)stmt).getLeftOp();
Value rightOp = ((AssignStmt)stmt).getRightOp();
if (!malocal.contains(leftOp) || !(rightOp instanceof NewArrayExpr))
break searchblock;
Local local = (Local)leftOp;
NewArrayExpr naexpr = (NewArrayExpr)rightOp;
Value size = naexpr.getSize();
if (!(size instanceof IntConstant))
break searchblock;
int firstdim = ((IntConstant)size).value;
if (firstdim > 100)
break searchblock;
ArrayType localtype = (ArrayType)local.getType();
Type basetype = localtype.baseType;
Local[] tmplocals = new Local[firstdim];
int seconddim = lookforPattern(units, stmt,
firstdim, local,
basetype, tmplocals);
if (seconddim >= 0)
transferPattern(units, stmt,
firstdim, seconddim,
local, basetype, tmplocals);
}
stmt = (Stmt)units.getSuccOf(stmt);
}
}
/* if the local is assigned a rect array, return back the second dimension length,
else return -1
*/
private int lookforPattern(Chain units, Stmt startpoint,
int firstdim, Local local,
Type basetype, Local[] tmplocals)
{
/* It is a state machine to match the pattern */
/* state input goto
start r1 = new(A[])[c] 1
1 r2 = newA[d] 2
2 r2[?] = ... 2
r1[e] = r2 (e = c-1) 3
r1[e] = r2 (e = e'+1) 2
3 end
*/
int seconddim = -1;
int curdim = 0;
Object curtmp = local; // Local, I have to initialize it. It should not be this value.
Stmt curstmt = startpoint;
int fault = 99;
int state = 1;
while (true)
{
curstmt = (Stmt)units.getSuccOf(curstmt);
if (curstmt == null)
return -1;
if (!(curstmt instanceof AssignStmt))
return -1;
Value leftOp = ((AssignStmt)curstmt).getLeftOp();
Value rightOp = ((AssignStmt)curstmt).getRightOp();
switch (state)
{
/* we already did state 0 outside */
case 0:
break;
case 1:
/* make sure it is a new array expr */
{
state = fault;
if (!(rightOp instanceof NewArrayExpr))
break;
NewArrayExpr naexpr = (NewArrayExpr)rightOp;
Type type = naexpr.getBaseType();
Value size = naexpr.getSize();
if (!type.equals(basetype))
break;
if (!(size instanceof IntConstant))
break;
if (curdim == 0)
seconddim = ((IntConstant)size).value;
else
{
if (((IntConstant)size).value != seconddim)
break;
}
curtmp = leftOp;
state = 2;
}
break;
case 2:
{
state = fault;
if (!(leftOp instanceof ArrayRef))
break;
Value base = ((ArrayRef)leftOp).getBase();
Value idx = ((ArrayRef)leftOp).getIndex();
/* curtmp[?] = ? */
if (base.equals(curtmp))
state = 2;
else
/* local[?] = curtmp? */
if (base.equals(local))
{
if (!(idx instanceof IntConstant))
break;
if (curdim != ((IntConstant)idx).value)
break;
if (!rightOp.equals(curtmp))
break;
tmplocals[curdim] = (Local)curtmp;
curdim++;
if (curdim >= firstdim)
state = 3;
else
state = 1;
}
}
break;
case 3:
return seconddim;
default:
return -1;
}
}
}
private void transferPattern(Chain units, Stmt startpoint,
int firstdim, int seconddim,
Local local, Type basetype,
Local[] tmplocals)
{
/* sequentially search and replace the sub dimension assignment */
{
/* change the first one, reset the right op */
ArrayType atype = (ArrayType)local.getType();
List sizes = new ArrayList(2);
sizes.add(IntConstant.v(firstdim));
sizes.add(IntConstant.v(seconddim));
Value nmexpr = new JNewMultiArrayExpr(atype, sizes);
((AssignStmt)startpoint).setRightOp(nmexpr);
}
{
int curdim = 0;
Local tmpcur = local;
Stmt curstmt = (Stmt)units.getSuccOf(startpoint);
while (curdim < firstdim)
{
Value leftOp = ((AssignStmt)curstmt).getLeftOp();
Value rightOp = ((AssignStmt)curstmt).getRightOp();
if (tmplocals[curdim].equals(leftOp) && (rightOp instanceof NewArrayExpr))
{
ArrayRef arexpr = new JArrayRef(local, IntConstant.v(curdim));
((AssignStmt)curstmt).setRightOp(arexpr);
tmpcur = (Local)leftOp;
}
else
if ((leftOp instanceof ArrayRef) && (rightOp.equals(tmpcur)))
{
/* delete current stmt */
Stmt tmpstmt = curstmt;
curstmt = (Stmt)units.getSuccOf(curstmt);
units.remove(tmpstmt);
curdim++;
}
else
curstmt = (Stmt)units.getSuccOf(curstmt);
}
}
}
public boolean isRectangular(Object obj)
{
if (trueSet.contains(obj))
return true;
else
return false;
}
}