package org.ntlab.reverseDebugger; import java.util.ArrayList; import org.ntlab.traceCollector.tracer.trace.ArrayAccess; import org.ntlab.traceCollector.tracer.trace.ArrayCreate; import org.ntlab.traceCollector.tracer.trace.ArrayUpdate; import org.ntlab.traceCollector.tracer.trace.FieldAccess; import org.ntlab.traceCollector.tracer.trace.FieldUpdate; import org.ntlab.traceCollector.tracer.trace.MethodExecution; import org.ntlab.traceCollector.tracer.trace.MethodInvocation; import org.ntlab.traceCollector.tracer.trace.ObjectReference; import org.ntlab.traceCollector.tracer.trace.Statement; import org.ntlab.traceCollector.tracer.trace.Trace; import org.ntlab.traceCollector.tracer.trace.TracePoint; /** * オブジェクトの参照情報(エイリアス)を表すクラス * @author Isitani * */ public class Alias { private String objectId; private TracePoint occurrencePoint; // 当該オブジェクトの参照が行われている実行箇所に対応するTracePoint /** * 当該オブジェクトの参照がTracePointにおいてどこに現れているかを表す<br> * 0 フィールドアクセス時のコンテナ もしくは メソッド呼び出し時のレシーバ<br> * 1, 2, 3 …… n フィールドアクセス時のフィールド(1) もしくは メソッド呼び出し時のn番目の実引数 (1から順番に)<br> * -1 メソッド呼び出し時の戻り値<br> * <br> * 例1: d = a.m(b, c);<br> * <br> * 例1の実行文において, aはメソッド呼び出しのレシーバなので0, bはメソッド呼び出しの1番目の実引数なので1,<br> * cはメソッド呼び出しの2番目の実引数なので2, a.m(b, c)の戻り値は-1 となる.<br> * <br> * 例2: d = a.f;<br> * 例2の実行文において, aはフィールドのコンテナなので0, bはフィールドなので1 となる. * */ private int occurrenceExp; public static final int OCCURRENCE_EXP_CONTAINER = 0; public static final int OCCURRENCE_EXP_RECEIVER = 0; public static final int OCCURRENCE_EXP_FIELD = 1; public static final int OCCURRENCE_EXP_ARRAY = 1; public static final int OCCURRENCE_EXP_FIRST_ARG = 1; public static final int OCCURRENCE_EXP_RETURN = -1; public Alias(String objectId, TracePoint occurrencePoint, int occurrenceExp) { this.objectId = objectId; this.occurrencePoint = occurrencePoint; this.occurrenceExp = occurrenceExp; } public String getObjectId() { return objectId; } public TracePoint getOccurrencePoint() { return occurrencePoint; } public int getOccurrenceExp() { return occurrenceExp; } public MethodExecution getMethodExecution() { return occurrencePoint.getMethodExecution(); } public String getMethodExecutionClassName() { MethodExecution methodExecution = occurrencePoint.getMethodExecution(); return Trace.getDeclaringType(methodExecution.getSignature(), methodExecution.isConstructor()); } public String getMethodSignature() { return occurrencePoint.getMethodExecution().getCallerSideSignature(); } public int getLineNo() { Statement statement = occurrencePoint.getStatement(); return statement.getLineNo(); } public String getStatementType() { Statement statement = occurrencePoint.getStatement(); String statementType = ""; if (statement instanceof FieldAccess) { FieldAccess fa = (FieldAccess)statement; statementType = "FieldAccess"; } else if (statement instanceof FieldUpdate) { FieldUpdate fu = (FieldUpdate)statement; statementType = "FieldUpdate"; } else if (statement instanceof ArrayAccess) { ArrayAccess aa = (ArrayAccess)statement; statementType = "ArrayAccess"; } else if (statement instanceof ArrayUpdate) { ArrayUpdate au = (ArrayUpdate)statement; statementType = "ArrayUpdate"; } else if (statement instanceof ArrayCreate) { ArrayCreate ac = (ArrayCreate)statement; statementType = "ArrayCreate"; } else if (statement instanceof MethodInvocation) { MethodExecution me = ((MethodInvocation)statement).getCalledMethodExecution(); statementType = "MethodInvocation"; } return statementType; } public String getStatementSignature() { Statement statement = occurrencePoint.getStatement(); String statementSignature = ""; if (statement instanceof FieldAccess) { FieldAccess fa = (FieldAccess)statement; statementSignature = fa.getFieldName(); } else if (statement instanceof FieldUpdate) { FieldUpdate fu = (FieldUpdate)statement; statementSignature = fu.getFieldName(); } else if (statement instanceof ArrayAccess) { ArrayAccess aa = (ArrayAccess)statement; statementSignature = aa.getArrayClassName() + "[" + aa.getIndex() + "]"; } else if (statement instanceof ArrayUpdate) { ArrayUpdate au = (ArrayUpdate)statement; statementSignature = au.getArrayClassName() + "[" + au.getIndex() + "]"; } else if (statement instanceof ArrayCreate) { ArrayCreate ac = (ArrayCreate)statement; statementSignature = ac.getArrayClassName(); } else if (statement instanceof MethodInvocation) { MethodExecution me = ((MethodInvocation)statement).getCalledMethodExecution(); statementSignature = me.getCallerSideSignature(); } return statementSignature; } public String getClassName() { Statement statement = occurrencePoint.getStatement(); String className = ""; if (statement instanceof FieldAccess) { if (occurrenceExp == OCCURRENCE_EXP_CONTAINER) { className = ((FieldAccess) statement).getContainerClassName(); } else if (occurrenceExp == OCCURRENCE_EXP_FIELD) { className = ((FieldAccess) statement).getValueClassName(); } } else if (statement instanceof FieldUpdate) { if (occurrenceExp == OCCURRENCE_EXP_CONTAINER) { className = ((FieldUpdate) statement).getContainerClassName(); } else if (occurrenceExp == OCCURRENCE_EXP_FIELD) { className = ((FieldUpdate) statement).getValueClassName(); } } else if (statement instanceof ArrayAccess) { className = ((ArrayAccess) statement).getValueClassName(); } else if (statement instanceof ArrayUpdate) { className = ((ArrayUpdate) statement).getValueClassName(); } else if (statement instanceof ArrayCreate) { className = ((ArrayCreate) statement).getArrayClassName(); } else if (statement instanceof MethodInvocation) { MethodExecution me = ((MethodInvocation)statement).getCalledMethodExecution(); if (occurrenceExp == OCCURRENCE_EXP_RETURN) { className = me.getReturnValue().getActualType(); } else if (occurrenceExp == OCCURRENCE_EXP_RECEIVER) { className = me.getThisClassName(); } else { int index = occurrenceExp - OCCURRENCE_EXP_FIRST_ARG; ArrayList<ObjectReference> args = me.getArguments(); if (index >= 0 && index < args.size()) { className = me.getArguments().get(index).getActualType(); } } } return className; } public String getOccurrenceText() { String statementType = getStatementType(); switch (statementType) { case "FieldAccess": case "FieldUpdate": return (occurrenceExp == 0) ? "container" : "field"; case "ArrayAccess": case "ArrayUpdate": return (occurrenceExp == 0) ? "arrayObject" : "arrayValue"; case "ArrayCreate": return "return"; case "MethodInvocation": if (occurrenceExp <= 0) { return (occurrenceExp == 0) ? "receiver" : "return"; } final String[] ORDER_TEXT = {"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th"}; // 0-13に対応 final String ARG = " arg"; if (occurrenceExp % 100 >= ORDER_TEXT.length) { return occurrenceExp + ORDER_TEXT[occurrenceExp % 10] + ARG; // 下2桁が14以上なら, 下1桁の数字に対応させる } else if (occurrenceExp % 100 >= 0) { return occurrenceExp + ORDER_TEXT[occurrenceExp % 100] + ARG; // 下2桁が0以上13以下なら, 下2桁の数字に対応させる } } return String.valueOf(occurrenceExp); } // @Override // public String toString() { // Statement statement = occurrencePoint.getStatement(); // String className = getClassName(); // String methodSignature = getMethodSignature(); // String statementType = getStatementType(); // String statementSigunarure = getStatementSignature(); // String indent = " "; // StringBuilder str = new StringBuilder(); // str.append("objId: " + objectId + " (class = " + className + ")" + "\n"); // str.append("tp: " + occurrencePoint + "\n"); // str.append(indent + "signature: " + methodSignature + "\n"); // str.append(indent + "lineNo: " + statement.getLineNo() + "\n"); // str.append(indent + "statementType: " + statementType + " -> " + statementSigunarure + "\n"); // str.append("occurrenceExp: " + occurrenceExp + "\n"); // return str.toString(); // } }