/* * Minha.pt: middleware testing platform. * Copyright (c) 2011-2014, Universidade do Minho. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package pt.minha.kernel.instrument; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import pt.minha.models.local.io.WrappedObjectInputStream; import pt.minha.models.local.io.WrappedObjectOutputStream; public class SerializableClassVisitor extends ClassVisitor implements Opcodes { private boolean isSerializable; private String name; private Translation trans; public SerializableClassVisitor(ClassVisitor visitor, Translation trans) { super(Opcodes.ASM5, visitor); this.trans = trans; } public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { this.name = name; for(String intf: interfaces) { if (intf.equals("java/io/Serializable")) { isSerializable = true; break; } } trans.getLogger().debug("found Serializable super-interface"); super.visit(version, access, name, signature, superName, interfaces); } public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { if (isSerializable && trans.isUsingMoved()) { if (name.equals("writeObject") && desc.equals("(L"+ClassConfig.fake_prefix+"java/io/ObjectOutputStream;)V")) makeWriteStub(); if (name.equals("readObject") && desc.equals("(L"+ClassConfig.fake_prefix+"java/io/ObjectInputStream;)V")) makeReadStub(); } return super.visitMethod(access, name, desc, signature, exceptions); } private void makeWriteStub() { String wclz = WrappedObjectOutputStream.class.getCanonicalName().replace('.', '/'); trans.getLogger().debug("adding writeObject(...) bridge method"); MethodVisitor mv = super.visitMethod(ACC_PRIVATE, "writeObject", "(Ljava/io/ObjectOutputStream;)V", null, new String[] { "java/io/IOException" }); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, wclz); mv.visitFieldInsn(GETFIELD, wclz, "wrapper", "Ljava/lang/Object;"); mv.visitTypeInsn(CHECKCAST, ClassConfig.fake_prefix+"java/io/ObjectOutputStream"); mv.visitMethodInsn(INVOKESPECIAL, name, "writeObject", "(L"+ClassConfig.fake_prefix+"java/io/ObjectOutputStream;)V", false); Label l1 = new Label(); mv.visitLabel(l1); mv.visitInsn(RETURN); Label l2 = new Label(); mv.visitLabel(l2); mv.visitLocalVariable("this", "L"+name+";", null, l0, l2, 0); mv.visitLocalVariable("stream", "Ljava/io/ObjectOutputStream;", null, l0, l2, 1); mv.visitMaxs(2, 2); mv.visitEnd(); } private void makeReadStub() { String wclz = WrappedObjectInputStream.class.getCanonicalName().replace('.', '/'); trans.getLogger().debug("adding readObject(...) bridge method"); MethodVisitor mv = super.visitMethod(ACC_PRIVATE, "readObject", "(Ljava/io/ObjectInputStream;)V", null, new String[] { "java/io/IOException", "java/lang/ClassNotFoundException" }); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, wclz); mv.visitFieldInsn(GETFIELD, wclz, "wrapper", "Ljava/lang/Object;"); mv.visitTypeInsn(CHECKCAST, ClassConfig.fake_prefix+"java/io/ObjectInputStream"); mv.visitMethodInsn(INVOKESPECIAL, name, "readObject", "(L"+ClassConfig.fake_prefix+"java/io/ObjectInputStream;)V", false); Label l1 = new Label(); mv.visitLabel(l1); mv.visitInsn(RETURN); Label l2 = new Label(); mv.visitLabel(l2); mv.visitLocalVariable("this", "L"+name+";", null, l0, l2, 0); mv.visitLocalVariable("stream", "Ljava/io/ObjectInputStream;", null, l0, l2, 1); mv.visitMaxs(2, 2); mv.visitEnd(); } }