/* 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.toolkits.pointer;
import java.util.*;
import soot.*;
/** Represents the read or write set of a statement. */
public class MethodRWSet extends RWSet {
public Set globals;
public Map<Object,PointsToSet> fields;
protected boolean callsNative = false;
protected boolean isFull = false;
public static final int MAX_SIZE = Integer.MAX_VALUE;
public String toString() {
boolean empty = true;
StringBuffer ret = new StringBuffer();
if( fields != null ) {
for (Object element : fields.keySet()) {
final Object field = element;
ret.append( "[Field: "+field+" "+fields.get(field)+"]\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("empty");
return ret.toString();
}
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();
}
}
//static int count = 0;
public MethodRWSet() {
/*
count++;
if( 0 == (count % 1000) ) {
G.v().out.println( "Created "+count+"th MethodRWSet" );
}
*/
}
public boolean getCallsNative() {
return callsNative;
}
public boolean setCallsNative() {
boolean ret = !callsNative;
callsNative = true;
return ret;
}
/** Returns an iterator over any globals read/written. */
public Set getGlobals() {
if( isFull ) return G.v().MethodRWSet_allGlobals;
if( globals == null ) return Collections.EMPTY_SET;
return globals;
}
/** Returns an iterator over any fields read/written. */
public Set getFields() {
if( isFull ) return G.v().MethodRWSet_allFields;
if( fields == null ) return Collections.EMPTY_SET;
return fields.keySet();
}
/** Returns a set of base objects whose field f is read/written. */
public PointsToSet getBaseForField( Object f ) {
if( isFull ) return FullObjectSet.v();
if( fields == null ) return null;
return fields.get( f );
}
public boolean hasNonEmptyIntersection( RWSet oth ) {
if( isFull ) return oth != null;
if( !(oth instanceof MethodRWSet) ) {
return oth.hasNonEmptyIntersection( this );
}
MethodRWSet other = (MethodRWSet) oth;
if( globals != null && other.globals != null
&& !globals.isEmpty() && !other.globals.isEmpty() ) {
for( Iterator it = other.globals.iterator(); it.hasNext(); ) {
if( globals.contains( it.next() ) ) return true;
}
}
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 ) ) {
if( Union.hasNonEmptyIntersection(
getBaseForField( field ),
other.getBaseForField( field ) ) ) {
return true;
}
}
}
}
return false;
}
/** 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 {
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;
}
}
if( !getCallsNative() && other.getCallsNative() ) {
setCallsNative();
return true;
}
return ret;
}
public boolean addGlobal( SootField global ) {
if( globals == null ) globals = new HashSet();
boolean ret = globals.add( global );
if( globals.size() > MAX_SIZE ) {
globals = null;
isFull = true;
throw new RuntimeException( "attempt to add more than "+MAX_SIZE+" globals into "+this );
}
return ret;
}
public boolean addFieldRef( PointsToSet otherBase, Object field ) {
boolean ret = false;
if( fields == null ) fields = new HashMap();
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;
Union u;
if( base == null || !(base instanceof Union) ) {
u = G.v().Union_factory.newUnion();
if( base != null) u.addAll( base );
fields.put( field, u );
if( base == null ) addedField( fields.size() );
ret = true;
if( fields.keySet().size() > MAX_SIZE ) {
fields = null;
isFull = true;
if( true ) throw new RuntimeException( "attempt to add more than "+MAX_SIZE+" fields into "+this );
return true;
}
} else {
u = (Union) base;
}
ret = u.addAll( otherBase ) | ret;
return ret;
}
static void addedField( int size ) {
}
public boolean isEquivTo( RWSet other ) {
return other == this;
}
}