diff --git a/TracerOnJavassist/src/tracer/ITraceGenerator.java b/TracerOnJavassist/src/tracer/ITraceGenerator.java index 870078d..364d98c 100644 --- a/TracerOnJavassist/src/tracer/ITraceGenerator.java +++ b/TracerOnJavassist/src/tracer/ITraceGenerator.java @@ -1,5 +1,7 @@ package tracer; +import java.util.List; + import javassist.CtBehavior; import javassist.CtClass; @@ -11,23 +13,25 @@ public interface ITraceGenerator { public abstract String generateReplaceStatementsForFieldSet( - String targetClass, String targetObject, - String argClass, String argObject, + String fieldName, String containerClass, String containerObject, + String valueClass, String valueObject, String threadId, String timeStamp); - public abstract String generateReplaceStatementsForFieldGet(String thisClass, String thisObject, - String targetClass, String targetObject, - String returnedClass, String returnedObject, + public abstract String generateReplaceStatementsForFieldGet( + String fieldName, String thisClass, String thisObject, + String containerClass, String containerObject, + String valueClass, String valueObject, String threadId, String timeStamp); public abstract String generateInsertBeforeStatements( CtBehavior m, String methodSignature, - String thisClass, String thisObject, CtClass[] parameterClasses, + String thisClass, String thisObject, + List argClasses, List argObjects, String threadId, String timeStamp); public abstract String generateInsertAfterStatements( CtClass cls, CtBehavior m, - String thisObject, + String thisClass, String thisObject, String returnedClass, String returnedObject, String threadId, String timeStamp, boolean isCallerSideInstrumentation); diff --git a/TracerOnJavassist/src/tracer/JSONTraceGenerator.java b/TracerOnJavassist/src/tracer/JSONTraceGenerator.java new file mode 100644 index 0000000..a90c228 --- /dev/null +++ b/TracerOnJavassist/src/tracer/JSONTraceGenerator.java @@ -0,0 +1,128 @@ +package tracer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; + +import javassist.CtBehavior; +import javassist.CtClass; +import javassist.CtConstructor; + +public class JSONTraceGenerator implements ITraceGenerator { + private static final String DQ_GEN = "\"\\\"\""; + + @Override + public String generateReplaceStatementsForFieldSet( + String fieldName, String containerClass, String containerObject, + String valueClass, String valueObject, + String threadId, String timeStamp) { + ArrayList keys = new ArrayList<>(); + ArrayList values = new ArrayList<>(); + keys.add("type"); values.add(DQ_GEN + " + \"fieldSet\" + " + DQ_GEN); + keys.add("fieldName"); values.add(DQ_GEN + " + " + fieldName + " + " + DQ_GEN); + keys.add("container"); values.add(generateJSONObjectGenerator(containerClass, containerObject)); + keys.add("value"); values.add(generateJSONObjectGenerator(valueClass, valueObject)); + keys.add("threadId"); values.add(threadId); + keys.add("time"); values.add(timeStamp); + return "{$proceed($$); " + + "tracer.MyPrintStream.println(" + generateJSONMapGenerator(keys, values) + " + \",\");}"; + } + + @Override + public String generateReplaceStatementsForFieldGet( + String fieldName, String thisClass, String thisObject, + String containerClass, String containerObject, + String valueClass, String valueObject, + String threadId, String timeStamp) { + ArrayList keys = new ArrayList<>(); + ArrayList values = new ArrayList<>(); + keys.add("type"); values.add(DQ_GEN + " + \"fieldGet\" + " + DQ_GEN); + keys.add("fieldName"); values.add(DQ_GEN + " + " + fieldName + " + " + DQ_GEN); + keys.add("this"); values.add(generateJSONObjectGenerator(thisClass, thisObject)); + keys.add("container"); values.add(generateJSONObjectGenerator(containerClass, containerObject)); + keys.add("value"); values.add(generateJSONObjectGenerator(valueClass, valueObject)); + keys.add("threadId"); values.add(threadId); + keys.add("time"); values.add(timeStamp); + return "{$_ = $proceed(); " + + "tracer.MyPrintStream.println(" + generateJSONMapGenerator(keys, values) + " + \",\");}"; + } + + @Override + public String generateInsertBeforeStatements( + CtBehavior m, String methodSignature, + String thisClass, String thisObject, + List argClasses, List argObjects, + String threadId, String timeStamp) { + ArrayList keys = new ArrayList<>(); + ArrayList values = new ArrayList<>(); + if (!(m instanceof CtConstructor)) { + keys.add("type"); values.add(DQ_GEN + " + \"methodEntry\" + " + DQ_GEN); + } else { + keys.add("type"); values.add(DQ_GEN + " + \"constructorEntry\" + " + DQ_GEN); + } + keys.add("signature"); values.add(DQ_GEN + " + " + methodSignature + " + " + DQ_GEN); + if (!(m instanceof CtConstructor)) { + keys.add("receiver"); values.add(generateJSONObjectGenerator(thisClass, thisObject)); + } + ArrayList argList = new ArrayList<>(); + for (int i = 0; i < argClasses.size(); i++) { + argList.add(generateJSONObjectGenerator(argClasses.get(i), argObjects.get(i))); + } + keys.add("args"); values.add(generateJSONArrayGenerator(argList)); + keys.add("threadId"); values.add(threadId); + keys.add("time"); values.add(timeStamp); + String output = "tracer.MyPrintStream.println(" + generateJSONMapGenerator(keys, values) + " + \",\");"; + System.out.println(output); + return output; + } + + @Override + public String generateInsertAfterStatements(CtClass cls, CtBehavior m, + String thisClass, String thisObject, String returnedClass, String returnedObject, + String threadId, String timeStamp, + boolean isCallerSideInstrumentation) { + ArrayList keys = new ArrayList<>(); + ArrayList values = new ArrayList<>(); + if (!(m instanceof CtConstructor)) { + keys.add("type"); values.add(DQ_GEN + " + \"methodExit\" + " + DQ_GEN); + } else { + keys.add("type"); values.add(DQ_GEN + " + \"constructorExit\" + " + DQ_GEN); + } + if (!(m instanceof CtConstructor)) { + keys.add("receiver"); values.add(generateJSONObjectGenerator(thisClass, thisObject)); + } + keys.add("returnValue"); values.add(generateJSONObjectGenerator(returnedClass, returnedObject)); + keys.add("threadId"); values.add(threadId); + keys.add("time"); values.add(timeStamp); + return "tracer.MyPrintStream.println(" + generateJSONMapGenerator(keys, values) + " + \",\");"; + } + + private String generateJSONObjectGenerator(String className, String objectId) { + ArrayList keys = new ArrayList<>(); + ArrayList values = new ArrayList<>(); + keys.add("class"); values.add(DQ_GEN + " + " + className + " + " + DQ_GEN); + keys.add("id"); values.add(objectId); + return generateJSONMapGenerator(keys, values); + } + + private String generateJSONMapGenerator(ArrayList keys, ArrayList valueGenerators) { + String mapJSON = "\"{\" + "; + String delimiter = ""; + for (int i = 0; i < keys.size(); i++) { + mapJSON += delimiter + "\"\\\"" + keys.get(i) + "\\\":\" + " + valueGenerators.get(i); + delimiter = " + \",\" + "; + } + mapJSON += " + \"}\""; + return mapJSON; + } + private String generateJSONArrayGenerator(ArrayList valueGenerators) { + String arrayJSON = "\"[\""; + String delimiter = " + "; + for (int i = 0; i < valueGenerators.size(); i++) { + arrayJSON += delimiter + valueGenerators.get(i); + delimiter = " + \",\" + "; + } + arrayJSON += " + \"]\""; + return arrayJSON; + } +} diff --git a/TracerOnJavassist/src/tracer/OutputStatementsGenerator.java b/TracerOnJavassist/src/tracer/OutputStatementsGenerator.java index 4741f28..f820145 100644 --- a/TracerOnJavassist/src/tracer/OutputStatementsGenerator.java +++ b/TracerOnJavassist/src/tracer/OutputStatementsGenerator.java @@ -1,11 +1,14 @@ package tracer; +import java.util.ArrayList; + import javassist.CtBehavior; import javassist.CtClass; import javassist.CtConstructor; import javassist.CtMethod; import javassist.Modifier; import javassist.NotFoundException; +import javassist.expr.FieldAccess; /** * �g���[�X�o�͂��s�����s���𐶐�����N���X�i�t�H�[�}�b�g�ˑ�������ITraceGenerator�Ɉڏ��j @@ -20,17 +23,19 @@ this.generator = generator; } - public String generateReplaceStatementsForFieldSet(CtClass cc) { - String targetClass = "(($0 != null)?$0.getClass().getName():\"" + cc.getName() + "\")"; - String targetObject = "(($0 != null)?System.identityHashCode($0):0)"; - String argClass = "(($1 != null)?$1.getClass().getName():\"---\")"; - String argObject = "(($1 != null)?System.identityHashCode($1):0)"; + public String generateReplaceStatementsForFieldSet(CtClass cc, FieldAccess f) { + String fieldName = "\"" + f.getClassName() + "." + f.getFieldName() + "\""; + String containerClass = "(($0 != null)?$0.getClass().getName():\"" + cc.getName() + "\")"; + String containerObject = "(($0 != null)?System.identityHashCode($0):0)"; + String valueClass = "(($1 != null)?$1.getClass().getName():\"---\")"; + String valueObject = "(($1 != null)?System.identityHashCode($1):0)"; String threadId = "Thread.currentThread().getId()"; String timeStamp = "System.nanoTime()"; - return generator.generateReplaceStatementsForFieldSet(targetClass, targetObject, argClass, argObject, threadId, timeStamp); + return generator.generateReplaceStatementsForFieldSet(fieldName, containerClass, containerObject, valueClass, valueObject, threadId, timeStamp); } - public String generateReplaceStatementsForFieldGet(CtClass cc, CtBehavior m) { + public String generateReplaceStatementsForFieldGet(CtClass cc, CtBehavior m, FieldAccess f) { + String fieldName = "\"" + f.getClassName() + "." + f.getFieldName() + "\""; String thisClass; String thisObject; if ((m.getModifiers() & Modifier.STATIC) == 0 && m instanceof CtMethod) { @@ -41,13 +46,13 @@ thisClass = "\"" + cc.getName() + "\""; thisObject = "\"0\""; } - String targetClass = "(($0 != null)?$0.getClass().getName():\"---\")"; - String targetObject = "(($0 != null)?System.identityHashCode($0):0)"; - String returnedClass = "(($_ != null)?$_.getClass().getName():\"---\")"; - String returnedObject = "(($_ != null)?System.identityHashCode($_):0)"; + String containerClass = "(($0 != null)?$0.getClass().getName():\"---\")"; + String containerObject = "(($0 != null)?System.identityHashCode($0):0)"; + String valueClass = "(($_ != null)?$_.getClass().getName():\"---\")"; + String valueObject = "(($_ != null)?System.identityHashCode($_):0)"; String threadId = "Thread.currentThread().getId()"; String timeStamp = "System.nanoTime()"; - return generator.generateReplaceStatementsForFieldGet(thisClass, thisObject, targetClass, targetObject, returnedClass, returnedObject, threadId, timeStamp); + return generator.generateReplaceStatementsForFieldGet(fieldName, thisClass, thisObject, containerClass, containerObject, valueClass, valueObject, threadId, timeStamp); } @@ -72,8 +77,8 @@ * @throws NotFoundException */ private String generateInsertBeforeStatements(CtClass cls, CtBehavior m, boolean isCallerSideInstrumentation) throws NotFoundException { + // ���\�b�h�V�O�j�`���̍\�� String declaredClassName = cls.getName(); - CtClass parameterClasses[] = m.getParameterTypes(); String modifiers = ""; if ((m.getModifiers() & Modifier.PUBLIC) != 0) { modifiers = "public "; @@ -117,24 +122,44 @@ thisObject = "System.identityHashCode($0)"; } } + // �����̏o�͎��̍\�� + int p = 0; + CtClass parameterClasses[] = m.getParameterTypes(); + ArrayList argClasses = new ArrayList<>(); + ArrayList argObjects = new ArrayList<>(); + for (CtClass c : parameterClasses) { + if (!c.isPrimitive()) { + argClasses.add("$args[" + p + "].getClass().getName()"); + argObjects.add("System.identityHashCode($" + (p + 1) + ")"); + } else { + argClasses.add("$args[" + p + "].getClass().getName()"); + argObjects.add("$" + (p + 1)); + } + p++; + } + String threadId = "Thread.currentThread().getId()"; String timeStamp = "System.nanoTime()"; - return generator.generateInsertBeforeStatements(m, methodSignature, thisClass, thisObject, parameterClasses, threadId, timeStamp); + return generator.generateInsertBeforeStatements(m, methodSignature, thisClass, thisObject, argClasses, argObjects, threadId, timeStamp); } private String generateInsertAfterStatements(CtClass cls, CtBehavior m, boolean isCallerSideInstrumentation) throws NotFoundException { + String declaredClassName = cls.getName(); String returnedClass; String returnedObject; + String thisClass; String thisObject; if ((m.getModifiers() & Modifier.STATIC) != 0) { // static���\�b�h�̏ꍇ if (!((CtMethod)m).getReturnType().isPrimitive() || ((CtMethod)m).getReturnType() == CtClass.voidType) { returnedClass = "(($_ != null)?$_.getClass().getName():\"void\")"; returnedObject = "(($_ != null)?System.identityHashCode($_):0)"; + thisClass = "\"" + declaredClassName + "\""; thisObject = "\"0\""; } else { returnedClass = "\"" + ((CtMethod)m).getReturnType().getName() +"\""; returnedObject = "$_"; + thisClass = "\"" + declaredClassName + "\""; thisObject = "\"0\""; } } else if (m instanceof CtConstructor) { @@ -143,11 +168,13 @@ // �Ăяo����ɖ��ߍ��ޏꍇ(�ʏ�) returnedClass = "$0.getClass().getName()"; returnedObject = "System.identityHashCode($0)"; + thisClass = "\"" + declaredClassName + "\""; thisObject = "System.identityHashCode($0)"; } else { // �ďo�����ɖ��ߍ��ޏꍇ(�W���N���X�������̓f�t�H���g�R���X�g���N�^�̌ďo���A�܂��͐e�R���X�g���N�^�̌ďo��) returnedClass = "(($_ != null)?$_.getClass().getName():$0.getClass().getName())"; returnedObject = "(($_ != null)?System.identityHashCode($_):System.identityHashCode($0))"; + thisClass = "\"" + declaredClassName + "\""; thisObject = "(($_ != null)?System.identityHashCode($_):System.identityHashCode($0))"; } } else { @@ -157,10 +184,12 @@ if (!((CtMethod)m).getReturnType().isPrimitive() || ((CtMethod)m).getReturnType() == CtClass.voidType) { returnedClass = "(($_ != null)?$_.getClass().getName():\"void\")"; returnedObject = "(($_ != null)?System.identityHashCode($_):0)"; + thisClass = "this.getClass().getName()"; thisObject = "System.identityHashCode(this)"; } else { returnedClass = "\"" + ((CtMethod)m).getReturnType().getName() +"\""; returnedObject = "$_"; + thisClass = "this.getClass().getName()"; thisObject = "System.identityHashCode(this)"; } } else { @@ -168,16 +197,18 @@ if (!((CtMethod)m).getReturnType().isPrimitive() || ((CtMethod)m).getReturnType() == CtClass.voidType) { returnedClass = "(($_ != null)?$_.getClass().getName():\"void\")"; returnedObject = "(($_ != null)?System.identityHashCode($_):0)"; + thisClass = "$0.getClass().getName()"; thisObject = "System.identityHashCode($0)"; } else { returnedClass = "\"" + ((CtMethod)m).getReturnType().getName() +"\""; returnedObject = "$_"; + thisClass = "$0.getClass().getName()"; thisObject = "System.identityHashCode($0)"; } } } String threadId = "Thread.currentThread().getId()"; String timeStamp = "System.nanoTime()"; - return generator.generateInsertAfterStatements(cls, m, thisObject, returnedClass, returnedObject, threadId, timeStamp, isCallerSideInstrumentation); + return generator.generateInsertAfterStatements(cls, m, thisClass, thisObject, returnedClass, returnedObject, threadId, timeStamp, isCallerSideInstrumentation); } } diff --git a/TracerOnJavassist/src/tracer/PlainTextTraceGenerator.java b/TracerOnJavassist/src/tracer/PlainTextTraceGenerator.java index 3c092c6..c65c7c8 100644 --- a/TracerOnJavassist/src/tracer/PlainTextTraceGenerator.java +++ b/TracerOnJavassist/src/tracer/PlainTextTraceGenerator.java @@ -1,5 +1,7 @@ package tracer; +import java.util.List; + import javassist.CtBehavior; import javassist.CtClass; import javassist.CtConstructor; @@ -9,41 +11,40 @@ public static final String LINE = "\":Line \" + (tracer.Tracer.lineNo++) + \":\""; @Override - public String generateReplaceStatementsForFieldSet(String targetClass, String targetObject, String argClass, String argObject, String threadId, String timeStamp) { + public String generateReplaceStatementsForFieldSet( + String fieldName, String containerClass, String containerObject, + String valueClass, String valueObject, String threadId, String timeStamp) { return "{$proceed($$); " + - "tracer.MyPrintStream.println(\"set:\" + " + targetClass + " + \":\" + " + targetObject + " + \":\" + " + - argClass + " + \":\" + " + argObject + " + " + LINE_AND_THREAD + threadId + ");}"; + "tracer.MyPrintStream.println(\"set:\" + " + containerClass + " + \":\" + " + containerObject + " + \":\" + " + + valueClass + " + \":\" + " + valueObject + " + " + LINE_AND_THREAD + threadId + ");}"; } @Override - public String generateReplaceStatementsForFieldGet(String thisClass, String thisObject, String targetClass, String targetObject, - String returnedClass, String returnedObject, String threadId, String timeStamp) { + public String generateReplaceStatementsForFieldGet( + String fieldName, String thisClass, String thisObject, String containerClass, String containerObject, + String valueClass, String valueObject, String threadId, String timeStamp) { return "{$_ = $proceed(); " + "tracer.MyPrintStream.println(\"get:\" + " + thisClass + " + \":\" + " + thisObject + " + \":\" + " + - targetClass + " + \":\" + " + targetObject + " + \":\" + " + - returnedClass + " + \":\" + " + returnedObject + " + " + LINE_AND_THREAD + threadId + ");}"; + containerClass + " + \":\" + " + containerObject + " + \":\" + " + + valueClass + " + \":\" + " + valueObject + " + " + LINE_AND_THREAD + threadId + ");}"; } @Override public String generateInsertBeforeStatements(CtBehavior m, String methodSignature, - String thisClass, String thisObject, CtClass[] parameterClasses, String threadId, String timeStamp) { + String thisClass, String thisObject, + List argClasses, List argObjects, + String threadId, String timeStamp) { String newOutput = ""; String methodOutput = ""; String classOutput = ""; String argsOutput = ""; - String delimiter = "tracer.MyPrintStream.println(\"Args:\" + "; // �����̏o�� - int p = 0; - for (CtClass c : parameterClasses) { - if (!c.isPrimitive()) { - argsOutput += delimiter + "$args[" + p + "].getClass().getName() + " + "\":\" + System.identityHashCode($" + (p + 1) + ")"; - } else { - argsOutput += delimiter + "$args[" + p + "].getClass().getName() + " + "\":\" + $" + (p + 1); - } - p++; + String delimiter = "tracer.MyPrintStream.println(\"Args:\" + "; + for (int p = 0; p < argClasses.size(); p++) { + argsOutput += delimiter + argClasses.get(p) + " + \":\" + " + argObjects.get(p); delimiter = " + \":\" + "; } - if (p > 0) { + if (argClasses.size() > 0) { argsOutput += " + " + LINE_AND_THREAD + threadId + ");"; } if (m instanceof CtConstructor) { @@ -59,7 +60,9 @@ @Override public String generateInsertAfterStatements(CtClass cls, CtBehavior m, - String thisObject, String returnedClass, String returnedObject, String threadId, String timeStamp, boolean isCallerSideInstrumentation) { + String thisClass, String thisObject, + String returnedClass, String returnedObject, + String threadId, String timeStamp, boolean isCallerSideInstrumentation) { String shortName = null; String invocationType = null; if (m instanceof CtConstructor) { diff --git a/TracerOnJavassist/src/tracer/Tracer.java b/TracerOnJavassist/src/tracer/Tracer.java index 33bd9b5..9baa5ce 100644 --- a/TracerOnJavassist/src/tracer/Tracer.java +++ b/TracerOnJavassist/src/tracer/Tracer.java @@ -39,8 +39,8 @@ private static OutputStatementsGenerator outputStatementsGenerator = null; public static void main(String[] args) { - outputStatementsGenerator = new OutputStatementsGenerator(new PlainTextTraceGenerator()); // �����ŏo�̓t�H�[�}�b�g���w�肷�� - String packageName = "constructor"; // �w�肵���p�b�P�[�W�����̑S�N���X�ɃC���X�g�D�������e�[�V�������s�� + outputStatementsGenerator = new OutputStatementsGenerator(new JSONTraceGenerator()); // �����ŏo�̓t�H�[�}�b�g���w�肷�� + String packageName = "arraySample"; // �w�肵���p�b�P�[�W�����̑S�N���X�ɃC���X�g�D�������e�[�V�������s�� ClassLoader loader = Thread.currentThread().getContextClassLoader(); URL resource = loader.getResource(packageName); File dir; @@ -91,11 +91,11 @@ public void edit(FieldAccess f) throws CannotCompileException { if (f.isReader()) { if (!f.getFieldName().contains("$")) { // AspectJ�ł� final local �ϐ�����̃Q�b�g�͖��������̂ŁA����ɍ��킹�ď��O���� - f.replace(outputStatementsGenerator.generateReplaceStatementsForFieldGet(cc, m)); + f.replace(outputStatementsGenerator.generateReplaceStatementsForFieldGet(cc, m, f)); } } else { if (!f.getFieldName().contains("$")) { // ���̏������Ȃ��ƂȂ���������i�����t�B�[���h?�ւ̃Z�b�g�������āA������E���ė����Ă�?�j - f.replace(outputStatementsGenerator.generateReplaceStatementsForFieldSet(cc)); + f.replace(outputStatementsGenerator.generateReplaceStatementsForFieldSet(cc, f)); } } }