diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/handlers/InstrumentationHandler.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/handlers/InstrumentationHandler.java index ba3dc45..d642d45 100644 --- a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/handlers/InstrumentationHandler.java +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/handlers/InstrumentationHandler.java @@ -18,6 +18,7 @@ import org.eclipse.ui.handlers.HandlerUtil; import org.ntlab.traceCollector.Activator; import org.ntlab.traceCollector.tracer.JSONTraceGenerator; +import org.ntlab.traceCollector.tracer.OnlineTraceGenerator; import org.ntlab.traceCollector.tracer.OutputStatementsGenerator; import org.ntlab.traceCollector.tracer.Tracer; @@ -59,7 +60,8 @@ cp.appendClassPath(classPath); // �C���X�g�D�������e�[�V�������s�� - Tracer.initialize(new OutputStatementsGenerator(new JSONTraceGenerator()), cp); // �����ŏo�̓t�H�[�}�b�g���w�肷�� +// Tracer.initialize(new OutputStatementsGenerator(new JSONTraceGenerator()), cp); // �����ŏo�̓t�H�[�}�b�g���w�肷�� + Tracer.initialize(new OutputStatementsGenerator(new OnlineTraceGenerator()), cp); // �����ŏo�̓t�H�[�}�b�g���w�肷�� Tracer.packageInstrumentation("", classPath + "/"); } catch (JavaModelException | NotFoundException e) { e.printStackTrace(); diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/MyPrintStream.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/MyPrintStream.java index c201349..3732c3d 100644 --- a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/MyPrintStream.java +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/MyPrintStream.java @@ -68,7 +68,7 @@ // �V���b�g�_�E�����Ƀo�b�t�@�Ɏc�����g���[�X���o�͂��؂� // bFlushed = true; for (String s: output) { - sysout.println(s); + sysout.println(s); } // } } diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/OnlineArrayAdvisor.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/OnlineArrayAdvisor.java new file mode 100644 index 0000000..f929c6a --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/OnlineArrayAdvisor.java @@ -0,0 +1,132 @@ +package org.ntlab.traceCollector.tracer; + +import java.util.ArrayList; + +/** + * �z��ւ̃A�N�Z�X�����o�͂��邽�߂̃N���X (�I�����C����͗p) + * @author �ΒJ�� + * + */ +public class OnlineArrayAdvisor { + public static void arrayWriteInt(Object array, int index, int value) { + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arraySetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, "int", Integer.toString(value), threadId, timeStamp); + ((int [])array)[index] = value; + } + + public static int arrayReadInt(Object array, int index) { + int value = ((int [])array)[index]; + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arrayGetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, "int", Integer.toString(value), threadId, timeStamp); + return value; + } + + public static void arrayWriteLong(Object array, int index, long value) { + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arraySetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, "long", Long.toString(value), threadId, timeStamp); + ((long [])array)[index] = value; + } + + public static long arrayReadLong(Object array, int index) { + long value = ((long [])array)[index]; + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arrayGetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, "long", Long.toString(value), threadId, timeStamp); + return value; + } + + public static void arrayWriteFloat(Object array, int index, float value) { + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arraySetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, "float", Float.toString(value), threadId, timeStamp); + ((float [])array)[index] = value; + } + + public static float arrayReadFloat(Object array, int index) { + float value = ((float [])array)[index]; + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arrayGetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, "float", Float.toString(value), threadId, timeStamp); + return value; + } + + public static void arrayWriteDouble(Object array, int index, double value) { + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arraySetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, "double", Double.toString(value), threadId, timeStamp); + ((double [])array)[index] = value; + } + + public static double arrayReadDouble(Object array, int index) { + double value = ((double [])array)[index]; + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arrayGetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, "double", Double.toString(value), threadId, timeStamp); + return value; + } + + public static void arrayWriteShort(Object array, int index, short value) { + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arraySetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, "short", Short.toString(value), threadId, timeStamp); + ((short [])array)[index] = value; + } + + public static short arrayReadShort(Object array, int index) { + short value = ((short [])array)[index]; + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arrayGetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, "short", Short.toString(value), threadId, timeStamp); + return value; + } + + public static void arrayWriteChar(Object array, int index, char value) { + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arraySetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, "char", Integer.toString(Character.getNumericValue(value)), threadId, timeStamp); + ((char [])array)[index] = value; + } + + public static char arrayReadChar(Object array, int index) { + char value = ((char [])array)[index]; + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arrayGetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, "char", Integer.toString(Character.getNumericValue(value)), threadId, timeStamp); + return value; + } + + public static void arrayWriteByteOrBoolean(Object array, int index, byte value) { + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arraySetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, "byte", Byte.toString(value), threadId, timeStamp); + ((byte [])array)[index] = value; + } + + public static byte arrayReadByteOrBoolean(Object array, int index) { + byte value = ((byte [])array)[index]; + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arrayGetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, "byte", Byte.toString(value), threadId, timeStamp); + return value; + } + + public static void arrayWriteObject(Object array, int index, Object value) { + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arraySetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, + ((value !=null)?value.getClass().getName():"---"), ((value != null)?Integer.toString(System.identityHashCode(value)):"0"), threadId, timeStamp); + ((Object [])array)[index] = value; + } + + public static Object arrayReadObject(Object array, int index) { + Object value = ((Object [])array)[index]; + long threadId = Thread.currentThread().getId(); + long timeStamp = System.nanoTime(); + OnlineTraceGenerator.arrayGetOutput(array.getClass().getName(), Integer.toString(System.identityHashCode(array)), index, + ((value !=null)?value.getClass().getName():"---"), ((value != null)?Integer.toString(System.identityHashCode(value)):"0"), threadId, timeStamp); + return value; + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/OnlineTraceGenerator.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/OnlineTraceGenerator.java new file mode 100644 index 0000000..b98c547 --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/OnlineTraceGenerator.java @@ -0,0 +1,170 @@ +package org.ntlab.traceCollector.tracer; + +import java.util.ArrayList; +import java.util.List; + +import org.ntlab.traceCollector.tracer.trace.TraceJSON; + +import javassist.CtBehavior; +import javassist.CtClass; +import javassist.CtConstructor; +import javassist.CtMethod; + +/** + * �I�����C����͗p�̎��s�������� + * @author Isitani + * + */ +public class OnlineTraceGenerator implements ITraceGenerator { + + @Override + public String generateReplaceStatementsForFieldSet( + String fieldName, String containerClass, String containerObject, + String valueClass, String valueObject, + String threadId, String lineNum, String timeStamp) { + // ���ߍ��ݏ��� + String proceed = "$proceed($$); "; + StringBuilder embedded = new StringBuilder(); + embedded.append(Tracer.TRACER + "OnlineTraceOutput.onlineTraceFieldSet("); + embedded.append(fieldName + ", "); + embedded.append(containerClass + ", String.valueOf(" + containerObject + "), "); + embedded.append(valueClass + ", String.valueOf(" + valueObject + "), "); + embedded.append("String.valueOf(" + threadId + "), " + lineNum + ", " + timeStamp + ");"); + return proceed + embedded; + } + + @Override + public String generateReplaceStatementsForFieldGet( + String fieldName, String thisClass, String thisObject, + String containerClass, String containerObject, + String valueClass, String valueObject, + String threadId, String lineNum, String timeStamp) { + // ���ߍ��ݏ��� + String proceed = "$_ = $proceed(); "; + StringBuilder embedded = new StringBuilder(); + embedded.append(Tracer.TRACER + "OnlineTraceOutput.onlineTraceFieldGet("); + embedded.append(fieldName + ", "); + embedded.append(thisClass + ", String.valueOf(" + thisObject + "), "); + embedded.append(containerClass + ", String.valueOf(" + containerObject + "), "); + embedded.append(valueClass + ", String.valueOf(" + valueObject + "), "); + embedded.append("String.valueOf(" + threadId + "), " + lineNum + ", " + timeStamp + ");"); + return proceed + embedded; + } + + @Override + public String generateReplaceStatementsForNewArray( + String arrayClass, String arrayObject, String dimension, + String threadId, String lineNum, String timeStamp) { + // ���ߍ��ݏ��� + String proceed = "$_ = $proceed($$); "; + StringBuilder embedded = new StringBuilder(); + embedded.append(Tracer.TRACER + "OnlineTraceOutput.onlineTraceArrayCreate("); + embedded.append(arrayClass + ", String.valueOf(" + arrayObject + "), "); + embedded.append(dimension + ", String.valueOf(" + threadId + "), "); + embedded.append(lineNum + ", " + timeStamp + ");"); + return proceed + embedded; + } + + @Override + public String generateInsertBeforeStatements( + CtBehavior m, String methodSignature, + String thisClass, String thisObject, + List argClasses, List argObjects, + String threadId, String timeStamp) { + // ���ߍ��ݏ����ŌĂяo�����\�b�h�ɓn�������̂����A�����f�[�^�𕶎���A���ō쐬���� + StringBuilder args = new StringBuilder(); + String delimiter = ""; + for (int i = 0; i < argClasses.size(); i++) { + args.append(delimiter + argClasses.get(i)); + delimiter = " + \",\" + "; // �����f�[�^���A + "," + �ŋ�؂� + args.append(delimiter + argObjects.get(i)); + } + if (args.toString().isEmpty()) { + args.append("\"\""); + } + + // ���ߍ��ݏ��� + StringBuilder embedded = new StringBuilder(); + boolean isConstructor = (m instanceof CtConstructor); + if (!isConstructor) { + embedded.append(Tracer.TRACER + "OnlineTraceOutput.onlineTraceMethodEntry("); + embedded.append(methodSignature + ", "); + embedded.append(thisClass + ", String.valueOf(" + thisObject + "), "); + embedded.append("String.valueOf(" + threadId + "), " + timeStamp + ", "); + embedded.append(args.toString() + ");"); + } else { + embedded.append(Tracer.TRACER + "OnlineTraceOutput.onlineTraceConstructorEntry("); + embedded.append(methodSignature + ", "); + embedded.append(thisClass + ", String.valueOf(" + thisObject + "), "); + embedded.append("String.valueOf(" + threadId + "), " + timeStamp + ", "); + embedded.append(args.toString() + ");"); + } + return embedded.toString(); + } + + @Override + public String generateInsertAfterStatements(CtClass cls, CtBehavior m, + String thisClass, String thisObject, String returnedClass, String returnedObject, + String threadId, String timeStamp, boolean isCallerSideInstrumentation) { + // ���ߍ��ݏ��� + String shortSignature = "\"" + m.getLongName().replace('$', ',') + "\""; + StringBuilder embedded = new StringBuilder(); + boolean isConstructor = (m instanceof CtConstructor); + if (!isConstructor) { + embedded.append(Tracer.TRACER + "OnlineTraceOutput.onlineTraceMethodExit("); + embedded.append(shortSignature + ", "); + embedded.append(thisClass + ", String.valueOf(" + thisObject + "), "); + embedded.append(returnedClass + ", " + "String.valueOf(" + returnedObject + "), "); + embedded.append("String.valueOf(" + threadId + "), " + timeStamp + ");"); + } else { + embedded.append(Tracer.TRACER + "OnlineTraceOutput.onlineTraceConstructorExit("); + embedded.append(shortSignature + ", "); + embedded.append(returnedClass + ", String.valueOf(" + returnedObject + "), "); + embedded.append("String.valueOf(" + threadId + "), " + timeStamp + ");"); + } + return embedded.toString(); + } + + @Override + public String generateInsertStatementsForCall(CtBehavior m, String lineNum, String threadId) { + // ���ߍ��ݏ��� + String signature = "\"" + m.getLongName().replace('$', '.') + "\""; + StringBuilder embedded = new StringBuilder(); + embedded.append(Tracer.TRACER + "OnlineTraceOutput.onlineTracePreCallMethod("); + embedded.append(signature + ", String.valueOf(" + threadId + "), " + lineNum + ");"); + return embedded.toString(); + } + + @Override + public String generateInsertStatementsForBlockEntry( + CtMethod m, String blockId, String incomings, + String threadId, String lineNum, String timeStamp) { + // ���ߍ��ݏ��� + StringBuilder embedded = new StringBuilder(); + embedded.append(Tracer.TRACER + "OnlineTraceOutput.onlineTraceBlockEntry("); + embedded.append(blockId + ", " + incomings + ", "); + embedded.append("String.valueOf(" + threadId + "), " + lineNum + ", " + timeStamp + ");"); + return embedded.toString(); + } + + @Override + public String generateInsertBeforeStatementsForClassDefinition(String className, String classPath, String loaderPath) { + // ���ߍ��ݏ��� + StringBuilder embedded = new StringBuilder(); + embedded.append(Tracer.TRACER + "OnlineTraceOutput.onlineTraceClassDefinition("); + embedded.append(className + ", " + classPath + ", " + loaderPath + ");"); + return embedded.toString(); + } + + public static void arraySetOutput(String arrayType, String arrayId, int index, String valueType, String valueId, long threadId, long timeStamp) { + // ���ߍ��ݏ��� + OnlineTraceOutput.onlineTraceArraySet(arrayType, arrayId, index, + valueType, valueId, String.valueOf(threadId), timeStamp); + } + + public static void arrayGetOutput(String arrayType, String arrayId, int index, String valueType, String valueId, long threadId, long timeStamp) { + // ���ߍ��ݏ��� + OnlineTraceOutput.onlineTraceArrayGet(arrayType, arrayId, index, + valueType, valueId, String.valueOf(threadId), timeStamp); + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/OnlineTraceOutput.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/OnlineTraceOutput.java new file mode 100644 index 0000000..0dee3a8 --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/OnlineTraceOutput.java @@ -0,0 +1,100 @@ +package org.ntlab.traceCollector.tracer; + +import java.util.HashMap; + +import org.ntlab.traceCollector.tracer.trace.ArrayUpdate; +import org.ntlab.traceCollector.tracer.trace.ClassInfo; +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.ThreadInstance; +import org.ntlab.traceCollector.tracer.trace.TraceJSON; +import org.ntlab.traceCollector.tracer.trace.TracePoint; + +public class OnlineTraceOutput { + + public static void onlineTraceClassDefinition(String className, + String classPath, String loaderPath) { + TraceJSON.onlineTraceClassDefinition(className, classPath, loaderPath); + } + + public static void onlineTracePreCallMethod(String signature, + String threadId, String lineNum) { + TraceJSON.onlineTracePreCallMethod(signature, threadId, lineNum); + } + + public static void onlineTraceMethodEntry(String signature, + String thisClassName, String thisObjectId, String threadId, + long timeStamp, String argList) { + TraceJSON.onlineTraceMethodEntry(signature, thisClassName, + thisObjectId, threadId, timeStamp, argList); + } + + public static void onlineTraceConstructorEntry(String signature, + String thisClassName, String thisObjectId, String threadId, + long timeStamp, String argList) { + TraceJSON.onlineTraceConstructorEntry(signature, thisClassName, + thisObjectId, threadId, timeStamp, argList); + } + + public static void onlineTraceMethodExit(String shortSignature, + String thisClassName, String thisObjectId, String returnClassName, + String returnObjectId, String threadId, long timeStamp) { + TraceJSON.onlineTraceMethodExit(shortSignature, thisClassName, + thisObjectId, returnClassName, returnObjectId, threadId, + timeStamp); + } + + public static void onlineTraceConstructorExit(String shortSignature, + String returnClassName, String returnObjectId, String threadId, + long timeStamp) { + TraceJSON.onlineTraceConstructorExit(shortSignature, returnClassName, + returnObjectId, threadId, timeStamp); + } + + public static void onlineTraceFieldGet(String fieldName, + String thisClassName, String thisObjectId, + String containerClassName, String containerObjectId, + String valueClassName, String valueObjectId, String threadId, + String lineNum, long timeStamp) { + TraceJSON.onlineTraceFieldGet(fieldName, thisClassName, thisObjectId, + containerClassName, containerObjectId, valueClassName, + valueObjectId, threadId, lineNum, timeStamp); + } + + public static void onlineTraceFieldSet(String fieldName, + String containerClassName, String containerObjectId, + String valueClassName, String valueObjectId, String threadId, + String lineNum, long timeStamp) { + TraceJSON.onlineTraceFieldSet(fieldName, containerClassName, + containerObjectId, valueClassName, valueObjectId, threadId, + lineNum, timeStamp); + } + + public static void onlineTraceArrayCreate(String arrayClassName, + String arrayObjectId, String dimension, String threadId, + String lineNum, long timeStamp) { + TraceJSON.onlineTraceArrayCreate(arrayClassName, arrayObjectId, + dimension, threadId, lineNum, timeStamp); + } + + public static void onlineTraceArraySet(String arrayClassName, + String arrayObjectId, int index, String valueClassName, + String valueObjectId, String threadId, long timeStamp) { + TraceJSON.onlineTraceArraySet(arrayClassName, arrayObjectId, index, + valueClassName, valueObjectId, threadId, timeStamp); + } + + public static void onlineTraceArrayGet(String arrayClassName, + String arrayObjectId, int index, String valueClassName, + String valueObjectId, String threadId, long timeStamp) { + TraceJSON.onlineTraceArrayGet(arrayClassName, arrayObjectId, index, + valueClassName, valueObjectId, threadId, timeStamp); + } + + public static void onlineTraceBlockEntry(String blockId, String incomings, + String threadId, String lineNum, long timeStamp) { + TraceJSON.onlineTraceBlockEntry(blockId, incomings, threadId, lineNum, + timeStamp); + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/Tracer.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/Tracer.java index 03f8812..f8171c0 100644 --- a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/Tracer.java +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/Tracer.java @@ -79,7 +79,8 @@ Tracer.conv = new CodeConverter(); if (!(Tracer.outputStatementsGenerator.getGenerator() instanceof PlainTextTraceGenerator)) { try { - CtClass cc = cp.get(TRACER + "JSONArrayAdvisor"); // JSON�̏ꍇ�̂ݔz��A�N�Z�X���o�͂��� +// CtClass cc = cp.get(TRACER + "JSONArrayAdvisor"); // JSON�̏ꍇ�̂ݔz��A�N�Z�X���o�͂��� + CtClass cc = cp.get(TRACER + "OnlineArrayAdvisor"); // �I�����C����͂̏ꍇ�ɔz��A�N�Z�X���o�͂��� conv.replaceArrayAccess(cc, new CodeConverter.DefaultArrayAccessReplacementMethodNames()); } catch (NotFoundException e1) { e1.printStackTrace(); diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ArrayAccess.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ArrayAccess.java new file mode 100644 index 0000000..0ecfc2f --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ArrayAccess.java @@ -0,0 +1,40 @@ +package org.ntlab.traceCollector.tracer.trace; + + +public class ArrayAccess extends Statement { + private String arrayClassName; + private String arrayObjectId; + private int index; + private String valueClassName; + private String valueObjectId; + + public ArrayAccess(String arrayClassName, String arrayObjectId, int index, String valueClassName, String valueObjectId, + int lineNo, String threadNo, long timeStamp) { + super(lineNo, threadNo, timeStamp); + this.arrayClassName = arrayClassName; + this.arrayObjectId = arrayObjectId; + this.index = index; + this.valueClassName = valueClassName; + this.valueObjectId = valueObjectId; + } + + public String getArrayClassName() { + return arrayClassName; + } + + public String getArrayObjectId() { + return arrayObjectId; + } + + public int getIndex() { + return index; + } + + public String getValueClassName() { + return valueClassName; + } + + public String getValueObjectId() { + return valueObjectId; + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ArrayCreate.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ArrayCreate.java new file mode 100644 index 0000000..9932018 --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ArrayCreate.java @@ -0,0 +1,27 @@ +package org.ntlab.traceCollector.tracer.trace; + + +public class ArrayCreate extends Statement { + private String arrayClassName; + private String arrayObjectId; + private int dimension; + + public ArrayCreate(String arrayClassName, String arrayObjectId, int dimension, int lineNo, String threadNo, long timeStamp) { + super(lineNo, threadNo, timeStamp); + this.arrayClassName = arrayClassName; + this.arrayObjectId = arrayObjectId; + this.dimension = dimension; + } + + public String getArrayClassName() { + return arrayClassName; + } + + public String getArrayObjectId() { + return arrayObjectId; + } + + public int getDimension() { + return dimension; + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ArrayUpdate.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ArrayUpdate.java new file mode 100644 index 0000000..4087b32 --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ArrayUpdate.java @@ -0,0 +1,40 @@ +package org.ntlab.traceCollector.tracer.trace; + + +public class ArrayUpdate extends Statement { + private String arrayClassName; + private String arrayObjectId; + private int index; + private String valueClassName; + private String valueObjectId; + + public ArrayUpdate(String arrayClassName, String arrayObjectId, int index, String valueClassName, String valueObjectId, + int lineNo, String threadNo, long timeStamp) { + super(lineNo, threadNo, timeStamp); + this.arrayClassName = arrayClassName; + this.arrayObjectId = arrayObjectId; + this.index = index; + this.valueClassName = valueClassName; + this.valueObjectId = valueObjectId; + } + + public String getArrayClassName() { + return arrayClassName; + } + + public String getArrayObjectId() { + return arrayObjectId; + } + + public int getIndex() { + return index; + } + + public String getValueClassName() { + return valueClassName; + } + + public String getValueObjectId() { + return valueObjectId; + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/AugmentationInfo.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/AugmentationInfo.java new file mode 100644 index 0000000..82e0fed --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/AugmentationInfo.java @@ -0,0 +1,5 @@ +package org.ntlab.traceCollector.tracer.trace; + +abstract public class AugmentationInfo { + +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/BlockEnter.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/BlockEnter.java new file mode 100644 index 0000000..b7c454c --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/BlockEnter.java @@ -0,0 +1,21 @@ +package org.ntlab.traceCollector.tracer.trace; + + +public class BlockEnter extends Statement { + private int blockId; + private int incomings; + + public BlockEnter(int blockId, int incomings, int lineNo, String threadNo, long timeStamp) { + super(lineNo, threadNo, timeStamp); + this.blockId = blockId; + this.incomings = incomings; + } + + public int getBlockId() { + return blockId; + } + + public int getIncomings() { + return incomings; + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ClassInfo.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ClassInfo.java new file mode 100644 index 0000000..9bb12ba --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ClassInfo.java @@ -0,0 +1,25 @@ +package org.ntlab.traceCollector.tracer.trace; + +public class ClassInfo { + private String name; + private String path; + private String loaderPath; + + public ClassInfo(String name, String path, String loaderPath) { + this.name = name; + this.path = path; + this.loaderPath = loaderPath; + } + + public String getName() { + return name; + } + + public String getPath() { + return path; + } + + public String getLoaderPath() { + return loaderPath; + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/FieldAccess.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/FieldAccess.java new file mode 100644 index 0000000..36d8284 --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/FieldAccess.java @@ -0,0 +1,81 @@ +package org.ntlab.traceCollector.tracer.trace; + + +public class FieldAccess extends Statement { + private String fieldName; + private String containerClassName; + private String containerObjId; + private String valueClassName; + private String valueObjId; + protected String thisClassName; + protected String thisObjId; + + public FieldAccess(String valueClassName, String valueObjId, String containerClassName, + String containerObjId, String thisClassName, String thisObjId, + int lineNo, String threadNo) { + super(lineNo, threadNo); + this.containerClassName = containerClassName; + this.containerObjId = containerObjId; + this.valueClassName = valueClassName; + this.valueObjId = valueObjId; + this.thisClassName = thisClassName; + this.thisObjId = thisObjId; + } + + public FieldAccess(String valueClassName, String valueObjId, String containerClassName, + String containerObjId, String thisClassName, String thisObjId, + int lineNo, String threadNo, long timeStamp) { + super(lineNo, threadNo, timeStamp); + this.containerClassName = containerClassName; + this.containerObjId = containerObjId; + this.valueClassName = valueClassName; + this.valueObjId = valueObjId; + this.thisClassName = thisClassName; + this.thisObjId = thisObjId; + } + + public FieldAccess(String fieldName, String valueClassName, String valueObjId, String containerClassName, + String containerObjId, String thisClassName, String thisObjId, + int lineNo, String threadNo, long timeStamp) { + super(lineNo, threadNo, timeStamp); + this.fieldName = fieldName; + this.containerClassName = containerClassName; + this.containerObjId = containerObjId; + this.valueClassName = valueClassName; + this.valueObjId = valueObjId; + this.thisClassName = thisClassName; + this.thisObjId = thisObjId; + } + + public String getFieldName() { + return fieldName; + } + + public String getContainerClassName() { + return containerClassName; + } + + public String getContainerObjId() { + return containerObjId; + } + + public String getValueClassName() { + return valueClassName; + } + + public String getValueObjId() { + return valueObjId; + } + + public String getThisClassName() { + return thisClassName; + } + + public String getThisObjId() { + return thisObjId; + } + + public Reference getReference() { + return new Reference(containerObjId, valueObjId, containerClassName, valueClassName); + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/FieldUpdate.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/FieldUpdate.java new file mode 100644 index 0000000..6261ec8 --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/FieldUpdate.java @@ -0,0 +1,62 @@ +package org.ntlab.traceCollector.tracer.trace; + + +public class FieldUpdate extends Statement { + private String fieldName; + private String containerClassName; + private String containerObjId; + private String valueClassName; + private String valueObjId; + + public FieldUpdate(String valueClassName, String valueObjId, String containerClassName, String containerObjId, + int lineNo, String threadNo) { + super(lineNo, threadNo); + this.containerClassName = containerClassName; + this.containerObjId = containerObjId; + this.valueClassName = valueClassName; + this.valueObjId = valueObjId; + } + + public FieldUpdate(String valueClassName, String valueObjId, String containerClassName, String containerObjId, + int lineNo, String threadNo, long timeStamp) { + super(lineNo, threadNo, timeStamp); + this.containerClassName = containerClassName; + this.containerObjId = containerObjId; + this.valueClassName = valueClassName; + this.valueObjId = valueObjId; + } + + public FieldUpdate(String fieldName, String valueClassName, String valueObjId, String containerClassName, String containerObjId, + int lineNo, String threadNo, long timeStamp) { + super(lineNo, threadNo, timeStamp); + this.fieldName = fieldName; + this.containerClassName = containerClassName; + this.containerObjId = containerObjId; + this.valueClassName = valueClassName; + this.valueObjId = valueObjId; + } + + public String getFieldName() { + return fieldName; + } + + public String getContainerClassName() { + return containerClassName; + } + + public String getContainerObjId() { + return containerObjId; + } + + public String getValueClassName() { + return valueClassName; + } + + public String getValueObjId() { + return valueObjId; + } + + public Reference getReference() { + return new Reference(containerObjId, valueObjId, containerClassName, valueClassName); + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/IMethodExecutionVisitor.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/IMethodExecutionVisitor.java new file mode 100644 index 0000000..7890d72 --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/IMethodExecutionVisitor.java @@ -0,0 +1,10 @@ +package org.ntlab.traceCollector.tracer.trace; + +import java.util.ArrayList; + +public interface IMethodExecutionVisitor { + abstract public boolean preVisitThread(ThreadInstance thread); + abstract public boolean postVisitThread(ThreadInstance thread); + abstract public boolean preVisitMethodExecution(MethodExecution methodExecution); + abstract public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children); +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/IStatementVisitor.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/IStatementVisitor.java new file mode 100644 index 0000000..6fe1473 --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/IStatementVisitor.java @@ -0,0 +1,7 @@ +package org.ntlab.traceCollector.tracer.trace; + + +public interface IStatementVisitor { + abstract public boolean preVisitStatement(Statement statement); + abstract public boolean postVisitStatement(Statement statement); +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/MethodExecution.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/MethodExecution.java new file mode 100644 index 0000000..c16140c --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/MethodExecution.java @@ -0,0 +1,281 @@ +package org.ntlab.traceCollector.tracer.trace; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +public class MethodExecution { + private String signature; + private String callerSideSignature; + private String thisClassName; + private String thisObjId; + private ArrayList arguments; + private ObjectReference returnValue = null; + private boolean isConstructor; + private boolean isStatic; + private boolean isCollectionType; + private ArrayList statements = new ArrayList(); + private ArrayList children = new ArrayList(); + private MethodExecution callerMethodExecution = null; + private int callerStatementExecution = -1; + private boolean isTerminated = false; + private AugmentationInfo augmentation = null; + private long entryTime = 0L; + private long exitTime = 0L; + + public MethodExecution(String signature, String callerSideSignature, + String thisClassName, String thisObjId, boolean isConstructor, + boolean isStatic, long enterTime) { + this.signature = signature; + this.callerSideSignature = callerSideSignature; + this.thisClassName = thisClassName; + this.thisObjId = thisObjId; + this.isConstructor = isConstructor; + this.isStatic = isStatic; + this.isCollectionType = false; + this.isTerminated = false; + this.entryTime = enterTime; + } + + public void setArguments(ArrayList arguments) { + this.arguments = arguments; + } + + public void setThisObjeId(String thisObjId) { + this.thisObjId = thisObjId; + } + + public void setReturnValue(ObjectReference returnValue) { + this.returnValue = returnValue; + } + + public void setCollectionType(boolean isCollectionType) { + this.isCollectionType = isCollectionType; + } + + public void setTerminated(boolean isTerminated) { + this.isTerminated = isTerminated; + } + + public String getDeclaringClassName() { + return Trace.getDeclaringType(signature, isConstructor); + } + + public String getSignature() { + return signature; + } + + public String getCallerSideSignature() { + return callerSideSignature; + } + + public String getThisClassName() { + return thisClassName; + } + + public String getThisObjId() { + if (isStatic) return Trace.getNull(); + return thisObjId; + } + + public ArrayList getArguments() { + if (arguments == null) arguments = new ArrayList(); + return arguments; + } + + public ObjectReference getReturnValue() { + return returnValue; + } + + public boolean isConstructor() { + return isConstructor; + } + + public boolean isStatic() { + return isStatic; + } + + public boolean isCollectionType() { + return isCollectionType; + } + + public boolean isTerminated() { + return isTerminated; + } + + public long getEntryTime() { + return entryTime; + } + + public long getExitTime() { + return exitTime; + } + + public void setExitTime(long exitTime) { + this.exitTime = exitTime; + } + + public void addStatement(Statement statement) { + statements.add(statement); + if (statement instanceof MethodInvocation) { + children.add(((MethodInvocation)statement).getCalledMethodExecution()); + } + } + + public ArrayList getStatements() { + return statements; + } + + public ArrayList getChildren() { + return children; + } + + public void setCaller(MethodExecution callerMethodExecution, int callerStatementExecution) { + this.callerMethodExecution = callerMethodExecution; + this.callerStatementExecution = callerStatementExecution; + } + + public MethodExecution getParent() { + return callerMethodExecution; + } + + public TracePoint getEntryPoint() { + return new TracePoint(this, 0); + } + + public TracePoint getExitPoint() { + return new TracePoint(this, statements.size() - 1); + } + + public TracePoint getExitOutPoint() { + return new TracePoint(this, statements.size()); + } + + public MethodExecution getCallerMethodExecution() { + return callerMethodExecution; + } + + public int getCallerStatementExecution() { + return callerStatementExecution; + } + + public TracePoint getCallerTracePoint() { + if (callerMethodExecution == null) return null; + return new TracePoint(callerMethodExecution, callerStatementExecution); + } + + /** + * ���̃��\�b�h���s����т��̑S�Ăяo������Ăяo���؂̒��ŋt�����ɒT������(�������Avisitor �� true ��Ԃ��܂�) + * @param visitor �r�W�^�[ + * @return�@true -- �T���𒆒f����, false -- �Ō�܂ŒT������ + */ + public boolean traverseMethodExecutionsBackward(IMethodExecutionVisitor visitor) { + if (visitor.preVisitMethodExecution(this)) return true; + ArrayList calledMethodExecutions = getChildren(); + for (int i = calledMethodExecutions.size() - 1; i >= 0; i--) { + MethodExecution child = calledMethodExecutions.get(i); + if (child.traverseMethodExecutionsBackward(visitor)) return true; + } + if (visitor.postVisitMethodExecution(this, null)) return true; + return false; + } + + public void traverseMarkedMethodExecutions(IMethodExecutionVisitor visitor, long markStart, long markEnd) { + if (entryTime <= markEnd) { + if (entryTime >= markStart) { + ArrayList markedChildren = new ArrayList(); + visitor.preVisitMethodExecution(this); + for (int i = 0; i < children.size(); i++) { + MethodExecution child = children.get(i); + if (child.getEntryTime() <= markEnd) { + child.traverseMarkedMethodExecutions(visitor, markStart, markEnd); + markedChildren.add(child); + } else { + break; + } + } + visitor.postVisitMethodExecution(this, markedChildren); + } else { + for (int i = 0; i < children.size(); i++) { + MethodExecution child = children.get(i); + if (child.getEntryTime() <= markEnd) { + child.traverseMarkedMethodExecutions(visitor, markStart, markEnd); + } + } + } + } + } + + public void getMarkedMethodSignatures(HashSet signatures, long markStart, long markEnd) { + if (entryTime <= markEnd) { + if (entryTime >= markStart) { + signatures.add(getSignature()); + } + for (int i = 0; i < children.size(); i++) { + MethodExecution child = children.get(i); + child.getMarkedMethodSignatures(signatures, markStart, markEnd); + } + } + } + + public void getUnmarkedMethodSignatures(HashSet signatures, long markStart, long markEnd) { + if (entryTime < markStart || entryTime > markEnd) { + signatures.add(getSignature()); + for (int i = 0; i < children.size(); i++) { + MethodExecution child = children.get(i); + child.getUnmarkedMethodSignatures(signatures, markStart, markEnd); + } + } else { + for (int i = 0; i < children.size(); i++) { + MethodExecution child = children.get(i); + child.getUnmarkedMethodSignatures(signatures, markStart, markEnd); + } + } + } + + public void getUnmarkedMethodExecutions(HashMap> allExecutions, long markStart, long markEnd) { + if (entryTime < markStart || entryTime > markEnd) { + ArrayList executions = allExecutions.get(getSignature()); + if (executions == null) { + executions = new ArrayList<>(); + allExecutions.put(getSignature(), executions); + } + executions.add(this); + for (int i = 0; i < children.size(); i++) { + MethodExecution child = children.get(i); + child.getUnmarkedMethodExecutions(allExecutions, markStart, markEnd); + } + } else { + for (int i = 0; i < children.size(); i++) { + MethodExecution child = children.get(i); + child.getUnmarkedMethodExecutions(allExecutions, markStart, markEnd); + } + } + } + + public AugmentationInfo getAugmentation() { + return augmentation; + } + + public void setAugmentation(AugmentationInfo augmentation) { + this.augmentation = augmentation; + } + + /** + *�@�����œn���ꂽmethodExecution���Ăяo�������\�b�h�Ăяo����T���ĕԂ� + * @param child ����methodExecution����Ăяo���ꂽ���Ƃ̂���ʂ�methodExecution + * @return �����œn���ꂽmethodExecution���Ăяo�������Ƃ��L�^���Ă��郁�\�b�h�Ăяo�� + */ + public MethodInvocation getMethodInvocation(MethodExecution child) { + for (Statement statement : statements) { + if (statement instanceof MethodInvocation) { + MethodExecution calledMethodExecution = ((MethodInvocation)statement).getCalledMethodExecution(); + if (calledMethodExecution.equals(child)) { + return (MethodInvocation)statement; + } + } + } + return null; + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/MethodInvocation.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/MethodInvocation.java new file mode 100644 index 0000000..923d6c8 --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/MethodInvocation.java @@ -0,0 +1,52 @@ +package org.ntlab.traceCollector.tracer.trace; + + +public class MethodInvocation extends Statement { + private MethodExecution calledMethodExecution = null; + protected String thisClassName; + protected String thisObjId; + protected String callerSideMethodName = null; + + public MethodInvocation(MethodExecution methodExecution, String thisClassName, String thisObjId, + int lineNo, String threadNo) { + super(lineNo, threadNo); + this.calledMethodExecution = methodExecution; + this.thisClassName = thisClassName; + this.thisObjId = thisObjId; + } + + public MethodInvocation(String callerSideMethodName, String thisClassName, String thisObjId, + int lineNo, String threadNo) { + super(lineNo, threadNo); + this.callerSideMethodName = callerSideMethodName; + this.thisClassName = thisClassName; + this.thisObjId = thisObjId; + } + + public long getTimeStamp() { + if (calledMethodExecution != null) { + return calledMethodExecution.getEntryTime(); + } + return timeStamp; + } + + public void setCalledMethodExecution(MethodExecution calledMethodExecution) { + this.calledMethodExecution = calledMethodExecution; + } + + public MethodExecution getCalledMethodExecution() { + return calledMethodExecution; + } + + public String getThisClassName() { + return thisClassName; + } + + public String getThisObjId() { + return calledMethodExecution.getCallerMethodExecution().getThisObjId(); + } + + public String getCallerSideMethodName() { + return callerSideMethodName; + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ObjectReference.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ObjectReference.java new file mode 100644 index 0000000..cee6c4b --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ObjectReference.java @@ -0,0 +1,70 @@ +package org.ntlab.traceCollector.tracer.trace; + +public class ObjectReference { + private String id; + private String actualType = null; // ���ۂ̌^ + private String calleeType = null; // �Ăяo���惁�\�b�h���ł̌^(�ÓI�Ɍ���ł���^) + private String callerType = null; // �Ăяo�������\�b�h���ł̌^(�ÓI�Ɍ���ł���^) + + public ObjectReference(String id) { + this.id = id; + this.actualType = null; + } + + public ObjectReference(String id, String actualType) { + this.id = id; + this.actualType = actualType; + } + + public ObjectReference(String id, String actualType, String calleeType) { + this.id = id; + this.actualType = actualType; + this.calleeType = calleeType; + } + + public ObjectReference(String id, String actualType, String calleeType, String callerType) { + this.id = id; + this.actualType = actualType; + this.calleeType = calleeType; + this.callerType = callerType; + } + + public String getId() { + return id; + } + + public String getActualType() { + return actualType; + } + + public String getCalleeType() { + return calleeType; + } + + public String getCallerType() { + return callerType; + } + + public void setId(String id) { + this.id = id; + } + + public void setActualType(String actualType) { + this.actualType = actualType; + } + + public void setCalleeType(String calleeType) { + this.calleeType = calleeType; + } + + public void setCallerType(String callerType) { + this.callerType = callerType; + } + + public boolean equals(Object other) { + if (this == other) return true; + if (!(other instanceof ObjectReference)) return false; + if (id != null && id.equals(((ObjectReference)other).id)) return true; + return false; + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/Reference.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/Reference.java new file mode 100644 index 0000000..79985c9 --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/Reference.java @@ -0,0 +1,120 @@ +package org.ntlab.traceCollector.tracer.trace; + + +public class Reference { + private String id; + private ObjectReference srcObj; // �Q�ƌ��I�u�W�F�N�g + private ObjectReference dstObj; // �Q�Ɛ�I�u�W�F�N�g + private boolean bCreation = false; // �Q�ƌ��I�u�W�F�N�g���Q�Ɛ�I�u�W�F�N�g�𐶐�������? + private boolean bArray = false; // �Q�ƌ��I�u�W�F�N�g���z��ŎQ�Ɛ�I�u�W�F�N�g��v�f�Ƃ��ĕێ����Ă��邩? + private boolean bCollection = false; // �Q�ƌ��I�u�W�F�N�g���R���N�V�����ŎQ�Ɛ�I�u�W�F�N�g��v�f�Ƃ��ĕێ����Ă��邩? + private boolean bFinalLocal = false; // �Q�ƌ��I�u�W�F�N�g�������܂��͓����N���X�̂Ƃ��Q�Ɛ�I�u�W�F�N�g���O���N���X�� final local �ϐ��Ƃ��ĎQ�Ƃ��Ă��邩? + + public Reference(String srcObjectId, String dstObjectId, String srcClassName, + String dstClassName) { + srcObj = new ObjectReference(srcObjectId, srcClassName); + dstObj = new ObjectReference(dstObjectId, dstClassName); + } + + public Reference(ObjectReference srcObj, ObjectReference dstObj) { + this.srcObj = srcObj; + this.dstObj = dstObj; + } + + public ObjectReference getSrcObject() { + return srcObj; + } + + public ObjectReference getDstObject() { + return dstObj; + } + + public void setSrcClassName(String srcClassName) { + this.srcObj.setActualType(srcClassName); + } + + public void setDstClassName(String dstClassName) { + this.dstObj.setActualType(dstClassName); + } + + public void setSrcObjectId(String srcObjectId) { + this.srcObj.setId(srcObjectId); + } + + public void setDstObjectId(String dstObjectId) { + this.dstObj.setId(dstObjectId); + } + + public String getSrcClassName() { + return srcObj.getActualType(); + } + + public String getDstClassName() { + return dstObj.getActualType(); + } + + public String getSrcObjectId() { + return srcObj.getId(); + } + + public String getDstObjectId() { + return dstObj.getId(); + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public void setCreation(boolean bCreation) { + this.bCreation = bCreation; + } + + public boolean isCreation(){ + return bCreation; + } + + public void setArray(boolean bArray) { + this.bArray = bArray; + } + + public boolean isArray() { + return bArray; + } + + public void setCollection(boolean bCollection) { + this.bCollection = bCollection; + } + + public boolean isCollection() { + return bCollection; + } + + public void setFinalLocal(boolean bFinalLocal) { + this.bFinalLocal = bFinalLocal; + } + + public boolean isFinalLocal() { + return bFinalLocal; + } + + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof Reference) { + if (this.hashCode() != o.hashCode()) return false; + return (this.srcObj.getId().equals(((Reference)o).srcObj.getId()) && this.dstObj.getId().equals(((Reference)o).dstObj.getId())); + } + return false; + } + + public int hashCode() { + return Integer.parseInt(srcObj.getId()) + Integer.parseInt(dstObj.getId()); + } + + public String toString() { + return srcObj.getId() + "(" + srcObj.getActualType() + ")" + "->" + dstObj.getId() + "(" + dstObj.getActualType() + ")"; + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/Statement.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/Statement.java new file mode 100644 index 0000000..c669fee --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/Statement.java @@ -0,0 +1,29 @@ +package org.ntlab.traceCollector.tracer.trace; + +public class Statement { + protected int lineNo; + protected String threadNo; + protected long timeStamp = 0L; + + public Statement(int lineNo, String threadNo) { + this.lineNo = lineNo; + this.threadNo = threadNo; + } + + public Statement(int lineNo, String threadNo, long timeStamp) { + this(lineNo, threadNo); + this.timeStamp = timeStamp; + } + + public int getLineNo() { + return lineNo; + } + + public String getThreadNo() { + return threadNo; + } + + public long getTimeStamp() { + return timeStamp; + } +} \ No newline at end of file diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ThreadInstance.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ThreadInstance.java new file mode 100644 index 0000000..faf635c --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/ThreadInstance.java @@ -0,0 +1,178 @@ +package org.ntlab.traceCollector.tracer.trace; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +public class ThreadInstance { + private ArrayList roots = new ArrayList(); + private MethodExecution curMethodExecution = null; + private MethodInvocation curMethodInvocation = null; + private String id; + + public ThreadInstance(String id) { + this.id = id; + } + + public void addRoot(MethodExecution root) { + this.roots.add(root); + curMethodExecution = root; + } + + public ArrayList getRoot() { + return roots; + } + + public String getId() { + return id; + } + + public void preCallMethod(String callerSideSignature, int lineNumOfInvocationStatement) { + if (curMethodExecution != null) { + curMethodInvocation = new MethodInvocation(callerSideSignature, curMethodExecution.getThisClassName(), curMethodExecution.getThisObjId(), lineNumOfInvocationStatement, id); + } + } + + public void callMethod(String signature, String callerSideSignature, String receiverClassName, String receiverObjId, + boolean isConstractor, boolean isStatic, long timeStamp) { + if (callerSideSignature == null && curMethodInvocation != null) { + callerSideSignature = curMethodInvocation.getCallerSideMethodName(); + } + MethodExecution newMethodExecution = new MethodExecution(signature, callerSideSignature, receiverClassName, receiverObjId, isConstractor, isStatic, timeStamp); + if (curMethodExecution != null) { + if (curMethodInvocation == null) { + curMethodExecution.addStatement(new MethodInvocation(newMethodExecution, curMethodExecution.getThisClassName(), curMethodExecution.getThisObjId(), 0, id)); + } else { + curMethodInvocation.setCalledMethodExecution(newMethodExecution); + curMethodExecution.addStatement(curMethodInvocation); + curMethodInvocation = null; + } + newMethodExecution.setCaller(curMethodExecution, curMethodExecution.getStatements().size() - 1); + curMethodExecution = newMethodExecution; + } else { + addRoot(newMethodExecution); + } + } + + public void setArgments(ArrayList arguments) { + curMethodExecution.setArguments(arguments); + } + + public void returnMethod(ObjectReference returnValue, String thisObjId, boolean isCollectionType) { + if (curMethodExecution == null) return; + curMethodExecution.setReturnValue(returnValue); + if (curMethodExecution.getThisObjId().equals("0")) { + curMethodExecution.setThisObjeId(thisObjId); + } + curMethodExecution.setCollectionType(isCollectionType); + curMethodExecution = curMethodExecution.getParent(); + curMethodInvocation = null; // �O�̂��� + } + + public void returnMethod(ObjectReference returnValue, String thisObjId, boolean isCollectionType, long exitTime) { + if (curMethodExecution != null) curMethodExecution.setExitTime(exitTime); + returnMethod(returnValue, thisObjId, isCollectionType); + } + + public void terminateMethod() { + if (curMethodExecution == null) return; + curMethodExecution.setTerminated(true); + curMethodExecution = curMethodExecution.getParent(); + } + + public void fieldAccess(String valueClassName, String valueObjId, String containerClassName, String containerObjId, String thisClassName, String thisId) { + FieldAccess fieldAccess = new FieldAccess(valueClassName, valueObjId, containerClassName, containerObjId, thisClassName, thisId, 0, id); + if (curMethodExecution != null) curMethodExecution.addStatement(fieldAccess); + } + + public void fieldAccess(String valueClassName, String valueObjId, String containerClassName, String containerObjId, String thisClassName, String thisId, int lineNo, long timeStamp) { + FieldAccess fieldAccess = new FieldAccess(valueClassName, valueObjId, containerClassName, containerObjId, thisClassName, thisId, lineNo, id, timeStamp); + if (curMethodExecution != null) curMethodExecution.addStatement(fieldAccess); + } + + public void fieldAccess(String fieldName, String valueClassName, String valueObjId, String containerClassName, String containerObjId, String thisClassName, String thisId, int lineNo, long timeStamp) { + FieldAccess fieldAccess = new FieldAccess(fieldName, valueClassName, valueObjId, containerClassName, containerObjId, thisClassName, thisId, lineNo, id, timeStamp); + if (curMethodExecution != null) curMethodExecution.addStatement(fieldAccess); + } + + public void fieldUpdate(String valueClassName, String valueObjId, String containerClassName, String containerObjId) { + FieldUpdate fieldUpdate = new FieldUpdate(valueClassName, valueObjId, containerClassName, containerObjId, 0, id); + if (curMethodExecution != null) curMethodExecution.addStatement(fieldUpdate); + } + + public void fieldUpdate(String valueClassName, String valueObjId, String containerClassName, String containerObjId, int lineNo, long timeStamp) { + FieldUpdate fieldUpdate = new FieldUpdate(valueClassName, valueObjId, containerClassName, containerObjId, lineNo, id, timeStamp); + if (curMethodExecution != null) curMethodExecution.addStatement(fieldUpdate); + } + + public void fieldUpdate(String fieldName, String valueClassName, String valueObjId, String containerClassName, String containerObjId, int lineNo, long timeStamp) { + FieldUpdate fieldUpdate = new FieldUpdate(fieldName, valueClassName, valueObjId, containerClassName, containerObjId, lineNo, id, timeStamp); + if (curMethodExecution != null) curMethodExecution.addStatement(fieldUpdate); + } + + public void arrayCreate(String arrayClassName, String arrayObjectId, int dimension, int lineNo, long timeStamp) { + ArrayCreate arrayCreate = new ArrayCreate(arrayClassName, arrayObjectId, dimension, lineNo, id, timeStamp); + if (curMethodExecution != null) curMethodExecution.addStatement(arrayCreate); + } + + public void arraySet(String arrayClassName, String arrayObjectId, int index, String valueClassName, String valueObjectId, int lineNo, long timeStamp) { + ArrayUpdate arraySet = new ArrayUpdate(arrayClassName, arrayObjectId, index, valueClassName, valueObjectId, lineNo, id, timeStamp); + if (curMethodExecution != null) curMethodExecution.addStatement(arraySet); + } + + public void arrayGet(String arrayClassName, String arrayObjectId, int index, String valueClassName, String valueObjectId, int lineNo, long timeStamp) { + ArrayAccess arrayGet = new ArrayAccess(arrayClassName, arrayObjectId, index, valueClassName, valueObjectId, lineNo, id, timeStamp); + if (curMethodExecution != null) curMethodExecution.addStatement(arrayGet); + } + + public void blockEnter(int blockId, int incomings, int lineNo, long timeStamp) { + BlockEnter blockEnter = new BlockEnter(blockId, incomings, lineNo, id, timeStamp); + if (curMethodExecution != null) curMethodExecution.addStatement(blockEnter); + } + + public void traverseMethodExecutionsBackward(IMethodExecutionVisitor visitor) { + visitor.preVisitThread(this); + for (int i = 0; i < roots.size(); i++) { + MethodExecution root = roots.get(i); + root.traverseMethodExecutionsBackward(visitor); + } + visitor.postVisitThread(this); + } + + public void traverseMarkedMethodExecutions(IMethodExecutionVisitor visitor, long markStart, long markEnd) { + visitor.preVisitThread(this); + for (int i = 0; i < roots.size(); i++) { + MethodExecution root = roots.get(i); + if (root.getEntryTime() <= markEnd) { + root.traverseMarkedMethodExecutions(visitor, markStart, markEnd); + } else { + break; + } + } + visitor.postVisitThread(this); + } + + public void getUnmarkedMethodSignatures(HashSet signatures, long markStart, long markEnd) { + for (int i = 0; i < roots.size(); i++) { + MethodExecution root = roots.get(i); + root.getUnmarkedMethodSignatures(signatures, markStart, markEnd); + } + } + + public void getUnmarkedMethodExecutions(HashMap> executions, long markStart, long markEnd) { + for (int i = 0; i < roots.size(); i++) { + MethodExecution root = roots.get(i); + root.getUnmarkedMethodExecutions(executions, markStart, markEnd); + } + } + + public MethodExecution getCurrentMethodExecution() { + return curMethodExecution; + } + + public TracePoint getCurrentTracePoint() { + return new TracePoint(curMethodExecution, curMethodExecution.getStatements().size() - 1); + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/Trace.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/Trace.java new file mode 100644 index 0000000..9fc31cf --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/Trace.java @@ -0,0 +1,1230 @@ +package org.ntlab.traceCollector.tracer.trace; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Stack; + +public class Trace { + protected static final boolean EAGER_DETECTION_OF_ARRAY_SET = false; // �z��v�f�ւ̑���̌��o�𑽂����ς��邩?(�������ς����False Positive�ɂȂ�”\��������) + protected static Trace theTrace = null; + protected HashMap threads = new HashMap(); + + protected Trace() { + } + + /** + * �w�肵��PlainText�̃g���[�X�t�@�C������ǂ��� Trace �I�u�W�F�N�g�𐶐����� + * @param file �g���[�X�t�@�C�� + */ + public Trace(BufferedReader file) { + try { + read(file); + file.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * �w�肵��PlainText�̃g���[�X�t�@�C������ǂ��� Trace �I�u�W�F�N�g�𐶐����� + * @param traceFile �g���[�X�t�@�C���̃p�X + */ + public Trace(String traceFile) { + BufferedReader file; + try { + file = new BufferedReader(new FileReader(traceFile)); + read(file); + file.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static Trace getInstance() { + if (theTrace == null) { + theTrace = new Trace(); + } + return theTrace; + } + + private void read(BufferedReader file) throws IOException { + // �g���[�X�t�@�C���ǂݍ��� + String line, prevLine = null; + String signature; + String callerSideSignature; + String threadNo = null; + String[] methodData; + String[] argData; + String[] returnData; + String[] accessData; + String[] updateData; + String thisObjectId; + String thisClassName; + boolean isConstractor = false; + boolean isCollectionType = false; + boolean isStatic = false; + long timeStamp = 0L; + ThreadInstance thread = null; + HashMap> stacks = new HashMap>(); + while ((line = file.readLine()) != null) { + // �g���[�X�t�@�C���̉�� + if (line.startsWith("Method")) { + // ���\�b�h�Ăяo���i�R���X�g���N�^�Ăяo�����܂ށj + methodData = line.split(":"); + int n = methodData[0].indexOf(','); + signature = methodData[0].substring(n + 1); + threadNo = methodData[methodData.length - 1].split(" ")[1]; + thisObjectId = methodData[1]; + thisClassName = methodData[0].substring(0, n).split(" ")[1]; + isConstractor = false; + isStatic = false; + if (signature.contains("static ")) { + isStatic = true; + } + callerSideSignature = signature; + timeStamp = Long.parseLong(methodData[methodData.length - 2]); + if (prevLine != null) { + if (prevLine.startsWith("New")) { + isConstractor = true; + } else if (prevLine.startsWith("Invoke")) { + callerSideSignature = prevLine.split(":")[1]; + } + } + thread = threads.get(threadNo); + Stack stack; + if (thread == null) { + thread = new ThreadInstance(threadNo); + threads.put(threadNo, thread); + stack = new Stack(); + stacks.put(threadNo, stack); + } else { + stack = stacks.get(threadNo); + } + stack.push(line); + thread.callMethod(signature, callerSideSignature, thisClassName, thisObjectId, isConstractor, isStatic, timeStamp); + } else if (line.startsWith("Args")) { + // ���\�b�h�Ăяo���̈��� + argData = line.split(":"); + threadNo = argData[argData.length - 1].split(" ")[1]; + thread = threads.get(threadNo); + ArrayList arguments = new ArrayList(); + for (int k = 1; k < argData.length - 2; k += 2) { + arguments.add(new ObjectReference(argData[k+1], argData[k])); + } + thread.setArgments(arguments); + } else if (line.startsWith("Return")) { + // ���\�b�h����̕��A + returnData = line.split(":"); + threadNo = returnData[returnData.length - 1].split(" ")[1]; + Stack stack = stacks.get(threadNo); + if (!stack.isEmpty()) { + String line2 = stack.peek(); + if (line2.split("\\(")[0].endsWith(line.split("\\(")[1])) { + stack.pop(); + } else { + do { + stack.pop(); + thread.terminateMethod(); + line2 = stack.peek(); + } while (!stack.isEmpty() && !line2.split("\\(")[0].endsWith(line.split("\\(")[1])); + if (!stack.isEmpty()) stack.pop(); + } + thread = threads.get(threadNo); + ObjectReference returnValue = new ObjectReference(returnData[2], returnData[1]); + thisObjectId = returnData[2]; + isCollectionType = false; + String curLine = returnData[0]; + if(curLine.contains("Return call(List") + || curLine.contains("Return call(Vector") + || curLine.contains("Return call(Iterator") + || curLine.contains("Return call(ListIterator") + || curLine.contains("Return call(ArrayList") + || curLine.contains("Return call(Stack") + || curLine.contains("Return call(Hash") + || curLine.contains("Return call(Map") + || curLine.contains("Return call(Set") + || curLine.contains("Return call(Linked") + || curLine.contains("Return call(Thread")) { + isCollectionType = true; + } + thread.returnMethod(returnValue, thisObjectId, isCollectionType); + } + } else if (line.startsWith("get")) { + // �t�B�[���h�A�N�Z�X + accessData = line.split(":"); + threadNo = accessData[8].split(" ")[1]; + thread = threads.get(threadNo); + if (thread != null) thread.fieldAccess(accessData[5], accessData[6], accessData[3], accessData[4], accessData[1], accessData[2]); + } else if (line.startsWith("set")) { + // �t�B�[���h�X�V + updateData = line.split(":"); + threadNo = updateData[6].split(" ")[1]; + thread = threads.get(threadNo); + if (thread != null) thread.fieldUpdate(updateData[3], updateData[4], updateData[1], updateData[2]); + } + prevLine = line; + } + } + + /** + * �S�X���b�h���擾���� + * @return �X���b�hID����X���b�h�C���X�^���X�ւ̃}�b�v + */ + public HashMap getAllThreads() { + return threads; + } + + /** + * �w�肵���X���b�h��Ō��ݎ��s���̃��\�b�h���s���擾����(�I�����C����͗p) + * @param thread �ΏۃX���b�h + * @return thread ��Ō��ݎ��s���̃��\�b�h���s + */ + public static MethodExecution getCurrentMethodExecution(Thread thread) { + ThreadInstance t = getInstance().threads.get(String.valueOf(thread.getId())); + return t.getCurrentMethodExecution(); + } + + /** + * �w�肵���X���b�h��Ō��ݎ��s���̃g���[�X�|�C���g���擾����(�I�����C����͗p) + * @param thread �ΏۃX���b�h + * @return thread ��Ō��ݎ��s���̎��s���̃g���[�X�|�C���g + */ + public static TracePoint getCurrentTracePoint(Thread thread) { + ThreadInstance t = getInstance().threads.get(String.valueOf(thread.getId())); + return t.getCurrentTracePoint(); + } + + /** + * methodSignature �ɑO����v���郁�\�b�h�������ƒ��\�b�h�̍Ō�̎��s + * @param methodSignature ���\�b�h��(�O����v�Ō�������) + * @return �Y������Ō�̃��\�b�h���s + */ + public MethodExecution getLastMethodExecution(final String methodSignature) { + return traverseMethodEntriesInTraceBackward(new IMethodExecutionVisitor() { + @Override + public boolean preVisitThread(ThreadInstance thread) { return false; } + @Override + public boolean postVisitThread(ThreadInstance thread) { return false; } + @Override + public boolean preVisitMethodExecution(MethodExecution methodExecution) { return false; } + @Override + public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) { + if (methodExecution.getSignature().startsWith(methodSignature)) return true; + return false; + } + }); + } + + /** + * �g���[�X���̑S���\�b�h���s�̊J�n�n�_���t�����ɒT������ + * @param visitor ���\�b�h���s�̃r�W�^�[(postVisitMethodExecution()�����ĂѕԂ��Ȃ��̂Œ���) + * @return ���f�������\�b�h���s + */ + public MethodExecution traverseMethodEntriesInTraceBackward(IMethodExecutionVisitor visitor) { + HashMap> threadRoots = new HashMap>(); + HashMap threadLastPoints = new HashMap(); + Iterator threadsIterator = threads.keySet().iterator(); + // �e�X���b�h�ɂ����Ĉ�ԍŌ�ɊJ�n�������\�b�h���s��T�� + long traceLastTime = 0; + String traceLastThread = null; + long traceLastTime2 = 0; + String traceLastThread2 = null; + for (; threadsIterator.hasNext();) { + String threadId = threadsIterator.next(); + ThreadInstance thread = threads.get(threadId); + ArrayList rootExecutions = (ArrayList)thread.getRoot().clone(); + threadRoots.put(threadId, rootExecutions); + TracePoint threadLastTp = getLastMethodEntryInThread(rootExecutions); + threadLastPoints.put(threadId, threadLastTp); + if (threadLastTp != null) { + long threadLastTime = threadLastTp.getMethodExecution().getEntryTime(); + if (traceLastTime < threadLastTime) { + traceLastTime2 = traceLastTime; + traceLastThread2 = traceLastThread; + traceLastTime = threadLastTime; + traceLastThread = threadId; + } + } + } + return traverseMethodEntriesInTraceBackwardSub(visitor, threadRoots, threadLastPoints, traceLastThread, traceLastThread2, traceLastTime2); + } + + /** + * methodSignature �ɑO����v���郁�\�b�h�������ƒ��\�b�h�� before �ȑO�̍Ō�̎��s + * @param methodSignature ���\�b�h��(�O����v�Ō�������) + * @param before�@�T���J�n�g���[�X�|�C���g(������ȑO��T��) + * @return�@�Y������Ō�̃��\�b�h���s + */ + public MethodExecution getLastMethodExecution(final String methodSignature, TracePoint before) { + return traverseMethodEntriesInTraceBackward(new IMethodExecutionVisitor() { + @Override + public boolean preVisitThread(ThreadInstance thread) { return false; } + @Override + public boolean postVisitThread(ThreadInstance thread) { return false; } + @Override + public boolean preVisitMethodExecution(MethodExecution methodExecution) { return false; } + @Override + public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) { + if (methodExecution.getSignature().startsWith(methodSignature)) return true; + return false; + } + }, before); + } + + /** + * �w�肵�����s���_�ȑO�Ɏ��s���J�n���ꂽ���\�b�h���s�̊J�n���_���t�����ɒT������ + * @param visitor ���\�b�h���s�̃r�W�^�[(postVisitMethodExecution()�����ĂѕԂ��Ȃ��̂Œ���) + * @param before �T���J�n���_ + * @return ���f�������\�b�h���s + */ + public MethodExecution traverseMethodEntriesInTraceBackward(IMethodExecutionVisitor visitor, TracePoint before) { + HashMap> threadRoots = new HashMap>(); + HashMap threadLastPoints = new HashMap(); + Iterator threadsIterator = threads.keySet().iterator(); + String traceLastThread = null; + long traceLastTime2 = 0; + String traceLastThread2 = null; + ThreadInstance thread = threads.get(before.getStatement().getThreadNo()); + ArrayList rootExecutions = (ArrayList)thread.getRoot().clone(); + for (int n = rootExecutions.size() - 1; n >= 0; n--) { + MethodExecution root = rootExecutions.get(n); + if (root.getEntryTime() > before.getMethodExecution().getEntryTime()) { + rootExecutions.remove(n); + } else { + break; + } + } + if (rootExecutions.size() > 0) { + rootExecutions.remove(rootExecutions.size() - 1); + } + before = getLastMethodEntryInThread(rootExecutions, before); + for (; threadsIterator.hasNext();) { + String threadId = threadsIterator.next(); + ThreadInstance t = threads.get(threadId); + if (t == thread) { + threadRoots.put(threadId, rootExecutions); + traceLastThread = threadId; + threadLastPoints.put(threadId, before); + } else { + ArrayList rootExes = (ArrayList)t.getRoot().clone(); + threadRoots.put(threadId, rootExes); + MethodExecution threadLastExecution = rootExes.remove(rootExes.size() - 1); + TracePoint threadBeforeTp = getLastMethodEntryInThread(rootExes, threadLastExecution.getExitOutPoint(), before.getMethodExecution().getEntryTime()); + threadLastPoints.put(threadId, threadBeforeTp); + if (threadBeforeTp != null) { + long threadLastTime = threadBeforeTp.getMethodExecution().getEntryTime(); + if (traceLastTime2 < threadLastTime) { + traceLastTime2 = threadLastTime; + traceLastThread2 = threadId; + } + } + } + } + return traverseMethodEntriesInTraceBackwardSub(visitor, threadRoots, threadLastPoints, traceLastThread, traceLastThread2, traceLastTime2); + } + + private MethodExecution traverseMethodEntriesInTraceBackwardSub( + final IMethodExecutionVisitor visitor, + HashMap> threadRoots, HashMap threadLastPoints, + String traceLastThread, String traceLastThread2, long traceLastTime2) { + // �S�X���b�h�̓������Ƃ�Ȃ���t�����Ƀ��\�b�h���s��T������ + for (;;) { + // �T���Ώۂ̃X���b�h���̋t�����T�� + TracePoint threadLastTp = threadLastPoints.get(traceLastThread); + MethodExecution threadLastExecution = threadLastTp.getMethodExecution(); + do { + threadLastTp.stepBackOver(); + // ���̃X���b�h�̎��̃��\�b�h���s�J�n���_�܂ŒT������ + threadLastTp = getLastMethodEntryInThread(threadRoots.get(traceLastThread), threadLastTp); + if (threadLastTp == null) break; + if (visitor.postVisitMethodExecution(threadLastExecution, threadLastExecution.getChildren())) { + // �Y�����郁�\�b�h���s�����‚��� + return threadLastExecution; + } + threadLastExecution = threadLastTp.getMethodExecution(); + } while (threadLastExecution.getEntryTime() > traceLastTime2); + threadLastPoints.put(traceLastThread, threadLastTp); + traceLastThread = traceLastThread2; + // ���̎��ɒT�����ׂ��X���b�h(���T���̗̈悪��ԍŌ�܂Ŏc���Ă���X���b�h)�����肷�� + traceLastTime2 = 0; + traceLastThread2 = null; + boolean continueTraverse = false; + Iterator threadIterator = threadLastPoints.keySet().iterator(); + for (; threadIterator.hasNext();) { + String threadId = threadIterator.next(); + if (!threadId.equals(traceLastThread)) { + TracePoint lastTp = threadLastPoints.get(threadId); + if (lastTp != null) { + continueTraverse = true; + long threadLastTime = lastTp.getMethodExecution().getEntryTime(); + if (traceLastTime2 < threadLastTime) { + traceLastTime2 = threadLastTime; + traceLastThread2 = threadId; + } + } + } + } + if (!continueTraverse && threadLastPoints.get(traceLastThread) == null) break; + } + return null; + } + + /** + * ���\�b�h���� methodSignature�@�ɑO����v���郁�\�b�h���s��S�ẴX���b�h������o�� + * @param methodSignature ���������� + * @return ��v�����S���\�b�h���s + */ + public ArrayList getMethodExecutions(final String methodSignature) { + Iterator threadsIterator = threads.keySet().iterator(); + final ArrayList results = new ArrayList(); + for (; threadsIterator.hasNext();) { + ThreadInstance thread = threads.get(threadsIterator.next()); + thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() { + @Override + public boolean preVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean preVisitMethodExecution(MethodExecution methodExecution) { + if (methodExecution.getSignature().startsWith(methodSignature)) { + results.add(methodExecution); + } + return false; + } + @Override + public boolean postVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) { + return false; + } + }); + } + return results; + } + + /** + * ���\�b�h���ɑS���\�b�h���s��S�ẴX���b�h������o�� + * @return ���\�b�h�V�O�j�`�����烁�\�b�h���s�̃��X�g�ւ�HashMap + */ + public HashMap> getAllMethodExecutions() { + Iterator threadsIterator = threads.keySet().iterator(); + final HashMap> results = new HashMap<>(); + for (; threadsIterator.hasNext();) { + ThreadInstance thread = threads.get(threadsIterator.next()); + thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() { + @Override + public boolean preVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean preVisitMethodExecution(MethodExecution methodExecution) { + String signature = methodExecution.getSignature(); + ArrayList executions = results.get(signature); + if (executions == null) { + executions = new ArrayList<>(); + results.put(signature, executions); + } + executions.add(methodExecution); + return false; + } + @Override + public boolean postVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) { + return false; + } + }); + } + return results; + } + + /** + * �Ăяo�����̎����� markStart ���� markEnd �̊Ԃɂ���S�X���b�h���̑S���\�b�h���s��T������ + * @param visitor�@�r�W�^�[ + * @param markStart �J�n���� + * @param markEnd �I������ + */ + public void traverseMarkedMethodExecutions(IMethodExecutionVisitor visitor, long markStart, long markEnd) { + Iterator threadsIterator = threads.keySet().iterator(); + for (; threadsIterator.hasNext();) { + ThreadInstance thread = threads.get(threadsIterator.next()); + thread.traverseMarkedMethodExecutions(visitor, markStart, markEnd); + } + } + + /** + * �S���\�b�h�̃V�O�j�`�����擾���� + * @return �S���\�b�h�V�O�j�`�� + */ + public HashSet getAllMethodSignatures() { + final HashSet signatures = new HashSet(); + Iterator threadsIterator = threads.keySet().iterator(); + for (; threadsIterator.hasNext();) { + ThreadInstance thread = threads.get(threadsIterator.next()); + thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() { + @Override + public boolean preVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean postVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean preVisitMethodExecution(MethodExecution methodExecution) { + signatures.add(methodExecution.getSignature()); + return false; + } + @Override + public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) { + return false; + } + }); + } + return signatures; + } + + /** + * �}�[�N���Ŏ��s���J�n���ꂽ�S���\�b�h�̃V�O�j�`�����擾���� + * @param markStart �}�[�N�̊J�n���� + * @param markEnd �}�[�N�̏I������ + * @return �Y�����郁�\�b�h�V�O�j�`�� + */ + public HashSet getMarkedMethodSignatures(final long markStart, final long markEnd) { + final HashSet signatures = new HashSet(); + Iterator threadsIterator = threads.keySet().iterator(); + for (; threadsIterator.hasNext();) { + ThreadInstance thread = threads.get(threadsIterator.next()); + thread.traverseMarkedMethodExecutions(new IMethodExecutionVisitor() { + @Override + public boolean preVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean postVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean preVisitMethodExecution(MethodExecution methodExecution) { + signatures.add(methodExecution.getSignature()); + return false; + } + @Override + public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) { + return false; + } + }, markStart, markEnd); + } + return signatures; + } + + /** + * �}�[�N���Ŏ��s���J�n���ꂽ�S���\�b�h���s�����\�b�h���Ɏ擾���� + * @param markStart �}�[�N�̊J�n���� + * @param markEnd �}�[�N�̏I������ + * @return ���\�b�h�V�O�j�`������Y�����郁�\�b�h���s�̃��X�g�ւ�HashMap + */ + public HashMap> getMarkedMethodExecutions(final long markStart, final long markEnd) { + final HashMap>allExecutions = new HashMap<>(); + Iterator threadsIterator = threads.keySet().iterator(); + for (; threadsIterator.hasNext();) { + ThreadInstance thread = threads.get(threadsIterator.next()); + thread.traverseMarkedMethodExecutions(new IMethodExecutionVisitor() { + @Override + public boolean preVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean postVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean preVisitMethodExecution(MethodExecution methodExecution) { + ArrayList executions = allExecutions.get(methodExecution.getSignature()); + if (executions == null) { + executions = new ArrayList<>(); + allExecutions.put(methodExecution.getSignature(), executions); + } + executions.add(methodExecution); + return false; + } + @Override + public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) { + return false; + } + }, markStart, markEnd); + } + return allExecutions; + } + + /** + * �}�[�N�O�Ŏ��s���J�n���ꂽ�S���\�b�h�̃V�O�j�`�����擾���� + * @param markStart �}�[�N�̊J�n���� + * @param markEnd �}�[�N�̏I������ + * @return �Y�����郁�\�b�h�V�O�j�`�� + */ + public HashSet getUnmarkedMethodSignatures(long markStart, long markEnd) { + HashSet signatures = new HashSet(); + Iterator threadsIterator = threads.keySet().iterator(); + for (; threadsIterator.hasNext();) { + ThreadInstance thread = threads.get(threadsIterator.next()); + thread.getUnmarkedMethodSignatures(signatures, markStart, markEnd); + } + return signatures; + } + + /** + * �}�[�N�O�Ŏ��s���J�n���ꂽ�S���\�b�h���s���擾���� + * @param markStart �}�[�N�̊J�n���� + * @param markEnd �}�[�N�̏I������ + * @return ���\�b�h�V�O�j�`������Y�����郁�\�b�h���s�̃��X�g�ւ�HashMap + */ + public HashMap> getUnmarkedMethodExecutions(long markStart, long markEnd) { + HashMap> executions = new HashMap<>(); + Iterator threadsIterator = threads.keySet().iterator(); + for (; threadsIterator.hasNext();) { + ThreadInstance thread = threads.get(threadsIterator.next()); + thread.getUnmarkedMethodExecutions(executions, markStart, markEnd); + } + return executions; + } + + /** + * �g���[�X���̑S�X���b�h�𓯊������Ȃ炪�S���s�����������ɒT������ + * + * @param visitor ���s���̃r�W�^�[ + * @return ���f�����g���[�X�|�C���g + */ + public TracePoint traverseStatementsInTrace(IStatementVisitor visitor) { + HashMap> threadRoots = new HashMap>(); + HashMap threadCurPoints = new HashMap(); + // �e�X���b�h�ɂ����Ĉ�ԍŏ��ɊJ�n�������\�b�h���s��T�� + long traceCurTime = -1; + String traceCurThread = null; + long traceCurTime2 = -1; + String traceCurThread2 = null; + for (String threadId: threads.keySet()) { + ThreadInstance thread = threads.get(threadId); + ArrayList roots = (ArrayList)thread.getRoot().clone(); + threadRoots.put(threadId, roots); + TracePoint threadCurTp; + do { + MethodExecution threadCurExecution = roots.remove(0); + threadCurTp = threadCurExecution.getEntryPoint(); + } while (!threadCurTp.isValid() && roots.size() > 0); + if (threadCurTp.isValid()) { + threadCurPoints.put(threadId, threadCurTp); + long methodEntry = threadCurTp.getMethodExecution().getEntryTime(); + if (traceCurTime == -1 || traceCurTime > methodEntry) { + traceCurTime2 = traceCurTime; + traceCurThread2 = traceCurThread; + traceCurTime = methodEntry; + traceCurThread = threadId; + } + } else { + threadCurPoints.put(threadId, null); + } + } + return traverseStatementsInTraceSub(visitor, threadRoots, threadCurPoints, traceCurThread, traceCurThread2, traceCurTime2); + } + + private TracePoint traverseStatementsInTraceSub(IStatementVisitor visitor, + HashMap> threadRoots, + HashMap threadCurPoints, + String curThreadId, String nextThreadId, long nextThreadTime) { + // �S�X���b�h�̓������Ƃ�Ȃ��珇�����Ɏ��s����T������ + for (;;) { + // �T���Ώۂ̃X���b�h���̏������T�� + TracePoint curTp = threadCurPoints.get(curThreadId); + while (curTp != null + && (curTp.getStatement().getTimeStamp() <= nextThreadTime || nextThreadTime == -1)) { + Statement statement = curTp.getStatement(); + if (visitor.preVisitStatement(statement)) return curTp; + if (!(statement instanceof MethodInvocation)) { + if (visitor.postVisitStatement(statement)) return curTp; + } + curTp.stepNoReturn(); // ���A�����ɌĂяo���؂�����Ă��� + if (!curTp.isValid()) { + // ���A���Ȃ��Ƃ���ȏ�T���ł��Ȃ� + while (!curTp.stepOver()) { // ���x�͕��A�͂��邪���炸�ɒT�� + if (curTp.isValid()) { + // �Ăяo����T���O�Ɉ�x�K��ς݂̃��\�b�h�Ăяo���s���A�T���������x�K�₷�� + if (visitor.postVisitStatement(curTp.getStatement())) return curTp; + } else { + // �Ăяo���؂̊J�n���_�܂ŒT�����I�����ꍇ + ArrayList roots = threadRoots.get(curThreadId); + while (!curTp.isValid() && roots.size() > 0) { + // ���̌Ăяo���؂�����΂�����ŏ�����T�� + MethodExecution firstExecution = roots.remove(0); + curTp = firstExecution.getEntryPoint(); + } + if (curTp.isValid()) { + // ���̌Ăяo���؂�����΂�����ŏ�����T�� + threadCurPoints.put(curThreadId, curTp); + } else { + // ���̃X���b�h�̒T�������ׂďI�������ꍇ + threadCurPoints.put(curThreadId, null); + curTp = null; + } + break; + } + } + } + } + curThreadId = nextThreadId; + if (curThreadId == null) break; + // ���̎��ɒT�����ׂ��X���b�h(���T���̗̈悪��ԍŏ��Ɏn�܂�X���b�h)�����肷�� + nextThreadTime = -1; + nextThreadId = null; + boolean continueTraverse = false; + for (String threadId: threadCurPoints.keySet()) { + if (!threadId.equals(curThreadId)) { + TracePoint threadTp = threadCurPoints.get(threadId); + if (threadTp != null) { + continueTraverse = true; + long threadTime = threadTp.getStatement().getTimeStamp(); + if (threadTime > 0 && (nextThreadTime == -1 || nextThreadTime > threadTime)) { + nextThreadTime = threadTime; + nextThreadId = threadId; + } + } + } + } + if (!continueTraverse && threadCurPoints.get(curThreadId) == null) break; + } + return null; + } + + /** + * �g���[�X���̑S�X���b�h�𓯊������Ȃ炪�S���s�����t�����ɒT������ + * + * @param visitor ���s���̃r�W�^�[ + * @return ���f�����g���[�X�|�C���g + */ + public TracePoint traverseStatementsInTraceBackward(IStatementVisitor visitor) { + HashMap> threadRoots = new HashMap>(); + HashMap threadLastPoints = new HashMap(); + Iterator threadsIterator = threads.keySet().iterator(); + // �e�X���b�h�ɂ����Ĉ�ԍŌ�ɊJ�n�������\�b�h���s��T�� + long traceLastTime = 0; + String traceLastThread = null; + long traceLastTime2 = 0; + String traceLastThread2 = null; + for (; threadsIterator.hasNext();) { + String threadId = threadsIterator.next(); + ThreadInstance thread = threads.get(threadId); + ArrayList root = (ArrayList)thread.getRoot().clone(); + threadRoots.put(threadId, root); + TracePoint threadLastTp; + do { + MethodExecution threadLastExecution = root.remove(root.size() - 1); + threadLastTp = threadLastExecution.getExitPoint(); + } while (!threadLastTp.isValid() && root.size() > 0); + if (threadLastTp.isValid()) { + threadLastPoints.put(threadId, threadLastTp); + if (traverseStatamentsInCallTreeBackwardNoReturn(visitor, threadLastTp)) return threadLastTp; + long methodEntry = threadLastTp.getMethodExecution().getEntryTime(); + if (traceLastTime < methodEntry) { + traceLastTime2 = traceLastTime; + traceLastThread2 = traceLastThread; + traceLastTime = methodEntry; + traceLastThread = threadId; + } + } else { + threadLastPoints.put(threadId, null); + } + } + return traverseStatementsInTraceBackwardSub(visitor, threadRoots, threadLastPoints, traceLastThread, traceLastThread2, traceLastTime2); + } + + /** + * + * @param visitor + * @param before + * @return + */ + public TracePoint traverseStatementsInTraceBackward(IStatementVisitor visitor, TracePoint before) { + if (traverseStatamentsInCallTreeBackwardNoReturn(visitor, before)) return before; + HashMap> threadRoots = new HashMap>(); + HashMap threadLastPoints = new HashMap(); + Iterator threadsIterator = threads.keySet().iterator(); + String traceLastThread = null; + long traceLastTime2 = 0; + String traceLastThread2 = null; + ThreadInstance thread = threads.get(before.getStatement().getThreadNo()); + for (; threadsIterator.hasNext();) { + String threadId = threadsIterator.next(); + ThreadInstance t = threads.get(threadId); + ArrayList rootExecutions = (ArrayList)t.getRoot().clone(); + threadRoots.put(threadId, rootExecutions); + if (t == thread) { + traceLastThread = threadId; + threadLastPoints.put(threadId, before); + for (int n = rootExecutions.size() - 1; n >= 0; n--) { + MethodExecution root = rootExecutions.get(n); + if (root.getEntryTime() > before.getMethodExecution().getEntryTime()) { + rootExecutions.remove(n); + } else { + break; + } + } + if (rootExecutions.size() > 0) { + rootExecutions.remove(rootExecutions.size() - 1); + } + } else { + MethodExecution threadLastExecution = rootExecutions.remove(rootExecutions.size() - 1); + TracePoint threadBeforeTp = getLastMethodEntryInThread(rootExecutions, threadLastExecution.getExitOutPoint(), before.getMethodExecution().getEntryTime()); + threadLastPoints.put(threadId, threadBeforeTp); + if (threadBeforeTp != null) { + long threadLastTime = threadBeforeTp.getMethodExecution().getEntryTime(); + if (traceLastTime2 < threadLastTime) { + traceLastTime2 = threadLastTime; + traceLastThread2 = threadId; + } + } + } + } + return traverseStatementsInTraceBackwardSub(visitor, threadRoots, threadLastPoints, traceLastThread, traceLastThread2, traceLastTime2); + } + + private TracePoint traverseStatementsInTraceBackwardSub(IStatementVisitor visitor, + HashMap> threadRoots, + HashMap threadLastPoints, + String traceLastThread, String traceLastThread2, long traceLastTime2) { + // �S�X���b�h�̓������Ƃ�Ȃ���t�����Ɏ��s����T������ + for (;;) { + // �T���Ώۂ̃X���b�h���̋t�����T�� + TracePoint lastTp = threadLastPoints.get(traceLastThread); + do { + if (lastTp.stepBackOver()) { + // ���̃X���b�h�̎��̃��\�b�h���s�J�n���_�܂ŒT������ + if (traverseStatamentsInCallTreeBackwardNoReturn(visitor, lastTp)) return lastTp; + } else { + // �Ăяo�����ɖ߂����ꍇ + if (lastTp.isValid()) { + if (visitor.postVisitStatement(lastTp.getStatement())) return lastTp; + } else { + // �Ăяo���؂̊J�n���_�܂ŒT�����I�����ꍇ + ArrayList root = threadRoots.get(traceLastThread); + while (!lastTp.isValid() && root.size() > 0) { + // ���̌Ăяo���؂�����΂�����Ōォ��T�� + MethodExecution lastExecution = root.remove(root.size() - 1); + lastTp = lastExecution.getExitPoint(); + } + if (lastTp.isValid()) { + // ���̌Ăяo���؂�����΂�����Ōォ��T�� + threadLastPoints.put(traceLastThread, lastTp); + if (traverseStatamentsInCallTreeBackwardNoReturn(visitor, lastTp)) return lastTp; + } else { + // ���̃X���b�h�̒T�������ׂďI�������ꍇ + threadLastPoints.put(traceLastThread, null); + break; + } + } + } + } while (lastTp.getMethodExecution().getEntryTime() >= traceLastTime2); + traceLastThread = traceLastThread2; + // ���̎��ɒT�����ׂ��X���b�h(���T���̗̈悪��ԍŌ�܂Ŏc���Ă���X���b�h)�����肷�� + traceLastTime2 = 0; + traceLastThread2 = null; + boolean continueTraverse = false; + Iterator threadsIterator = threadLastPoints.keySet().iterator(); + for (; threadsIterator.hasNext();) { + String threadId = threadsIterator.next(); + if (!threadId.equals(traceLastThread)) { + TracePoint threadLastTp = threadLastPoints.get(threadId); + if (threadLastTp != null) { + continueTraverse = true; + long threadLastTime = threadLastTp.getMethodExecution().getEntryTime(); + if (traceLastTime2 < threadLastTime) { + traceLastTime2 = threadLastTime; + traceLastThread2 = threadId; + } + } + } + } + if (!continueTraverse && threadLastPoints.get(traceLastThread) == null) break; + } + return null; + } + + private TracePoint getLastMethodEntryInThread(ArrayList rootExecutions) { + MethodExecution lastExecution = rootExecutions.remove(rootExecutions.size() - 1); + return getLastMethodEntryInThread(rootExecutions, lastExecution.getExitOutPoint()); + } + + private TracePoint getLastMethodEntryInThread(ArrayList rootExecutions, TracePoint start) { + return getLastMethodEntryInThread(rootExecutions, start, -1L); + } + + /** + * + * @param rootExecutions + * @param start + * @param before + * @return + */ + private TracePoint getLastMethodEntryInThread(ArrayList rootExecutions, TracePoint start, final long before) { + final TracePoint cp[] = new TracePoint[1]; + cp[0] = start; + for (;;) { + if (!cp[0].isStepBackOut() && traverseMethodExecutionsInCallTreeBackward( + new IMethodExecutionVisitor() { + @Override + public boolean preVisitThread(ThreadInstance thread) { return false; } + @Override + public boolean preVisitMethodExecution(MethodExecution methodExecution) { return false; } + @Override + public boolean postVisitThread(ThreadInstance thread) { return false; } + @Override + public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) { + if (methodExecution.getEntryTime() < before || before == -1L) { + cp[0] = methodExecution.getEntryPoint(); + return true; + } + return false; + } + }, cp[0])) { + return cp[0]; + } + if (rootExecutions.size() == 0) break; + MethodExecution lastExecution = rootExecutions.remove(rootExecutions.size() - 1); + cp[0] = lastExecution.getExitOutPoint(); + } + return null; + } + + /** + * before �Ŏw�肵���g���[�X�|�C���g�ȑO�̓���Ăяo���ؓ��̑S���s�����t�����ɒT������(�������Avisitor �� true ��Ԃ��܂�) + * @param visitor �r�W�^�[ + * @param before �T���̊J�n�_(�T���ΏۃX���b�h���w�肵�Ă���) + * @return true -- �T���𒆒f����, false -- �Ō�܂ŒT������ + */ + public boolean traverseStatementsInCallTreeBackward(IStatementVisitor visitor, TracePoint before) { + for (;;) { + if (traverseStatamentsInCallTreeBackwardNoReturn(visitor, before)) return true; + before.stepBackOver(); + if (!before.isValid()) break; + } + return false; + } + + /** + * before�ȍ~�̌Ăяo���؂��Ăяo���悩��̕��A�������ɍs����Ƃ���܂ŋt�����ɒT������ + * + * @param visitor ���s���̃r�W�^�[ + * @param before �T���J�n���s���_ + * @return true -- �T���𒆒f����, false -- ���A�����Ȃ����肱��ȏ�i�߂Ȃ� + */ + private boolean traverseStatamentsInCallTreeBackwardNoReturn(IStatementVisitor visitor, TracePoint before) { + for (;;) { + Statement statement = before.getStatement(); + if (statement instanceof MethodInvocation) { + // ���\�b�h�Ăяo�����̏ꍇ�́A�Ăяo���̑O��� preVisit �� postVisit ��ʁX�Ɏ��s���� + if (visitor.preVisitStatement(statement)) return true; + before.stepBackNoReturn(); + if (!before.isValid()) { + // �Ăяo����̃��\�b�h�Ŏ��s�����L�^����Ă��Ȃ��ꍇ + before.stepBackOver(); + if (visitor.postVisitStatement(statement)) return true; + if (before.isMethodEntry()) return false; + before.stepBackOver(); + } + } else { + if (visitor.preVisitStatement(statement)) return true; + if (visitor.postVisitStatement(statement)) return true; + if (before.isMethodEntry()) return false; + before.stepBackNoReturn(); + } + } + } + + /** + * before �Ŏw�肵���g���[�X�|�C���g�ȑO�̓���X���b�h���̑S���\�b�h���s���Ăяo���؂̒��ŋt�����ɒT������(�������Avisitor �� true ��Ԃ��܂�) + * @param visitor �r�W�^�[ + * @param before �T���̊J�n�_(�T���ΏۃX���b�h���w�肵�Ă���) + * @return true -- �T���𒆒f����, false -- �Ō�܂ŒT������ + */ + public boolean traverseMethodExecutionsInCallTreeBackward(IMethodExecutionVisitor visitor, TracePoint before) { + ArrayList prevMethodExecutions = before.getPreviouslyCalledMethods(); + for (int i = prevMethodExecutions.size() - 1; i >= 0; i--) { + MethodExecution child = prevMethodExecutions.get(i); + if (child.traverseMethodExecutionsBackward(visitor)) return true; + } + MethodExecution methodExecution = before.getMethodExecution(); + if (visitor.postVisitMethodExecution(methodExecution, null)) return true; + TracePoint caller = methodExecution.getCallerTracePoint(); + if (caller != null) { + if (traverseMethodExecutionsInCallTreeBackward(visitor, caller)) return true; + } + return false; + } + + public TracePoint getCreationTracePoint(final ObjectReference newObjectId, TracePoint before) { + before = before.duplicate(); + before = traverseStatementsInTraceBackward( + new IStatementVisitor() { + @Override + public boolean preVisitStatement(Statement statement) { + if (statement instanceof MethodInvocation) { + MethodInvocation mi = (MethodInvocation)statement; + if (mi.getCalledMethodExecution().isConstructor() + && mi.getCalledMethodExecution().getReturnValue().equals(newObjectId)) { + return true; + } + } + return false; + } + @Override + public boolean postVisitStatement(Statement statement) { return false; } + }, before); + if (before != null) { + return before; + } + return null; + } + + public TracePoint getFieldUpdateTracePoint(final Reference ref, TracePoint before) { + before = before.duplicate(); + final String srcType = ref.getSrcClassName(); + final String dstType = ref.getDstClassName(); + final String srcObjId = ref.getSrcObjectId(); + final String dstObjId = ref.getDstObjectId(); + + before = traverseStatementsInTraceBackward(new IStatementVisitor() { + @Override + public boolean preVisitStatement(Statement statement) { + if (statement instanceof FieldUpdate) { + FieldUpdate fu = (FieldUpdate)statement; + if (fu.getContainerObjId().equals(srcObjId) + && fu.getValueObjId().equals(dstObjId)) { + // �I�u�W�F�N�gID���݂��Ɉ�v�����ꍇ + return true; + } else if ((srcObjId == null || isNull(srcObjId)) && fu.getContainerClassName().equals(srcType)) { + if ((dstObjId == null || isNull(dstObjId)) && fu.getValueClassName().equals(dstType)) { + // ref �ɃI�u�W�F�N�gID���w�肵�Ă��Ȃ������ꍇ + ref.setSrcObjectId(fu.getContainerObjId()); + ref.setDstObjectId(fu.getValueObjId()); + return true; + } else if (fu.getValueObjId().equals(dstObjId)) { + // �N���X�ϐ��ւ̑���̏ꍇ + ref.setSrcObjectId(srcObjId); + ref.setDstClassName(dstType); + return true; + } + } + } + return false; + } + @Override + public boolean postVisitStatement(Statement statement) { return false; } + }, before); + if (before != null) { + return before; + } + return null; + } + + public TracePoint getCollectionAddTracePoint(final Reference ref, TracePoint before) { + final TracePoint[] result = new TracePoint[1]; + if (traverseMethodEntriesInTraceBackward(new IMethodExecutionVisitor() { + @Override + public boolean preVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean postVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean preVisitMethodExecution(MethodExecution methodExecution) { + return false; + } + @Override + public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) { + String srcType = ref.getSrcClassName(); + String dstType = ref.getDstClassName(); + String srcObjId = ref.getSrcObjectId(); + String dstObjId = ref.getDstObjectId(); + if (methodExecution.isCollectionType() && isCollectionAdd(methodExecution.getSignature())) { + if (dstObjId != null && methodExecution.getThisObjId().equals(srcObjId)) { + ArrayList args = methodExecution.getArguments(); + for (int i = 0; i < args.size(); i++) { + ObjectReference arg = args.get(i); + if (arg.getId().equals(dstObjId)) { + ref.setSrcClassName(methodExecution.getThisClassName()); + ref.setDstClassName(arg.getActualType()); + result[0] = methodExecution.getCallerTracePoint(); + return true; + } + } + } else if (dstObjId == null && methodExecution.getThisClassName().equals(srcType)) { + ArrayList args = methodExecution.getArguments(); + for (int i = 0; i < args.size(); i++) { + ObjectReference arg = args.get(i); + if (arg.getActualType().equals(dstType)) { + ref.setSrcObjectId(methodExecution.getThisObjId()); + ref.setDstObjectId(arg.getId()); + result[0] = methodExecution.getCallerTracePoint(); + return true; + } + } + } + } + return false; + } + }, before) != null) { + return result[0]; + } + return null; + } + + private boolean isCollectionAdd(String methodSignature) { + return (methodSignature.contains("add(") || methodSignature.contains("set(") || methodSignature.contains("put(") || methodSignature.contains("push(")); + } + + public TracePoint getArraySetTracePoint(final Reference ref, TracePoint before) { + final TracePoint start = before.duplicate(); + before = traverseStatementsInTraceBackward(new IStatementVisitor() { + @Override + public boolean preVisitStatement(Statement statement) { + if (statement instanceof FieldAccess) { + if (isArraySet(ref, start)) { + return true; + } + } + return false; + } + @Override + public boolean postVisitStatement(Statement statement) { return false; } + }, start); + if (before != null) { + return before; + } + return null; + } + + private boolean isArraySet(Reference ref, TracePoint fieldAccessPoint) { + FieldAccess fieldAccess = (FieldAccess)fieldAccessPoint.getStatement(); + String srcObjId = ref.getSrcObjectId(); + String dstObjId = ref.getDstObjectId(); + if (fieldAccess.getValueClassName().startsWith("[L") + && fieldAccess.getValueObjId().equals(srcObjId)) { + // srcId �͔z�� + // ���\�b�h���s�J�n���� fieldAccessPoint �܂ł̊Ԃ̃��\�b�h���s���� dstId ���o��������? + TracePoint p = fieldAccessPoint.duplicate(); + while (p.stepBackOver()) { + Statement statement = p.getStatement(); + if (statement instanceof MethodInvocation) { + MethodExecution calledMethod = ((MethodInvocation)statement).getCalledMethodExecution(); + if (calledMethod.getReturnValue().getId().equals(dstObjId)) { + // dstId �͖߂�l�Ƃ��ďo�� + ref.setSrcClassName(fieldAccess.getValueClassName()); + ref.setDstClassName(calledMethod.getReturnValue().getActualType()); + return true; + } else if (dstObjId == null || isNull(dstObjId) && calledMethod.getReturnValue().getActualType().equals(ref.getDstClassName())) { + // dstClassName �͖߂�l�̌^�Ƃ��ďo�� + ref.setSrcObjectId(fieldAccess.getValueObjId()); + ref.setDstObjectId(calledMethod.getReturnValue().getId()); + return true; + } + } + if (EAGER_DETECTION_OF_ARRAY_SET) { + if (statement instanceof FieldAccess) { + if (((FieldAccess)statement).getContainerObjId().equals(dstObjId)) { + // dstId �̓t�B�[���h�ɏo�� + ref.setSrcClassName(fieldAccess.getValueClassName()); + ref.setDstClassName(((FieldAccess)statement).getContainerClassName()); + return true; + } else if (dstObjId == null || isNull(dstObjId) && ((FieldAccess)statement).getContainerClassName().equals(ref.getDstClassName())) { + // dstClassName �̓t�B�[���h�̌^�Ƃ��ďo�� + ref.setSrcObjectId(fieldAccess.getValueObjId()); + ref.setDstObjectId(((FieldAccess)statement).getContainerObjId()); + return true; + } + } + } + } + ArrayList args = fieldAccessPoint.getMethodExecution().getArguments(); + int argindex = args.indexOf(new ObjectReference(dstObjId)); + if (argindex != -1) { + // dstId �͈����ɏo�� + ref.setSrcClassName(fieldAccess.getValueClassName()); + ref.setDstClassName(args.get(argindex).getActualType()); + return true; + } else if (dstObjId == null || isNull(dstObjId)) { + for (int j = 0; j < args.size(); j++) { + if (args.get(j).getActualType().equals(ref.getDstClassName())) { + // dstClassName �͈����̌^�ɏo�� + ref.setSrcObjectId(fieldAccess.getValueObjId()); + ref.setDstObjectId(args.get(j).getId()); + return true; + } + } + } + } + return false; + } + + public static String getDeclaringType(String methodSignature, boolean isConstructor) { + if (isConstructor) { + String[] fragments = methodSignature.split("\\("); + return fragments[0].substring(fragments[0].lastIndexOf(' ') + 1); + } + String[] fragments = methodSignature.split("\\("); + return fragments[0].substring(fragments[0].lastIndexOf(' ') + 1, fragments[0].lastIndexOf('.')); + } + + public static String getMethodName(String methodSignature) { + String[] fragments = methodSignature.split("\\("); + String[] fragments2 = fragments[0].split("\\."); + return fragments2[fragments2.length - 1]; + } + + public static String getReturnType(String methodSignature) { + String[] fragments = methodSignature.split(" "); + for (int i = 0; i < fragments.length; i++) { + if (!fragments[i].equals("public") && !fragments[i].equals("private") && !fragments[i].equals("protected") + && !fragments[i].equals("abstract") && !fragments[i].equals("final") && !fragments[i].equals("static") + && !fragments[i].equals("synchronized") && !fragments[i].equals("native")) { + return fragments[i]; + } + } + return ""; + } + + public static boolean isNull(String objectId) { + return objectId.equals("0"); + } + + public static String getNull() { + return "0"; + } + + public static boolean isPrimitive(String typeName) { + if (typeName.equals("int") + || typeName.equals("boolean") + || typeName.equals("long") + || typeName.equals("double") + || typeName.equals("float") + || typeName.equals("char") + || typeName.equals("byte") + || typeName.equals("java.lang.Integer") + || typeName.equals("java.lang.Boolean") + || typeName.equals("java.lang.Long") + || typeName.equals("java.lang.Double") + || typeName.equals("java.lang.Float") + || typeName.equals("java.lang.Character") + || typeName.equals("java.lang.Byte")) return true; + return false; + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/TraceJSON.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/TraceJSON.java new file mode 100644 index 0000000..a8231c8 --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/TraceJSON.java @@ -0,0 +1,972 @@ +package org.ntlab.traceCollector.tracer.trace; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import org.ntlab.traceCollector.tracer.OnlineTraceOutput; + +public class TraceJSON extends Trace { +// private static TraceJSON theTrace = null; + private HashMap classes = new HashMap<>(); + private HashMap> stacks = new HashMap>(); + private ThreadInstance thread = null; + + private TraceJSON() { + + } + + /** + * �w�肵��JSON�̃g���[�X�t�@�C������ǂ��� Trace �I�u�W�F�N�g�𐶐����� + * @param file �g���[�X�t�@�C�� + */ + private TraceJSON(BufferedReader file) { + try { + readJSON(file); + file.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * �w�肵��JSON�̃g���[�X�t�@�C������ǂ��� Trace �I�u�W�F�N�g�𐶐����� + * @param traceFile �g���[�X�t�@�C���̃p�X + */ + private TraceJSON(String traceFile) { + BufferedReader file; + try { + file = new BufferedReader(new FileReader(traceFile)); + readJSON(file); + file.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static TraceJSON getInstance() { + if (theTrace == null) { + theTrace = new TraceJSON(); + } + return (TraceJSON)theTrace; + } + + private void readJSON(BufferedReader file) throws IOException { + // �g���[�X�t�@�C���ǂݍ��� + String line = null; + String[] type; + String[] classNameData; + String[] pathData; + String[] signature; + String[] receiver; + String[] arguments; + String[] lineData; + String[] threadId; + String[] thisObj; + String[] containerObj; + String[] valueObj; + String[] returnValue; + String[] arrayObj; + String[] thisData; + String[] containerData; + String[] valueData; + String[] returnData; + String[] fieldData; + String[] arrayData; + String[] blockIdData; + String[] incomingsData; + String[] dimensionData; + String[] indexData; + String className; + String classPath; + String loaderPath; + String time; + String thisObjectId; + String thisClassName; + String containerObjectId; + String containerClassName; + String valueObjectId; + String valueClassName; + String returnClassName; + String returnObjectId; + String arrayObjectId; + String arrayClassName; + String shortSignature; + boolean isConstractor = false; + boolean isCollectionType = false; + boolean isStatic = false; + int dimension; + int index; + int blockId; + int incomings; + int lineNum; + long timeStamp = 0L; + ThreadInstance thread = null; + HashMap> stacks = new HashMap>(); + while ((line = file.readLine()) != null) { + // �g���[�X�t�@�C���̉�� + if (line.startsWith("{\"type\":\"classDef\"")) { + // �N���X��` + type = line.split(",\"name\":\""); + classNameData = type[1].split("\",\"path\":\""); + className = classNameData[0]; + pathData = classNameData[1].split("\",\"loaderPath\":\""); + classPath = pathData[0].substring(1); // �擪�� / ����菜�� + loaderPath = pathData[1].substring(1, pathData[1].length() - 3); // �擪�� / �ƁA������ "}, ����菜�� + initializeClass(className, classPath, loaderPath); + } else if (line.startsWith("{\"type\":\"methodCall\"")) { + // ���\�b�h�Ăяo���̌Ăяo���� + type = line.split(",\"callerSideSignature\":\""); + signature = type[1].split("\",\"threadId\":"); + threadId = signature[1].split(",\"lineNum\":"); + lineNum = Integer.parseInt(threadId[1].substring(0, threadId[1].length() - 2)); // ������ }, ����菜�� + thread = threads.get(threadId[0]); + thread.preCallMethod(signature[0], lineNum); + } else if (line.startsWith("{\"type\":\"methodEntry\"")) { + // ���\�b�h�Ăяo�� + type = line.split("\"signature\":\""); + signature = type[1].split("\",\"receiver\":"); + receiver = signature[1].split(",\"args\":"); + arguments = receiver[1].split(",\"threadId\":"); + threadId = arguments[1].split(",\"time\":"); + thisData = parseClassNameAndObjectId(receiver[0]); + thisClassName = thisData[0]; + thisObjectId = thisData[1]; + isConstractor = false; + isStatic = false; + if (signature[0].contains("static ")) { + isStatic = true; + } + thread = threads.get(threadId[0]); + time = threadId[1].substring(0, threadId[1].length() - 2); // ������ }, ����菜�� + timeStamp = Long.parseLong(time); + Stack stack; + if (thread == null) { + thread = new ThreadInstance(threadId[0]); + threads.put(threadId[0], thread); + stack = new Stack(); + stacks.put(threadId[0], stack); + } else { + stack = stacks.get(threadId[0]); + } + stack.push(signature[0]); + // ���\�b�h�Ăяo���̐ݒ� + thread.callMethod(signature[0], null, thisClassName, thisObjectId, isConstractor, isStatic, timeStamp); + // �����̐ݒ� + thread.setArgments(parseArguments(arguments)); + } else if (line.startsWith("{\"type\":\"constructorEntry\"")) { + // �R���X�g���N�^�Ăяo�� + type = line.split("\"signature\":\""); + signature = type[1].split("\",\"class\":\""); + receiver = signature[1].split("\",\"args\":"); + arguments = receiver[1].split(",\"threadId\":"); + threadId = arguments[1].split(",\"time\":"); + thisClassName = receiver[0]; + thisObjectId = "0"; + isConstractor = true; + isStatic = false; + thread = threads.get(threadId[0]); + time = threadId[1].substring(0, threadId[1].length() - 2); // ������ }, ����菜�� + timeStamp = Long.parseLong(time); + Stack stack; + if (thread == null) { + thread = new ThreadInstance(threadId[0]); + threads.put(threadId[0], thread); + stack = new Stack(); + stacks.put(threadId[0], stack); + } else { + stack = stacks.get(threadId[0]); + } + stack.push(signature[0]); + // ���\�b�h�Ăяo���̐ݒ� + thread.callMethod(signature[0], null, thisClassName, thisObjectId, isConstractor, isStatic, timeStamp); + // �����̐ݒ� + thread.setArgments(parseArguments(arguments)); + } else if (line.startsWith("{\"type\":\"methodExit\"")) { + // ���\�b�h����̕��A + type = line.split(",\"shortSignature\":\""); + signature = type[1].split("\",\"receiver\":"); + receiver = signature[1].split(",\"returnValue\":"); + returnValue = receiver[1].split(",\"threadId\":"); + threadId = returnValue[1].split(",\"time\":"); + thisData = parseClassNameAndObjectId(receiver[0]); + thisClassName = thisData[0]; + thisObjectId = thisData[1]; + returnData = parseClassNameAndObjectId(returnValue[0]); + returnClassName = returnData[0]; + returnObjectId = returnData[1]; + shortSignature = signature[0]; + time = threadId[1].substring(0, threadId[1].length() - 2); // ������ }, ����菜�� + timeStamp = Long.parseLong(time); + Stack stack = stacks.get(threadId[0]); + if (!stack.isEmpty()) { + String line2 = stack.peek(); + if (line2.endsWith(shortSignature)) { + stack.pop(); + } else { + do { + stack.pop(); + thread.terminateMethod(); + line2 = stack.peek(); + } while (!stack.isEmpty() && !line2.endsWith(shortSignature)); + if (!stack.isEmpty()) stack.pop(); + } + thread = threads.get(threadId[0]); + ObjectReference returnVal = new ObjectReference(returnObjectId, returnClassName); + isCollectionType = false; + if(thisClassName.contains("java.util.List") + || thisClassName.contains("java.util.Vector") + || thisClassName.contains("java.util.Iterator") + || thisClassName.contains("java.util.ListIterator") + || thisClassName.contains("java.util.ArrayList") + || thisClassName.contains("java.util.Stack") + || thisClassName.contains("java.util.Hash") + || thisClassName.contains("java.util.Map") + || thisClassName.contains("java.util.Set") + || thisClassName.contains("java.util.Linked") + || thisClassName.contains("java.lang.Thread")) { + isCollectionType = true; + } + // ���\�b�h����̕��A�̐ݒ� + thread.returnMethod(returnVal, thisObjectId, isCollectionType, timeStamp); + } + } else if (line.startsWith("{\"type\":\"constructorExit\"")) { + // �R���X�g���N�^����̕��A + type = line.split(",\"shortSignature\":\""); + signature = type[1].split("\",\"returnValue\":"); + returnValue = signature[1].split(",\"threadId\":"); + threadId = returnValue[1].split(",\"time\":"); + returnData = parseClassNameAndObjectId(returnValue[0]); + thisClassName = returnClassName = returnData[0]; + thisObjectId = returnObjectId = returnData[1]; + time = threadId[1].substring(0, threadId[1].length() - 2); // ������ }, ����菜�� + timeStamp = Long.parseLong(time); + Stack stack = stacks.get(threadId[0]); + shortSignature = signature[0]; + if (!stack.isEmpty()) { + String line2 = stack.peek(); + if (line2.endsWith(shortSignature)) { + stack.pop(); + } else { + do { + stack.pop(); + thread.terminateMethod(); + line2 = stack.peek(); + } while (!stack.isEmpty() && !line2.endsWith(shortSignature)); + if (!stack.isEmpty()) stack.pop(); + } + thread = threads.get(threadId[0]); + ObjectReference returnVal = new ObjectReference(returnObjectId, returnClassName); + isCollectionType = false; + if(thisClassName.contains("java.util.List") + || thisClassName.contains("java.util.Vector") + || thisClassName.contains("java.util.Iterator") + || thisClassName.contains("java.util.ListIterator") + || thisClassName.contains("java.util.ArrayList") + || thisClassName.contains("java.util.Stack") + || thisClassName.contains("java.util.Hash") + || thisClassName.contains("java.util.Map") + || thisClassName.contains("java.util.Set") + || thisClassName.contains("java.util.Linked") + || thisClassName.contains("java.lang.Thread")) { + isCollectionType = true; + } + // ���\�b�h����̕��A�̐ݒ� + thread.returnMethod(returnVal, thisObjectId, isCollectionType, timeStamp); + } + } else if (line.startsWith("{\"type\":\"fieldGet\"")) { + // �t�B�[���h�A�N�Z�X + type = line.split(",\"fieldName\":\""); + fieldData = type[1].split("\",\"this\":"); + thisObj = fieldData[1].split(",\"container\":"); + containerObj = thisObj[1].split(",\"value\":"); + valueObj = containerObj[1].split(",\"threadId\":"); + threadId = valueObj[1].split(",\"lineNum\":"); + lineData = threadId[1].split(",\"time\":"); + thisData = parseClassNameAndObjectId(thisObj[0]); + thisClassName = thisData[0]; + thisObjectId = thisData[1]; + containerData = parseClassNameAndObjectId(containerObj[0]); + containerClassName = containerData[0]; + containerObjectId = containerData[1]; + valueData = parseClassNameAndObjectId(valueObj[0]); + valueClassName = valueData[0]; + valueObjectId = valueData[1]; + thread = threads.get(threadId[0]); + lineNum = Integer.parseInt(lineData[0]); + time = lineData[1].substring(0, lineData[1].length() - 2); // ������ }, ����菜�� + timeStamp = Long.parseLong(time); + // �t�B�[���h�A�N�Z�X�̐ݒ� + if (thread != null) thread.fieldAccess(fieldData[0], valueClassName, valueObjectId, containerClassName, containerObjectId, thisClassName, thisObjectId, lineNum, timeStamp); + } else if (line.startsWith("{\"type\":\"fieldSet\"")) { + // �t�B�[���h�X�V + type = line.split(",\"fieldName\":\""); + fieldData = type[1].split("\",\"container\":"); + containerObj = fieldData[1].split(",\"value\":"); + valueObj = containerObj[1].split(",\"threadId\":"); + threadId = valueObj[1].split(",\"lineNum\":"); + lineData = threadId[1].split(",\"time\":"); + containerData = parseClassNameAndObjectId(containerObj[0]); + containerClassName = containerData[0]; + containerObjectId = containerData[1]; + valueData = parseClassNameAndObjectId(valueObj[0]); + valueClassName = valueData[0]; + valueObjectId = valueData[1]; + thread = threads.get(threadId[0]); + lineNum = Integer.parseInt(lineData[0]); + time = lineData[1].substring(0, lineData[1].length() - 2); // ������ }, ����菜�� + timeStamp = Long.parseLong(time); + // �t�B�[���h�X�V�̐ݒ� + if (thread != null) thread.fieldUpdate(fieldData[0], valueClassName, valueObjectId, containerClassName, containerObjectId, lineNum, timeStamp); + } else if (line.startsWith("{\"type\":\"arrayCreate\"")) { + // �z�񐶐� + type = line.split(",\"array\":"); + arrayObj = type[1].split(",\"dimension\":"); + arrayData = parseClassNameAndObjectId(arrayObj[0]); + arrayClassName = arrayData[0]; + arrayObjectId = arrayData[1]; + dimensionData = arrayObj[1].split(",\"threadId\":"); + dimension = Integer.parseInt(dimensionData[0]); + threadId = dimensionData[1].split(",\"lineNum\":"); + thread = threads.get(threadId[0]); + lineData = threadId[1].split(",\"time\":"); + lineNum = Integer.parseInt(lineData[0]); + time = lineData[1].substring(0, lineData[1].length() - 2); // ������ }, ����菜�� + timeStamp = Long.parseLong(time); + if (thread != null) thread.arrayCreate(arrayClassName, arrayObjectId, dimension, lineNum, timeStamp); + } else if (line.startsWith("{\"type\":\"arraySet\"")) { + // �z��v�f�ւ̑�� + type = line.split(",\"array\":"); + arrayObj = type[1].split(",\"index\":"); + arrayData = parseClassNameAndObjectId(arrayObj[0]); + arrayClassName = arrayData[0]; + arrayObjectId = arrayData[1]; + indexData = arrayObj[1].split(",\"value\":"); + index = Integer.parseInt(indexData[0]); + valueObj = indexData[1].split(",\"threadId\":"); + valueData = parseClassNameAndObjectId(valueObj[0]); + valueClassName = valueData[0]; + valueObjectId = valueData[1]; + threadId = valueObj[1].split(",\"time\":"); + thread = threads.get(threadId[0]); + time = threadId[1].substring(0, threadId[1].length() - 2); // ������ }, ����菜�� + timeStamp = Long.parseLong(time); + if (thread != null) thread.arraySet(arrayClassName, arrayObjectId, index, valueClassName, valueObjectId, 0, timeStamp); + } else if (line.startsWith("{\"type\":\"arrayGet\"")) { + // �z��v�f�̎Q�� + type = line.split(",\"array\":"); + arrayObj = type[1].split(",\"index\":"); + arrayData = parseClassNameAndObjectId(arrayObj[0]); + arrayClassName = arrayData[0]; + arrayObjectId = arrayData[1]; + indexData = arrayObj[1].split(",\"value\":"); + index = Integer.parseInt(indexData[0]); + valueObj = indexData[1].split(",\"threadId\":"); + valueData = parseClassNameAndObjectId(valueObj[0]); + valueClassName = valueData[0]; + valueObjectId = valueData[1]; + threadId = valueObj[1].split(",\"time\":"); + thread = threads.get(threadId[0]); + time = threadId[1].substring(0, threadId[1].length() - 2); // ������ }, ����菜�� + timeStamp = Long.parseLong(time); + if (thread != null) thread.arrayGet(arrayClassName, arrayObjectId, index, valueClassName, valueObjectId, 0, timeStamp); + } else if (line.startsWith("{\"type\":\"blockEntry\"")) { + // �u���b�N�̊J�n + type = line.split(",\"methodSignature\":\""); + signature = type[1].split("\",\"blockId\":"); + blockIdData = signature[1].split(",\"incomings\":"); + blockId = Integer.parseInt(blockIdData[0]); + incomingsData = blockIdData[1].split(",\"threadId\":"); + incomings = Integer.parseInt(incomingsData[0]); + threadId = incomingsData[1].split(",\"lineNum\":"); + thread = threads.get(threadId[0]); + lineData = threadId[1].split(",\"time\":"); + lineNum = Integer.parseInt(lineData[0]); + time = lineData[1].substring(0, lineData[1].length() - 2); // ������ }, ����菜�� + timeStamp = Long.parseLong(time); + if (thread != null) thread.blockEnter(blockId, incomings, lineNum, timeStamp); + } + } + } + + /** + * �N���X���ƃI�u�W�F�N�gID��\��JSON�I�u�W�F�N�g����ǂ��� + * @param classNameAndObjectIdJSON �g���[�X�t�@�C������JSON�I�u�W�F�N�g + * @return + */ + protected String[] parseClassNameAndObjectId(String classNameAndObjectIdJSON) { + // �擪�� {"class":" ��10�����Ɩ����� } ����菜���ĕ��� + return classNameAndObjectIdJSON.substring(10, classNameAndObjectIdJSON.length() - 1).split("\",\"id\":"); + } + + /** + * ������\��JSON�z�����ǂ��� + * @param arguments + * @return + */ + protected ArrayList parseArguments(String[] arguments) { + String[] argData; + argData = arguments[0].substring(1, arguments[0].length() - 1).split(","); // �擪�� [ �Ɩ����� ] ����菜�� + ArrayList argumentsData = new ArrayList(); + for (int k = 0; k < argData.length - 1; k += 2) { + argumentsData.add(new ObjectReference(argData[k+1].substring(5, argData[k+1].length() - 1), argData[k].substring(10, argData[k].length() - 1))); + } + return argumentsData; + } + +// public void initializeClass(String name, String path, String loaderPath) { +// classes.put(name, new ClassInfo(name, path, loaderPath)); +// } + + public static void initializeClass(String name, String path, String loaderPath) { + getInstance().classes.put(name, new ClassInfo(name, path, loaderPath)); + + // �m�F�p + System.out.println("name = " + name); + System.out.println("path = " + path); + System.out.println("loaderPath = " + loaderPath); + System.out.println(); + } + +// public ClassInfo getClassInfo(String className) { +// return classes.get(className); +// } + + public static ClassInfo getClassInfo(String className) { + return getInstance().classes.get(className); + } + + public TracePoint getArraySetTracePoint(final Reference ref, TracePoint before) { + final TracePoint start = before.duplicate(); + before = traverseStatementsInTraceBackward(new IStatementVisitor() { + @Override + public boolean preVisitStatement(Statement statement) { + if (statement instanceof ArrayUpdate) { + ArrayUpdate arraySet = (ArrayUpdate)start.getStatement(); + String srcObjId = ref.getSrcObjectId(); + String dstObjId = ref.getDstObjectId(); + String srcClassName = ref.getSrcClassName(); + String dstClassName = ref.getDstClassName(); + if ((srcObjId != null && srcObjId.equals(arraySet.getArrayObjectId())) + || (srcObjId == null || isNull(srcObjId)) && srcClassName.equals(arraySet.getArrayClassName())) { + if ((dstObjId != null && dstObjId.equals(arraySet.getValueObjectId())) + || ((dstObjId == null || isNull(dstObjId)) && dstClassName.equals(arraySet.getValueClassName()))) { + if (srcObjId == null) { + ref.setSrcObjectId(arraySet.getArrayObjectId()); + } else if (srcClassName == null) { + ref.setSrcClassName(arraySet.getArrayClassName()); + } + if (dstObjId == null) { + ref.setDstObjectId(arraySet.getValueObjectId()); + } else if (dstClassName == null) { + ref.setDstClassName(arraySet.getValueClassName()); + } + return true; + } + } + } + return false; + } + @Override + public boolean postVisitStatement(Statement statement) { return false; } + }, start); + if (before != null) { + return before; + } + return null; + } + + /** + * ���s���ꂽ�S�u���b�N���擾���� + * @return �S�u���b�N(���\�b�h��:�u���b�NID) + */ + public HashSet getAllBlocks() { + final HashSet blocks = new HashSet(); + Iterator threadsIterator = threads.keySet().iterator(); + for (; threadsIterator.hasNext();) { + ThreadInstance thread = threads.get(threadsIterator.next()); + thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() { + @Override + public boolean preVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean postVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean preVisitMethodExecution(MethodExecution methodExecution) { + for (Statement s: methodExecution.getStatements()) { + if (s instanceof BlockEnter) { + blocks.add(methodExecution.getSignature() + ":" + ((BlockEnter)s).getBlockId()); + } + } + return false; + } + @Override + public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) { + return false; + } + }); + } + return blocks; + } + + /** + * �}�[�N���Ŏ��s���J�n���ꂽ�u���b�N���擾���� + * @param markStart �}�[�N�̊J�n���� + * @param markEnd �}�[�N�̏I������ + * @return �Y������u���b�N(���\�b�h��:�u���b�NID) + */ + public HashSet getMarkedBlocks(final long markStart, final long markEnd) { + final HashSet blocks = new HashSet(); + Iterator threadsIterator = threads.keySet().iterator(); + for (; threadsIterator.hasNext();) { + ThreadInstance thread = threads.get(threadsIterator.next()); + thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() { + @Override + public boolean preVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean postVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean preVisitMethodExecution(MethodExecution methodExecution) { + if (methodExecution.getExitTime() < markStart) return true; // �T���I�� + if (methodExecution.getEntryTime() > markEnd) return false; + for (Statement s: methodExecution.getStatements()) { + if (s instanceof BlockEnter) { + long entryTime = ((BlockEnter)s).getTimeStamp(); + if (entryTime >= markStart && entryTime <= markEnd) { + blocks.add(methodExecution.getSignature() + ":" + ((BlockEnter)s).getBlockId()); + } + } + } + return false; + } + @Override + public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) { + return false; + } + }); + } + return blocks; + } + + /** + * ���s���ꂽ�S�t���[���擾���� + * @return �S�t���[(���\�b�h��:�t���[���u���b�NID:�t���[��u���b�NID) + */ + public HashSet getAllFlows() { + final HashSet flows = new HashSet(); + Iterator threadsIterator = threads.keySet().iterator(); + for (; threadsIterator.hasNext();) { + ThreadInstance thread = threads.get(threadsIterator.next()); + thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() { + @Override + public boolean preVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean postVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean preVisitMethodExecution(MethodExecution methodExecution) { + int prevBlockId = -1; + for (Statement s: methodExecution.getStatements()) { + if (s instanceof BlockEnter) { + int curBlockID = ((BlockEnter)s).getBlockId(); + if (prevBlockId != -1) { + flows.add(methodExecution.getSignature() + ":" + prevBlockId + ":" + curBlockID); + } else { + flows.add(methodExecution.getSignature() + ":" + curBlockID); + } + prevBlockId = curBlockID; + } + } + return false; + } + @Override + public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) { + return false; + } + }); + } + return flows; + } + + /** + * �}�[�N���Ŏ��s���ꂽ�t���[���擾���� + * @param markStart �}�[�N�̊J�n���� + * @param markEnd �}�[�N�̏I������ + * @return �Y������t���[(���\�b�h��:�t���[���u���b�NID:�t���[��u���b�NID) + */ + public HashSet getMarkedFlows(final long markStart, final long markEnd) { + final HashSet flows = new HashSet(); + Iterator threadsIterator = threads.keySet().iterator(); + for (; threadsIterator.hasNext();) { + ThreadInstance thread = threads.get(threadsIterator.next()); + thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() { + @Override + public boolean preVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean postVisitThread(ThreadInstance thread) { + return false; + } + @Override + public boolean preVisitMethodExecution(MethodExecution methodExecution) { + if (methodExecution.getExitTime() < markStart) return true; // �T���I�� + if (methodExecution.getEntryTime() > markEnd) return false; + int prevBlockId = -1; + for (Statement s: methodExecution.getStatements()) { + if (s instanceof BlockEnter) { + long entryTime = ((BlockEnter)s).getTimeStamp(); + int curBlockID = ((BlockEnter)s).getBlockId(); + if (entryTime >= markStart && entryTime <= markEnd) { + if (prevBlockId != -1) { + flows.add(methodExecution.getSignature() + ":" + prevBlockId + ":" + curBlockID); + } else { + flows.add(methodExecution.getSignature() + ":" + curBlockID); + } + } + prevBlockId = curBlockID; + } + } + return false; + } + @Override + public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) { + return false; + } + }); + } + return flows; + } + + public static HashMap getClasses() { + return getInstance().classes; + } + + public static HashMap getThreads() { + return getInstance().threads; + } + + public static synchronized void onlineTraceClassDefinition(String className, String classPath, String loaderPath) { + // classPath��loaderPath�ɂ‚��Ă͐擪�� / ����菜���ċL�^���� (readJSON���ł̏����Ɠ����ɂȂ�) + initializeClass(className, classPath.substring(1), loaderPath.substring(1)); + } + + public static synchronized void onlineTracePreCallMethod(String signature, String threadId, String lineNum) { + getInstance().thread = getInstance().threads.get(threadId); + getInstance().thread.preCallMethod(signature, Integer.parseInt(lineNum)); + } + + public static synchronized void onlineTraceMethodEntry(String signature, String thisClassName, String thisObjectId, + String threadId, long timeStamp, String argList) { + boolean isConstractor = false; + boolean isStatic = false; + if (signature.contains("static ")) { + isStatic = true; + } + getInstance().thread = getInstance().threads.get(threadId); + Stack stack; + if (getInstance().thread == null) { + getInstance().thread = new ThreadInstance(threadId); + getInstance().threads.put(threadId, getInstance().thread); + stack = new Stack(); + getInstance().stacks.put(threadId, stack); + } else { + stack = getInstance().stacks.get(threadId); + } + stack.push(signature); + // ���\�b�h�Ăяo���̐ݒ� + getInstance().thread.callMethod(signature, null, thisClassName, thisObjectId, isConstractor, isStatic, timeStamp); + // �����̐ݒ� + ArrayList arguments = new ArrayList<>(); + String[] args = argList.split(","); + for (int i = 0; i < args.length - 1; i += 2) { + arguments.add(new ObjectReference(args[i+1], args[i])); + } + getInstance().thread.setArgments(arguments); + } + + public static synchronized void onlineTraceConstructorEntry(String signature, String thisClassName, String thisObjectId, + String threadId, long timeStamp, String argList) { + boolean isConstractor = true; + boolean isStatic = false; + getInstance().thread = getInstance().threads.get(threadId); + Stack stack; + if (getInstance().thread == null) { + getInstance().thread = new ThreadInstance(threadId); + getInstance().threads.put(threadId, getInstance().thread); + stack = new Stack(); + getInstance().stacks.put(threadId, stack); + } else { + stack = getInstance().stacks.get(threadId); + } + stack.push(signature); + // ���\�b�h�Ăяo���̐ݒ� + getInstance().thread.callMethod(signature, null, thisClassName, thisObjectId, isConstractor, isStatic, timeStamp); + // �����̐ݒ� + ArrayList arguments = new ArrayList<>(); + String[] args = argList.split(","); + for (int i = 0; i < args.length - 1; i += 2) { + arguments.add(new ObjectReference(args[i+1], args[i])); + } + getInstance().thread.setArgments(arguments); + } + + public static synchronized void onlineTraceMethodExit(String shortSignature, String thisClassName, String thisObjectId, + String returnClassName, String returnObjectId, String threadId, long timeStamp) { + Stack stack = getInstance().stacks.get(threadId); + if (!stack.isEmpty()) { + String line2 = stack.peek(); + if (line2.endsWith(shortSignature)) { + stack.pop(); + } else { + do { + stack.pop(); + getInstance().thread.terminateMethod(); + line2 = stack.peek(); + } while (!stack.isEmpty() && !line2.endsWith(shortSignature)); + if (!stack.isEmpty()) stack.pop(); + } + getInstance().thread = getInstance().threads.get(threadId); + ObjectReference returnVal = new ObjectReference(returnObjectId, returnClassName); + boolean isCollectionType = false; + if(thisClassName.contains("java.util.List") + || thisClassName.contains("java.util.Vector") + || thisClassName.contains("java.util.Iterator") + || thisClassName.contains("java.util.ListIterator") + || thisClassName.contains("java.util.ArrayList") + || thisClassName.contains("java.util.Stack") + || thisClassName.contains("java.util.Hash") + || thisClassName.contains("java.util.Map") + || thisClassName.contains("java.util.Set") + || thisClassName.contains("java.util.Linked") + || thisClassName.contains("java.lang.Thread")) { + isCollectionType = true; + } + // ���\�b�h����̕��A�̐ݒ� + getInstance().thread.returnMethod(returnVal, thisObjectId, isCollectionType, timeStamp); + } + } + + public static synchronized void onlineTraceConstructorExit(String shortSignature, String returnClassName, String returnObjectId, + String threadId, long timeStamp) { + String thisClassName = returnClassName; + String thisObjectId = returnObjectId; + Stack stack = getInstance().stacks.get(threadId); + if (!stack.isEmpty()) { + String line2 = stack.peek(); + if (line2.endsWith(shortSignature)) { + stack.pop(); + } else { + do { + stack.pop(); + getInstance().thread.terminateMethod(); + line2 = stack.peek(); + } while (!stack.isEmpty() && !line2.endsWith(shortSignature)); + if (!stack.isEmpty()) stack.pop(); + } + getInstance().thread = getInstance().threads.get(threadId); + ObjectReference returnVal = new ObjectReference(returnObjectId, returnClassName); + boolean isCollectionType = false; + if(thisClassName.contains("java.util.List") + || thisClassName.contains("java.util.Vector") + || thisClassName.contains("java.util.Iterator") + || thisClassName.contains("java.util.ListIterator") + || thisClassName.contains("java.util.ArrayList") + || thisClassName.contains("java.util.Stack") + || thisClassName.contains("java.util.Hash") + || thisClassName.contains("java.util.Map") + || thisClassName.contains("java.util.Set") + || thisClassName.contains("java.util.Linked") + || thisClassName.contains("java.lang.Thread")) { + isCollectionType = true; + } + // ���\�b�h����̕��A�̐ݒ� + getInstance().thread.returnMethod(returnVal, thisObjectId, isCollectionType, timeStamp); + } + } + + public static synchronized void onlineTraceFieldGet(String fieldName, String thisClassName, String thisObjectId, + String containerClassName, String containerObjectId, String valueClassName, String valueObjectId, + String threadId, String lineNum, long timeStamp) { + getInstance().thread = getInstance().threads.get(threadId); + // �t�B�[���h�A�N�Z�X�̐ݒ� + if (getInstance().thread != null) getInstance().thread.fieldAccess(fieldName, valueClassName, valueObjectId, containerClassName, containerObjectId, thisClassName, thisObjectId, Integer.parseInt(lineNum), timeStamp); + } + + public static synchronized void onlineTraceFieldSet(String fieldName, String containerClassName, String containerObjectId, + String valueClassName, String valueObjectId, String threadId, String lineNum, long timeStamp) { + getInstance().thread = getInstance().threads.get(threadId); + // �t�B�[���h�X�V�̐ݒ� + if (getInstance().thread != null) getInstance().thread.fieldUpdate(fieldName, valueClassName, valueObjectId, containerClassName, containerObjectId, Integer.parseInt(lineNum), timeStamp); + } + + public static synchronized void onlineTraceArrayCreate(String arrayClassName, String arrayObjectId, String dimension, + String threadId, String lineNum, long timeStamp) { + getInstance().thread = getInstance().threads.get(threadId); + if (getInstance().thread != null) getInstance().thread.arrayCreate(arrayClassName, arrayObjectId, Integer.parseInt(dimension), Integer.parseInt(lineNum), timeStamp); + } + + public static synchronized void onlineTraceArraySet(String arrayClassName, String arrayObjectId, int index, + String valueClassName, String valueObjectId, String threadId, long timeStamp) { + // �z��v�f�ւ̑�� + getInstance().thread = getInstance().threads.get(threadId); + if (getInstance().thread != null) getInstance().thread.arraySet(arrayClassName, arrayObjectId, index, valueClassName, valueObjectId, 0, timeStamp); + } + + public static synchronized void onlineTraceArrayGet(String arrayClassName, String arrayObjectId, int index, + String valueClassName, String valueObjectId, String threadId, long timeStamp) { + // �z��v�f�̎Q�� + getInstance().thread = getInstance().threads.get(threadId); + if (getInstance().thread != null) getInstance().thread.arrayGet(arrayClassName, arrayObjectId, index, valueClassName, valueObjectId, 0, timeStamp); + } + + public static synchronized void onlineTraceBlockEntry(String blockId, String incomings, + String threadId, String lineNum, long timeStamp) { + // �u���b�N�̊J�n + getInstance().thread = getInstance().threads.get(threadId); + if (getInstance().thread != null) getInstance().thread.blockEnter(Integer.parseInt(blockId), Integer.parseInt(incomings), Integer.parseInt(lineNum), timeStamp); + } + + public static ThreadInstance getThreadInstanceForDebuggingControl(String threadId) { + return getInstance().threads.get(threadId); + } + + /** + * �w�肵���X���b�h��Ō��ݎ��s���̃��\�b�h���s���擾����(�I�����C����͗p) + * @param thread �ΏۃX���b�h + * @return thread ��Ō��ݎ��s���̃��\�b�h���s + */ + public static MethodExecution getCurrentMethodExecution(Thread thread) { + ThreadInstance t = getInstance().threads.get(String.valueOf(thread.getId())); + return t.getCurrentMethodExecution(); + } + + /** + * �w�肵���X���b�h��Ō��ݎ��s���̃g���[�X�|�C���g���擾����(�I�����C����͗p) + * @param thread �ΏۃX���b�h + * @return thread ��Ō��ݎ��s���̎��s���̃g���[�X�|�C���g + */ + public static TracePoint getCurrentTracePoint(Thread thread) { + ThreadInstance t = getInstance().threads.get(String.valueOf(thread.getId())); + return t.getCurrentTracePoint(); + } + + /** + * �����œn�����R���e�i�����ƒt�B�[���h�̍ŏI�X�V�ɑΉ�����FieldUpdate��Ԃ� + * @param containerObjId + * @param fieldName + * @param thread + * @return + */ + public static FieldUpdate getRecentlyFieldUpdateForDebuggingControl(String containerObjId, String fieldName, Thread thread) { + TracePoint before = getCurrentTracePoint(thread); + if (!before.isValid()) { + before.stepBackOver(); + } + TracePoint tp = getFieldUpdateTracePointForDebuggingControl(containerObjId, fieldName, before); + if (tp != null && tp.getStatement() instanceof FieldUpdate) { + return (FieldUpdate)tp.getStatement(); + } + return null; + } + + /** + * �����Ŏw�肵���R���e�i�̎��“���̃t�B�[���h���Ō�ɍX�V���ꂽstatement���t�����ɒT�����āA
+ * ���‚�����statement�ɑΉ�����TracePoint��Ԃ� + * @param containerObjId + * @param fieldName + * @param before + * @return + */ + public static TracePoint getFieldUpdateTracePointForDebuggingControl(final String containerObjId, final String fieldName, TracePoint before) { + before = before.duplicate(); + before = getInstance().traverseStatementsInTraceBackward(new IStatementVisitor() { + @Override + public boolean preVisitStatement(Statement statement) { + if (statement instanceof FieldUpdate) { + FieldUpdate fu = (FieldUpdate)statement; + if (fu.getContainerObjId().equals(containerObjId) + && fu.getFieldName().equals(fieldName)) { + // �R���e�i�I�u�W�F�N�gID�ƃt�B�[���h�������Ɉ�v�����ꍇ + return true; + } + } + return false; + } + @Override + public boolean postVisitStatement(Statement statement) { return false; } + }, before); + if (before != null) { + return before; + } + return null; + } + + /** + * �����œn�����z��̎w��C���f�b�N�X�̍ŏI�X�V�ɑΉ�����ArrayUpdate��Ԃ� + * @param arrayObjId + * @param index + * @param thread + * @return + */ + public static ArrayUpdate getRecentlyArrayUpdateForDebuggingControl(String arrayObjId, int index, Thread thread) { + TracePoint before = getCurrentTracePoint(thread); + if (!before.isValid()) { + before.stepBackOver(); + } + TracePoint tp = getArrayUpdateTracePointForDebuggingControl(arrayObjId, index, before); + if (tp != null && tp.getStatement() instanceof ArrayUpdate) { + return (ArrayUpdate)tp.getStatement(); + } + return null; + } + + /** + * �����Ŏw�肵���z��ŁA���Žw�肵���C���f�b�N�X���Ō�ɍX�V���ꂽstatement���t�����ɒT�����āA
+ * ���‚�����statement�ɑΉ�����TracePoint��Ԃ� + * @param arrayObjId + * @param index + * @param before + * @return + */ + public static TracePoint getArrayUpdateTracePointForDebuggingControl(final String arrayObjId, final int index, TracePoint before) { + before = before.duplicate(); + before = getInstance().traverseStatementsInTraceBackward(new IStatementVisitor() { + @Override + public boolean preVisitStatement(Statement statement) { + if (statement instanceof ArrayUpdate) { + ArrayUpdate au = (ArrayUpdate)statement; + if (au.getArrayObjectId().equals(arrayObjId) + && au.getIndex() == index) { + // �z��ID�ƃC���f�b�N�X�����Ɉ�v�����ꍇ + return true; + } + } + return false; + } + @Override + public boolean postVisitStatement(Statement statement) { return false; } + }, before); + if (before != null) { + return before; + } + return null; + } +} diff --git a/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/TracePoint.java b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/TracePoint.java new file mode 100644 index 0000000..0219a9d --- /dev/null +++ b/org.ntlab.traceCollector/src/org/ntlab/traceCollector/tracer/trace/TracePoint.java @@ -0,0 +1,175 @@ +package org.ntlab.traceCollector.tracer.trace; + +import java.util.ArrayList; + +public class TracePoint { + private MethodExecution methodExecution; + private int order = 0; + + public TracePoint(MethodExecution methodExecution, int order) { + this.methodExecution = methodExecution; + this.order = order; + } + + public TracePoint duplicate() { + return new TracePoint(methodExecution, order); + } + + public Statement getStatement() { + return methodExecution.getStatements().get(order); + } + + public MethodExecution getMethodExecution() { + return methodExecution; + } + + public ArrayList getPreviouslyCalledMethods() { + ArrayList children = new ArrayList(); + ArrayList statements = methodExecution.getStatements(); + for (int i = 0; i < order; i++) { + Statement statement = statements.get(i); + if (statement instanceof MethodInvocation) { + MethodExecution child = ((MethodInvocation)statement).getCalledMethodExecution(); + children.add(child); + } + } + return children; + } + + /** + * �������̑S�T��(�������A���s�����L�^����Ă��Ȃ����\�b�h���s�ɂ͐���Ȃ�) + * @return false: ����ȏ�H��Ȃ��ꍇ, true: ����ȊO + */ + public boolean stepFull() { + if (getStatement() instanceof MethodInvocation) { + MethodExecution calledMethodExecution = ((MethodInvocation)getStatement()).getCalledMethodExecution(); + if (calledMethodExecution.getStatements().size() > 0) { + methodExecution = calledMethodExecution; + order = 0; + return true; + } + } + while (order >= methodExecution.getStatements().size() - 1) { + order = methodExecution.getCallerStatementExecution(); + methodExecution = methodExecution.getCallerMethodExecution(); + if (methodExecution == null) { + order = -1; + return false; + } + } + order++; + return true; + } + + /** + * �t�����̑S�T��(�������A���s�����L�^����Ă��Ȃ����\�b�h���s�ɂ͐���Ȃ��B�܂��A�Ăяo����̃��\�b�h���s����T��������ɁA�Ăяo�����̃��\�b�h�Ăяo������K�₷��̂Œ���!!) + * @return false: ����ȏ�H��Ȃ��ꍇ, true: ����ȊO + */ + public boolean stepBackFull() { + if (order <= 0) { + order = methodExecution.getCallerStatementExecution(); + methodExecution = methodExecution.getCallerMethodExecution(); + if (methodExecution == null) { + order = -1; + return false; + } + return true; + } + order--; + while (getStatement() instanceof MethodInvocation) { + MethodExecution calledMethodExecution = ((MethodInvocation)getStatement()).getCalledMethodExecution(); + if (calledMethodExecution.getStatements().size() == 0) break; + methodExecution = calledMethodExecution; + order = methodExecution.getStatements().size() - 1; + } + return true; + } + + /** + * �������ɒT������B�Ăяo�����ɖ߂邪�Ăяo����ɂ͐���Ȃ��B + * @return false: �Ăяo�����ɖ߂����ꍇ�܂��͂���ȏ�H��Ȃ��ꍇ, true: ����ȊO + */ + public boolean stepOver() { + if (order < methodExecution.getStatements().size() - 1) { + order++; + return true; + } + order = methodExecution.getCallerStatementExecution(); + methodExecution = methodExecution.getCallerMethodExecution(); + if (methodExecution == null) { + order = -1; + return false; + } + return false; + } + + /** + * �t�����ɒT������B�Ăяo�����ɖ߂邪�Ăяo����ɂ͐���Ȃ��B + * @return false: �Ăяo�����ɖ߂����ꍇ�܂��͂���ȏ�H��Ȃ��ꍇ, true: ����ȊO + */ + public boolean stepBackOver() { + if (order > 0) { + order--; + return true; + } + order = methodExecution.getCallerStatementExecution(); + methodExecution = methodExecution.getCallerMethodExecution(); + if (methodExecution == null) { + order = -1; + return false; + } + return false; + } + + /** + * �������ɒT������B�Ăяo�����H�邪�Ăяo�����ɂ͖߂�Ȃ��B + * @return false: �Ăяo����Ɉڂ����ꍇ�܂��͂���ȏ�H��Ȃ��ꍇ, true: ����ȊO + */ + public boolean stepNoReturn() { + if (getStatement() instanceof MethodInvocation) { + methodExecution = ((MethodInvocation)getStatement()).getCalledMethodExecution(); + if (methodExecution.getStatements().size() > 0) { + order = 0; + } else { + order = -1; // �Ăяo����Ŏ��s�����L�^����Ă��Ȃ��ꍇ + } + return false; + } + order++; + if (order < methodExecution.getStatements().size()) { + return true; + } + return false; + } + + /** + * �t�����ɒT������B�Ăяo�����H�邪�Ăяo�����ɂ͖߂�Ȃ��B(��ɌĂяo�����̃��\�b�h�Ăяo������K�₵�Ă���Ăяo����̃��\�b�h���s��K�₷��̂Œ���!!) + * @return�@false: �Ăяo����Ɉڂ����ꍇ�܂��͂���ȏ�H��Ȃ��ꍇ, true: ����ȊO + */ + public boolean stepBackNoReturn() { + if (getStatement() instanceof MethodInvocation) { + methodExecution = ((MethodInvocation)getStatement()).getCalledMethodExecution(); + order = methodExecution.getStatements().size() - 1; // -1 �ɂȂ�ꍇ������(�Ăяo����Ŏ��s�����L�^����Ă��Ȃ��ꍇ) + return false; + } + order--; + if (order >= 0) { + return true; + } + return false; + } + + public boolean isValid() { + if (methodExecution == null || order == -1 || order >= methodExecution.getStatements().size()) return false; + return true; + } + + public boolean isMethodEntry() { + return (order == 0); + } + + public boolean isStepBackOut() { + if (order < 0) return true; + return false; + } +}