diff --git a/src/org/ntlab/deltaViewer/DeltaAliasCollector.java b/src/org/ntlab/deltaViewer/DeltaAliasCollector.java index cd25b31..9ec9be5 100644 --- a/src/org/ntlab/deltaViewer/DeltaAliasCollector.java +++ b/src/org/ntlab/deltaViewer/DeltaAliasCollector.java @@ -9,6 +9,7 @@ import org.ntlab.trace.MethodExecution; import org.ntlab.trace.MethodInvocation; import org.ntlab.trace.Statement; +import org.ntlab.trace.TracePoint; /** * Collect delta alias for MagnetRON.(Derived from DeltaAliasTracker.) @@ -78,49 +79,216 @@ } public void shrink() { - // TODO Implement shrink(). List standardMethodInvocations = collectStandardMethodInvocations(aliasList); - List> invocatoinChains = collectInvocatoinChains(standardMethodInvocations); - replaceInvocatoinChains(aliasList, invocatoinChains); + List> invocationChains = collectInvocatoinChains(standardMethodInvocations); + aliasList = replaceInvocatoinChains(aliasList, invocationChains); + + // for debug. + System.out.println("standardMethodInvocations: "); + for (Alias alias: standardMethodInvocations) { + System.out.println(alias.getAliasType() + ":: " + alias.getObjectId() + ": " + alias.getMethodSignature()); + } + System.out.println("invocatoinChains: "); + for (int i = 0; i < invocationChains.size(); i++) { + System.out.println("i = " + i); + for (Alias alias: invocationChains.get(i)) { + System.out.println("\t" + alias.getAliasType() + ":: " + alias.getObjectId() + ": " + alias.getMethodSignature()); + } + } + System.out.println("replaceInvocatoinChains: "); + for (Alias alias: aliasList) { + System.out.println(alias.getObjectId() + ": " + alias.getMethodSignature() + " l." + alias.getLineNo() + " :: " + alias.getAliasType().toString()); + } } private List collectStandardMethodInvocations(List aliasList) { - // TODO Implement collectStandardMethodInvocations(). + List standardMethodInvocations = new ArrayList<>(); + List standardMethodInvsIdx = new ArrayList<>(); + // Collect 1 set of RECEIVER, THIS RETURN_VALUE, METHOD_INVOCATION and it is CollectionType. for (int i = 0; i < aliasList.size(); i++) { Alias alias = aliasList.get(i); if (alias.getAliasType() == AliasType.RECEIVER) { Statement st = alias.getOccurrencePoint().getStatement(); MethodInvocation methodInvocation = (MethodInvocation)st; if (methodInvocation.getCalledMethodExecution().isCollectionType()) { - + if (standardMethodInvsIdx.size() != 0) standardMethodInvsIdx.clear(); + standardMethodInvsIdx.add(i); } } else if (alias.getAliasType() == AliasType.THIS) { - if (alias.getMethodExecution().isCollectionType()) { + if (alias.getMethodExecution().isCollectionType() && standardMethodInvsIdx.size() == 1) { + standardMethodInvsIdx.add(i); } } else if (alias.getAliasType() == AliasType.RETURN_VALUE) { - if (alias.getMethodExecution().isCollectionType()) { + if (alias.getMethodExecution().isCollectionType() && standardMethodInvsIdx.size() == 2) { + standardMethodInvsIdx.add(i); } } else if (alias.getAliasType() == AliasType.METHOD_INVOCATION) { Statement st = alias.getOccurrencePoint().getStatement(); MethodInvocation methodInvocation = (MethodInvocation)st; - if (methodInvocation.getCalledMethodExecution().isCollectionType()) { - } + if (methodInvocation.getCalledMethodExecution().isCollectionType() && standardMethodInvsIdx.size() == 3) { + standardMethodInvsIdx.add(i); + for (int index: standardMethodInvsIdx) { + standardMethodInvocations.add(aliasList.get(index)); + } + standardMethodInvsIdx.clear(); + } } } - return null; - + return standardMethodInvocations; } private List> collectInvocatoinChains(List standardMethodInvocations) { - // TODO Implement collectInvocatoinChains(). - return null; - + List> invocationChains = new ArrayList<>(); + List invChainsIdx = new ArrayList<>(); + // Compare whether same callerMethodExecution. + MethodExecution compareMethodExec = null; + for (int i = 0; i < standardMethodInvocations.size(); i++) { + Alias standardMethodInv = standardMethodInvocations.get(i); + MethodExecution methodExec = null; + if (standardMethodInv.getAliasType() == AliasType.RECEIVER && invChainsIdx.size() == 0) { + methodExec = standardMethodInv.getMethodExecution(); + } else if (standardMethodInv.getAliasType() == AliasType.THIS && invChainsIdx.size() == 1) { + methodExec = standardMethodInv.getMethodExecution().getCallerMethodExecution(); + } else if (standardMethodInv.getAliasType() == AliasType.RETURN_VALUE && invChainsIdx.size() == 2) { + methodExec = standardMethodInv.getMethodExecution().getCallerMethodExecution(); + } else if (standardMethodInv.getAliasType() == AliasType.METHOD_INVOCATION && invChainsIdx.size() == 3) { + methodExec = standardMethodInv.getMethodExecution(); + } else { + invChainsIdx.clear(); + continue; + } + + if (compareMethodExec == null) { + compareMethodExec = methodExec; + invocationChains.add(new ArrayList<>()); + } else { + if (compareMethodExec != methodExec) { + compareMethodExec = methodExec; + invocationChains.add(new ArrayList<>()); + } + } + invChainsIdx.add(i); + if (invChainsIdx.size() == 4) { + for (int index: invChainsIdx) { + invocationChains.get(invocationChains.size() - 1).add(standardMethodInvocations.get(index)); + } + invChainsIdx.clear(); + } + } + System.out.println("invocatoinChains: "); + for (int i = 0; i < invocationChains.size(); i++) { + System.out.println("i = " + i); + for (Alias alias: invocationChains.get(i)) { + System.out.println("\t" + alias.getAliasType() + ": " + alias.getObjectId() + ", " + alias.getMethodSignature()); + } + } + + // Compare whether same objectId from RETURN_VALUE to THIS. + int i = 0; + while (i < invocationChains.size()) { + List invChain = invocationChains.get(i); + if (invChain.size() > 4) { + int j = 2; + String compareObjId = null; + while (j < invChain.size() - (1 + 2)) { + Alias pRetauVal = invChain.get(j); + Alias pMethodInv = invChain.get(j + 1); + Alias nReceiver = invChain.get(j + 2); + Alias nThis = invChain.get(j + 3); + compareObjId = pRetauVal.getObjectId(); + if (compareObjId.equals(pMethodInv.getObjectId()) + && compareObjId.equals(nReceiver.getObjectId()) + && compareObjId.equals(nThis.getObjectId())) { + j += 4; + } else { + // Remove 1 set of from RECEIVER to METHOD_INVOCATION. + for (int k = i - 2; k < i + 2; k++) { + invChain.remove(k); + } + if (invChain.size() <= 4) { + invocationChains.remove(i); + i--; + } + } + } + i++; + } else { + invocationChains.remove(i); + } + } + return invocationChains; } - private List replaceInvocatoinChains(List aliasList, List> invocatoinChains) { - // TODO Implement replaceInvocatoinChains(). - return null; - } + private List replaceInvocatoinChains(List aliasList, List> invocationChains) { + List replacedAliasList = new ArrayList<>(aliasList); + for (List invChain: invocationChains) { + int firstIdx = replacedAliasList.indexOf(invChain.get(0)); // RECEIVER + int secondIdx = replacedAliasList.indexOf(invChain.get(1)); // THIS + int thirdIdx = replacedAliasList.indexOf(invChain.get(invChain.size() - 2)); // RETURN_VALUE + int lastIdx = replacedAliasList.indexOf(invChain.get(invChain.size() - 1)); // METHOD_INVOCATION + if(firstIdx != -1 && secondIdx != -1 && thirdIdx != -1 && lastIdx != -1) { + Alias receiverAlias = replacedAliasList.get(firstIdx); + Alias oldThisAlias = replacedAliasList.get(secondIdx); + Alias oldReturnValAlias = replacedAliasList.get(thirdIdx); + // Collect signature chains. + StringBuilder sb = new StringBuilder(); + for (int i = 1; i < invChain.size(); i+=4) { + if (i == 1) { + sb.append(invChain.get(i).getMethodSignature()); + } else { + String[] splitMethodSig = invChain.get(i).getMethodSignature().split("\\."); + sb.append("."); + sb.append(splitMethodSig[splitMethodSig.length - 1]); + } + } + String signatureChains = sb.toString(); + String callerSideSignature = signatureChains; + String thisClassName = oldThisAlias.getMethodExecution().getThisClassName(); + long enterTime = oldThisAlias.getOccurrencePoint().getMethodExecution().getEntryTime(); + long exitTime = oldReturnValAlias.getOccurrencePoint().getMethodExecution().getExitTime(); + + // Create new alias for THIS. + String thisObjId = oldThisAlias.getObjectId(); + MethodExecution newCalledMethodExec = new MethodExecution(signatureChains, callerSideSignature, thisClassName, thisObjId, false, false, enterTime); + newCalledMethodExec.setCollectionType(true); + newCalledMethodExec.setExitTime(exitTime); + TracePoint newThisTp = new TracePoint(newCalledMethodExec, -1); + Alias newThisAlias = new Alias(AliasType.THIS, 0, thisObjId, newThisTp.duplicate()); + + // Change called method execution of RECEIVER alias. + // TODO Caution: The trace will be changed by the following code! + TracePoint receiverTp = receiverAlias.getOccurrencePoint(); + Statement st = receiverTp.getStatement(); + MethodInvocation methodInvocation = (MethodInvocation)st; + methodInvocation.setCalledMethodExecution(newCalledMethodExec); + newCalledMethodExec.setCaller(receiverTp.getMethodExecution(), receiverTp.getMethodExecution().getStatements().indexOf(st)); + + // Create new alias for RETURN_VALUE. + String returnValObjId = oldReturnValAlias.getObjectId(); + TracePoint newReturnValTp = new TracePoint(newCalledMethodExec, -1); + Alias newReturnValAlias = new Alias(AliasType.RETURN_VALUE, 0, returnValObjId, newReturnValTp.duplicate()); + + // Create new alias for METHOD_INVOCATION. + Alias newMethodInvAlias = new Alias(AliasType.METHOD_INVOCATION, 0, returnValObjId, receiverTp.duplicate()); + + /* Replace InvocatoinChains */ + // Remove invocationChains from aliasList. + for (int i = 1; i < invChain.size(); i++) { // Except first alias of THIS. + Alias invAlias = invChain.get(i); + int invAliasIdx = replacedAliasList.indexOf(invAlias); // Get index of invAlias in aliasList. + if (invAliasIdx != - 1) replacedAliasList.remove(invAliasIdx); + else System.out.println("Failed to remove invAlias in aliasList..."); + } + // Add new Alias for THIS and RETURN_VALUE, METHOD_INVOCATION. + replacedAliasList.add(secondIdx, newMethodInvAlias); + replacedAliasList.add(secondIdx, newReturnValAlias); + replacedAliasList.add(secondIdx, newThisAlias); + } else { + System.out.println("Failed to shrink aliasList..."); + } + } + return replacedAliasList; + } }