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 }