/**
*
*/
package org.joogie.util;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import org.joogie.Options;
import soot.Scene;
import soot.SootField;
import soot.SootMethod;
import soot.jimple.toolkits.pointer.RWSet;
import soot.jimple.toolkits.thread.AbstractRuntimeThread;
import soot.jimple.toolkits.thread.mhp.MhpTester;
import soot.jimple.toolkits.thread.mhp.MhpTransformer;
/**
* @author schaef
* Singleton class that collects information about which SootFields that are modified within a method
* may be modified by other threads.
*/
public class MhpInfo {
private HashMap<SootMethod, Set<SootField>> sharedFields = new HashMap<SootMethod, Set<SootField>>();
private static MhpInfo instance = null;
public static MhpInfo v() {
if (instance==null) {
if (!Options.v().useSoundThreads()) {
throw new RuntimeException("You can only use MhpInfo if the SoundThread option is enabled");
}
instance = new MhpInfo();
}
return instance;
}
public static void resetInstance() {
instance = null;
}
/**
* Returns the set of fields that are modified in "m"
* and may be modified by other threads at the same time.
* @param m
* @return
*/
public Set<SootField> getSharedFields(SootMethod m) {
if (this.sharedFields.containsKey(m)) {
return this.sharedFields.get(m);
}
return new HashSet<SootField>();
}
/**
*
*/
private MhpInfo() {
MhpTester mhpt = MhpTransformer.v().getMhpTester();
List<HashSet<SootField>> read_sets = new LinkedList<HashSet<SootField>>();
List<HashSet<SootField>> write_sets = new LinkedList<HashSet<SootField>>();
List<AbstractRuntimeThread> arts = mhpt.getThreads();
if (arts == null) {
return;
}
for (AbstractRuntimeThread art : arts) {
HashSet<SootField> read_fields = new HashSet<SootField>();
HashSet<SootField> write_fields = new HashSet<SootField>();
for (int i=0; i<art.methodCount(); i++) {
Object o = art.getMethod(i);
if (o instanceof SootMethod) {
SootMethod m = (SootMethod)o;
RWSet read_set = Scene.v().getSideEffectAnalysis().nonTransitiveReadSet(m);
RWSet write_set = Scene.v().getSideEffectAnalysis().nonTransitiveWriteSet(m);
read_fields.addAll(collectFields(read_set));
write_fields.addAll(collectFields(write_set));
} else {
throw new RuntimeException("Not implemented "+o.getClass().toString());
}
}
read_sets.add(read_fields);
write_sets.add(write_fields);
}
for (int i=0; i<read_sets.size(); i++) {
HashSet<SootField> shared_vars = new HashSet<SootField>();
for (int j=0; j<read_sets.size(); j++) {
//if (i==j) continue;
HashSet<SootField> rw = new HashSet<SootField>(read_sets.get(i));
rw.retainAll(write_sets.get(j));
if (!rw.isEmpty()) {
shared_vars.addAll(rw);
}
HashSet<SootField> ww = new HashSet<SootField>(write_sets.get(i));
ww.retainAll(write_sets.get(j));
if (!ww.isEmpty()) {
shared_vars.addAll(ww);
}
}
AbstractRuntimeThread art = arts.get(i);
for (int j=0; j< art.methodCount(); j++) {
Object o = art.getMethod(j);
if (o instanceof SootMethod) {
SootMethod m = (SootMethod)o;
if (!this.sharedFields.containsKey(m)) {
this.sharedFields.put(m, new HashSet<SootField>());
}
this.sharedFields.get(m).addAll(shared_vars);
} else {
throw new RuntimeException("Not implemented.");
}
}
}
}
private Set<SootField> collectFields(RWSet rwset) {
HashSet<SootField> fields = new HashSet<SootField>();
if (rwset!=null) {
for (Object obj : rwset.getGlobals()) {
if (obj instanceof SootField) {
SootField sf = (SootField)obj;
fields.add(sf);
} else if (obj instanceof String) {
Log.error("String case not implemented "+((String)obj));
} else {
throw new RuntimeException("case not implemented "+obj.getClass().toString());
}
}
for (Object obj : rwset.getFields()) {
if (obj instanceof SootField) {
SootField sf = (SootField)obj;
fields.add(sf);
} else if (obj instanceof String) {
Log.error("String case not implemented "+((String)obj));
} else {
throw new RuntimeException("case not implemented "+obj.getClass().toString());
}
}
}
return fields;
}
/**
* Debug print the set of shared variables for each SootMethod.
*/
public void printParallelFields() {
StringBuilder sb = new StringBuilder();
for (Entry<SootMethod, Set<SootField>> entry : this.sharedFields.entrySet()) {
sb.append("Method " + entry.getKey().getBytecodeSignature()+" shares \n the following fields with other threads:\n");
for (SootField sf : entry.getValue()) {
sb.append("\t");
sb.append(sf.getName());
sb.append("\n");
}
}
Log.error(sb.toString());
}
}