package com.ikokoon.serenity.instrumentation.profiling; import org.apache.log4j.Logger; import org.objectweb.asm.Label; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import com.ikokoon.serenity.IConstants; import com.ikokoon.toolkit.Toolkit; /** * Not used, to be removed. * * @see {@link ProfilingClassAdapter} * * @author Michael Couck * @since 30.09.09 * @version 01.00 */ public class ProfilingMethodAdapter extends MethodAdapter implements Opcodes { /** The logger for the class. */ private Logger logger = Logger.getLogger(ProfilingMethodAdapter.class); /** The name of the class that this method adapter is enhancing the methods for. */ private String className; private String methodName; /** The description of the method being enhanced. */ private String methodDescription; private String objectName = "java/lang/Object"; private String threadName = "java/lang/Thread"; private String sleep = "sleep"; private String wait = "wait"; private String join = "join"; private String yield = "yield"; private boolean clinit = false; private boolean init = false; /** * The constructor takes all the interesting items for the method that is to be enhanced. * * @param methodVisitor * the parent method visitor * @param className * the name of the class to enhance * @param methodName * the name of the method to enhance * @param methodDescription * the method description */ public ProfilingMethodAdapter(MethodVisitor methodVisitor, Integer access, String className, String methodName, String methodDescription) { super(methodVisitor); this.className = Toolkit.slashToDot(className); this.methodName = methodName; this.methodDescription = methodDescription; logger.debug("Class name : " + className + ", name : " + methodName + ", desc : " + methodDescription); if (methodName.equals("<clinit>")) { clinit = true; } else if (methodName.startsWith("<init>")) { init = true; } } public void visitCode() { logger.warn("Class name : " + className + ", name : " + methodName + ", desc : " + methodDescription); if (clinit) { // super.visitCode() this.mv.visitCode(); return; } if (init) { // Because the collectAllocation method looks at the class + method // of the caller this call needs to come before the call to insertInstruction(IConstants.COLLECTOR_CLASS_NAME, IConstants.COLLECT_ALLOCATION, IConstants.PROFILING_METHOD_DESCRIPTION); // this.visitLdcInsn(className); // this.visitLdcInsn(methodName); // this.visitLdcInsn(methodDescription); // this.visitMethodInsn(Opcodes.INVOKESTATIC, IConstants.collectorClassName, IConstants.collectAllocation, // IConstants.profilingMethodDescription); // this.visitMethodInsn(INVOKESTATIC, collectorClassName, "collectAllocation", "(Ljava/lang/String;)V"); } insertInstruction(IConstants.COLLECTOR_CLASS_NAME, IConstants.COLLECT_START, IConstants.PROFILING_METHOD_DESCRIPTION); // this.visitLdcInsn(className); // this.visitLdcInsn(methodName); // this.visitMethodInsn(INVOKESTATIC, collectorClassName, "collectStart", "(Ljava/lang/String;Ljava/lang/String;)V"); this.mv.visitCode(); // super.visitCode(); } public void visitInsn(int inst) { if (clinit) { super.visitInsn(inst); // this.mv.visitInsn(inst); return; } switch (inst) { case Opcodes.ARETURN: case Opcodes.DRETURN: case Opcodes.FRETURN: case Opcodes.IRETURN: case Opcodes.LRETURN: case Opcodes.RETURN: case Opcodes.ATHROW: insertInstruction(IConstants.COLLECTOR_CLASS_NAME, IConstants.COLLECT_END, IConstants.PROFILING_METHOD_DESCRIPTION); // this.visitLdcInsn(className); // this.visitLdcInsn(methodName); // this.visitMethodInsn(INVOKESTATIC, collectorClassName, "collectEnd", "(Ljava/lang/String;Ljava/lang/String;)V"); break; default: break; } this.mv.visitInsn(inst); if (Opcodes.MONITORENTER == inst) { insertInstruction(IConstants.COLLECTOR_CLASS_NAME, IConstants.COLLECT_START_WAIT, IConstants.PROFILING_METHOD_DESCRIPTION); // this.visitLdcInsn(className); // this.visitLdcInsn(methodName); // this.visitMethodInsn(INVOKESTATIC, collectorClassName, "beginWait", "(Ljava/lang/String;Ljava/lang/String;)V"); // super.visitInsn(inst); insertInstruction(IConstants.COLLECTOR_CLASS_NAME, IConstants.COLLECT_END_WAIT, IConstants.PROFILING_METHOD_DESCRIPTION); // this.visitLdcInsn(className); // this.visitLdcInsn(methodName); // this.visitMethodInsn(INVOKESTATIC, collectorClassName, "endWait", "(Ljava/lang/String;Ljava/lang/String;)V"); } else { // super.visitInsn(inst); // this.mv.visitInsn(inst); } } @Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { if (isWaitInsn(opcode, owner, name, desc)) { insertInstruction(IConstants.COLLECTOR_CLASS_NAME, IConstants.COLLECT_START_WAIT, IConstants.PROFILING_METHOD_DESCRIPTION); // this.visitLdcInsn(className); // this.visitLdcInsn(methodName); // this.visitMethodInsn(INVOKESTATIC, collectorClassName, "beginWait", "(Ljava/lang/String;Ljava/lang/String;)V"); // super.visitMethodInsn(opcode, owner, name, desc); this.mv.visitMethodInsn(opcode, owner, name, desc); insertInstruction(IConstants.COLLECTOR_CLASS_NAME, IConstants.COLLECT_END_WAIT, IConstants.PROFILING_METHOD_DESCRIPTION); // this.visitLdcInsn(className); // this.visitLdcInsn(methodName); // this.visitMethodInsn(INVOKESTATIC, collectorClassName, "endWait", "(Ljava/lang/String;Ljava/lang/String;)V"); } else { // super.visitMethodInsn(opcode, owner, name, desc); this.mv.visitMethodInsn(opcode, owner, name, desc); } } private void insertInstruction(String collectorClassName, String collectorMethodName, String collectorMethodDescription) { this.mv.visitLdcInsn(this.className); this.mv.visitLdcInsn(this.methodName); this.mv.visitLdcInsn(this.methodDescription); this.mv.visitMethodInsn(Opcodes.INVOKESTATIC, collectorClassName, collectorMethodName, collectorMethodDescription); } /** * Code to handle unwinding the call stack when an exception is thrown. */ @Override public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { // super.visitTryCatchBlock(start, end, handler, type); this.mv.visitTryCatchBlock(start, end, handler, type); // Note: static initializers aren't measured, so make sure that the exception isn't being caught in one if (type != null && !clinit) { // handler.info = new ExceptionInfo(type); // int offset = handler.getOffset(); } } @Override public void visitLabel(Label label) { // super.visitLabel(label); this.mv.visitLabel(label); if (true /* label.info instanceof ExceptionInfo */) { // this.visitLdcInsn(className); // this.visitLdcInsn(methodName); // this.visitLdcInsn(((ExceptionInfo) label.info).type); // this.visitMethodInsn(INVOKESTATIC, collectorClassName, "unwind", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); } } // class ExceptionInfo { // String type; // // ExceptionInfo(String type) { // this.type = type; // } // } private boolean isWaitInsn(int opcode, String owner, String name, String desc) { switch (opcode) { case Opcodes.INVOKESTATIC: { if (threadName.equals(owner)) { if (sleep.equals(name)) { if ("(J)V".equals(desc) || "(JI)V".equals(desc)) { return true; } } } if (threadName.equals(owner)) { if (yield.equals(name)) { if ("()V".equals(desc)) { return true; } } } } case Opcodes.INVOKEVIRTUAL: { if (objectName.equals(owner)) { if (wait.equals(name)) { if ("()V".equals(desc) || "(J)V".equals(desc) || "(JI)V".equals(desc)) { return true; } } } if (threadName.equals(owner)) { if (join.equals(name)) { if ("()V".equals(desc) || "(J)V".equals(desc) || "(JI)V".equals(desc)) { return true; } } } } } return false; } }