Package net.sourceforge.retroweaver.translator

Source Code of net.sourceforge.retroweaver.translator.NameTranslatorClassVisitor

package net.sourceforge.retroweaver.translator;

import java.util.HashSet;
import java.util.Set;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureWriter;

public class NameTranslatorClassVisitor extends ClassAdapter {

  private final NameTranslator translator;

  public NameTranslatorClassVisitor(final ClassVisitor classVisitor, final NameTranslator translator) {
    super(classVisitor);
    this.translator = translator;
  }

  private Set<String> visitedMethods;

  private String className;

  private String translateSignature(final String signature, boolean type) {
    if (signature == null) {
      return null;
    }
    SignatureReader r = new SignatureReader(signature);
    SignatureWriter w = new SignatureWriter() {
        public void visitClassType(final String name) {
          String n = translator.getClassMirrorTranslation(name);
          super.visitClassType(n);
        }
    };

    if (type) {
      r.acceptType(w);   
    } else {
      r.accept(w);   
    }
    return w.toString();
  }

  public void visit(final int version, final int access, final String name,
      final String signature, final String superName,
      final String[] interfaces) {
    final String newSuperName = translator.getClassMirrorTranslation(superName);

    String newInterfaces[] = new String[interfaces.length];
    for (int i = 0; i < interfaces.length; i++) {
      newInterfaces[i] = translator.getClassMirrorTranslation(interfaces[i]);
    }

    className = name;
    visitedMethods = new HashSet<String>();

    super.visit(version, access, name, translateSignature(signature, false), newSuperName, newInterfaces);
  }

  public FieldVisitor visitField(final int access, final String name,
      final String desc, final String signature, final Object value) {
    return super.visitField(access, name,
                translator.getClassMirrorTranslationDescriptor(desc),
                translateSignature(signature, true), value);
  }

  public MethodVisitor visitMethod(final int access, final String name,
      final String desc, final String signature, final String[] exceptions) {

    final String newDesc = translator.translateMethodDescriptor(desc);
    final String fullDesc = name + newDesc;
    if (visitedMethods.contains(fullDesc)) {
      throw new TranslatorException(
          "Duplicate method after name translation in class "
              + className + ": " + name + ' ' + newDesc);
    }
    visitedMethods.add(fullDesc);

    MethodVisitor mv = super.visitMethod(access, name, newDesc,
        translateSignature(signature, false), exceptions);
    return (mv == null)?null:new MethodTranslator(mv);
  }

    public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
      final String newDesc = translateAnnotationDescriptor(desc);
        return new AnnotationTranslator(cv.visitAnnotation(newDesc, visible));
    }

  private String translateAnnotationDescriptor(final String name) {
    if ((name == null) || (name.length() == 0)) {
      return name;
    }

    if ((name.charAt(0) != 'L') || (name.charAt(name.length()-1) != ';')) {
      return name;
    }

    return translator.translateDescriptor(name);
  }

  private class MethodTranslator extends MethodAdapter {
    MethodTranslator(MethodVisitor methodVisitor) {
      super(methodVisitor);
    }

    public void visitTypeInsn(final int opcode, final String desc) {
      super.visitTypeInsn(opcode, translator.getClassMirrorTranslationDescriptor(desc));
    }

    public void visitFieldInsn(final int opcode, final String owner,
        final String name, final String desc) {

      String newDesc = translator.getClassMirrorTranslationDescriptor(desc);

      if (opcode == Opcodes.GETSTATIC) {
        final Mirror mirror = translator.getMirror(owner);
        if (mirror.hasStaticField(name, newDesc)) {
          super.visitFieldInsn(opcode,
                      translator.translate(owner), name, newDesc);

          return;
        }
      }
      super.visitFieldInsn(opcode,
                  translator.getClassMirrorTranslation(owner),
                  name, newDesc);
    }

    public void visitMethodInsn(final int opcode, final String owner,
        final String name, final String desc) {

      // Special case method invocations for name translation.
      // Specifically to deal with methods mirrors.
      String newOwner = owner;
      int newOpcode = opcode;
      String newDesc = translator.translateMethodDescriptor(desc);
     
      String lookupOwner = owner;
      while (lookupOwner.startsWith("[")) {
        lookupOwner = lookupOwner.substring(1);
      }
      final Mirror mirror = translator.getMirror(lookupOwner);

      if (mirror.isClassMirror()) {
        newOwner = translator.translate(owner);
      } else if ("<init>".equals(name)&&(opcode == Opcodes.INVOKESPECIAL)) {
        /* Look for an equivalent constructor. For instance,
         * INVOKESPECIAL, "java/math/BigDecimal", "<init>", "(I)V")
         * will be transformed as
         * INVOKESTATIC, "../BigDecimal_", "BigDecimal", "(I)Ljava/math/BigDecimal;"
         *
         * the previously constructed object was on top of the stack and the mirror
         * function has put its result on top, so a SWAP and POP are issued to
         * discard the previously constructed object and store the new one instead.
         */
        String constructorDesc = newDesc.substring(0, newDesc.length()-1) + 'L' + owner + ';';
        String constructorName;
        int i = owner.lastIndexOf('/');
        if (i == -1) {
          constructorName = owner;
        } else {
          constructorName = owner.substring(i+1);
        }
        if (mirror.hasMethod(owner, constructorName, constructorDesc, Opcodes.INVOKESPECIAL)) {
          newOwner = translator.translate(owner);

          super.visitMethodInsn(Opcodes.INVOKESTATIC, newOwner, constructorName,
              constructorDesc);

          super.visitInsn(Opcodes.SWAP);
          super.visitInsn(Opcodes.POP);
          super.visitInsn(Opcodes.SWAP);
          super.visitInsn(Opcodes.POP);
          return;
        }
      } else if (mirror.hasMethod(owner, name, newDesc, opcode)) {
        newOwner = translator.translate(owner);
        newOpcode = Opcodes.INVOKESTATIC;

        // We have to insert the owner into the arguments of the
        // descriptor
        if (opcode == Opcodes.INVOKEVIRTUAL || opcode == Opcodes.INVOKEINTERFACE) {
          final Type[] argTypes = Type.getArgumentTypes(newDesc);
          final Type[] newArgTypes = new Type[argTypes.length + 1];
          newArgTypes[0] = Type.getType("L" + owner + ";");
          System.arraycopy(argTypes, 0, newArgTypes, 1, argTypes.length);
          newDesc = Type.getMethodDescriptor(
              Type.getReturnType(newDesc), newArgTypes);
          newDesc = translator.translateMethodDescriptor(newDesc);
        }
      }

      super.visitMethodInsn(newOpcode, newOwner, name, newDesc);
    }

    public void visitTryCatchBlock(final Label start, final Label end,
        final Label handler, final String type) {
      super.visitTryCatchBlock(start, end, handler, translator.translate(type));
    }

    public void visitLocalVariable(final String name, final String desc,
        final String signature, final Label start, final Label end,
        final int index) {
      super.visitLocalVariable(name, translator.translateDescriptor(desc),
          translateSignature(signature, true), start, end, index);
    }

      public AnnotationVisitor visitAnnotationDefault() {
          return new AnnotationTranslator(mv.visitAnnotationDefault());
      }

      public AnnotationVisitor visitAnnotation(
          final String desc,
          final boolean visible)
      {
        String newDesc = translator.getClassMirrorTranslationDescriptor(desc);
          return new AnnotationTranslator(mv.visitAnnotation(newDesc, visible));
      }

      public AnnotationVisitor visitParameterAnnotation(
          final int parameter,
          final String desc,
          final boolean visible)
      {
        String newDesc = translator.getClassMirrorTranslationDescriptor(desc);
          return new AnnotationTranslator(mv.visitParameterAnnotation(parameter, newDesc, visible));
      }

  }

  private class AnnotationTranslator implements AnnotationVisitor {
   
    private final AnnotationVisitor av;
   
    AnnotationTranslator(final AnnotationVisitor av) {
      this.av = av;
    }

    public void visit(final String name, final Object value) {
      final String newName = translateAnnotationDescriptor(name);
      av.visit(newName, value);
    }

    public void visitEnum(final String name, final String desc, final String value) {
      final String newName = translateAnnotationDescriptor(name);
      final String newDesc = translateAnnotationDescriptor(desc);
        av.visitEnum(newName, newDesc, value);
      }

    public AnnotationVisitor visitAnnotation(final String name, final String desc) {
      final String newName = translateAnnotationDescriptor(name);
        return new AnnotationTranslator(av.visitAnnotation(newName, desc));
      }

    public AnnotationVisitor visitArray(final String name) {
      final String newName = translateAnnotationDescriptor(name);
        return new AnnotationTranslator(av.visitArray(newName));
      }

    public void visitEnd() {
        av.visitEnd();
      }

  }
}
TOP

Related Classes of net.sourceforge.retroweaver.translator.NameTranslatorClassVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.