use of jodd.asm5.MethodVisitor in project tomee by apache.
the class LocalBeanProxyFactory method visit.
public static MethodVisitor visit(final ClassWriter cw, final Method method, final String proxyName, final String handlerName) throws ProxyGenerationException {
final Class<?> returnType = method.getReturnType();
final Class<?>[] parameterTypes = method.getParameterTypes();
final Class<?>[] exceptionTypes = method.getExceptionTypes();
final int modifiers = method.getModifiers();
// push the method definition
int modifier = 0;
if (Modifier.isPublic(modifiers)) {
modifier = ACC_PUBLIC;
} else if (Modifier.isProtected(modifiers)) {
modifier = ACC_PROTECTED;
}
final MethodVisitor mv = cw.visitMethod(modifier, method.getName(), getMethodSignatureAsString(returnType, parameterTypes), null, null);
mv.visitCode();
// push try/catch block, to catch declared exceptions, and to catch java.lang.Throwable
final Label l0 = new Label();
final Label l1 = new Label();
final Label l2 = new Label();
if (exceptionTypes.length > 0) {
mv.visitTryCatchBlock(l0, l1, l2, "java/lang/reflect/InvocationTargetException");
}
// push try code
mv.visitLabel(l0);
final String classNameToOverride = method.getDeclaringClass().getName().replace('.', '/');
mv.visitLdcInsn(Type.getType("L" + classNameToOverride + ";"));
// the following code generates the bytecode for this line of Java:
// Method method = <proxy>.class.getMethod("add", new Class[] { <array of function argument classes> });
// get the method name to invoke, and push to stack
mv.visitLdcInsn(method.getName());
// create the Class[]
createArrayDefinition(mv, parameterTypes.length, Class.class);
int length = 1;
// push parameters into array
for (int i = 0; i < parameterTypes.length; i++) {
// keep copy of array on stack
mv.visitInsn(DUP);
final Class<?> parameterType = parameterTypes[i];
// push number onto stack
pushIntOntoStack(mv, i);
if (parameterType.isPrimitive()) {
final String wrapperType = getWrapperType(parameterType);
mv.visitFieldInsn(GETSTATIC, wrapperType, "TYPE", "Ljava/lang/Class;");
} else {
mv.visitLdcInsn(Type.getType(getAsmTypeAsString(parameterType, true)));
}
mv.visitInsn(AASTORE);
if (Long.TYPE.equals(parameterType) || Double.TYPE.equals(parameterType)) {
length += 2;
} else {
length++;
}
}
// invoke getMethod() with the method name and the array of types
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
// store the returned method for later
mv.visitVarInsn(ASTORE, length);
// the following code generates bytecode equivalent to:
// return ((<returntype>) invocationHandler.invoke(this, method, new Object[] { <function arguments }))[.<primitive>Value()];
final Label l4 = new Label();
mv.visitLabel(l4);
mv.visitVarInsn(ALOAD, 0);
// get the invocationHandler field from this class
mv.visitFieldInsn(GETFIELD, proxyName, handlerName, "Ljava/lang/reflect/InvocationHandler;");
// we want to pass "this" in as the first parameter
mv.visitVarInsn(ALOAD, 0);
// and the method we fetched earlier
mv.visitVarInsn(ALOAD, length);
// need to construct the array of objects passed in
// create the Object[]
createArrayDefinition(mv, parameterTypes.length, Object.class);
int index = 1;
// push parameters into array
for (int i = 0; i < parameterTypes.length; i++) {
// keep copy of array on stack
mv.visitInsn(DUP);
final Class<?> parameterType = parameterTypes[i];
// push number onto stack
pushIntOntoStack(mv, i);
if (parameterType.isPrimitive()) {
final String wrapperType = getWrapperType(parameterType);
mv.visitVarInsn(getVarInsn(parameterType), index);
mv.visitMethodInsn(INVOKESTATIC, wrapperType, "valueOf", "(" + getPrimitiveLetter(parameterType) + ")L" + wrapperType + ";", false);
mv.visitInsn(AASTORE);
if (Long.TYPE.equals(parameterType) || Double.TYPE.equals(parameterType)) {
index += 2;
} else {
index++;
}
} else {
mv.visitVarInsn(ALOAD, index);
mv.visitInsn(AASTORE);
index++;
}
}
// invoke the invocationHandler
mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/reflect/InvocationHandler", "invoke", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;", true);
// cast the result
mv.visitTypeInsn(CHECKCAST, getCastType(returnType));
if (returnType.isPrimitive() && !Void.TYPE.equals(returnType)) {
// get the primitive value
mv.visitMethodInsn(INVOKEVIRTUAL, getWrapperType(returnType), getPrimitiveMethod(returnType), "()" + getPrimitiveLetter(returnType), false);
}
// push return
mv.visitLabel(l1);
if (!Void.TYPE.equals(returnType)) {
mv.visitInsn(getReturnInsn(returnType));
} else {
mv.visitInsn(POP);
mv.visitInsn(RETURN);
}
// catch InvocationTargetException
if (exceptionTypes.length > 0) {
mv.visitLabel(l2);
mv.visitVarInsn(ASTORE, length);
final Label l5 = new Label();
mv.visitLabel(l5);
for (int i = 0; i < exceptionTypes.length; i++) {
final Class<?> exceptionType = exceptionTypes[i];
mv.visitLdcInsn(Type.getType("L" + exceptionType.getName().replace('.', '/') + ";"));
mv.visitVarInsn(ALOAD, length);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false);
final Label l6 = new Label();
mv.visitJumpInsn(IFEQ, l6);
final Label l7 = new Label();
mv.visitLabel(l7);
mv.visitVarInsn(ALOAD, length);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;", false);
mv.visitTypeInsn(CHECKCAST, exceptionType.getName().replace('.', '/'));
mv.visitInsn(ATHROW);
mv.visitLabel(l6);
if (i == exceptionTypes.length - 1) {
mv.visitTypeInsn(NEW, "java/lang/reflect/UndeclaredThrowableException");
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, length);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/reflect/UndeclaredThrowableException", "<init>", "(Ljava/lang/Throwable;)V", false);
mv.visitInsn(ATHROW);
}
}
}
// finish this method
mv.visitMaxs(0, 0);
return mv;
}
use of jodd.asm5.MethodVisitor in project jodd by oblac.
the class ProxettaClassBuilder method makeStaticInitBlock.
/**
* Creates static initialization block that simply calls all
* advice static init methods in correct order.
*/
protected void makeStaticInitBlock() {
if (wd.adviceClinits != null) {
MethodVisitor mv = wd.dest.visitMethod(AsmUtil.ACC_STATIC, CLINIT, DESC_VOID, null, null);
mv.visitCode();
for (String name : wd.adviceClinits) {
mv.visitMethodInsn(INVOKESTATIC, wd.thisReference, name, DESC_VOID, false);
}
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
}
use of jodd.asm5.MethodVisitor in project jodd by oblac.
the class ProxettaWrapperClassBuilder method createEmptyCtor.
/**
* Created empty default constructor.
*/
protected void createEmptyCtor() {
MethodVisitor mv = wd.dest.visitMethod(AsmUtil.ACC_PUBLIC, INIT, "()V", null, null);
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, AsmUtil.SIGNATURE_JAVA_LANG_OBJECT, INIT, "()V", false);
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
use of jodd.asm5.MethodVisitor in project jodd by oblac.
the class ProxettaWrapperClassBuilder method createSimpleMethodWrapper.
/**
* Creates simple method wrapper without proxy.
*/
protected void createSimpleMethodWrapper(MethodSignatureVisitor msign) {
int access = msign.getAccessFlags();
access &= ~ACC_ABSTRACT;
access &= ~ACC_NATIVE;
MethodVisitor mv = wd.dest.visitMethod(access, msign.getMethodName(), msign.getDescription(), msign.getRawSignature(), msign.getExceptionsArray());
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, wd.thisReference, wd.wrapperRef, wd.wrapperType);
loadVirtualMethodArguments(mv, msign);
if (wd.wrapInterface) {
mv.visitMethodInsn(INVOKEINTERFACE, wd.wrapperType.substring(1, wd.wrapperType.length() - 1), msign.getMethodName(), msign.getDescription(), true);
} else {
mv.visitMethodInsn(INVOKEVIRTUAL, wd.wrapperType.substring(1, wd.wrapperType.length() - 1), msign.getMethodName(), msign.getDescription(), false);
}
ProxettaAsmUtil.prepareReturnValue(mv, msign, 0);
visitReturn(mv, msign, true);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
use of jodd.asm5.MethodVisitor in project jodd by oblac.
the class ProxyAspectData method readAdviceData.
// ---------------------------------------------------------------- read
/**
* Parse advice class to gather some advice data. Should be called before any advice use.
* Must be called only *once* per advice.
*/
private void readAdviceData() {
if (ready) {
return;
}
adviceClassReader.accept(new EmptyClassVisitor() {
/**
* Stores advice reference.
*/
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
adviceReference = name;
super.visit(version, access, name, signature, superName, interfaces);
}
/**
* Prevents advice to have inner classes.
*/
@Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
if (outerName.equals(adviceReference)) {
throw new ProxettaException("Proxetta doesn't allow inner classes in/for advice: " + advice.getName());
}
super.visitInnerClass(name, outerName, innerName, access);
}
/**
* Clones advices fields to destination.
*/
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
// [A5]
wd.dest.visitField(access, adviceFieldName(name, aspectIndex), desc, signature, value);
return super.visitField(access, name, desc, signature, value);
}
/**
* Copies advices methods to destination.
*/
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (name.equals(CLINIT)) {
// [A6]
if (!desc.equals(DESC_VOID)) {
throw new ProxettaException("Invalid static initialization block description for advice: " + advice.getName());
}
name = clinitMethodName + methodDivider + aspectIndex;
access |= AsmUtil.ACC_PRIVATE | AsmUtil.ACC_FINAL;
wd.addAdviceClinitMethod(name);
return new MethodAdapter(wd.dest.visitMethod(access, name, desc, signature, exceptions)) {
@Override
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
}
@Override
public void visitLineNumber(int line, Label start) {
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isInterface) {
if (opcode == INVOKESTATIC) {
if (owner.equals(adviceReference)) {
owner = wd.thisReference;
name = adviceMethodName(name, aspectIndex);
}
}
super.visitMethodInsn(opcode, owner, name, desc, isInterface);
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
// [F6]
if (owner.equals(adviceReference)) {
// [F5]
owner = wd.thisReference;
name = adviceFieldName(name, aspectIndex);
}
super.visitFieldInsn(opcode, owner, name, desc);
}
};
} else if (name.equals(INIT)) {
// [A7]
if (!desc.equals(DESC_VOID)) {
throw new ProxettaException("Advices can have only default constructors. Invalid advice: " + advice.getName());
}
name = initMethodName + methodDivider + aspectIndex;
access = ProxettaAsmUtil.makePrivateFinalAccess(access);
wd.addAdviceInitMethod(name);
return new MethodAdapter(wd.dest.visitMethod(access, name, desc, signature, exceptions)) {
@Override
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
}
@Override
public void visitLineNumber(int line, Label start) {
}
// used to detect and to ignore the first super call()
int state;
@Override
public void visitVarInsn(int opcode, int var) {
// [F7]
if ((state == 0) && (opcode == ALOAD) && (var == 0)) {
state++;
return;
}
super.visitVarInsn(opcode, var);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isInterface) {
if ((state == 1) && (opcode == INVOKESPECIAL)) {
state++;
return;
}
if ((opcode == INVOKEVIRTUAL) || (opcode == INVOKEINTERFACE)) {
if (owner.equals(adviceReference)) {
owner = wd.thisReference;
name = adviceMethodName(name, aspectIndex);
}
} else if (opcode == INVOKESTATIC) {
if (owner.equals(adviceReference)) {
owner = wd.thisReference;
name = adviceMethodName(name, aspectIndex);
}
}
super.visitMethodInsn(opcode, owner, name, desc, isInterface);
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
// [F7]
if (owner.equals(adviceReference)) {
// [F5]
owner = wd.thisReference;
name = adviceFieldName(name, aspectIndex);
}
super.visitFieldInsn(opcode, owner, name, desc);
}
};
} else // other methods
if (!name.equals(executeMethodName)) {
name = adviceMethodName(name, aspectIndex);
return new MethodAdapter(wd.dest.visitMethod(access, name, desc, signature, exceptions)) {
@Override
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
}
@Override
public void visitLineNumber(int line, Label start) {
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isInterface) {
if ((opcode == INVOKEVIRTUAL) || (opcode == INVOKEINTERFACE)) {
if (owner.equals(adviceReference)) {
owner = wd.thisReference;
name = adviceMethodName(name, aspectIndex);
}
} else if (opcode == INVOKESTATIC || opcode == INVOKESPECIAL) {
if (owner.equals(adviceReference)) {
owner = wd.thisReference;
name = adviceMethodName(name, aspectIndex);
}
}
super.visitMethodInsn(opcode, owner, name, desc, isInterface);
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
// replace field references
if (owner.equals(adviceReference)) {
owner = wd.thisReference;
name = adviceFieldName(name, aspectIndex);
}
super.visitFieldInsn(opcode, owner, name, desc);
}
};
}
//return new MethodAdapter(new EmptyMethodVisitor()) { // toask may we replace this with the following code?
return new EmptyMethodVisitor() {
@Override
public void visitVarInsn(int opcode, int var) {
if (isStoreOpcode(opcode)) {
if (var > maxLocalVarOffset) {
// find max local var offset
maxLocalVarOffset = var;
}
}
super.visitVarInsn(opcode, var);
}
};
// return super.visitMethod(access, name, desc, signature, exceptions);
}
}, 0);
// increment offset by 2 because var on last index may be a dword value
maxLocalVarOffset += 2;
ready = true;
}
Aggregations