001 package org.shiftone.jrat.inject.bytecode.asm; 002 003 004 import org.objectweb.asm.Label; 005 import org.objectweb.asm.MethodVisitor; 006 import org.objectweb.asm.Opcodes; 007 import org.objectweb.asm.Type; 008 import org.objectweb.asm.commons.GeneratorAdapter; 009 import org.objectweb.asm.commons.Method; 010 import org.shiftone.jrat.inject.bytecode.Modifier; 011 import org.shiftone.jrat.util.log.Logger; 012 013 014 /** 015 * @author jeff@shiftone.org (Jeff Drost) 016 */ 017 public class ProxyMethodVisitor extends GeneratorAdapter implements Constants, Opcodes { 018 019 private static final Logger LOG = Logger.getLogger(ProxyMethodVisitor.class); 020 private boolean isStatic; 021 private boolean isVoidReturn; 022 private Type classType; 023 private String handlerFieldName; 024 private String targetMethodName; 025 private Method method; 026 027 public ProxyMethodVisitor(int access, Method method, MethodVisitor mv, Type classType, String targetMethodName, 028 String handlerFieldName) { 029 030 super(access, method, mv); 031 032 this.method = method; 033 this.isStatic = Modifier.isStatic(access); 034 this.isVoidReturn = Type.VOID_TYPE.equals(method.getReturnType()); 035 this.classType = classType; 036 this.targetMethodName = targetMethodName; 037 this.handlerFieldName = handlerFieldName; 038 } 039 040 041 public void visitCode() { 042 043 Label tryLabel = newLabel(); 044 045 // ------------------------------------------------------------------------------- 046 // HANDLER.onMethodStart(this); 047 getStatic(classType, handlerFieldName, Constants.MethodHandler.TYPE); 048 pushThis(); 049 invokeInterface(MethodHandler.TYPE, MethodHandler.onMethodStart); 050 mark(tryLabel); 051 052 // ------------------------------------------------------------------------------- 053 // long startTime = System.currentTimeNanos(); 054 int startTime = newLocal(Type.LONG_TYPE); 055 056 invokeStatic(Clock.TYPE, Clock.currentTimeNanos); 057 storeLocal(startTime, Type.LONG_TYPE); 058 059 // ------------------------------------------------------------------------------- 060 // local var result is defined only if there is a non-void return type 061 // Object result = method(args) 062 Label tryStart = mark(); // try { 063 064 if (isStatic) { 065 loadArgs(); // push the args on the stack 066 invokeStatic(classType, new Method(targetMethodName, method.getDescriptor())); 067 } else { 068 loadThis(); // push this on the stack (for non-static methods) 069 loadArgs(); // push the args on the stack 070 invokeVirtual(classType, new Method(targetMethodName, method.getDescriptor())); 071 } 072 073 int result = -1; 074 075 if (!isVoidReturn) { 076 result = newLocal(method.getReturnType()); 077 078 storeLocal(result); 079 } 080 081 // ------------------------------------------------------------------------------- 082 // HANDLER.onMethodFinish(this, System.currentTimeNanos - start, null); 083 getStatic(classType, handlerFieldName, MethodHandler.TYPE); // get the 084 085 // MethodHandler 086 pushThis(); // param 1 087 invokeStatic(Clock.TYPE, Clock.currentTimeNanos); // param 2 : obtain 088 089 // end time 090 // (Clock.currentTimeNanos) 091 loadLocal(startTime); // param 2 : getPreferences the start time onto the stack 092 math(GeneratorAdapter.SUB, Type.LONG_TYPE); // param 2 : subtract, 093 094 // leaving the result on the 095 // stack 096 visitInsn(ACONST_NULL); // param 2 : null (no exception) 097 invokeInterface(MethodHandler.TYPE, MethodHandler.onMethodFinish); 098 099 // ------------------------------------------------------------------------------- 100 // return result; 101 if (!isVoidReturn) { 102 loadLocal(result); 103 } 104 105 returnValue(); 106 107 Label tryEnd = mark(); // } catch (Throwable e) { 108 109 // this is the beginning of the catch block 110 catchException(tryStart, tryEnd, Throwable.TYPE); 111 112 // ------------------------------------------------------------------------------- 113 // Throwable exception = e; 114 int exception = newLocal(Throwable.TYPE); 115 116 storeLocal(exception); 117 118 // ------------------------------------------------------------------------------- 119 // HANDLER.onMethodFinish(this, System.currentTimeNanos - start, 120 // exception); 121 getStatic(classType, handlerFieldName, MethodHandler.TYPE); 122 pushThis(); // param 1 123 invokeStatic(Clock.TYPE, Clock.currentTimeNanos); // param 2 : obtain 124 125 // end time 126 // (Clock.currentTimeNanos) 127 loadLocal(startTime); // param 2 : getPreferences the start time back onto the 128 129 // stack 130 math(GeneratorAdapter.SUB, Type.LONG_TYPE); // param 2 : subtract, 131 132 // leaving the result on the 133 // stack 134 loadLocal(exception); // param 3 : getPreferences the exception 135 invokeInterface(MethodHandler.TYPE, MethodHandler.onMethodFinish); 136 loadLocal(exception); 137 throwException(); 138 139 // ------------------------------------------------------------------------------- 140 endMethod(); 141 } 142 143 144 private void pushThis() { 145 146 if (isStatic) { 147 push("test"); 148 } else { 149 loadThis(); 150 } 151 } 152 }