/* Soot - a J*va Optimization Framework
* Copyright (C) 2003 Ondrej 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.spark.pag;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import soot.ArrayType;
import soot.Body;
import soot.Context;
import soot.EntryPoints;
import soot.G;
import soot.RefLikeType;
import soot.RefType;
import soot.Scene;
import soot.SootClass;
import soot.SootMethod;
import soot.VoidType;
import soot.jimple.Stmt;
import soot.jimple.spark.builder.MethodNodeFactory;
import soot.util.NumberedString;
import soot.util.SingletonList;
import soot.util.queue.ChunkedQueue;
import soot.util.queue.QueueReader;
/** Part of a pointer assignment graph for a single method.
* @author Ondrej Lhotak
*/
public final class MethodPAG {
private PAG pag;
public PAG pag() { return pag; }
protected MethodPAG( PAG pag, SootMethod m ) {
this.pag = pag;
this.method = m;
this.nodeFactory = new MethodNodeFactory( pag, this );
}
private Set<Context> addedContexts;
/** Adds this method to the main PAG, with all VarNodes parameterized by
* varNodeParameter. */
public void addToPAG( Context varNodeParameter ) {
if( !hasBeenBuilt ) throw new RuntimeException();
if( varNodeParameter == null ) {
if( hasBeenAdded ) return;
hasBeenAdded = true;
} else {
if( addedContexts == null ) addedContexts = new HashSet<Context>();
if( !addedContexts.add( varNodeParameter ) ) return;
}
QueueReader reader = (QueueReader) internalReader.clone();
while(reader.hasNext()) {
Node src = (Node) reader.next();
src = parameterize( src, varNodeParameter );
Node dst = (Node) reader.next();
dst = parameterize( dst, varNodeParameter );
pag.addEdge( src, dst );
}
reader = (QueueReader) inReader.clone();
while(reader.hasNext()) {
Node src = (Node) reader.next();
Node dst = (Node) reader.next();
dst = parameterize( dst, varNodeParameter );
pag.addEdge( src, dst );
}
reader = (QueueReader) outReader.clone();
while(reader.hasNext()) {
Node src = (Node) reader.next();
src = parameterize( src, varNodeParameter );
Node dst = (Node) reader.next();
pag.addEdge( src, dst );
}
}
public void addInternalEdge( Node src, Node dst ) {
if( src == null ) return;
internalEdges.add( src );
internalEdges.add( dst );
if (hasBeenAdded) {
pag.addEdge(src, dst);
}
}
public void addInEdge( Node src, Node dst ) {
if( src == null ) return;
inEdges.add( src );
inEdges.add( dst );
if (hasBeenAdded) {
pag.addEdge(src, dst);
}
}
public void addOutEdge( Node src, Node dst ) {
if( src == null ) return;
outEdges.add( src );
outEdges.add( dst );
if (hasBeenAdded) {
pag.addEdge(src, dst);
}
}
private final ChunkedQueue internalEdges = new ChunkedQueue();
private final ChunkedQueue inEdges = new ChunkedQueue();
private final ChunkedQueue outEdges = new ChunkedQueue();
private final QueueReader internalReader = internalEdges.reader();
private final QueueReader inReader = inEdges.reader();
private final QueueReader outReader = outEdges.reader();
SootMethod method;
public SootMethod getMethod() { return method; }
protected MethodNodeFactory nodeFactory;
public MethodNodeFactory nodeFactory() { return nodeFactory; }
public static MethodPAG v( PAG pag, SootMethod m ) {
MethodPAG ret = G.v().MethodPAG_methodToPag.get( m );
if( ret == null ) {
ret = new MethodPAG( pag, m );
G.v().MethodPAG_methodToPag.put( m, ret );
}
return ret;
}
public void build() {
if( hasBeenBuilt ) return;
hasBeenBuilt = true;
if( method.isNative() ) {
if( pag().getOpts().simulate_natives() ) {
buildNative();
}
} else {
if( method.isConcrete() && !method.isPhantom() ) {
buildNormal();
}
}
addMiscEdges();
}
protected VarNode parameterize( LocalVarNode vn, Context varNodeParameter ) {
SootMethod m = vn.getMethod();
if( m != method && m != null ) throw new RuntimeException( "VarNode "+vn+" with method "+m+" parameterized in method "+method );
//System.out.println( "parameterizing "+vn+" with "+varNodeParameter );
return pag().makeContextVarNode( vn, varNodeParameter );
}
protected FieldRefNode parameterize( FieldRefNode frn, Context varNodeParameter ) {
return pag().makeFieldRefNode(
(VarNode) parameterize( frn.getBase(), varNodeParameter ),
frn.getField() );
}
public Node parameterize( Node n, Context varNodeParameter ) {
if( varNodeParameter == null ) return n;
if( n instanceof LocalVarNode )
return parameterize( (LocalVarNode) n, varNodeParameter);
if( n instanceof FieldRefNode )
return parameterize( (FieldRefNode) n, varNodeParameter);
return n;
}
protected boolean hasBeenAdded = false;
protected boolean hasBeenBuilt = false;
protected void buildNormal() {
Body b = method.retrieveActiveBody();
Iterator unitsIt = b.getUnits().iterator();
while( unitsIt.hasNext() )
{
Stmt s = (Stmt) unitsIt.next();
nodeFactory.handleStmt( s );
}
}
protected void buildNative() {
ValNode thisNode = null;
ValNode retNode = null;
if( !method.isStatic() ) {
thisNode = (ValNode) nodeFactory.caseThis();
}
if( method.getReturnType() instanceof RefLikeType ) {
retNode = (ValNode) nodeFactory.caseRet();
}
ValNode[] args = new ValNode[ method.getParameterCount() ];
for( int i = 0; i < method.getParameterCount(); i++ ) {
if( !( method.getParameterType(i) instanceof RefLikeType ) ) continue;
args[i] = (ValNode) nodeFactory.caseParm(i);
}
pag.nativeMethodDriver.process( method, thisNode, retNode, args );
}
protected void addMiscEdges() {
// Add node for parameter (String[]) in main method
if( method.getSubSignature().equals( SootMethod.getSubSignature( "main", new SingletonList( ArrayType.v(RefType.v("java.lang.String"), 1) ), VoidType.v() ) ) ) {
addInEdge( pag().nodeFactory().caseArgv(), nodeFactory.caseParm(0) );
} else
if( method.getSignature().equals(
"<java.lang.Thread: void <init>(java.lang.ThreadGroup,java.lang.String)>" ) ) {
addInEdge( pag().nodeFactory().caseMainThread(), nodeFactory.caseThis() );
addInEdge( pag().nodeFactory().caseMainThreadGroup(), nodeFactory.caseParm( 0 ) );
} else
if (method.getSignature().equals(
"<java.lang.ref.Finalizer: void <init>(java.lang.Object)>")) {
addInEdge( nodeFactory.caseThis(), pag().nodeFactory().caseFinalizeQueue());
} else
if (method.getSignature().equals(
"<java.lang.ref.Finalizer: void runFinalizer()>")) {
addInEdge(pag.nodeFactory().caseFinalizeQueue(), nodeFactory.caseThis());
} else
if (method.getSignature().equals(
"<java.lang.ref.Finalizer: void access$100(java.lang.Object)>")) {
addInEdge(pag.nodeFactory().caseFinalizeQueue(), nodeFactory.caseParm(0));
} else
if (method.getSignature().equals(
"<java.lang.ClassLoader: void <init>()>")) {
addInEdge(pag.nodeFactory().caseDefaultClassLoader(), nodeFactory.caseThis());
} else
if (method.getSignature().equals("<java.lang.Thread: void exit()>")) {
addInEdge(pag.nodeFactory().caseMainThread(), nodeFactory.caseThis());
} else
if (method
.getSignature()
.equals(
"<java.security.PrivilegedActionException: void <init>(java.lang.Exception)>")) {
addInEdge(pag.nodeFactory().caseThrow(), nodeFactory.caseParm(0));
addInEdge(pag.nodeFactory().casePrivilegedActionException(), nodeFactory.caseThis());
}
if (method.getNumberedSubSignature().equals(sigCanonicalize)) {
SootClass cl = method.getDeclaringClass();
while (true) {
if (cl.equals(Scene.v().getSootClass("java.io.FileSystem"))) {
addInEdge(pag.nodeFactory().caseCanonicalPath(), nodeFactory.caseRet());
}
if (!cl.hasSuperclass())
break;
cl = cl.getSuperclass();
}
}
boolean isImplicit = false;
for (SootMethod implicitMethod : EntryPoints.v().implicit()) {
if (implicitMethod.getNumberedSubSignature().equals(
method.getNumberedSubSignature())) {
isImplicit = true;
break;
}
}
if (isImplicit) {
SootClass c = method.getDeclaringClass();
outer: do {
while (!c.getName().equals("java.lang.ClassLoader")) {
if (!c.hasSuperclass()) {
break outer;
}
c = c.getSuperclass();
}
if (method.getName().equals("<init>"))
continue;
addInEdge(pag().nodeFactory().caseDefaultClassLoader(),
nodeFactory.caseThis());
addInEdge(pag().nodeFactory().caseMainClassNameString(),
nodeFactory.caseParm(0));
} while (false);
}
}
protected final NumberedString sigCanonicalize = Scene.v().getSubSigNumberer().
findOrAdd("java.lang.String canonicalize(java.lang.String)");
}