mirror of
https://github.com/EsotericSoftware/reflectasm.git
synced 2025-03-26 11:12:23 +08:00
Updated synchronization to avoid defining the same class twice.
Fixed issue 8, constructor access for inner classes.
This commit is contained in:
parent
9ede9fd513
commit
ef70ad89dc
@ -9,63 +9,124 @@ import org.objectweb.asm.MethodVisitor;
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public abstract class ConstructorAccess<T> {
|
||||
static public <T> ConstructorAccess<T> get (Class<T> type) {
|
||||
try {
|
||||
type.getConstructor((Class[])null);
|
||||
} catch (Exception ex) {
|
||||
if (type.isMemberClass() && !Modifier.isStatic(type.getModifiers()))
|
||||
throw new RuntimeException("Class cannot be created (non-static member class): " + type.getName());
|
||||
else
|
||||
throw new RuntimeException("Class cannot be created (missing no-arg constructor): " + type.getName());
|
||||
}
|
||||
|
||||
AccessClassLoader loader = AccessClassLoader.get(type);
|
||||
boolean isNonStaticMemberClass;
|
||||
|
||||
public boolean isNonStaticMemberClass () {
|
||||
return isNonStaticMemberClass;
|
||||
}
|
||||
|
||||
/** Constructor for top-level classes and static nested classes.
|
||||
* <p>
|
||||
* If the underlying class is a inner (non-static nested) class, a new instance will be created using <code>null</code> as the
|
||||
* this$0 synthetic reference. The instantiated object will work as long as it actually don't use any member variable or method
|
||||
* fron the enclosing instance. */
|
||||
abstract public T newInstance ();
|
||||
|
||||
/** Constructor for inner classes (non-static nested classes).
|
||||
* @param enclosingInstance The instance of the enclosing type to which this inner instance is related to (assigned to its
|
||||
* synthetic this$0 field). */
|
||||
abstract public T newInstance (Object enclosingInstance);
|
||||
|
||||
static public <T> ConstructorAccess<T> get (Class<T> type) {
|
||||
Class enclosingType = type.getEnclosingClass();
|
||||
boolean isNonStaticMemberClass = enclosingType != null && type.isMemberClass() && !Modifier.isStatic(type.getModifiers());
|
||||
|
||||
String className = type.getName();
|
||||
String accessClassName = className + "ConstructorAccess";
|
||||
if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName;
|
||||
Class accessClass = null;
|
||||
try {
|
||||
accessClass = loader.loadClass(accessClassName);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
if (accessClass == null) {
|
||||
String accessClassNameInternal = accessClassName.replace('.', '/');
|
||||
String classNameInternal = className.replace('.', '/');
|
||||
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null,
|
||||
"com/esotericsoftware/reflectasm/ConstructorAccess", null);
|
||||
MethodVisitor mv;
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "com/esotericsoftware/reflectasm/ConstructorAccess", "<init>", "()V");
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
AccessClassLoader loader = AccessClassLoader.get(type);
|
||||
synchronized (loader) {
|
||||
try {
|
||||
accessClass = loader.loadClass(accessClassName);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
String accessClassNameInternal = accessClassName.replace('.', '/');
|
||||
String classNameInternal = className.replace('.', '/');
|
||||
String enclosingClassNameInternal;
|
||||
|
||||
if (!isNonStaticMemberClass) {
|
||||
enclosingClassNameInternal = null;
|
||||
try {
|
||||
type.getConstructor((Class[])null);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Class cannot be created (missing no-arg constructor): " + type.getName());
|
||||
}
|
||||
} else {
|
||||
enclosingClassNameInternal = enclosingType.getName().replace('.', '/');
|
||||
try {
|
||||
type.getConstructor(enclosingType); // Inner classes should have this.
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Non-static member class cannot be created (missing enclosing class constructor): "
|
||||
+ type.getName());
|
||||
}
|
||||
}
|
||||
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null,
|
||||
"com/esotericsoftware/reflectasm/ConstructorAccess", null);
|
||||
|
||||
insertConstructor(cw);
|
||||
insertNewInstance(cw, classNameInternal);
|
||||
insertNewInstanceInner(cw, classNameInternal, enclosingClassNameInternal);
|
||||
|
||||
cw.visitEnd();
|
||||
accessClass = loader.defineClass(accessClassName, cw.toByteArray());
|
||||
}
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC, "newInstance", "()Ljava/lang/Object;", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitTypeInsn(NEW, classNameInternal);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, classNameInternal, "<init>", "()V");
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(2, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
byte[] data = cw.toByteArray();
|
||||
accessClass = loader.defineClass(accessClassName, data);
|
||||
}
|
||||
try {
|
||||
return (ConstructorAccess)accessClass.newInstance();
|
||||
ConstructorAccess<T> access = (ConstructorAccess<T>)accessClass.newInstance();
|
||||
access.isNonStaticMemberClass = isNonStaticMemberClass;
|
||||
return access;
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Error constructing constructor access class: " + accessClassName, ex);
|
||||
}
|
||||
}
|
||||
|
||||
abstract public T newInstance ();
|
||||
static private void insertConstructor (ClassWriter cw) {
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "com/esotericsoftware/reflectasm/ConstructorAccess", "<init>", "()V");
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
static void insertNewInstance (ClassWriter cw, String classNameInternal) {
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "newInstance", "()Ljava/lang/Object;", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitTypeInsn(NEW, classNameInternal);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, classNameInternal, "<init>", "()V");
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(2, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
static void insertNewInstanceInner (ClassWriter cw, String classNameInternal, String enclosingClassNameInternal) {
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "newInstance", "(Ljava/lang/Object;)Ljava/lang/Object;", null, null);
|
||||
mv.visitCode();
|
||||
if (enclosingClassNameInternal != null) {
|
||||
mv.visitTypeInsn(NEW, classNameInternal);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitTypeInsn(CHECKCAST, enclosingClassNameInternal);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;");
|
||||
mv.visitInsn(POP);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, classNameInternal, "<init>", "(L" + enclosingClassNameInternal + ";)V");
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(4, 2);
|
||||
} else {
|
||||
mv.visitTypeInsn(NEW, "java/lang/UnsupportedOperationException");
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitLdcInsn("Not an inner class.");
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/UnsupportedOperationException", "<init>", "(Ljava/lang/String;)V");
|
||||
mv.visitInsn(ATHROW);
|
||||
mv.visitMaxs(3, 2);
|
||||
}
|
||||
mv.visitEnd();
|
||||
}
|
||||
}
|
||||
|
@ -72,8 +72,6 @@ public abstract class FieldAccess {
|
||||
abstract public float getFloat (Object instance, int fieldIndex);
|
||||
|
||||
static public FieldAccess get (Class type) {
|
||||
AccessClassLoader loader = AccessClassLoader.get(type);
|
||||
|
||||
ArrayList<Field> fields = new ArrayList<Field>();
|
||||
Class nextClass = type;
|
||||
while (nextClass != Object.class) {
|
||||
@ -96,41 +94,41 @@ public abstract class FieldAccess {
|
||||
String accessClassName = className + "FieldAccess";
|
||||
if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName;
|
||||
Class accessClass = null;
|
||||
try {
|
||||
accessClass = loader.loadClass(accessClassName);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
if (accessClass == null) {
|
||||
String accessClassNameInternal = accessClassName.replace('.', '/');
|
||||
String classNameInternal = className.replace('.', '/');
|
||||
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "com/esotericsoftware/reflectasm/FieldAccess",
|
||||
null);
|
||||
AccessClassLoader loader = AccessClassLoader.get(type);
|
||||
synchronized (loader) {
|
||||
try {
|
||||
accessClass = loader.loadClass(accessClassName);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
String accessClassNameInternal = accessClassName.replace('.', '/');
|
||||
String classNameInternal = className.replace('.', '/');
|
||||
|
||||
insertConstructor(cw);
|
||||
insertGetObject(cw, classNameInternal, fields);
|
||||
insertSetObject(cw, classNameInternal, fields);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
|
||||
insertGetString(cw, classNameInternal, fields);
|
||||
|
||||
cw.visitEnd();
|
||||
accessClass = loader.defineClass(accessClassName, cw.toByteArray());
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "com/esotericsoftware/reflectasm/FieldAccess",
|
||||
null);
|
||||
insertConstructor(cw);
|
||||
insertGetObject(cw, classNameInternal, fields);
|
||||
insertSetObject(cw, classNameInternal, fields);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
|
||||
insertGetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
|
||||
insertSetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
|
||||
insertGetString(cw, classNameInternal, fields);
|
||||
cw.visitEnd();
|
||||
accessClass = loader.defineClass(accessClassName, cw.toByteArray());
|
||||
}
|
||||
}
|
||||
try {
|
||||
FieldAccess access = (FieldAccess)accessClass.newInstance();
|
||||
@ -539,7 +537,7 @@ public abstract class FieldAccess {
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitLdcInsn("The field is not declared as " + fieldType + ": ");
|
||||
mv.visitLdcInsn("Field not declared as " + fieldType + ": ");
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
|
||||
mv.visitVarInsn(ILOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;");
|
||||
|
@ -47,8 +47,6 @@ public abstract class MethodAccess {
|
||||
}
|
||||
|
||||
static public MethodAccess get (Class type) {
|
||||
AccessClassLoader loader = AccessClassLoader.get(type);
|
||||
|
||||
ArrayList<Method> methods = new ArrayList();
|
||||
Class nextClass = type;
|
||||
while (nextClass != Object.class) {
|
||||
@ -75,163 +73,165 @@ public abstract class MethodAccess {
|
||||
String accessClassName = className + "MethodAccess";
|
||||
if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName;
|
||||
Class accessClass = null;
|
||||
try {
|
||||
accessClass = loader.loadClass(accessClassName);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
if (accessClass == null) {
|
||||
String accessClassNameInternal = accessClassName.replace('.', '/');
|
||||
String classNameInternal = className.replace('.', '/');
|
||||
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||
MethodVisitor mv;
|
||||
cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "com/esotericsoftware/reflectasm/MethodAccess",
|
||||
null);
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "com/esotericsoftware/reflectasm/MethodAccess", "<init>", "()V");
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "invoke", "(Ljava/lang/Object;I[Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
null, null);
|
||||
mv.visitCode();
|
||||
AccessClassLoader loader = AccessClassLoader.get(type);
|
||||
synchronized (loader) {
|
||||
try {
|
||||
accessClass = loader.loadClass(accessClassName);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
String accessClassNameInternal = accessClassName.replace('.', '/');
|
||||
String classNameInternal = className.replace('.', '/');
|
||||
|
||||
if (!methods.isEmpty()) {
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitTypeInsn(CHECKCAST, classNameInternal);
|
||||
mv.visitVarInsn(ASTORE, 4);
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||
MethodVisitor mv;
|
||||
cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "com/esotericsoftware/reflectasm/MethodAccess",
|
||||
null);
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "com/esotericsoftware/reflectasm/MethodAccess", "<init>", "()V");
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "invoke",
|
||||
"(Ljava/lang/Object;I[Ljava/lang/Object;)Ljava/lang/Object;", null, null);
|
||||
mv.visitCode();
|
||||
|
||||
mv.visitVarInsn(ILOAD, 2);
|
||||
Label[] labels = new Label[methods.size()];
|
||||
for (int i = 0, n = labels.length; i < n; i++)
|
||||
labels[i] = new Label();
|
||||
Label defaultLabel = new Label();
|
||||
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
|
||||
if (!methods.isEmpty()) {
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitTypeInsn(CHECKCAST, classNameInternal);
|
||||
mv.visitVarInsn(ASTORE, 4);
|
||||
|
||||
StringBuilder buffer = new StringBuilder(128);
|
||||
for (int i = 0, n = labels.length; i < n; i++) {
|
||||
mv.visitLabel(labels[i]);
|
||||
if (i == 0)
|
||||
mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {classNameInternal}, 0, null);
|
||||
else
|
||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
mv.visitVarInsn(ALOAD, 4);
|
||||
mv.visitVarInsn(ILOAD, 2);
|
||||
Label[] labels = new Label[methods.size()];
|
||||
for (int i = 0, n = labels.length; i < n; i++)
|
||||
labels[i] = new Label();
|
||||
Label defaultLabel = new Label();
|
||||
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
|
||||
|
||||
buffer.setLength(0);
|
||||
buffer.append('(');
|
||||
StringBuilder buffer = new StringBuilder(128);
|
||||
for (int i = 0, n = labels.length; i < n; i++) {
|
||||
mv.visitLabel(labels[i]);
|
||||
if (i == 0)
|
||||
mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {classNameInternal}, 0, null);
|
||||
else
|
||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
mv.visitVarInsn(ALOAD, 4);
|
||||
|
||||
Method method = methods.get(i);
|
||||
Class[] paramTypes = method.getParameterTypes();
|
||||
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitIntInsn(BIPUSH, paramIndex);
|
||||
mv.visitInsn(AALOAD);
|
||||
Type paramType = Type.getType(paramTypes[paramIndex]);
|
||||
switch (paramType.getSort()) {
|
||||
buffer.setLength(0);
|
||||
buffer.append('(');
|
||||
|
||||
Method method = methods.get(i);
|
||||
Class[] paramTypes = method.getParameterTypes();
|
||||
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitIntInsn(BIPUSH, paramIndex);
|
||||
mv.visitInsn(AALOAD);
|
||||
Type paramType = Type.getType(paramTypes[paramIndex]);
|
||||
switch (paramType.getSort()) {
|
||||
case Type.BOOLEAN:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
|
||||
break;
|
||||
case Type.BYTE:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
|
||||
break;
|
||||
case Type.CHAR:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
|
||||
break;
|
||||
case Type.SHORT:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
|
||||
break;
|
||||
case Type.INT:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
|
||||
break;
|
||||
case Type.FLOAT:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
|
||||
break;
|
||||
case Type.LONG:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
|
||||
break;
|
||||
case Type.DOUBLE:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
|
||||
break;
|
||||
case Type.ARRAY:
|
||||
mv.visitTypeInsn(CHECKCAST, paramType.getDescriptor());
|
||||
break;
|
||||
case Type.OBJECT:
|
||||
mv.visitTypeInsn(CHECKCAST, paramType.getInternalName());
|
||||
break;
|
||||
}
|
||||
buffer.append(paramType.getDescriptor());
|
||||
}
|
||||
|
||||
buffer.append(')');
|
||||
buffer.append(Type.getDescriptor(method.getReturnType()));
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, classNameInternal, method.getName(), buffer.toString());
|
||||
|
||||
switch (Type.getType(method.getReturnType()).getSort()) {
|
||||
case Type.VOID:
|
||||
mv.visitInsn(ACONST_NULL);
|
||||
break;
|
||||
case Type.BOOLEAN:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
|
||||
break;
|
||||
case Type.BYTE:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
|
||||
break;
|
||||
case Type.CHAR:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
|
||||
break;
|
||||
case Type.SHORT:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
|
||||
break;
|
||||
case Type.INT:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
|
||||
break;
|
||||
case Type.FLOAT:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
|
||||
break;
|
||||
case Type.LONG:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
|
||||
break;
|
||||
case Type.DOUBLE:
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
|
||||
break;
|
||||
case Type.ARRAY:
|
||||
mv.visitTypeInsn(CHECKCAST, paramType.getDescriptor());
|
||||
break;
|
||||
case Type.OBJECT:
|
||||
mv.visitTypeInsn(CHECKCAST, paramType.getInternalName());
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
|
||||
break;
|
||||
}
|
||||
buffer.append(paramType.getDescriptor());
|
||||
|
||||
mv.visitInsn(ARETURN);
|
||||
}
|
||||
|
||||
buffer.append(')');
|
||||
buffer.append(Type.getDescriptor(method.getReturnType()));
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, classNameInternal, method.getName(), buffer.toString());
|
||||
|
||||
switch (Type.getType(method.getReturnType()).getSort()) {
|
||||
case Type.VOID:
|
||||
mv.visitInsn(ACONST_NULL);
|
||||
break;
|
||||
case Type.BOOLEAN:
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
|
||||
break;
|
||||
case Type.BYTE:
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
|
||||
break;
|
||||
case Type.CHAR:
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
|
||||
break;
|
||||
case Type.SHORT:
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
|
||||
break;
|
||||
case Type.INT:
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
|
||||
break;
|
||||
case Type.FLOAT:
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
|
||||
break;
|
||||
case Type.LONG:
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
|
||||
break;
|
||||
case Type.DOUBLE:
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
|
||||
break;
|
||||
}
|
||||
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitLabel(defaultLabel);
|
||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
}
|
||||
|
||||
mv.visitLabel(defaultLabel);
|
||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitLdcInsn("Method not found: ");
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
|
||||
mv.visitVarInsn(ILOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "(Ljava/lang/String;)V");
|
||||
mv.visitInsn(ATHROW);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitLdcInsn("Method not found: ");
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
|
||||
mv.visitVarInsn(ILOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "(Ljava/lang/String;)V");
|
||||
mv.visitInsn(ATHROW);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
cw.visitEnd();
|
||||
byte[] data = cw.toByteArray();
|
||||
accessClass = loader.defineClass(accessClassName, data);
|
||||
}
|
||||
cw.visitEnd();
|
||||
byte[] data = cw.toByteArray();
|
||||
accessClass = loader.defineClass(accessClassName, data);
|
||||
}
|
||||
try {
|
||||
MethodAccess access = (MethodAccess)accessClass.newInstance();
|
||||
|
Loading…
Reference in New Issue
Block a user