package org.deuce.transform.asm.method;
import java.util.HashMap;
import org.deuce.Unsafe;
import org.deuce.objectweb.asm.AnnotationVisitor;
import org.deuce.objectweb.asm.Attribute;
import org.deuce.objectweb.asm.Label;
import org.deuce.objectweb.asm.MethodVisitor;
import org.deuce.objectweb.asm.Opcodes;
import org.deuce.objectweb.asm.Type;
import org.deuce.objectweb.asm.commons.AnalyzerAdapter;
import org.deuce.objectweb.asm.commons.Method;
import org.deuce.transform.asm.FieldsHolder;
public class MethodTransformer implements MethodVisitor{
final static private String UNSAFE_DESCRIPTOR = Type.getDescriptor(Unsafe.class);
private MethodVisitor originalMethod;
final private MethodVisitor originalCopyMethod;
private MethodVisitor copyMethod;
final private String className;
final private String methodName;
final private String descriptor; // original descriptor
final private HashMap<Label, Label> labelMap = new HashMap<Label, Label>();
final private boolean isStatic;
final private Method newMethod;
public MethodTransformer(MethodVisitor originalMethod, MethodVisitor copyMethod,
String className, int access, String methodName, String descriptor, Method newMethod,
FieldsHolder fieldsHolder) {
this.originalMethod = originalMethod;
this.newMethod = newMethod;
this.isStatic = (access & Opcodes.ACC_STATIC) != 0;
this.originalCopyMethod = copyMethod;
// The AnalyzerAdapter delegates the call to the DuplicateMethod, while the DuplicateMethod uses
// the analyzer for stack state in the original method.
DuplicateMethod duplicateMethod = new DuplicateMethod( copyMethod, isStatic, newMethod, fieldsHolder);
AnalyzerAdapter analyzerAdapter = new AnalyzerAdapter( className, access, methodName, descriptor, duplicateMethod);
duplicateMethod.setAnalyzer( analyzerAdapter);
this.copyMethod = analyzerAdapter;
this.className = className;
this.methodName = methodName;
this.descriptor = descriptor;
}
public void visitCode() {
originalMethod.visitCode();
copyMethod.visitCode();
}
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
// FIXME we might see other annotations before and we need to put it on the new AtomicMethod
// need to create an atomic method from the original method
if( AtomicMethod.ATOMIC_DESCRIPTOR.equals(desc) && !(originalMethod instanceof AtomicMethod))
originalMethod = new AtomicMethod( originalMethod, className, methodName,
descriptor, newMethod, isStatic);
if( UNSAFE_DESCRIPTOR.equals(desc)) // if marked as Unsafe no just duplicate the method as is.
copyMethod = originalCopyMethod;
if( !desc.contains("org/junit")) // TODO find another way
return new MethodAnnotationVisitor( originalMethod.visitAnnotation(desc, visible),
copyMethod.visitAnnotation(desc, visible));
else
return originalMethod.visitAnnotation(desc, visible);
}
public AnnotationVisitor visitAnnotationDefault() {
return new MethodAnnotationVisitor( originalMethod.visitAnnotationDefault(),
copyMethod.visitAnnotationDefault());
}
public void visitAttribute(Attribute attr) {
originalMethod.visitAttribute(attr);
copyMethod.visitAttribute(attr);
}
public void visitEnd() {
originalMethod.visitEnd();
copyMethod.visitEnd();
}
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
originalMethod.visitFieldInsn(opcode, owner, name, desc);
copyMethod.visitFieldInsn(opcode, owner, name, desc);
}
public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) {
originalMethod.visitFrame(type, local, local2, stack, stack2);
copyMethod.visitFrame(type, local, local2, stack, stack2);
}
public void visitIincInsn(int var, int increment) {
originalMethod.visitIincInsn(var, increment);
copyMethod.visitIincInsn(var, increment);
}
public void visitInsn(int opcode) {
originalMethod.visitInsn(opcode);
copyMethod.visitInsn(opcode);
}
public void visitIntInsn(int opcode, int operand) {
originalMethod.visitIntInsn(opcode, operand);
copyMethod.visitIntInsn(opcode, operand);
}
public void visitJumpInsn(int opcode, Label label) {
originalMethod.visitJumpInsn(opcode, label);
copyMethod.visitJumpInsn(opcode, getLabel(label));
}
public void visitLabel(Label label) {
originalMethod.visitLabel(label);
copyMethod.visitLabel(getLabel(label));
}
public void visitLdcInsn(Object cst) {
originalMethod.visitLdcInsn(cst);
copyMethod.visitLdcInsn(cst);
}
public void visitLineNumber(int line, Label start) {
originalMethod.visitLineNumber(line, start);
copyMethod.visitLineNumber(line, getLabel(start));
}
public void visitLocalVariable(String name, String desc, String signature, Label start,
Label end, int index) {
originalMethod.visitLocalVariable(name, desc, signature, start, end, index);
copyMethod.visitLocalVariable(name, desc, signature, getLabel(start), getLabel(end), index);
}
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
originalMethod.visitLookupSwitchInsn(dflt, keys, labels);
copyMethod.visitLookupSwitchInsn( getLabel(dflt), keys, getCopyLabels(labels));
}
public void visitMaxs(int maxStack, int maxLocals) {
originalMethod.visitMaxs(maxStack, maxLocals);
copyMethod.visitMaxs(maxStack, maxLocals);
}
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
originalMethod.visitMethodInsn(opcode, owner, name, desc);
copyMethod.visitMethodInsn(opcode, owner, name, desc);
}
public void visitMultiANewArrayInsn(String desc, int dims) {
originalMethod.visitMultiANewArrayInsn(desc, dims);
copyMethod.visitMultiANewArrayInsn(desc, dims);
}
public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
return new MethodAnnotationVisitor( originalMethod.visitParameterAnnotation(parameter, desc, visible),
copyMethod.visitParameterAnnotation(parameter, desc, visible));
}
public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
originalMethod.visitTableSwitchInsn(min, max, dflt, labels);
copyMethod.visitTableSwitchInsn(min, max, getLabel(dflt), getCopyLabels(labels));
}
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
originalMethod.visitTryCatchBlock(start, end, handler, type);
copyMethod.visitTryCatchBlock(getLabel(start), getLabel(end), getLabel(handler), type);
}
public void visitTypeInsn(int opcode, String type) {
originalMethod.visitTypeInsn(opcode, type);
copyMethod.visitTypeInsn(opcode, type);
}
public void visitVarInsn(int opcode, int var) {
originalMethod.visitVarInsn(opcode, var);
copyMethod.visitVarInsn(opcode, var);
}
private Label[] getCopyLabels(Label[] labels) {
Label[] copyLabels = new Label[ labels.length];
for( int i=0; i<labels.length ;++i) {
copyLabels[i] = getLabel(labels[i]);
}
return copyLabels;
}
private Label getLabel( Label label){
Label duplicateLabel = labelMap.get( label);
if( duplicateLabel == null) {
duplicateLabel = new Label();
labelMap.put(label, duplicateLabel);
}
return duplicateLabel;
}
}