package nebula.data.impl; import static org.objectweb.asm.Opcodes.ACC_BRIDGE; import static org.objectweb.asm.Opcodes.ACC_FINAL; import static org.objectweb.asm.Opcodes.ACC_NATIVE; import static org.objectweb.asm.Opcodes.ACC_PRIVATE; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; import static org.objectweb.asm.Opcodes.ACC_STATIC; import static org.objectweb.asm.Opcodes.ACC_SUPER; import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC; import static org.objectweb.asm.Opcodes.ALOAD; import static org.objectweb.asm.Opcodes.ARETURN; import static org.objectweb.asm.Opcodes.CHECKCAST; import static org.objectweb.asm.Opcodes.DLOAD; import static org.objectweb.asm.Opcodes.DRETURN; import static org.objectweb.asm.Opcodes.FLOAD; import static org.objectweb.asm.Opcodes.FRETURN; import static org.objectweb.asm.Opcodes.GETFIELD; import static org.objectweb.asm.Opcodes.ILOAD; import static org.objectweb.asm.Opcodes.INVOKEINTERFACE; import static org.objectweb.asm.Opcodes.INVOKESPECIAL; import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; import static org.objectweb.asm.Opcodes.IRETURN; import static org.objectweb.asm.Opcodes.LLOAD; import static org.objectweb.asm.Opcodes.LRETURN; import static org.objectweb.asm.Opcodes.RETURN; import nebula.data.Broker; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; class BrokerForInterfaceClassVisitor extends ClassVisitor { String name; String targetTypeName; final static String brokerTypeName = Broker.class.getName().replace('.', '/'); public BrokerForInterfaceClassVisitor(int api) { super(api); } public BrokerForInterfaceClassVisitor(int api, ClassVisitor cv, String name) { super(api, cv); this.name = name; } @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { this.targetTypeName = name; super.visit(version, ACC_PUBLIC + ACC_SUPER, this.name, "L" + brokerTypeName + "<L" + this.targetTypeName + ";>;L" + this.targetTypeName + ";", "" + brokerTypeName + "", new String[] { name }); MethodVisitor mv; { mv = super.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "" + brokerTypeName + "", "<init>", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } { mv = super.visitMethod(ACC_PUBLIC, "get", "()L" + targetTypeName + ";", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(ARETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } } @Override public void visitSource(String source, String debug) { String newSourceName = this.name + ".java"; super.visitSource(newSourceName, debug); } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor mv = null; { if (!!!name.equals("<init>") && !!!name.equals("<clinit>") && (access & (ACC_STATIC | ACC_PRIVATE | ACC_SYNTHETIC | ACC_NATIVE | ACC_BRIDGE)) == 0) { if ((access & ACC_FINAL) != 0) throw new RuntimeException("new FinalModifierException(superToCopy, name)"); mv = super.visitMethod(ACC_PUBLIC, name, desc, signature, exceptions); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, this.name, "actualValue", "Ljava/lang/Object;"); mv.visitTypeInsn(CHECKCAST, this.targetTypeName); Method currentTransformMethod = new Method(name, desc); delegateCall(mv, currentTransformMethod, this.targetTypeName); mv.visitMaxs(2, 2); mv.visitEnd(); } } return mv; } /** * This method loads this, any args, then invokes the super version of this */ private final void delegateCall(MethodVisitor mv, Method currentTransformMethod, String typeName) { int nargs = currentTransformMethod.getArgumentTypes().length; for (int i = 1; i <= nargs; i++) { switch (currentTransformMethod.getArgumentTypes()[i - 1].getSort()) { case (Type.BOOLEAN): case (Type.BYTE): case (Type.CHAR): case (Type.SHORT): case (Type.INT): mv.visitVarInsn(ILOAD, i); break; case (Type.FLOAT): mv.visitVarInsn(FLOAD, i); break; case (Type.DOUBLE): mv.visitVarInsn(DLOAD, i); break; case (Type.LONG): mv.visitVarInsn(LLOAD, i); break; default: mv.visitVarInsn(ALOAD, i); } } mv.visitMethodInsn(INVOKEINTERFACE, typeName, currentTransformMethod.getName(), currentTransformMethod.getDescriptor()); switch (currentTransformMethod.getReturnType().getSort()) { case (Type.BOOLEAN): case (Type.BYTE): case (Type.CHAR): case (Type.SHORT): case (Type.INT): mv.visitInsn(IRETURN); break; case (Type.VOID): mv.visitInsn(RETURN); break; case (Type.FLOAT): mv.visitInsn(FRETURN); break; case (Type.DOUBLE): mv.visitInsn(DRETURN); break; case (Type.LONG): mv.visitInsn(LRETURN); break; default: mv.visitInsn(ARETURN); } } @Override public void visitEnd() { MethodVisitor mv; { mv = super.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "get", "()Ljava/lang/Object;", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKEVIRTUAL, this.name, "get", "()L" + targetTypeName + ";"); mv.visitInsn(ARETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } super.visitEnd(); } @Override public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { // return super.visitField(access, name, desc, signature, value); return null; } }