/* Soot - a J*va Optimization Framework
* Copyright (C) 2002 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.solver;
import soot.jimple.spark.pag.*;
import soot.jimple.spark.sets.*;
import soot.*;
import soot.util.queue.*;
import java.util.*;
/** Propagates points-to sets along pointer assignment graph using iteration.
* @author Ondrej Lhotak
*/
public final class PropIter extends Propagator {
public PropIter( PAG pag ) { this.pag = pag; }
/** Actually does the propagation. */
public final void propagate() {
final OnFlyCallGraph ofcg = pag.getOnFlyCallGraph();
new TopoSorter( pag, false ).sort();
for (Object object : pag.allocSources()) {
handleAllocNode( (AllocNode) object );
}
int iteration = 1;
boolean change;
do {
change = false;
TreeSet<Object> simpleSources = new TreeSet<Object>( pag.simpleSources() );
if( pag.getOpts().verbose() ) {
G.v().out.println( "Iteration "+(iteration++) );
}
for (Object object : simpleSources) {
change = handleSimples( (VarNode) object ) | change;
}
if( ofcg != null ) {
QueueReader addedEdges = pag.edgeReader();
for( Iterator srcIt = pag.getVarNodeNumberer().iterator(); srcIt.hasNext(); ) {
final VarNode src = (VarNode) srcIt.next();
ofcg.updatedNode( src );
}
ofcg.build();
while(addedEdges.hasNext()) {
Node addedSrc = (Node) addedEdges.next();
Node addedTgt = (Node) addedEdges.next();
change = true;
if( addedSrc instanceof VarNode ) {
PointsToSetInternal p2set = ((VarNode)addedSrc).getP2Set();
if( p2set != null ) p2set.unFlushNew();
} else if( addedSrc instanceof AllocNode ) {
((VarNode) addedTgt).makeP2Set().add( addedSrc );
}
}
if( change ) {
new TopoSorter( pag, false ).sort();
}
}
for (Object object : pag.loadSources()) {
change = handleLoads( (FieldRefNode) object ) | change;
}
for (Object object : pag.storeSources()) {
change = handleStores( (VarNode) object ) | change;
}
} while( change );
}
/* End of public methods. */
/* End of package methods. */
/** Propagates new points-to information of node src to all its
* successors. */
protected final boolean handleAllocNode( AllocNode src ) {
boolean ret = false;
Node[] targets = pag.allocLookup( src );
for (Node element : targets) {
ret = element.makeP2Set().add( src ) | ret;
}
return ret;
}
protected final boolean handleSimples( VarNode src ) {
boolean ret = false;
PointsToSetInternal srcSet = src.getP2Set();
if( srcSet.isEmpty() ) return false;
Node[] simpleTargets = pag.simpleLookup( src );
for (Node element : simpleTargets) {
ret = element.makeP2Set().addAll( srcSet, null ) | ret;
}
return ret;
}
protected final boolean handleStores( VarNode src ) {
boolean ret = false;
final PointsToSetInternal srcSet = src.getP2Set();
if( srcSet.isEmpty() ) return false;
Node[] storeTargets = pag.storeLookup( src );
for (Node element : storeTargets) {
final FieldRefNode fr = (FieldRefNode) element;
final SparkField f = fr.getField();
ret = fr.getBase().getP2Set().forall( new P2SetVisitor() {
public final void visit( Node n ) {
AllocDotField nDotF = pag.makeAllocDotField(
(AllocNode) n, f );
if( nDotF.makeP2Set().addAll( srcSet, null ) ) {
returnValue = true;
}
}
} ) | ret;
}
return ret;
}
protected final boolean handleLoads( FieldRefNode src ) {
boolean ret = false;
final Node[] loadTargets = pag.loadLookup( src );
final SparkField f = src.getField();
ret = src.getBase().getP2Set().forall( new P2SetVisitor() {
public final void visit( Node n ) {
AllocDotField nDotF = ((AllocNode)n).dot( f );
if( nDotF == null ) return;
PointsToSetInternal set = nDotF.getP2Set();
if( set.isEmpty() ) return;
for (Node element : loadTargets) {
VarNode target = (VarNode) element;
if( target.makeP2Set().addAll( set, null ) ) {
returnValue = true;
}
}
}
} ) | ret;
return ret;
}
protected PAG pag;
}