package com.jsonde.instrumentation;
import com.jsonde.profiler.Profiler;
import com.jsonde.util.ClassUtils;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.AdviceAdapter;
public class JSondeMethodTransformerOld extends AdviceAdapter {
private final long methodId;
private final Label startFinallyLabel = new Label();
private final boolean isConstructor;
private final boolean isStaticConstructor;
private final String className;
private final String parentClassName;
private static final String PROFILER_CLASS_INTERNAL_NAME =
ClassUtils.getInternalClassName(Profiler.CLASS_CANONICAL_NAME);
public JSondeMethodTransformerOld(long methodId, MethodVisitor mv, int access, String name, String desc, String className, String parentClassName) {
super(Opcodes.ASM4, mv, access, name, desc);
this.methodId = methodId;
this.isConstructor = name.equals(ClassUtils.CONSTRUCTOR_METHOD_NAME);
this.isStaticConstructor = name.equals(ClassUtils.STATIC_CONSTRUCTOR_METHOD_NAME);
this.className = className;
this.parentClassName = parentClassName;
}
@Override
public void visitCode() {
super.visitCode();
mv.visitLabel(startFinallyLabel);
}
@Override
public void visitMaxs(int maxStack, int maxLocals) {
Label endFinallyLabel = new Label();
mv.visitTryCatchBlock(startFinallyLabel, endFinallyLabel, endFinallyLabel, null);
mv.visitLabel(endFinallyLabel);
onFinally(ATHROW);
mv.visitInsn(ATHROW);
mv.visitMaxs(maxStack, maxLocals);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
if (isConstructor && name.equals(ClassUtils.CONSTRUCTOR_METHOD_NAME) && (owner.equals(parentClassName) || ClassUtils.getFullyQualifiedName(owner).equals(className))) {
super.visitLdcInsn(methodId);
super.visitMethodInsn(
INVOKESTATIC,
PROFILER_CLASS_INTERNAL_NAME,
Profiler.PRE_ENTER_CONSTRUCTOR_METHOD_NAME,
Profiler.PRE_ENTER_CONSTRUCTOR_METHOD_DESCRIPTOR
);
}
super.visitMethodInsn(opcode, owner, name, desc);
}
private void onFinally(int opcode) {
if (opcode == ATHROW) {
super.visitInsn(DUP);
super.visitMethodInsn(
INVOKESTATIC,
PROFILER_CLASS_INTERNAL_NAME,
Profiler.LEAVE_METHOD_THROW_EXCEPTION_METHOD_NAME,
Profiler.LEAVE_METHOD_THROW_EXCEPTION_METHOD_DESCRIPTOR
);
} else if (opcode == RETURN) {
super.visitMethodInsn(
INVOKESTATIC,
PROFILER_CLASS_INTERNAL_NAME,
Profiler.LEAVE_METHOD_METHOD_NAME,
Profiler.LEAVE_METHOD_METHOD_DESCRIPTOR
);
} else {
if (opcode == LRETURN || opcode == DRETURN) {
super.visitInsn(DUP2);
} else {
super.visitInsn(DUP);
}
box(Type.getReturnType(methodDesc));
super.visitMethodInsn(
INVOKESTATIC,
PROFILER_CLASS_INTERNAL_NAME,
Profiler.LEAVE_METHOD_RETURN_VALUE_METHOD_NAME,
Profiler.LEAVE_METHOD_RETURN_VALUE_METHOD_DESCRIPTOR
);
}
}
@Override
protected void onMethodExit(int opcode) {
if (opcode != ATHROW) {
onFinally(opcode);
}
}
@Override
protected void onMethodEnter() {
try {
if ((ACC_STATIC & methodAccess) == 0) {
int argIndex = generateArgumentsArray(1);
super.visitLdcInsn(methodId);
super.visitVarInsn(ALOAD, 0);
super.visitVarInsn(ALOAD, argIndex);
if (isConstructor) {
super.visitMethodInsn(
INVOKESTATIC,
PROFILER_CLASS_INTERNAL_NAME,
Profiler.ENTER_CONSTRUCTOR_METHOD_NAME,
Profiler.ENTER_CONSTRUCTOR_METHOD_DESCRIPTOR
);
} else {
super.visitMethodInsn(
INVOKESTATIC,
PROFILER_CLASS_INTERNAL_NAME,
Profiler.ENTER_METHOD_METHOD_NAME,
Profiler.ENTER_METHOD_METHOD_DESCRIPTOR
);
}
} else {
if (isStaticConstructor) {
super.visitLdcInsn(methodId);
super.visitMethodInsn(
INVOKESTATIC,
PROFILER_CLASS_INTERNAL_NAME,
Profiler.DESCRIBE_CLASS_METHOD_NAME,
Profiler.DESCRIBE_CLASS_METHOD_DESCRIPTOR
);
}
int argIndex = generateArgumentsArray(0);
super.visitLdcInsn(methodId);
super.visitInsn(ACONST_NULL);
super.visitVarInsn(ALOAD, argIndex);
super.visitMethodInsn(
INVOKESTATIC,
PROFILER_CLASS_INTERNAL_NAME,
Profiler.ENTER_METHOD_METHOD_NAME,
Profiler.ENTER_METHOD_METHOD_DESCRIPTOR
);
}
} catch (Throwable e) {
e.printStackTrace();
}
}
private int generateArgumentsArray(int argIndex) {
Type[] argumentTypes = Type.getArgumentTypes(methodDesc);
super.visitIntInsn(BIPUSH, argumentTypes.length);
super.visitTypeInsn(ANEWARRAY, "java/lang/Object");
for (int i = 0; i < argumentTypes.length; i++) {
Type argumentType = argumentTypes[i];
super.visitInsn(DUP);
super.visitIntInsn(BIPUSH, i);
super.visitVarInsn(argumentType.getOpcode(ILOAD), argIndex);
// boxing start
switch (argumentType.getSort()) {
case Type.BYTE:
super.visitMethodInsn(
INVOKESTATIC,
"java/lang/Byte",
"valueOf",
"(B)Ljava/lang/Byte;"
);
break;
case Type.BOOLEAN:
super.visitMethodInsn(
INVOKESTATIC,
"java/lang/Boolean",
"valueOf",
"(Z)Ljava/lang/Boolean;"
);
break;
case Type.SHORT:
super.visitMethodInsn(
INVOKESTATIC,
"java/lang/Short",
"valueOf",
"(S)Ljava/lang/Short;"
);
break;
case Type.CHAR:
super.visitMethodInsn(
INVOKESTATIC,
"java/lang/Character",
"valueOf",
"(C)Ljava/lang/Character;"
);
break;
case Type.INT:
super.visitMethodInsn(
INVOKESTATIC,
"java/lang/Integer",
"valueOf",
"(I)Ljava/lang/Integer;"
);
break;
case Type.FLOAT:
super.visitMethodInsn(
INVOKESTATIC,
"java/lang/Float",
"valueOf",
"(F)Ljava/lang/Float;"
);
break;
case Type.LONG:
super.visitMethodInsn(
INVOKESTATIC,
"java/lang/Long",
"valueOf",
"(J)Ljava/lang/Long;"
);
break;
case Type.DOUBLE:
super.visitMethodInsn(
INVOKESTATIC,
"java/lang/Double",
"valueOf",
"(D)Ljava/lang/Double;"
);
break;
}
// boxing end
super.visitInsn(AASTORE);
argIndex += argumentType.getSize();
}
super.visitVarInsn(ASTORE, argIndex);
return argIndex;
}
}