package soot.jimple.toolkits.pointer;
import java.util.*;
import soot.PointsToSet;
import soot.SootField;
import soot.*;
import soot.jimple.spark.pag.*;
import soot.jimple.spark.sets.*;
public class CodeBlockRWSet extends MethodRWSet
{
public int size()
{
if(globals == null)
{
if(fields == null)
return 0;
else
return fields.size();
}
else
{
if(fields == null)
return globals.size();
else
return globals.size() + fields.size();
}
}
public String toString()
{
boolean empty = true;
final StringBuffer ret = new StringBuffer();
if( fields != null )
{
for (Object element : fields.keySet()) {
final Object field = element;
ret.append( "[Field: "+field+" ");
Object baseObj = fields.get(field);
if(baseObj instanceof PointsToSetInternal)
{
/* PointsToSetInternal base = (PointsToSetInternal) fields.get(field);
base.forall(
new P2SetVisitor()
{
public void visit( Node n )
{
ret.append(n.getNumber() + " ");
}
}
);
*/
int baseSize = ((PointsToSetInternal)baseObj).size();
ret.append(baseSize + (baseSize == 1 ? " Node]\n" : " Nodes]\n"));
}
else
{
ret.append(baseObj + "]\n");
}
empty = false;
}
}
if( globals != null )
{
for( Iterator globalIt = globals.iterator(); globalIt.hasNext(); )
{
final Object global = globalIt.next();
ret.append( "[Global: "+global+"]\n" );
empty = false;
}
}
if(empty) ret.append("[emptyset]\n");
return ret.toString();
}
/** Adds the RWSet other into this set. */
public boolean union( RWSet other )
{
if( other == null ) return false;
if( isFull ) return false;
boolean ret = false;
if( other instanceof MethodRWSet )
{
MethodRWSet o = (MethodRWSet) other;
if( o.getCallsNative() )
{
ret = !getCallsNative() | ret;
setCallsNative();
}
if( o.isFull )
{
ret = !isFull | ret;
isFull = true;
if( true ) throw new RuntimeException( "attempt to add full set "+o+" into "+this );
globals = null;
fields = null;
return ret;
}
if( o.globals != null )
{
if( globals == null ) globals = new HashSet();
ret = globals.addAll( o.globals ) | ret;
if( globals.size() > MAX_SIZE )
{
globals = null;
isFull = true;
throw new RuntimeException( "attempt to add full set "+o+" into "+this );
}
}
if( o.fields != null )
{
for (Object element : o.fields.keySet()) {
final Object field = element;
PointsToSet os = o.getBaseForField( field );
ret = addFieldRef( os, field ) | ret;
}
}
}
else if( other instanceof StmtRWSet )
{
StmtRWSet oth = (StmtRWSet) other;
if( oth.base != null )
{
ret = addFieldRef( oth.base, oth.field ) | ret;
}
else if( oth.field != null )
{
ret = addGlobal( (SootField) oth.field ) | ret;
}
}
else if( other instanceof SiteRWSet)
{
SiteRWSet oth = (SiteRWSet) other;
for (RWSet set : oth.sets) {
this.union(set);
}
}
if( !getCallsNative() && other.getCallsNative() )
{
setCallsNative();
return true;
}
return ret;
}
public boolean containsField( Object field )
{
if(fields == null) return false;
return fields.containsKey(field);
}
public CodeBlockRWSet intersection( MethodRWSet other )
{// May run slowly... O(n^2)
CodeBlockRWSet ret = new CodeBlockRWSet();
if( isFull )
return ret;
if( globals != null && other.globals != null
&& !globals.isEmpty() && !other.globals.isEmpty() )
{
for( Iterator it = other.globals.iterator(); it.hasNext(); )
{
SootField sg = (SootField) it.next();
if( globals.contains(sg) )
ret.addGlobal(sg);
}
}
if( fields != null && other.fields != null
&& !fields.isEmpty() && !other.fields.isEmpty() )
{
for (Object element : other.fields.keySet()) {
final Object field = element;
if( fields.containsKey( field ) )
{
PointsToSet pts1 = getBaseForField( field );
PointsToSet pts2 = other.getBaseForField( field );
if(pts1 instanceof FullObjectSet)
ret.addFieldRef(pts2, field);
else if(pts2 instanceof FullObjectSet)
ret.addFieldRef(pts1, field);
else if( pts1.hasNonEmptyIntersection(pts2) )
{
if((pts1 instanceof PointsToSetInternal) && (pts2 instanceof PointsToSetInternal))
{
final PointsToSetInternal pti1 = (PointsToSetInternal) pts1;
final PointsToSetInternal pti2 = (PointsToSetInternal) pts2;
final PointsToSetInternal newpti = new HashPointsToSet(pti1.getType(), (PAG) Scene.v().getPointsToAnalysis());
pti1.forall(
new P2SetVisitor()
{
public void visit( Node n )
{
if( pti2.contains( n ) ) newpti.add(n);
}
}
);
ret.addFieldRef(newpti, field);
}
}
}
}
}
return ret;
}
public boolean addFieldRef( PointsToSet otherBase, Object field )
{
boolean ret = false;
if( fields == null )
fields = new HashMap();
// Get our points-to set, merge with other
PointsToSet base = getBaseForField( field );
if( base instanceof FullObjectSet )
return false;
if( otherBase instanceof FullObjectSet )
{
fields.put( field, otherBase );
return true;
}
if( otherBase.equals( base ) )
return false;
if( base == null )
{
// NOTE: this line makes unsafe assumptions about the PTA
PointsToSetInternal newpti = new HashPointsToSet(((PointsToSetInternal)otherBase).getType(), (PAG) Scene.v().getPointsToAnalysis());
base = newpti;
fields.put( field, base );
}
ret = ((PointsToSetInternal)base).addAll((PointsToSetInternal) otherBase, null) | ret;
return ret;
}
}