package org.springframework.aop.framework.asm; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.springframework.aop.framework.AdvisedSupport; import org.springframework.aop.framework.AopContext; import java.lang.reflect.UndeclaredThrowableException; /** * @author robh */ public abstract class AbstractCodeGenerationStrategy implements CodeGenerationStrategy { protected static final String NO_ARG_CONSTRUCTOR_DESCRIPTOR = "()V"; protected static final String CONSTRUCTOR_INTERNAL_NAME = "<init>"; protected static final String TARGET_FIELD_NAME = "__target"; protected static final String ADVISED_FIELD_NAME = "__advised"; protected static final Object PROXY_COUNT_LOCK = new Object(); protected static final String GET_TARGET_SOURCE_METHOD = "getTargetSource"; protected static final String ADVISED_SUPPORT_INTERNAL_NAME = Type.getInternalName(AdvisedSupport.class); protected static final String ADVISED_SUPPORT_DESCRIPTOR = Type.getDescriptor(AdvisedSupport.class); protected static final String GET_TARGET_SOURCE_DESCRIPTOR = "()Lorg/springframework/aop/TargetSource;"; protected static final String TARGET_SOURCE_INTERNAL_NAME = "org/springframework/aop/TargetSource"; protected static final String GET_TARGET_METHOD = "getTarget"; protected static final String EXCEPTION_INTERNAL_NAME = "java/lang/Exception"; protected static final String AOP_CONFIG_EXCEPTION_INTERNAL_NAME = "org/springframework/aop/framework/AopConfigException"; protected static final String EXCEPTION_CONSTRUCTOR_DESCRIPTOR = "(Ljava/lang/String;Ljava/lang/Throwable;)V"; protected static final String GET_TARGET_DESCRIPTOR = "()Ljava/lang/Object;"; protected static final String GET_TARGET_CLASS_METHOD = "getTargetClass"; protected static final String GET_TARGET_CLASS_DESCRIPTOR = "()Ljava/lang/Class;"; protected static final String OBJECT_INTERNAL_NAME = Type.getInternalName(Object.class); protected static final String VALUE_OF_METHOD = "valueOf"; protected static final String CLASS_INTERNAL_NAME = "java/lang/Class"; protected static final String GET_METHOD_METHOD = "getMethod"; protected static final String GET_METHOD_DESCRIPTOR = "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"; protected static final String CLASS_DESCRIPTOR = Type.getDescriptor(Class.class); protected static final String TYPE_FIELD = "TYPE"; protected static final String GET_ADVISOR_CHAIN_FACTORY_DESCRIPTOR = "()Lorg/springframework/aop/framework/AdvisorChainFactory;"; protected static final String GET_ADVISOR_CHAIN_FACTORY_METHOD = "getAdvisorChainFactory"; protected static final String SET_CURRENT_PROXY_METHOD = "setCurrentProxy"; protected static final String AOP_CONTEXT_INTERNAL_NAME = Type.getInternalName(AopContext.class); protected static final String SET_CURRENT_PROXY_DESCRIPTOR = "(Ljava/lang/Object;)Ljava/lang/Object;"; protected static final String UNDECLARED_THROWABLE_EXCEPTION_INTERNAL_NAME = Type.getInternalName(UndeclaredThrowableException.class); protected static final String SINGLE_ARG_EXCEPTION_CONSTRUCTOR_DESCRIPTOR = "(Ljava/lang/Throwable;)V"; protected static final String RELEASE_TARGET_METHOD = "releaseTarget"; protected static final String RELEASE_TARGET_DESCRIPTOR = "(Ljava/lang/Object;)V"; protected int getLoadOpcodeForType(Class type) { if (type.isPrimitive()) { if (type == double.class) { return Opcodes.DLOAD; } else if (type == float.class) { return Opcodes.FLOAD; } else if (type == long.class) { return Opcodes.LLOAD; } else { return Opcodes.ILOAD; } } else { return Opcodes.ALOAD; } } protected int getStoreOpcodeForType(Class type) { if (type.isPrimitive()) { if (type == double.class) { return Opcodes.DSTORE; } else if (type == float.class) { return Opcodes.FSTORE; } else if (type == long.class) { return Opcodes.LSTORE; } else { return Opcodes.ISTORE; } } else { return Opcodes.ASTORE; } } protected int getReturnOpcodeForType(Class type) { if (type.isPrimitive()) { if (type == double.class) { return Opcodes.DRETURN; } else if (type == float.class) { return Opcodes.FRETURN; } else if (type == long.class) { return Opcodes.LRETURN; } else if (type == void.class) { return Opcodes.RETURN; } else { return Opcodes.IRETURN; } } else { return Opcodes.ARETURN; } } protected int calculateInitialLocalsOffset(Class[] args) { int localsSize = 0; for (int i = 0; i < args.length; i++) { localsSize += getLocalsSizeForType(args[i]); } return localsSize; } protected int getLocalsSizeForType(Class type) { if ((type == double.class) || (type == long.class)) { return 2; } else { return 1; } } protected void visitWrapPrimitive(MethodVisitor mv, Class parameterType) { if (byte.class == parameterType) { mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Byte.class), VALUE_OF_METHOD, "(B)Ljava/lang/Byte;"); } else if (short.class == parameterType) { mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Short.class), VALUE_OF_METHOD, "(S)Ljava/lang/Short;"); } else if (int.class == parameterType) { mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Integer.class), VALUE_OF_METHOD, "(I)Ljava/lang/Integer;"); } else if (long.class == parameterType) { mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Long.class), VALUE_OF_METHOD, "(J)Ljava/lang/Long;"); } else if (float.class == parameterType) { mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), VALUE_OF_METHOD, "(F)Ljava/lang/Float;"); } else if (double.class == parameterType) { mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Double.class), VALUE_OF_METHOD, "(D)Ljava/lang/Double;"); } else if (char.class == parameterType) { mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Character.class), VALUE_OF_METHOD, "(C)Ljava/lang/Character;"); } else if (boolean.class == parameterType) { mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Boolean.class), VALUE_OF_METHOD, "(Z)Ljava/lang/Boolean;"); } else { throw new IllegalArgumentException("Cannot wrap non-primitive value: " + parameterType.getName()); } } protected void visitGetPrimitiveType(MethodVisitor mv, Class parameterType) { if (byte.class == parameterType) { mv.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(Byte.class), TYPE_FIELD, CLASS_DESCRIPTOR); } else if (short.class == parameterType) { mv.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(Short.class), TYPE_FIELD, CLASS_DESCRIPTOR); } else if (int.class == parameterType) { mv.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(Integer.class), TYPE_FIELD, CLASS_DESCRIPTOR); } else if (long.class == parameterType) { mv.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(Long.class), TYPE_FIELD, CLASS_DESCRIPTOR); } else if (float.class == parameterType) { mv.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(Float.class), TYPE_FIELD, CLASS_DESCRIPTOR); } else if (double.class == parameterType) { mv.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(Double.class), TYPE_FIELD, CLASS_DESCRIPTOR); } else if (char.class == parameterType) { mv.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(Character.class), TYPE_FIELD, CLASS_DESCRIPTOR); } else if (boolean.class == parameterType) { mv.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class), TYPE_FIELD, CLASS_DESCRIPTOR); } else { throw new IllegalArgumentException("Cannot get type for non-primitive value: " + parameterType.getName()); } } protected void visitUnwrapPrimtiveType(MethodVisitor mv, Class parameterType) { if (byte.class == parameterType) { String wrapperInternalName = Type.getInternalName(Byte.class); mv.visitTypeInsn(Opcodes.CHECKCAST, wrapperInternalName); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, wrapperInternalName, "byteValue", "()B"); } else if (short.class == parameterType) { String wrapperInternalName = Type.getInternalName(Short.class); mv.visitTypeInsn(Opcodes.CHECKCAST, wrapperInternalName); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, wrapperInternalName, "shortValue", "()S"); } else if (int.class == parameterType) { String wrapperInternalName = Type.getInternalName(Integer.class); mv.visitTypeInsn(Opcodes.CHECKCAST, wrapperInternalName); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, wrapperInternalName, "intValue", "()I"); } else if (long.class == parameterType) { String wrapperInternalName = Type.getInternalName(Long.class); mv.visitTypeInsn(Opcodes.CHECKCAST, wrapperInternalName); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, wrapperInternalName, "longValue", "()J"); } else if (float.class == parameterType) { String wrapperInternalName = Type.getInternalName(Float.class); mv.visitTypeInsn(Opcodes.CHECKCAST, wrapperInternalName); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, wrapperInternalName, "floatValue", "()F"); } else if (double.class == parameterType) { String wrapperInternalName = Type.getInternalName(Double.class); mv.visitTypeInsn(Opcodes.CHECKCAST, wrapperInternalName); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, wrapperInternalName, "doubleValue", "()D"); } else if (char.class == parameterType) { String wrapperInternalName = Type.getInternalName(Character.class); mv.visitTypeInsn(Opcodes.CHECKCAST, wrapperInternalName); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, wrapperInternalName, "charValue", "()C"); } else if (boolean.class == parameterType) { String wrapperInternalName = Type.getInternalName(Boolean.class); mv.visitTypeInsn(Opcodes.CHECKCAST, wrapperInternalName); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, wrapperInternalName, "booleanValue", "()Z"); } else { throw new IllegalArgumentException("Cannot unwrap non-primitive value: " + parameterType.getName()); } } protected void visitIntegerInsn(int intValue, MethodVisitor mv) { switch (intValue) { case 0: mv.visitInsn(Opcodes.ICONST_0); break; case 1: mv.visitInsn(Opcodes.ICONST_1); break; case 2: mv.visitInsn(Opcodes.ICONST_2); break; case 3: mv.visitInsn(Opcodes.ICONST_3); break; case 4: mv.visitInsn(Opcodes.ICONST_4); break; case 5: mv.visitInsn(Opcodes.ICONST_5); break; default: mv.visitIntInsn(Opcodes.BIPUSH, intValue); } } protected String getMethodDescriptor(Class returnType, Class[] argumentTypes) { Type asmReturnType = Type.getType(returnType); Type[] asmArgumentTypes = new Type[argumentTypes.length]; for (int i = 0; i < asmArgumentTypes.length; i++) { asmArgumentTypes[i] = Type.getType(argumentTypes[i]); } return Type.getMethodDescriptor(asmReturnType, asmArgumentTypes); } protected String[] convertToInternalTypes(Class[] classes) { String[] types = new String[classes.length]; for (int i = 0; i < types.length; i++) { types[i] = Type.getInternalName(classes[i]); } return types; } }