Fixed writing private fields with a compiled structure modifier.

Incredibly hard to track down. Lucked out by randomly removing a
semicolon.
This commit is contained in:
Kristian S. Stangeland 2012-11-20 06:17:52 +01:00
parent 456764468a
commit ac993896cc
2 changed files with 30 additions and 30 deletions

View File

@ -30,9 +30,8 @@ import com.google.common.collect.Sets;
* Represents a compiled structure modifier. * Represents a compiled structure modifier.
* *
* @author Kristian * @author Kristian
* @param <TField> Field type.
*/ */
public abstract class CompiledStructureModifier<TField> extends StructureModifier<TField> { public abstract class CompiledStructureModifier extends StructureModifier<Object> {
// Used to compile instances of structure modifiers // Used to compile instances of structure modifiers
protected StructureCompiler compiler; protected StructureCompiler compiler;
@ -64,9 +63,8 @@ public abstract class CompiledStructureModifier<TField> extends StructureModifie
} }
// Speed up the default writer // Speed up the default writer
@SuppressWarnings("unchecked")
@Override @Override
public StructureModifier<TField> writeDefaults() throws FieldAccessException { public StructureModifier<Object> writeDefaults() throws FieldAccessException {
DefaultInstances generator = DefaultInstances.DEFAULT; DefaultInstances generator = DefaultInstances.DEFAULT;
@ -75,21 +73,20 @@ public abstract class CompiledStructureModifier<TField> extends StructureModifie
Integer index = entry.getValue(); Integer index = entry.getValue();
Field field = entry.getKey(); Field field = entry.getKey();
write(index, (TField) generator.getDefault(field.getType())); write(index, (Object) generator.getDefault(field.getType()));
} }
return this; return this;
} }
@SuppressWarnings("unchecked")
@Override @Override
public final TField read(int fieldIndex) throws FieldAccessException { public final Object read(int fieldIndex) throws FieldAccessException {
Object result = readGenerated(fieldIndex); Object result = readGenerated(fieldIndex);
if (converter != null) if (converter != null)
return converter.getSpecific(result); return converter.getSpecific(result);
else else
return (TField) result; return result;
} }
/** /**
@ -104,11 +101,10 @@ public abstract class CompiledStructureModifier<TField> extends StructureModifie
protected abstract Object readGenerated(int fieldIndex) throws FieldAccessException; protected abstract Object readGenerated(int fieldIndex) throws FieldAccessException;
@SuppressWarnings("unchecked")
@Override @Override
public StructureModifier<TField> write(int index, Object value) throws FieldAccessException { public StructureModifier<Object> write(int index, Object value) throws FieldAccessException {
if (converter != null) if (converter != null)
value = converter.getGeneric(getFieldType(index), (TField) value); value = converter.getGeneric(getFieldType(index), value);
return writeGenerated(index, value); return writeGenerated(index, value);
} }
@ -118,15 +114,14 @@ public abstract class CompiledStructureModifier<TField> extends StructureModifie
* @param value - new value. * @param value - new value.
* @throws FieldAccessException The field doesn't exist, or it cannot be accessed under the current security contraints. * @throws FieldAccessException The field doesn't exist, or it cannot be accessed under the current security contraints.
*/ */
@SuppressWarnings("unchecked")
protected void writeReflected(int index, Object value) throws FieldAccessException { protected void writeReflected(int index, Object value) throws FieldAccessException {
super.write(index, (TField) value); super.write(index, value);
} }
protected abstract StructureModifier<TField> writeGenerated(int index, Object value) throws FieldAccessException; protected abstract StructureModifier<Object> writeGenerated(int index, Object value) throws FieldAccessException;
@Override @Override
public StructureModifier<TField> withTarget(Object target) { public StructureModifier<Object> withTarget(Object target) {
if (compiler != null) if (compiler != null)
return compiler.compile(super.withTarget(target)); return compiler.compile(super.withTarget(target));
else else

View File

@ -138,7 +138,7 @@ public final class StructureCompiler {
* Construct a structure compiler. * Construct a structure compiler.
* @param loader - main class loader. * @param loader - main class loader.
*/ */
StructureCompiler(ClassLoader loader) { public StructureCompiler(ClassLoader loader) {
this.loader = loader; this.loader = loader;
} }
@ -219,8 +219,7 @@ public final class StructureCompiler {
} }
cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, PACKAGE_NAME + "/" + className, cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, PACKAGE_NAME + "/" + className,
"<TField:Ljava/lang/Object;>L" + COMPILED_CLASS + "<TTField;>;", null, COMPILED_CLASS, null);
COMPILED_CLASS, null);
createFields(cw, targetSignature); createFields(cw, targetSignature);
createConstructor(cw, className, targetSignature, targetName); createConstructor(cw, className, targetSignature, targetName);
@ -295,14 +294,16 @@ public final class StructureCompiler {
private void createWriteMethod(ClassWriter cw, String className, List<Field> fields, String targetSignature, String targetName) { private void createWriteMethod(ClassWriter cw, String className, List<Field> fields, String targetSignature, String targetName) {
String methodDescriptor = "(ILjava/lang/Object;)L" + SUPER_CLASS + ";"; String methodDescriptor = "(ILjava/lang/Object;)L" + SUPER_CLASS + ";";
String methodSignature = "(ITTField;)L" + SUPER_CLASS + "<TTField;>;"; String methodSignature = "(ILjava/lang/Object;)L" + SUPER_CLASS + "<Ljava/lang/Object;>;";
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PROTECTED, "writeGenerated", methodDescriptor, methodSignature, MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PROTECTED, "writeGenerated", methodDescriptor, methodSignature,
new String[] { FIELD_EXCEPTION_CLASS }); new String[] { FIELD_EXCEPTION_CLASS });
BoxingHelper boxingHelper = new BoxingHelper(mv); BoxingHelper boxingHelper = new BoxingHelper(mv);
String generatedClassName = PACKAGE_NAME + "/" + className;
mv.visitCode(); mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitFieldInsn(Opcodes.GETFIELD, PACKAGE_NAME + "/" + className, "typedTarget", targetSignature); mv.visitFieldInsn(Opcodes.GETFIELD, generatedClassName, "typedTarget", targetSignature);
mv.visitVarInsn(Opcodes.ASTORE, 3); mv.visitVarInsn(Opcodes.ASTORE, 3);
mv.visitVarInsn(Opcodes.ILOAD, 1); mv.visitVarInsn(Opcodes.ILOAD, 1);
@ -351,7 +352,7 @@ public final class StructureCompiler {
mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitVarInsn(Opcodes.ILOAD, 1); mv.visitVarInsn(Opcodes.ILOAD, 1);
mv.visitVarInsn(Opcodes.ALOAD, 2); mv.visitVarInsn(Opcodes.ALOAD, 2);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, COMPILED_CLASS, "writeReflected", "(ILjava/lang/Object;)V;"); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, generatedClassName, "writeReflected", "(ILjava/lang/Object;)V");
} }
mv.visitJumpInsn(Opcodes.GOTO, returnLabel); mv.visitJumpInsn(Opcodes.GOTO, returnLabel);
@ -384,9 +385,11 @@ public final class StructureCompiler {
new String[] { "com/comphenix/protocol/reflect/FieldAccessException" }); new String[] { "com/comphenix/protocol/reflect/FieldAccessException" });
BoxingHelper boxingHelper = new BoxingHelper(mv); BoxingHelper boxingHelper = new BoxingHelper(mv);
String generatedClassName = PACKAGE_NAME + "/" + className;
mv.visitCode(); mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitFieldInsn(Opcodes.GETFIELD, PACKAGE_NAME + "/" + className, "typedTarget", targetSignature); mv.visitFieldInsn(Opcodes.GETFIELD, generatedClassName, "typedTarget", targetSignature);
mv.visitVarInsn(Opcodes.ASTORE, 2); mv.visitVarInsn(Opcodes.ASTORE, 2);
mv.visitVarInsn(Opcodes.ILOAD, 1); mv.visitVarInsn(Opcodes.ILOAD, 1);
@ -425,7 +428,7 @@ public final class StructureCompiler {
// We have to use reflection for private and protected fields. // We have to use reflection for private and protected fields.
mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitVarInsn(Opcodes.ILOAD, 1); mv.visitVarInsn(Opcodes.ILOAD, 1);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, COMPILED_CLASS, "readReflected", "(I)Ljava/lang/Object;"); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, generatedClassName, "readReflected", "(I)Ljava/lang/Object;");
} }
mv.visitInsn(Opcodes.ARETURN); mv.visitInsn(Opcodes.ARETURN);
@ -451,25 +454,27 @@ public final class StructureCompiler {
private void createConstructor(ClassWriter cw, String className, String targetSignature, String targetName) { private void createConstructor(ClassWriter cw, String className, String targetSignature, String targetName) {
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>",
"(L" + SUPER_CLASS + ";L" + PACKAGE_NAME + "/StructureCompiler;)V", "(L" + SUPER_CLASS + ";L" + PACKAGE_NAME + "/StructureCompiler;)V",
"(L" + SUPER_CLASS + "<TTField;>;L" + SUPER_CLASS + ";)V", null); "(L" + SUPER_CLASS + "<Ljava/lang/Object;>;L" + PACKAGE_NAME + "/StructureCompiler;)V", null);
String fullClassName = PACKAGE_NAME + "/" + className;
mv.visitCode(); mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, COMPILED_CLASS, "<init>", "()V"); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, COMPILED_CLASS, "<init>", "()V");
mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitVarInsn(Opcodes.ALOAD, 1); mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, PACKAGE_NAME + "/" + className, "initialize", "(L" + SUPER_CLASS + ";)V"); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, fullClassName, "initialize", "(L" + SUPER_CLASS + ";)V");
mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitVarInsn(Opcodes.ALOAD, 1); mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, SUPER_CLASS, "getTarget", "()Ljava/lang/Object;"); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, SUPER_CLASS, "getTarget", "()Ljava/lang/Object;");
mv.visitFieldInsn(Opcodes.PUTFIELD, PACKAGE_NAME + "/" + className, "target", "Ljava/lang/Object;"); mv.visitFieldInsn(Opcodes.PUTFIELD, fullClassName, "target", "Ljava/lang/Object;");
mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitFieldInsn(Opcodes.GETFIELD, PACKAGE_NAME + "/" + className, "target", "Ljava/lang/Object;"); mv.visitFieldInsn(Opcodes.GETFIELD, fullClassName, "target", "Ljava/lang/Object;");
mv.visitTypeInsn(Opcodes.CHECKCAST, targetName); mv.visitTypeInsn(Opcodes.CHECKCAST, targetName);
mv.visitFieldInsn(Opcodes.PUTFIELD, PACKAGE_NAME + "/" + className, "typedTarget", targetSignature); mv.visitFieldInsn(Opcodes.PUTFIELD, fullClassName, "typedTarget", targetSignature);
mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitVarInsn(Opcodes.ALOAD, 2); mv.visitVarInsn(Opcodes.ALOAD, 2);
mv.visitFieldInsn(Opcodes.PUTFIELD, PACKAGE_NAME + "/" + className, "compiler", "L" + PACKAGE_NAME + "/StructureCompiler;"); mv.visitFieldInsn(Opcodes.PUTFIELD, fullClassName, "compiler", "L" + PACKAGE_NAME + "/StructureCompiler;");
mv.visitInsn(Opcodes.RETURN); mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(2, 3); mv.visitMaxs(2, 3);
mv.visitEnd(); mv.visitEnd();