package org.nutz.lang.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import org.nutz.repo.org.objectweb.asm.Label;
import org.nutz.repo.org.objectweb.asm.MethodVisitor;
import org.nutz.repo.org.objectweb.asm.Opcodes;
import org.nutz.repo.org.objectweb.asm.Type;
public class FastClassAdpter implements Opcodes {
protected final MethodVisitor mv;
protected String enhancedSuperName;
protected Type returnType;
protected String[] descs;
protected String[] methodNames;
protected int[] modifies;
protected int[] invokeOps;
private FastClassAdpter(MethodVisitor mv, String enhancedSuperName) {
this.mv = mv;
this.enhancedSuperName = enhancedSuperName;
}
public void createInokeMethod() {
mv.visitCode();
for (int i = 0; i < methodNames.length; i++) {
mv.visitVarInsn(ILOAD, 2);
visitX(i);
Label l0 = new Label();
mv.visitJumpInsn(IF_ICMPNE, l0);
if (!Modifier.isStatic(modifies[i])) {
mv.visitVarInsn(ALOAD, 1);
returnType = Type.getObjectType(enhancedSuperName);
checkCast();
}
Type args[] = Type.getArgumentTypes(descs[i]);
for (int j = 0; j < args.length; j++) {
mv.visitVarInsn(ALOAD, 3);
visitX(j);
mv.visitInsn(AALOAD);
returnType = args[j];
checkCast();
}
mv.visitMethodInsn( invokeOps[i],
enhancedSuperName,
methodNames[i],
Type.getMethodDescriptor( Type.getReturnType(descs[i]),
Type.getArgumentTypes(descs[i])));
returnType = Type.getReturnType(descs[i]);
if (returnType.equals(Type.VOID_TYPE))
mv.visitInsn(ACONST_NULL);
else if (returnType.getOpcode(IRETURN) != ARETURN)
packagePrivateData(returnType);
mv.visitInsn(ARETURN);
mv.visitLabel(l0);
}
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ARETURN);
mv.visitMaxs(4, 3);
mv.visitEnd();
}
public void createInokeConstructor(Constructor<?>[] constructors) {
mv.visitCode();
for (int i = 0; i < constructors.length; i++) {
mv.visitVarInsn(ILOAD, 1);
visitX(i);
Label l0 = new Label();
mv.visitJumpInsn(IF_ICMPNE, l0);
mv.visitTypeInsn(NEW, enhancedSuperName);
mv.visitInsn(DUP);
Type args[] = Type.getArgumentTypes(Type.getConstructorDescriptor(constructors[i]));
for (int j = 0; j < args.length; j++) {
mv.visitVarInsn(ALOAD, 2);
visitX(j);
mv.visitInsn(AALOAD);
returnType = args[j];
checkCast();
}
mv.visitMethodInsn( INVOKESPECIAL,
enhancedSuperName,
"<init>",
Type.getConstructorDescriptor(constructors[i]));
mv.visitInsn(ARETURN);
mv.visitLabel(l0);
}
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ARETURN);
mv.visitMaxs(4, 3);
mv.visitEnd();
}
protected void loadInsn(final Type type, final int index) {
mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index);
}
protected void visitX(int i) {
if (i < 6) {
mv.visitInsn(i + ICONST_0);
} else {
mv.visitIntInsn(BIPUSH, i);
}
}
protected boolean packagePrivateData(Type type) {
if (type.equals(Type.BOOLEAN_TYPE)) {
mv.visitMethodInsn( INVOKESTATIC,
"java/lang/Boolean",
"valueOf",
"(Z)Ljava/lang/Boolean;");
} else if (type.equals(Type.BYTE_TYPE)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
} else if (type.equals(Type.CHAR_TYPE)) {
mv.visitMethodInsn( INVOKESTATIC,
"java/lang/Character",
"valueOf",
"(C)Ljava/lang/Character;");
} else if (type.equals(Type.SHORT_TYPE)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
} else if (type.equals(Type.INT_TYPE)) {
mv.visitMethodInsn( INVOKESTATIC,
"java/lang/Integer",
"valueOf",
"(I)Ljava/lang/Integer;");
} else if (type.equals(Type.LONG_TYPE)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
} else if (type.equals(Type.FLOAT_TYPE)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
} else if (type.equals(Type.DOUBLE_TYPE)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
} else {
return false;
}
return true;
}
protected void unpackagePrivateData(Type type) {
if (type.equals(Type.BOOLEAN_TYPE)) {
mv.visitMethodInsn( INVOKESTATIC,
"org/nutz/aop/asm/Helper",
"valueOf",
"(Ljava/lang/Boolean;)Z");
} else if (type.equals(Type.BYTE_TYPE)) {
mv.visitMethodInsn( INVOKESTATIC,
"org/nutz/aop/asm/Helper",
"valueOf",
"(Ljava/lang/Byte;)B");
} else if (type.equals(Type.CHAR_TYPE)) {
mv.visitMethodInsn( INVOKESTATIC,
"org/nutz/aop/asm/Helper",
"valueOf",
"(Ljava/lang/Character;)C");
} else if (type.equals(Type.SHORT_TYPE)) {
mv.visitMethodInsn( INVOKESTATIC,
"org/nutz/aop/asm/Helper",
"valueOf",
"(Ljava/lang/Short;)S");
} else if (type.equals(Type.INT_TYPE)) {
mv.visitMethodInsn( INVOKESTATIC,
"org/nutz/aop/asm/Helper",
"valueOf",
"(Ljava/lang/Integer;)I");
} else if (type.equals(Type.LONG_TYPE)) {
mv.visitMethodInsn( INVOKESTATIC,
"org/nutz/aop/asm/Helper",
"valueOf",
"(Ljava/lang/Long;)J");
} else if (type.equals(Type.FLOAT_TYPE)) {
mv.visitMethodInsn( INVOKESTATIC,
"org/nutz/aop/asm/Helper",
"valueOf",
"(Ljava/lang/Float;)F");
} else if (type.equals(Type.DOUBLE_TYPE)) {
mv.visitMethodInsn( INVOKESTATIC,
"org/nutz/aop/asm/Helper",
"valueOf",
"(Ljava/lang/Double;)D");
}
}
protected boolean isObject = true;
protected void checkCast() {
if (returnType.getSort() == Type.ARRAY) {
mv.visitTypeInsn(CHECKCAST, returnType.getDescriptor());
return;
}
if (returnType.equals(Type.getType(Object.class))) {
;
} else {
if (returnType.getOpcode(IRETURN) != ARETURN) {
checkCast2();
unpackagePrivateData(returnType);
isObject = false;
} else {
mv.visitTypeInsn(CHECKCAST, returnType.getClassName().replace('.', '/'));
}
}
}
protected void checkCast2() {
if (returnType.equals(Type.BOOLEAN_TYPE)) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
} else if (returnType.equals(Type.BYTE_TYPE)) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
} else if (returnType.equals(Type.CHAR_TYPE)) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
} else if (returnType.equals(Type.SHORT_TYPE)) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
} else if (returnType.equals(Type.INT_TYPE)) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
} else if (returnType.equals(Type.LONG_TYPE)) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
} else if (returnType.equals(Type.FLOAT_TYPE)) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
} else if (returnType.equals(Type.DOUBLE_TYPE)) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
}
}
public final static void createInokeMethod( MethodVisitor mv,
String[] methodNames,
String[] descs,
int[] modifies,
int[] invokeOps,
String enhancedSuperName) {
FastClassAdpter adpter = new FastClassAdpter(mv, enhancedSuperName);
adpter.descs = descs;
adpter.methodNames = methodNames;
adpter.modifies = modifies;
adpter.invokeOps = invokeOps;
adpter.createInokeMethod();
}
public final static void createInokeConstructor(MethodVisitor mv,
String enhancedSuperName,
Constructor<?>[] constructors) {
FastClassAdpter adpter = new FastClassAdpter(mv, enhancedSuperName);
adpter.createInokeConstructor(constructors);
}
}