/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ package instrumentj.impl; import instrumentj.Constants; import instrumentj.StaticProfilerInterface; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.AdviceAdapter; /** * @author Stephen Evanchik (evanchsa@gmail.com) * */ public class InstrumentMethodVisitor extends AdviceAdapter implements Constants { private final String className; private final String methodName; private final String methodDescription; /** * * @param className * @param mv * @param access * @param methodName * @param methodDescription */ public InstrumentMethodVisitor( final String className, final MethodVisitor mv, final int access, final String methodName, final String methodDescription) { super(Opcodes.ASM4, mv, access, methodName, methodDescription); if (className == null) { throw new NullPointerException("className"); } if (methodName == null) { throw new NullPointerException("methodName"); } this.className = className; this.methodName = methodName; this.methodDescription = methodDescription; } /** * Adds a call to * {@link StaticProfilerInterface#objectAllocationProbes(String)} in the * case of constructor calls and also a call to * {@link StaticProfilerInterface#methodEnterProbes(String, String)} * <br> * <br> * {@inheritDoc} */ @Override protected void onMethodEnter() { final boolean constructor = "<init>".equals(methodName); if (constructor) { visitLdcInsn(className); visitMethodInsn( INVOKESTATIC, INSTRUMENTJ_STATIC_PROFILER_INTERFACE, OBJECT_ALLOCATION_PROBES, OBJECT_ALLOCATION_PROBES_DESC); } visitLdcInsn(className); visitLdcInsn(methodName); visitLdcInsn(methodDescription); final Type[] argTypes = Type.getArgumentTypes(methodDescription); final int argCount = argTypes.length; if (argCount > 0) { loadArgArray(); } else { visitIntInsn(Opcodes.BIPUSH, 1); visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); } visitMethodInsn( INVOKESTATIC, INSTRUMENTJ_STATIC_PROFILER_INTERFACE, METHOD_ENTER_PROBES, METHOD_ENTER_PROBES_DESC); } /** * Adds a call to * {@link StaticProfilerInterface#methodExitProbes(String, String, int)} <br> * <br> * {@inheritDoc} */ @Override protected void onMethodExit(final int opcode) { // TODO: If we're exiting the constructor because of an exception then should that be counted differently? visitLdcInsn(className); visitLdcInsn(methodName); visitLdcInsn(methodDescription); visitLdcInsn(opcode); visitMethodInsn( INVOKESTATIC, INSTRUMENTJ_STATIC_PROFILER_INTERFACE, METHOD_EXIT_PROBES, METHOD_EXIT_PROBES_DESC); } @Override public String toString() { return super.toString() + " for " + className + "." + methodName + "(" + methodDescription + ")"; } }