From: yeom Date: Tue, 22 Nov 2011 19:15:28 +0000 (+0000) Subject: working on shared loc extension: need to keep additional mappings from shared loc... X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=d174e9afd47ee2b9fc78f590244e6f958843371c;p=IRC.git working on shared loc extension: need to keep additional mappings from shared loc composite location to a set of may written descriptors. --- diff --git a/Robust/src/Analysis/SSJava/DefinitelyWrittenCheck.java b/Robust/src/Analysis/SSJava/DefinitelyWrittenCheck.java index e9a2f42f..a5724874 100644 --- a/Robust/src/Analysis/SSJava/DefinitelyWrittenCheck.java +++ b/Robust/src/Analysis/SSJava/DefinitelyWrittenCheck.java @@ -57,6 +57,9 @@ public class DefinitelyWrittenCheck { // alias. private Hashtable> mapHeapPath; + // maps a temp descriptor to its composite location + private Hashtable> mapDescriptorToComposteLocation; + // 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>> mapFlatMethodToReadSet; @@ -65,6 +68,15 @@ public class DefinitelyWrittenCheck { // 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; @@ -117,8 +129,12 @@ public class DefinitelyWrittenCheck { // it is for setting clearance flag when all read set is overwritten private Hashtable mapMethodDescriptorToReadSummary; + private Hashtable mapFlatNodeToSharedLocMapping; + private Hashtable> mapSharedLocationToCoverSet; + private Hashtable, Set> mapSharedLocationTupleToMayWriteSet; + private LinkedList sortedDescriptors; private FlatNode ssjavaLoopEntrance; @@ -128,6 +144,8 @@ public class DefinitelyWrittenCheck { private Set> calleeUnionBoundReadSet; private Set> calleeIntersectBoundMustWriteSet; private Set> calleeUnionBoundMayWriteSet; + private Set> calleeUnionBoundDeleteSet; + private SharedLocMappingSet calleeIntersectBoundSharedSet; private Hashtable mapDescToLocation; @@ -142,6 +160,7 @@ public class DefinitelyWrittenCheck { this.mapFlatNodeToMustWriteSet = new Hashtable>>(); this.mapDescriptorToSetDependents = new Hashtable>(); this.mapHeapPath = new Hashtable>(); + this.mapDescriptorToComposteLocation = new Hashtable>(); this.mapFlatMethodToReadSet = new Hashtable>>(); this.mapFlatMethodToMustWriteSet = new Hashtable>>(); this.mapFlatMethodToMayWriteSet = new Hashtable>>(); @@ -167,18 +186,28 @@ public class DefinitelyWrittenCheck { 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.mapSharedLocationTupleToMayWriteSet = new Hashtable, Set>(); } public void definitelyWrittenCheck() { if (!ssjava.getAnnotationRequireSet().isEmpty()) { initialize(); - methodReadWriteSetAnalysis(); - methodReadWriteSetAnalysisToEventLoopBody(); - eventLoopAnalysis(); computeSharedCoverSet(); System.out.println("#"); - System.out.println(mapSharedLocationToCoverSet); + System.out.println(mapSharedLocationTupleToMayWriteSet); + + // methodReadWriteSetAnalysis(); + + // sharedLocAnalysis(); + + // eventLoopAnalysis(); + // XXXXXXX // methodReadWriteSetAnalysis(); // methodReadWriteSetAnalysisToEventLoopBody(); @@ -189,6 +218,317 @@ public class DefinitelyWrittenCheck { } } + private void sharedLocAnalysis() { + + // 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 + 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()) { + // start to analyze leaf node + MethodDescriptor md = methodDescriptorsToVisitStack.pop(); + FlatMethod fm = state.getMethodFlat(md); + + Set> deleteSet = new HashSet>(); + + sharedLoc_analyzeMethod(fm, deleteSet); + System.out.println("deleteSet result=" + deleteSet); + + Set> prevDeleteSet = mapFlatMethodToDeleteSet.get(fm); + + if (!deleteSet.equals(prevDeleteSet)) { + mapFlatMethodToDeleteSet.put(fm, deleteSet); + + // 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) + && methodDescriptorToVistSet.contains(methodNext)) { + methodDescriptorsToVisitStack.add(methodNext); + } + + } + + } + + } + + } + + private void sharedLoc_analyzeMethod(FlatMethod fm, Set> deleteSet) { + if (state.SSJAVADEBUG) { + 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(); + flatNodesToVisit.add(startNode); + + while (!flatNodesToVisit.isEmpty()) { + FlatNode fn = flatNodesToVisit.iterator().next(); + flatNodesToVisit.remove(fn); + + SharedLocMappingSet currSharedSet = new SharedLocMappingSet(); + + for (int i = 0; i < fn.numPrev(); i++) { + FlatNode prevFn = fn.getPrev(i); + SharedLocMappingSet in = mapFlatNodeToSharedLocMapping.get(prevFn); + if (in != null) { + merge(currSharedSet, in); + } + } + + 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 ((!isEventLoopBody) || loopIncElements.contains(nn)) { + flatNodesToVisit.add(nn); + } + + } + } + + } + + } + + 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: { + + if (isEventLoopBody) { + FlatOpNode fon = (FlatOpNode) fn; + lhs = fon.getDest(); + rhs = fon.getLeft(); + + if (!lhs.getSymbol().startsWith("neverused")) { + + if (rhs.getType().isImmutable()) { + NTuple rhsHeapPath = computePath(rhs); + + 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(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); + + } + } + } + + } + break; + + case FKind.FlatSetFieldNode: + case FKind.FlatSetElementNode: { + + 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); + } + + // 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); + + // 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; + + } + + // computeNewMapping(curr, readWriteKillSet, readWriteGenSet); + // System.out.println("#######" + curr); + + } + + private void computeKILLSetForWrite(SharedLocMappingSet curr, NTuple hp, + Location loc, SharedLocMappingSet killSet) { + + Set currWriteSet = curr.getWriteSet(hp, loc); + if (!currWriteSet.isEmpty()) { + killSet.addWriteSet(hp, loc, currWriteSet); + } + + } + + private void computeGENSetForHigherWrite(SharedLocMappingSet curr, NTuple hp, + Location loc, Descriptor desc, SharedLocMappingSet genSet) { + + Set genWriteSet = new HashSet(); + genWriteSet.addAll(curr.getWriteSet(hp, loc)); + genWriteSet.add(desc); + + genSet.addWriteSet(hp, loc, genWriteSet); + + } + + private void computeGENSetForSharedWrite(SharedLocMappingSet curr, NTuple hp, + Location loc, Descriptor desc, SharedLocMappingSet genSet) { + + 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 checkSharedLocationResult() { // mapping of method containing ssjava loop has the final result of @@ -454,71 +794,11 @@ public class DefinitelyWrittenCheck { } break; - case FKind.FlatFieldNode: - case FKind.FlatElementNode: { - - if (fn.kind() == FKind.FlatFieldNode) { - FlatFieldNode ffn = (FlatFieldNode) fn; - lhs = ffn.getDst(); - rhs = ffn.getSrc(); - fld = ffn.getField(); - } else { - FlatElementNode fen = (FlatElementNode) fn; - lhs = fen.getDst(); - rhs = fen.getSrc(); - TypeDescriptor td = rhs.getType().dereference(); - fld = getArrayField(td); - } - - // read field - NTuple srcHeapPath = mapHeapPath.get(rhs); - - if (srcHeapPath != null) { - // if lhs srcHeapPath is null, it means that it is not reachable from - // callee's parameters. so just ignore it - NTuple fldHeapPath = new NTuple(srcHeapPath.getList()); - - if (!fld.getType().isArray() && fld.getType().isImmutable()) { - Location loc; - if (fn.kind() == FKind.FlatElementNode) { - // array element read case - NTuple newHeapPath = new NTuple(); - for (int i = 0; i < fldHeapPath.size() - 1; i++) { - newHeapPath.add(fldHeapPath.get(i)); - } - - Descriptor desc = fldHeapPath.get(fldHeapPath.size() - 1); - if (desc instanceof FieldDescriptor) { - fld = (FieldDescriptor) desc; - fldHeapPath = newHeapPath; - loc = getLocation(fld); - readLocation(md, curr, fldHeapPath, loc, fld); - } - } else { - loc = getLocation(fld); - readLocation(md, curr, fldHeapPath, loc, fld); - } - } else { - - if (fn.kind() != FKind.FlatElementNode) { - // if it is multi dimensional array, do not need to add heap path - // because all accesses from the same array is represented by - // "_element_" - fldHeapPath.add(fld); - } - mapHeapPath.put(lhs, fldHeapPath); - } - - } - - // } - - } - break; - case FKind.FlatSetFieldNode: case FKind.FlatSetElementNode: { + // x.f=y + if (fn.kind() == FKind.FlatSetFieldNode) { FlatSetFieldNode fsfn = (FlatSetFieldNode) fn; lhs = fsfn.getDst(); @@ -536,6 +816,7 @@ public class DefinitelyWrittenCheck { 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); @@ -892,7 +1173,7 @@ public class DefinitelyWrittenCheck { case FKind.FlatOpNode: { FlatOpNode fon = (FlatOpNode) fn; - // for a normal assign node, need to propagate lhs's heap path to + // for a normal assign node, need to propagate lhs's location path to // rhs if (fon.getOp().getOp() == Operation.ASSIGN) { rhs = fon.getLeft(); @@ -900,15 +1181,23 @@ public class DefinitelyWrittenCheck { 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); - } - } + + System.out.println("FN=" + fn); + NTuple loc = deriveLocationTuple(md, rhs); + System.out.println("LOC TUPLE=" + loc); + + addDescriptorToSharedLocMayWriteSet(loc, lhs); + + // // 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); + // } + // } } } @@ -936,14 +1225,65 @@ public class DefinitelyWrittenCheck { 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); + addDescriptorToSharedLocMayWriteSet(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; + } + + System.out.println("FN=" + fn); + NTuple locTuple = deriveLocationTuple(md, rhs); + locTuple.addAll(deriveLocationTuple(md, fld)); + System.out.println("LOC TUPLE=" + locTuple); + mapDescriptorToComposteLocation.put(lhs, locTuple); + System.out.println("mapping " + lhs + " to " + locTuple); + } break; } } + private void addDescriptorToSharedLocMayWriteSet(NTuple locTuple, Descriptor d) { + + Set mayWriteSet = mapSharedLocationTupleToMayWriteSet.get(locTuple); + if (mayWriteSet == null) { + mayWriteSet = new HashSet(); + mapSharedLocationTupleToMayWriteSet.put(locTuple, mayWriteSet); + } + mayWriteSet.add(d); + + } + private void addSharedLocDescriptor(Location sharedLoc, Descriptor desc) { Set descSet = mapSharedLocationToCoverSet.get(sharedLoc); @@ -990,6 +1330,8 @@ public class DefinitelyWrittenCheck { 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) { @@ -1131,9 +1473,9 @@ public class DefinitelyWrittenCheck { private void eventLoopAnalysis_nodeAction(FlatNode fn, Hashtable, Set> curr, FlatNode loopEntrance) { - Hashtable, Set> KILLSet = + Hashtable, Set> readWriteKillSet = new Hashtable, Set>(); - Hashtable, Set> GENSet = + Hashtable, Set> readWriteGenSet = new Hashtable, Set>(); if (fn.equals(loopEntrance)) { @@ -1181,8 +1523,8 @@ public class DefinitelyWrittenCheck { // System.out.println("WRITE VARIABLE=" + path + " from=" + lhs); - computeKILLSetForWrite(curr, path, KILLSet); - computeGENSetForWrite(path, GENSet); + computeKILLSetForWrite(curr, path, readWriteKillSet); + computeGENSetForWrite(path, readWriteGenSet); // System.out.println("#VARIABLE WRITE:" + fn); // System.out.println("#KILLSET=" + KILLSet); @@ -1248,8 +1590,8 @@ public class DefinitelyWrittenCheck { NTuple fldHeapPath = new NTuple(lhsHeapPath.getList()); fldHeapPath.add(fld); - computeKILLSetForWrite(curr, fldHeapPath, KILLSet); - computeGENSetForWrite(fldHeapPath, GENSet); + computeKILLSetForWrite(curr, fldHeapPath, readWriteKillSet); + computeGENSetForWrite(fldHeapPath, readWriteGenSet); // System.out.println("FIELD WRITE:" + fn); // System.out.println("KILLSET=" + KILLSet); @@ -1261,8 +1603,8 @@ public class DefinitelyWrittenCheck { case FKind.FlatCall: { FlatCall fc = (FlatCall) fn; - generateKILLSetForFlatCall(fc, curr, KILLSet); - generateGENSetForFlatCall(fc, GENSet); + generateKILLSetForFlatCall(fc, curr, readWriteKillSet); + generateGENSetForFlatCall(fc, readWriteGenSet); // System.out.println("FLATCALL:" + fn); // System.out.println("KILLSET=" + KILLSet); @@ -1273,7 +1615,7 @@ public class DefinitelyWrittenCheck { } - computeNewMapping(curr, KILLSet, GENSet); + computeNewMapping(curr, readWriteKillSet, readWriteGenSet); // System.out.println("#######" + curr); } @@ -1327,6 +1669,12 @@ public class DefinitelyWrittenCheck { } + private void computeNewMapping(SharedLocMappingSet curr, SharedLocMappingSet KILLSet, + SharedLocMappingSet GENSet) { + curr.kill(KILLSet); + curr.add(GENSet); + } + private void computeNewMapping(Hashtable, Set> curr, Hashtable, Set> KILLSet, Hashtable, Set> GENSet) { @@ -1496,6 +1844,115 @@ public class DefinitelyWrittenCheck { } + 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(); + 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 = mapFlatMethodToDeleteSet.get(calleeFlatMethod); + if (calleeReadSet == null) { + calleeReadSet = new HashSet>(); + 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 + offset), param); + } + + Set> calleeBoundDeleteSet = + bindSet(calleeReadSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath); + // union of the current read set and the current callee's + // read set + 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) { // the definitely written analysis only takes care about locations that @@ -1600,18 +2057,26 @@ public class DefinitelyWrittenCheck { Set> readSet = new HashSet>(); Set> mustWriteSet = new HashSet>(); Set> mayWriteSet = new HashSet>(); + SharedLocMappingSet sharedLocMapping = new SharedLocMappingSet(); + Set> deleteSet = new HashSet>(); - methodReadWriteSet_analyzeMethod(fm, readSet, mustWriteSet, mayWriteSet); + 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))) { + 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 @@ -1630,15 +2095,19 @@ public class DefinitelyWrittenCheck { } + methodReadWriteSetAnalysisToEventLoopBody(); + } private void methodReadWriteSet_analyzeMethod(FlatMethod fm, Set> readSet, - Set> mustWriteSet, Set> mayWriteSet) { + 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, null); + methodReadWriteSet_analyzeBody(fm, readSet, mustWriteSet, mayWriteSet, sharedLocMapping, + deleteSet, false); } @@ -1656,19 +2125,24 @@ public class DefinitelyWrittenCheck { 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, - loopIncElements); + sharedLocMapping, deleteSet, true); } private void methodReadWriteSet_analyzeBody(FlatNode startNode, Set> readSet, Set> mustWriteSet, Set> mayWriteSet, - Set bodyNodeSet) { + SharedLocMappingSet sharedLocMapping, Set> deleteSet, + boolean isEventLoopBody) { // intraprocedural analysis Set flatNodesToVisit = new HashSet(); @@ -1678,24 +2152,32 @@ public class DefinitelyWrittenCheck { FlatNode fn = flatNodesToVisit.iterator().next(); flatNodesToVisit.remove(fn); + SharedLocMappingSet currSharedLocMapping = new SharedLocMappingSet(); Set> currMustWriteSet = new HashSet>(); for (int i = 0; i < fn.numPrev(); i++) { FlatNode prevFn = fn.getPrev(i); Set> in = mapFlatNodeToMustWriteSet.get(prevFn); + SharedLocMappingSet inSharedLoc = mapFlatNodeToSharedLocMapping.get(prevFn); if (in != null) { merge(currMustWriteSet, in); + merge(currSharedLocMapping, inSharedLoc); } } - methodReadWriteSet_nodeActions(fn, currMustWriteSet, readSet, mustWriteSet, mayWriteSet); + methodReadWriteSet_nodeActions(fn, currMustWriteSet, readSet, mustWriteSet, mayWriteSet, + currSharedLocMapping, sharedLocMapping, deleteSet, isEventLoopBody); + SharedLocMappingSet prevSharedLocSet = mapFlatNodeToSharedLocMapping.get(fn); Set> mustSetPrev = mapFlatNodeToMustWriteSet.get(fn); - if (!currMustWriteSet.equals(mustSetPrev)) { + + 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); - if (bodyNodeSet == null || bodyNodeSet.contains(nn)) { + if ((!isEventLoopBody) || loopIncElements.contains(nn)) { flatNodesToVisit.add(nn); } @@ -1708,7 +2190,13 @@ public class DefinitelyWrittenCheck { private void methodReadWriteSet_nodeActions(FlatNode fn, Set> currMustWriteSet, Set> readSet, - Set> mustWriteSet, Set> mayWriteSet) { + 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; @@ -1744,6 +2232,48 @@ public class DefinitelyWrittenCheck { 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; @@ -1801,6 +2331,8 @@ public class DefinitelyWrittenCheck { // x.f=y; if (fn.kind() == FKind.FlatSetFieldNode) { + SharedLocMappingSet killSet = new SharedLocMappingSet(); + SharedLocMappingSet genSet = new SharedLocMappingSet(); FlatSetFieldNode fsfn = (FlatSetFieldNode) fn; lhs = fsfn.getDst(); fld = fsfn.getField(); @@ -1819,14 +2351,40 @@ public class DefinitelyWrittenCheck { 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 - currMustWriteSet.add(newHeapPath); - mayWriteSet.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); } @@ -1867,17 +2425,95 @@ public class DefinitelyWrittenCheck { 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(mustWriteSet, currMustWriteSet); + + // shared loc extension + merge(sharedLocMapping, currSharedLocMapping); } break; } + computeNewMapping(currSharedLocMapping, killSetSharedLoc, genSetSharedLoc); + + } + + private void generateGENSharedSetForFlatCall(SharedLocMappingSet currSharedLocMapping, + SharedLocMappingSet genSetSharedLoc) { + + 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 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); + + } + } + + } + + 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) { @@ -2098,4 +2734,34 @@ public class DefinitelyWrittenCheck { } } + private NTuple deriveLocationTuple(MethodDescriptor md, TempDescriptor td) { + + assert td.getType() != null; + + if (mapDescriptorToComposteLocation.containsKey(td)) { + return mapDescriptorToComposteLocation.get(td); + } else { + if (td.getSymbol().startsWith("this")) { + String thisLocIdentifier = ssjava.getMethodLattice(md).getThisLoc(); + Location thisLoc = new Location(md, thisLocIdentifier); + NTuple locTuple = new NTuple(); + locTuple.add(thisLoc); + return locTuple; + } else { + return ((SSJavaType) td.getType().getExtension()).getCompLoc().getTuple(); + } + } + + } + + 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 diff --git a/Robust/src/Analysis/SSJava/NTuple.java b/Robust/src/Analysis/SSJava/NTuple.java index 800c3652..3190cef0 100644 --- a/Robust/src/Analysis/SSJava/NTuple.java +++ b/Robust/src/Analysis/SSJava/NTuple.java @@ -84,7 +84,17 @@ public class NTuple { return true; } - - + + public NTuple subList(int startIdx, int endIdx) { + + NTuple subList = new NTuple(); + + for (int i = startIdx; i < endIdx; i++) { + subList.add(elements.get(i)); + } + + return subList; + + } } diff --git a/Robust/src/Analysis/SSJava/SharedLocMappingSet.java b/Robust/src/Analysis/SSJava/SharedLocMappingSet.java new file mode 100644 index 00000000..396a858a --- /dev/null +++ b/Robust/src/Analysis/SSJava/SharedLocMappingSet.java @@ -0,0 +1,139 @@ +package Analysis.SSJava; + +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Set; + +import IR.Descriptor; + +public class SharedLocMappingSet { + + Hashtable, Hashtable>> map; + + public SharedLocMappingSet() { + map = new Hashtable, Hashtable>>(); + } + + public Set getWriteSet(NTuple hp, Location loc) { + + Hashtable> loc2Set = map.get(hp); + + if (loc2Set == null) { + loc2Set = new Hashtable>(); + map.put(hp, loc2Set); + } + + Set writeSet = loc2Set.get(loc); + if (writeSet == null) { + writeSet = new HashSet(); + loc2Set.put(loc, writeSet); + } + + return writeSet; + + } + + public void addWrite(NTuple hp, Location loc, Descriptor desc) { + getWriteSet(hp, loc).add(desc); + } + + public void addWriteSet(NTuple hp, Location loc, Set descSet) { + getWriteSet(hp, loc).addAll(descSet); + } + + public void removeWriteSet(NTuple hp, Location loc, Set descSet) { + getWriteSet(hp, loc).removeAll(descSet); + } + + public Hashtable, Hashtable>> getMap() { + return map; + } + + public boolean equals(Object obj) { + + if (!(obj instanceof SharedLocMappingSet)) { + return false; + } + + SharedLocMappingSet in = (SharedLocMappingSet) obj; + return getMap().equals(in.getMap()); + + } + + public Set> getHeapPathKeySet() { + return map.keySet(); + } + + public Set getLocationKeySet(NTuple hp) { + Hashtable> loc2Set = map.get(hp); + return loc2Set.keySet(); + } + + public void intersectWriteSet(NTuple hp, Location loc, Set inSet) { + + boolean isFirst = false; + Hashtable> loc2Set = map.get(hp); + if (loc2Set != null) { + Set set = loc2Set.get(loc); + if (set == null) { + isFirst = true; + } + } else { + isFirst = true; + } + + Set writeSet = getWriteSet(hp, loc); + if (isFirst) { + writeSet.addAll(inSet); + } else { + writeSet.retainAll(inSet); + } + + } + + public String toString() { + return map.toString(); + } + + public void clear() { + map.clear(); + } + + public void remove(NTuple hp, Location loc) { + Hashtable> loc2Set = map.get(hp); + if (loc2Set != null) { + loc2Set.remove(loc); + if (loc2Set.isEmpty()) { + map.remove(hp); + } + } + } + + public void kill(SharedLocMappingSet kill) { + Set> hpKeySet = kill.getHeapPathKeySet(); + for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) { + NTuple hpKey = (NTuple) iterator.next(); + Hashtable> loc2Set = kill.getMap().get(hpKey); + Set locKeySet = loc2Set.keySet(); + for (Iterator iterator2 = locKeySet.iterator(); iterator2.hasNext();) { + Location locKey = (Location) iterator2.next(); + remove(hpKey, locKey); + } + } + } + + public void add(SharedLocMappingSet gen) { + Set> hpKeySet = gen.getMap().keySet(); + for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) { + NTuple hpKey = (NTuple) iterator.next(); + Hashtable> loc2Set = gen.getMap().get(hpKey); + Set locKeySet = loc2Set.keySet(); + for (Iterator iterator2 = locKeySet.iterator(); iterator2.hasNext();) { + Location locKey = (Location) iterator2.next(); + addWriteSet(hpKey, locKey, gen.getWriteSet(hpKey, locKey)); + } + } + } + +}