package org.ntlab.traceDebugger.analyzerProvider; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import org.ntlab.traceAnalysisPlatform.tracer.trace.FieldUpdate; import org.ntlab.traceAnalysisPlatform.tracer.trace.MethodExecution; import org.ntlab.traceAnalysisPlatform.tracer.trace.MethodInvocation; import org.ntlab.traceAnalysisPlatform.tracer.trace.ObjectReference; import org.ntlab.traceAnalysisPlatform.tracer.trace.Statement; import org.ntlab.traceAnalysisPlatform.tracer.trace.ThreadInstance; import org.ntlab.traceAnalysisPlatform.tracer.trace.Trace; import org.ntlab.traceAnalysisPlatform.tracer.trace.TracePoint; public class VariableUpdatePointFinder { private static VariableUpdatePointFinder theInstance = new VariableUpdatePointFinder(); private Trace trace; private Map<String, Map<String, List<TracePoint>>> updatePoints = new HashMap<>(); // コンテナIDとフィールド名をキーにした変数更新ポイント private Map<String, Map<String, List<TracePoint>>> definitionInvocationPoints = new HashMap<>(); // レシーバIDと引数IDをキーにしたコレクションへの追加ポイント private Map<String, TracePoint> gettingIteratorPoints = new HashMap<>(); // イテレータのIDをキーにそれを取得したポイント private Map<String, List<TracePoint>> changeOtherCollectionPoints = new HashMap<>(); // 乗せ換え後のコレクションIDをキーにそれを乗せ換えた地点のポイント public void setTrace(Trace trace) { this.trace = trace; init(); } public static VariableUpdatePointFinder getInstance() { return theInstance; } private void init() { registerUpdatePoints(); System.out.println(updatePoints); System.out.println(definitionInvocationPoints); sort(updatePoints); sort(definitionInvocationPoints); System.out.println(updatePoints); System.out.println(definitionInvocationPoints); } private void registerUpdatePoints() { for (Map.Entry<String, ThreadInstance> entry : trace.getAllThreads().entrySet()) { ThreadInstance thread = entry.getValue(); for (MethodExecution me : thread.getRoot()) { TracePoint start = me.getEntryPoint(); while (start.stepFull()) { Statement statement = start.getStatement(); if (statement instanceof FieldUpdate) { registerFieldUpdatePoint(start, (FieldUpdate)statement); } else if (statement instanceof MethodInvocation) { MethodInvocation mi = (MethodInvocation)statement; MethodExecution calledME = mi.getCalledMethodExecution(); String methodName = calledME.getSignature(); List<ObjectReference> args = calledME.getArguments(); if (methodName.contains(".add(") || methodName.contains(".addElement(")) { registerdefinitionInvocationPoint(start, calledME); } else if (methodName.contains(".iterator(") || methodName.contains("Iterator(")) { registerIteratorPoint(start, calledME); } else if (args.size() == 1 && args.get(0).getActualType().startsWith("java.util.")) { ObjectReference returnValue = calledME.getReturnValue(); if (calledME.getThisClassName().startsWith("java.util.") && !(calledME.getThisObjId().equals("0"))) { String toCollectionId = calledME.getThisObjId(); registerChangeOtherCollectionPoint(start, toCollectionId); } else if (returnValue != null && returnValue.getActualType().startsWith("java.util.")) { String toCollectionId = returnValue.getId(); registerChangeOtherCollectionPoint(start, toCollectionId); } } } } } } } private void registerFieldUpdatePoint(TracePoint tp, FieldUpdate fu) { String objectId = fu.getContainerObjId(); String fieldName = fu.getFieldName(); register(updatePoints, objectId, fieldName, tp); } private void registerdefinitionInvocationPoint(TracePoint tp, MethodExecution calledME) { List<ObjectReference> args = calledME.getArguments(); if (args.size() == 1) { String receiverId = calledME.getThisObjId(); String argId = args.get(0).getId(); register(definitionInvocationPoints, receiverId, argId, tp); } } private void registerIteratorPoint(TracePoint tp, MethodExecution calledME) { ObjectReference returnIteratorValue = calledME.getReturnValue(); String iteratorId = returnIteratorValue.getId(); gettingIteratorPoints.put(iteratorId, tp.duplicate()); } private void registerChangeOtherCollectionPoint(TracePoint tp, String toCollectionId) { List<TracePoint> tracePoints = changeOtherCollectionPoints.get(toCollectionId); if (tracePoints == null) { tracePoints = new ArrayList<TracePoint>(); changeOtherCollectionPoints.put(toCollectionId, tracePoints); } tracePoints.add(tp.duplicate()); } private void register(Map<String, Map<String, List<TracePoint>>> map, String key1, String key2, TracePoint tp) { Map<String, List<TracePoint>> innerMap = map.get(key1); if (innerMap == null) { innerMap = new HashMap<>(); map.put(key1, innerMap); } List<TracePoint> tracePoints = innerMap.get(key2); if (tracePoints == null) { tracePoints = new ArrayList<>(); innerMap.put(key2, tracePoints); } tracePoints.add(tp.duplicate()); } private void sort(Map<String, Map<String, List<TracePoint>>> map) { for (Map<String, List<TracePoint>> innerMap : map.values()) { for (List<TracePoint> tracePoints : innerMap.values()) { Collections.sort(tracePoints, new Comparator<TracePoint>() { @Override public int compare(TracePoint arg0, TracePoint arg1) { long time0 = arg0.getStatement().getTimeStamp(); long time1 = arg1.getStatement().getTimeStamp(); return (time0 < time1) ? -1 : 1; } }); } } } public TracePoint getPoint(String objectId, String fieldName, TracePoint before) { return getPoint(updatePoints, objectId, fieldName, before); } public TracePoint getDefinitionInvocationPoint(String receiverId, String argId, TracePoint before) { return getPoint(definitionInvocationPoints, receiverId, argId, before); } public TracePoint getIteratorPoint(String iteratorId) { return gettingIteratorPoints.get(iteratorId); } public TracePoint getTransferCollectionPoint(String toCollectionId, TracePoint before) { List<TracePoint> tracePoints = changeOtherCollectionPoints.get(toCollectionId); long beforeTime = before.getStatement().getTimeStamp(); TracePoint tmp = null; for (TracePoint tp : tracePoints) { long time = tp.getStatement().getTimeStamp(); if (time >= beforeTime) return tmp; tmp = tp; } return tmp; } private TracePoint getPoint(Map<String, Map<String, List<TracePoint>>> map, String key1, String key2, TracePoint before) { Map<String, List<TracePoint>> innerMap = map.get(key1); if (innerMap == null) return null; List<TracePoint> tracePoints = innerMap.get(key2); if (tracePoints == null) return null; long beforeTime = before.getStatement().getTimeStamp(); TracePoint tmp = null; for (TracePoint tp : tracePoints) { long time = tp.getStatement().getTimeStamp(); if (time >= beforeTime) return tmp; tmp = tp; } return tmp; } }