package xsched.analysis.wala.schedule_extraction; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.Map.Entry; import com.ibm.wala.ssa.ISSABasicBlock; public final class JoinNodeFlowData extends NormalNodeFlowData { private static final boolean DEBUG = false; private final EdgeFlowData[] incoming; JoinNodeFlowData(ISSABasicBlock basicBlock, int numIncomingEdges) { super(basicBlock); //this constructor is called when the initial flow data instances are created; so elements in incoming[] can be null before the meet operation ran incoming = new EdgeFlowData[numIncomingEdges]; } void initAndMergeFromIncoming(EdgeFlowData[] incoming) { this.initEmpty(); assert this.incoming.length == incoming.length; for(int i = 0; i < incoming.length; i++) { this.incoming[i] = incoming[i]; } //we do not create a new happensBeforeMap because we have to do the intersection of all //and for that we need the null as a flag of "nothing happened yet" if(DEBUG) System.out.println("JoinNodeFlowData: joining " + basicBlock); for(int i = 0; i < incoming.length; i++) { EdgeFlowData edge = incoming[i]; assert edge != null; //should not happen after we ran the meet operator this.mergeState(edge); } //now we unioned all edges; check that for all edges if an incoming data "knows" about lhs and rhs, it also knows the edge; //otherwise they disagree and we can't keep the edge for(int i = 0; i < this.incoming.length; i++) { EdgeFlowData edge = this.incoming[i]; this.filterUnreliableEdges(edge); } } @Override JoinNodeFlowData duplicate(ISSABasicBlock forBasicBlock) { JoinNodeFlowData data = new JoinNodeFlowData(forBasicBlock, incoming.length); data.copyState(this); return data; } @Override public NormalNodeVisitor createNodeVisitor() { return new JoinNodeVisitor(this); } EdgeFlowData incomingEdgeAtPosition(int pos) { return incoming[pos]; } NormalNodeFlowData incomingDataAtPosition(int pos) { EdgeFlowData edge = incoming[pos]; if(edge != null) { NormalNodeFlowData data = edge.getData(); assert ! data.isInitial(); return data; } else { return null; } } void addPhiVariable(PhiVariable phi, TaskVariable task) { if (phiMappings == null) phiMappings = new HashMap<PhiVariable, Set<TaskVariable>>(); Set<TaskVariable> tasks = phiMappings.get(phi); if(tasks == null) { tasks = new HashSet<TaskVariable>(); phiMappings.put(phi, tasks); } tasks.add(task); } @Override boolean stateEquals(FlowData otherData) { return super.stateEquals(otherData); } protected void filterUnreliableEdges(EdgeFlowData edge) { //iterate a copy of my hb edges and check whether the incoming data agrees if(!edge.isInitial()) { NormalNodeFlowData other = edge.getData(); Iterator<TaskVariable> lhsNodes = this.partialSchedule.iterator(); while(lhsNodes.hasNext()) { TaskVariable lhs = lhsNodes.next(); Iterator<TaskVariable> rhsNodes = this.partialSchedule.getSuccNodes(lhs); while(rhsNodes.hasNext()) { TaskVariable rhs = rhsNodes.next(); //check for each edge whether the other guy agrees on a) the existence of the task variables and b) on the edge lhs->rhs if(other.partialSchedule.containsNode(lhs) && other.partialSchedule.containsNode(rhs)) { if(! other.partialSchedule.hasEdge(lhs, rhs)) //not sure if this throws an concurrent modification exception this.partialSchedule.removeEdge(lhs, rhs); } } } } } //called in the constructor private void mergeState(EdgeFlowData edge) { if(!edge.isInitial()) { NormalNodeFlowData other = edge.getData(); assert ! other.isInitial(); this.loopContexts.addAll(other.loopContexts); this.partialSchedule.addAllNodesAndEdges(other.partialSchedule); if (other.phiMappings != null) { for(Entry<PhiVariable, Set<TaskVariable>> entry : other.phiMappings.entrySet()) { this.addAllPhiVariables(entry.getKey(), entry.getValue()); } } //we saw this edge, so add it to the list of loop contexts if(edge instanceof BackEdgeFlowData) { BackEdgeFlowData backEdge = (BackEdgeFlowData)edge; for(LoopContext lc : this.loopContexts) { this.loopContexts.add(lc.contextByAddingLoop(backEdge)); } } } } @Override public void copyState(FlowData v) { super.copyState(v); assert(v instanceof JoinNodeFlowData); JoinNodeFlowData other = (JoinNodeFlowData)v; assert other.incoming.length == incoming.length; for(int i = 0; i < incoming.length; i++) { incoming[i] = other.incoming[i]; } } @Override public String toString() { return "Join-" + super.toString(); } }