From: yeom Date: Tue, 22 Jun 2010 20:46:56 +0000 (+0000) Subject: set up OoOJava analysis. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=3d553ff691f44767fc955245a743e7b4b759a71a;p=IRC.git set up OoOJava analysis. --- diff --git a/Robust/src/Analysis/Disjoint/DisjointAnalysis.java b/Robust/src/Analysis/Disjoint/DisjointAnalysis.java index f150279f..f40261fa 100644 --- a/Robust/src/Analysis/Disjoint/DisjointAnalysis.java +++ b/Robust/src/Analysis/Disjoint/DisjointAnalysis.java @@ -2172,6 +2172,9 @@ getFlaggedAllocationSitesReachableFromTaskPRIVATE(TaskDescriptor td) { return asSetTotal; } + public Set getDescriptorsToAnalyze() { + return descriptorsToAnalyze; + } diff --git a/Robust/src/Analysis/OoOJava/CodePlan.java b/Robust/src/Analysis/OoOJava/CodePlan.java new file mode 100644 index 00000000..efb82ca0 --- /dev/null +++ b/Robust/src/Analysis/OoOJava/CodePlan.java @@ -0,0 +1,108 @@ +package Analysis.OoOJava; + +import IR.*; +import IR.Flat.*; +import java.util.*; +import java.io.*; + + +// a code plan contains information based on analysis results +// for injecting code before and/or after a flat node +public class CodePlan { + + private Hashtable< VariableSourceToken, Set > stall2copySet; + private Set dynamicStallSet; + private Hashtable dynAssign_lhs2rhs; + private Set dynAssign_lhs2curr; + private FlatSESEEnterNode currentSESE; + + public CodePlan( FlatSESEEnterNode fsen ) { + stall2copySet = new Hashtable< VariableSourceToken, Set >(); + dynamicStallSet = new HashSet(); + dynAssign_lhs2rhs = new Hashtable(); + dynAssign_lhs2curr = new HashSet(); + currentSESE = fsen; + } + + public FlatSESEEnterNode getCurrentSESE() { + return currentSESE; + } + + public void addStall2CopySet( VariableSourceToken stallToken, + Set copySet ) { + + if( stall2copySet.containsKey( stallToken ) ) { + Set priorCopySet = stall2copySet.get( stallToken ); + priorCopySet.addAll( copySet ); + } else { + stall2copySet.put( stallToken, copySet ); + } + } + + public Set getStallTokens() { + return stall2copySet.keySet(); + } + + public Set getCopySet( VariableSourceToken stallToken ) { + return stall2copySet.get( stallToken ); + } + + + public void addDynamicStall( TempDescriptor var ) { + dynamicStallSet.add( var ); + } + + public Set getDynamicStallSet() { + return dynamicStallSet; + } + + public void addDynAssign( TempDescriptor lhs, + TempDescriptor rhs ) { + dynAssign_lhs2rhs.put( lhs, rhs ); + } + + public Hashtable getDynAssigns() { + return dynAssign_lhs2rhs; + } + + public void addDynAssign( TempDescriptor lhs ) { + dynAssign_lhs2curr.add( lhs ); + } + + public Set getDynAssignCurr() { + return dynAssign_lhs2curr; + } + + public String toString() { + String s = " PLAN: "; + + if( !stall2copySet.entrySet().isEmpty() ) { + s += "[STATIC STALLS:"; + } + Iterator cpsItr = stall2copySet.entrySet().iterator(); + while( cpsItr.hasNext() ) { + Map.Entry me = (Map.Entry) cpsItr.next(); + VariableSourceToken stallToken = (VariableSourceToken) me.getKey(); + Set copySet = (Set) me.getValue(); + + s += "("+stallToken+"->"+copySet+")"; + } + if( !stall2copySet.entrySet().isEmpty() ) { + s += "]"; + } + + if( !dynamicStallSet.isEmpty() ) { + s += "[DYN STALLS:"+dynamicStallSet+"]"; + } + + if( !dynAssign_lhs2rhs.isEmpty() ) { + s += "[DYN ASSIGNS:"+dynAssign_lhs2rhs+"]"; + } + + if( !dynAssign_lhs2curr.isEmpty() ) { + s += "[DYN ASS2CURR:"+dynAssign_lhs2curr+"]"; + } + + return s; + } +} diff --git a/Robust/src/Analysis/OoOJava/OoOJavaAnalysis.java b/Robust/src/Analysis/OoOJava/OoOJavaAnalysis.java index 95941e6e..ee4cff96 100644 --- a/Robust/src/Analysis/OoOJava/OoOJavaAnalysis.java +++ b/Robust/src/Analysis/OoOJava/OoOJavaAnalysis.java @@ -1,61 +1,729 @@ package Analysis.OoOJava; -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; -import java.io.StringWriter; -import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; -import java.util.LinkedList; -import java.util.Map; import java.util.Set; import java.util.Stack; -import java.util.Map.Entry; -import Analysis.Liveness; + import Analysis.ArrayReferencees; +import Analysis.Liveness; import Analysis.CallGraph.CallGraph; +import Analysis.Disjoint.DisjointAnalysis; +import Analysis.OwnershipAnalysis.AllocationSite; +import Analysis.OwnershipAnalysis.MethodContext; import IR.Descriptor; -import IR.FieldDescriptor; -import IR.MethodDescriptor; import IR.Operation; import IR.State; -import IR.TypeDescriptor; import IR.TypeUtil; import IR.Flat.FKind; -import IR.Flat.FlatCall; -import IR.Flat.FlatCondBranch; import IR.Flat.FlatEdge; -import IR.Flat.FlatElementNode; -import IR.Flat.FlatFieldNode; import IR.Flat.FlatMethod; -import IR.Flat.FlatNew; import IR.Flat.FlatNode; import IR.Flat.FlatOpNode; import IR.Flat.FlatReturnNode; import IR.Flat.FlatSESEEnterNode; import IR.Flat.FlatSESEExitNode; -import IR.Flat.FlatSetElementNode; -import IR.Flat.FlatSetFieldNode; import IR.Flat.FlatWriteDynamicVarNode; import IR.Flat.TempDescriptor; - public class OoOJavaAnalysis { // data from the compiler - private State state; - private TypeUtil typeUtil; - private CallGraph callGraph; + private State state; + private TypeUtil typeUtil; + private CallGraph callGraph; + private DisjointAnalysis disjointAnalysis; + + // an implicit SESE is automatically spliced into + // the IR graph around the C main before this analysis--it + // is nothing special except that we can make assumptions + // about it, such as the whole program ends when it ends + private FlatSESEEnterNode mainSESE; + + // SESEs that are the root of an SESE tree belong to this + // set--the main SESE is always a root, statically SESEs + // inside methods are a root because we don't know how they + // will fit into the runtime tree of SESEs + private Set rootSESEs; + + // simply a set of every reachable SESE in the program, not + // including caller placeholder SESEs + private Set allSESEs; + + // A mapping of flat nodes to the stack of SESEs for that node, where + // an SESE is the child of the SESE directly below it on the stack. + // These stacks do not reflect the heirarchy over methods calls--whenever + // there is an empty stack it means all variables are available. + private Hashtable> seseStacks; + + private Hashtable> livenessRootView; + private Hashtable> livenessVirtualReads; + private Hashtable variableResults; + private Hashtable> notAvailableResults; + private Hashtable codePlans; + + private Hashtable> notAvailableIntoSESE; + + private Hashtable wdvNodesToSpliceIn; + + private Hashtable> mapMethodContextToLiveInAllocationSiteSet; + +// private Hashtable conflictsResults; +// private Hashtable methodSummaryResults; +// private OwnershipAnalysis ownAnalysisForSESEConflicts; +// private Hashtable conflictGraphResults; + + // temporal data structures to track analysis progress. + static private int uniqueLockSetId = 0; + + public static int maxSESEage = -1; + + // use these methods in BuildCode to have access to analysis results + public FlatSESEEnterNode getMainSESE() { + return mainSESE; + } + + public Set getRootSESEs() { + return rootSESEs; + } + + public Set getAllSESEs() { + return allSESEs; + } + + public int getMaxSESEage() { + return maxSESEage; + } + + // may be null + public CodePlan getCodePlan(FlatNode fn) { + CodePlan cp = codePlans.get(fn); + return cp; + } + + public OoOJavaAnalysis(State state, TypeUtil tu, CallGraph callGraph, + DisjointAnalysis disjointAnalysis, Liveness liveness, ArrayReferencees arrayReferencees) { + + double timeStartAnalysis = (double) System.nanoTime(); + + this.state = state; + this.typeUtil = tu; + this.callGraph = callGraph; + this.disjointAnalysis = disjointAnalysis; + this.maxSESEage = state.MLP_MAXSESEAGE; + + rootSESEs = new HashSet(); + allSESEs = new HashSet(); + + seseStacks = new Hashtable>(); + livenessRootView = new Hashtable>(); + livenessVirtualReads = new Hashtable>(); + variableResults = new Hashtable(); + notAvailableResults = new Hashtable>(); + codePlans = new Hashtable(); + wdvNodesToSpliceIn = new Hashtable(); + + notAvailableIntoSESE = new Hashtable>(); + + mapMethodContextToLiveInAllocationSiteSet = new Hashtable>(); + +// conflictsResults = new Hashtable(); +// methodSummaryResults = new Hashtable(); +// conflictGraphResults = new Hashtable(); + + // seseSummaryMap = new Hashtable(); + // isAfterChildSESEIndicatorMap = new Hashtable(); + // conflictGraphLockMap = new Hashtable>(); + + FlatMethod fmMain = state.getMethodFlat(typeUtil.getMain()); + + mainSESE = (FlatSESEEnterNode) fmMain.getNext(0); + mainSESE.setfmEnclosing(fmMain); + mainSESE.setmdEnclosing(fmMain.getMethod()); + mainSESE.setcdEnclosing(fmMain.getMethod().getClassDesc()); + + // 1st pass + // run analysis on each method that is actually called + // reachability analysis already computed this so reuse + Iterator methItr = disjointAnalysis.getDescriptorsToAnalyze().iterator(); + while (methItr.hasNext()) { + Descriptor d = methItr.next(); + FlatMethod fm = state.getMethodFlat(d); + + // find every SESE from methods that may be called + // and organize them into roots and children + buildForestForward(fm); + } + + // 2nd pass, results are saved in FlatSESEEnterNode, so + // intermediate results, for safety, are discarded + Iterator rootItr = rootSESEs.iterator(); + while (rootItr.hasNext()) { + FlatSESEEnterNode root = rootItr.next(); + livenessAnalysisBackward(root, true, null); + } + + // 3rd pass + methItr = disjointAnalysis.getDescriptorsToAnalyze().iterator(); + while (methItr.hasNext()) { + Descriptor d = methItr.next(); + FlatMethod fm = state.getMethodFlat(d); + + // starting from roots do a forward, fixed-point + // variable analysis for refinement and stalls + variableAnalysisForward(fm); + } + + // 4th pass, compute liveness contribution from + // virtual reads discovered in variable pass + rootItr = rootSESEs.iterator(); + while (rootItr.hasNext()) { + FlatSESEEnterNode root = rootItr.next(); + livenessAnalysisBackward(root, true, null); + } + + /* + * SOMETHING IS WRONG WITH THIS, DON'T USE IT UNTIL IT CAN BE FIXED + * + * // 5th pass methItr = ownAnalysis.descriptorsToAnalyze.iterator(); while( + * methItr.hasNext() ) { Descriptor d = methItr.next(); FlatMethod fm = + * state.getMethodFlat( d ); + * + * // prune variable results in one traversal // by removing reference + * variables that are not live pruneVariableResultsWithLiveness( fm ); } + */ + + // 6th pass + methItr = disjointAnalysis.getDescriptorsToAnalyze().iterator(); + while (methItr.hasNext()) { + Descriptor d = methItr.next(); + FlatMethod fm = state.getMethodFlat(d); + + // compute what is not available at every program + // point, in a forward fixed-point pass + notAvailableForward(fm); + } + + } + + private void buildForestForward(FlatMethod fm) { + + // start from flat method top, visit every node in + // method exactly once, find SESEs and remember + // roots and child relationships + Set flatNodesToVisit = new HashSet(); + flatNodesToVisit.add(fm); + + Set visited = new HashSet(); + + Stack seseStackFirst = new Stack(); + seseStacks.put(fm, seseStackFirst); + + while (!flatNodesToVisit.isEmpty()) { + Iterator fnItr = flatNodesToVisit.iterator(); + FlatNode fn = fnItr.next(); + + Stack seseStack = seseStacks.get(fn); + assert seseStack != null; + + flatNodesToVisit.remove(fn); + visited.add(fn); + + buildForest_nodeActions(fn, seseStack, fm); + + for (int i = 0; i < fn.numNext(); i++) { + FlatNode nn = fn.getNext(i); + + if (!visited.contains(nn)) { + flatNodesToVisit.add(nn); + + // clone stack and send along each analysis path + seseStacks.put(nn, (Stack) seseStack.clone()); + } + } + } + } + + private void buildForest_nodeActions(FlatNode fn, Stack seseStack, + FlatMethod fm) { + switch (fn.kind()) { + + case FKind.FlatSESEEnterNode: { + FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn; + + if (!fsen.getIsCallerSESEplaceholder()) { + allSESEs.add(fsen); + } + + fsen.setfmEnclosing(fm); + fsen.setmdEnclosing(fm.getMethod()); + fsen.setcdEnclosing(fm.getMethod().getClassDesc()); + + if (seseStack.empty()) { + rootSESEs.add(fsen); + fsen.setParent(null); + } else { + seseStack.peek().addChild(fsen); + fsen.setParent(seseStack.peek()); + } + + seseStack.push(fsen); + } + break; + + case FKind.FlatSESEExitNode: { + FlatSESEExitNode fsexn = (FlatSESEExitNode) fn; + assert !seseStack.empty(); + FlatSESEEnterNode fsen = seseStack.pop(); + } + break; + + case FKind.FlatReturnNode: { + FlatReturnNode frn = (FlatReturnNode) fn; + if (!seseStack.empty() && !seseStack.peek().getIsCallerSESEplaceholder()) { + throw new Error("Error: return statement enclosed within SESE " + + seseStack.peek().getPrettyIdentifier()); + } + } + break; + + } + } + + private void livenessAnalysisBackward(FlatSESEEnterNode fsen, boolean toplevel, + Hashtable> liveout) { + + // start from an SESE exit, visit nodes in reverse up to + // SESE enter in a fixed-point scheme, where children SESEs + // should already be analyzed and therefore can be skipped + // because child SESE enter node has all necessary info + Set flatNodesToVisit = new HashSet(); + + if (toplevel) { + flatNodesToVisit.add(fsen.getfmEnclosing().getFlatExit()); + } else { + flatNodesToVisit.add(fsen.getFlatExit()); + } + + Hashtable> livenessResults = new Hashtable>(); + + if (toplevel) { + liveout = new Hashtable>(); + } + + while (!flatNodesToVisit.isEmpty()) { + FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next(); + flatNodesToVisit.remove(fn); + + Set prev = livenessResults.get(fn); + + // merge sets from control flow joins + Set u = new HashSet(); + for (int i = 0; i < fn.numNext(); i++) { + FlatNode nn = fn.getNext(i); + Set s = livenessResults.get(nn); + if (s != null) { + u.addAll(s); + } + } + + Set curr = liveness_nodeActions(fn, u, fsen, toplevel, liveout); + + // if a new result, schedule backward nodes for analysis + if (!curr.equals(prev)) { + livenessResults.put(fn, curr); + + // don't flow backwards past current SESE enter + if (!fn.equals(fsen)) { + for (int i = 0; i < fn.numPrev(); i++) { + FlatNode nn = fn.getPrev(i); + flatNodesToVisit.add(nn); + } + } + } + } + + Set s = livenessResults.get(fsen); + if (s != null) { + fsen.addInVarSet(s); + } + // remember liveness per node from the root view as the + // global liveness of variables for later passes to use + if (toplevel) { + livenessRootView.putAll(livenessResults); + } + // post-order traversal, so do children first + Iterator childItr = fsen.getChildren().iterator(); + while (childItr.hasNext()) { + FlatSESEEnterNode fsenChild = childItr.next(); + livenessAnalysisBackward(fsenChild, false, liveout); + } + } + + private Set liveness_nodeActions(FlatNode fn, Set liveIn, + FlatSESEEnterNode currentSESE, boolean toplevel, + Hashtable> liveout) { + switch (fn.kind()) { + + case FKind.FlatSESEExitNode: + if (toplevel) { + FlatSESEExitNode fsexn = (FlatSESEExitNode) fn; + if (!liveout.containsKey(fsexn)) { + liveout.put(fsexn, new HashSet()); + } + liveout.get(fsexn).addAll(liveIn); + } + // no break, sese exits should also execute default actions + + default: { + // handle effects of statement in reverse, writes then reads + TempDescriptor[] writeTemps = fn.writesTemps(); + for (int i = 0; i < writeTemps.length; ++i) { + liveIn.remove(writeTemps[i]); + + if (!toplevel) { + FlatSESEExitNode fsexn = currentSESE.getFlatExit(); + Set livetemps = liveout.get(fsexn); + if (livetemps != null && livetemps.contains(writeTemps[i])) { + // write to a live out temp... + // need to put in SESE liveout set + currentSESE.addOutVar(writeTemps[i]); + } + } + } + + TempDescriptor[] readTemps = fn.readsTemps(); + for (int i = 0; i < readTemps.length; ++i) { + liveIn.add(readTemps[i]); + } - public OoOJavaAnalysis( State state, - TypeUtil tu, - CallGraph callGraph, - Liveness liveness, - ArrayReferencees arrayReferencees - ) { + Set virtualReadTemps = livenessVirtualReads.get(fn); + if (virtualReadTemps != null) { + liveIn.addAll(virtualReadTemps); + } + + } + break; + + } // end switch + + return liveIn; } + + private void variableAnalysisForward(FlatMethod fm) { + + Set flatNodesToVisit = new HashSet(); + flatNodesToVisit.add(fm); + + while (!flatNodesToVisit.isEmpty()) { + FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next(); + flatNodesToVisit.remove(fn); + + Stack seseStack = seseStacks.get(fn); + assert seseStack != null; + + VarSrcTokTable prev = variableResults.get(fn); + + // merge sets from control flow joins + VarSrcTokTable curr = new VarSrcTokTable(); + for (int i = 0; i < fn.numPrev(); i++) { + FlatNode nn = fn.getPrev(i); + VarSrcTokTable incoming = variableResults.get(nn); + curr.merge(incoming); + } + + if (!seseStack.empty()) { + variable_nodeActions(fn, curr, seseStack.peek()); + } + + // if a new result, schedule forward nodes for analysis + if (!curr.equals(prev)) { + variableResults.put(fn, curr); + + for (int i = 0; i < fn.numNext(); i++) { + FlatNode nn = fn.getNext(i); + flatNodesToVisit.add(nn); + } + } + } + } + + private void variable_nodeActions(FlatNode fn, VarSrcTokTable vstTable, + FlatSESEEnterNode currentSESE) { + switch (fn.kind()) { + + case FKind.FlatSESEEnterNode: { + FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn; + assert fsen.equals(currentSESE); + + vstTable.age(currentSESE); + vstTable.assertConsistency(); + } + break; + + case FKind.FlatSESEExitNode: { + FlatSESEExitNode fsexn = (FlatSESEExitNode) fn; + FlatSESEEnterNode fsen = fsexn.getFlatEnter(); + assert currentSESE.getChildren().contains(fsen); + + // remap all of this child's children tokens to be + // from this child as the child exits + vstTable.remapChildTokens(fsen); + + // liveness virtual reads are things that might be + // written by an SESE and should be added to the in-set + // anything virtually read by this SESE should be pruned + // of parent or sibling sources + Set liveVars = livenessRootView.get(fn); + Set fsenVirtReads = vstTable.calcVirtReadsAndPruneParentAndSiblingTokens( + fsen, liveVars); + Set fsenVirtReadsOld = livenessVirtualReads.get(fn); + if (fsenVirtReadsOld != null) { + fsenVirtReads.addAll(fsenVirtReadsOld); + } + livenessVirtualReads.put(fn, fsenVirtReads); + + // then all child out-set tokens are guaranteed + // to be filled in, so clobber those entries with + // the latest, clean sources + Iterator outVarItr = fsen.getOutVarSet().iterator(); + while (outVarItr.hasNext()) { + TempDescriptor outVar = outVarItr.next(); + HashSet ts = new HashSet(); + ts.add(outVar); + VariableSourceToken vst = new VariableSourceToken(ts, fsen, new Integer(0), outVar); + vstTable.remove(outVar); + vstTable.add(vst); + } + vstTable.assertConsistency(); + + } + break; + + case FKind.FlatOpNode: { + FlatOpNode fon = (FlatOpNode) fn; + + if (fon.getOp().getOp() == Operation.ASSIGN) { + TempDescriptor lhs = fon.getDest(); + TempDescriptor rhs = fon.getLeft(); + + vstTable.remove(lhs); + + Set forAddition = new HashSet(); + + Iterator itr = vstTable.get(rhs).iterator(); + while (itr.hasNext()) { + VariableSourceToken vst = itr.next(); + + HashSet ts = new HashSet(); + ts.add(lhs); + + if (currentSESE.getChildren().contains(vst.getSESE())) { + // if the source comes from a child, copy it over + forAddition.add(new VariableSourceToken(ts, vst.getSESE(), vst.getAge(), vst + .getAddrVar())); + } else { + // otherwise, stamp it as us as the source + forAddition.add(new VariableSourceToken(ts, currentSESE, new Integer(0), lhs)); + } + } + + vstTable.addAll(forAddition); + + // only break if this is an ASSIGN op node, + // otherwise fall through to default case + vstTable.assertConsistency(); + break; + } + } + + // note that FlatOpNode's that aren't ASSIGN + // fall through to this default case + default: { + TempDescriptor[] writeTemps = fn.writesTemps(); + if (writeTemps.length > 0) { + + // for now, when writeTemps > 1, make sure + // its a call node, programmer enforce only + // doing stuff like calling a print routine + // assert writeTemps.length == 1; + if (writeTemps.length > 1) { + assert fn.kind() == FKind.FlatCall || fn.kind() == FKind.FlatMethod; + break; + } + + vstTable.remove(writeTemps[0]); + + HashSet ts = new HashSet(); + ts.add(writeTemps[0]); + + vstTable.add(new VariableSourceToken(ts, currentSESE, new Integer(0), writeTemps[0])); + } + + vstTable.assertConsistency(); + } + break; + + } // end switch + } + + private void notAvailableForward(FlatMethod fm) { + + Set flatNodesToVisit = new HashSet(); + flatNodesToVisit.add(fm); + + while (!flatNodesToVisit.isEmpty()) { + FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next(); + flatNodesToVisit.remove(fn); + + Stack seseStack = seseStacks.get(fn); + assert seseStack != null; + + Set prev = notAvailableResults.get(fn); + + Set curr = new HashSet(); + for (int i = 0; i < fn.numPrev(); i++) { + FlatNode nn = fn.getPrev(i); + Set notAvailIn = notAvailableResults.get(nn); + if (notAvailIn != null) { + curr.addAll(notAvailIn); + } + } + + if (!seseStack.empty()) { + notAvailable_nodeActions(fn, curr, seseStack.peek()); + } + + // if a new result, schedule forward nodes for analysis + if (!curr.equals(prev)) { + notAvailableResults.put(fn, curr); + + for (int i = 0; i < fn.numNext(); i++) { + FlatNode nn = fn.getNext(i); + flatNodesToVisit.add(nn); + } + } + } + } + + private void notAvailable_nodeActions(FlatNode fn, Set notAvailSet, + FlatSESEEnterNode currentSESE) { + + // any temps that are removed from the not available set + // at this node should be marked in this node's code plan + // as temps to be grabbed at runtime! + + switch (fn.kind()) { + + case FKind.FlatSESEEnterNode: { + FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn; + assert fsen.equals(currentSESE); + + // keep a copy of what's not available into the SESE + // and restore it at the matching exit node + Set notAvailCopy = new HashSet(); + Iterator tdItr = notAvailSet.iterator(); + while (tdItr.hasNext()) { + notAvailCopy.add(tdItr.next()); + } + notAvailableIntoSESE.put(fsen, notAvailCopy); + + notAvailSet.clear(); + } + break; + + case FKind.FlatSESEExitNode: { + FlatSESEExitNode fsexn = (FlatSESEExitNode) fn; + FlatSESEEnterNode fsen = fsexn.getFlatEnter(); + assert currentSESE.getChildren().contains(fsen); + + notAvailSet.addAll(fsen.getOutVarSet()); + + Set notAvailIn = notAvailableIntoSESE.get(fsen); + assert notAvailIn != null; + notAvailSet.addAll(notAvailIn); + + } + break; + + case FKind.FlatMethod: { + notAvailSet.clear(); + } + + case FKind.FlatOpNode: { + FlatOpNode fon = (FlatOpNode) fn; + + if (fon.getOp().getOp() == Operation.ASSIGN) { + TempDescriptor lhs = fon.getDest(); + TempDescriptor rhs = fon.getLeft(); + + // copy makes lhs same availability as rhs + if (notAvailSet.contains(rhs)) { + notAvailSet.add(lhs); + } else { + notAvailSet.remove(lhs); + } + + // only break if this is an ASSIGN op node, + // otherwise fall through to default case + break; + } + } + + // note that FlatOpNode's that aren't ASSIGN + // fall through to this default case + default: { + TempDescriptor[] writeTemps = fn.writesTemps(); + for (int i = 0; i < writeTemps.length; i++) { + TempDescriptor wTemp = writeTemps[i]; + notAvailSet.remove(wTemp); + } + TempDescriptor[] readTemps = fn.readsTemps(); + for (int i = 0; i < readTemps.length; i++) { + TempDescriptor rTemp = readTemps[i]; + notAvailSet.remove(rTemp); + + // if this variable has exactly one source, potentially + // get other things from this source as well + VarSrcTokTable vstTable = variableResults.get(fn); + + VSTWrapper vstIfStatic = new VSTWrapper(); + Integer srcType = vstTable.getRefVarSrcType(rTemp, currentSESE, vstIfStatic); + + if (srcType.equals(VarSrcTokTable.SrcType_STATIC)) { + + VariableSourceToken vst = vstIfStatic.vst; + + Iterator availItr = vstTable.get(vst.getSESE(), vst.getAge()) + .iterator(); + + // look through things that are also available from same source + while (availItr.hasNext()) { + VariableSourceToken vstAlsoAvail = availItr.next(); + + Iterator refVarItr = vstAlsoAvail.getRefVars().iterator(); + while (refVarItr.hasNext()) { + TempDescriptor refVarAlso = refVarItr.next(); + + // if a variable is available from the same source, AND it ALSO + // only comes from one statically known source, mark it available + VSTWrapper vstIfStaticNotUsed = new VSTWrapper(); + Integer srcTypeAlso = vstTable.getRefVarSrcType(refVarAlso, currentSESE, + vstIfStaticNotUsed); + if (srcTypeAlso.equals(VarSrcTokTable.SrcType_STATIC)) { + notAvailSet.remove(refVarAlso); + } + } + } + } + } + } + break; + + } // end switch + } + } diff --git a/Robust/src/Analysis/OoOJava/SVKey.java b/Robust/src/Analysis/OoOJava/SVKey.java new file mode 100644 index 00000000..e98ff31e --- /dev/null +++ b/Robust/src/Analysis/OoOJava/SVKey.java @@ -0,0 +1,50 @@ +package Analysis.OoOJava; + +import IR.*; +import IR.Flat.*; +import java.util.*; +import java.io.*; + +public class SVKey { + + private FlatSESEEnterNode sese; + private TempDescriptor var; + + public SVKey( FlatSESEEnterNode sese, + TempDescriptor var ) { + this.sese = sese; + this.var = var; + } + + public FlatSESEEnterNode getSESE() { + return sese; + } + + public TempDescriptor getVar() { + return var; + } + + public boolean equals( Object o ) { + if( o == null ) { + return false; + } + + if( !(o instanceof SVKey) ) { + return false; + } + + SVKey k = (SVKey) o; + + return var.equals( k.var ) && + sese.equals( k.sese ); + } + + public int hashCode() { + return (sese.hashCode() << 2)*(var.hashCode() << 5); + } + + + public String toString() { + return "key["+sese.getPrettyIdentifier()+", "+var+"]"; + } +} diff --git a/Robust/src/Analysis/OoOJava/VSTWrapper.java b/Robust/src/Analysis/OoOJava/VSTWrapper.java new file mode 100644 index 00000000..6f17610a --- /dev/null +++ b/Robust/src/Analysis/OoOJava/VSTWrapper.java @@ -0,0 +1,17 @@ +package Analysis.OoOJava; + +import IR.*; +import IR.Flat.*; +import java.util.*; +import java.io.*; + +// the reason for this class is to allow a VariableSourceToken +// to be null in some circumstances + +public class VSTWrapper { + public VariableSourceToken vst; + + public VSTWrapper() { + vst = null; + } +} diff --git a/Robust/src/Analysis/OoOJava/VarSrcTokTable.java b/Robust/src/Analysis/OoOJava/VarSrcTokTable.java new file mode 100644 index 00000000..782d45e0 --- /dev/null +++ b/Robust/src/Analysis/OoOJava/VarSrcTokTable.java @@ -0,0 +1,884 @@ +package Analysis.OoOJava; + +import IR.*; +import IR.Flat.*; +import java.util.*; +import java.io.*; + +// This class formerly had lazy consistency properties, but +// it is being changed so that the full set and the extra +// hash tables to access the full set efficiently by different +// elements will be consistent after EVERY operation. Also, +// a consistent assert method allows a debugger to ask whether +// an operation has produced an inconsistent VarSrcTokTable. + +// in an effort to make sure operations keep the table consistent, +// all public methods that are also used by other methods for +// intermediate results (add and remove are used in other methods) +// there should be a public version that calls the private version +// so consistency is checked after public ops, but not private ops +public class VarSrcTokTable { + + // a set of every token in the table + private HashSet trueSet; + + // these hashtables provide an efficient retreival from the true set + private Hashtable< TempDescriptor, Set > var2vst; + private Hashtable< FlatSESEEnterNode, Set > sese2vst; + private Hashtable< SVKey, Set > sv2vst; + + // maximum age from aging operation + private static final Integer MAX_AGE = new Integer( 2 ); + + public static final Integer SrcType_READY = new Integer( 34 ); + public static final Integer SrcType_STATIC = new Integer( 35 ); + public static final Integer SrcType_DYNAMIC = new Integer( 36 ); + + + public VarSrcTokTable() { + trueSet = new HashSet(); + + sese2vst = new Hashtable< FlatSESEEnterNode, Set >(); + var2vst = new Hashtable< TempDescriptor, Set >(); + sv2vst = new Hashtable< SVKey, Set >(); + + assertConsistency(); + } + + + // make a deep copy of the in table + public VarSrcTokTable( VarSrcTokTable in ) { + this(); + merge( in ); + assertConsistency(); + } + + + public void add( VariableSourceToken vst ) { + addPrivate( vst ); + assertConsistency(); + } + + private void addPrivate( VariableSourceToken vst ) { + + // make sure we aren't clobbering anything! + if( trueSet.contains( vst ) ) { + // if something with the same hashcode is in the true set, they might + // have different reference variable sets because that set is not considered + // in a token's equality, so make sure we smooth that out right here + Iterator vstItr = trueSet.iterator(); + while( vstItr.hasNext() ) { + VariableSourceToken vstAlready = vstItr.next(); + + if( vstAlready.equals( vst ) ) { + + // take out the one that is in (we dont' want collisions in + // any of the other hash map sets either) + removePrivate( vstAlready ); + + // combine reference variable sets + vst.getRefVars().addAll( vstAlready.getRefVars() ); + + // now jump back as we are adding in a brand new token + break; + } + } + } + + trueSet.add( vst ); + + Set s; + + s = sese2vst.get( vst.getSESE() ); + if( s == null ) { + s = new HashSet(); + } + s.add( vst ); + sese2vst.put( vst.getSESE(), s ); + + Iterator refVarItr = vst.getRefVars().iterator(); + while( refVarItr.hasNext() ) { + TempDescriptor refVar = refVarItr.next(); + s = var2vst.get( refVar ); + if( s == null ) { + s = new HashSet(); + } + s.add( vst ); + var2vst.put( refVar, s ); + + SVKey key = new SVKey( vst.getSESE(), refVar ); + s = sv2vst.get( key ); + if( s == null ) { + s = new HashSet(); + } + s.add( vst ); + sv2vst.put( key, s ); + } + } + + public void addAll( Set s ) { + Iterator itr = s.iterator(); + while( itr.hasNext() ) { + addPrivate( itr.next() ); + } + assertConsistency(); + } + + + public Set get() { + return trueSet; + } + + public Set get( FlatSESEEnterNode sese ) { + Set s = sese2vst.get( sese ); + if( s == null ) { + s = new HashSet(); + sese2vst.put( sese, s ); + } + return s; + } + + public Set get( TempDescriptor refVar ) { + Set s = var2vst.get( refVar ); + if( s == null ) { + s = new HashSet(); + var2vst.put( refVar, s ); + } + return s; + } + + public Set get( FlatSESEEnterNode sese, + TempDescriptor refVar ) { + SVKey key = new SVKey( sese, refVar ); + Set s = sv2vst.get( key ); + if( s == null ) { + s = new HashSet(); + sv2vst.put( key, s ); + } + return s; + } + + public Set get( FlatSESEEnterNode sese, + Integer age ) { + + HashSet s0 = (HashSet) sese2vst.get( sese ); + if( s0 == null ) { + s0 = new HashSet(); + sese2vst.put( sese, s0 ); + } + + Set s = (Set) s0.clone(); + Iterator sItr = s.iterator(); + while( sItr.hasNext() ) { + VariableSourceToken vst = sItr.next(); + if( !vst.getAge().equals( age ) ) { + s.remove( vst ); + } + } + + return s; + } + + + // merge now makes a deep copy of incoming stuff because tokens may + // be modified (reference var sets) by later ops that change more + // than one table, causing inconsistency + public void merge( VarSrcTokTable in ) { + + if( in == null ) { + return; + } + + Iterator vstItr = in.trueSet.iterator(); + while( vstItr.hasNext() ) { + VariableSourceToken vst = vstItr.next(); + this.addPrivate( vst.copy() ); + } + + assertConsistency(); + } + + + // remove operations must leave the trueSet + // and the hash maps consistent + public void remove( VariableSourceToken vst ) { + removePrivate( vst ); + assertConsistency(); + } + + private void removePrivate( VariableSourceToken vst ) { + trueSet.remove( vst ); + + Set s; + + s = get( vst.getSESE() ); + if( s != null ) { s.remove( vst ); } + + Iterator refVarItr = vst.getRefVars().iterator(); + while( refVarItr.hasNext() ) { + TempDescriptor refVar = refVarItr.next(); + + s = get( refVar ); + if( s != null ) { + s.remove( vst ); + if( s.isEmpty() ) { + var2vst.remove( refVar ); + } + } + + s = get( vst.getSESE(), refVar ); + if( s != null ) { + s.remove( vst ); + if( s.isEmpty() ) { + sv2vst.remove( new SVKey( vst.getSESE(), refVar ) ); + } + } + } + } + + + public void remove( FlatSESEEnterNode sese ) { + removePrivate( sese ); + assertConsistency(); + } + + public void removePrivate( FlatSESEEnterNode sese ) { + Set s = sese2vst.get( sese ); + if( s == null ) { + return; + } + + Iterator itr = s.iterator(); + while( itr.hasNext() ) { + VariableSourceToken vst = itr.next(); + removePrivate( vst ); + } + + sese2vst.remove( sese ); + } + + + public void remove( TempDescriptor refVar ) { + removePrivate( refVar ); + assertConsistency(); + } + + private void removePrivate( TempDescriptor refVar ) { + Set s = var2vst.get( refVar ); + if( s == null ) { + return; + } + + Set forRemoval = new HashSet(); + + // iterate over tokens that this temp can reference, make a set + // of tokens that need this temp stripped out of them + Iterator itr = s.iterator(); + while( itr.hasNext() ) { + VariableSourceToken vst = itr.next(); + Set refVars = vst.getRefVars(); + assert refVars.contains( refVar ); + forRemoval.add( vst ); + } + + itr = forRemoval.iterator(); + while( itr.hasNext() ) { + + // here's a token marked for removal + VariableSourceToken vst = itr.next(); + Set refVars = vst.getRefVars(); + + // if there was only one one variable + // referencing this token, just take it + // out of the table all together + if( refVars.size() == 1 ) { + removePrivate( vst ); + } + + sv2vst.remove( new SVKey( vst.getSESE(), refVar ) ); + + refVars.remove( refVar ); + } + + var2vst.remove( refVar ); + } + + + public void remove( FlatSESEEnterNode sese, + TempDescriptor var ) { + + // don't seem to need this, don't bother maintaining + // until its clear we need it + assert false; + } + + + // age tokens with respect to SESE curr, where + // any curr tokens increase age by 1 + public void age( FlatSESEEnterNode curr ) { + + Set forRemoval = + new HashSet(); + + Set forAddition = + new HashSet(); + + Iterator itr = trueSet.iterator(); + while( itr.hasNext() ) { + VariableSourceToken vst = itr.next(); + + if( vst.getSESE().equals( curr ) ) { + + // only age if the token isn't already the maximum age + if( vst.getAge() < MAX_AGE ) { + + forRemoval.add( vst ); + + forAddition.add( new VariableSourceToken( vst.getRefVars(), + curr, + vst.getAge() + 1, + vst.getAddrVar() + ) + ); + } + } + } + + itr = forRemoval.iterator(); + while( itr.hasNext() ) { + VariableSourceToken vst = itr.next(); + remove( vst ); + } + + itr = forRemoval.iterator(); + while( itr.hasNext() ) { + VariableSourceToken vst = itr.next(); + add( vst ); + } + + assertConsistency(); + } + + + // at an SESE enter node, all ref vars in the SESE's in-set will + // be copied into the SESE's local scope, change source to itself + public void ownInSet( FlatSESEEnterNode curr ) { + Iterator inVarItr = curr.getInVarSet().iterator(); + while( inVarItr.hasNext() ) { + TempDescriptor inVar = inVarItr.next(); + + remove( inVar ); + assertConsistency(); + + Set refVars = new HashSet(); + refVars.add( inVar ); + add( new VariableSourceToken( refVars, + curr, + new Integer( 0 ), + inVar + ) + ); + assertConsistency(); + } + } + + + // for the given SESE, change child tokens into this parent + public void remapChildTokens( FlatSESEEnterNode curr ) { + + Iterator childItr = curr.getChildren().iterator(); + if( childItr.hasNext() ) { + FlatSESEEnterNode child = childItr.next(); + + // set of VSTs for removal + HashSet removalSet=new HashSet(); + // set of VSTs for additon + HashSet additionSet=new HashSet(); + + Iterator vstItr = get( child ).iterator(); + while( vstItr.hasNext() ) { + VariableSourceToken vst = vstItr.next(); + removalSet.add(vst); + additionSet.add(new VariableSourceToken( vst.getRefVars(), + curr, + new Integer( 0 ), + vst.getAddrVar() + )); + } + + // remove( eah item in forremoval ) + vstItr = removalSet.iterator(); + while( vstItr.hasNext() ) { + VariableSourceToken vst = vstItr.next(); + remove( vst ); + } + // add( each ite inm for additon _ + vstItr = additionSet.iterator(); + while( vstItr.hasNext() ) { + VariableSourceToken vst = vstItr.next(); + add( vst ); + } + } + + assertConsistency(); + } + + + // this method is called at the SESE exit of SESE 'curr' + // if the sources for a variable written by curr can also + // come from curr's parent or curr's siblings then we're not + // sure that curr will actually modify the variable. There are + // many ways to handle this, but for now, mark the variable as + // virtually read so curr insists on having ownership of it + // whether it ends up writing to it or not. It will always, then, + // appear in curr's out-set. + public Set + calcVirtReadsAndPruneParentAndSiblingTokens( FlatSESEEnterNode exiter, + Set liveVars ) { + + Set virtReadSet = new HashSet(); + + FlatSESEEnterNode parent = exiter.getParent(); + if( parent == null ) { + // having no parent means no siblings, too + return virtReadSet; + } + + Set alternateSESEs = new HashSet(); + alternateSESEs.add( parent ); + Iterator childItr = parent.getChildren().iterator(); + while( childItr.hasNext() ) { + FlatSESEEnterNode sibling = childItr.next(); + if( !sibling.equals( exiter ) ) { + alternateSESEs.add( sibling ); + } + } + + // VSTs to remove if they are alternate sources for exiter VSTs + // whose variables will become virtual reads + Set forRemoval = new HashSet(); + + // look at all of this SESE's VSTs at exit... + Iterator vstItr = get( exiter ).iterator(); + while( vstItr.hasNext() ) { + VariableSourceToken vstExiterSrc = vstItr.next(); + + // only interested in tokens that come from our current instance + if( vstExiterSrc.getAge() != 0 ) { + continue; + } + + // for each variable that might come from those sources... + Iterator refVarItr = vstExiterSrc.getRefVars().iterator(); + while( refVarItr.hasNext() ) { + TempDescriptor refVar = refVarItr.next(); + + // only matters for live variables at SESE exit program point + if( !liveVars.contains( refVar ) ) { + continue; + } + + // examine other sources for a variable... + Iterator srcItr = get( refVar ).iterator(); + while( srcItr.hasNext() ) { + VariableSourceToken vstPossibleOtherSrc = srcItr.next(); + + if( vstPossibleOtherSrc.getSESE().equals( exiter ) && + vstPossibleOtherSrc.getAge() > 0 + ) { + // this is an alternate source if its + // an older instance of this SESE + virtReadSet.add( refVar ); + forRemoval.add( vstPossibleOtherSrc ); + + } else if( alternateSESEs.contains( vstPossibleOtherSrc.getSESE() ) ) { + // this is an alternate source from parent or sibling + virtReadSet.add( refVar ); + forRemoval.add( vstPossibleOtherSrc ); + + } else { + assert vstPossibleOtherSrc.getSESE().equals( exiter ); + assert vstPossibleOtherSrc.getAge().equals( 0 ); + } + } + } + } + + vstItr = forRemoval.iterator(); + while( vstItr.hasNext() ) { + VariableSourceToken vst = vstItr.next(); + remove( vst ); + } + assertConsistency(); + + return virtReadSet; + } + + + // get the set of VST's that come from a child + public Set getChildrenVSTs( FlatSESEEnterNode curr ) { + + Set out = new HashSet(); + + Iterator cItr = curr.getChildren().iterator(); + while( cItr.hasNext() ) { + FlatSESEEnterNode child = cItr.next(); + out.addAll( get( child ) ); + } + + return out; + } + + + // given a table from a subsequent program point, decide + // which variables are going from a non-dynamic to a + // dynamic source and return them + public Hashtable + getReadyOrStatic2DynamicSet( VarSrcTokTable nextTable, + Set nextLiveIn, + FlatSESEEnterNode current + ) { + + Hashtable out = + new Hashtable(); + + Iterator itr = var2vst.entrySet().iterator(); + while( itr.hasNext() ) { + Map.Entry me = (Map.Entry) itr.next(); + TempDescriptor var = (TempDescriptor) me.getKey(); + HashSet s1 = (HashSet) me.getValue(); + + // only worth tracking if live + if( nextLiveIn.contains( var ) ) { + + VSTWrapper vstIfStaticBefore = new VSTWrapper(); + VSTWrapper vstIfStaticAfter = new VSTWrapper(); + + Integer srcTypeBefore = this.getRefVarSrcType( var, current, vstIfStaticBefore ); + Integer srcTypeAfter = nextTable.getRefVarSrcType( var, current, vstIfStaticAfter ); + + if( !srcTypeBefore.equals( SrcType_DYNAMIC ) && + srcTypeAfter.equals( SrcType_DYNAMIC ) + ) { + // remember the variable and a source + // it had before crossing the transition + // 1) if it was ready, vstIfStatic.vst is null + // 2) if is was static, use vstIfStatic.vst + out.put( var, vstIfStaticBefore ); + } + } + } + + return out; + } + + + // for some reference variable, return the type of source + // it might have in this table, which might be: + // 1. Ready -- this variable is + // definitely available when you are issued. + // 2. Static -- there is definitely one child SESE with + // a known age that will produce the value + // 3. Dynamic -- we don't know where the value will come + // from statically, so we'll track it dynamically + public Integer getRefVarSrcType( TempDescriptor refVar, + FlatSESEEnterNode current, + VSTWrapper vstIfStatic ) { + assert refVar != null; + assert vstIfStatic != null; + + vstIfStatic.vst = null; + + // when the current SESE is null, that simply means it is + // an unknown placeholder, in which case the system will + // ensure that any variables are READY + if( current == null ) { + return SrcType_READY; + } + + // if there appear to be no sources, it means this variable + // comes from outside of any statically-known SESE scope, + // which means the system guarantees its READY, so jump over + // while loop + Set srcs = get( refVar ); + Iterator itrSrcs = srcs.iterator(); + while( itrSrcs.hasNext() ) { + VariableSourceToken vst = itrSrcs.next(); + + // to make the refVar non-READY we have to find at least + // one child token + if( current.getChildren().contains( vst.getSESE() ) ) { + + // if we ever have at least one child source with an + // unknown age, have to treat var as dynamic + if( vst.getAge().equals( OoOJavaAnalysis.maxSESEage ) ) { + return SrcType_DYNAMIC; + } + + // if we have a known-age child source, this var is + // either static or dynamic now: it's static if this + // source is the only source, otherwise dynamic + if( srcs.size() > 1 ) { + return SrcType_DYNAMIC; + } + + vstIfStatic.vst = vst; + return SrcType_STATIC; + } + } + + // if we never found a child source, all other + // sources must be READY before we could even + // begin executing! + return SrcType_READY; + } + + + // any reference variables that are not live can be pruned + // from the table, and if any VSTs are then no longer + // referenced, they can be dropped as well + // THIS CAUSES INCONSISTENCY, FIX LATER, NOT REQUIRED + public void pruneByLiveness( Set rootLiveSet ) { + + // the set of reference variables in the table minus the + // live set gives the set of reference variables to remove + Set deadRefVars = new HashSet(); + deadRefVars.addAll( var2vst.keySet() ); + + if( rootLiveSet != null ) { + deadRefVars.removeAll( rootLiveSet ); + } + + // just use the remove operation to prune the table now + Iterator deadItr = deadRefVars.iterator(); + while( deadItr.hasNext() ) { + TempDescriptor dead = deadItr.next(); + removePrivate( dead ); + } + + assertConsistency(); + } + + + + // use as an aid for debugging, where true-set is checked + // against the alternate mappings: assert that nothing is + // missing or extra in the alternates + public void assertConsistency() { + + Iterator itr; + Set s; + + Set trueSetByAlts = new HashSet(); + itr = sese2vst.entrySet().iterator(); + while( itr.hasNext() ) { + Map.Entry me = (Map.Entry) itr.next(); + FlatSESEEnterNode sese = (FlatSESEEnterNode) me.getKey(); + HashSet s1 = (HashSet) me.getValue(); + assert s1 != null; + + // the trueSet should have all entries in s1 + assert trueSet.containsAll( s1 ); + + // s1 should not have anything that doesn't appear in trueset + Set sInt = (Set) s1.clone(); + sInt.removeAll( trueSet ); + + assert sInt.isEmpty(); + + // add s1 to a running union--at the end check if trueSet has extra + trueSetByAlts.addAll( s1 ); + } + // make sure trueSet isn't too big + assert trueSetByAlts.containsAll( trueSet ); + + + trueSetByAlts = new HashSet(); + itr = var2vst.entrySet().iterator(); + while( itr.hasNext() ) { + Map.Entry me = (Map.Entry) itr.next(); + TempDescriptor var = (TempDescriptor) me.getKey(); + HashSet s1 = (HashSet) me.getValue(); + assert s1 != null; + + // the trueSet should have all entries in s1 + assert trueSet.containsAll( s1 ); + + // s1 should not have anything that doesn't appear in trueset + Set sInt = (Set) s1.clone(); + sInt.removeAll( trueSet ); + + assert sInt.isEmpty(); + + // add s1 to a running union--at the end check if trueSet has extra + trueSetByAlts.addAll( s1 ); + } + // make sure trueSet isn't too big + assert trueSetByAlts.containsAll( trueSet ); + + + trueSetByAlts = new HashSet(); + itr = sv2vst.entrySet().iterator(); + while( itr.hasNext() ) { + Map.Entry me = (Map.Entry) itr.next(); + SVKey key = (SVKey) me.getKey(); + HashSet s1 = (HashSet) me.getValue(); + assert s1 != null; + + // the trueSet should have all entries in s1 + assert trueSet.containsAll( s1 ); + + // s1 should not have anything that doesn't appear in trueset + Set sInt = (Set) s1.clone(); + sInt.removeAll( trueSet ); + + assert sInt.isEmpty(); + + // add s1 to a running union--at the end check if trueSet has extra + trueSetByAlts.addAll( s1 ); + } + // make sure trueSet isn't too big + assert trueSetByAlts.containsAll( trueSet ); + + + // also check that the reference var sets are consistent + Hashtable > vst2refVars = + new Hashtable >(); + itr = var2vst.entrySet().iterator(); + while( itr.hasNext() ) { + Map.Entry me = (Map.Entry) itr.next(); + TempDescriptor refVar = (TempDescriptor) me.getKey(); + HashSet s1 = (HashSet) me.getValue(); + Iterator vstItr = s1.iterator(); + while( vstItr.hasNext() ) { + VariableSourceToken vst = vstItr.next(); + assert vst.getRefVars().contains( refVar ); + + Set refVarsPart = vst2refVars.get( vst ); + if( refVarsPart == null ) { + refVarsPart = new HashSet(); + } + refVarsPart.add( refVar ); + vst2refVars.put( vst, refVarsPart ); + } + } + itr = vst2refVars.entrySet().iterator(); + while( itr.hasNext() ) { + Map.Entry me = (Map.Entry) itr.next(); + VariableSourceToken vst = (VariableSourceToken) me.getKey(); + Set s1 = (Set) me.getValue(); + + assert vst.getRefVars().equals( s1 ); + } + } + + + public boolean equals( Object o ) { + if( o == null ) { + return false; + } + + if( !(o instanceof VarSrcTokTable) ) { + return false; + } + + VarSrcTokTable table = (VarSrcTokTable) o; + return trueSet.equals( table.trueSet ); + } + + public int hashCode() { + return trueSet.hashCode(); + } + + public Iterator iterator() { + return trueSet.iterator(); + } + + public String toString() { + return toStringPretty(); + } + + public String toStringVerbose() { + return "trueSet ="+trueSet.toString()+"\n"+ + "sese2vst="+sese2vst.toString()+"\n"+ + "var2vst ="+var2vst.toString()+"\n"+ + "sv2vst ="+sv2vst.toString(); + } + + public String toStringPretty() { + String tokHighlighter = "o"; + + String str = "VarSrcTokTable\n"; + Iterator vstItr = trueSet.iterator(); + while( vstItr.hasNext() ) { + str += " "+tokHighlighter+" "+vstItr.next()+"\n"; + } + return str; + } + + public String toStringPrettyVerbose() { + String tokHighlighter = "o"; + + String str = "VarSrcTokTable\n"; + + Set s; + Iterator itr; + Iterator vstItr; + + str += " trueSet\n"; + vstItr = trueSet.iterator(); + while( vstItr.hasNext() ) { + str += " "+tokHighlighter+" "+vstItr.next()+"\n"; + } + + str += " sese2vst\n"; + itr = sese2vst.entrySet().iterator(); + while( itr.hasNext() ) { + Map.Entry me = (Map.Entry) itr.next(); + FlatSESEEnterNode sese = (FlatSESEEnterNode) me.getKey(); + HashSet s1 = (HashSet) me.getValue(); + assert s1 != null; + + str += " "+sese.getPrettyIdentifier()+" -> \n"; + + vstItr = s1.iterator(); + while( vstItr.hasNext() ) { + str += " "+tokHighlighter+" "+vstItr.next()+"\n"; + } + } + + str += " var2vst\n"; + itr = var2vst.entrySet().iterator(); + while( itr.hasNext() ) { + Map.Entry me = (Map.Entry) itr.next(); + TempDescriptor var = (TempDescriptor) me.getKey(); + Set s1 = (Set) me.getValue(); + assert s1 != null; + + str += " "+var+" -> \n"; + + vstItr = s1.iterator(); + while( vstItr.hasNext() ) { + str += " "+tokHighlighter+" "+vstItr.next()+"\n"; + } + } + + str += " sv2vst\n"; + itr = sv2vst.entrySet().iterator(); + while( itr.hasNext() ) { + Map.Entry me = (Map.Entry) itr.next(); + SVKey key = (SVKey) me.getKey(); + Set s1 = (Set) me.getValue(); + assert s1 != null; + + str += " "+key+" -> \n"; + + vstItr = s1.iterator(); + while( vstItr.hasNext() ) { + str += " "+tokHighlighter+" "+vstItr.next()+"\n"; + } + } + + return str; + } +} diff --git a/Robust/src/Analysis/OoOJava/VariableSourceToken.java b/Robust/src/Analysis/OoOJava/VariableSourceToken.java new file mode 100644 index 00000000..1d845074 --- /dev/null +++ b/Robust/src/Analysis/OoOJava/VariableSourceToken.java @@ -0,0 +1,82 @@ +package Analysis.OoOJava; + +import IR.*; +import IR.Flat.*; +import java.util.*; +import java.io.*; + +public class VariableSourceToken { + + private Set refVars; + private FlatSESEEnterNode sese; + private Integer seseAge; + private TempDescriptor addrVar; + + public VariableSourceToken( Set refVars, + FlatSESEEnterNode sese, + Integer seseAge, + TempDescriptor addrVar + ) { + this.refVars = refVars; + this.sese = sese; + this.seseAge = seseAge; + this.addrVar = addrVar; + } + + public Set getRefVars() { + return refVars; + } + + public FlatSESEEnterNode getSESE() { + return sese; + } + + public Integer getAge() { + return seseAge; + } + + public TempDescriptor getAddrVar() { + return addrVar; + } + + public VariableSourceToken copy() { + Set refVarsCopy = new HashSet(); + + Iterator rvItr = refVars.iterator(); + while( rvItr.hasNext() ) { + refVarsCopy.add( rvItr.next() ); + } + + return new VariableSourceToken( refVarsCopy, + sese, + new Integer( seseAge ), + addrVar ); + } + + public boolean equals( Object o ) { + if( o == null ) { + return false; + } + + if( !(o instanceof VariableSourceToken) ) { + return false; + } + + VariableSourceToken vst = (VariableSourceToken) o; + + // the reference vars have no bearing on equality + return sese.equals( vst.sese ) && + addrVar.equals( vst.addrVar ) && + seseAge.equals( vst.seseAge ); + } + + public int hashCode() { + // the reference vars have no bearing on hashCode + return (sese.hashCode() << 3) * (addrVar.hashCode() << 4) ^ seseAge.intValue(); + } + + + public String toString() { + return refVars+"\tref "+addrVar+"\t@"+sese.toPrettyString()+"("+seseAge+")"; + } +} diff --git a/Robust/src/Main/Main.java b/Robust/src/Main/Main.java index 51ebbeb6..2bd8897b 100644 --- a/Robust/src/Main/Main.java +++ b/Robust/src/Main/Main.java @@ -512,7 +512,8 @@ public class Main { CallGraph cg = new CallGraph(state); Liveness l = new Liveness(); ArrayReferencees ar = new ArrayReferencees(state); - OoOJavaAnalysis oa = new OoOJavaAnalysis(state, tu, cg, l, ar); + DisjointAnalysis da = new DisjointAnalysis(state, tu, cg, l, ar); + OoOJavaAnalysis oa = new OoOJavaAnalysis(state, tu, cg, da, l, ar); }