/*
* 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.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class MethodRemapperClassVisitor extends ClassVisitor {
private Translation trans;
public MethodRemapperClassVisitor(ClassVisitor arg0, Translation trans) {
super(Opcodes.ASM5, arg0);
this.trans = trans;
}
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
return new RemapMethodVisitor(name, desc, super.visitMethod(access, name, desc, signature, exceptions));
}
private class RemapMethodVisitor extends MethodVisitor {
private final String name;
private final String desc;
public RemapMethodVisitor(String name, String desc, MethodVisitor arg0) {
super(Opcodes.ASM5, arg0);
this.name = name;
this.desc = desc;
}
/**
* Remapped methods go here. This happens either because we don't need to remap the whole
* class (e.g. nanoTime), because we can't override a final method (e.g. wait/notify) or
* cannot wrap the entire class (i.e. throwables).
*/
public void visitMethodInsn (int opcode, String owner, String name, String desc, boolean itf) {
if (owner.equals("java/lang/Class") && name.equals("forName") && trans.isUsingFakes())
mv.visitMethodInsn(opcode, ClassConfig.fake_prefix+owner+"Fake", name, desc, itf);
else if (owner.equals("java/lang/Class") && name.equals("getResourceAsStream") && trans.isUsingMoved())
mv.visitMethodInsn(Opcodes.INVOKESTATIC, ClassConfig.fake_prefix+owner+"Fake", "_fake_"+name, "(Ljava/lang/Class;"+desc.substring(1), itf);
else if (owner.equals("java/lang/ClassLoader") && trans.isUsingMoved()) {
if (name.equals("getResourceAsStream"))
// Convert to invocation of static wrapper method
mv.visitMethodInsn(Opcodes.INVOKESTATIC, ClassConfig.fake_prefix+owner+"Fake", "_fake_"+name, "(Ljava/lang/ClassLoader;"+desc.substring(1), itf);
else if (name.equals("getSystemResourceAsStream"))
// Invoke wrapper method, that is already static
mv.visitMethodInsn(Opcodes.INVOKESTATIC, ClassConfig.fake_prefix+owner+"Fake", "_fake_"+name, desc, itf);
else {
mv.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
} else if (name.equals("openStream") && owner.equals("java/net/URL") && trans.isUsingMoved()) {
mv.visitMethodInsn(Opcodes.INVOKESTATIC, ClassConfig.fake_prefix+owner+"Fake", "_fake_"+name, "(Ljava/net/URL;"+desc.substring(1), itf);
} else if (name.equals("printStackTrace") && trans.isUsingMoved() && (desc.equals("(L"+ClassConfig.moved_prefix+"java/io/PrintStream;)V") || desc.contains("(L"+ClassConfig.moved_prefix+"java/io/PrintWriter;)V")))
mv.visitMethodInsn(Opcodes.INVOKESTATIC, ClassConfig.fake_prefix+"java/lang/ThrowableFake", "_fake_"+name, "(Ljava/lang/Object;"+desc.substring(1), itf);
else if (owner.equals("java/lang/Object") && trans.isSynchronized() && (name.equals("wait") || name.equals("notify") || name.equals("notifyAll")))
mv.visitMethodInsn(Opcodes.INVOKESTATIC, ClassConfig.fake_prefix+owner, "_fake_"+name, "(Ljava/lang/Object;"+desc.substring(1), itf);
else {
mv.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
if (trans.getLogger().isDebugEnabled())
trans.getLogger().debug("in {}{}: remapped call to {}.{}{}", this,name, this.desc, owner, name, desc);
}
}
}