package org.ntlab.deltaViewer; import java.util.ArrayList; import java.util.List; import org.ntlab.deltaExtractor.Alias; import org.ntlab.deltaExtractor.Alias.AliasType; import org.ntlab.deltaExtractor.IAliasTracker; 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.) * * @author Nitta Lab. */ public class DeltaAliasCollector implements IAliasTracker { // Reverse execution order. private List<Alias> aliasList = new ArrayList<>(); public DeltaAliasCollector() { } @Override public void addAlias(Alias alias) { switch(alias.getAliasType()) { case FORMAL_PARAMETER: aliasList.add(0, alias); break; case THIS: aliasList.add(0, alias); break; case METHOD_INVOCATION: aliasList.add(0, alias); break; case CONSTRACTOR_INVOCATION: aliasList.add(0, alias); break; case FIELD: aliasList.add(0, alias); break; case ARRAY_ELEMENT: aliasList.add(0, alias); break; case ARRAY: aliasList.add(0, alias); break; case ACTUAL_ARGUMENT: aliasList.add(0, alias); break; case RECEIVER: aliasList.add(0, alias); if (alias.getOccurrencePoint().getStatement() instanceof MethodInvocation) { MethodExecution me = ((MethodInvocation) alias.getOccurrencePoint().getStatement()).getCalledMethodExecution(); } break; case RETURN_VALUE: aliasList.add(0, alias); break; default: break; } System.out.println(alias.getObjectId() + ", " + alias.getMethodSignature() + " l." + alias.getLineNo() + " : " + alias.getAliasType().toString()); } @Override public List<Alias> getAliasList() { return this.aliasList; } /* * Don't write anything here. */ @Override public void changeTrackingObject(String from, String to, boolean isSrcSide) { } public void shrink() { List<Alias> standardMethodInvocations = collectStandardMethodInvocations(aliasList); List<List<Alias>> 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<Alias> collectStandardMethodInvocations(List<Alias> aliasList) { List<Alias> standardMethodInvocations = new ArrayList<>(); List<Integer> 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() && standardMethodInvsIdx.size() == 1) { standardMethodInvsIdx.add(i); } } else if (alias.getAliasType() == AliasType.RETURN_VALUE) { 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() && standardMethodInvsIdx.size() == 3) { standardMethodInvsIdx.add(i); for (int index: standardMethodInvsIdx) { standardMethodInvocations.add(aliasList.get(index)); } standardMethodInvsIdx.clear(); } } } return standardMethodInvocations; } private List<List<Alias>> collectInvocatoinChains(List<Alias> standardMethodInvocations) { List<List<Alias>> invocationChains = new ArrayList<>(); List<Integer> 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<Alias> 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<Alias> replaceInvocatoinChains(List<Alias> aliasList, List<List<Alias>> invocationChains) { List<Alias> replacedAliasList = new ArrayList<>(aliasList); for (List<Alias> 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; } }