/** Rewrites a field reference to another field access. */ MemberAdapter fieldToField(Field f) { final String newName = f.getName(); final Type newType = Type.getType(f.getType()); final String newTypeDescriptor = newType.getDescriptor(); final String newTypeInternalName = isReferenceType(newType) ? newType.getInternalName() : null; return new MemberAdapter(f) { @Override boolean adapt(int opcode, String owner, String name, String desc, MethodVisitor delegate) { switch (opcode) { case GETFIELD: case GETSTATIC: // rewrite "x.y" to "(T)x.z". // we'll leave it up to HotSpot to optimize away casts delegate.visitFieldInsn(opcode, owner, newName, newTypeDescriptor); Type t = Type.getType(desc); if (isReferenceType(t)) delegate.visitTypeInsn(CHECKCAST, t.getInternalName()); return true; case PUTFIELD: case PUTSTATIC: // rewrite "x.y=v" to "x.z=(T)v" if (isReferenceType(newType)) delegate.visitTypeInsn(CHECKCAST, newTypeInternalName); delegate.visitFieldInsn(opcode, owner, newName, newTypeDescriptor); return true; } return false; } }; }
@Override boolean adapt(int opcode, String owner, String name, String desc, MethodVisitor delegate) { if (opcode == fieldOpcode) { Type t = Type.getType(desc); boolean expectedReference = isReferenceType(t); if (actuallyPrimitive ^ expectedReference) { // rewrite "x.y" to "(T)x.z()". // we'll leave it up to HotSpot to optimize away casts delegate.visitMethodInsn(invokeOpcode, owner, methodName, methodDescriptor); if (expectedReference) delegate.visitTypeInsn(CHECKCAST, t.getInternalName()); return true; } } return false; }
public FieldToMethodAdapter(Method m, int fieldOpcode, int invokeOpcode) { super(m); methodName = m.getName(); methodDescriptor = Type.getMethodDescriptor(m); Class<?>[] params = m.getParameterTypes(); boolean isGetter = params.length == 0; actuallyPrimitive = isGetter ? m.getReturnType().isPrimitive() : params[0].isPrimitive(); this.fieldOpcode = fieldOpcode; this.invokeOpcode = invokeOpcode; }
@Override boolean adapt(int opcode, String owner, String name, String desc, MethodVisitor delegate) { if (opcode == fieldOpcode) { Type t = Type.getType(desc); boolean expectedReference = isReferenceType(t); if (actuallyPrimitive ^ expectedReference) { // rewrite "x.y=v" to "x.z(v)" // we expect the argument type to match delegate.visitMethodInsn(invokeOpcode, owner, methodName, methodDescriptor); return true; } } return false; }
private static boolean isReferenceType(Type t) { return t.getSort() == ARRAY || t.getSort() == OBJECT; }