X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=Robust%2Fsrc%2FAnalysis%2FSSJava%2FDefinitelyWrittenCheck.java;h=63cbf7e38c71bfc338063c0e285980de4d55077a;hb=4e6e3860c77a7d2a8817976d909533a74ce8d02c;hp=437c22ba42f435486af51df1076e8e527cd0ab72;hpb=f7d7d8aff5cfc5e0462c687d2b2c6815d5d202b3;p=IRC.git diff --git a/Robust/src/Analysis/SSJava/DefinitelyWrittenCheck.java b/Robust/src/Analysis/SSJava/DefinitelyWrittenCheck.java index 437c22ba..63cbf7e3 100644 --- a/Robust/src/Analysis/SSJava/DefinitelyWrittenCheck.java +++ b/Robust/src/Analysis/SSJava/DefinitelyWrittenCheck.java @@ -1,5 +1,9 @@ package Analysis.SSJava; +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; @@ -9,21 +13,26 @@ import java.util.Stack; import Analysis.CallGraph.CallGraph; import Analysis.Loops.LoopFinder; +import IR.ClassDescriptor; import IR.Descriptor; import IR.FieldDescriptor; import IR.MethodDescriptor; import IR.Operation; import IR.State; import IR.TypeDescriptor; +import IR.TypeExtension; import IR.Flat.FKind; import IR.Flat.FlatCall; +import IR.Flat.FlatElementNode; import IR.Flat.FlatFieldNode; import IR.Flat.FlatLiteralNode; import IR.Flat.FlatMethod; 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 { @@ -32,6 +41,8 @@ public class DefinitelyWrittenCheck { State state; CallGraph callGraph; + int debugcount = 0; + // 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) @@ -39,142 +50,218 @@ public class DefinitelyWrittenCheck { // 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> mapDescriptorToLocationStrPath; + // 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 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 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; + + // 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 mapFlatMethodToSharedLocMappingSet; + + // 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 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 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 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, Hashtable>> definitelyWrittenResults; + private Hashtable, Set>> mapFlatNodetoEventLoopMap; // 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, SharedLocState>> mapMethodDescriptorToCompleteClearingSummary; + private Hashtable mapMethodDescriptorToCompleteClearingSummary; // maps a method descriptor to the merged incoming caller's current // overwritten status - private Hashtable, SharedLocState>> mapMethodDescriptorToInitialClearingSummary; + private Hashtable mapMethodDescriptorToInitialClearingSummary; // maps a flat node to current partial results - private Hashtable, SharedLocState>> mapFlatNodeToClearingSummary; + private Hashtable mapFlatNodeToClearingSummary; // maps shared location to the set of descriptors which belong to the shared // location - private Hashtable, Location>, Set> mapSharedLocation2DescriptorSet; - // data structure for merging current state - private Hashtable, Location>, Boolean> mapHeapPathLocation2Flag; + // keep current descriptors to visit in fixed-point interprocedural analysis, + private Stack methodDescriptorsToVisitStack; + + // when analyzing flatcall, need to re-schedule set of callee + private Set calleesToEnqueue; + + 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 MultiSourceMap mapLocationPathToMayWrittenSet; + + private Hashtable> mapMethodToSharedWriteMapping; + + private Hashtable mapFlatNodeToSharedLocMapping; + + private Hashtable> mapSharedLocationToCoverSet; + + private LinkedList sortedDescriptors; private FlatNode ssjavaLoopEntrance; private LoopFinder ssjavaLoop; private Set loopIncElements; private Set> calleeUnionBoundReadSet; - private Set> calleeIntersectBoundOverWriteSet; + private Set> calleeIntersectBoundMustWriteSet; + private Set> calleeUnionBoundMayWriteSet; + private Set> calleeUnionBoundDeleteSet; + private SharedLocMappingSet calleeIntersectBoundSharedSet; + + 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.mapFlatNodeToMustWriteSet = new Hashtable>>(); this.mapDescriptorToSetDependents = new Hashtable>(); this.mapHeapPath = new Hashtable>(); - this.mapFlatMethodToRead = new Hashtable>>(); - this.mapFlatMethodToOverWrite = new Hashtable>>(); - this.definitelyWrittenResults = - new Hashtable, Hashtable>>(); + this.mapDescriptorToLocationStrPath = 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.calleeIntersectBoundMustWriteSet = new HashSet>(); + this.calleeUnionBoundMayWriteSet = new HashSet>(); this.mapMethodDescriptorToCompleteClearingSummary = - new Hashtable, SharedLocState>>(); + new Hashtable(); this.mapMethodDescriptorToInitialClearingSummary = - new Hashtable, SharedLocState>>(); - this.mapFlatNodeToClearingSummary = - new Hashtable, SharedLocState>>(); - this.mapSharedLocation2DescriptorSet = - new Hashtable, Location>, Set>(); - this.mapHeapPathLocation2Flag = new Hashtable, Location>, Boolean>(); + 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.possibleCalleeReadSummarySetToCaller = new HashSet(); + this.mapMethodDescriptorToReadSummary = new Hashtable(); + this.mapFlatNodeToBoundReadSet = new Hashtable>>(); + this.mapFlatNodeToBoundMustWriteSet = new Hashtable>>(); + this.mapFlatNodeToBoundMayWriteSet = new Hashtable>>(); + this.mapSharedLocationToCoverSet = new Hashtable>(); + this.mapFlatNodeToSharedLocMapping = new Hashtable(); + this.mapFlatMethodToDeleteSet = new Hashtable>>(); + this.calleeUnionBoundDeleteSet = new HashSet>(); + this.calleeIntersectBoundSharedSet = new SharedLocMappingSet(); + this.mapFlatMethodToSharedLocMappingSet = new Hashtable(); + this.mapLocationPathToMayWrittenSet = new MultiSourceMap(); + this.mapMethodToSharedWriteMapping = + new Hashtable>(); } public void definitelyWrittenCheck() { if (!ssjava.getAnnotationRequireSet().isEmpty()) { - methodReadOverWriteAnalysis(); - writtenAnalyis(); - sharedLocationAnalysis(); - checkSharedLocationResult(); - } - } + initialize(); + computeSharedCoverSet(); - private void checkSharedLocationResult() { + System.out.println("#"); + System.out.println(mapLocationPathToMayWrittenSet); - Hashtable, SharedLocState> result = - mapFlatNodeToClearingSummary.get(ssjavaLoopEntrance); - System.out.println("checkSharedLocationResult=" + result); - Set> hpKeySet = result.keySet(); - for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) { - NTuple hpKey = (NTuple) iterator.next(); - SharedLocState state = result.get(hpKey); - Set locKeySet = state.getLocationSet(); - for (Iterator iterator2 = locKeySet.iterator(); iterator2.hasNext();) { - Location locKey = (Location) iterator2.next(); - if (!state.getFlag(locKey)) { - throw new Error( - "Some concrete locations of the shared abstract location are not cleared at the same time."); - } - } - } + methodReadWriteSetAnalysis(); + // sharedLocAnalysis(); + + // eventLoopAnalysis(); + + // XXXXXXX + // methodReadWriteSetAnalysis(); + // methodReadWriteSetAnalysisToEventLoopBody(); + // eventLoopAnalysis(); + // XXXXXXX + // sharedLocationAnalysis(); + // checkSharedLocationResult(); + } } - private void sharedLocationAnalysis() { - // verify that all concrete locations of shared location are cleared out at - // the same time once per the out-most loop + private void sharedLocAnalysis() { - computeReadSharedDescriptorSet(); + // perform method READ/OVERWRITE analysis + LinkedList descriptorListToAnalyze = + (LinkedList) sortedDescriptors.clone(); - Set methodDescriptorsToAnalyze = new HashSet(); - methodDescriptorsToAnalyze.addAll(ssjava.getAnnotationRequireSet()); + // current descriptors to visit in fixed-point interprocedural analysis, + // prioritized by + // dependency in the call graph + methodDescriptorsToVisitStack.clear(); - LinkedList sortedDescriptors = topologicalSort(methodDescriptorsToAnalyze); + descriptorListToAnalyze.removeFirst(); - Stack methodDescriptorsToVisitStack = new Stack(); Set methodDescriptorToVistSet = new HashSet(); - methodDescriptorToVistSet.addAll(sortedDescriptors); + methodDescriptorToVistSet.addAll(descriptorListToAnalyze); - while (!sortedDescriptors.isEmpty()) { - MethodDescriptor md = sortedDescriptors.removeLast(); + while (!descriptorListToAnalyze.isEmpty()) { + MethodDescriptor md = descriptorListToAnalyze.removeFirst(); methodDescriptorsToVisitStack.add(md); } // 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); - sharedLocation_analyzeMethod(fm, (md.equals(methodContainingSSJavaLoop))); + Set> deleteSet = new HashSet>(); + + sharedLoc_analyzeMethod(fm, deleteSet); + System.out.println("deleteSet result=" + deleteSet); - if (true) { + Set> prevDeleteSet = mapFlatMethodToDeleteSet.get(fm); + + if (!deleteSet.equals(prevDeleteSet)) { + mapFlatMethodToDeleteSet.put(fm, deleteSet); // results for callee changed, so enqueue dependents caller for - // further analysis + // further + // analysis Iterator depsItr = getDependents(md).iterator(); while (depsItr.hasNext()) { MethodDescriptor methodNext = depsItr.next(); @@ -189,72 +276,46 @@ public class DefinitelyWrittenCheck { } - Set flatNodesToVisit = new HashSet(); - flatNodesToVisit.add(ssjavaLoopEntrance); - } - private void sharedLocation_analyzeMethod(FlatMethod fm, boolean onlyVisitSSJavaLoop) { - + private void sharedLoc_analyzeMethod(FlatMethod fm, Set> deleteSet) { if (state.SSJAVADEBUG) { - System.out.println("Definitely written for shared locations Analyzing: " + fm + " " - + onlyVisitSSJavaLoop); + System.out.println("SSJAVA: Definite clearance for shared locations Analyzing: " + fm); } + sharedLoc_analyzeBody(fm, deleteSet, false); + + } + + private void sharedLoc_analyzeBody(FlatNode startNode, Set> deleteSet, + boolean isEventLoopBody) { + // intraprocedural analysis Set flatNodesToVisit = new HashSet(); - - if (onlyVisitSSJavaLoop) { - flatNodesToVisit.add(ssjavaLoopEntrance); - } else { - flatNodesToVisit.add(fm); - } + flatNodesToVisit.add(startNode); while (!flatNodesToVisit.isEmpty()) { FlatNode fn = flatNodesToVisit.iterator().next(); flatNodesToVisit.remove(fn); - Hashtable, SharedLocState> curr = - new Hashtable, SharedLocState>(); + SharedLocMappingSet currSharedSet = new SharedLocMappingSet(); - mapHeapPathLocation2Flag.clear(); for (int i = 0; i < fn.numPrev(); i++) { FlatNode prevFn = fn.getPrev(i); - Hashtable, SharedLocState> in = mapFlatNodeToClearingSummary.get(prevFn); + SharedLocMappingSet in = mapFlatNodeToSharedLocMapping.get(prevFn); if (in != null) { - mergeSharedAnaylsis(curr, in); + merge(currSharedSet, in); } } - // merge flag status - Set> hpKeySet = curr.keySet(); - for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) { - NTuple hpKey = (NTuple) iterator.next(); - SharedLocState 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 = mapHeapPathLocation2Flag.get(new Pair(hpKey, locKey)); - boolean newFlag = currentFlag | inFlag.booleanValue(); - if (currentFlag != newFlag) { - currState.getMap().put(locKey, new Pair(pair.getFirst(), new Boolean(newFlag))); - } - } - } - - sharedLocation_nodeActions(fn, curr, onlyVisitSSJavaLoop); - Hashtable, SharedLocState> clearingPrev = - mapFlatNodeToClearingSummary.get(fn); - - if (!curr.equals(clearingPrev)) { - mapFlatNodeToClearingSummary.put(fn, curr); + sharedLoc_nodeActions(fn, currSharedSet, deleteSet, isEventLoopBody); + SharedLocMappingSet mustSetPrev = mapFlatNodeToSharedLocMapping.get(fn); + if (!currSharedSet.equals(mustSetPrev)) { + mapFlatNodeToSharedLocMapping.put(fn, currSharedSet); 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); } @@ -265,50 +326,71 @@ public class DefinitelyWrittenCheck { } - private void sharedLocation_nodeActions(FlatNode fn, - Hashtable, SharedLocState> curr, boolean isSSJavaLoop) { + private void sharedLoc_nodeActions(FlatNode fn, SharedLocMappingSet curr, + Set> deleteSet, boolean isEventLoopBody) { + + SharedLocMappingSet killSet = new SharedLocMappingSet(); + SharedLocMappingSet genSet = new SharedLocMappingSet(); 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) { - // 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, rhs); - writeLocation(curr, lhsHeapPath, lhs); - } - } - } + if (isEventLoopBody) { + FlatOpNode fon = (FlatOpNode) fn; + lhs = fon.getDest(); + rhs = fon.getLeft(); - } - break; + if (!lhs.getSymbol().startsWith("neverused")) { - case FKind.FlatFieldNode: - case FKind.FlatElementNode: { + if (rhs.getType().isImmutable()) { + NTuple rhsHeapPath = computePath(rhs); - FlatFieldNode ffn = (FlatFieldNode) fn; - lhs = ffn.getDst(); - rhs = ffn.getSrc(); - fld = ffn.getField(); + if (rhs.getType().getExtension() instanceof Location + && lhs.getType().getExtension() instanceof CompositeLocation) { + // rhs is field! + Location rhsLoc = (Location) rhs.getType().getExtension(); - // read field - NTuple srcHeapPath = mapHeapPath.get(rhs); - NTuple fldHeapPath = new NTuple(srcHeapPath.getList()); + CompositeLocation lhsCompLoc = (CompositeLocation) lhs.getType().getExtension(); + Location dstLoc = lhsCompLoc.get(lhsCompLoc.getSize() - 1); - if (fld.getType().isImmutable()) { - readLocation(curr, fldHeapPath, fld); + 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); + + System.out.println("VAR WRITE:" + fn); + System.out.println("LHS TYPE EXTENSION=" + lhs.getType().getExtension()); + System.out.println("RHS TYPE EXTENSION=" + rhs.getType().getExtension() + + " HEAPPATH=" + rhsHeapPath); + + // computing gen/kill set + computeKILLSetForWrite(curr, heapPath, dstLoc, killSet); + if (!dstLoc.equals(rhsLoc)) { + computeGENSetForHigherWrite(curr, heapPath, dstLoc, lhs, genSet); + deleteSet.remove(writeHeapPath); + } else { + computeGENSetForSharedWrite(curr, heapPath, dstLoc, lhs, genSet); + deleteSet.add(writeHeapPath); + } + + } + + // System.out.println("fieldLoc=" + fieldLoc + " srcLoc=" + srcLoc); + System.out.println("KILLSET=" + killSet); + System.out.println("GENSet=" + genSet); + System.out.println("DELETESET=" + deleteSet); + + } + } } } @@ -317,289 +399,1182 @@ public class DefinitelyWrittenCheck { case FKind.FlatSetFieldNode: case FKind.FlatSetElementNode: { - FlatSetFieldNode fsfn = (FlatSetFieldNode) fn; - lhs = fsfn.getDst(); - fld = fsfn.getField(); + 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(); + rhs = fsen.getSrc(); + TypeDescriptor td = lhs.getType().dereference(); + fld = getArrayField(td); + } - // write(field) - NTuple lhsHeapPath = computePath(lhs); - NTuple fldHeapPath = new NTuple(lhsHeapPath.getList()); + // shared loc extension + Location srcLoc = getLocation(rhs); + Location fieldLoc = (Location) fld.getType().getExtension(); + if (ssjava.isSharedLocation(fieldLoc)) { + // only care the case that loc(f) is shared location + // write(field) + NTuple lhsHeapPath = computePath(lhs); + NTuple fldHeapPath = new NTuple(lhsHeapPath.getList()); + fldHeapPath.add(fld); - if (fld.getType().isImmutable()) { - writeLocation(curr, fldHeapPath, fld); + // computing gen/kill set + computeKILLSetForWrite(curr, lhsHeapPath, fieldLoc, killSet); + if (!fieldLoc.equals(srcLoc)) { + System.out.println("LOC IS DIFFERENT"); + computeGENSetForHigherWrite(curr, lhsHeapPath, fieldLoc, fld, genSet); + deleteSet.remove(fldHeapPath); + } else { + computeGENSetForSharedWrite(curr, lhsHeapPath, fieldLoc, fld, genSet); + deleteSet.add(fldHeapPath); + } } + System.out.println("################"); + System.out.println("FIELD WRITE:" + fn); + System.out.println("fieldLoc=" + fieldLoc + " srcLoc=" + srcLoc); + System.out.println("KILLSET=" + killSet); + System.out.println("GENSet=" + genSet); + System.out.println("DELETESET=" + deleteSet); + } break; case FKind.FlatCall: { + FlatCall fc = (FlatCall) fn; + + bindHeapPathCallerArgWithCaleeParamForSharedLoc(fc); + // generateKILLSetForFlatCall(fc, curr, readWriteKillSet); + // generateGENSetForFlatCall(fc, readWriteGenSet); + + // System.out.println + // // only care the case that loc(f) is shared location + // // write(field) + // NTuple lhsHeapPath = computePath(lhs); + // NTuple fldHeapPath = new + // NTuple(lhsHeapPath.getList()); + // fldHeapPath.add(fld); + // + // // computing gen/kill set + // computeKILLSetForWrite(curr, lhsHeapPath, fieldLoc, killSet); + // if (!fieldLoc.equals(srcLoc)) { + // System.out.println("LOC IS DIFFERENT"); + // computeGENSetForHigherWrite(curr, lhsHeapPath, fieldLoc, fld, genSet); + // deleteSet.remove(fldHeapPath); + // } else { + // computeGENSetForSharedWrite(curr, lhsHeapPath, fieldLoc, fld, genSet); + // deleteSet.add(fldHeapPath); + // } + // ("FLATCALL:" + fn); + // System.out.println("bound DELETE Set=" + calleeUnionBoundDeleteSet); + // // System.out.println("KILLSET=" + KILLSet); + // // System.out.println("GENSet=" + GENSet); + // } - break; + // break; + } + // computeNewMapping(curr, readWriteKillSet, readWriteGenSet); + // System.out.println("#######" + curr); + } - private void computeReadSharedDescriptorSet() { - Set methodDescriptorsToAnalyze = new HashSet(); - methodDescriptorsToAnalyze.addAll(ssjava.getAnnotationRequireSet()); + private void computeKILLSetForWrite(SharedLocMappingSet curr, NTuple hp, + Location loc, SharedLocMappingSet killSet) { - for (Iterator iterator = methodDescriptorsToAnalyze.iterator(); iterator.hasNext();) { - MethodDescriptor md = (MethodDescriptor) iterator.next(); - FlatMethod fm = state.getMethodFlat(md); - computeReadSharedDescriptorSet_analyzeMethod(fm, md.equals(methodContainingSSJavaLoop)); + Set currWriteSet = curr.getWriteSet(hp, loc); + if (!currWriteSet.isEmpty()) { + killSet.addWriteSet(hp, loc, currWriteSet); } } - private void computeReadSharedDescriptorSet_analyzeMethod(FlatMethod fm, - boolean onlyVisitSSJavaLoop) { + private void computeGENSetForHigherWrite(SharedLocMappingSet curr, NTuple hp, + Location loc, Descriptor desc, SharedLocMappingSet genSet) { - Set flatNodesToVisit = new HashSet(); - Set visited = new HashSet(); + Set genWriteSet = new HashSet(); + genWriteSet.addAll(curr.getWriteSet(hp, loc)); + genWriteSet.add(desc); - if (onlyVisitSSJavaLoop) { - flatNodesToVisit.add(ssjavaLoopEntrance); - } else { - flatNodesToVisit.add(fm); - } + genSet.addWriteSet(hp, loc, genWriteSet); - while (!flatNodesToVisit.isEmpty()) { - FlatNode fn = flatNodesToVisit.iterator().next(); - flatNodesToVisit.remove(fn); - visited.add(fn); + } - computeReadSharedDescriptorSet_nodeActions(fn, onlyVisitSSJavaLoop); + private void computeGENSetForSharedWrite(SharedLocMappingSet curr, NTuple hp, + Location loc, Descriptor desc, SharedLocMappingSet genSet) { - 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); - } - } - } + Set genWriteSet = new HashSet(); + genWriteSet.addAll(curr.getWriteSet(hp, loc)); + genWriteSet.remove(desc); + + if (!genWriteSet.isEmpty()) { + genSet.addWriteSet(hp, loc, genWriteSet); + } + } + private void merge(SharedLocMappingSet currSharedSet, SharedLocMappingSet in) { + + Set> hpKeySet = in.getHeapPathKeySet(); + for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) { + NTuple hpKey = (NTuple) iterator.next(); + Set locSet = in.getLocationKeySet(hpKey); + for (Iterator iterator2 = locSet.iterator(); iterator2.hasNext();) { + Location locKey = (Location) iterator2.next(); + Set writeSet = in.getWriteSet(hpKey, locKey); + currSharedSet.intersectWriteSet(hpKey, locKey, writeSet); + } } } - private void computeReadSharedDescriptorSet_nodeActions(FlatNode fn, boolean isSSJavaLoop) { + private void checkSharedLocationResult() { - TempDescriptor lhs; - TempDescriptor rhs; - FieldDescriptor fld; + // mapping of method containing ssjava loop has the final result of + // shared location analysis - switch (fn.kind()) { - case FKind.FlatOpNode: { - FlatOpNode fon = (FlatOpNode) fn; - lhs = fon.getDest(); - rhs = fon.getLeft(); + ClearingSummary result = + mapMethodDescriptorToCompleteClearingSummary.get(methodContainingSSJavaLoop); - 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); - addReadDescriptor(rhsHeapPath, rhs); + String str = generateNotClearedResult(result); + if (str.length() > 0) { + throw new Error( + "Following concrete locations of the shared abstract location are not cleared at the same time:\n" + + str); + } + + } + + private String generateNotClearedResult(ClearingSummary result) { + Set> keySet = result.keySet(); + + StringBuffer str = new StringBuffer(); + 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! + str.append("- Concrete locations of the shared location '" + locKey + + "' are not cleared out, which are reachable through the heap path '" + hpKey + + ".\n"); + } } } - } - break; - case FKind.FlatFieldNode: - case FKind.FlatElementNode: { + return str.toString(); - FlatFieldNode ffn = (FlatFieldNode) fn; - lhs = ffn.getDst(); - rhs = ffn.getSrc(); - fld = ffn.getField(); + } - // read field - NTuple srcHeapPath = mapHeapPath.get(rhs); - NTuple fldHeapPath = new NTuple(srcHeapPath.getList()); - // fldHeapPath.add(fld); + private void writeReadMapFile() { - if (fld.getType().isImmutable()) { - addReadDescriptor(fldHeapPath, fld); - } + String fileName = "SharedLocationReadMap"; - // propagate rhs's heap path to the lhs - mapHeapPath.put(lhs, fldHeapPath); + try { + BufferedWriter bw = new BufferedWriter(new FileWriter(fileName + ".txt")); + Set keySet = mapMethodDescriptorToReadSummary.keySet(); + for (Iterator iterator = keySet.iterator(); iterator.hasNext();) { + MethodDescriptor mdKey = (MethodDescriptor) iterator.next(); + ReadSummary summary = mapMethodDescriptorToReadSummary.get(mdKey); + bw.write("Method " + mdKey + "::\n"); + bw.write(summary + "\n\n"); + } + bw.close(); + } catch (IOException e) { + e.printStackTrace(); } - break; - case FKind.FlatSetFieldNode: - case FKind.FlatSetElementNode: { + } - FlatSetFieldNode fsfn = (FlatSetFieldNode) fn; - lhs = fsfn.getDst(); - fld = fsfn.getField(); + private void sharedLocationAnalysis() { + // verify that all concrete locations of shared location are cleared out at + // the same time once per the out-most loop - // write(field) - NTuple lhsHeapPath = computePath(lhs); - NTuple fldHeapPath = new NTuple(lhsHeapPath.getList()); - // writeLocation(curr, fldHeapPath, fld, getLocation(fld)); + computeSharedCoverSet(); + if (state.SSJAVADEBUG) { + writeReadMapFile(); } - break; - } - } + // methodDescriptorsToVisitStack.clear(); + // methodDescriptorsToVisitStack.add(sortedDescriptors.peekFirst()); - private void addReadDescriptor(NTuple hp, Descriptor d) { + LinkedList descriptorListToAnalyze = + (LinkedList) sortedDescriptors.clone(); - Location loc = getLocation(d); + // current descriptors to visit in fixed-point interprocedural analysis, + // prioritized by + // dependency in the call graph + methodDescriptorsToVisitStack.clear(); - if (loc != null && ssjava.isSharedLocation(loc)) { + Set methodDescriptorToVistSet = new HashSet(); + methodDescriptorToVistSet.addAll(descriptorListToAnalyze); - Pair key = new Pair(hp, loc); - Set set = mapSharedLocation2DescriptorSet.get(key); - if (set == null) { - set = new HashSet(); - mapSharedLocation2DescriptorSet.put(key, set); - } - set.add(d); + while (!descriptorListToAnalyze.isEmpty()) { + MethodDescriptor md = descriptorListToAnalyze.removeFirst(); + methodDescriptorsToVisitStack.add(md); } - } + // analyze scheduled methods until there are no more to visit + while (!methodDescriptorsToVisitStack.isEmpty()) { + MethodDescriptor md = methodDescriptorsToVisitStack.pop(); - private Location getLocation(Descriptor d) { + ClearingSummary completeSummary = + sharedLocation_analyzeMethod(md, (md.equals(methodContainingSSJavaLoop))); - if (d instanceof FieldDescriptor) { - return (Location) ((FieldDescriptor) d).getType().getExtension(); - } else { - assert d instanceof TempDescriptor; - CompositeLocation comp = (CompositeLocation) ((TempDescriptor) d).getType().getExtension(); - if (comp == null) { - return null; - } else { - return comp.get(comp.getSize() - 1); - } - } + ClearingSummary prevCompleteSummary = mapMethodDescriptorToCompleteClearingSummary.get(md); - } + if (!completeSummary.equals(prevCompleteSummary)) { - private void writeLocation(Hashtable, SharedLocState> curr, - NTuple hp, Descriptor d) { - Location loc = getLocation(d); - if (loc != null && ssjava.isSharedLocation(loc)) { - SharedLocState state = getState(curr, hp); - state.addVar(loc, d); + mapMethodDescriptorToCompleteClearingSummary.put(md, completeSummary); - // if the set v contains all of variables belonging to the shared - // location, set flag to true + // results for callee changed, so enqueue dependents caller for + // further analysis + Iterator depsItr = getDependents(md).iterator(); + while (depsItr.hasNext()) { + MethodDescriptor methodNext = depsItr.next(); + if (!methodDescriptorsToVisitStack.contains(methodNext)) { + methodDescriptorsToVisitStack.add(methodNext); + } + } - Set sharedVarSet = - mapSharedLocation2DescriptorSet.get(new Pair, Location>(hp, loc)); + // 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(); - if (state.getVarSet(loc).containsAll(sharedVarSet)) { - state.updateFlag(loc, true); } - } - } - private void readLocation(Hashtable, SharedLocState> curr, - NTuple hp, Descriptor d) { - // remove reading var x from written set - Location loc = getLocation(d); - if (loc != null && ssjava.isSharedLocation(loc)) { - SharedLocState state = getState(curr, hp); - state.removeVar(loc, d); } - } - private SharedLocState getState(Hashtable, SharedLocState> curr, - NTuple hp) { - SharedLocState state = curr.get(hp); - if (state == null) { - state = new SharedLocState(); - curr.put(hp, state); - } - return state; } - private void writtenAnalyis() { - // perform second stage analysis: intraprocedural analysis ensure that - // all - // variables are definitely written in-between the same read + private ClearingSummary sharedLocation_analyzeMethod(MethodDescriptor md, + boolean onlyVisitSSJavaLoop) { - // First, identify ssjava loop entrace - FlatMethod fm = state.getMethodFlat(methodContainingSSJavaLoop); + if (state.SSJAVADEBUG) { + System.out.println("SSJAVA: Definite clearance for shared locations Analyzing: " + md); + } + + FlatMethod fm = state.getMethodFlat(md); + + // intraprocedural analysis Set flatNodesToVisit = new HashSet(); - flatNodesToVisit.add(fm); - LoopFinder loopFinder = new LoopFinder(fm); + // start a new mapping of partial results for each flat node + mapFlatNodeToClearingSummary = new Hashtable(); + + if (onlyVisitSSJavaLoop) { + flatNodesToVisit.add(ssjavaLoopEntrance); + } else { + flatNodesToVisit.add(fm); + } + + Set returnNodeSet = new HashSet(); + + while (!flatNodesToVisit.isEmpty()) { + FlatNode fn = flatNodesToVisit.iterator().next(); + flatNodesToVisit.remove(fn); + + ClearingSummary curr = new ClearingSummary(); + + 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); + } + } + mergeSharedLocationAnaylsis(curr, prevSet); + + sharedLocation_nodeActions(md, fn, curr, returnNodeSet, onlyVisitSSJavaLoop); + ClearingSummary clearingPrev = mapFlatNodeToClearingSummary.get(fn); + + if (!curr.equals(clearingPrev)) { + mapFlatNodeToClearingSummary.put(fn, curr); + + for (int i = 0; i < fn.numNext(); i++) { + FlatNode nn = fn.getNext(i); + + if (!onlyVisitSSJavaLoop || (onlyVisitSSJavaLoop && loopIncElements.contains(nn))) { + flatNodesToVisit.add(nn); + } + + } + } + + } + + 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); + + return completeSummary; + } + + private void sharedLocation_nodeActions(MethodDescriptor md, FlatNode fn, ClearingSummary curr, + Set returnNodeSet, boolean isSSJavaLoop) { + + TempDescriptor lhs; + TempDescriptor rhs; + FieldDescriptor fld; + switch (fn.kind()) { + + case FKind.FlatMethod: { + FlatMethod fm = (FlatMethod) fn; + + ClearingSummary summaryFromCaller = + mapMethodDescriptorToInitialClearingSummary.get(fm.getMethod()); + + Set inSet = new HashSet(); + if (summaryFromCaller != null) { + inSet.add(summaryFromCaller); + mergeSharedLocationAnaylsis(curr, inSet); + } + + } + break; + + case FKind.FlatOpNode: { + FlatOpNode fon = (FlatOpNode) fn; + 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(md, curr, rhsHeapPath, getLocation(rhs), rhs); + writeLocation(md, curr, lhsHeapPath, getLocation(lhs), lhs); + } + } + } + + } + 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(); + rhs = fsen.getSrc(); + TypeDescriptor td = lhs.getType().dereference(); + fld = getArrayField(td); + } + + // write(field) + NTuple lhsHeapPath = computePath(lhs); + NTuple fldHeapPath = new NTuple(lhsHeapPath.getList()); + if (fld.getType().isImmutable()) { + + writeLocation(md, curr, fldHeapPath, getLocation(fld), fld); + + 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)); + } + SharedStatus state = getState(curr, arrayPath); + state.setWriteEffect(getLocation(desc)); + } + + } else { + // updates reference field case: + fldHeapPath.add(fld); + updateWriteEffectOnReferenceField(curr, fldHeapPath); + } + + } + 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)); + + 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; + + writeLocation(md, curr, argHeapPath, loc, fld); + } + + } else { + // find out the set of callees + MethodDescriptor mdCallee = fc.getMethod(); + FlatMethod fmCallee = state.getMethodFlat(mdCallee); + Set setPossibleCallees = new HashSet(); + setPossibleCallees.addAll(callGraph.getMethods(mdCallee)); + + possibleCalleeCompleteSummarySetToCaller.clear(); + + for (Iterator iterator = setPossibleCallees.iterator(); iterator.hasNext();) { + MethodDescriptor mdPossibleCallee = (MethodDescriptor) iterator.next(); + FlatMethod calleeFlatMethod = state.getMethodFlat(mdPossibleCallee); + + addDependent(mdPossibleCallee, // callee + md); // caller + + calleesToEnqueue.add(mdPossibleCallee); + + // 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); + } + + // if changes, update the init summary + // and reschedule the callee for analysis + if (!calleeInitSummary.equals(prevCalleeInitSummary)) { + + if (!methodDescriptorsToVisitStack.contains(mdPossibleCallee)) { + methodDescriptorsToVisitStack.add(mdPossibleCallee); + } + + mapMethodDescriptorToInitialClearingSummary.put(mdPossibleCallee, calleeInitSummary); + } + + } + + // contribute callee's writing effects to the caller + mergeSharedLocationAnaylsis(curr, possibleCalleeCompleteSummarySetToCaller); + + } + + } + break; + + case FKind.FlatReturnNode: { + returnNodeSet.add(fn); + } + break; + + } + + } + + private void updateWriteEffectOnReferenceField(ClearingSummary curr, NTuple heapPath) { + + // 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); + } + } + + } + + private ClearingSummary bindHeapPathOfCalleeCallerEffects(FlatCall fc, + FlatMethod calleeFlatMethod, ClearingSummary curr) { + + ClearingSummary boundSet = new ClearingSummary(); + + // create mapping from arg idx to its heap paths + Hashtable> mapArgIdx2CallerArgHeapPath = + new Hashtable>(); + + 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()); + } + + mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(0), thisHeapPath); + } + + 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()); + } + + } + } + + } + + // 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++) { + 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 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)) { + + NTuple boundHeapPathForCaller = replace(hpKey, argHeapPath); + + boundCalleeEfffects.put(boundHeapPathForCaller, calleeCompleteSummary.get(hpKey) + .clone()); + + } + } + + } + + } + possibleCalleeCompleteSummarySetToCaller.add(boundCalleeEfffects); + } + + return boundSet; + } + + private NTuple replace(NTuple hpKey, NTuple argHeapPath) { + + // 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 + + NTuple bound = new NTuple(); + + for (int i = 0; i < argHeapPath.size(); i++) { + bound.add(argHeapPath.get(i)); + } + + for (int i = 1; i < hpKey.size(); i++) { + bound.add(hpKey.get(i)); + } + + 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 + + NTuple boundHeapPath = new NTuple(); + boundHeapPath.add(calleeParamHeapPath); + + for (int i = argHeapPath.size(); i < effectHeapPath.size(); i++) { + boundHeapPath.add(effectHeapPath.get(i)); + } + + return boundHeapPath; + } + + private void computeSharedCoverSet() { + LinkedList descriptorListToAnalyze = + (LinkedList) sortedDescriptors.clone(); + + // 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); + } + + // analyze scheduled methods until there are no more to visit + while (!methodDescriptorsToVisitStack.isEmpty()) { + MethodDescriptor md = methodDescriptorsToVisitStack.pop(); + FlatMethod fm = state.getMethodFlat(md); + computeSharedCoverSet_analyzeMethod(fm, md.equals(methodContainingSSJavaLoop)); + } + + computeSharedCoverSetForEventLoop(); + + } + + private void computeSharedCoverSetForEventLoop() { + computeSharedCoverSet_analyzeMethod(state.getMethodFlat(methodContainingSSJavaLoop), true); + } + + 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); + } else { + flatNodesToVisit.add(fm); + } + + while (!flatNodesToVisit.isEmpty()) { + FlatNode fn = flatNodesToVisit.iterator().next(); + flatNodesToVisit.remove(fn); + visited.add(fn); + + computeSharedCoverSet_nodeActions(md, fn); + + 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 computeSharedCoverSet_nodeActions(MethodDescriptor md, FlatNode fn) { + TempDescriptor lhs; + TempDescriptor rhs; + FieldDescriptor fld; + + switch (fn.kind()) { + + case FKind.FlatLiteralNode: { + FlatLiteralNode fln = (FlatLiteralNode) fn; + lhs = fln.getDst(); + + 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); + // check if the last one is shared loc + if (ssjava.isSharedLocation(lastLocElement)) { + addSharedLocDescriptor(lastLocElement, lhs); + } + } + } + + } + 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(); + + if (lhs.getType().isPrimitive() && !lhs.getSymbol().startsWith("neverused") + && !lhs.getSymbol().startsWith("srctmp") && !lhs.getSymbol().startsWith("leftop") + && !lhs.getSymbol().startsWith("rightop")) { + + NTuple locTuple = deriveLocationTuple(md, rhs); + mapLocationPathToMayWrittenSet.put(locTuple, null, lhs); + addMayWrittenSet(md, locTuple, lhs); - while (!flatNodesToVisit.isEmpty()) { - FlatNode fn = flatNodesToVisit.iterator().next(); - flatNodesToVisit.remove(fn); + } - String label = (String) state.fn2labelMap.get(fn); - if (label != null) { + if (mapDescriptorToLocationStrPath.containsKey(rhs)) { + mapDescriptorToLocationStrPath.put(lhs, mapDescriptorToLocationStrPath.get(rhs)); + } else { + if (rhs.getType().getExtension() instanceof SSJavaType) { + NTuple locTuple = + ((SSJavaType) rhs.getType().getExtension()).getCompLoc().getTuple(); + mapDescriptorToLocationStrPath.put(lhs, locTuple); + } + } + + } + } + 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(); + rhs = fsen.getSrc(); + TypeDescriptor td = lhs.getType().dereference(); + fld = getArrayField(td); + } + + Location fieldLocation = (Location) fld.getType().getExtension(); + if (ssjava.isSharedLocation(fieldLocation)) { + addSharedLocDescriptor(fieldLocation, fld); + + System.out.println("FIELD WRITE FN=" + fn); + NTuple locTuple = deriveLocationTuple(md, lhs); + locTuple.addAll(deriveLocationTuple(md, fld)); + System.out.println("LOC TUPLE=" + locTuple); + + // mapLocationPathToMayWrittenSet.put(locTuple, null, fld); + addMayWrittenSet(md, locTuple, fld); + } + + } + break; + + case FKind.FlatElementNode: + case FKind.FlatFieldNode: { + + // x=y.f; + + 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.isFinal()) { + // if field is final no need to check + break; + } + + NTuple locTuple = deriveLocationTuple(md, rhs); + locTuple.addAll(deriveLocationTuple(md, fld)); + mapDescriptorToLocationStrPath.put(lhs, locTuple); + + } + break; + + case FKind.FlatCall: { + + // System.out.println("###FLATCALL=" + fn); + FlatCall fc = (FlatCall) fn; + bindLocationPathCallerArgWithCalleeParam(md, fc); + + } + break; + + } + } + + private void addMayWrittenSet(MethodDescriptor md, NTuple locTuple, Descriptor d) { + + MultiSourceMap map = mapMethodToSharedWriteMapping.get(md); + if (map == null) { + map = new MultiSourceMap(); + mapMethodToSharedWriteMapping.put(md, map); + } + + Set writeSet = map.get(locTuple); + if (writeSet == null) { + writeSet = new HashSet(); + map.put(locTuple, writeSet); + } + writeSet.add(d); + + System.out.println("ADD WRITE DESC=" + d + " TO locTuple=" + locTuple); + } + + private void bindLocationPathCallerArgWithCalleeParam(MethodDescriptor mdCaller, FlatCall fc) { + + 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); + mapLocationPathToMayWrittenSet.put(argLocationPath, null, + argHeapPath.get(argHeapPath.size() - 1)); + + } else { + + // 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> mapArgIdx2CallerAgLocationStrPath = + new Hashtable>(); + + // arg idx is starting from 'this' arg + if (fc.getThis() != null) { + NTuple thisLocationPath = deriveLocationTuple(mdCaller, fc.getThis()); + mapArgIdx2CallerAgLocationStrPath.put(Integer.valueOf(0), thisLocationPath); + } + + Hashtable> mapParamIdx2WriteSet = + new Hashtable>(); + + for (int i = 0; i < fc.numArgs() + 1; i++) { + mapParamIdx2WriteSet.put(Integer.valueOf(i), new HashSet()); + } + + for (int i = 0; i < fc.numArgs(); i++) { + TempDescriptor arg = fc.getArg(i); + NTuple argLocationPath = deriveLocationTuple(mdCaller, arg); + mapArgIdx2CallerAgLocationStrPath.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 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); + } + + Set keySet = mapArgIdx2CallerAgLocationStrPath.keySet(); + for (Iterator iterator2 = keySet.iterator(); iterator2.hasNext();) { + Integer idx = (Integer) iterator2.next(); + NTuple callerArgLocationStrPath = mapArgIdx2CallerAgLocationStrPath.get(idx); + + TempDescriptor calleeParam = mapParamIdx2ParamTempDesc.get(idx); + NTuple calleeLocationPath = deriveLocationTuple(mdCallee, calleeParam); + + // System.out.println("#createNewMappingOfMayWrittenSet callee=" + + // callee + // + " callerArgLocationStrPath=" + callerArgLocationStrPath + + // "calleeLocationPath=" + // + calleeLocationPath + " idx=" + idx + " writeset=" + + // mapParamIdx2WriteSet.get(idx)); + createNewMappingOfMayWrittenSet(callee, callerArgLocationStrPath, calleeLocationPath, + mapParamIdx2WriteSet.get(idx)); - if (label.equals(ssjava.SSJAVA)) { - ssjavaLoopEntrance = fn; - break; } + } - for (int i = 0; i < fn.numNext(); i++) { - FlatNode nn = fn.getNext(i); - flatNodesToVisit.add(nn); + } + + } + + private void createNewMappingOfMayWrittenSet(MethodDescriptor callee, + NTuple callerPath, NTuple calleeParamPath, Set writeSet) { + + // 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 mapping = mapMethodToSharedWriteMapping.get(callee); + + if (mapping == null) { + return; + } + + Hashtable, Set> paramMapping = + mapping.getMappingByStartedWith(calleeParamPath); + + Set> calleeKeySet = mapping.keySet(); + for (Iterator iterator = calleeKeySet.iterator(); iterator.hasNext();) { + NTuple calleeKey = (NTuple) iterator.next(); + Set calleeMayWriteSet = paramMapping.get(calleeKey); + + if (calleeMayWriteSet != null) { + writeSet.addAll(calleeMayWriteSet); + + NTuple newKey = new NTuple(); + newKey.addAll(callerPath); + // 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)); + } + + System.out.println("calleeParamPath=" + calleeParamPath + " newKey=" + newKey + + " maywriteSet=" + writeSet); + mapLocationPathToMayWrittenSet.put(calleeKey, newKey, writeSet); } + } - 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 void addSharedLocDescriptor(Location sharedLoc, Descriptor desc) { + + Set descSet = mapSharedLocationToCoverSet.get(sharedLoc); + if (descSet == null) { + descSet = new HashSet(); + mapSharedLocationToCoverSet.put(sharedLoc, descSet); + } + + descSet.add(desc); + + } + + private boolean hasReadingEffectOnSharedLocation(MethodDescriptor md, NTuple hp, + Location loc, Descriptor d) { + + ReadSummary summary = mapMethodDescriptorToReadSummary.get(md); + + if (summary != null) { + Hashtable> map = summary.get(hp); + if (map != null) { + Set descSec = map.get(loc); + if (descSec != null) { + return descSec.contains(d); + } } } + return false; - assert ssjavaLoop != null; + } + + private Location getLocation(Descriptor d) { + + System.out.println("GETLOCATION d=" + d + " d=" + d.getClass()); + + 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; + + TypeExtension te = td.getType().getExtension(); + if (te != null) { + if (te instanceof SSJavaType) { + SSJavaType ssType = (SSJavaType) te; + CompositeLocation comp = ssType.getCompLoc(); + return comp.get(comp.getSize() - 1); + } else { + return (Location) te; + } + } + } + + return mapDescToLocation.get(d); + } + + private void writeLocation(MethodDescriptor md, ClearingSummary curr, NTuple hp, + Location loc, Descriptor d) { + + SharedStatus state = getState(curr, hp); + if (loc != null && hasReadingEffectOnSharedLocation(md, hp, loc, d)) { + // 1. add field x to the clearing set + + state.addVar(loc, d); + + // 3. if the set v contains all of variables belonging to the shared + // location, set flag to true + if (isOverWrittenAllDescsOfSharedLoc(md, hp, loc, state.getVarSet(loc))) { + state.updateFlag(loc, true); + } + } + state.setWriteEffect(loc); + + } + + private boolean isOverWrittenAllDescsOfSharedLoc(MethodDescriptor md, NTuple hp, + Location loc, Set writtenSet) { + + ReadSummary summary = mapMethodDescriptorToReadSummary.get(md); + + if (summary != null) { + Hashtable> map = summary.get(hp); + if (map != null) { + Set descSet = map.get(loc); + if (descSet != null) { + return writtenSet.containsAll(descSet); + } + } + } + return false; + } - writtenAnalysis_analyzeLoop(); + private void readLocation(MethodDescriptor md, ClearingSummary curr, NTuple hp, + Location loc, Descriptor d) { + // remove reading var x from written set + if (loc != null && hasReadingEffectOnSharedLocation(md, hp, loc, d)) { + SharedStatus state = getState(curr, hp); + state.removeVar(loc, d); + } + } + private SharedStatus getState(ClearingSummary curr, NTuple hp) { + SharedStatus state = curr.get(hp); + if (state == null) { + state = new SharedStatus(); + curr.put(hp, state); + } + return state; } - 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(); - 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, ssjavaLoopEntrance); // 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); @@ -612,56 +1587,87 @@ 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); } + } + // System.out.println("EVENT LOOP ENTRY=" + curr); + } 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 (!lhs.getSymbol().startsWith("neverused")) { + NTuple rhsHeapPath = computePath(rhs); + if (!rhs.getType().isImmutable()) { + mapHeapPath.put(lhs, rhsHeapPath); + } else { + // write(lhs) + // NTuple lhsHeapPath = computePath(lhs); + NTuple path = new NTuple(); + path.add(lhs); - case FKind.FlatLiteralNode: { - FlatLiteralNode fln = (FlatLiteralNode) fn; - lhs = fln.getDst(); + // System.out.println("WRITE VARIABLE=" + path + " from=" + lhs); - // write(lhs) - NTuple lhsHeapPath = computePath(lhs); - removeHeapPath(curr, lhsHeapPath); + computeKILLSetForWrite(curr, path, readWriteKillSet); + computeGENSetForWrite(path, readWriteGenSet); + + // System.out.println("#VARIABLE WRITE:" + fn); + // System.out.println("#KILLSET=" + KILLSet); + // System.out.println("#GENSet=" + GENSet); + + } + } } break; @@ -669,22 +1675,33 @@ public class DefinitelyWrittenCheck { case FKind.FlatFieldNode: case FKind.FlatElementNode: { - FlatFieldNode ffn = (FlatFieldNode) fn; - lhs = ffn.getDst(); - rhs = ffn.getSrc(); - fld = ffn.getField(); + 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); + } // read field NTuple srcHeapPath = mapHeapPath.get(rhs); - NTuple fldHeapPath = new NTuple(srcHeapPath.getList()); - fldHeapPath.add(fld); - - if (fld.getType().isImmutable()) { - readValue(fn, fldHeapPath, curr); + 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); - // propagate rhs's heap path to the lhs - mapHeapPath.put(lhs, fldHeapPath); + Set writeAgeSet = curr.get(fldHeapPath); + checkWriteAgeSet(writeAgeSet, fldHeapPath, fn); } break; @@ -692,57 +1709,140 @@ public class DefinitelyWrittenCheck { case FKind.FlatSetFieldNode: case FKind.FlatSetElementNode: { - FlatSetFieldNode fsfn = (FlatSetFieldNode) fn; - lhs = fsfn.getDst(); - fld = fsfn.getField(); + if (fn.kind() == FKind.FlatSetFieldNode) { + FlatSetFieldNode fsfn = (FlatSetFieldNode) fn; + lhs = fsfn.getDst(); + fld = fsfn.getField(); + } else { + FlatSetElementNode fsen = (FlatSetElementNode) fn; + lhs = fsen.getDst(); + rhs = fsen.getSrc(); + TypeDescriptor td = lhs.getType().dereference(); + fld = getArrayField(td); + } // write(field) NTuple lhsHeapPath = computePath(lhs); NTuple fldHeapPath = new NTuple(lhsHeapPath.getList()); fldHeapPath.add(fld); - removeHeapPath(curr, fldHeapPath); + + computeKILLSetForWrite(curr, fldHeapPath, readWriteKillSet); + computeGENSetForWrite(fldHeapPath, readWriteGenSet); + + // System.out.println("FIELD WRITE:" + fn); + // System.out.println("KILLSET=" + KILLSet); + // System.out.println("GENSet=" + GENSet); } break; case FKind.FlatCall: { FlatCall fc = (FlatCall) fn; - 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); - } + + generateKILLSetForFlatCall(fc, curr, readWriteKillSet); + generateGENSetForFlatCall(fc, readWriteGenSet); + + // System.out.println("FLATCALL:" + fn); + // System.out.println("KILLSET=" + KILLSet); + // System.out.println("GENSet=" + GENSet); + + } + break; + + } + + computeNewMapping(curr, readWriteKillSet, readWriteGenSet); + // System.out.println("#######" + curr); + + } + + } + + 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) { + 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, + Hashtable, Set> GENSet) { + + Set> boundMayWriteSet = mapFlatNodeToBoundMayWriteSet.get(fc); + + for (Iterator iterator = boundMayWriteSet.iterator(); iterator.hasNext();) { + NTuple key = (NTuple) iterator.next(); + // TODO: shared location + Set set = new HashSet(); + set.add(new WriteAge(0)); + GENSet.put(key, set); + } + + } + + private void generateKILLSetForFlatCall(FlatCall fc, + Hashtable, Set> curr, + Hashtable, Set> KILLSet) { + + Set> boundMustWriteSet = mapFlatNodeToBoundMustWriteSet.get(fc); + + for (Iterator iterator = boundMustWriteSet.iterator(); iterator.hasNext();) { + NTuple key = (NTuple) iterator.next(); + // TODO: shared location + if (curr.get(key) != null) { + KILLSet.put(key, curr.get(key)); + } + } + + } + + private void computeNewMapping(SharedLocMappingSet curr, SharedLocMappingSet KILLSet, + SharedLocMappingSet GENSet) { + curr.kill(KILLSet); + curr.add(GENSet); + } - // 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); - } - } - break; + 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(); + curr.put(key, GENSet.get(key)); } } + 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 readValue(FlatNode fn, NTuple hp, Hashtable, Hashtable> curr) { Hashtable gen = curr.get(hp); @@ -759,8 +1859,8 @@ public class DefinitelyWrittenCheck { } - private void removeHeapPath(Hashtable, Hashtable> curr, - NTuple hp) { + 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 @@ -770,40 +1870,142 @@ 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(); + 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); + calleeIntersectBoundMustWriteSet.add(argHeapPath); + calleeUnionBoundMayWriteSet.add(argHeapPath); + } else { + 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); + } + + for (int i = 0; i < fc.numArgs(); i++) { + TempDescriptor arg = fc.getArg(i); + NTuple argHeapPath = computePath(arg); + mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(i + 1), argHeapPath); + } + + 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 + + Set> calleeReadSet = mapFlatMethodToReadSet.get(calleeFlatMethod); + if (calleeReadSet == null) { + calleeReadSet = new HashSet>(); + mapFlatMethodToReadSet.put(calleeFlatMethod, calleeReadSet); + } + + Set> calleeMustWriteSet = + mapFlatMethodToMustWriteSet.get(calleeFlatMethod); + + if (calleeMustWriteSet == null) { + calleeMustWriteSet = new HashSet>(); + mapFlatMethodToMustWriteSet.put(calleeFlatMethod, calleeMustWriteSet); + } + + Set> calleeMayWriteSet = + mapFlatMethodToMayWriteSet.get(calleeFlatMethod); + + if (calleeMayWriteSet == null) { + calleeMayWriteSet = new HashSet>(); + mapFlatMethodToMayWriteSet.put(calleeFlatMethod, calleeMayWriteSet); + } + + 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); + } + + Set> calleeBoundReadSet = + bindSet(calleeReadSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath); + // union of the current read set and the current callee's + // read set + calleeUnionBoundReadSet.addAll(calleeBoundReadSet); + + Set> calleeBoundMustWriteSet = + bindSet(calleeMustWriteSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath); + // intersection of the current overwrite set and the current + // callee's + // overwrite set + merge(calleeIntersectBoundMustWriteSet, calleeBoundMustWriteSet); + + Set> boundWriteSetFromCallee = + bindSet(calleeMayWriteSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath); + calleeUnionBoundMayWriteSet.addAll(boundWriteSetFromCallee); + } + + } + + } + + private void bindHeapPathCallerArgWithCaleeParamForSharedLoc(FlatCall fc) { + // compute all possible callee set + // transform all DELETE set from the any possible + // callees to the caller + calleeUnionBoundDeleteSet.clear(); + calleeIntersectBoundSharedSet.clear(); MethodDescriptor mdCallee = fc.getMethod(); - FlatMethod fmCallee = state.getMethodFlat(mdCallee); Set setPossibleCallees = new HashSet(); - TypeDescriptor typeDesc = fc.getThis().getType(); - setPossibleCallees.addAll(callGraph.getMethods(mdCallee, typeDesc)); + 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 - 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 (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); + mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(0), thisHeapPath); + } for (int i = 0; i < fc.numArgs(); i++) { TempDescriptor arg = fc.getArg(i); @@ -817,102 +2019,168 @@ public class DefinitelyWrittenCheck { // binding caller's args and callee's params - Set> calleeReadSet = mapFlatMethodToRead.get(calleeFlatMethod); + Set> calleeReadSet = mapFlatMethodToDeleteSet.get(calleeFlatMethod); if (calleeReadSet == null) { calleeReadSet = new HashSet>(); - mapFlatMethodToRead.put(calleeFlatMethod, calleeReadSet); - } - Set> calleeOverWriteSet = mapFlatMethodToOverWrite.get(calleeFlatMethod); - if (calleeOverWriteSet == null) { - calleeOverWriteSet = new HashSet>(); - mapFlatMethodToOverWrite.put(calleeFlatMethod, calleeOverWriteSet); + mapFlatMethodToDeleteSet.put(calleeFlatMethod, calleeReadSet); } 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), param); + mapParamIdx2ParamTempDesc.put(Integer.valueOf(i + offset), param); } - Set> calleeBoundReadSet = + Set> calleeBoundDeleteSet = bindSet(calleeReadSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath); // union of the current read set and the current callee's // read set - calleeUnionBoundReadSet.addAll(calleeBoundReadSet); - Set> calleeBoundWriteSet = - bindSet(calleeOverWriteSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath); - // intersection of the current overwrite set and the current - // callee's - // overwrite set - merge(calleeIntersectBoundOverWriteSet, calleeBoundWriteSet); + calleeUnionBoundDeleteSet.addAll(calleeBoundDeleteSet); + + SharedLocMappingSet calleeSharedLocMap = + mapFlatMethodToSharedLocMappingSet.get(calleeFlatMethod); + + Set> calleeHeapPathKeySet = calleeSharedLocMap.getHeapPathKeySet(); + + for (Iterator iterator2 = calleeHeapPathKeySet.iterator(); iterator2.hasNext();) { + NTuple calleeHeapPathKey = (NTuple) iterator2.next(); + + NTuple calleeBoundHeapPathKey = + bind(calleeHeapPathKey, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath); + + Set calleeLocSet = calleeSharedLocMap.getLocationKeySet(calleeHeapPathKey); + + for (Iterator iterator3 = calleeLocSet.iterator(); iterator3.hasNext();) { + Location calleeLocKey = (Location) iterator3.next(); + Set calleeWriteSet = + calleeSharedLocMap.getWriteSet(calleeHeapPathKey, calleeLocKey); + + calleeIntersectBoundSharedSet.intersectWriteSet(calleeBoundHeapPathKey, calleeLocKey, + calleeWriteSet); + + } + + } + } } + private NTuple bind(NTuple calleeHeapPathKey, + Hashtable mapParamIdx2ParamTempDesc, + Hashtable> mapCallerArgIdx2HeapPath) { + + Set keySet = mapCallerArgIdx2HeapPath.keySet(); + for (Iterator iterator = keySet.iterator(); iterator.hasNext();) { + Integer idx = (Integer) iterator.next(); + NTuple callerArgHeapPath = mapCallerArgIdx2HeapPath.get(idx); + TempDescriptor calleeParam = mapParamIdx2ParamTempDesc.get(idx); + if (calleeHeapPathKey.startsWith(calleeParam)) { + NTuple boundElement = combine(callerArgHeapPath, calleeHeapPathKey); + return boundElement; + } + } + return null; + } + private void checkFlag(boolean booleanValue, FlatNode fn, NTuple hp) { if (booleanValue) { - throw new Error( - "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()); + // the definitely written analysis only takes care about locations that + // are written to inside of the SSJava loop + for (Iterator iterator = calleeUnionBoundMayWriteSet.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 merge(Hashtable, Hashtable> curr, - Hashtable, Hashtable> in) { + private void initialize() { + // First, identify ssjava loop entrace - Set> inKeySet = in.keySet(); - for (Iterator iterator = inKeySet.iterator(); iterator.hasNext();) { - NTuple inKey = (NTuple) iterator.next(); - Hashtable inPair = in.get(inKey); + // no need to analyze method having ssjava loop + methodContainingSSJavaLoop = ssjava.getMethodContainingSSJavaLoop(); + + FlatMethod fm = state.getMethodFlat(methodContainingSSJavaLoop); + Set flatNodesToVisit = new HashSet(); + flatNodesToVisit.add(fm); - Set pairKeySet = inPair.keySet(); - for (Iterator iterator2 = pairKeySet.iterator(); iterator2.hasNext();) { - FlatNode pairKey = (FlatNode) iterator2.next(); - Boolean inFlag = inPair.get(pairKey); + LoopFinder loopFinder = new LoopFinder(fm); - Hashtable currPair = curr.get(inKey); - if (currPair == null) { - currPair = new Hashtable(); - curr.put(inKey, currPair); - } + while (!flatNodesToVisit.isEmpty()) { + FlatNode fn = flatNodesToVisit.iterator().next(); + flatNodesToVisit.remove(fn); - Boolean currFlag = currPair.get(pairKey); - // by default, flag is set by false - if (currFlag == null) { - currFlag = Boolean.FALSE; + String label = (String) state.fn2labelMap.get(fn); + if (label != null) { + + if (label.equals(ssjava.SSJAVA)) { + ssjavaLoopEntrance = fn; + break; } - currFlag = Boolean.valueOf(inFlag.booleanValue() | currFlag.booleanValue()); - currPair.put(pairKey, currFlag); } + for (int i = 0; i < fn.numNext(); i++) { + FlatNode nn = fn.getNext(i); + flatNodesToVisit.add(nn); + } + } + + 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; + } } - } + assert ssjavaLoop != null; - private void methodReadOverWriteAnalysis() { - // perform method READ/OVERWRITE analysis + 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); + } - LinkedList sortedDescriptors = topologicalSort(methodDescriptorsToAnalyze); - - // no need to analyze method having ssjava loop - methodContainingSSJavaLoop = sortedDescriptors.removeFirst(); + private void methodReadWriteSetAnalysis() { + // perform method READ/OVERWRITE analysis + LinkedList descriptorListToAnalyze = + (LinkedList) sortedDescriptors.clone(); // current descriptors to visit in fixed-point interprocedural analysis, // prioritized by // dependency in the call graph - Stack methodDescriptorsToVisitStack = new Stack(); + methodDescriptorsToVisitStack.clear(); + + descriptorListToAnalyze.removeFirst(); Set methodDescriptorToVistSet = new HashSet(); - methodDescriptorToVistSet.addAll(sortedDescriptors); + methodDescriptorToVistSet.addAll(descriptorListToAnalyze); - while (!sortedDescriptors.isEmpty()) { - MethodDescriptor md = sortedDescriptors.removeFirst(); + while (!descriptorListToAnalyze.isEmpty()) { + MethodDescriptor md = descriptorListToAnalyze.removeFirst(); methodDescriptorsToVisitStack.add(md); } @@ -923,16 +2191,28 @@ public class DefinitelyWrittenCheck { FlatMethod fm = state.getMethodFlat(md); Set> readSet = new HashSet>(); - Set> overWriteSet = new HashSet>(); - - methodReadOverWrite_analyzeMethod(fm, readSet, overWriteSet); - - Set> prevRead = mapFlatMethodToRead.get(fm); - Set> prevOverWrite = mapFlatMethodToOverWrite.get(fm); - - if (!(readSet.equals(prevRead) && overWriteSet.equals(prevOverWrite))) { - mapFlatMethodToRead.put(fm, readSet); - mapFlatMethodToOverWrite.put(fm, overWriteSet); + Set> mustWriteSet = new HashSet>(); + Set> mayWriteSet = new HashSet>(); + SharedLocMappingSet sharedLocMapping = new SharedLocMappingSet(); + Set> deleteSet = new HashSet>(); + + methodReadWriteSet_analyzeMethod(fm, readSet, mustWriteSet, mayWriteSet, sharedLocMapping, + deleteSet); + + Set> prevRead = mapFlatMethodToReadSet.get(fm); + Set> prevMustWrite = mapFlatMethodToMustWriteSet.get(fm); + Set> prevMayWrite = mapFlatMethodToMayWriteSet.get(fm); + SharedLocMappingSet prevSharedLocMapping = mapFlatMethodToSharedLocMappingSet.get(fm); + Set> prevDeleteSet = mapFlatMethodToDeleteSet.get(fm); + + if (!(readSet.equals(prevRead) && mustWriteSet.equals(prevMustWrite) + && mayWriteSet.equals(prevMayWrite) && sharedLocMapping.equals(prevSharedLocMapping) && deleteSet + .equals(prevDeleteSet))) { + mapFlatMethodToReadSet.put(fm, readSet); + mapFlatMethodToMustWriteSet.put(fm, mustWriteSet); + mapFlatMethodToMayWriteSet.put(fm, mayWriteSet); + mapFlatMethodToSharedLocMappingSet.put(fm, sharedLocMapping); + mapFlatMethodToDeleteSet.put(fm, deleteSet); // results for callee changed, so enqueue dependents caller for // further @@ -951,40 +2231,92 @@ public class DefinitelyWrittenCheck { } + methodReadWriteSetAnalysisToEventLoopBody(); + + } + + private void methodReadWriteSet_analyzeMethod(FlatMethod fm, Set> readSet, + Set> mustWriteSet, Set> mayWriteSet, + SharedLocMappingSet sharedLocMapping, Set> deleteSet) { + if (state.SSJAVADEBUG) { + System.out.println("SSJAVA: Definitely written Analyzing: " + fm); + } + + methodReadWriteSet_analyzeBody(fm, readSet, mustWriteSet, mayWriteSet, sharedLocMapping, + deleteSet, false); + } - private void methodReadOverWrite_analyzeMethod(FlatMethod fm, Set> readSet, - Set> overWriteSet) { + 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>(); + SharedLocMappingSet sharedLocMapping = new SharedLocMappingSet(); + Set> deleteSet = new HashSet>(); + + mapFlatMethodToReadSet.put(flatMethodContainingSSJavaLoop, readSet); + mapFlatMethodToMustWriteSet.put(flatMethodContainingSSJavaLoop, mustWriteSet); + mapFlatMethodToMayWriteSet.put(flatMethodContainingSSJavaLoop, mayWriteSet); + mapFlatMethodToSharedLocMappingSet.put(flatMethodContainingSSJavaLoop, sharedLocMapping); + mapFlatMethodToDeleteSet.put(flatMethodContainingSSJavaLoop, deleteSet); + + methodReadWriteSet_analyzeBody(ssjavaLoopEntrance, readSet, mustWriteSet, mayWriteSet, + sharedLocMapping, deleteSet, true); + + } + + private void methodReadWriteSet_analyzeBody(FlatNode startNode, Set> readSet, + Set> mustWriteSet, Set> mayWriteSet, + SharedLocMappingSet sharedLocMapping, Set> deleteSet, + 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>(); + SharedLocMappingSet currSharedLocMapping = new SharedLocMappingSet(); + 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); + SharedLocMappingSet inSharedLoc = mapFlatNodeToSharedLocMapping.get(prevFn); if (in != null) { - merge(curr, in); + merge(currMustWriteSet, in); + merge(currSharedLocMapping, inSharedLoc); } } - methodReadOverWrite_nodeActions(fn, curr, readSet, overWriteSet); + methodReadWriteSet_nodeActions(fn, currMustWriteSet, readSet, mustWriteSet, mayWriteSet, + currSharedLocMapping, sharedLocMapping, deleteSet, isEventLoopBody); + + SharedLocMappingSet prevSharedLocSet = mapFlatNodeToSharedLocMapping.get(fn); + Set> mustSetPrev = mapFlatNodeToMustWriteSet.get(fn); - Set> writtenSetPrev = mapFlatNodeToWrittenSet.get(fn); - if (!curr.equals(writtenSetPrev)) { - mapFlatNodeToWrittenSet.put(fn, curr); + if ((!currMustWriteSet.equals(mustSetPrev)) + || (!currSharedLocMapping.equals(prevSharedLocSet))) { + mapFlatNodeToMustWriteSet.put(fn, currMustWriteSet); + mapFlatNodeToSharedLocMapping.put(fn, currSharedLocMapping); for (int i = 0; i < fn.numNext(); i++) { FlatNode nn = fn.getNext(i); - flatNodesToVisit.add(nn); + if ((!isEventLoopBody) || loopIncElements.contains(nn)) { + flatNodesToVisit.add(nn); + } + } } @@ -992,8 +2324,15 @@ public class DefinitelyWrittenCheck { } - private void methodReadOverWrite_nodeActions(FlatNode fn, Set> writtenSet, - Set> readSet, Set> overWriteSet) { + private void methodReadWriteSet_nodeActions(FlatNode fn, + Set> currMustWriteSet, Set> readSet, + Set> mustWriteSet, Set> mayWriteSet, + SharedLocMappingSet currSharedLocMapping, SharedLocMappingSet sharedLocMapping, + Set> deleteSet, boolean isEventLoopBody) { + + SharedLocMappingSet killSetSharedLoc = new SharedLocMappingSet(); + SharedLocMappingSet genSetSharedLoc = new SharedLocMappingSet(); + TempDescriptor lhs; TempDescriptor rhs; FieldDescriptor fld; @@ -1023,21 +2362,80 @@ public class DefinitelyWrittenCheck { NTuple rhsHeapPath = mapHeapPath.get(rhs); if (rhsHeapPath != null) { mapHeapPath.put(lhs, mapHeapPath.get(rhs)); + } else { + NTuple heapPath = new NTuple(); + heapPath.add(rhs); + mapHeapPath.put(lhs, heapPath); + } + + // 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); + + System.out.println("VAR WRITE:" + fn); + System.out.println("LHS TYPE EXTENSION=" + lhs.getType().getExtension()); + System.out.println("RHS TYPE EXTENSION=" + rhs.getType().getExtension() + + " HEAPPATH=" + rhsHeapPath); + + // computing gen/kill set + computeKILLSetForWrite(currSharedLocMapping, heapPath, dstLoc, killSetSharedLoc); + if (!dstLoc.equals(rhsLoc)) { + computeGENSetForHigherWrite(currSharedLocMapping, heapPath, dstLoc, lhs, + genSetSharedLoc); + deleteSet.remove(writeHeapPath); + } else { + computeGENSetForSharedWrite(currSharedLocMapping, heapPath, dstLoc, lhs, + genSetSharedLoc); + deleteSet.add(writeHeapPath); + } + + } + } } } } break; - case FKind.FlatFieldNode: - case FKind.FlatElementNode: { + case FKind.FlatElementNode: + case FKind.FlatFieldNode: { + + // x=y.f; - // y=x.f; + 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); + } - FlatFieldNode ffn = (FlatFieldNode) fn; - lhs = ffn.getDst(); - rhs = ffn.getSrc(); - fld = ffn.getField(); + if (fld.isFinal()) { + // if field is final no need to check + break; + } // set up heap path NTuple srcHeapPath = mapHeapPath.get(rhs); @@ -1052,13 +2450,12 @@ public class DefinitelyWrittenCheck { // 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); } } - // need to kill hp(x.f) from WT - writtenSet.remove(readingHeapPath); + // no need to kill hp(x.f) from WT } } @@ -1068,23 +2465,63 @@ public class DefinitelyWrittenCheck { case FKind.FlatSetElementNode: { // x.f=y; - FlatSetFieldNode fsfn = (FlatSetFieldNode) fn; - lhs = fsfn.getDst(); - fld = fsfn.getField(); - rhs = fsfn.getSrc(); + + if (fn.kind() == FKind.FlatSetFieldNode) { + SharedLocMappingSet killSet = new SharedLocMappingSet(); + SharedLocMappingSet genSet = new SharedLocMappingSet(); + FlatSetFieldNode fsfn = (FlatSetFieldNode) fn; + lhs = fsfn.getDst(); + fld = fsfn.getField(); + rhs = fsfn.getSrc(); + } else { + FlatSetElementNode fsen = (FlatSetElementNode) fn; + lhs = fsen.getDst(); + rhs = fsen.getSrc(); + TypeDescriptor td = lhs.getType().dereference(); + fld = getArrayField(td); + } // 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()); + fldHeapPath.add(fld); + mapHeapPath.put(fld, fldHeapPath); // write(x.f) // need to add hp(y) to WT - writtenSet.add(newHeapPath); + currMustWriteSet.add(fldHeapPath); + mayWriteSet.add(fldHeapPath); + + // shared loc extension + Location srcLoc = getLocation(rhs); + Location fieldLoc = (Location) fld.getType().getExtension(); + if (ssjava.isSharedLocation(fieldLoc)) { + // only care the case that loc(f) is shared location + // write(field) + + computeKILLSetForWrite(currSharedLocMapping, lhsHeapPath, fieldLoc, killSetSharedLoc); + if (!fieldLoc.equals(srcLoc)) { + computeGENSetForHigherWrite(currSharedLocMapping, lhsHeapPath, fieldLoc, fld, + genSetSharedLoc); + deleteSet.remove(fldHeapPath); + } else { + computeGENSetForSharedWrite(currSharedLocMapping, lhsHeapPath, fieldLoc, fld, + genSetSharedLoc); + deleteSet.add(fldHeapPath); + } + } + + System.out.println("################"); + System.out.println("FIELD WRITE:" + fn); + System.out.println("fieldLoc=" + fieldLoc + " srcLoc=" + srcLoc); + System.out.println("KILLSET=" + killSetSharedLoc); + System.out.println("GENSet=" + genSetSharedLoc); + System.out.println("DELETESET=" + deleteSet); + } } @@ -1094,77 +2531,207 @@ public class DefinitelyWrittenCheck { FlatCall fc = (FlatCall) fn; - bindHeapPathCallerArgWithCaleeParam(fc); + bindHeapPathCallerArgWithCalleeParam(fc); + + mapFlatNodeToBoundReadSet.put(fn, calleeUnionBoundReadSet); + mapFlatNodeToBoundMustWriteSet.put(fn, calleeIntersectBoundMustWriteSet); + mapFlatNodeToBoundMayWriteSet.put(fn, calleeUnionBoundMayWriteSet); // 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); } } - writtenSet.removeAll(calleeUnionBoundReadSet); // 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(); + currMustWriteSet.add(write); + } + + // add heap path, which is an element of WRITE_BOUND set, to the + // caller's writeSet + for (Iterator iterator = calleeUnionBoundMayWriteSet.iterator(); iterator.hasNext();) { NTuple write = (NTuple) iterator.next(); - writtenSet.add(write); + mayWriteSet.add(write); } + // shared loc extension + bindHeapPathCallerArgWithCaleeParamForSharedLoc(fc); + + generateKILLSharedSetForFlatCall(currSharedLocMapping, killSetSharedLoc); + generateGENSharedSetForFlatCall(currSharedLocMapping, genSetSharedLoc); + + System.out.println("### Analyzing FC=" + fc); + System.out.println("### BOUNDSET=" + calleeIntersectBoundSharedSet); + System.out.println("### GEN=" + genSetSharedLoc); + System.out.println("### KILL=" + killSetSharedLoc); } break; case FKind.FlatExit: { // merge the current written set with OVERWRITE set - merge(overWriteSet, writtenSet); + merge(mustWriteSet, currMustWriteSet); + + // shared loc extension + merge(sharedLocMapping, currSharedLocMapping); } break; } + computeNewMapping(currSharedLocMapping, killSetSharedLoc, genSetSharedLoc); + } - private void mergeSharedAnaylsis(Hashtable, SharedLocState> curr, - Hashtable, SharedLocState> in) { + private void generateGENSharedSetForFlatCall(SharedLocMappingSet currSharedLocMapping, + SharedLocMappingSet genSetSharedLoc) { - Set> keySet = in.keySet(); - for (Iterator iterator = keySet.iterator(); iterator.hasNext();) { + Set> hpKeySet = calleeIntersectBoundSharedSet.getHeapPathKeySet(); + for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) { NTuple hpKey = (NTuple) iterator.next(); - SharedLocState inState = in.get(hpKey); + Set locKeySet = calleeIntersectBoundSharedSet.getLocationKeySet(hpKey); + for (Iterator iterator2 = locKeySet.iterator(); iterator2.hasNext();) { + Location locKey = (Location) iterator2.next(); + + Set calleeBoundWriteSet = + calleeIntersectBoundSharedSet.getWriteSet(hpKey, locKey); + System.out.println("calleeBoundWriteSet=" + calleeBoundWriteSet + " hp=" + hpKey + " loc=" + + locKey); + Set removeSet = computeRemoveSet(hpKey, locKey); + + Set currWriteSet = currSharedLocMapping.getWriteSet(hpKey, locKey); + + genSetSharedLoc.addWriteSet(hpKey, locKey, currWriteSet); + genSetSharedLoc.addWriteSet(hpKey, locKey, calleeBoundWriteSet); + genSetSharedLoc.removeWriteSet(hpKey, locKey, removeSet); - SharedLocState currState = curr.get(hpKey); - if (currState == null) { - currState = new SharedLocState(); - 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 = mapHeapPathLocation2Flag.get(flagKey); - if (current == null) { - current = new Boolean(true); + } + + public NTuple getPrefix(NTuple in) { + return in.subList(0, in.size() - 1); + } + + public NTuple getSuffix(NTuple in) { + return in.subList(in.size() - 1, in.size()); + } + + private Set computeRemoveSet(NTuple hpKey, Location locKey) { + Set removeSet = new HashSet(); + + for (Iterator iterator = calleeUnionBoundDeleteSet.iterator(); iterator.hasNext();) { + NTuple removeHeapPath = (NTuple) iterator.next(); + if (getPrefix(removeHeapPath).equals(hpKey)) { + removeSet.add(getSuffix(removeHeapPath).get(0)); + } + } + + return removeSet; + } + + private void generateKILLSharedSetForFlatCall(SharedLocMappingSet currSharedLocMapping, + SharedLocMappingSet killSetSharedLoc) { + + Set> hpKeySet = calleeIntersectBoundSharedSet.getHeapPathKeySet(); + for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) { + NTuple hpKey = (NTuple) iterator.next(); + Set locKeySet = calleeIntersectBoundSharedSet.getLocationKeySet(hpKey); + for (Iterator iterator2 = locKeySet.iterator(); iterator2.hasNext();) { + Location locKey = (Location) iterator2.next(); + Set currWriteSet = currSharedLocMapping.getWriteSet(hpKey, locKey); + killSetSharedLoc.addWriteSet(hpKey, locKey, currWriteSet); + } + } + } + + static public FieldDescriptor getArrayField(TypeDescriptor td) { + FieldDescriptor fd = mapTypeToArrayField.get(td); + if (fd == null) { + fd = + new FieldDescriptor(new Modifiers(Modifiers.PUBLIC), td, arrayElementFieldName, null, + false); + mapTypeToArrayField.put(td, fd); + } + 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)); } - boolean newInFlag = current.booleanValue() & inFlag; - mapHeapPathLocation2Flag.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); @@ -1205,7 +2772,6 @@ public class DefinitelyWrittenCheck { NTuple callerArgHeapPath = mapCallerArgIdx2HeapPath.get(idx); TempDescriptor calleeParam = mapParamIdx2ParamTempDesc.get(idx); - for (Iterator iterator2 = calleeSet.iterator(); iterator2.hasNext();) { NTuple element = (NTuple) iterator2.next(); if (element.startsWith(calleeParam)) { @@ -1251,16 +2817,13 @@ public class DefinitelyWrittenCheck { discovered.add(md); - // otherwise call graph guides DFS 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 @@ -1307,4 +2870,40 @@ public class DefinitelyWrittenCheck { } } + 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; + } + + private NTuple deriveLocationTuple(MethodDescriptor md, TempDescriptor td) { + + assert td.getType() != null; + + if (mapDescriptorToLocationStrPath.containsKey(td)) { + return mapDescriptorToLocationStrPath.get(td); + } else { + if (td.getSymbol().startsWith("this")) { + return deriveThisLocationTuple(md); + } else { + NTuple locTuple = + ((SSJavaType) td.getType().getExtension()).getCompLoc().getTuple(); + return locTuple; + } + } + + } + + private NTuple deriveLocationTuple(MethodDescriptor md, FieldDescriptor fld) { + + assert fld.getType() != null; + + Location fieldLoc = (Location) fld.getType().getExtension(); + NTuple locTuple = new NTuple(); + locTuple.add(fieldLoc); + return locTuple; + } + } \ No newline at end of file