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:
Martin Grotzke 2016-05-08 22:44:25 +02:00
parent 88ec7037ea
commit c5563b1205
3 changed files with 232 additions and 220 deletions

View File

@ -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;

View File

@ -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 {

View File

@ -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 {