diff --git a/src/org/ntlab/deltaViewer/CollaborationAliasCollector.java b/src/org/ntlab/deltaViewer/CollaborationAliasCollector.java index c1be68f..dad7fd1 100644 --- a/src/org/ntlab/deltaViewer/CollaborationAliasCollector.java +++ b/src/org/ntlab/deltaViewer/CollaborationAliasCollector.java @@ -1,14 +1,22 @@ package org.ntlab.deltaViewer; +import java.util.AbstractMap; +import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import org.ntlab.deltaExtractor.Alias; import org.ntlab.deltaExtractor.IAliasCollector; import org.ntlab.featureExtractor.Extract; import org.ntlab.trace.MethodExecution; +import org.ntlab.trace.MethodInvocation; +import org.ntlab.trace.Statement; import org.ntlab.trace.TracePoint; /** @@ -41,26 +49,51 @@ * Merge other into aliasList(this) in time stamp order. * @param other�@IAliasCollector to be merged into the aliasList. * @param extract + * @param newToOldMethodExecMap */ - public void merge(IAliasCollector other, Extract extract) { + public void merge(IAliasCollector other, Extract extract, Map> newToOldMethodExecMap) { List otherAliasList = other.getAliasList(); otherAliasList = sortAliasListByTimeStamp(otherAliasList); + int otherIdx = 0; // Index in otherAliasList int thisIdx = 0; // Index in thisAliasList int thisOrgIdx = 0; // Index in the original thisAliasList + MethodExecution newCallee = null; while(otherIdx < otherAliasList.size()) { Alias otherAlias = otherAliasList.get(otherIdx); + if (newCallee != null && newToOldMethodExecMap.get(newCallee).contains(otherAlias.getMethodExecution())) { + Statement st = otherAlias.getOccurrencePoint().getStatement(); + if (st instanceof MethodInvocation) { + // Caution!!: The internal structure of the trace is modified. + MethodExecution calleeCallee = ((MethodInvocation) st).getCalledMethodExecution(); + calleeCallee.setCaller(newCallee, calleeCallee.getCallerStatementExecution()); + } + DummyTracePoint dummyTp = new DummyTracePoint(otherAlias.getOccurrencePoint(), newCallee); + Alias newAlias = new Alias(otherAlias.getAliasType(), otherAlias.getIndex(), otherAlias.getObjectId(), dummyTp); + otherAliasList.set(otherIdx, newAlias); + } if (thisIdx >= aliasList.size()) { if (extract != null && extract.isToConnect() && otherIdx == 0) { Alias thisPrevAlias = aliasList.get(aliasList.size() - 1); if (!otherAlias.getMethodExecution().isStatic() && otherAlias.getMethodExecution().getCallerMethodExecution() != thisPrevAlias.getMethodExecution()) { // Add a dummy alias to connect disjunct call hierarchies. (thisPrevAlias -> otherAlias) MethodExecution caller = thisPrevAlias.getMethodExecution(); -// MethodExecution callee = new DummyMethodExecution(otherAlias.getMethodExecution()); // Currently does not work because this dummy and the original one will be mixed. - MethodExecution callee = otherAlias.getMethodExecution(); + MethodExecution oldCallee = otherAlias.getMethodExecution(); + MethodExecution callee = null; + if (oldCallee instanceof DummyMethodExecution) { + callee = oldCallee; + } else { + callee = getNewMethodExec(newToOldMethodExecMap, oldCallee); + if (callee == null) { + callee = new DummyMethodExecution(oldCallee); + Set oldExecs = new HashSet<>(); + oldExecs.add(oldCallee); + newToOldMethodExecMap.put(callee, oldExecs); + newCallee = callee; + } + } callee.setCaller(caller, caller.getStatements().indexOf(thisPrevAlias.getOccurrencePoint().getStatement())); DummyMethodInvocation dummyInv = new DummyMethodInvocation(callee, caller.getThisClassName(), caller.getThisObjId(), 0, thisPrevAlias.getOccurrencePoint().getStatement().getThreadNo()); - dummyInv.setTimeStamp(callee.getEntryTime()); DummyTracePoint dummyTp = new DummyTracePoint(caller, dummyInv); aliasList.add(new Alias(Alias.AliasType.RECEIVER, 0, callee.getThisObjId(), dummyTp)); thisIdx++; @@ -72,6 +105,11 @@ } Alias thisAlias = aliasList.get(thisIdx); + Alias newThisAlias = getUpdatedAlias(thisAlias, newToOldMethodExecMap); + if (newThisAlias != null) { + aliasList.set(thisIdx, newThisAlias); + thisAlias = newThisAlias; + } if (otherAlias.equals(thisAlias)) { otherIdx++; thisIdx++; thisOrgIdx++; } else { @@ -84,11 +122,22 @@ if (!otherAlias.getMethodExecution().isStatic() && otherAlias.getMethodExecution().getCallerMethodExecution() != thisPrevAlias.getMethodExecution()) { // Add a dummy alias to connect disjunct call hierarchies. (thisPrevAlias -> otherAlias) MethodExecution caller = thisPrevAlias.getMethodExecution(); -// MethodExecution callee = new DummyMethodExecution(otherAlias.getMethodExecution()); // Currently does not work because this dummy and the original one will be mixed. - MethodExecution callee = otherAlias.getMethodExecution(); + MethodExecution oldCallee = otherAlias.getMethodExecution(); + MethodExecution callee = null; + if (oldCallee instanceof DummyMethodExecution) { + callee = oldCallee; + } else { + callee = getNewMethodExec(newToOldMethodExecMap, oldCallee); + if (callee == null) { + callee = new DummyMethodExecution(oldCallee); + Set oldExecs = new HashSet<>(); + oldExecs.add(oldCallee); + newToOldMethodExecMap.put(callee, oldExecs); + newCallee = callee; + } + } callee.setCaller(caller, caller.getStatements().indexOf(thisPrevAlias.getOccurrencePoint().getStatement())); DummyMethodInvocation dummyInv = new DummyMethodInvocation(callee, caller.getThisClassName(), caller.getThisObjId(), 0, thisPrevAlias.getOccurrencePoint().getStatement().getThreadNo()); - dummyInv.setTimeStamp(callee.getEntryTime()); DummyTracePoint dummyTp = new DummyTracePoint(caller, dummyInv); aliasList.add(new Alias(Alias.AliasType.RECEIVER, 0, callee.getThisObjId(), dummyTp)); thisIdx++; @@ -102,11 +151,22 @@ if (!thisAlias.getMethodExecution().isStatic() && thisAlias.getMethodExecution().getCallerMethodExecution() != otherPrevAlias.getMethodExecution()) { // Add a dummy alias to connect disjunct call hierarchies. (otherPrevAlias -> thisAlias) MethodExecution caller = otherPrevAlias.getMethodExecution(); -// MethodExecution callee = new DummyMethodExecution(thisAlias.getMethodExecution()); // Currently does not work because this dummy and the original one will be mixed. - MethodExecution callee = thisAlias.getMethodExecution(); + MethodExecution oldCallee = thisAlias.getMethodExecution(); + MethodExecution callee = null; + if (oldCallee instanceof DummyMethodExecution) { + callee = oldCallee; + } else { + callee = getNewMethodExec(newToOldMethodExecMap, oldCallee); + if (callee == null) { + callee = new DummyMethodExecution(oldCallee); + Set oldExecs = new HashSet<>(); + oldExecs.add(oldCallee); + newToOldMethodExecMap.put(callee, oldExecs); + newCallee = callee; + } + } callee.setCaller(caller, caller.getStatements().indexOf(otherPrevAlias.getOccurrencePoint().getStatement())); DummyMethodInvocation dummyInv = new DummyMethodInvocation(callee, caller.getThisClassName(), caller.getThisObjId(), 0, otherPrevAlias.getOccurrencePoint().getStatement().getThreadNo()); - dummyInv.setTimeStamp(callee.getEntryTime()); DummyTracePoint dummyTp = new DummyTracePoint(caller, dummyInv); aliasList.add(new Alias(Alias.AliasType.RECEIVER, 0, callee.getThisObjId(), dummyTp)); thisIdx++; @@ -130,17 +190,61 @@ if (!thisAlias.getMethodExecution().isStatic() && thisAlias.getMethodExecution().getCallerMethodExecution() != otherPrevAlias.getMethodExecution()) { // Add a dummy alias to connect disjunct call hierarchies. (otherPrevAlias -> thisAlias) MethodExecution caller = otherPrevAlias.getMethodExecution(); -// MethodExecution callee = new DummyMethodExecution(thisAlias.getMethodExecution()); // Currently does not work because this dummy and the original one will be mixed. - MethodExecution callee = thisAlias.getMethodExecution(); + MethodExecution oldCallee = thisAlias.getMethodExecution(); + MethodExecution callee = null; + if (oldCallee instanceof DummyMethodExecution) { + callee = oldCallee; + } else { + callee = getNewMethodExec(newToOldMethodExecMap, oldCallee); + if (callee == null) { + callee = new DummyMethodExecution(oldCallee); + Set oldExecs = new HashSet<>(); + oldExecs.add(oldCallee); + newToOldMethodExecMap.put(callee, oldExecs); + newCallee = callee; + } + } callee.setCaller(caller, caller.getStatements().indexOf(otherPrevAlias.getOccurrencePoint().getStatement())); DummyMethodInvocation dummyInv = new DummyMethodInvocation(callee, caller.getThisClassName(), caller.getThisObjId(), 0, otherPrevAlias.getOccurrencePoint().getStatement().getThreadNo()); - dummyInv.setTimeStamp(callee.getEntryTime()); DummyTracePoint dummyTp = new DummyTracePoint(caller, dummyInv); aliasList.add(new Alias(Alias.AliasType.RECEIVER, 0, callee.getThisObjId(), dummyTp)); } } } + private Alias getUpdatedAlias(Alias alias, Map> newToOldMethodExecMap) { + Alias newAlias = null; + MethodExecution newExec = getNewMethodExec(newToOldMethodExecMap, alias.getMethodExecution()); + Statement st = alias.getOccurrencePoint().getStatement(); + DummyMethodInvocation dummyInvocation = null; + if (st instanceof MethodInvocation) { + MethodInvocation mi = ((MethodInvocation) st); + MethodExecution calledExec = mi.getCalledMethodExecution(); + MethodExecution newCalledExec = getNewMethodExec(newToOldMethodExecMap, calledExec); + if (newCalledExec != null) { + dummyInvocation = new DummyMethodInvocation(newCalledExec, mi.getThisClassName(), mi.getThisObjId(), 0, mi.getThreadNo()); + } + } + if (newExec != null || dummyInvocation != null) { + TracePoint dummyTp = null; + if (newExec == null) { + // Only the called method is to be replaced. + dummyTp = new DummyTracePoint(alias.getMethodExecution(), dummyInvocation); + } else { + if (dummyInvocation == null) { + // Only this method is to be replaced. + Statement originalSt = alias.getOccurrencePoint().getStatement(); + dummyTp = new DummyTracePoint(newExec, originalSt); + } else { + // Both the calling and the called methods are to be replaced. + dummyTp = new DummyTracePoint(newExec, dummyInvocation); + } + } + newAlias = new Alias(alias.getAliasType(), alias.getIndex(), alias.getObjectId(), dummyTp); + } + return newAlias; + } + /** * Sort aliasList in time stamp order. * @param aliasList AliasList to sort. @@ -159,4 +263,11 @@ ).collect(Collectors.toList()); return sortedAliasList; } + + private MethodExecution getNewMethodExec(Map> newToOldMethodExecMap, MethodExecution oldExec) { + for (MethodExecution newExec: newToOldMethodExecMap.keySet()) { + if (newToOldMethodExecMap.get(newExec).contains(oldExec)) return newExec; + } + return null; + } }