X-Git-Url: http://plrg.eecs.uci.edu/git/?p=IRC.git;a=blobdiff_plain;f=Robust%2Fsrc%2FAnalysis%2FSSJava%2FDefinitelyWrittenCheck.java;h=c1f482419fe6af507ba347ac155485b36d79064e;hp=b030a6db5658d0a3c5ee6bfea7f2097462cca501;hb=9d767c1f5cef3242ff67473368e5ad327c340bfa;hpb=6fd21f1dfbc64d2ff8eba5e3c0f9e7928318cea2 diff --git a/Robust/src/Analysis/SSJava/DefinitelyWrittenCheck.java b/Robust/src/Analysis/SSJava/DefinitelyWrittenCheck.java index b030a6db..c1f48241 100644 --- a/Robust/src/Analysis/SSJava/DefinitelyWrittenCheck.java +++ b/Robust/src/Analysis/SSJava/DefinitelyWrittenCheck.java @@ -1,5 +1,6 @@ package Analysis.SSJava; +import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; @@ -7,6 +8,7 @@ import java.util.LinkedList; import java.util.Set; import java.util.Stack; +import Analysis.Liveness; import Analysis.CallGraph.CallGraph; import Analysis.Loops.LoopFinder; import IR.Descriptor; @@ -22,13 +24,13 @@ import IR.Flat.FlatElementNode; import IR.Flat.FlatFieldNode; import IR.Flat.FlatLiteralNode; import IR.Flat.FlatMethod; +import IR.Flat.FlatNew; import IR.Flat.FlatNode; import IR.Flat.FlatOpNode; import IR.Flat.FlatSetElementNode; import IR.Flat.FlatSetFieldNode; import IR.Flat.TempDescriptor; import IR.Tree.Modifiers; -import Util.Pair; public class DefinitelyWrittenCheck { @@ -36,51 +38,59 @@ public class DefinitelyWrittenCheck { State state; CallGraph callGraph; - int debugcount = 0; + Liveness liveness; - // maps a descriptor to its known dependents: namely - // methods or tasks that call the descriptor's method - // AND are part of this analysis (reachable from main) - private Hashtable> mapDescriptorToSetDependents; + int debugcount = 0; // maps a flat node to its WrittenSet: this keeps all heap path overwritten // previously. - private Hashtable>> mapFlatNodeToWrittenSet; + private Hashtable>> mapFlatNodeToMustWriteSet; // maps a temp descriptor to its heap path // each temp descriptor has a unique heap path since we do not allow any // alias. private Hashtable> mapHeapPath; + // maps a temp descriptor to its composite location + private Hashtable> mapDescriptorToLocationPath; + // maps a flat method to the READ that is the set of heap path that is // expected to be written before method invocation - private Hashtable>> mapFlatMethodToRead; + private Hashtable>> mapFlatMethodToReadSet; - // maps a flat method to the OVERWRITE that is the set of heap path that is - // overwritten on every possible path during method invocation - private Hashtable>> mapFlatMethodToOverWrite; + // maps a flat method to the must-write set that is the set of heap path that + // is overwritten on every possible path during method invocation + private Hashtable>> mapFlatMethodToMustWriteSet; - // maps a flat method to the WRITE that is the set of heap path that is - // written to - private Hashtable>> mapFlatMethodToWrite; + // maps a flat method to the DELETE SET that is a set of heap path to shared + // locations that are + // written to but not overwritten by the higher value + private Hashtable mapFlatMethodToDeleteSet; - // points to method containing SSJAVA Loop - private MethodDescriptor methodContainingSSJavaLoop; + private Hashtable mapFlatMethodToMustClearMap; - // maps a flatnode to definitely written analysis mapping M - private Hashtable, Hashtable>> definitelyWrittenResults; + // maps a flat method to the S SET that is a set of heap path to shared + // locations that are overwritten by the higher value + private Hashtable mapFlatMethodToSharedLocMap; - // maps a method descriptor to its current summary during the analysis - // then analysis reaches fixed-point, this mapping will have the final summary - // for each method descriptor - private Hashtable mapMethodDescriptorToCompleteClearingSummary; + // maps a flat method to the may-wirte set that is the set of heap path that + // might be written to + private Hashtable>> mapFlatMethodToMayWriteSet; - // maps a method descriptor to the merged incoming caller's current - // overwritten status - private Hashtable mapMethodDescriptorToInitialClearingSummary; + // maps a call site to the read set contributed by all callees + private Hashtable>> mapFlatNodeToBoundReadSet; + + // maps a call site to the must write set contributed by all callees + private Hashtable>> mapFlatNodeToBoundMustWriteSet; - // maps a flat node to current partial results - private Hashtable mapFlatNodeToClearingSummary; + // maps a call site to the may read set contributed by all callees + private Hashtable>> mapFlatNodeToBoundMayWriteSet; + + // points to method containing SSJAVA Loop + private MethodDescriptor methodContainingSSJavaLoop; + + // maps a flatnode to definitely written analysis mapping M + private Hashtable, Set>> mapFlatNodetoEventLoopMap; // maps shared location to the set of descriptors which belong to the shared // location @@ -91,140 +101,107 @@ public class DefinitelyWrittenCheck { // when analyzing flatcall, need to re-schedule set of callee private Set calleesToEnqueue; - // maps heap path to the mapping of a shared location and the set of reading - // descriptors - // it is for setting clearance flag when all read set is overwritten - private Hashtable, Hashtable>> mapHeapPathToLocSharedDescReadSet; + private Set possibleCalleeReadSummarySetToCaller; public static final String arrayElementFieldName = "___element_"; static protected Hashtable mapTypeToArrayField; - private Set possibleCalleeCompleteSummarySetToCaller; + // maps a method descriptor to the merged incoming caller's current + // reading status + // it is for setting clearance flag when all read set is overwritten + private Hashtable mapMethodDescriptorToReadSummary; + + private Hashtable, NTuple>> mapMethodToSharedLocCoverSet; - private LinkedList sortedDescriptors; + private Hashtable mapFlatNodeToSharedLocMapping; + private Hashtable mapFlatNodeToDeleteSet; + private Hashtable mapFlatNodeToMustClearMap; - private FlatNode ssjavaLoopEntrance; private LoopFinder ssjavaLoop; private Set loopIncElements; private Set> calleeUnionBoundReadSet; - private Set> calleeIntersectBoundOverWriteSet; - private Set> calleeBoundWriteSet; + private Set> calleeIntersectBoundMustWriteSet; + private Set> calleeUnionBoundMayWriteSet; + private SharedLocMap calleeUnionBoundDeleteSet; + private SharedLocMap calleeIntersectBoundSharedSet; + private SharedLocMap calleeIntersectBoundMustClearSet; + + Set liveInTempSetToEventLoop; private Hashtable mapDescToLocation; private TempDescriptor LOCAL; + public static int MAXAGE = 1; + public DefinitelyWrittenCheck(SSJavaAnalysis ssjava, State state) { this.state = state; this.ssjava = ssjava; this.callGraph = ssjava.getCallGraph(); - this.mapFlatNodeToWrittenSet = new Hashtable>>(); - this.mapDescriptorToSetDependents = new Hashtable>(); + this.mapFlatNodeToMustWriteSet = new Hashtable>>(); this.mapHeapPath = new Hashtable>(); - this.mapFlatMethodToRead = new Hashtable>>(); - this.mapFlatMethodToOverWrite = new Hashtable>>(); - this.mapFlatMethodToWrite = new Hashtable>>(); - this.definitelyWrittenResults = - new Hashtable, Hashtable>>(); + this.mapDescriptorToLocationPath = new Hashtable>(); + this.mapFlatMethodToReadSet = new Hashtable>>(); + this.mapFlatMethodToMustWriteSet = new Hashtable>>(); + this.mapFlatMethodToMayWriteSet = new Hashtable>>(); + this.mapFlatNodetoEventLoopMap = + new Hashtable, Set>>(); this.calleeUnionBoundReadSet = new HashSet>(); - this.calleeIntersectBoundOverWriteSet = new HashSet>(); - this.calleeBoundWriteSet = new HashSet>(); + this.calleeIntersectBoundMustWriteSet = new HashSet>(); + this.calleeUnionBoundMayWriteSet = new HashSet>(); - this.mapMethodDescriptorToCompleteClearingSummary = - new Hashtable(); - this.mapMethodDescriptorToInitialClearingSummary = - new Hashtable(); this.methodDescriptorsToVisitStack = new Stack(); this.calleesToEnqueue = new HashSet(); - this.possibleCalleeCompleteSummarySetToCaller = new HashSet(); this.mapTypeToArrayField = new Hashtable(); this.LOCAL = new TempDescriptor("LOCAL"); this.mapDescToLocation = new Hashtable(); - this.mapHeapPathToLocSharedDescReadSet = - new Hashtable, Hashtable>>(); + this.possibleCalleeReadSummarySetToCaller = new HashSet(); + this.mapMethodDescriptorToReadSummary = new Hashtable(); + this.mapFlatNodeToBoundReadSet = new Hashtable>>(); + this.mapFlatNodeToBoundMustWriteSet = new Hashtable>>(); + this.mapFlatNodeToBoundMayWriteSet = new Hashtable>>(); + this.mapFlatNodeToSharedLocMapping = new Hashtable(); + this.mapFlatMethodToDeleteSet = new Hashtable(); + this.calleeUnionBoundDeleteSet = new SharedLocMap(); + this.calleeIntersectBoundSharedSet = new SharedLocMap(); + this.mapFlatMethodToSharedLocMap = new Hashtable(); + this.mapMethodToSharedLocCoverSet = + new Hashtable, NTuple>>(); + this.mapFlatNodeToDeleteSet = new Hashtable(); + this.liveness = new Liveness(); + this.liveInTempSetToEventLoop = new HashSet(); + this.mapFlatNodeToMustClearMap = new Hashtable(); + this.calleeIntersectBoundMustClearSet = new SharedLocMap(); + this.mapFlatMethodToMustClearMap = new Hashtable(); } public void definitelyWrittenCheck() { if (!ssjava.getAnnotationRequireSet().isEmpty()) { - methodReadOverWriteAnalysis(); - writtenAnalyis(); - sharedLocationAnalysis(); - checkSharedLocationResult(); - } - } - - private void checkSharedLocationResult() { - - // mapping of method containing ssjava loop has the final result of - // shared location analysis - - ClearingSummary result = - mapMethodDescriptorToCompleteClearingSummary.get(methodContainingSSJavaLoop); + initialize(); - System.out.println("\n\n#RESULT=" + result); + methodReadWriteSetAnalysis(); + computeSharedCoverSet(); - Set> hpKeySet = result.keySet(); - for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) { - NTuple hpKey = (NTuple) iterator.next(); - SharedStatus state = result.get(hpKey); - Set locKeySet = state.getLocationSet(); - for (Iterator iterator2 = locKeySet.iterator(); iterator2.hasNext();) { - Location locKey = (Location) iterator2.next(); - if (!state.getFlag(locKey)) { - printNotClearedResult(result); - throw new Error( - "Some concrete locations of the shared abstract location are not cleared at the same time:"); - } - } - } - - } + sharedLocAnalysis(); - private void printNotClearedResult(ClearingSummary result) { - Set> keySet = result.keySet(); + eventLoopAnalysis(); - for (Iterator iterator = keySet.iterator(); iterator.hasNext();) { - NTuple hpKey = (NTuple) iterator.next(); - SharedStatus status = result.get(hpKey); - Hashtable, Boolean>> map = status.getMap(); - Set locKeySet = map.keySet(); - for (Iterator iterator2 = locKeySet.iterator(); iterator2.hasNext();) { - Location locKey = (Location) iterator2.next(); - if (status.haveWriteEffect(locKey)) { - Pair, Boolean> pair = map.get(locKey); - if (!pair.getSecond().booleanValue()) { - // not cleared! - System.out.println("Concrete locations of the shared location '" + locKey - + "' are not cleared out, which are reachable through the heap path '" + hpKey - + "'"); - } - } - } } - } - private void sharedLocationAnalysis() { - // verify that all concrete locations of shared location are cleared out at - // the same time once per the out-most loop - - computeReadSharedDescriptorSet(); - - System.out.println("###"); - System.out.println("READ SHARED=" + mapHeapPathToLocSharedDescReadSet); + private void sharedLocAnalysis() { - // methodDescriptorsToVisitStack.clear(); - // methodDescriptorsToVisitStack.add(sortedDescriptors.peekFirst()); - - LinkedList descriptorListToAnalyze = - (LinkedList) sortedDescriptors.clone(); + // perform method READ/OVERWRITE analysis + LinkedList descriptorListToAnalyze = ssjava.getSortedDescriptors(); // current descriptors to visit in fixed-point interprocedural analysis, // prioritized by // dependency in the call graph methodDescriptorsToVisitStack.clear(); + descriptorListToAnalyze.removeFirst(); + Set methodDescriptorToVistSet = new HashSet(); methodDescriptorToVistSet.addAll(descriptorListToAnalyze); @@ -235,101 +212,117 @@ public class DefinitelyWrittenCheck { // analyze scheduled methods until there are no more to visit while (!methodDescriptorsToVisitStack.isEmpty()) { + // start to analyze leaf node MethodDescriptor md = methodDescriptorsToVisitStack.pop(); + FlatMethod fm = state.getMethodFlat(md); - ClearingSummary completeSummary = - sharedLocation_analyzeMethod(md, (md.equals(methodContainingSSJavaLoop))); - - ClearingSummary prevCompleteSummary = mapMethodDescriptorToCompleteClearingSummary.get(md); - - if (!completeSummary.equals(prevCompleteSummary)) { + SharedLocMap sharedLocMap = new SharedLocMap(); + SharedLocMap deleteSet = new SharedLocMap(); + SharedLocMap mustClearMap = new SharedLocMap(); - ClearingSummary summaryFromCaller = mapMethodDescriptorToInitialClearingSummary.get(md); - // System.out.println("###"); - // System.out.println("# summaryFromCaller=" + summaryFromCaller); - // System.out.println("# completeSummary=" + completeSummary); - // System.out.println("# prev=" + prevCompleteSummary); - // System.out.println("# changed!\n"); + sharedLoc_analyzeMethod(fm, sharedLocMap, deleteSet, mustClearMap); + SharedLocMap prevSharedLocMap = mapFlatMethodToSharedLocMap.get(fm); + SharedLocMap prevDeleteSet = mapFlatMethodToDeleteSet.get(fm); + SharedLocMap prevMustClearMap = mapFlatMethodToMustClearMap.get(fm); - mapMethodDescriptorToCompleteClearingSummary.put(md, completeSummary); + if (!(deleteSet.equals(prevDeleteSet) && sharedLocMap.equals(prevSharedLocMap) && mustClearMap + .equals(prevMustClearMap))) { + mapFlatMethodToSharedLocMap.put(fm, sharedLocMap); + mapFlatMethodToDeleteSet.put(fm, deleteSet); + mapFlatMethodToMustClearMap.put(fm, mustClearMap); // results for callee changed, so enqueue dependents caller for - // further analysis - Iterator depsItr = getDependents(md).iterator(); + // further + // analysis + Iterator depsItr = ssjava.getDependents(md).iterator(); while (depsItr.hasNext()) { MethodDescriptor methodNext = depsItr.next(); - if (!methodDescriptorsToVisitStack.contains(methodNext)) { + if (!methodDescriptorsToVisitStack.contains(methodNext) + && methodDescriptorToVistSet.contains(methodNext)) { methodDescriptorsToVisitStack.add(methodNext); } - } - // if there is set of callee to be analyzed, - // add this set into the top of stack - Iterator calleeIter = calleesToEnqueue.iterator(); - while (calleeIter.hasNext()) { - MethodDescriptor mdNext = calleeIter.next(); - if (!methodDescriptorsToVisitStack.contains(mdNext)) { - methodDescriptorsToVisitStack.add(mdNext); - } } - calleesToEnqueue.clear(); } } - } + sharedLoc_analyzeEventLoop(); - private ClearingSummary sharedLocation_analyzeMethod(MethodDescriptor md, - boolean onlyVisitSSJavaLoop) { + } + private void sharedLoc_analyzeEventLoop() { if (state.SSJAVADEBUG) { - System.out.println("Definite clearance for shared locations Analyzing: " + md + " " - + onlyVisitSSJavaLoop); + System.out.println("SSJAVA: Definite clearance for shared locations Analyzing: eventloop"); } + SharedLocMap sharedLocMap = new SharedLocMap(); + SharedLocMap deleteSet = new SharedLocMap(); + SharedLocMap mustClearMap = new SharedLocMap(); + sharedLoc_analyzeBody(state.getMethodFlat(methodContainingSSJavaLoop), + ssjava.getSSJavaLoopEntrance(), sharedLocMap, deleteSet, mustClearMap, true); - FlatMethod fm = state.getMethodFlat(md); + } - // intraprocedural analysis - Set flatNodesToVisit = new HashSet(); + private void sharedLoc_analyzeMethod(FlatMethod fm, SharedLocMap sharedLocMap, + SharedLocMap deleteSet, SharedLocMap mustClearMap) { + if (state.SSJAVADEBUG) { + System.out.println("SSJAVA: Definite clearance for shared locations Analyzing: " + fm); + } - // start a new mapping of partial results for each flat node - mapFlatNodeToClearingSummary = new Hashtable(); + sharedLoc_analyzeBody(fm, fm, sharedLocMap, deleteSet, mustClearMap, false); - if (onlyVisitSSJavaLoop) { - flatNodesToVisit.add(ssjavaLoopEntrance); - } else { - flatNodesToVisit.add(fm); - } + } + + private void sharedLoc_analyzeBody(FlatMethod fm, FlatNode startNode, SharedLocMap sharedLocMap, + SharedLocMap deleteSet, SharedLocMap mustClearMap, boolean isEventLoopBody) { - Set returnNodeSet = new HashSet(); + // intraprocedural analysis + Set flatNodesToVisit = new HashSet(); + flatNodesToVisit.add(startNode); while (!flatNodesToVisit.isEmpty()) { FlatNode fn = flatNodesToVisit.iterator().next(); flatNodesToVisit.remove(fn); - ClearingSummary curr = new ClearingSummary(); + SharedLocMap currSharedSet = new SharedLocMap(); + SharedLocMap currDeleteSet = new SharedLocMap(); + SharedLocMap currMustClearMap = new SharedLocMap(); - Set prevSet = new HashSet(); for (int i = 0; i < fn.numPrev(); i++) { FlatNode prevFn = fn.getPrev(i); - ClearingSummary in = mapFlatNodeToClearingSummary.get(prevFn); - if (in != null) { - prevSet.add(in); + SharedLocMap inSharedLoc = mapFlatNodeToSharedLocMapping.get(prevFn); + if (inSharedLoc != null) { + mergeSharedLocMap(currSharedSet, inSharedLoc); + } + + SharedLocMap inDeleteLoc = mapFlatNodeToDeleteSet.get(prevFn); + if (inDeleteLoc != null) { + mergeDeleteSet(currDeleteSet, inDeleteLoc); + } + + SharedLocMap inMustClearMap = mapFlatNodeToMustClearMap.get(prevFn); + if (inMustClearMap != null) { + mergeSharedLocMap(currMustClearMap, inMustClearMap); } + } - mergeSharedLocationAnaylsis(curr, prevSet); - sharedLocation_nodeActions(md, fn, curr, returnNodeSet, onlyVisitSSJavaLoop); - ClearingSummary clearingPrev = mapFlatNodeToClearingSummary.get(fn); + sharedLoc_nodeActions(fm, fn, currSharedSet, currDeleteSet, currMustClearMap, sharedLocMap, + deleteSet, mustClearMap, isEventLoopBody); - if (!curr.equals(clearingPrev)) { - mapFlatNodeToClearingSummary.put(fn, curr); + SharedLocMap prevSharedSet = mapFlatNodeToSharedLocMapping.get(fn); + SharedLocMap prevDeleteSet = mapFlatNodeToDeleteSet.get(fn); + SharedLocMap prevMustClearMap = mapFlatNodeToMustClearMap.get(fn); + if (!(currSharedSet.equals(prevSharedSet) && currDeleteSet.equals(prevDeleteSet) && currMustClearMap + .equals(prevMustClearMap))) { + mapFlatNodeToSharedLocMapping.put(fn, currSharedSet); + mapFlatNodeToDeleteSet.put(fn, currDeleteSet); + mapFlatNodeToMustClearMap.put(fn, currMustClearMap); for (int i = 0; i < fn.numNext(); i++) { FlatNode nn = fn.getNext(i); - - if (!onlyVisitSSJavaLoop || (onlyVisitSSJavaLoop && loopIncElements.contains(nn))) { + if ((!isEventLoopBody) || loopIncElements.contains(nn)) { flatNodesToVisit.add(nn); } @@ -338,159 +331,69 @@ public class DefinitelyWrittenCheck { } - ClearingSummary completeSummary = new ClearingSummary(); - Set summarySet = new HashSet(); - - if (onlyVisitSSJavaLoop) { - // when analyzing ssjava loop, - // complete summary is merging of all previous nodes of ssjava loop - // entrance - for (int i = 0; i < ssjavaLoopEntrance.numPrev(); i++) { - ClearingSummary frnSummary = - mapFlatNodeToClearingSummary.get(ssjavaLoopEntrance.getPrev(i)); - if (frnSummary != null) { - summarySet.add(frnSummary); - } - } - } else { - // merging all exit node summary into the complete summary - if (!returnNodeSet.isEmpty()) { - for (Iterator iterator = returnNodeSet.iterator(); iterator.hasNext();) { - FlatNode frn = (FlatNode) iterator.next(); - ClearingSummary frnSummary = mapFlatNodeToClearingSummary.get(frn); - summarySet.add(frnSummary); - } - } - } - mergeSharedLocationAnaylsis(completeSummary, summarySet); + } - if (md.getSymbol().startsWith("decodeFrame")) { - System.out.println("#"); - System.out.println("# method=" + md); - System.out.println("XXXXX summarySet=" + summarySet); - System.out.println("XXXXX completeSummary=" + completeSummary); - System.out.println("#"); - } + private void sharedLoc_nodeActions(FlatMethod fm, FlatNode fn, SharedLocMap curr, + SharedLocMap currDeleteSet, SharedLocMap currMustClearMap, SharedLocMap sharedLocMap, + SharedLocMap deleteSet, SharedLocMap mustClearMap, boolean isEventLoopBody) { - return completeSummary; - } + MethodDescriptor md = fm.getMethod(); - private void sharedLocation_nodeActions(MethodDescriptor caller, FlatNode fn, - ClearingSummary curr, Set returnNodeSet, boolean isSSJavaLoop) { + SharedLocMap killSet = new SharedLocMap(); + SharedLocMap genSet = new SharedLocMap(); TempDescriptor lhs; TempDescriptor rhs; FieldDescriptor fld; - switch (fn.kind()) { - case FKind.FlatMethod: { - FlatMethod fm = (FlatMethod) fn; + NTuple fieldLocTuple = null; + Location fieldLoc = null; + boolean isHigherWriteCase = false; - ClearingSummary summaryFromCaller = - mapMethodDescriptorToInitialClearingSummary.get(fm.getMethod()); + switch (fn.kind()) { - Set inSet = new HashSet(); - if (summaryFromCaller != null) { - inSet.add(summaryFromCaller); - mergeSharedLocationAnaylsis(curr, inSet); - } + case FKind.FlatOpNode: { - } - break; + if (isEventLoopBody) { + FlatOpNode fon = (FlatOpNode) fn; - case FKind.FlatOpNode: { - FlatOpNode fon = (FlatOpNode) fn; - lhs = fon.getDest(); - rhs = fon.getLeft(); + if (fon.getOp().getOp() == Operation.ASSIGN) { + lhs = fon.getDest(); + rhs = fon.getLeft(); - if (fon.getOp().getOp() == Operation.ASSIGN) { - if (rhs.getType().isImmutable() && isSSJavaLoop) { - // in ssjavaloop, we need to take care about reading local variables! - NTuple rhsHeapPath = new NTuple(); - NTuple lhsHeapPath = new NTuple(); - rhsHeapPath.add(LOCAL); - lhsHeapPath.add(LOCAL); - if (!lhs.getSymbol().startsWith("neverused")) { - readLocation(curr, rhsHeapPath, getLocation(rhs), rhs); - writeLocation(curr, lhsHeapPath, getLocation(lhs), lhs); - } - } - } + if (!lhs.getSymbol().startsWith("neverused") && !lhs.getSymbol().startsWith("leftop") + && !lhs.getSymbol().startsWith("rightop") && rhs.getType().isImmutable()) { - } - break; + if (mapHeapPath.containsKey(rhs)) { + Location dstLoc = getLocation(lhs); + if (dstLoc != null && ssjava.isSharedLocation(dstLoc)) { + NTuple lhsHeapPath = computePath(lhs); + NTuple lhsLocTuple = mapDescriptorToLocationPath.get(lhs); - case FKind.FlatFieldNode: - case FKind.FlatElementNode: { + Location srcLoc = getLocation(lhs); - if (fn.kind() == FKind.FlatFieldNode) { - FlatFieldNode ffn = (FlatFieldNode) fn; - lhs = ffn.getDst(); - rhs = ffn.getSrc(); - fld = ffn.getField(); - } else { - FlatElementNode fen = (FlatElementNode) fn; - lhs = fen.getDst(); - rhs = fen.getSrc(); - TypeDescriptor td = rhs.getType().dereference(); - fld = getArrayField(td); - } + // computing gen/kill set + computeKILLSetForWrite(curr, killSet, lhsLocTuple, lhsHeapPath); - // read field - NTuple srcHeapPath = mapHeapPath.get(rhs); + if (!ssjava.isSameHeightWrite(fn)) { + computeGENSetForHigherWrite(curr, killSet, lhsLocTuple, lhsHeapPath); + updateDeleteSetForHigherWrite(currDeleteSet, lhsLocTuple, lhsHeapPath); + } else { + computeGENSetForSameHeightWrite(curr, killSet, lhsLocTuple, lhsHeapPath); + updateDeleteSetForSameHeightWrite(currDeleteSet, lhsLocTuple, lhsHeapPath); + } - if (srcHeapPath != null) { - // if lhs srcHeapPath is null, it means that it is not reachable from - // callee's parameters. so just ignore it - NTuple fldHeapPath = new NTuple(srcHeapPath.getList()); - - // if (!fld.getType().isArray() && fld.getType().isImmutable()) { - // addReadDescriptor(fldHeapPath, getLocation(fld), fld); - // } else { - // if (fn.kind() == FKind.FlatFieldNode) { - // mapDescToLocation.put(lhs, getLocation(fld)); - // readLocation(curr, fldHeapPath, getLocation(fld), fld); - // } else { - // fldHeapPath.add(fld); - // } - // mapHeapPath.put(lhs, fldHeapPath); - // } - - if (!fld.getType().isArray() && fld.getType().isImmutable()) { - Location loc; - if (fn.kind() == FKind.FlatElementNode) { - // array element read case - loc = mapDescToLocation.get(rhs); - NTuple newHeapPath = new NTuple(); - for (int i = 0; i < fldHeapPath.size() - 1; i++) { - newHeapPath.add(fldHeapPath.get(i)); + } + } else { + break; } - Descriptor desc = fldHeapPath.get(fldHeapPath.size() - 1); - if (desc instanceof FieldDescriptor) { - fld = (FieldDescriptor) desc; - fldHeapPath = newHeapPath; - readLocation(curr, fldHeapPath, loc, fld); - } - } else { - loc = getLocation(fld); - readLocation(curr, fldHeapPath, loc, fld); } - } else { - if (fn.kind() != FKind.FlatElementNode) { - // if it is multi dimensional array, do not need to add heap path - // because all accesses from the same array is represented by - // "_element_" - fldHeapPath.add(fld); - } - mapHeapPath.put(lhs, fldHeapPath); } } - // } - } break; @@ -502,324 +405,271 @@ public class DefinitelyWrittenCheck { lhs = fsfn.getDst(); fld = fsfn.getField(); rhs = fsfn.getSrc(); + fieldLoc = (Location) fld.getType().getExtension(); } else { - FlatSetElementNode fsen = (FlatSetElementNode) fn; - lhs = fsen.getDst(); - rhs = fsen.getSrc(); - TypeDescriptor td = lhs.getType().dereference(); - fld = getArrayField(td); + break; } - // write(field) - NTuple lhsHeapPath = computePath(lhs); - NTuple fldHeapPath = new NTuple(lhsHeapPath.getList()); - if (fld.getType().isImmutable()) { - writeLocation(curr, fldHeapPath, getLocation(fld), fld); + if (!isEventLoopBody && fieldLoc.getDescriptor().equals(md)) { + // if the field belongs to the local lattice, no reason to calculate + // shared location + break; + } - Descriptor desc = fldHeapPath.get(fldHeapPath.size() - 1); - if (desc instanceof FieldDescriptor) { - NTuple arrayPath = new NTuple(); - for (int i = 0; i < fldHeapPath.size() - 1; i++) { - arrayPath.add(fldHeapPath.get(i)); + fieldLocTuple = new NTuple(); + if (fld.isStatic()) { + if (fld.isFinal()) { + // in this case, fld has TOP location + Location topLocation = Location.createTopLocation(md); + fieldLocTuple.add(topLocation); + } else { + fieldLocTuple.addAll(deriveGlobalLocationTuple(md)); + if (fn.kind() == FKind.FlatSetFieldNode) { + fieldLocTuple.add((Location) fld.getType().getExtension()); } - SharedStatus state = getState(curr, arrayPath); - state.setWriteEffect(getLocation(desc)); } } else { - // updates reference field case: - fldHeapPath.add(fld); - updateWriteEffectOnReferenceField(curr, fldHeapPath); + fieldLocTuple.addAll(deriveLocationTuple(md, lhs)); + if (fn.kind() == FKind.FlatSetFieldNode) { + fieldLocTuple.add((Location) fld.getType().getExtension()); + } } - } - break; - - case FKind.FlatCall: { - - FlatCall fc = (FlatCall) fn; - - if (ssjava.isSSJavaUtil(fc.getMethod().getClassDesc())) { - // ssjava util case! - // have write effects on the first argument - - if (fc.getArg(0).getType().isArray()) { - // updates reference field case: - // 2. if there exists a tuple t in sharing summary that starts with - // hp(x) then, set flag of tuple t to 'true' - NTuple argHeapPath = computePath(fc.getArg(0)); + // shared loc extension + Location srcLoc = getLocation(rhs); + if (ssjava.isSharedLocation(fieldLoc)) { + // only care the case that loc(f) is shared location + // write(field) - Location loc = getLocation(fc.getArg(0)); - NTuple newHeapPath = new NTuple(); - for (int i = 0; i < argHeapPath.size() - 1; i++) { - newHeapPath.add(argHeapPath.get(i)); - } - fld = (FieldDescriptor) argHeapPath.get(argHeapPath.size() - 1); - argHeapPath = newHeapPath; + // NTuple fieldLocTuple = new NTuple(); + // fieldLocTuple.addAll(mapDescriptorToLocationPath.get(lhs)); + // fieldLocTuple.add(fieldLoc); - writeLocation(curr, argHeapPath, loc, fld); + NTuple fldHeapPath = new NTuple(); + fldHeapPath.addAll(computePath(lhs)); + if (fn.kind() == FKind.FlatSetFieldNode) { + fldHeapPath.add(fld); } - } else { - // find out the set of callees - MethodDescriptor mdCallee = fc.getMethod(); - FlatMethod fmCallee = state.getMethodFlat(mdCallee); - Set setPossibleCallees = new HashSet(); - // TypeDescriptor typeDesc = fc.getThis().getType(); - setPossibleCallees.addAll(callGraph.getMethods(mdCallee)); - - possibleCalleeCompleteSummarySetToCaller.clear(); - - for (Iterator iterator = setPossibleCallees.iterator(); iterator.hasNext();) { - MethodDescriptor mdPossibleCallee = (MethodDescriptor) iterator.next(); - FlatMethod calleeFlatMethod = state.getMethodFlat(mdPossibleCallee); + // computing gen/kill set + computeKILLSetForWrite(curr, killSet, fieldLocTuple, fldHeapPath); - addDependent(mdPossibleCallee, // callee - caller); // caller + if (!ssjava.isSameHeightWrite(fn)) { + computeGENSetForHigherWrite(curr, genSet, fieldLocTuple, fldHeapPath); + updateDeleteSetForHigherWrite(currDeleteSet, fieldLocTuple, fldHeapPath); - calleesToEnqueue.add(mdPossibleCallee); + isHigherWriteCase = true; - // updates possible callee's initial summary using caller's current - // writing status - ClearingSummary prevCalleeInitSummary = - mapMethodDescriptorToInitialClearingSummary.get(mdPossibleCallee); - - ClearingSummary calleeInitSummary = - bindHeapPathOfCalleeCallerEffects(fc, calleeFlatMethod, curr); - - Set inSet = new HashSet(); - if (prevCalleeInitSummary != null) { - inSet.add(prevCalleeInitSummary); - mergeSharedLocationAnaylsis(calleeInitSummary, inSet); - } + } else { + computeGENSetForSameHeightWrite(curr, genSet, fieldLocTuple, fldHeapPath); + updateDeleteSetForSameHeightWrite(currDeleteSet, fieldLocTuple, fldHeapPath); + } - // if changes, update the init summary - // and reschedule the callee for analysis - if (!calleeInitSummary.equals(prevCalleeInitSummary)) { - // System.out.println("#CALLEE INIT CHANGED=" + mdPossibleCallee); - // System.out.println("# prev=" + prevCalleeInitSummary); - // System.out.println("# current=" + calleeInitSummary); - // System.out.println("#"); + } - if (!methodDescriptorsToVisitStack.contains(mdPossibleCallee)) { - methodDescriptorsToVisitStack.add(mdPossibleCallee); - } + } + break; - mapMethodDescriptorToInitialClearingSummary.put(mdPossibleCallee, calleeInitSummary); - } + case FKind.FlatCall: { + FlatCall fc = (FlatCall) fn; - } + bindHeapPathCallerArgWithCaleeParamForSharedLoc(fm.getMethod(), fc); - // contribute callee's writing effects to the caller - mergeSharedLocationAnaylsis(curr, possibleCalleeCompleteSummarySetToCaller); - if (fc.getMethod().getSymbol().startsWith("decode")) { - System.out.println("XXXXX callee " + fc + " summary=" - + possibleCalleeCompleteSummarySetToCaller); - System.out.println("XXXXX curr=" + curr); - } + // computing gen/kill set + generateKILLSetForFlatCall(curr, killSet); + generateGENSetForFlatCall(curr, genSet); + Set> locTupleSet = calleeIntersectBoundMustClearSet.keySet(); + for (Iterator iterator = locTupleSet.iterator(); iterator.hasNext();) { + NTuple locTupleKey = (NTuple) iterator.next(); + currMustClearMap.addWrite(locTupleKey, calleeIntersectBoundMustClearSet.get(locTupleKey)); } } break; - case FKind.FlatReturnNode: { - returnNodeSet.add(fn); + case FKind.FlatExit: { + // merge the current delete/shared loc mapping + mergeSharedLocMap(sharedLocMap, curr); + mergeDeleteSet(deleteSet, currDeleteSet); + mergeSharedLocMap(mustClearMap, currMustClearMap); } break; } - } - - private void updateWriteEffectOnReferenceField(ClearingSummary curr, NTuple heapPath) { + computeNewMapping(curr, killSet, genSet); + if (isHigherWriteCase) { + // check all locations with the same shared location are cleared out at this point + Set> writtenSet = curr.get(fieldLocTuple); + Set requirementSet = ssjava.getSharedDescSet(fieldLoc); - // DEBUG! - // System.out.println("UPDATE WRITE REF=" + heapPath); - // Descriptor d = heapPath.get(heapPath.size() - 1); - // boolean print = false; - // if (d instanceof FieldDescriptor) { - // FieldDescriptor fd = (FieldDescriptor) d; - // if (fd.getSymbol().equals("si")) { - // System.out.println("UPDATE PREV CURR=" + curr); - // print = true; - // } - // } - // 2. if there exists a tuple t in sharing summary that starts with - // hp(x) then, set flag of tuple t to 'true' - Set> hpKeySet = curr.keySet(); - for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) { - NTuple hpKey = (NTuple) iterator.next(); - if (hpKey.startsWith(heapPath)) { - curr.get(hpKey).updateFlag(true); + if (checkAllSharedLocationsAreOverwritten(requirementSet, writtenSet)) { + currMustClearMap.addWrite(fieldLocTuple, writtenSet); } } - - // if (print) { - // System.out.println("UPDATE CURR=" + curr); - // } } - private ClearingSummary bindHeapPathOfCalleeCallerEffects(FlatCall fc, - FlatMethod calleeFlatMethod, ClearingSummary curr) { + private boolean checkAllSharedLocationsAreOverwritten(Set sharedDescSet, + Set> writtenSet) { + + if (sharedDescSet == null || writtenSet == null) { + return false; + } + Set writtenDescSet = new HashSet(); + for (Iterator iterator = writtenSet.iterator(); iterator.hasNext();) { + NTuple tuple = (NTuple) iterator.next(); + writtenDescSet.add(tuple.get(tuple.size() - 1)); + } + + return writtenDescSet.containsAll(sharedDescSet); + // return sharedDescSet.containsAll(writtenDescSet); - ClearingSummary boundSet = new ClearingSummary(); + } - // create mapping from arg idx to its heap paths - Hashtable> mapArgIdx2CallerArgHeapPath = - new Hashtable>(); + private void generateGENSetForFlatCall(SharedLocMap curr, SharedLocMap genSet) { - if (fc.getThis() != null) { - // arg idx is starting from 'this' arg - NTuple thisHeapPath = mapHeapPath.get(fc.getThis()); - if (thisHeapPath == null) { - // method is called without creating new flat node representing 'this' - thisHeapPath = new NTuple(); - thisHeapPath.add(fc.getThis()); - } + Set> locTupleSet = calleeIntersectBoundSharedSet.keySet(); + for (Iterator iterator = locTupleSet.iterator(); iterator.hasNext();) { + NTuple locTupleKey = (NTuple) iterator.next(); + genSet.addWrite(locTupleKey, curr.get(locTupleKey)); + genSet.addWrite(locTupleKey, calleeIntersectBoundSharedSet.get(locTupleKey)); - mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(0), thisHeapPath); + genSet.removeWriteAll(locTupleKey, calleeUnionBoundDeleteSet.get(locTupleKey)); } - for (int i = 0; i < fc.numArgs(); i++) { - TempDescriptor arg = fc.getArg(i); - NTuple argHeapPath = computePath(arg); - mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(i + 1), argHeapPath); - } - - Hashtable mapParamIdx2ParamTempDesc = - new Hashtable(); - int offset = 0; - if (calleeFlatMethod.getMethod().isStatic()) { - // static method does not have implicit 'this' arg - offset = 1; - } - for (int i = 0; i < calleeFlatMethod.numParameters(); i++) { - TempDescriptor param = calleeFlatMethod.getParameter(i); - mapParamIdx2ParamTempDesc.put(Integer.valueOf(i + offset), param); - } - - // binding caller's writing effects to callee's params - for (int i = 0; i < calleeFlatMethod.numParameters(); i++) { - NTuple argHeapPath = mapArgIdx2CallerArgHeapPath.get(Integer.valueOf(i)); - - if (argHeapPath != null) { - // if method is static, the first argument is nulll because static - // method does not have implicit "THIS" arg - TempDescriptor calleeParamHeapPath = mapParamIdx2ParamTempDesc.get(Integer.valueOf(i)); - - // iterate over caller's writing effect set - Set> hpKeySet = curr.keySet(); - for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) { - NTuple hpKey = (NTuple) iterator.next(); - // current element is reachable caller's arg - // so need to bind it to the caller's side and add it to the - // callee's - // init summary - if (hpKey.startsWith(argHeapPath)) { - NTuple boundHeapPath = replace(hpKey, argHeapPath, calleeParamHeapPath); - boundSet.put(boundHeapPath, curr.get(hpKey).clone()); - } + } - } - } + private void generateKILLSetForFlatCall(SharedLocMap curr, SharedLocMap killSet) { + Set> locTupleSet = calleeIntersectBoundSharedSet.keySet(); + for (Iterator iterator = locTupleSet.iterator(); iterator.hasNext();) { + NTuple locTupleKey = (NTuple) iterator.next(); + killSet.addWrite(locTupleKey, curr.get(locTupleKey)); } - // contribute callee's complete summary into the caller's current summary - ClearingSummary calleeCompleteSummary = - mapMethodDescriptorToCompleteClearingSummary.get(calleeFlatMethod.getMethod()); - if (calleeCompleteSummary != null) { - ClearingSummary boundCalleeEfffects = new ClearingSummary(); - for (int i = 0; i < calleeFlatMethod.numParameters(); i++) { - // for (int i = 0; i < fc.numArgs(); i++) { - NTuple argHeapPath = mapArgIdx2CallerArgHeapPath.get(Integer.valueOf(i)); + } - if (argHeapPath != null) { - // if method is static, the first argument is nulll because static - // method does not have implicit "THIS" arg - TempDescriptor calleeParamHeapPath = mapParamIdx2ParamTempDesc.get(Integer.valueOf(i)); + private void mergeDeleteSet(SharedLocMap currDeleteSet, SharedLocMap inDeleteLoc) { - // iterate over callee's writing effect set - Set> hpKeySet = calleeCompleteSummary.keySet(); - for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) { - NTuple hpKey = (NTuple) iterator.next(); - // current element is reachable caller's arg - // so need to bind it to the caller's side and add it to the - // callee's - // init summary - if (hpKey.startsWith(calleeParamHeapPath)) { + Set> locTupleKeySet = inDeleteLoc.keySet(); - NTuple boundHeapPathForCaller = replace(hpKey, argHeapPath); + for (Iterator iterator = locTupleKeySet.iterator(); iterator.hasNext();) { + NTuple locTupleKey = (NTuple) iterator.next(); - boundCalleeEfffects.put(boundHeapPathForCaller, calleeCompleteSummary.get(hpKey) - .clone()); + Set> inSet = inDeleteLoc.get(locTupleKey); + currDeleteSet.addWrite(locTupleKey, inSet); - } - } + } + } - } + private void computeNewMapping(SharedLocMap curr, SharedLocMap killSet, SharedLocMap genSet) { + curr.kill(killSet); + curr.gen(genSet); + } - } - possibleCalleeCompleteSummarySetToCaller.add(boundCalleeEfffects); - } + private void updateDeleteSetForHigherWrite(SharedLocMap currDeleteSet, NTuple locTuple, + NTuple hp) { + currDeleteSet.removeWrite(locTuple, hp); + } - return boundSet; + private void updateDeleteSetForSameHeightWrite(SharedLocMap currDeleteSet, + NTuple locTuple, NTuple hp) { + currDeleteSet.addWrite(locTuple, hp); } - private NTuple replace(NTuple hpKey, NTuple argHeapPath) { + private void computeGENSetForHigherWrite(SharedLocMap curr, SharedLocMap genSet, + NTuple locTuple, NTuple hp) { + Set> currWriteSet = curr.get(locTuple); - // replace the head of heap path with caller's arg path - // for example, heap path 'param.a.b' in callee's side will be replaced with - // (corresponding arg heap path).a.b for caller's side + if (currWriteSet != null) { + genSet.addWrite(locTuple, currWriteSet); + } + genSet.addWrite(locTuple, hp); + } - NTuple bound = new NTuple(); + private void computeGENSetForSameHeightWrite(SharedLocMap curr, SharedLocMap genSet, + NTuple locTuple, NTuple hp) { + Set> currWriteSet = curr.get(locTuple); - for (int i = 0; i < argHeapPath.size(); i++) { - bound.add(argHeapPath.get(i)); + if (currWriteSet != null) { + genSet.addWrite(locTuple, currWriteSet); } + genSet.removeWrite(locTuple, hp); + } - for (int i = 1; i < hpKey.size(); i++) { - bound.add(hpKey.get(i)); + private void computeKILLSetForWrite(SharedLocMap curr, SharedLocMap killSet, + NTuple locTuple, NTuple hp) { + + Set> writeSet = curr.get(locTuple); + if (writeSet != null) { + killSet.addWrite(locTuple, writeSet); } - return bound; } - private NTuple replace(NTuple effectHeapPath, - NTuple argHeapPath, TempDescriptor calleeParamHeapPath) { - // replace the head of caller's heap path with callee's param heap path + private void mergeSharedLocMap(SharedLocMap currSharedSet, SharedLocMap in) { - NTuple boundHeapPath = new NTuple(); - boundHeapPath.add(calleeParamHeapPath); + Set> locTupleKeySet = in.keySet(); + for (Iterator iterator = locTupleKeySet.iterator(); iterator.hasNext();) { + NTuple locTupleKey = (NTuple) iterator.next(); - for (int i = argHeapPath.size(); i < effectHeapPath.size(); i++) { - boundHeapPath.add(effectHeapPath.get(i)); + Set> inSet = in.get(locTupleKey); + Set> currSet = currSharedSet.get(locTupleKey); + if (currSet == null) { + currSet = new HashSet>(); + currSet.addAll(inSet); + currSharedSet.addWrite(locTupleKey, currSet); + } + currSet.retainAll(inSet); } - return boundHeapPath; } - private void computeReadSharedDescriptorSet() { - Set methodDescriptorsToAnalyze = new HashSet(); - methodDescriptorsToAnalyze.addAll(ssjava.getAnnotationRequireSet()); + private void computeSharedCoverSet() { + LinkedList descriptorListToAnalyze = ssjava.getSortedDescriptors(); + + // current descriptors to visit in fixed-point interprocedural analysis, + // prioritized by + // dependency in the call graph + methodDescriptorsToVisitStack.clear(); + + descriptorListToAnalyze.removeFirst(); + + Set methodDescriptorToVistSet = new HashSet(); + methodDescriptorToVistSet.addAll(descriptorListToAnalyze); + + while (!descriptorListToAnalyze.isEmpty()) { + MethodDescriptor md = descriptorListToAnalyze.removeFirst(); + methodDescriptorsToVisitStack.add(md); + } - for (Iterator iterator = methodDescriptorsToAnalyze.iterator(); iterator.hasNext();) { - MethodDescriptor md = (MethodDescriptor) iterator.next(); + // analyze scheduled methods until there are no more to visit + while (!methodDescriptorsToVisitStack.isEmpty()) { + MethodDescriptor md = methodDescriptorsToVisitStack.pop(); FlatMethod fm = state.getMethodFlat(md); - computeReadSharedDescriptorSet_analyzeMethod(fm, md.equals(methodContainingSSJavaLoop)); + computeSharedCoverSet_analyzeMethod(fm, md.equals(methodContainingSSJavaLoop)); } + computeSharedCoverSetForEventLoop(); + + } + + private void computeSharedCoverSetForEventLoop() { + computeSharedCoverSet_analyzeMethod(state.getMethodFlat(methodContainingSSJavaLoop), true); } - private void computeReadSharedDescriptorSet_analyzeMethod(FlatMethod fm, - boolean onlyVisitSSJavaLoop) { + private void computeSharedCoverSet_analyzeMethod(FlatMethod fm, boolean onlyVisitSSJavaLoop) { + + MethodDescriptor md = fm.getMethod(); Set flatNodesToVisit = new HashSet(); + Set visited = new HashSet(); if (onlyVisitSSJavaLoop) { - flatNodesToVisit.add(ssjavaLoopEntrance); + flatNodesToVisit.add(ssjava.getSSJavaLoopEntrance()); } else { flatNodesToVisit.add(fm); } @@ -829,119 +679,131 @@ public class DefinitelyWrittenCheck { flatNodesToVisit.remove(fn); visited.add(fn); - computeReadSharedDescriptorSet_nodeActions(fn, onlyVisitSSJavaLoop); + computeSharedCoverSet_nodeActions(md, fn, onlyVisitSSJavaLoop); for (int i = 0; i < fn.numNext(); i++) { FlatNode nn = fn.getNext(i); + if (!visited.contains(nn)) { if (!onlyVisitSSJavaLoop || (onlyVisitSSJavaLoop && loopIncElements.contains(nn))) { flatNodesToVisit.add(nn); } } + } } } - private void computeReadSharedDescriptorSet_nodeActions(FlatNode fn, boolean isSSJavaLoop) { - + private void computeSharedCoverSet_nodeActions(MethodDescriptor md, FlatNode fn, + boolean isEventLoopBody) { TempDescriptor lhs; TempDescriptor rhs; FieldDescriptor fld; switch (fn.kind()) { - case FKind.FlatOpNode: { - FlatOpNode fon = (FlatOpNode) fn; - lhs = fon.getDest(); - rhs = fon.getLeft(); - if (fon.getOp().getOp() == Operation.ASSIGN) { - if (rhs.getType().isImmutable() && isSSJavaLoop && (!rhs.getSymbol().startsWith("srctmp"))) { - // in ssjavaloop, we need to take care about reading local variables! - NTuple rhsHeapPath = new NTuple(); - NTuple lhsHeapPath = new NTuple(); - rhsHeapPath.add(LOCAL); - Location loc = getLocation(rhs); - addReadDescriptor(rhsHeapPath, loc, rhs); + case FKind.FlatLiteralNode: { + FlatLiteralNode fln = (FlatLiteralNode) fn; + lhs = fln.getDst(); + + NTuple lhsLocTuple = new NTuple(); + lhsLocTuple.add(Location.createTopLocation(md)); + mapDescriptorToLocationPath.put(lhs, lhsLocTuple); + + if (lhs.getType().isPrimitive() && !lhs.getSymbol().startsWith("neverused") + && !lhs.getSymbol().startsWith("srctmp")) { + // only need to care about composite location case here + if (lhs.getType().getExtension() instanceof SSJavaType) { + CompositeLocation compLoc = ((SSJavaType) lhs.getType().getExtension()).getCompLoc(); + Location lastLocElement = compLoc.get(compLoc.getSize() - 1); } } } break; - case FKind.FlatFieldNode: - case FKind.FlatElementNode: { - - if (fn.kind() == FKind.FlatFieldNode) { - FlatFieldNode ffn = (FlatFieldNode) fn; - lhs = ffn.getDst(); - rhs = ffn.getSrc(); - fld = ffn.getField(); - } else { - FlatElementNode fen = (FlatElementNode) fn; - lhs = fen.getDst(); - rhs = fen.getSrc(); - TypeDescriptor td = rhs.getType().dereference(); - fld = getArrayField(td); - } - - if (fld.isStatic() && fld.isFinal()) { - break; - } + case FKind.FlatOpNode: { + FlatOpNode fon = (FlatOpNode) fn; + // for a normal assign node, need to propagate lhs's location path to + // rhs + if (fon.getOp().getOp() == Operation.ASSIGN) { + rhs = fon.getLeft(); + lhs = fon.getDest(); - // read field - NTuple srcHeapPath = mapHeapPath.get(rhs); - if (srcHeapPath != null) { - // if srcHeapPath is null, it means that it is not reachable from - // callee's parameters. so just ignore it + if (!lhs.getSymbol().startsWith("neverused") && !lhs.getSymbol().startsWith("leftop") + && !lhs.getSymbol().startsWith("rightop")) { + + if (mapHeapPath.containsKey(rhs)) { + NTuple rhsLocTuple = new NTuple(); + NTuple lhsLocTuple = new NTuple(); + if (mapDescriptorToLocationPath.containsKey(rhs)) { + mapDescriptorToLocationPath.put(lhs, deriveLocationTuple(md, rhs)); + lhsLocTuple = mapDescriptorToLocationPath.get(lhs); + } else { + // rhs side + if (rhs.getType().getExtension() != null + && rhs.getType().getExtension() instanceof SSJavaType) { + + if (((SSJavaType) rhs.getType().getExtension()).getCompLoc() != null) { + rhsLocTuple.addAll(((SSJavaType) rhs.getType().getExtension()).getCompLoc() + .getTuple()); + } + + } else { + NTuple locTuple = deriveLocationTuple(md, rhs); + if (locTuple != null) { + rhsLocTuple.addAll(locTuple); + } + } + if (rhsLocTuple.size() > 0) { + mapDescriptorToLocationPath.put(rhs, rhsLocTuple); + } + + // lhs side + if (lhs.getType().getExtension() != null + && lhs.getType().getExtension() instanceof SSJavaType) { + lhsLocTuple.addAll(((SSJavaType) lhs.getType().getExtension()).getCompLoc() + .getTuple()); + mapDescriptorToLocationPath.put(lhs, lhsLocTuple); + } else if (mapDescriptorToLocationPath.get(rhs) != null) { + // propagate rhs's location to lhs + lhsLocTuple.addAll(mapDescriptorToLocationPath.get(rhs)); + mapDescriptorToLocationPath.put(lhs, lhsLocTuple); + } + } - NTuple fldHeapPath = new NTuple(srcHeapPath.getList()); + if (isEventLoopBody && lhs.getType().isPrimitive() + && !lhs.getSymbol().startsWith("srctmp")) { - if (!fld.getType().isArray() && fld.getType().isImmutable()) { + NTuple lhsHeapPath = computePath(lhs); - Location loc; - if (fn.kind() == FKind.FlatElementNode) { - // array element read case - loc = mapDescToLocation.get(rhs); - NTuple newHeapPath = new NTuple(); - for (int i = 0; i < fldHeapPath.size() - 1; i++) { - newHeapPath.add(fldHeapPath.get(i)); - } + if (lhsLocTuple != null) { + addMayWrittenSet(md, lhsLocTuple, lhsHeapPath); + } - Descriptor desc = fldHeapPath.get(fldHeapPath.size() - 1); - if (desc instanceof FieldDescriptor) { - fld = (FieldDescriptor) desc; - fldHeapPath = newHeapPath; - addReadDescriptor(fldHeapPath, loc, fld); } } else { - loc = getLocation(fld); - addReadDescriptor(fldHeapPath, loc, fld); + break; } - } else { - // propagate rhs's heap path to the lhs - if (fn.kind() == FKind.FlatElementNode) { - mapDescToLocation.put(lhs, getLocation(rhs)); - } else { - fldHeapPath.add(fld); - } - mapHeapPath.put(lhs, fldHeapPath); } } - } break; case FKind.FlatSetFieldNode: case FKind.FlatSetElementNode: { + // x.f=y; + if (fn.kind() == FKind.FlatSetFieldNode) { FlatSetFieldNode fsfn = (FlatSetFieldNode) fn; lhs = fsfn.getDst(); fld = fsfn.getField(); + rhs = fsfn.getSrc(); } else { FlatSetElementNode fsen = (FlatSetElementNode) fn; lhs = fsen.getDst(); @@ -950,218 +812,437 @@ public class DefinitelyWrittenCheck { fld = getArrayField(td); } - // write(field) - NTuple lhsHeapPath = computePath(lhs); - NTuple fldHeapPath = new NTuple(lhsHeapPath.getList()); - // writeLocation(curr, fldHeapPath, fld, getLocation(fld)); + NTuple lhsLocTuple = new NTuple(); + if (fld.isStatic()) { + if (fld.isFinal()) { + // in this case, fld has TOP location + Location topLocation = Location.createTopLocation(md); + lhsLocTuple.add(topLocation); + } else { + lhsLocTuple.addAll(deriveGlobalLocationTuple(md)); + } + } else { + lhsLocTuple.addAll(deriveLocationTuple(md, lhs)); + } + + mapDescriptorToLocationPath.put(lhs, lhsLocTuple); + + NTuple fieldLocTuple = new NTuple(); + fieldLocTuple.addAll(lhsLocTuple); + + if (fn.kind() == FKind.FlatSetFieldNode) { + fieldLocTuple.add((Location) fld.getType().getExtension()); + } + + if (mapHeapPath.containsKey(lhs)) { + // fields reachable from the param can have heap path entry. + NTuple lhsHeapPath = new NTuple(); + lhsHeapPath.addAll(mapHeapPath.get(lhs)); + + Location fieldLocation; + if (fn.kind() == FKind.FlatSetFieldNode) { + fieldLocation = getLocation(fld); + } else { + fieldLocation = getLocation(lhsHeapPath.get(getArrayBaseDescriptorIdx(lhsHeapPath))); + } + + // Location fieldLocation = getLocation(lhs); + if (!isEventLoopBody && fieldLocation.getDescriptor().equals(md)) { + // if the field belongs to the local lattice, no reason to calculate + // shared location + break; + } + + if (ssjava.isSharedLocation(fieldLocation)) { + + NTuple fieldHeapPath = new NTuple(); + fieldHeapPath.addAll(computePath(lhs)); + if (fn.kind() == FKind.FlatSetFieldNode) { + fieldHeapPath.add(fld); + } + + addMayWrittenSet(md, fieldLocTuple, fieldHeapPath); + + } + } } break; - } - } + case FKind.FlatElementNode: + case FKind.FlatFieldNode: { - private boolean hasReadingEffectOnSharedLocation(NTuple hp, Location loc, Descriptor d) { + // x=y.f; - Hashtable> mapLocToDescSet = - mapHeapPathToLocSharedDescReadSet.get(hp); - if (mapLocToDescSet == null) { - return false; - } else { - Set setDesc = mapLocToDescSet.get(loc); - if (setDesc == null) { - return false; + if (fn.kind() == FKind.FlatFieldNode) { + FlatFieldNode ffn = (FlatFieldNode) fn; + lhs = ffn.getDst(); + rhs = ffn.getSrc(); + fld = ffn.getField(); } else { - return setDesc.contains(d); + FlatElementNode fen = (FlatElementNode) fn; + lhs = fen.getDst(); + rhs = fen.getSrc(); + TypeDescriptor td = rhs.getType().dereference(); + fld = getArrayField(td); } - } - } + NTuple locTuple = new NTuple(); - private void addReadDescriptor(NTuple hp, Location loc, Descriptor d) { + if (fld.isStatic()) { - if (loc != null && ssjava.isSharedLocation(loc)) { - Hashtable> mapLocToDescSet = - mapHeapPathToLocSharedDescReadSet.get(hp); - if (mapLocToDescSet == null) { - mapLocToDescSet = new Hashtable>(); - mapHeapPathToLocSharedDescReadSet.put(hp, mapLocToDescSet); + if (fld.isFinal()) { + // in this case, fld has TOP location + Location topLocation = Location.createTopLocation(md); + locTuple.add(topLocation); + } else { + locTuple.addAll(deriveGlobalLocationTuple(md)); + if (fn.kind() == FKind.FlatFieldNode) { + locTuple.add((Location) fld.getType().getExtension()); + } + } + + } else { + locTuple.addAll(deriveLocationTuple(md, rhs)); + if (fn.kind() == FKind.FlatFieldNode) { + locTuple.add((Location) fld.getType().getExtension()); + } } - Set descSet = mapLocToDescSet.get(loc); - if (descSet == null) { - descSet = new HashSet(); - mapLocToDescSet.put(loc, descSet); + + mapDescriptorToLocationPath.put(lhs, locTuple); + + } + break; + + case FKind.FlatCall: { + + FlatCall fc = (FlatCall) fn; + + bindLocationPathCallerArgWithCalleeParam(md, fc); + + } + break; + + case FKind.FlatNew: { + + FlatNew fnew = (FlatNew) fn; + TempDescriptor dst = fnew.getDst(); + NTuple locTuple = deriveLocationTuple(md, dst); + + if (locTuple != null) { + NTuple dstLocTuple = new NTuple(); + dstLocTuple.addAll(locTuple); + mapDescriptorToLocationPath.put(dst, dstLocTuple); } - descSet.add(d); + } + break; + } + } + + private void addMayWrittenSet(MethodDescriptor md, NTuple locTuple, + NTuple heapPath) { + + MultiSourceMap, NTuple> map = mapMethodToSharedLocCoverSet.get(md); + if (map == null) { + map = new MultiSourceMap, NTuple>(); + mapMethodToSharedLocCoverSet.put(md, map); + } + + Set> writeSet = map.get(locTuple); + if (writeSet == null) { + writeSet = new HashSet>(); + map.put(locTuple, writeSet); + } + writeSet.add(heapPath); } - private Location getLocation(Descriptor d) { + private void bindLocationPathCallerArgWithCalleeParam(MethodDescriptor mdCaller, FlatCall fc) { - if (d instanceof FieldDescriptor) { - TypeExtension te = ((FieldDescriptor) d).getType().getExtension(); - if (te != null) { - return (Location) te; - } - } else { - assert d instanceof TempDescriptor; - TempDescriptor td = (TempDescriptor) d; + if (ssjava.isSSJavaUtil(fc.getMethod().getClassDesc())) { + // ssjava util case! + // have write effects on the first argument + TempDescriptor arg = fc.getArg(0); + NTuple argLocationPath = deriveLocationTuple(mdCaller, arg); + NTuple argHeapPath = computePath(arg); + addMayWrittenSet(mdCaller, argLocationPath, argHeapPath); + } else if (ssjava.needTobeAnnotated(fc.getMethod())) { - TypeExtension te = td.getType().getExtension(); - if (te != null) { - if (te instanceof CompositeLocation) { - CompositeLocation comp = (CompositeLocation) te; + // if arg is not primitive type, we need to propagate maywritten set to + // the caller's location path + + MethodDescriptor mdCallee = fc.getMethod(); + Set setPossibleCallees = new HashSet(); + setPossibleCallees.addAll(callGraph.getMethods(mdCallee)); + + // create mapping from arg idx to its heap paths + Hashtable> mapArgIdx2CallerArgHeapPath = + new Hashtable>(); + + // create mapping from arg idx to its location paths + Hashtable> mapArgIdx2CallerArgLocationPath = + new Hashtable>(); + + if (fc.getThis() != null) { + + if (mapHeapPath.containsKey(fc.getThis())) { + + // setup heap path for 'this' + NTuple thisHeapPath = new NTuple(); + thisHeapPath.addAll(mapHeapPath.get(fc.getThis())); + mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(0), thisHeapPath); + + // setup location path for 'this' + NTuple thisLocationPath = deriveLocationTuple(mdCaller, fc.getThis()); + mapArgIdx2CallerArgLocationPath.put(Integer.valueOf(0), thisLocationPath); - return comp.get(comp.getSize() - 1); - } else { - return (Location) te; } } - } - return mapDescToLocation.get(d); - } + for (int i = 0; i < fc.numArgs(); i++) { + TempDescriptor arg = fc.getArg(i); + // create mapping arg to loc path + + if (mapHeapPath.containsKey(arg)) { + // setup heap path + NTuple argHeapPath = mapHeapPath.get(arg); + mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(i + 1), argHeapPath); + // setup loc path + NTuple argLocationPath = deriveLocationTuple(mdCaller, arg); + mapArgIdx2CallerArgLocationPath.put(Integer.valueOf(i + 1), argLocationPath); + } - private void writeLocation(ClearingSummary curr, NTuple hp, Location loc, Descriptor d) { + } - // System.out.println("# WRITE LOC hp=" + hp + " d=" + d + " loc=" + loc); - SharedStatus state = getState(curr, hp); - if (loc != null && hasReadingEffectOnSharedLocation(hp, loc, d)) { - // 1. add field x to the clearing set + for (Iterator iterator = setPossibleCallees.iterator(); iterator.hasNext();) { + MethodDescriptor callee = (MethodDescriptor) iterator.next(); + FlatMethod calleeFlatMethod = state.getMethodFlat(callee); - state.addVar(loc, d); + // binding caller's args and callee's params + + Hashtable, NTuple> mapParamHeapPathToCallerArgHeapPath = + new Hashtable, NTuple>(); + + Hashtable mapParamIdx2ParamTempDesc = + new Hashtable(); + int offset = 0; + if (calleeFlatMethod.getMethod().isStatic()) { + // static method does not have implicit 'this' arg + offset = 1; + } + + for (int i = 0; i < calleeFlatMethod.numParameters(); i++) { + TempDescriptor param = calleeFlatMethod.getParameter(i); + mapParamIdx2ParamTempDesc.put(Integer.valueOf(i + offset), param); + + NTuple calleeHeapPath = computePath(param); + + NTuple argHeapPath = + mapArgIdx2CallerArgHeapPath.get(Integer.valueOf(i + offset)); + + if (argHeapPath != null) { + mapParamHeapPathToCallerArgHeapPath.put(calleeHeapPath, argHeapPath); + + } + + } + + Set keySet = mapArgIdx2CallerArgLocationPath.keySet(); + for (Iterator iterator2 = keySet.iterator(); iterator2.hasNext();) { + Integer idx = (Integer) iterator2.next(); + + NTuple callerArgLocationPath = mapArgIdx2CallerArgLocationPath.get(idx); + + TempDescriptor calleeParam = mapParamIdx2ParamTempDesc.get(idx); + NTuple calleeLocationPath = deriveLocationTuple(mdCallee, calleeParam); + + NTuple callerArgHeapPath = mapArgIdx2CallerArgHeapPath.get(idx); + NTuple calleeHeapPath = computePath(calleeParam); + + if (!calleeParam.getType().isPrimitive()) { + createNewMappingOfMayWrittenSet(mdCaller, callee, callerArgHeapPath, + callerArgLocationPath, calleeHeapPath, calleeLocationPath, + mapParamHeapPathToCallerArgHeapPath); + } + } - // 3. if the set v contains all of variables belonging to the shared - // location, set flag to true - if (overwrittenAllSharedConcreteLocation(hp, loc, state.getVarSet(loc))) { - state.updateFlag(loc, true); } + } - state.setWriteEffect(loc); - // System.out.println("# WRITE CURR=" + curr); } - private boolean overwrittenAllSharedConcreteLocation(NTuple hp, Location loc, - Set writtenSet) { + private Hashtable, Set>> getMappingByStartedWith( + MultiSourceMap, NTuple> map, NTuple in) { - Hashtable> mapLocToDescSet = - mapHeapPathToLocSharedDescReadSet.get(hp); + Hashtable, Set>> matchedMapping = + new Hashtable, Set>>(); - if (mapLocToDescSet != null) { - Set descSet = mapLocToDescSet.get(loc); - if (writtenSet.containsAll(descSet)) { - return true; - } else { - return false; + Set> keySet = map.keySet(); + + for (Iterator iterator = keySet.iterator(); iterator.hasNext();) { + NTuple key = (NTuple) iterator.next(); + if (key.startsWith(in)) { + matchedMapping.put(key, map.get(key)); } - } else { - return false; } + + return matchedMapping; + } - private void readLocation(ClearingSummary curr, NTuple hp, Location loc, Descriptor d) { - // remove reading var x from written set - // System.out.println("# READ LOC hp=" + hp + " d=" + d + " loc=" + loc); - if (loc != null && hasReadingEffectOnSharedLocation(hp, loc, d)) { - SharedStatus state = getState(curr, hp); - state.removeVar(loc, d); + private void createNewMappingOfMayWrittenSet(MethodDescriptor caller, MethodDescriptor callee, + NTuple callerArgHeapPath, NTuple callerArgLocPath, + NTuple calleeParamHeapPath, NTuple calleeParamLocPath, + Hashtable, NTuple> mapParamHeapPathToCallerArgHeapPath) { + + // propagate may-written-set associated with the key that is started with + // calleepath to the caller + // 1) makes a new key by combining caller path and callee path(except local + // loc element of param) + // 2) create new mapping of may-written-set of callee path to caller path + + // extract all may written effect accessed through callee param path + MultiSourceMap, NTuple> calleeMapping = + mapMethodToSharedLocCoverSet.get(callee); + + if (calleeMapping == null) { + return; } - // System.out.println("# READ CURR=" + curr); - } - private SharedStatus getState(ClearingSummary curr, NTuple hp) { - SharedStatus state = curr.get(hp); - if (state == null) { - state = new SharedStatus(); - curr.put(hp, state); + MultiSourceMap, NTuple> callerMapping = + mapMethodToSharedLocCoverSet.get(caller); + + if (callerMapping == null) { + callerMapping = new MultiSourceMap, NTuple>(); + mapMethodToSharedLocCoverSet.put(caller, callerMapping); } - return state; - } - private void writtenAnalyis() { - // perform second stage analysis: intraprocedural analysis ensure that - // all - // variables are definitely written in-between the same read + Hashtable, Set>> paramMapping = + getMappingByStartedWith(calleeMapping, calleeParamLocPath); - // First, identify ssjava loop entrace - FlatMethod fm = state.getMethodFlat(methodContainingSSJavaLoop); - Set flatNodesToVisit = new HashSet(); - flatNodesToVisit.add(fm); + Set> calleeKeySet = paramMapping.keySet(); - LoopFinder loopFinder = new LoopFinder(fm); + for (Iterator iterator = calleeKeySet.iterator(); iterator.hasNext();) { + NTuple calleeKey = (NTuple) iterator.next(); - while (!flatNodesToVisit.isEmpty()) { - FlatNode fn = flatNodesToVisit.iterator().next(); - flatNodesToVisit.remove(fn); + Set> calleeMayWriteSet = paramMapping.get(calleeKey); - String label = (String) state.fn2labelMap.get(fn); - if (label != null) { + if (calleeMayWriteSet != null) { - if (label.equals(ssjava.SSJAVA)) { - ssjavaLoopEntrance = fn; - break; + Set> boundMayWriteSet = new HashSet>(); + + Set> boundSet = + convertToCallerMayWriteSet(calleeParamHeapPath, calleeMayWriteSet, callerMapping, + mapParamHeapPathToCallerArgHeapPath); + + boundMayWriteSet.addAll(boundSet); + + NTuple newKey = new NTuple(); + newKey.addAll(callerArgLocPath); + // need to replace the local location with the caller's path so skip the + // local location of the parameter + for (int i = 1; i < calleeKey.size(); i++) { + newKey.add(calleeKey.get(i)); } - } - for (int i = 0; i < fn.numNext(); i++) { - FlatNode nn = fn.getNext(i); - flatNodesToVisit.add(nn); + callerMapping.union(newKey, boundMayWriteSet); } + } - assert ssjavaLoopEntrance != null; + } - // assume that ssjava loop is top-level loop in method, not nested loop - Set nestedLoop = loopFinder.nestedLoops(); - for (Iterator loopIter = nestedLoop.iterator(); loopIter.hasNext();) { - LoopFinder lf = (LoopFinder) loopIter.next(); - if (lf.loopEntrances().iterator().next().equals(ssjavaLoopEntrance)) { - ssjavaLoop = lf; + private Set> convertToCallerMayWriteSet( + NTuple calleeParamHeapPath, Set> calleeMayWriteSet, + MultiSourceMap, NTuple> callerMapping, + Hashtable, NTuple> mapParamHeapPathToCallerArgHeapPath) { + + Set> boundSet = new HashSet>(); + + // replace callee's param path with caller's arg path + for (Iterator iterator = calleeMayWriteSet.iterator(); iterator.hasNext();) { + NTuple calleeWriteHeapPath = (NTuple) iterator.next(); + + NTuple writeHeapPathParamHeapPath = calleeWriteHeapPath.subList(0, 1); + + NTuple callerArgHeapPath = + mapParamHeapPathToCallerArgHeapPath.get(writeHeapPathParamHeapPath); + + NTuple boundHeapPath = new NTuple(); + boundHeapPath.addAll(callerArgHeapPath); + + for (int i = 1; i < calleeWriteHeapPath.size(); i++) { + boundHeapPath.add(calleeWriteHeapPath.get(i)); } + + boundSet.add(boundHeapPath); + } - assert ssjavaLoop != null; + return boundSet; + } + + private Location getLocation(Descriptor d) { - writtenAnalysis_analyzeLoop(); + if (d instanceof FieldDescriptor) { + TypeExtension te = ((FieldDescriptor) d).getType().getExtension(); + if (te != null) { + return (Location) te; + } + } else { + assert d instanceof TempDescriptor; + TempDescriptor td = (TempDescriptor) d; - if (debugcount > 0) { - throw new Error(); + TypeExtension te = td.getType().getExtension(); + if (te != null) { + if (te instanceof SSJavaType) { + SSJavaType ssType = (SSJavaType) te; + if (ssType.getCompLoc() != null) { + CompositeLocation comp = ssType.getCompLoc(); + return comp.get(comp.getSize() - 1); + } else { + return null; + } + } else { + return (Location) te; + } + } } + return mapDescToLocation.get(d); } - private void writtenAnalysis_analyzeLoop() { + private void eventLoopAnalysis() { + // perform second stage analysis: intraprocedural analysis ensure that + // all + // variables are definitely written in-between the same read Set flatNodesToVisit = new HashSet(); - flatNodesToVisit.add(ssjavaLoopEntrance); - - loopIncElements = (Set) ssjavaLoop.loopIncElements(); + flatNodesToVisit.add(ssjava.getSSJavaLoopEntrance()); while (!flatNodesToVisit.isEmpty()) { FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next(); flatNodesToVisit.remove(fn); - Hashtable, Hashtable> prev = - definitelyWrittenResults.get(fn); + Hashtable, Set> prev = mapFlatNodetoEventLoopMap.get(fn); - Hashtable, Hashtable> curr = - new Hashtable, Hashtable>(); + Hashtable, Set> curr = + new Hashtable, Set>(); for (int i = 0; i < fn.numPrev(); i++) { FlatNode nn = fn.getPrev(i); - Hashtable, Hashtable> dwIn = - definitelyWrittenResults.get(nn); - if (dwIn != null) { - merge(curr, dwIn); + Hashtable, Set> in = mapFlatNodetoEventLoopMap.get(nn); + if (in != null) { + union(curr, in); } } - writtenAnalysis_nodeAction(fn, curr, ssjavaLoopEntrance); + eventLoopAnalysis_nodeAction(fn, curr, ssjava.getSSJavaLoopEntrance()); // if a new result, schedule forward nodes for analysis if (!curr.equals(prev)) { - definitelyWrittenResults.put(fn, curr); + mapFlatNodetoEventLoopMap.put(fn, curr); for (int i = 0; i < fn.numNext(); i++) { FlatNode nn = fn.getNext(i); @@ -1174,56 +1255,127 @@ public class DefinitelyWrittenCheck { } } - private void writtenAnalysis_nodeAction(FlatNode fn, - Hashtable, Hashtable> curr, FlatNode loopEntrance) { + private void union(Hashtable, Set> curr, + Hashtable, Set> in) { + + Set> inKeySet = in.keySet(); + for (Iterator iterator = inKeySet.iterator(); iterator.hasNext();) { + NTuple inKey = (NTuple) iterator.next(); + Set inSet = in.get(inKey); + + Set currSet = curr.get(inKey); + + if (currSet == null) { + currSet = new HashSet(); + curr.put(inKey, currSet); + } + currSet.addAll(inSet); + } + + } + + private void eventLoopAnalysis_nodeAction(FlatNode fn, + Hashtable, Set> curr, FlatNode loopEntrance) { + + Hashtable, Set> readWriteKillSet = + new Hashtable, Set>(); + Hashtable, Set> readWriteGenSet = + new Hashtable, Set>(); if (fn.equals(loopEntrance)) { // it reaches loop entrance: changes all flag to true Set> keySet = curr.keySet(); for (Iterator iterator = keySet.iterator(); iterator.hasNext();) { NTuple key = (NTuple) iterator.next(); - Hashtable pair = curr.get(key); - if (pair != null) { - Set pairKeySet = pair.keySet(); - for (Iterator iterator2 = pairKeySet.iterator(); iterator2.hasNext();) { - FlatNode pairKey = (FlatNode) iterator2.next(); - pair.put(pairKey, Boolean.TRUE); - } + Set writeAgeSet = curr.get(key); + + Set incSet = new HashSet(); + incSet.addAll(writeAgeSet); + writeAgeSet.clear(); + + for (Iterator iterator2 = incSet.iterator(); iterator2.hasNext();) { + WriteAge writeAge = (WriteAge) iterator2.next(); + WriteAge newWriteAge = writeAge.copy(); + newWriteAge.inc(); + writeAgeSet.add(newWriteAge); } + } + } else { TempDescriptor lhs; TempDescriptor rhs; FieldDescriptor fld; switch (fn.kind()) { + case FKind.FlatOpNode: { FlatOpNode fon = (FlatOpNode) fn; lhs = fon.getDest(); rhs = fon.getLeft(); - NTuple rhsHeapPath = computePath(rhs); - if (!rhs.getType().isImmutable()) { - mapHeapPath.put(lhs, rhsHeapPath); - } else { - if (fon.getOp().getOp() == Operation.ASSIGN) { - // read(rhs) - readValue(fn, rhsHeapPath, curr); - } - // write(lhs) - NTuple lhsHeapPath = computePath(lhs); - removeHeapPath(curr, lhsHeapPath); - } - } - break; + if (fon.getOp().getOp() == Operation.ASSIGN) { + + if (!lhs.getSymbol().startsWith("neverused") && !lhs.getSymbol().startsWith("leftop") + && !lhs.getSymbol().startsWith("rightop")) { + + boolean hasWriteEffect = false; + + if (rhs.getType().getExtension() instanceof SSJavaType + && lhs.getType().getExtension() instanceof SSJavaType) { + + CompositeLocation rhsCompLoc = + ((SSJavaType) rhs.getType().getExtension()).getCompLoc(); + + CompositeLocation lhsCompLoc = + ((SSJavaType) lhs.getType().getExtension()).getCompLoc(); + + if (lhsCompLoc != rhsCompLoc) { + // have a write effect! + hasWriteEffect = true; + } + + } else if (lhs.getType().isImmutable()) { + hasWriteEffect = true; + } + + if (hasWriteEffect && mapHeapPath.containsKey(lhs)) { + // write(lhs) + NTuple lhsHeapPath = new NTuple(); + lhsHeapPath.addAll(mapHeapPath.get(lhs)); + + Location lhsLoc = getLocation(lhs); + if (ssjava.isSharedLocation(lhsLoc)) { + + NTuple varHeapPath = computePath(lhs); + NTuple varLocTuple = mapDescriptorToLocationPath.get(lhs); + + Set> writtenSet = + mapFlatNodeToSharedLocMapping.get(fn).get(varLocTuple); + + Set> mustClearSet = + mapFlatNodeToMustClearMap.get(fn).get(varLocTuple); - case FKind.FlatLiteralNode: { - FlatLiteralNode fln = (FlatLiteralNode) fn; - lhs = fln.getDst(); + if (isCovered(varLocTuple, writtenSet, mustClearSet)) { + computeKILLSetForSharedWrite(curr, writtenSet, readWriteKillSet); + computeGENSetForSharedAllCoverWrite(curr, writtenSet, readWriteGenSet); + } else { + computeGENSetForSharedNonCoverWrite(curr, varHeapPath, readWriteGenSet); + } - // write(lhs) - NTuple lhsHeapPath = computePath(lhs); - removeHeapPath(curr, lhsHeapPath); + } else { + + computeKILLSetForWrite(curr, lhsHeapPath, readWriteKillSet); + computeGENSetForWrite(lhsHeapPath, readWriteGenSet); + } + + Set writeAgeSet = curr.get(lhsHeapPath); + checkWriteAgeSet(writeAgeSet, lhsHeapPath, fn); + } + + } + + } } break; @@ -1244,22 +1396,21 @@ public class DefinitelyWrittenCheck { fld = getArrayField(td); } - if (fld.isFinal() /* && fld.isStatic() */) { - // if field is final and static, no need to check - break; - } - // read field NTuple srcHeapPath = mapHeapPath.get(rhs); - NTuple fldHeapPath = new NTuple(srcHeapPath.getList()); + NTuple fldHeapPath; + if (srcHeapPath != null) { + fldHeapPath = new NTuple(srcHeapPath.getList()); + } else { + // if srcHeapPath is null, it is static reference + fldHeapPath = new NTuple(); + fldHeapPath.add(rhs); + } fldHeapPath.add(fld); - if (fld.getType().isImmutable()) { - readValue(fn, fldHeapPath, curr); - } + Set writeAgeSet = curr.get(fldHeapPath); - // propagate rhs's heap path to the lhs - mapHeapPath.put(lhs, fldHeapPath); + checkWriteAgeSet(writeAgeSet, fldHeapPath, fn); } break; @@ -1279,71 +1430,343 @@ public class DefinitelyWrittenCheck { fld = getArrayField(td); } - // write(field) - NTuple lhsHeapPath = computePath(lhs); - NTuple fldHeapPath = new NTuple(lhsHeapPath.getList()); - fldHeapPath.add(fld); - removeHeapPath(curr, fldHeapPath); + // set up heap path + NTuple lhsHeapPath = mapHeapPath.get(lhs); + if (lhsHeapPath != null) { + // write(field) + NTuple fldHeapPath = new NTuple(lhsHeapPath.getList()); + if (fn.kind() == FKind.FlatSetFieldNode) { + fldHeapPath.add(fld); + } + + // shared loc extension + Location fieldLoc; + if (fn.kind() == FKind.FlatSetFieldNode) { + fieldLoc = (Location) fld.getType().getExtension(); + } else { + NTuple locTuple = mapDescriptorToLocationPath.get(lhs); + fieldLoc = locTuple.get(locTuple.size() - 1); + } + + if (ssjava.isSharedLocation(fieldLoc)) { + + NTuple fieldLocTuple = new NTuple(); + fieldLocTuple.addAll(mapDescriptorToLocationPath.get(lhs)); + if (fn.kind() == FKind.FlatSetFieldNode) { + fieldLocTuple.add(fieldLoc); + } + + Set> writtenSet = + mapFlatNodeToSharedLocMapping.get(fn).get(fieldLocTuple); + if (isCovered(fieldLocTuple, writtenSet)) { + computeKILLSetForSharedWrite(curr, writtenSet, readWriteKillSet); + computeGENSetForSharedAllCoverWrite(curr, writtenSet, readWriteGenSet); + } else { + computeGENSetForSharedNonCoverWrite(curr, fldHeapPath, readWriteGenSet); + } + + } else { + computeKILLSetForWrite(curr, fldHeapPath, readWriteKillSet); + computeGENSetForWrite(fldHeapPath, readWriteGenSet); + } + + } } break; case FKind.FlatCall: { FlatCall fc = (FlatCall) fn; + SharedLocMap sharedLocMap = mapFlatNodeToSharedLocMapping.get(fc); + SharedLocMap mustClearMap = mapFlatNodeToMustClearMap.get(fc); + generateKILLSetForFlatCall(fc, curr, sharedLocMap, mustClearMap, readWriteKillSet); + generateGENSetForFlatCall(fc, sharedLocMap, mustClearMap, readWriteGenSet); - bindHeapPathCallerArgWithCaleeParam(fc); - // add in which hp is an element of - // READ_bound set - // of callee: callee has 'read' requirement! - - for (Iterator iterator = calleeUnionBoundReadSet.iterator(); iterator.hasNext();) { - NTuple read = (NTuple) iterator.next(); - Hashtable gen = curr.get(read); - if (gen == null) { - gen = new Hashtable(); - curr.put(read, gen); - } - Boolean currentStatus = gen.get(fn); - if (currentStatus == null) { - gen.put(fn, Boolean.FALSE); - } else { - checkFlag(currentStatus.booleanValue(), fn, read); + } + break; + + } + + computeNewMapping(curr, readWriteKillSet, readWriteGenSet); + if (fn instanceof FlatCall) { + checkManyRead((FlatCall) fn, curr); + } + + } + + } + + private void computeGENSetForSharedNonCoverWrite( + Hashtable, Set> curr, NTuple heapPath, + Hashtable, Set> genSet) { + + Set writeAgeSet = genSet.get(heapPath); + if (writeAgeSet == null) { + writeAgeSet = new HashSet(); + genSet.put(heapPath, writeAgeSet); + } + + writeAgeSet.add(new WriteAge(1)); + + } + + private void computeGENSetForSharedAllCoverWrite( + Hashtable, Set> curr, Set> writtenSet, + Hashtable, Set> genSet) { + + for (Iterator iterator = writtenSet.iterator(); iterator.hasNext();) { + NTuple writeHeapPath = (NTuple) iterator.next(); + + Set writeAgeSet = new HashSet(); + writeAgeSet.add(new WriteAge(0)); + + genSet.put(writeHeapPath, writeAgeSet); + } + + } + + private void computeKILLSetForSharedWrite(Hashtable, Set> curr, + Set> writtenSet, Hashtable, Set> killSet) { + + for (Iterator iterator = writtenSet.iterator(); iterator.hasNext();) { + NTuple writeHeapPath = (NTuple) iterator.next(); + Set writeSet = curr.get(writeHeapPath); + if (writeSet != null) { + killSet.put(writeHeapPath, writeSet); + } + } + + } + + private boolean isCovered(NTuple locTuple, Set> curWrittenSet) { + + Set> coverSet = + mapMethodToSharedLocCoverSet.get(methodContainingSSJavaLoop).get(locTuple); + + if (curWrittenSet == null) { + return false; + } + + return curWrittenSet.containsAll(coverSet); + } + + private boolean isCovered(NTuple locTuple, Set> curWrittenSet, + Set> mustClearSet) { + + Set> coverSet = + mapMethodToSharedLocCoverSet.get(methodContainingSSJavaLoop).get(locTuple); + + if (mustClearSet != null && mustClearSet.containsAll(coverSet)) { + return true; + } + + if (curWrittenSet == null) { + return false; + } + + return curWrittenSet.containsAll(coverSet); + } + + private void checkManyRead(FlatCall fc, Hashtable, Set> curr) { + Set> boundReadSet = mapFlatNodeToBoundReadSet.get(fc); + for (Iterator iterator = boundReadSet.iterator(); iterator.hasNext();) { + NTuple readHeapPath = (NTuple) iterator.next(); + Set writeAgeSet = curr.get(readHeapPath); + checkWriteAgeSet(writeAgeSet, readHeapPath, fc); + } + + } + + private void checkWriteAgeSet(Set writeAgeSet, NTuple path, FlatNode fn) { + + if (writeAgeSet != null) { + for (Iterator iterator = writeAgeSet.iterator(); iterator.hasNext();) { + WriteAge writeAge = (WriteAge) iterator.next(); + if (writeAge.getAge() > MAXAGE) { + generateErrorMessage(path, fn); + } + } + } + } + + private void generateErrorMessage(NTuple path, FlatNode fn) { + + Descriptor lastDesc = path.get(getArrayBaseDescriptorIdx(path)); + if (ssjava.isSharedLocation(getLocation(lastDesc))) { + + NTuple locPathTuple = getLocationTuple(path); + Set> coverSet = + mapMethodToSharedLocCoverSet.get(methodContainingSSJavaLoop).get(locPathTuple); + throw new Error("Shared memory locations, which is reachable through references " + path + + ", are not completely overwritten by the higher values at " + + methodContainingSSJavaLoop.getClassDesc().getSourceFileName() + "::" + fn.getNumLine() + + ".\nThe following memory locations belong to the same shared locations:" + coverSet); + + } else { + throw new Error( + "Memory location, which is reachable through references " + + path + + ", who comes back to the same read statement without being overwritten at the out-most iteration at " + + methodContainingSSJavaLoop.getClassDesc().getSourceFileName() + "::" + + fn.getNumLine()); + } + + } + + private void generateGENSetForFlatCall(FlatCall fc, SharedLocMap sharedLocMap, + SharedLocMap mustClearMap, Hashtable, Set> GENSet) { + + Set> boundMayWriteSet = mapFlatNodeToBoundMayWriteSet.get(fc); + + for (Iterator iterator = boundMayWriteSet.iterator(); iterator.hasNext();) { + NTuple heapPath = (NTuple) iterator.next(); + + if (!isSharedLocation(heapPath)) { + addWriteAgeToSet(heapPath, GENSet, new WriteAge(0)); + } else { + // if the current heap path is shared location + + NTuple locTuple = getLocationTuple(heapPath); + + Set> sharedWriteHeapPathSet = sharedLocMap.get(locTuple); + + if (isCovered(locTuple, sharedLocMap.get(locTuple), mustClearMap.get(locTuple))) { + // if it is covered, add all of heap paths belong to the same shared + // loc with write age 0 + for (Iterator iterator2 = sharedWriteHeapPathSet.iterator(); iterator2.hasNext();) { + NTuple sharedHeapPath = (NTuple) iterator2.next(); + addWriteAgeToSet(sharedHeapPath, GENSet, new WriteAge(0)); } + + } else { + // if not covered, add write age 1 to the heap path that is + // may-written but not covered + addWriteAgeToSet(heapPath, GENSet, new WriteAge(1)); + } + + } + + } + + } + + private void addWriteAgeToSet(NTuple heapPath, + Hashtable, Set> map, WriteAge age) { + + Set currSet = map.get(heapPath); + if (currSet == null) { + currSet = new HashSet(); + map.put(heapPath, currSet); + } + + currSet.add(age); + } + + private void generateKILLSetForFlatCall(FlatCall fc, + Hashtable, Set> curr, SharedLocMap sharedLocMap, + SharedLocMap mustClearMap, Hashtable, Set> KILLSet) { + + Set> boundMustWriteSet = mapFlatNodeToBoundMustWriteSet.get(fc); + + for (Iterator iterator = boundMustWriteSet.iterator(); iterator.hasNext();) { + NTuple heapPath = (NTuple) iterator.next(); + + if (isSharedLocation(heapPath)) { + NTuple locTuple = getLocationTuple(heapPath); + + if (isCovered(locTuple, sharedLocMap.get(locTuple), mustClearMap.get(locTuple)) + && curr.containsKey(heapPath)) { + // if it is shared loc and corresponding shared loc has been covered + KILLSet.put(heapPath, curr.get(heapPath)); } + } else { - // removes if hp is an element of - // OVERWRITE_bound - // set of callee. it means that callee will overwrite it - for (Iterator iterator = calleeIntersectBoundOverWriteSet.iterator(); iterator.hasNext();) { - NTuple write = (NTuple) iterator.next(); - removeHeapPath(curr, write); + for (Enumeration> e = curr.keys(); e.hasMoreElements();) { + NTuple key = e.nextElement(); + if (key.startsWith(heapPath)) { + KILLSet.put(key, curr.get(key)); + } } + } - break; + } + + } + + private int getArrayBaseDescriptorIdx(NTuple heapPath) { + + for (int i = heapPath.size() - 1; i >= 0; i--) { + if (!heapPath.get(i).getSymbol().equals(arrayElementFieldName)) { + return i; } } + return -1; + + } + + private boolean isSharedLocation(NTuple heapPath) { + + Descriptor d = heapPath.get(getArrayBaseDescriptorIdx(heapPath)); + + return ssjava.isSharedLocation(getLocation(heapPath.get(getArrayBaseDescriptorIdx(heapPath)))); + } - private void readValue(FlatNode fn, NTuple hp, - Hashtable, Hashtable> curr) { - Hashtable gen = curr.get(hp); - if (gen == null) { - gen = new Hashtable(); - curr.put(hp, gen); + private NTuple getLocationTuple(NTuple heapPath) { + + NTuple locTuple = new NTuple(); + + locTuple.addAll(mapDescriptorToLocationPath.get(heapPath.get(0))); + + for (int i = 1; i <= getArrayBaseDescriptorIdx(heapPath); i++) { + locTuple.add(getLocation(heapPath.get(i))); } - Boolean currentStatus = gen.get(fn); - if (currentStatus == null) { - gen.put(fn, Boolean.FALSE); - } else { - checkFlag(currentStatus.booleanValue(), fn, hp); + + return locTuple; + } + + private void computeNewMapping(Hashtable, Set> curr, + Hashtable, Set> KILLSet, + Hashtable, Set> GENSet) { + + for (Enumeration> e = KILLSet.keys(); e.hasMoreElements();) { + NTuple key = e.nextElement(); + + Set writeAgeSet = curr.get(key); + if (writeAgeSet == null) { + writeAgeSet = new HashSet(); + curr.put(key, writeAgeSet); + } + writeAgeSet.removeAll(KILLSet.get(key)); + } + + for (Enumeration> e = GENSet.keys(); e.hasMoreElements();) { + NTuple key = e.nextElement(); + + Set currWriteAgeSet = curr.get(key); + if (currWriteAgeSet == null) { + currWriteAgeSet = new HashSet(); + curr.put(key, currWriteAgeSet); + } + currWriteAgeSet.addAll(GENSet.get(key)); } } - private void removeHeapPath(Hashtable, Hashtable> curr, - NTuple hp) { + private void computeGENSetForWrite(NTuple fldHeapPath, + Hashtable, Set> GENSet) { + + // generate write age 0 for the field being written to + Set writeAgeSet = new HashSet(); + writeAgeSet.add(new WriteAge(0)); + GENSet.put(fldHeapPath, writeAgeSet); + + } + + private void computeKILLSetForWrite(Hashtable, Set> curr, + NTuple hp, Hashtable, Set> KILLSet) { // removes all of heap path that starts with prefix 'hp' // since any reference overwrite along heap path gives overwriting side @@ -1353,32 +1776,30 @@ public class DefinitelyWrittenCheck { for (Iterator> iter = keySet.iterator(); iter.hasNext();) { NTuple key = iter.next(); if (key.startsWith(hp)) { - curr.put(key, new Hashtable()); + KILLSet.put(key, curr.get(key)); } } } - private void bindHeapPathCallerArgWithCaleeParam(FlatCall fc) { + private void bindHeapPathCallerArgWithCalleeParam(FlatCall fc) { // compute all possible callee set - // transform all READ/OVERWRITE set from the any possible - // callees to the - // caller + // transform all READ/WRITE set from the any possible + // callees to the caller calleeUnionBoundReadSet.clear(); - calleeIntersectBoundOverWriteSet.clear(); - calleeBoundWriteSet.clear(); + calleeIntersectBoundMustWriteSet.clear(); + calleeUnionBoundMayWriteSet.clear(); if (ssjava.isSSJavaUtil(fc.getMethod().getClassDesc())) { // ssjava util case! // have write effects on the first argument TempDescriptor arg = fc.getArg(0); NTuple argHeapPath = computePath(arg); - calleeIntersectBoundOverWriteSet.add(argHeapPath); + calleeIntersectBoundMustWriteSet.add(argHeapPath); + calleeUnionBoundMayWriteSet.add(argHeapPath); } else { MethodDescriptor mdCallee = fc.getMethod(); - // FlatMethod fmCallee = state.getMethodFlat(mdCallee); Set setPossibleCallees = new HashSet(); - // setPossibleCallees.addAll(callGraph.getMethods(mdCallee, typeDesc)); setPossibleCallees.addAll(callGraph.getMethods(mdCallee)); // create mapping from arg idx to its heap paths @@ -1388,13 +1809,10 @@ public class DefinitelyWrittenCheck { // arg idx is starting from 'this' arg if (fc.getThis() != null) { NTuple thisHeapPath = mapHeapPath.get(fc.getThis()); - if (thisHeapPath == null) { - // method is called without creating new flat node representing 'this' - thisHeapPath = new NTuple(); - thisHeapPath.add(fc.getThis()); + if (thisHeapPath != null) { + // if 'this' does not have heap path, it is local reference + mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(0), thisHeapPath); } - - mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(0), thisHeapPath); } for (int i = 0; i < fc.numArgs(); i++) { @@ -1409,24 +1827,26 @@ public class DefinitelyWrittenCheck { // binding caller's args and callee's params - Set> calleeReadSet = mapFlatMethodToRead.get(calleeFlatMethod); + Set> calleeReadSet = mapFlatMethodToReadSet.get(calleeFlatMethod); if (calleeReadSet == null) { calleeReadSet = new HashSet>(); - mapFlatMethodToRead.put(calleeFlatMethod, calleeReadSet); + mapFlatMethodToReadSet.put(calleeFlatMethod, calleeReadSet); } - Set> calleeOverWriteSet = mapFlatMethodToOverWrite.get(calleeFlatMethod); + Set> calleeMustWriteSet = + mapFlatMethodToMustWriteSet.get(calleeFlatMethod); - if (calleeOverWriteSet == null) { - calleeOverWriteSet = new HashSet>(); - mapFlatMethodToOverWrite.put(calleeFlatMethod, calleeOverWriteSet); + if (calleeMustWriteSet == null) { + calleeMustWriteSet = new HashSet>(); + mapFlatMethodToMustWriteSet.put(calleeFlatMethod, calleeMustWriteSet); } - Set> calleeWriteSet = mapFlatMethodToWrite.get(calleeFlatMethod); + Set> calleeMayWriteSet = + mapFlatMethodToMayWriteSet.get(calleeFlatMethod); - if (calleeWriteSet == null) { - calleeWriteSet = new HashSet>(); - mapFlatMethodToWrite.put(calleeFlatMethod, calleeWriteSet); + if (calleeMayWriteSet == null) { + calleeMayWriteSet = new HashSet>(); + mapFlatMethodToMayWriteSet.put(calleeFlatMethod, calleeMayWriteSet); } Hashtable mapParamIdx2ParamTempDesc = @@ -1446,95 +1866,298 @@ public class DefinitelyWrittenCheck { // union of the current read set and the current callee's // read set calleeUnionBoundReadSet.addAll(calleeBoundReadSet); - Set> calleeBoundOverWriteSet = - bindSet(calleeOverWriteSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath); + + Set> calleeBoundMustWriteSet = + bindSet(calleeMustWriteSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath); // intersection of the current overwrite set and the current // callee's // overwrite set - merge(calleeIntersectBoundOverWriteSet, calleeBoundOverWriteSet); + merge(calleeIntersectBoundMustWriteSet, calleeBoundMustWriteSet); Set> boundWriteSetFromCallee = - bindSet(calleeWriteSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath); - calleeBoundWriteSet.addAll(boundWriteSetFromCallee); + bindSet(calleeMayWriteSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath); + calleeUnionBoundMayWriteSet.addAll(boundWriteSetFromCallee); } } } - private void checkFlag(boolean booleanValue, FlatNode fn, NTuple hp) { - if (booleanValue) { - // the definitely written analysis only takes care about locations that - // are written to inside of the SSJava loop - for (Iterator iterator = calleeBoundWriteSet.iterator(); iterator.hasNext();) { - NTuple write = (NTuple) iterator.next(); - if (hp.startsWith(write)) { - // it has write effect! - // throw new Error( - System.out - .println("###" - + "There is a variable, which is reachable through references " - + hp - + ", who comes back to the same read statement without being overwritten at the out-most iteration at " - + methodContainingSSJavaLoop.getClassDesc().getSourceFileName() + "::" - + fn.getNumLine()); - debugcount++; + private void bindHeapPathCallerArgWithCaleeParamForSharedLoc(MethodDescriptor mdCaller, + FlatCall fc) { + + calleeIntersectBoundSharedSet.clear(); + calleeUnionBoundDeleteSet.clear(); + + if (ssjava.isSSJavaUtil(fc.getMethod().getClassDesc())) { + // ssjava util case! + // have write effects on the first argument + TempDescriptor arg = fc.getArg(0); + NTuple argHeapPath = computePath(arg); + + // convert heap path to location path + NTuple argLocTuple = new NTuple(); + argLocTuple.addAll(deriveLocationTuple(mdCaller, (TempDescriptor) argHeapPath.get(0))); + for (int i = 1; i < argHeapPath.size(); i++) { + argLocTuple.add(getLocation(argHeapPath.get(i))); + } + + calleeIntersectBoundSharedSet.addWrite(argLocTuple, argHeapPath); + + } else if (ssjava.needTobeAnnotated(fc.getMethod())) { + + // if arg is not primitive type, we need to propagate maywritten set to + // the caller's location path + + MethodDescriptor mdCallee = fc.getMethod(); + Set setPossibleCallees = new HashSet(); + setPossibleCallees.addAll(callGraph.getMethods(mdCallee)); + + // create mapping from arg idx to its heap paths + Hashtable> mapArgIdx2CallerArgHeapPath = + new Hashtable>(); + + // arg idx is starting from 'this' arg + if (fc.getThis() != null) { + NTuple thisHeapPath = mapHeapPath.get(fc.getThis()); + if (thisHeapPath == null) { + // method is called without creating new flat node representing 'this' + thisHeapPath = new NTuple(); + thisHeapPath.add(fc.getThis()); } + + mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(0), thisHeapPath); } - } - } - private void merge(Hashtable, Hashtable> curr, - Hashtable, Hashtable> in) { + for (int i = 0; i < fc.numArgs(); i++) { + TempDescriptor arg = fc.getArg(i); + NTuple argHeapPath = computePath(arg); + mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(i + 1), argHeapPath); + } - Set> inKeySet = in.keySet(); - for (Iterator iterator = inKeySet.iterator(); iterator.hasNext();) { - NTuple inKey = (NTuple) iterator.next(); - Hashtable inPair = in.get(inKey); + // create mapping from arg idx to its location paths + Hashtable> mapArgIdx2CallerAgLocationPath = + new Hashtable>(); - Set pairKeySet = inPair.keySet(); - for (Iterator iterator2 = pairKeySet.iterator(); iterator2.hasNext();) { - FlatNode pairKey = (FlatNode) iterator2.next(); - Boolean inFlag = inPair.get(pairKey); + // arg idx is starting from 'this' arg + if (fc.getThis() != null) { + NTuple thisLocationPath = deriveLocationTuple(mdCaller, fc.getThis()); + if (thisLocationPath != null) { + mapArgIdx2CallerAgLocationPath.put(Integer.valueOf(0), thisLocationPath); + } + } + + for (int i = 0; i < fc.numArgs(); i++) { + TempDescriptor arg = fc.getArg(i); + NTuple argLocationPath = deriveLocationTuple(mdCaller, arg); + if (argLocationPath != null) { + mapArgIdx2CallerAgLocationPath.put(Integer.valueOf(i + 1), argLocationPath); + } + } + + for (Iterator iterator = setPossibleCallees.iterator(); iterator.hasNext();) { + MethodDescriptor callee = (MethodDescriptor) iterator.next(); + FlatMethod calleeFlatMethod = state.getMethodFlat(callee); + + // binding caller's args and callee's params - Hashtable currPair = curr.get(inKey); - if (currPair == null) { - currPair = new Hashtable(); - curr.put(inKey, currPair); + Hashtable mapParamIdx2ParamTempDesc = + new Hashtable(); + int offset = 0; + if (calleeFlatMethod.getMethod().isStatic()) { + // static method does not have implicit 'this' arg + offset = 1; + } + for (int i = 0; i < calleeFlatMethod.numParameters(); i++) { + TempDescriptor param = calleeFlatMethod.getParameter(i); + mapParamIdx2ParamTempDesc.put(Integer.valueOf(i + offset), param); } - Boolean currFlag = currPair.get(pairKey); - // by default, flag is set by false - if (currFlag == null) { - currFlag = Boolean.FALSE; + Set keySet = mapArgIdx2CallerAgLocationPath.keySet(); + for (Iterator iterator2 = keySet.iterator(); iterator2.hasNext();) { + Integer idx = (Integer) iterator2.next(); + NTuple callerArgLocationPath = mapArgIdx2CallerAgLocationPath.get(idx); + NTuple callerArgHeapPath = mapArgIdx2CallerArgHeapPath.get(idx); + + TempDescriptor calleeParam = mapParamIdx2ParamTempDesc.get(idx); + NTuple calleeLocationPath = deriveLocationTuple(mdCallee, calleeParam); + SharedLocMap calleeDeleteSet = mapFlatMethodToDeleteSet.get(calleeFlatMethod); + SharedLocMap calleeSharedLocMap = mapFlatMethodToSharedLocMap.get(calleeFlatMethod); + SharedLocMap calleeMustClearMap = mapFlatMethodToMustClearMap.get(calleeFlatMethod); + + if (calleeDeleteSet != null) { + createNewMappingOfDeleteSet(callerArgLocationPath, callerArgHeapPath, + calleeLocationPath, calleeDeleteSet); + } + + if (calleeSharedLocMap != null) { + createNewMappingOfSharedSet(callerArgLocationPath, callerArgHeapPath, + calleeLocationPath, calleeSharedLocMap); + } + + if (calleeMustClearMap != null) { + createNewMappingOfMustClearMap(callerArgLocationPath, callerArgHeapPath, + calleeLocationPath, calleeMustClearMap); + } + } - currFlag = Boolean.valueOf(inFlag.booleanValue() | currFlag.booleanValue()); - currPair.put(pairKey, currFlag); + } + } + + } + + private void createNewMappingOfMustClearMap(NTuple callerArgLocationPath, + NTuple callerArgHeapPath, NTuple calleeLocationPath, + SharedLocMap calleeMustClearMap) { + SharedLocMap calleeParamSharedSet = + calleeMustClearMap.getHeapPathStartedWith(calleeLocationPath); + + Set> keySet = calleeParamSharedSet.keySet(); + for (Iterator iterator = keySet.iterator(); iterator.hasNext();) { + NTuple calleeLocTupleKey = (NTuple) iterator.next(); + Set> heapPathSet = calleeParamSharedSet.get(calleeLocTupleKey); + Set> boundHeapPathSet = new HashSet>(); + for (Iterator iterator2 = heapPathSet.iterator(); iterator2.hasNext();) { + NTuple calleeHeapPath = (NTuple) iterator2.next(); + boundHeapPathSet.add(bindHeapPath(callerArgHeapPath, calleeHeapPath)); + } + calleeIntersectBoundMustClearSet.intersect( + bindLocationPath(callerArgLocationPath, calleeLocTupleKey), boundHeapPathSet); } } - private void methodReadOverWriteAnalysis() { - // perform method READ/OVERWRITE analysis - Set methodDescriptorsToAnalyze = new HashSet(); - methodDescriptorsToAnalyze.addAll(ssjava.getAnnotationRequireSet()); + private void createNewMappingOfDeleteSet(NTuple callerArgLocationPath, + NTuple callerArgHeapPath, NTuple calleeLocationPath, + SharedLocMap calleeDeleteSet) { + + SharedLocMap calleeParamDeleteSet = calleeDeleteSet.getHeapPathStartedWith(calleeLocationPath); + + Set> keySet = calleeParamDeleteSet.keySet(); + for (Iterator iterator = keySet.iterator(); iterator.hasNext();) { + NTuple calleeLocTupleKey = (NTuple) iterator.next(); + Set> heapPathSet = calleeParamDeleteSet.get(calleeLocTupleKey); + for (Iterator iterator2 = heapPathSet.iterator(); iterator2.hasNext();) { + NTuple calleeHeapPath = (NTuple) iterator2.next(); + calleeUnionBoundDeleteSet.addWrite( + bindLocationPath(callerArgLocationPath, calleeLocTupleKey), + bindHeapPath(callerArgHeapPath, calleeHeapPath)); + } + } + + } + + private void createNewMappingOfSharedSet(NTuple callerArgLocationPath, + NTuple callerArgHeapPath, NTuple calleeLocationPath, + SharedLocMap calleeSharedLocMap) { - sortedDescriptors = topologicalSort(methodDescriptorsToAnalyze); + SharedLocMap calleeParamSharedSet = + calleeSharedLocMap.getHeapPathStartedWith(calleeLocationPath); - LinkedList descriptorListToAnalyze = - (LinkedList) sortedDescriptors.clone(); + Set> keySet = calleeParamSharedSet.keySet(); + for (Iterator iterator = keySet.iterator(); iterator.hasNext();) { + NTuple calleeLocTupleKey = (NTuple) iterator.next(); + Set> heapPathSet = calleeParamSharedSet.get(calleeLocTupleKey); + Set> boundHeapPathSet = new HashSet>(); + for (Iterator iterator2 = heapPathSet.iterator(); iterator2.hasNext();) { + NTuple calleeHeapPath = (NTuple) iterator2.next(); + boundHeapPathSet.add(bindHeapPath(callerArgHeapPath, calleeHeapPath)); + } + calleeIntersectBoundSharedSet.intersect( + bindLocationPath(callerArgLocationPath, calleeLocTupleKey), boundHeapPathSet); + } + + } + + private NTuple bindLocationPath(NTuple start, NTuple end) { + NTuple locPath = new NTuple(); + locPath.addAll(start); + for (int i = 1; i < end.size(); i++) { + locPath.add(end.get(i)); + } + return locPath; + } + + private NTuple bindHeapPath(NTuple start, NTuple end) { + NTuple heapPath = new NTuple(); + heapPath.addAll(start); + for (int i = 1; i < end.size(); i++) { + heapPath.add(end.get(i)); + } + return heapPath; + } + + private void initialize() { + // First, identify ssjava loop entrace // no need to analyze method having ssjava loop - // methodContainingSSJavaLoop = descriptorListToAnalyze.removeFirst(); methodContainingSSJavaLoop = ssjava.getMethodContainingSSJavaLoop(); + FlatMethod fm = state.getMethodFlat(methodContainingSSJavaLoop); + Set flatNodesToVisit = new HashSet(); + flatNodesToVisit.add(fm); + + LoopFinder loopFinder = new LoopFinder(fm); + + while (!flatNodesToVisit.isEmpty()) { + FlatNode fn = flatNodesToVisit.iterator().next(); + flatNodesToVisit.remove(fn); + + String label = (String) state.fn2labelMap.get(fn); + if (label != null) { + + if (label.equals(ssjava.SSJAVA)) { + ssjava.setSSJavaLoopEntrance(fn); + break; + } + } + + for (int i = 0; i < fn.numNext(); i++) { + FlatNode nn = fn.getNext(i); + flatNodesToVisit.add(nn); + } + } + + assert ssjava.getSSJavaLoopEntrance() != null; + + // assume that ssjava loop is top-level loop in method, not nested loop + Set nestedLoop = loopFinder.nestedLoops(); + for (Iterator loopIter = nestedLoop.iterator(); loopIter.hasNext();) { + LoopFinder lf = (LoopFinder) loopIter.next(); + if (lf.loopEntrances().iterator().next().equals(ssjava.getSSJavaLoopEntrance())) { + ssjavaLoop = lf; + } + } + + assert ssjavaLoop != null; + + loopIncElements = (Set) ssjavaLoop.loopIncElements(); + + // perform topological sort over the set of methods accessed by the main + // event loop + // Set methodDescriptorsToAnalyze = new + // HashSet(); + // methodDescriptorsToAnalyze.addAll(ssjava.getAnnotationRequireSet()); + // sortedDescriptors = topologicalSort(methodDescriptorsToAnalyze); + + liveInTempSetToEventLoop = + liveness.getLiveInTemps(state.getMethodFlat(methodContainingSSJavaLoop), + ssjava.getSSJavaLoopEntrance()); + } + + private void methodReadWriteSetAnalysis() { + // perform method READ/OVERWRITE analysis + LinkedList descriptorListToAnalyze = ssjava.getSortedDescriptors(); + // current descriptors to visit in fixed-point interprocedural analysis, // prioritized by // dependency in the call graph methodDescriptorsToVisitStack.clear(); + descriptorListToAnalyze.removeFirst(); + Set methodDescriptorToVistSet = new HashSet(); methodDescriptorToVistSet.addAll(descriptorListToAnalyze); @@ -1550,25 +2173,25 @@ public class DefinitelyWrittenCheck { FlatMethod fm = state.getMethodFlat(md); Set> readSet = new HashSet>(); - Set> overWriteSet = new HashSet>(); - Set> writeSet = new HashSet>(); + Set> mustWriteSet = new HashSet>(); + Set> mayWriteSet = new HashSet>(); - methodReadOverWrite_analyzeMethod(fm, readSet, overWriteSet, writeSet); + methodReadWriteSet_analyzeMethod(fm, readSet, mustWriteSet, mayWriteSet); - Set> prevRead = mapFlatMethodToRead.get(fm); - Set> prevOverWrite = mapFlatMethodToOverWrite.get(fm); - Set> prevWrite = mapFlatMethodToWrite.get(fm); + Set> prevRead = mapFlatMethodToReadSet.get(fm); + Set> prevMustWrite = mapFlatMethodToMustWriteSet.get(fm); + Set> prevMayWrite = mapFlatMethodToMayWriteSet.get(fm); - if (!(readSet.equals(prevRead) && overWriteSet.equals(prevOverWrite) && writeSet - .equals(prevWrite))) { - mapFlatMethodToRead.put(fm, readSet); - mapFlatMethodToOverWrite.put(fm, overWriteSet); - mapFlatMethodToWrite.put(fm, writeSet); + if (!(readSet.equals(prevRead) && mustWriteSet.equals(prevMustWrite) && mayWriteSet + .equals(prevMayWrite))) { + mapFlatMethodToReadSet.put(fm, readSet); + mapFlatMethodToMustWriteSet.put(fm, mustWriteSet); + mapFlatMethodToMayWriteSet.put(fm, mayWriteSet); // results for callee changed, so enqueue dependents caller for // further // analysis - Iterator depsItr = getDependents(md).iterator(); + Iterator depsItr = ssjava.getDependents(md).iterator(); while (depsItr.hasNext()) { MethodDescriptor methodNext = depsItr.next(); if (!methodDescriptorsToVisitStack.contains(methodNext) @@ -1582,40 +2205,86 @@ public class DefinitelyWrittenCheck { } + methodReadWriteSetAnalysisToEventLoopBody(); + + } + + private void methodReadWriteSet_analyzeMethod(FlatMethod fm, Set> readSet, + Set> mustWriteSet, Set> mayWriteSet) { + if (state.SSJAVADEBUG) { + System.out.println("SSJAVA: Definitely written Analyzing: " + fm); + } + + methodReadWriteSet_analyzeBody(fm, readSet, mustWriteSet, mayWriteSet, false); + } - private void methodReadOverWrite_analyzeMethod(FlatMethod fm, Set> readSet, - Set> overWriteSet, Set> writeSet) { + private void methodReadWriteSetAnalysisToEventLoopBody() { + + // perform method read/write analysis for Event Loop Body + + FlatMethod flatMethodContainingSSJavaLoop = state.getMethodFlat(methodContainingSSJavaLoop); + if (state.SSJAVADEBUG) { - System.out.println("Definitely written Analyzing: " + fm); + System.out.println("SSJAVA: Definitely written Event Loop Analyzing: " + + flatMethodContainingSSJavaLoop); + } + + Set> readSet = new HashSet>(); + Set> mustWriteSet = new HashSet>(); + Set> mayWriteSet = new HashSet>(); + + mapFlatMethodToReadSet.put(flatMethodContainingSSJavaLoop, readSet); + mapFlatMethodToMustWriteSet.put(flatMethodContainingSSJavaLoop, mustWriteSet); + mapFlatMethodToMayWriteSet.put(flatMethodContainingSSJavaLoop, mayWriteSet); + + for (Iterator iterator = liveInTempSetToEventLoop.iterator(); iterator.hasNext();) { + TempDescriptor liveIn = (TempDescriptor) iterator.next(); + NTuple heapPath = new NTuple(); + heapPath.add(liveIn); + mapHeapPath.put(liveIn, heapPath); } + methodReadWriteSet_analyzeBody(ssjava.getSSJavaLoopEntrance(), readSet, mustWriteSet, + mayWriteSet, true); + + } + + private void methodReadWriteSet_analyzeBody(FlatNode startNode, Set> readSet, + Set> mustWriteSet, Set> mayWriteSet, + boolean isEventLoopBody) { + // intraprocedural analysis Set flatNodesToVisit = new HashSet(); - flatNodesToVisit.add(fm); + flatNodesToVisit.add(startNode); while (!flatNodesToVisit.isEmpty()) { FlatNode fn = flatNodesToVisit.iterator().next(); flatNodesToVisit.remove(fn); - Set> curr = new HashSet>(); + Set> currMustWriteSet = new HashSet>(); for (int i = 0; i < fn.numPrev(); i++) { FlatNode prevFn = fn.getPrev(i); - Set> in = mapFlatNodeToWrittenSet.get(prevFn); + Set> in = mapFlatNodeToMustWriteSet.get(prevFn); if (in != null) { - merge(curr, in); + merge(currMustWriteSet, in); } } - methodReadOverWrite_nodeActions(fn, curr, readSet, overWriteSet, writeSet); + methodReadWriteSet_nodeActions(fn, currMustWriteSet, readSet, mustWriteSet, mayWriteSet, + isEventLoopBody); + + Set> mustSetPrev = mapFlatNodeToMustWriteSet.get(fn); - Set> writtenSetPrev = mapFlatNodeToWrittenSet.get(fn); - if (!curr.equals(writtenSetPrev)) { - mapFlatNodeToWrittenSet.put(fn, curr); + if (!currMustWriteSet.equals(mustSetPrev)) { + mapFlatNodeToMustWriteSet.put(fn, currMustWriteSet); for (int i = 0; i < fn.numNext(); i++) { FlatNode nn = fn.getNext(i); - flatNodesToVisit.add(nn); + if ((!isEventLoopBody) || loopIncElements.contains(nn)) { + flatNodesToVisit.add(nn); + } + } } @@ -1623,9 +2292,11 @@ public class DefinitelyWrittenCheck { } - private void methodReadOverWrite_nodeActions(FlatNode fn, Set> writtenSet, - Set> readSet, Set> overWriteSet, - Set> writeSet) { + private void methodReadWriteSet_nodeActions(FlatNode fn, + Set> currMustWriteSet, Set> readSet, + Set> mustWriteSet, Set> mayWriteSet, + boolean isEventLoopBody) { + TempDescriptor lhs; TempDescriptor rhs; FieldDescriptor fld; @@ -1648,13 +2319,55 @@ public class DefinitelyWrittenCheck { FlatOpNode fon = (FlatOpNode) fn; // for a normal assign node, need to propagate lhs's heap path to // rhs + if (fon.getOp().getOp() == Operation.ASSIGN) { rhs = fon.getLeft(); lhs = fon.getDest(); NTuple rhsHeapPath = mapHeapPath.get(rhs); - if (rhsHeapPath != null) { + + // if (lhs.getType().isPrimitive()) { + // NTuple lhsHeapPath = new NTuple(); + // lhsHeapPath.add(lhs); + // mapHeapPath.put(lhs, lhsHeapPath); + // } else + + if (rhsHeapPath != null && (!lhs.getType().isPrimitive())) { mapHeapPath.put(lhs, mapHeapPath.get(rhs)); + } else { + break; + // if (isEventLoopBody) { + // NTuple lhsHeapPath = new NTuple(); + // lhsHeapPath.add(rhs); + // mapHeapPath.put(lhs, lhsHeapPath); + // } else { + // break; + // } + } + + // shared loc extension + if (isEventLoopBody) { + if (!lhs.getSymbol().startsWith("neverused") && rhs.getType().isImmutable()) { + + if (rhs.getType().getExtension() instanceof Location + && lhs.getType().getExtension() instanceof CompositeLocation) { + // rhs is field! + Location rhsLoc = (Location) rhs.getType().getExtension(); + + CompositeLocation lhsCompLoc = (CompositeLocation) lhs.getType().getExtension(); + Location dstLoc = lhsCompLoc.get(lhsCompLoc.getSize() - 1); + + NTuple heapPath = new NTuple(); + for (int i = 0; i < rhsHeapPath.size() - 1; i++) { + heapPath.add(rhsHeapPath.get(i)); + } + + NTuple writeHeapPath = new NTuple(); + writeHeapPath.addAll(heapPath); + writeHeapPath.add(lhs); + + } + } } } @@ -1664,7 +2377,7 @@ public class DefinitelyWrittenCheck { case FKind.FlatElementNode: case FKind.FlatFieldNode: { - // y=x.f; + // x=y.f; if (fn.kind() == FKind.FlatFieldNode) { FlatFieldNode ffn = (FlatFieldNode) fn; @@ -1679,8 +2392,8 @@ public class DefinitelyWrittenCheck { fld = getArrayField(td); } - if (fld.isFinal() /* && fld.isStatic() */) { - // if field is final and static, no need to check + if (fld.isFinal()) { + // if field is final no need to check break; } @@ -1691,13 +2404,16 @@ public class DefinitelyWrittenCheck { // callee's parameters. so just ignore it NTuple readingHeapPath = new NTuple(srcHeapPath.getList()); - readingHeapPath.add(fld); + if (fn.kind() == FKind.FlatFieldNode) { + readingHeapPath.add(fld); + } + mapHeapPath.put(lhs, readingHeapPath); // read (x.f) if (fld.getType().isImmutable()) { // if WT doesnot have hp(x.f), add hp(x.f) to READ - if (!writtenSet.contains(readingHeapPath)) { + if (!currMustWriteSet.contains(readingHeapPath)) { readSet.add(readingHeapPath); } } @@ -1728,18 +2444,23 @@ public class DefinitelyWrittenCheck { // set up heap path NTuple lhsHeapPath = mapHeapPath.get(lhs); + if (lhsHeapPath != null) { // if lhs heap path is null, it means that it is not reachable from // callee's parameters. so just ignore it - NTuple newHeapPath = new NTuple(lhsHeapPath.getList()); - newHeapPath.add(fld); - mapHeapPath.put(fld, newHeapPath); + NTuple fldHeapPath = new NTuple(lhsHeapPath.getList()); + if (fn.kind() != FKind.FlatSetElementNode) { + fldHeapPath.add(fld); + } + // mapHeapPath.put(fld, fldHeapPath); // write(x.f) // need to add hp(y) to WT - writtenSet.add(newHeapPath); + if (fn.kind() != FKind.FlatSetElementNode) { + currMustWriteSet.add(fldHeapPath); + } + mayWriteSet.add(fldHeapPath); - writeSet.add(newHeapPath); } } @@ -1749,30 +2470,43 @@ public class DefinitelyWrittenCheck { FlatCall fc = (FlatCall) fn; - bindHeapPathCallerArgWithCaleeParam(fc); + bindHeapPathCallerArgWithCalleeParam(fc); + + Set> boundReadSet = new HashSet>(); + boundReadSet.addAll(calleeUnionBoundReadSet); + + Set> boundMustWriteSet = new HashSet>(); + boundMustWriteSet.addAll(calleeIntersectBoundMustWriteSet); + + Set> boundMayWriteSet = new HashSet>(); + boundMayWriteSet.addAll(calleeUnionBoundMayWriteSet); + + mapFlatNodeToBoundReadSet.put(fn, boundReadSet); + mapFlatNodeToBoundMustWriteSet.put(fn, boundMustWriteSet); + mapFlatNodeToBoundMayWriteSet.put(fn, boundMayWriteSet); // add heap path, which is an element of READ_bound set and is not // an // element of WT set, to the caller's READ set for (Iterator iterator = calleeUnionBoundReadSet.iterator(); iterator.hasNext();) { NTuple read = (NTuple) iterator.next(); - if (!writtenSet.contains(read)) { + if (!currMustWriteSet.contains(read)) { readSet.add(read); } } // add heap path, which is an element of OVERWRITE_bound set, to the // caller's WT set - for (Iterator iterator = calleeIntersectBoundOverWriteSet.iterator(); iterator.hasNext();) { + for (Iterator iterator = calleeIntersectBoundMustWriteSet.iterator(); iterator.hasNext();) { NTuple write = (NTuple) iterator.next(); - writtenSet.add(write); + currMustWriteSet.add(write); } // add heap path, which is an element of WRITE_BOUND set, to the // caller's writeSet - for (Iterator iterator = calleeBoundWriteSet.iterator(); iterator.hasNext();) { + for (Iterator iterator = calleeUnionBoundMayWriteSet.iterator(); iterator.hasNext();) { NTuple write = (NTuple) iterator.next(); - writeSet.add(write); + mayWriteSet.add(write); } } @@ -1780,7 +2514,7 @@ public class DefinitelyWrittenCheck { case FKind.FlatExit: { // merge the current written set with OVERWRITE set - merge(overWriteSet, writtenSet); + merge(mustWriteSet, currMustWriteSet); } break; @@ -1799,75 +2533,9 @@ public class DefinitelyWrittenCheck { return fd; } - private void mergeSharedLocationAnaylsis(ClearingSummary curr, Set inSet) { - if (inSet.size() == 0) { - return; - } - Hashtable, Location>, Boolean> mapHeapPathLoc2Flag = - new Hashtable, Location>, Boolean>(); - - for (Iterator inIterator = inSet.iterator(); inIterator.hasNext();) { - - ClearingSummary inTable = (ClearingSummary) inIterator.next(); - - Set> keySet = inTable.keySet(); - - for (Iterator iterator = keySet.iterator(); iterator.hasNext();) { - NTuple hpKey = (NTuple) iterator.next(); - SharedStatus inState = inTable.get(hpKey); - SharedStatus currState = curr.get(hpKey); - if (currState == null) { - currState = new SharedStatus(); - curr.put(hpKey, currState); - } - - currState.merge(inState); - - Set locSet = inState.getMap().keySet(); - for (Iterator iterator2 = locSet.iterator(); iterator2.hasNext();) { - Location loc = (Location) iterator2.next(); - Pair, Boolean> pair = inState.getMap().get(loc); - boolean inFlag = pair.getSecond().booleanValue(); - - Pair, Location> flagKey = - new Pair, Location>(hpKey, loc); - Boolean current = mapHeapPathLoc2Flag.get(flagKey); - if (current == null) { - current = new Boolean(true); - } - boolean newInFlag = current.booleanValue() & inFlag; - mapHeapPathLoc2Flag.put(flagKey, Boolean.valueOf(newInFlag)); - } - - } - - } - - // merge flag status - Set> hpKeySet = curr.keySet(); - for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) { - NTuple hpKey = (NTuple) iterator.next(); - SharedStatus currState = curr.get(hpKey); - Set locKeySet = currState.getMap().keySet(); - for (Iterator iterator2 = locKeySet.iterator(); iterator2.hasNext();) { - Location locKey = (Location) iterator2.next(); - Pair, Boolean> pair = currState.getMap().get(locKey); - boolean currentFlag = pair.getSecond().booleanValue(); - Boolean inFlag = mapHeapPathLoc2Flag.get(new Pair(hpKey, locKey)); - if (inFlag != null) { - boolean newFlag = currentFlag | inFlag.booleanValue(); - if (currentFlag != newFlag) { - currState.getMap().put(locKey, new Pair(pair.getFirst(), new Boolean(newFlag))); - } - } - } - } - - } - private void merge(Set> curr, Set> in) { if (curr.isEmpty()) { - // WrittenSet has a special initial value which covers all possible + // set has a special initial value which covers all possible // elements // For the first time of intersection, we can take all previous set curr.addAll(in); @@ -1922,88 +2590,65 @@ public class DefinitelyWrittenCheck { } - // Borrowed it from disjoint analysis - private LinkedList topologicalSort(Set toSort) { - - Set discovered = new HashSet(); - - LinkedList sorted = new LinkedList(); - - Iterator itr = toSort.iterator(); - while (itr.hasNext()) { - MethodDescriptor d = itr.next(); - - if (!discovered.contains(d)) { - dfsVisit(d, toSort, sorted, discovered); - } + private NTuple computePath(Descriptor td) { + // generate proper path fot input td + // if td is local variable, it just generate one element tuple path + if (mapHeapPath.containsKey(td)) { + NTuple rtrHeapPath = new NTuple(); + rtrHeapPath.addAll(mapHeapPath.get(td)); + return rtrHeapPath; + } else { + NTuple rtrHeapPath = new NTuple(); + rtrHeapPath.add(td); + return rtrHeapPath; } - - return sorted; } - // While we're doing DFS on call graph, remember - // dependencies for efficient queuing of methods - // during interprocedural analysis: - // - // a dependent of a method decriptor d for this analysis is: - // 1) a method or task that invokes d - // 2) in the descriptorsToAnalyze set - private void dfsVisit(MethodDescriptor md, Set toSort, - LinkedList sorted, Set discovered) { + private NTuple deriveThisLocationTuple(MethodDescriptor md) { + String thisLocIdentifier = ssjava.getMethodLattice(md).getThisLoc(); + Location thisLoc = new Location(md, thisLocIdentifier); + NTuple locTuple = new NTuple(); + locTuple.add(thisLoc); + return locTuple; + } - discovered.add(md); + private NTuple deriveGlobalLocationTuple(MethodDescriptor md) { + String globalLocIdentifier = ssjava.getMethodLattice(md).getGlobalLoc(); + Location globalLoc = new Location(md, globalLocIdentifier); + NTuple locTuple = new NTuple(); + locTuple.add(globalLoc); + return locTuple; + } - Iterator itr = callGraph.getCallerSet(md).iterator(); - while (itr.hasNext()) { - MethodDescriptor dCaller = (MethodDescriptor) itr.next(); - // only consider callers in the original set to analyze - if (!toSort.contains(dCaller)) { - continue; - } - if (!discovered.contains(dCaller)) { - addDependent(md, // callee - dCaller // caller - ); + private NTuple deriveLocationTuple(MethodDescriptor md, TempDescriptor td) { - dfsVisit(dCaller, toSort, sorted, discovered); - } - } + assert td.getType() != null; - // for leaf-nodes last now! - sorted.addLast(md); - } + if (mapDescriptorToLocationPath.containsKey(td)) { + NTuple locPath = mapDescriptorToLocationPath.get(td); + NTuple rtrPath = new NTuple(); + rtrPath.addAll(locPath); + return rtrPath; + } else { + if (td.getSymbol().startsWith("this")) { + NTuple thisPath = deriveThisLocationTuple(md); + NTuple rtrPath = new NTuple(); + rtrPath.addAll(thisPath); + return rtrPath; + } else { - // a dependent of a method decriptor d for this analysis is: - // 1) a method or task that invokes d - // 2) in the descriptorsToAnalyze set - private void addDependent(MethodDescriptor callee, MethodDescriptor caller) { - Set deps = mapDescriptorToSetDependents.get(callee); - if (deps == null) { - deps = new HashSet(); - } - deps.add(caller); - mapDescriptorToSetDependents.put(callee, deps); - } + if (td.getType().getExtension() != null) { + SSJavaType ssJavaType = (SSJavaType) td.getType().getExtension(); + if (ssJavaType.getCompLoc() != null) { + NTuple rtrPath = new NTuple(); + rtrPath.addAll(ssJavaType.getCompLoc().getTuple()); + return rtrPath; + } + } - private Set getDependents(MethodDescriptor callee) { - Set deps = mapDescriptorToSetDependents.get(callee); - if (deps == null) { - deps = new HashSet(); - mapDescriptorToSetDependents.put(callee, deps); - } - return deps; - } + return null; - private NTuple computePath(TempDescriptor td) { - // generate proper path fot input td - // if td is local variable, it just generate one element tuple path - if (mapHeapPath.containsKey(td)) { - return mapHeapPath.get(td); - } else { - NTuple path = new NTuple(); - path.add(td); - return path; + } } } - } \ No newline at end of file