mirror of
https://github.com/EsotericSoftware/reflectasm.git
synced 2025-01-15 14:20:29 +08:00
Try to load accessClass without synchronization
In EsotericSoftware/kryo#422 it's reported that the sychronization in `ConstructorAccess.get` on the loader is causing significant thread contention. This change tries to prevent this, via double checked locking. Because it's the same pattern it's also done for `FieldAccess` and `MethodAccess` as well.
This commit is contained in:
parent
88ec7037ea
commit
c5563b1205
@ -49,55 +49,59 @@ public abstract class ConstructorAccess<T> {
|
|||||||
String accessClassName = className + "ConstructorAccess";
|
String accessClassName = className + "ConstructorAccess";
|
||||||
if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName;
|
if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName;
|
||||||
Class accessClass;
|
Class accessClass;
|
||||||
|
|
||||||
AccessClassLoader loader = AccessClassLoader.get(type);
|
AccessClassLoader loader = AccessClassLoader.get(type);
|
||||||
synchronized (loader) {
|
try {
|
||||||
try {
|
accessClass = loader.loadClass(accessClassName);
|
||||||
accessClass = loader.loadClass(accessClassName);
|
} catch (ClassNotFoundException ignored) {
|
||||||
} catch (ClassNotFoundException ignored) {
|
synchronized (loader) {
|
||||||
String accessClassNameInternal = accessClassName.replace('.', '/');
|
try {
|
||||||
String classNameInternal = className.replace('.', '/');
|
accessClass = loader.loadClass(accessClassName);
|
||||||
String enclosingClassNameInternal;
|
} catch (ClassNotFoundException ignored2) {
|
||||||
Constructor<T> constructor = null;
|
String accessClassNameInternal = accessClassName.replace('.', '/');
|
||||||
int modifiers = 0;
|
String classNameInternal = className.replace('.', '/');
|
||||||
if (!isNonStaticMemberClass) {
|
String enclosingClassNameInternal;
|
||||||
enclosingClassNameInternal = null;
|
Constructor<T> constructor = null;
|
||||||
try {
|
int modifiers = 0;
|
||||||
constructor = type.getDeclaredConstructor((Class[])null);
|
if (!isNonStaticMemberClass) {
|
||||||
modifiers = constructor.getModifiers();
|
enclosingClassNameInternal = null;
|
||||||
} catch (Exception ex) {
|
try {
|
||||||
throw new RuntimeException("Class cannot be created (missing no-arg constructor): " + type.getName(), ex);
|
constructor = type.getDeclaredConstructor((Class[])null);
|
||||||
}
|
modifiers = constructor.getModifiers();
|
||||||
if (Modifier.isPrivate(modifiers)) {
|
} catch (Exception ex) {
|
||||||
throw new RuntimeException("Class cannot be created (the no-arg constructor is private): " + type.getName());
|
throw new RuntimeException("Class cannot be created (missing no-arg constructor): " + type.getName(), ex);
|
||||||
}
|
}
|
||||||
} else {
|
if (Modifier.isPrivate(modifiers)) {
|
||||||
enclosingClassNameInternal = enclosingType.getName().replace('.', '/');
|
throw new RuntimeException("Class cannot be created (the no-arg constructor is private): " + type.getName());
|
||||||
try {
|
}
|
||||||
constructor = type.getDeclaredConstructor(enclosingType); // Inner classes should have this.
|
} else {
|
||||||
modifiers = constructor.getModifiers();
|
enclosingClassNameInternal = enclosingType.getName().replace('.', '/');
|
||||||
} catch (Exception ex) {
|
try {
|
||||||
throw new RuntimeException("Non-static member class cannot be created (missing enclosing class constructor): "
|
constructor = type.getDeclaredConstructor(enclosingType); // Inner classes should have this.
|
||||||
+ type.getName(), ex);
|
modifiers = constructor.getModifiers();
|
||||||
}
|
} catch (Exception ex) {
|
||||||
if (Modifier.isPrivate(modifiers)) {
|
throw new RuntimeException("Non-static member class cannot be created (missing enclosing class constructor): "
|
||||||
throw new RuntimeException(
|
+ type.getName(), ex);
|
||||||
"Non-static member class cannot be created (the enclosing class constructor is private): " + type.getName());
|
}
|
||||||
|
if (Modifier.isPrivate(modifiers)) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"Non-static member class cannot be created (the enclosing class constructor is private): " + type.getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
String superclassNameInternal = Modifier.isPublic(modifiers) ?
|
||||||
|
"com/esotericsoftware/reflectasm/PublicConstructorAccess" :
|
||||||
|
"com/esotericsoftware/reflectasm/ConstructorAccess";
|
||||||
|
|
||||||
|
ClassWriter cw = new ClassWriter(0);
|
||||||
|
cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, superclassNameInternal, null);
|
||||||
|
|
||||||
|
insertConstructor(cw, superclassNameInternal);
|
||||||
|
insertNewInstance(cw, classNameInternal);
|
||||||
|
insertNewInstanceInner(cw, classNameInternal, enclosingClassNameInternal);
|
||||||
|
|
||||||
|
cw.visitEnd();
|
||||||
|
accessClass = loader.defineClass(accessClassName, cw.toByteArray());
|
||||||
}
|
}
|
||||||
String superclassNameInternal = Modifier.isPublic(modifiers) ?
|
|
||||||
"com/esotericsoftware/reflectasm/PublicConstructorAccess" :
|
|
||||||
"com/esotericsoftware/reflectasm/ConstructorAccess";
|
|
||||||
|
|
||||||
ClassWriter cw = new ClassWriter(0);
|
|
||||||
cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, superclassNameInternal, null);
|
|
||||||
|
|
||||||
insertConstructor(cw, superclassNameInternal);
|
|
||||||
insertNewInstance(cw, classNameInternal);
|
|
||||||
insertNewInstanceInner(cw, classNameInternal, enclosingClassNameInternal);
|
|
||||||
|
|
||||||
cw.visitEnd();
|
|
||||||
accessClass = loader.defineClass(accessClassName, cw.toByteArray());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConstructorAccess<T> access;
|
ConstructorAccess<T> access;
|
||||||
|
@ -121,38 +121,42 @@ public abstract class FieldAccess {
|
|||||||
Class accessClass = null;
|
Class accessClass = null;
|
||||||
|
|
||||||
AccessClassLoader loader = AccessClassLoader.get(type);
|
AccessClassLoader loader = AccessClassLoader.get(type);
|
||||||
synchronized (loader) {
|
try {
|
||||||
try {
|
accessClass = loader.loadClass(accessClassName);
|
||||||
accessClass = loader.loadClass(accessClassName);
|
} catch (ClassNotFoundException ignored) {
|
||||||
} catch (ClassNotFoundException ignored) {
|
synchronized (loader) {
|
||||||
String accessClassNameInternal = accessClassName.replace('.', '/');
|
try {
|
||||||
String classNameInternal = className.replace('.', '/');
|
accessClass = loader.loadClass(accessClassName);
|
||||||
|
} catch (ClassNotFoundException ignored2) {
|
||||||
ClassWriter cw = new ClassWriter(0);
|
String accessClassNameInternal = accessClassName.replace('.', '/');
|
||||||
cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "com/esotericsoftware/reflectasm/FieldAccess",
|
String classNameInternal = className.replace('.', '/');
|
||||||
null);
|
|
||||||
insertConstructor(cw);
|
ClassWriter cw = new ClassWriter(0);
|
||||||
insertGetObject(cw, classNameInternal, fields);
|
cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "com/esotericsoftware/reflectasm/FieldAccess",
|
||||||
insertSetObject(cw, classNameInternal, fields);
|
null);
|
||||||
insertGetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
|
insertConstructor(cw);
|
||||||
insertSetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
|
insertGetObject(cw, classNameInternal, fields);
|
||||||
insertGetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
|
insertSetObject(cw, classNameInternal, fields);
|
||||||
insertSetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
|
insertGetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
|
||||||
insertGetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
|
insertSetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
|
||||||
insertSetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
|
insertGetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
|
||||||
insertGetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
|
insertSetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
|
||||||
insertSetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
|
insertGetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
|
||||||
insertGetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
|
insertSetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
|
||||||
insertSetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
|
insertGetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
|
||||||
insertGetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
|
insertSetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
|
||||||
insertSetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
|
insertGetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
|
||||||
insertGetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
|
insertSetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
|
||||||
insertSetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
|
insertGetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
|
||||||
insertGetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
|
insertSetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
|
||||||
insertSetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
|
insertGetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
|
||||||
insertGetString(cw, classNameInternal, fields);
|
insertSetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
|
||||||
cw.visitEnd();
|
insertGetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
|
||||||
accessClass = loader.defineClass(accessClassName, cw.toByteArray());
|
insertSetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
|
||||||
|
insertGetString(cw, classNameInternal, fields);
|
||||||
|
cw.visitEnd();
|
||||||
|
accessClass = loader.defineClass(accessClassName, cw.toByteArray());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -107,169 +107,173 @@ public abstract class MethodAccess {
|
|||||||
Class accessClass;
|
Class accessClass;
|
||||||
|
|
||||||
AccessClassLoader loader = AccessClassLoader.get(type);
|
AccessClassLoader loader = AccessClassLoader.get(type);
|
||||||
synchronized (loader) {
|
try {
|
||||||
try {
|
accessClass = loader.loadClass(accessClassName);
|
||||||
accessClass = loader.loadClass(accessClassName);
|
} catch (ClassNotFoundException ignored) {
|
||||||
} catch (ClassNotFoundException ignored) {
|
synchronized (loader) {
|
||||||
String accessClassNameInternal = accessClassName.replace('.', '/');
|
try {
|
||||||
String classNameInternal = className.replace('.', '/');
|
accessClass = loader.loadClass(accessClassName);
|
||||||
|
} catch (ClassNotFoundException ignored2) {
|
||||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
String accessClassNameInternal = accessClassName.replace('.', '/');
|
||||||
MethodVisitor mv;
|
String classNameInternal = className.replace('.', '/');
|
||||||
cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "com/esotericsoftware/reflectasm/MethodAccess",
|
|
||||||
null);
|
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||||
{
|
MethodVisitor mv;
|
||||||
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "com/esotericsoftware/reflectasm/MethodAccess",
|
||||||
mv.visitCode();
|
null);
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
{
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, "com/esotericsoftware/reflectasm/MethodAccess", "<init>", "()V");
|
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
||||||
mv.visitInsn(RETURN);
|
mv.visitCode();
|
||||||
mv.visitMaxs(0, 0);
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
mv.visitEnd();
|
mv.visitMethodInsn(INVOKESPECIAL, "com/esotericsoftware/reflectasm/MethodAccess", "<init>", "()V");
|
||||||
}
|
mv.visitInsn(RETURN);
|
||||||
{
|
mv.visitMaxs(0, 0);
|
||||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "invoke",
|
mv.visitEnd();
|
||||||
"(Ljava/lang/Object;I[Ljava/lang/Object;)Ljava/lang/Object;", null, null);
|
}
|
||||||
mv.visitCode();
|
{
|
||||||
|
mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "invoke",
|
||||||
if (!methods.isEmpty()) {
|
"(Ljava/lang/Object;I[Ljava/lang/Object;)Ljava/lang/Object;", null, null);
|
||||||
mv.visitVarInsn(ALOAD, 1);
|
mv.visitCode();
|
||||||
mv.visitTypeInsn(CHECKCAST, classNameInternal);
|
|
||||||
mv.visitVarInsn(ASTORE, 4);
|
if (!methods.isEmpty()) {
|
||||||
|
mv.visitVarInsn(ALOAD, 1);
|
||||||
mv.visitVarInsn(ILOAD, 2);
|
mv.visitTypeInsn(CHECKCAST, classNameInternal);
|
||||||
Label[] labels = new Label[n];
|
mv.visitVarInsn(ASTORE, 4);
|
||||||
for (int i = 0; i < n; i++)
|
|
||||||
labels[i] = new Label();
|
mv.visitVarInsn(ILOAD, 2);
|
||||||
Label defaultLabel = new Label();
|
Label[] labels = new Label[n];
|
||||||
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
|
for (int i = 0; i < n; i++)
|
||||||
|
labels[i] = new Label();
|
||||||
StringBuilder buffer = new StringBuilder(128);
|
Label defaultLabel = new Label();
|
||||||
for (int i = 0; i < n; i++) {
|
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
|
||||||
mv.visitLabel(labels[i]);
|
|
||||||
if (i == 0)
|
StringBuilder buffer = new StringBuilder(128);
|
||||||
mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {classNameInternal}, 0, null);
|
for (int i = 0; i < n; i++) {
|
||||||
else
|
mv.visitLabel(labels[i]);
|
||||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
if (i == 0)
|
||||||
mv.visitVarInsn(ALOAD, 4);
|
mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {classNameInternal}, 0, null);
|
||||||
|
else
|
||||||
buffer.setLength(0);
|
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||||
buffer.append('(');
|
mv.visitVarInsn(ALOAD, 4);
|
||||||
|
|
||||||
Class[] paramTypes = parameterTypes[i];
|
buffer.setLength(0);
|
||||||
Class returnType = returnTypes[i];
|
buffer.append('(');
|
||||||
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
|
|
||||||
mv.visitVarInsn(ALOAD, 3);
|
Class[] paramTypes = parameterTypes[i];
|
||||||
mv.visitIntInsn(BIPUSH, paramIndex);
|
Class returnType = returnTypes[i];
|
||||||
mv.visitInsn(AALOAD);
|
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
|
||||||
Type paramType = Type.getType(paramTypes[paramIndex]);
|
mv.visitVarInsn(ALOAD, 3);
|
||||||
switch (paramType.getSort()) {
|
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(returnType));
|
||||||
|
int invoke;
|
||||||
|
if (isInterface)
|
||||||
|
invoke = INVOKEINTERFACE;
|
||||||
|
else if (Modifier.isStatic(methods.get(i).getModifiers()))
|
||||||
|
invoke = INVOKESTATIC;
|
||||||
|
else
|
||||||
|
invoke = INVOKEVIRTUAL;
|
||||||
|
mv.visitMethodInsn(invoke, classNameInternal, methodNames[i], buffer.toString());
|
||||||
|
|
||||||
|
switch (Type.getType(returnType).getSort()) {
|
||||||
|
case Type.VOID:
|
||||||
|
mv.visitInsn(ACONST_NULL);
|
||||||
|
break;
|
||||||
case Type.BOOLEAN:
|
case Type.BOOLEAN:
|
||||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
|
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
|
|
||||||
break;
|
break;
|
||||||
case Type.BYTE:
|
case Type.BYTE:
|
||||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
|
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
|
|
||||||
break;
|
break;
|
||||||
case Type.CHAR:
|
case Type.CHAR:
|
||||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
|
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
|
|
||||||
break;
|
break;
|
||||||
case Type.SHORT:
|
case Type.SHORT:
|
||||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
|
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
|
|
||||||
break;
|
break;
|
||||||
case Type.INT:
|
case Type.INT:
|
||||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
|
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
|
|
||||||
break;
|
break;
|
||||||
case Type.FLOAT:
|
case Type.FLOAT:
|
||||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
|
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
|
|
||||||
break;
|
break;
|
||||||
case Type.LONG:
|
case Type.LONG:
|
||||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
|
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
|
|
||||||
break;
|
break;
|
||||||
case Type.DOUBLE:
|
case Type.DOUBLE:
|
||||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
|
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/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;
|
break;
|
||||||
}
|
}
|
||||||
buffer.append(paramType.getDescriptor());
|
|
||||||
|
mv.visitInsn(ARETURN);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.append(')');
|
mv.visitLabel(defaultLabel);
|
||||||
buffer.append(Type.getDescriptor(returnType));
|
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||||
int invoke;
|
|
||||||
if (isInterface)
|
|
||||||
invoke = INVOKEINTERFACE;
|
|
||||||
else if (Modifier.isStatic(methods.get(i).getModifiers()))
|
|
||||||
invoke = INVOKESTATIC;
|
|
||||||
else
|
|
||||||
invoke = INVOKEVIRTUAL;
|
|
||||||
mv.visitMethodInsn(invoke, classNameInternal, methodNames[i], buffer.toString());
|
|
||||||
|
|
||||||
switch (Type.getType(returnType).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.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
|
||||||
mv.visitLabel(defaultLabel);
|
mv.visitInsn(DUP);
|
||||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
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");
|
cw.visitEnd();
|
||||||
mv.visitInsn(DUP);
|
byte[] data = cw.toByteArray();
|
||||||
mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
|
accessClass = loader.defineClass(accessClassName, data);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
Loading…
Reference in New Issue
Block a user